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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/SConscript1
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h131
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h24
-rw-r--r--source/blender/blenkernel/BKE_customdata.h10
-rw-r--r--source/blender/blenkernel/BKE_mesh.h4
-rw-r--r--source/blender/blenkernel/BKE_modifier.h7
-rw-r--r--source/blender/blenkernel/BKE_multires.h3
-rw-r--r--source/blender/blenkernel/BKE_tessmesh.h66
-rw-r--r--source/blender/blenkernel/BKE_utildefines.h47
-rw-r--r--source/blender/blenkernel/BKE_verse.h586
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/BME_conversions.c13
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c385
-rw-r--r--source/blender/blenkernel/intern/anim.c27
-rw-r--r--source/blender/blenkernel/intern/booleanops.c28
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c8
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c540
-rw-r--r--source/blender/blenkernel/intern/cloth.c8
-rw-r--r--source/blender/blenkernel/intern/constraint.c1
-rw-r--r--source/blender/blenkernel/intern/customdata.c88
-rw-r--r--source/blender/blenkernel/intern/displist.c6
-rw-r--r--source/blender/blenkernel/intern/editderivedbmesh.c1526
-rw-r--r--source/blender/blenkernel/intern/exotic.c4
-rw-r--r--source/blender/blenkernel/intern/fluidsim.c15
-rw-r--r--source/blender/blenkernel/intern/fmodifier.c1197
-rw-r--r--source/blender/blenkernel/intern/mesh.c65
-rw-r--r--source/blender/blenkernel/intern/modifier.c327
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c568
-rw-r--r--source/blender/blenkernel/intern/multires.c4
-rw-r--r--source/blender/blenkernel/intern/object.c8
-rw-r--r--source/blender/blenkernel/intern/particle.c42
-rw-r--r--source/blender/blenkernel/intern/particle_system.c20
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c9
-rw-r--r--source/blender/blenkernel/intern/softbody.c10
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c387
-rw-r--r--source/blender/blenkernel/intern/verse_bitmap_node.c451
-rw-r--r--source/blender/blenkernel/intern/verse_geometry_node.c2101
-rw-r--r--source/blender/blenkernel/intern/verse_method.c523
-rw-r--r--source/blender/blenkernel/intern/verse_node.c750
-rw-r--r--source/blender/blenkernel/intern/verse_object_node.c620
-rw-r--r--source/blender/blenkernel/intern/verse_session.c480
-rw-r--r--source/blender/blenkernel/nla_private.h85
-rw-r--r--source/blender/blenlib/BLI_arithb.h3
-rw-r--r--source/blender/blenlib/BLI_editVert.h3
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c13
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c4
-rw-r--r--source/blender/blenlib/intern/arithb.c51
-rw-r--r--source/blender/blenlib/intern/edgehash.c19
-rw-r--r--source/blender/blenloader/intern/readfile.c157
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/bmesh/SConscript38
-rw-r--r--source/blender/bmesh/bmesh.h355
-rw-r--r--source/blender/bmesh/bmesh_error.h53
-rw-r--r--source/blender/bmesh/bmesh_filters.h4
-rw-r--r--source/blender/bmesh/bmesh_iterators.h70
-rw-r--r--source/blender/bmesh/bmesh_marking.h16
-rw-r--r--source/blender/bmesh/bmesh_operator_api.h338
-rw-r--r--source/blender/bmesh/bmesh_operators.h40
-rw-r--r--source/blender/bmesh/bmesh_queries.h86
-rw-r--r--source/blender/bmesh/bmesh_walkers.h64
-rw-r--r--source/blender/bmesh/editmesh_tools.c7244
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c566
-rw-r--r--source/blender/bmesh/intern/bmesh_eulers.c1186
-rw-r--r--source/blender/bmesh/intern/bmesh_filters.c5
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c246
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c393
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c307
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c277
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c417
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c324
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c1305
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h38
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c838
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h84
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c548
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c775
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h100
-rw-r--r--source/blender/bmesh/intern/bmesh_to_editmesh.c312
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c667
-rw-r--r--source/blender/bmesh/intern/editmesh_to_bmesh.c473
-rw-r--r--source/blender/bmesh/intern/in-progress/BME_conversions.c478
-rw-r--r--source/blender/bmesh/operators/bmesh_dupeops.c570
-rw-r--r--source/blender/bmesh/operators/connectops.c126
-rw-r--r--source/blender/bmesh/operators/createops.c156
-rw-r--r--source/blender/bmesh/operators/dissolveops.c430
-rw-r--r--source/blender/bmesh/operators/extrudeops.c190
-rw-r--r--source/blender/bmesh/operators/mesh_conv.c308
-rw-r--r--source/blender/bmesh/operators/removedoubles.c309
-rw-r--r--source/blender/bmesh/operators/subdivideop.c825
-rw-r--r--source/blender/bmesh/operators/subdivideop.h38
-rw-r--r--source/blender/bmesh/operators/triangulateop.c55
-rw-r--r--source/blender/bmesh/operators/utils.c91
-rw-r--r--source/blender/bmesh/tools/BME_bevel.c918
-rw-r--r--source/blender/bmesh/tools/BME_dupe_ops.c318
-rw-r--r--source/blender/bmesh/tools/BME_duplicate.c307
-rw-r--r--source/blender/bmesh/tools/BME_extrude.c216
-rw-r--r--source/blender/bmesh/tools/BME_weld.c333
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c679
-rw-r--r--source/blender/editors/armature/meshlaplacian.c8
-rw-r--r--source/blender/editors/armature/reeb.c9
-rw-r--r--source/blender/editors/include/ED_mesh.h79
-rw-r--r--source/blender/editors/include/ED_view3d.h14
-rw-r--r--source/blender/editors/mesh/SConscript1
-rw-r--r--source/blender/editors/mesh/bmesh_select.c1424
-rw-r--r--source/blender/editors/mesh/bmesh_selecthistory.c270
-rw-r--r--source/blender/editors/mesh/bmesh_tools.c1321
-rw-r--r--source/blender/editors/mesh/bmeshutils.c523
-rw-r--r--source/blender/editors/mesh/editmesh.c374
-rw-r--r--source/blender/editors/mesh/editmesh_add.c209
-rw-r--r--source/blender/editors/mesh/editmesh_lib.c143
-rw-r--r--source/blender/editors/mesh/editmesh_loop.c249
-rw-r--r--source/blender/editors/mesh/editmesh_mods.c787
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c269
-rw-r--r--source/blender/editors/mesh/mesh_intern.h61
-rw-r--r--source/blender/editors/mesh/mesh_layers.c76
-rw-r--r--source/blender/editors/mesh/meshtools.c85
-rw-r--r--source/blender/editors/object/SConscript2
-rw-r--r--source/blender/editors/object/object_edit.c76
-rw-r--r--source/blender/editors/physics/editparticle.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c4
-rw-r--r--source/blender/editors/space_buttons/SConscript2
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c14
-rw-r--r--source/blender/editors/space_image/image_header.c1
-rw-r--r--source/blender/editors/space_view3d/SConscript2
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c346
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c26
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c157
-rw-r--r--source/blender/editors/space_view3d/view3d_snap.c90
-rw-r--r--source/blender/editors/transform/SConscript2
-rw-r--r--source/blender/editors/transform/transform.c2
-rw-r--r--source/blender/editors/transform/transform_conversions.c159
-rw-r--r--source/blender/editors/transform/transform_generics.c18
-rw-r--r--source/blender/editors/transform/transform_manipulator.c17
-rw-r--r--source/blender/editors/transform/transform_ops.c23
-rw-r--r--source/blender/editors/transform/transform_orientations.c94
-rw-r--r--source/blender/editors/transform/transform_snap.c71
-rw-r--r--source/blender/editors/util/ed_util.c8
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c3
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c5
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h6
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h31
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h21
-rw-r--r--source/blender/makesdna/DNA_object_types.h2
-rw-r--r--source/blender/makesdna/intern/SConscript8
-rw-r--r--source/blender/makesrna/SConscript2
-rw-r--r--source/blender/makesrna/intern/Makefile1
-rw-r--r--source/blender/makesrna/intern/SConscript2
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c81
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c3
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c241
-rw-r--r--source/blender/makesrna/intern/rna_nla.c460
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c83
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c282
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c56
-rw-r--r--source/blender/nodes/intern/TEX_nodes/TEX_at.c70
-rw-r--r--source/blender/python/BPY_extern.h8
-rw-r--r--source/blender/python/BPY_menus.c1118
-rw-r--r--source/blender/python/BPY_menus.h128
-rw-r--r--source/blender/python/CMakeLists.txt4
-rw-r--r--source/blender/python/Makefile4
-rw-r--r--source/blender/python/SConscript6
-rw-r--r--source/blender/python/generic/BGL.c1610
-rwxr-xr-xsource/blender/python/generic/BGL.h338
-rw-r--r--source/blender/python/generic/Geometry.c542
-rw-r--r--source/blender/python/generic/Geometry.h39
-rw-r--r--source/blender/python/generic/Makefile66
-rw-r--r--source/blender/python/generic/Mathutils.c1266
-rw-r--r--source/blender/python/generic/Mathutils.h116
-rw-r--r--source/blender/python/generic/bpy_internal_import.c341
-rw-r--r--source/blender/python/generic/bpy_internal_import.h50
-rw-r--r--source/blender/python/generic/euler.c651
-rw-r--r--source/blender/python/generic/euler.h60
-rw-r--r--source/blender/python/generic/matrix.c1358
-rw-r--r--source/blender/python/generic/matrix.h66
-rw-r--r--source/blender/python/generic/quat.c879
-rw-r--r--source/blender/python/generic/quat.h60
-rw-r--r--source/blender/python/generic/vector.c2078
-rw-r--r--source/blender/python/generic/vector.h55
-rw-r--r--source/blender/python/intern/Makefile3
-rw-r--r--source/blender/python/intern/bpy_compat.h26
-rw-r--r--source/blender/python/intern/bpy_interface.c216
-rw-r--r--source/blender/python/intern/bpy_operator.c15
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c203
-rw-r--r--source/blender/python/intern/bpy_rna.c1295
-rw-r--r--source/blender/python/intern/bpy_rna.h2
-rw-r--r--source/blender/python/intern/bpy_ui.c2
-rw-r--r--source/blender/python/intern/bpy_util.c120
-rw-r--r--source/blender/python/intern/bpy_util.h3
-rw-r--r--source/blender/readblenfile/intern/BLO_readblenfile.c1
-rw-r--r--source/blender/render/intern/source/convertblender.c26
-rw-r--r--source/blender/render/intern/source/shadeoutput.c19
-rw-r--r--source/blender/render/intern/source/strand.c4
200 files changed, 39183 insertions, 16960 deletions
diff --git a/source/blender/SConscript b/source/blender/SConscript
index a064850c170..cce0354643b 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 06103596be1..bb50056b7f2 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -43,6 +43,8 @@
*/
#include "DNA_customdata_types.h"
+#include "DNA_meshdata_types.h"
+
#include "BKE_customdata.h"
#include "BKE_bvhutils.h"
@@ -53,43 +55,87 @@ struct MTFace;
struct Object;
struct Scene;
struct Mesh;
-struct EditMesh;
+struct BMEditMesh;
struct ModifierData;
struct MCol;
struct ColorBand;
struct GPUVertexAttribs;
+struct BMEditMesh;
/* 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.
+*/
+
+/*DM Iterators. For now, first implement face iterators.
+ These are read-only, at least for now.*/
+
+typedef struct DMLoopIter {
+ void (*step)(void *self);
+ int done;
+
+ int index, vindex, eindex;
+ MVert v; /*copy of the associated vert's data*/
+
+ /*note: if layer is -1, then the active layer is retrieved.
+ loop refers to per-face-vertex data.*/
+ void *(*getLoopCDData)(void *self, int type, int layer);
+ void *(*getVertCDData)(void *self, int type, int layer);
+} DMLoopIter;
+
+typedef struct DMFaceIter {
+ void (*step)(void *self);
+ void (*free)(void *self);
+ int done;
+
+ int index;
+ int len;
+ int mat_nr;
+ int flags;
+
+ /*note: you may only use one
+ loop iterator at a time.*/
+ DMLoopIter *(*getLoopsIter)(void *self);
+
+ /*if layer is -1, returns active layer*/
+ void *(*getCDData)(void *self, int type, int layer);
+} DMFaceIter;
typedef struct DerivedMesh DerivedMesh;
struct DerivedMesh {
/* Private DerivedMesh data, only for internal DerivedMesh use */
- CustomData vertData, edgeData, faceData;
- int numVertData, numEdgeData, numFaceData;
+ CustomData vertData, edgeData, faceData, loopData, polyData;
+ int numVertData, numEdgeData, numFaceData, numLoopData, numPolyData;
int needsFree; /* checked on ->release, is set to 0 for cached results */
int deformedOnly; /* set by modifier stack if only deformed from original */
BVHCache bvhCache;
/* Misc. Queries */
+
+ /*face iterator. initializes iter.*/
+ DMFaceIter *(*newFaceIter)(DerivedMesh *dm);
+
+ /*recalculates mesh tesselation*/
+ void (*recalcTesselation)(DerivedMesh *dm);
/* Also called in Editmode */
int (*getNumVerts)(DerivedMesh *dm);
- /* Also called in Editmode */
- int (*getNumFaces)(DerivedMesh *dm);
-
int (*getNumEdges)(DerivedMesh *dm);
+ int (*getNumTessFaces)(DerivedMesh *dm);
+ int (*getNumFaces) (DerivedMesh *dm);
- /* copy a single vert/edge/face from the derived mesh into
+ /* copy a single vert/edge/tesselated face from the derived mesh into
* *{vert/edge/face}_r. note that the current implementation
* of this function can be quite slow, iterating over all
* elements (editmesh)
*/
void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r);
void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r);
- void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r);
+ void (*getTessFace)(DerivedMesh *dm, int index, struct MFace *face_r);
/* return a pointer to the entire array of verts/edges/face from the
* derived mesh. if such an array does not exist yet, it will be created,
@@ -98,21 +144,21 @@ struct DerivedMesh {
*/
struct MVert *(*getVertArray)(DerivedMesh *dm);
struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
- struct MFace *(*getFaceArray)(DerivedMesh *dm);
+ struct MFace *(*getTessFaceArray)(DerivedMesh *dm);
/* copy all verts/edges/faces from the derived mesh into
* *{vert/edge/face}_r (must point to a buffer large enough)
*/
void (*copyVertArray)(DerivedMesh *dm, struct MVert *vert_r);
void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r);
- void (*copyFaceArray)(DerivedMesh *dm, struct MFace *face_r);
+ void (*copyTessFaceArray)(DerivedMesh *dm, struct MFace *face_r);
/* return a copy of all verts/edges/faces from the derived mesh
* it is the caller's responsibility to free the returned pointer
*/
struct MVert *(*dupVertArray)(DerivedMesh *dm);
struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
- struct MFace *(*dupFaceArray)(DerivedMesh *dm);
+ struct MFace *(*dupTessFaceArray)(DerivedMesh *dm);
/* return a pointer to a single element of vert/edge/face custom data
* from the derived mesh (this gives a pointer to the actual data, not
@@ -120,7 +166,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
@@ -128,7 +174,20 @@ struct DerivedMesh {
*/
void *(*getVertDataArray)(DerivedMesh *dm, int type);
void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
- void *(*getFaceDataArray)(DerivedMesh *dm, int type);
+ void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
+
+ /*retrieves the base CustomData structures for
+ verts/edges/tessfaces/loops/facdes*/
+ CustomData *(*getVertDataLayout)(DerivedMesh *dm);
+ CustomData *(*getEdgeDataLayout)(DerivedMesh *dm);
+ CustomData *(*getTessFaceDataLayout)(DerivedMesh *dm);
+ CustomData *(*getLoopDataLayout)(DerivedMesh *dm);
+ CustomData *(*getFaceDataLayout)(DerivedMesh *dm);
+
+ /*copies all customdata for an element source into dst at index dest*/
+ void (*copyFromVertCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
+ void (*copyFromEdgeCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
+ void (*copyFromFaceCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
/* Iterate over each mapped vertex in the derived mesh, calling the
* given function with the original vert and the mapped vert's new
@@ -299,13 +358,15 @@ 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, int numVerts, int numEdges, int numFaces);
+void DM_init(DerivedMesh *dm, 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,
- int numVerts, int numEdges, int numFaces);
+ 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
@@ -368,6 +429,10 @@ void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
+void DM_copy_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int source_index, int dest_index, int count);
+void DM_copy_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int source_index, int dest_index, int count);
void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
int source_index, int dest_index, int count);
@@ -377,8 +442,13 @@ void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
*/
void DM_free_vert_data(struct DerivedMesh *dm, int index, int count);
void DM_free_edge_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_loop_data(struct DerivedMesh *dm, int index, int count);
void DM_free_face_data(struct DerivedMesh *dm, int index, int count);
+/*sets up mpolys for a DM based on face iterators in source*/
+void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
+
/* interpolates vertex data from the vertices indexed by src_indices in the
* source mesh using the given weights and stores the result in the vertex
* indexed by dest_index in the dest mesh
@@ -408,12 +478,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, int *corner_indices);
+void DM_swap_tessface_data(struct DerivedMesh *dm, int index, int *corner_indices);
+
+void DM_interp_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index);
+
+void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index);
/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */
void vDM_ColorBand_store(struct ColorBand *coba);
@@ -434,6 +512,9 @@ DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object
DerivedMesh *mesh_create_derived_render(struct Scene *scene, struct Object *ob,
CustomDataMask dataMask);
+DerivedMesh *getEditDerivedBMesh(struct BMEditMesh *em, struct Object *ob,
+ float (*vertexCos)[3]);
+
DerivedMesh *mesh_create_derived_index_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask, int index);
/* same as above but wont use render settings */
@@ -449,17 +530,17 @@ DerivedMesh *mesh_create_derived_no_deform_render(struct Scene *scene, struct Ob
DerivedMesh *mesh_create_derived_no_virtual(struct Scene *scene, struct Object *ob, float (*vertCos)[3],
CustomDataMask dataMask);
-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_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);
-void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em, CustomDataMask dataMask);
+void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, CustomDataMask dataMask);
/* returns an array of deform matrices for crazyspace correction, and the
number of modifiers left */
-int editmesh_get_first_deform_matrices(struct Object *, struct EditMesh *em, float (**deformmats)[3][3],
+int editbmesh_get_first_deform_matrices(struct Object *, struct BMEditMesh *em, float (**deformmats)[3][3],
float (**deformcos)[3]);
void weight_to_rgb(float input, float *fr, float *fg, float *fb);
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index a570b4fe598..36db9553c59 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -38,12 +38,14 @@
#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);
/* creates a CDDerivedMesh from the given Mesh, this will reference the
original data in Mesh, but it is safe to apply vertex coordinates or
@@ -54,6 +56,9 @@ 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);
+
/* Copies the given DerivedMesh with verts, faces & edges stored as
* custom element data.
*/
@@ -64,7 +69,13 @@ struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
* 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
@@ -95,7 +106,9 @@ void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces);
*/
struct MVert *CDDM_get_vert(struct DerivedMesh *dm, int index);
struct MEdge *CDDM_get_edge(struct DerivedMesh *dm, int index);
-struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index);
+struct MFace *CDDM_get_tessface(struct DerivedMesh *dm, int index);
+struct MLoop *CDDM_get_loop(struct DerivedMesh *dm, int index);
+struct MPoly *CDDM_get_face(struct DerivedMesh *dm, int index);
/* vertex/edge/face array access functions - return the array holding the
* desired data
@@ -104,6 +117,9 @@ 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_faces(struct DerivedMesh *dm);
+
#endif
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 95ee918a888..d442a57b525 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -69,6 +69,12 @@ void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
CustomDataMask mask, int alloctype, int totelem);
+/*bmesh version of CustomData_merge; merges the layouts of source and dest,
+ then goes through the mesh and makes sure all the customdata blocks are
+ consistent with the new layout.*/
+void CustomData_bmesh_merge(struct CustomData *source, struct CustomData *dest,
+ int mask, int alloctype, struct BMesh *bm, int type);
+
/* frees data associated with a CustomData object (doesn't free the object
* itself, though)
*/
@@ -179,6 +185,7 @@ void CustomData_swap(struct CustomData *data, int index, int *corner_indices);
* returns NULL if there is no layer of type
*/
void *CustomData_get(const struct CustomData *data, int index, int type);
+void *CustomData_get_n(const struct CustomData *data, int type, int index, int n);
void *CustomData_em_get(const struct CustomData *data, void *block, int type);
void *CustomData_em_get_n(const struct CustomData *data, void *block, int type, int n);
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
@@ -275,7 +282,8 @@ void CustomData_set_layer_unique_name(struct CustomData *data, int index);
int CustomData_verify_versions(struct CustomData *data, int index);
/*BMesh specific customdata stuff*/
-void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
+void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata,
+ struct CustomData *ldata, int totloop, int totpoly);
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize);
#endif
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 24e7b3957a7..5a672ddc5b2 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -43,6 +43,7 @@ struct MFace;
struct MEdge;
struct MVert;
struct MCol;
+struct BMesh;
struct Object;
struct MTFace;
struct VecNor;
@@ -54,6 +55,7 @@ extern "C" {
struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me);
void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em);
+struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me);
void unlink_mesh(struct Mesh *me);
void free_mesh(struct Mesh *me);
@@ -135,8 +137,6 @@ int mesh_layers_menu_charlen(struct CustomData *data, int type); /* use this to
void mesh_layers_menu_concat(struct CustomData *data, int type, char *str);
int mesh_layers_menu(struct CustomData *data, int type);
-
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 144ed3bc624..b4efb742b27 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -43,6 +43,7 @@ struct ListBase;
struct LinkNode;
struct bArmature;
struct ModifierData;
+struct BMEditMesh;
typedef enum {
/* Should not be used, only for None modifier type */
@@ -134,13 +135,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 *********************/
@@ -178,7 +179,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 6558212519f..063f0ee96aa 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -40,7 +40,8 @@ typedef struct MultiresSubsurf {
/* MultiresDM */
struct Mesh *MultiresDM_get_mesh(struct DerivedMesh *dm);
-struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*, int, int, int);
+struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*,
+ int, int, int, int, int);
void *MultiresDM_get_vertnorm(struct DerivedMesh *);
void *MultiresDM_get_orco(struct DerivedMesh *);
struct MVert *MultiresDM_get_subco(struct DerivedMesh *);
diff --git a/source/blender/blenkernel/BKE_tessmesh.h b/source/blender/blenkernel/BKE_tessmesh.h
new file mode 100644
index 00000000000..c3ccf4b1e6a
--- /dev/null
+++ b/source/blender/blenkernel/BKE_tessmesh.h
@@ -0,0 +1,66 @@
+#include "bmesh.h"
+
+struct BMesh;
+struct BMLoop;
+struct DerivedMesh;
+struct BMFace;
+
+/*
+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.
+*/
+
+typedef struct BMEditSelection
+{
+ struct BMEditSelection *next, *prev;
+ short type;
+ void *data;
+} BMEditSelection;
+
+/*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->editbmesh will store a pointer to this structure.*/
+typedef struct BMEditMesh {
+ struct BMesh *bm;
+
+ /*this is for undoing failed operations*/
+ struct BMEditMesh *emcopy;
+
+ /*we store tesselations as triplets of three loops,
+ which each define a triangle.*/
+ struct BMLoop *(*looptris)[3];
+ int tottri;
+
+ /*derivedmesh stuff*/
+ struct DerivedMesh *derivedFinal, *derivedCage;
+ int lastDataMask;
+
+ /*retopo data pointer*/
+ struct RetopoPaintData *retopo_paint_data;
+
+ /*index tables, to map indices to elements via
+ EDBM_init_index_arrays and associated functions. don't
+ touch this or read it directly.*/
+ struct BMVert **vert_index;
+ struct BMEdge **edge_index;
+ struct BMFace **face_index;
+
+ /*selection order list*/
+ ListBase selected;
+
+ /*selection mode*/
+ int selectmode;
+
+ int mat_nr;
+} BMEditMesh;
+
+void BMEdit_RecalcTesselation(BMEditMesh *tm);
+BMEditMesh *BMEdit_Create(BMesh *bm);
+BMEditMesh *BMEdit_Copy(BMEditMesh *tm);
+void BMEdit_Free(BMEditMesh *em);
diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h
index f6c305b202d..3c01f86dc02 100644
--- a/source/blender/blenkernel/BKE_utildefines.h
+++ b/source/blender/blenkernel/BKE_utildefines.h
@@ -113,6 +113,8 @@
#define VECADD(v1,v2,v3) {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);}
#define VECSUB(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);}
#define VECSUB2D(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);}
+#define VECMUL(v1, fac) {v1[0] *= fac; v1[1] *= fac; v1[2] *= fac;}
+
#define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);}
#define QUATADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac); *(v1+3)= *(v2+3) + *(v3+3)*(fac);}
@@ -199,5 +201,50 @@
#define SET_INT_IN_POINTER(i) ((void*)(intptr_t)(i))
#define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i))
+/*little pointer array macro library. example of usage:
+
+int *arr = NULL;
+V_DECLARE(arr);
+int i;
+
+for (i=0; i<10; i++) {
+ V_GROW(arr);
+ arr[i] = something;
+}
+V_FREE(arr);
+
+arrays are buffered, using double-buffering (so on each reallocation,
+the array size is doubled). supposedly this should give good Big Oh
+behaviour, though it may not be the best in practice.
+*/
+
+#define V_DECLARE(vec) int _##vec##_count=0; void *_##vec##_tmp
+
+/*in the future, I plan on having V_DECLARE allocate stack memory it'll
+ use at first, and switch over to heap when it needs more. that'll mess
+ up cases where you'd want to use this API to build a dynamic list for
+ non-local use, so all such cases should use this macro.*/
+#define V_DYNDECLARE(vec) V_DECLARE(vec)
+
+/*this returns the entire size of the array, including any buffering.*/
+#define V_SIZE(vec) ((signed int)((vec)==NULL ? 0 : MEM_allocN_len(vec) / sizeof(*vec)))
+
+/*this returns the logical size of the array, not including buffering.*/
+#define V_COUNT(vec) _##vec##_count
+
+/*grow the array by one. zeroes the new elements.*/
+#define V_GROW(vec) \
+ V_SIZE(vec) > _##vec##_count ? _##vec##_count++ : \
+ ((_##vec##_tmp = MEM_callocN(sizeof(*vec)*(_##vec##_count*2+2), #vec " " __FILE__ " ")),\
+ (vec && memcpy(_##vec##_tmp, vec, sizeof(*vec) * _##vec##_count)),\
+ (vec && (MEM_freeN(vec),1)),\
+ (vec = _##vec##_tmp),\
+ _##vec##_count++)
+
+#define V_FREE(vec) if (vec) MEM_freeN(vec);
+/*resets the logical size of an array to zero, but doesn't
+ free the memory.*/
+#define V_RESET(vec) _##vec##_count=0
+
#endif
diff --git a/source/blender/blenkernel/BKE_verse.h b/source/blender/blenkernel/BKE_verse.h
new file mode 100644
index 00000000000..ee22081b03f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_verse.h
@@ -0,0 +1,586 @@
+/**
+ * $Id: BKE_verse.h 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* #define WITH_VERSE */
+
+#ifndef BKE_VERSE_H
+#define BKE_VERSE_H
+
+#include "DNA_listBase.h"
+#include "BLI_dynamiclist.h"
+
+#include "verse.h"
+#include "verse_ms.h"
+
+struct VNode;
+struct VerseEdge;
+
+/*
+ * Verse Edge Hash (similar to edit edge hash)
+ */
+#define VEDHASHSIZE (512*512)
+#define VEDHASH(a, b) ((a<b ? a : b) % VEDHASHSIZE)
+
+/*
+ * verse data: 4 float value
+ */
+typedef struct quat_real32_item {
+ struct quat_real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value[4];
+} quat_real32_item;
+
+/*
+ * verse data: 4 uint32 values
+ */
+typedef struct quat_uint32_item {
+ struct quat_uint32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint32 value[4];
+} quat_uint32_item;
+
+/*
+ * verse data: 3 float values
+ */
+typedef struct vec_real32_item {
+ struct vec_real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value[3];
+} vec_real32_item;
+
+/*
+ * verse data: float value (weight)
+ */
+typedef struct real32_item {
+ struct real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value;
+} real32_item;
+
+/*
+ * verse data: uint32 value
+ */
+typedef struct uint32_item {
+ struct uint32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint32 value;
+} uint32_item;
+
+/*
+ * verse data: uint8 value
+ */
+typedef struct uint8_item {
+ struct uint8_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint8 value;
+} uint8_item;
+
+/*
+ * verse data: vertex
+ */
+typedef struct VerseVert {
+ struct VerseVert *next, *prev;
+ /* verse data */
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of vertex */
+ real32 co[3]; /* x,y,z-coordinates of vertex */
+ real32 no[3]; /* normal of vertex */
+ /* blender internals */
+ short flag; /* flags: VERT_DELETED, VERT_RECEIVED, etc. */
+ void *vertex; /* pointer at EditVert or MVert */
+ int counter; /* counter of VerseFaces using this VerseVert */
+ union {
+ unsigned int index; /* counter need during transformation to mesh */
+ struct VerseVert *vvert;
+ } tmp; /* pointer at new created verse vert, it is
+ * used during duplicating geometry node */
+ float *cos; /* modified coordinates of vertex */
+ float *nos; /* modified normal vector */
+} VerseVert;
+
+/*
+ * structture used for verse edge hash
+ */
+typedef struct HashVerseEdge {
+ struct VerseEdge *vedge;
+ struct HashVerseEdge *next;
+} HashVerseEdge;
+
+/*
+ * fake verse data: edge
+ */
+typedef struct VerseEdge {
+ struct VerseEdge *next, *prev;
+ uint32 v0, v1; /* indexes of verse vertexes */
+ int counter; /* counter of verse faces using this edge */
+ struct HashVerseEdge hash; /* hash table */
+ union {
+ unsigned int index; /* temporary index of edge */
+ } tmp;
+} VerseEdge;
+
+/*
+ * verse data: polygon
+ */
+typedef struct VerseFace {
+ struct VerseFace *next, *prev;
+ /* verse data */
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of face */
+ struct VerseVert *vvert0; /* pointer at 1st VerseVert */
+ struct VerseVert *vvert1; /* pointer at 2nd VerseVert */
+ struct VerseVert *vvert2; /* pointer at 3th VerseVert */
+ struct VerseVert *vvert3; /* pointer at 4th VerseVert */
+ unsigned int v0, v1, v2, v3; /* indexes of VerseVerts ... needed during receiving */
+ /* blender internals */
+ char flag; /* flags: FACE_SEND_READY, FACE_SENT, FACE_RECEIVED, FACE_CHANGED*/
+ short counter; /* counter of missed VerseVertexes */
+ void *face; /* pointer at EditFace */
+ float no[3]; /* normal vector */
+ float *nos; /* modified normal vector */
+} VerseFace;
+
+/*
+ * verse data: layer
+ */
+typedef struct VLayer {
+ struct VLayer *next, *prev;
+ /* verse data*/
+ struct VNode *vnode; /* pointer at VerseNode */
+ uint16 id; /* id of layer */
+ char *name; /* name of layer */
+ VNGLayerType type; /* type of layer (VN_G_LAYER_VERTEX_XYZ, VN_G_LAYER_POLYGON_CORNER_UINT32) */
+ uint32 def_int; /* default integer value */
+ real64 def_real; /* default float value */
+ /* blender internals */
+ char flag; /* flags: LAYER_SENT, LAYER_RECEIVED, LAYER_DELETED, LAYER_OBSOLETE */
+ short content; /* type of content (VERTEX_LAYER, POLYGON_LAYER) */
+ struct DynamicList dl; /* vertexes, polygons, etc. */
+ struct ListBase queue; /* queue of vertexes, polygons, etc. waiting for sending to verse server */
+ struct ListBase orphans; /* list of versedata (polygons, etc.), that can be added to the DynamicList
+ * due to not received VerseVerts */
+ unsigned int counter; /* counter of sent items */
+ /* client dependent methods */
+ void (*post_layer_create)(struct VLayer *vlayer);
+ void (*post_layer_destroy)(struct VLayer *vlayer);
+} VLayer;
+
+/*
+ * verse data: link
+ */
+typedef struct VLink{
+ struct VLink *next, *prev;
+ /* verse data */
+ struct VerseSession *session; /* session pointer */
+ struct VNode *source; /* object VerseNode "pointing" at some other VerseNode */
+ struct VNode *target; /* VerseNode linked with some object node */
+ unsigned int id; /* id of VerseLink */
+ unsigned int target_id; /* some unknow id */
+ char *label; /* name/label of VerseLink */
+ /* blender internals */
+ char flag; /* flags: LINK_SEND_READY */
+ /* client dependent methods */
+ void (*post_link_set)(struct VLink *vlink);
+ void (*post_link_destroy)(struct VLink *vlink);
+} VLink;
+
+/*
+ * bitmap layer
+ */
+typedef struct VBitmapLayer {
+ struct VBitmapLayer *next, *prev;
+ /* verse data */
+ struct VNode *vnode; /* pointer at Verse Node */
+ VLayerID id; /* id of layer */
+ char *name; /* name of layer */
+ VNBLayerType type; /* type of layer (bits per channel) 1, 8, 16, 32, 64 */
+ void *data; /* dynamic allocated data */
+ /* blender internals */
+ char flag;
+} VBitmapLayer;
+
+/*
+ * data of bitmap node
+ */
+typedef struct VBitmapData {
+ struct DynamicList layers; /* dynamic list with access array of bitmap layers */
+ struct ListBase queue; /* queue of layers waiting for receiving from verse server */
+ uint16 width; /* width of all verse layers */
+ uint16 height; /* height of all verse layers */
+ uint16 depth; /* depth of bitmap 1 is 2D bitmap, >1 is 3D bitmap */
+ /* blender internals */
+ uint16 t_width; /* = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */
+ uint16 t_height; /* = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */
+ void *image; /* pointer at image */
+ /* client dependent methods */
+ void (*post_bitmap_dimension_set)(struct VNode *vnode);
+ void (*post_bitmap_layer_create)(struct VBitmapLayer *vblayer);
+ void (*post_bitmap_layer_destroy)(struct VBitmapLayer *vblayer);
+ void (*post_bitmap_tile_set)(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys);
+}VBitmapData;
+
+/*
+ * data of geometry node
+ */
+typedef struct VGeomData {
+ struct DynamicList layers; /* dynamic list with access array of Layers */
+ struct VLink *vlink; /* pointer at VerseLink connecting object node and geom node */
+ struct ListBase queue; /* queue of our layers waiting for receiving from verse server */
+ void *mesh; /* pointer at Mesh (object node) */
+ void *editmesh; /* pointer at EditMesh (edit mode) */
+ struct HashVerseEdge *hash; /* verse edge hash */
+ struct ListBase edges; /* list of fake verse edges */
+ /* client dependent methods */
+ void (*post_vertex_create)(struct VerseVert *vvert);
+ void (*post_vertex_set_xyz)(struct VerseVert *vvert);
+ void (*post_vertex_delete)(struct VerseVert *vvert);
+ void (*post_vertex_free_constraint)(struct VerseVert *vvert);
+ void (*post_polygon_create)(struct VerseFace *vface);
+ void (*post_polygon_set_corner)(struct VerseFace *vface);
+ void (*post_polygon_delete)(struct VerseFace *vface);
+ void (*post_polygon_free_constraint)(struct VerseFace *vface);
+ void (*post_geometry_free_constraint)(struct VNode *vnode);
+ void (*post_polygon_set_uint8)(struct VerseFace *vface);
+} VGeomData;
+
+/*
+ * data of object node
+ */
+typedef struct VObjectData {
+ struct DynamicList links; /* dynamic list with access array of links between other nodes */
+ struct ListBase queue; /* queue of links waiting for sending and receiving from verse server */
+ float pos[3]; /* position of object VerseNode */
+ float quat[4]; /* rotation of object VerseNode stored in quat */
+ float scale[3]; /* scale of object VerseNode */
+ void *object; /* pointer at object */
+ short flag; /* flag: POS_RECEIVE_READY, ROT_RECEIVE_READY. SCALE_RECEIVE_READY */
+ /* client dependent methods */
+/* void (*post_transform)(struct VNode *vnode);*/
+ void (*post_transform_pos)(struct VNode *vnode);
+ void (*post_transform_rot)(struct VNode *vnode);
+ void (*post_transform_scale)(struct VNode *vnode);
+ void (*post_object_free_constraint)(struct VNode *vnode);
+} VObjectData;
+
+/*
+ * Verse Tag
+ */
+typedef struct VTag {
+ struct VTag *next, *prev;
+ /* verse data*/
+ struct VTagGroup *vtaggroup; /* pointer at Verse Tag Group */
+ uint16 id; /* id of this tag */
+ char *name; /* name of this tag*/
+ VNTagType type; /* type: VN_TAG_BOOLEAN, VN_TAG_UINT32, VN_TAG_REAL64, VN_TAG_REAL64_VEC3,
+ VN_TAG_LINK, VN_TAG_ANIMATION, VN_TAG_BLOB */
+ VNTag *tag; /* pointer at value (enum: vboolean, vuint32, vreal64, vstring,
+ vreal64_vec3, vlink, vanimation, vblob)*/
+ /* blender internals */
+ void *value; /* pointer at blender value */
+} VTag;
+
+/*
+ * Verse Tag Group (verse tags are grouped in tag groups)
+ */
+typedef struct VTagGroup {
+ struct VTagGroup *next, *prev;
+ /* verse data*/
+ struct VNode *vnode; /* pointer at Verse Node */
+ uint16 id; /* id of this tag group */
+ char *name; /* name of this tag group */
+ /* blender internals */
+ struct DynamicList tags; /* dynamic list with access array containing tags */
+ struct ListBase queue; /* list of tags waiting for receiving from verse server */
+ /* client dependent methods */
+ void (*post_tag_change)(struct VTag *vatg);
+ void (*post_taggroup_create)(struct VTagGroup *vtaggroup);
+} VTagGroup;
+
+ /*
+ * Verse Method Group
+ */
+typedef struct VMethodGroup
+{
+ struct VMethodGroup *next, *prev;
+ uint16 group_id;
+ char name[16];
+ struct ListBase methods;
+} VMethodGroup;
+
+/*
+ * Verse Method
+ */
+typedef struct VMethod
+{
+ struct VMethod *next, *prev;
+ uint16 id;
+ char name[500];
+ uint8 param_count;
+ VNOParamType *param_type;
+ char **param_name;
+} VMethod;
+
+/*
+ * Verse Node
+ */
+typedef struct VNode {
+ struct VNode *next, *prev;
+ /* verse data*/
+ struct VerseSession *session; /* session pointer */
+ VNodeID id; /* node id */
+ VNodeID owner_id; /* owner's id of this node */
+ char *name; /* name of this node */
+ uint32 type; /* type of node (V_NT_OBJECT, V_NT_GEOMETRY, V_NT_BITMAP) */
+ /* blender internals */
+ char flag; /* flags: NODE_SENT, NODE_RECEIVED, NODE_DELTED, NODE_OBSOLETE */
+ struct DynamicList taggroups; /* dynamic list with access array of taggroups */
+ struct ListBase methodgroups; /* method groups */
+ struct ListBase queue; /* list of taggroups waiting for receiving from verse server */
+ void *data; /* generic pointer at some data (VObjectData, VGeomData, ...) */
+ int counter; /* counter of verse link pointing at this vnode (vlink->target) */
+ /* client dependent methods */
+ void (*post_node_create)(struct VNode *vnode);
+ void (*post_node_destroy)(struct VNode *vnode);
+ void (*post_node_name_set)(struct VNode *vnode);
+#ifdef VERSECHAT
+ /* verse chat */
+ int chat_flag; /* CHAT_LOGGED, CHAT_NOTLOGGED */
+#endif
+} VNode;
+
+
+/*
+ * Verse Session: verse client can be connected to several verse servers
+ * it is neccessary to store some information about each session
+ */
+typedef struct VerseSession {
+ struct VerseSession *next, *prev;
+ /* verse data */
+ VSession *vsession; /* pointer at VSeesion (verse.h) */
+ uint32 avatar; /* id of avatar */
+ char *address; /* string containg IP/domain name of verse server and number of port */
+ void *connection; /* no clue */
+ uint8 *host_id; /* no clue */
+ /* blender internals */
+ short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */
+ DynamicList nodes; /* list of verse nodes */
+ ListBase queue; /* list of nodes waiting for sending to verse server */
+ unsigned int counter; /* count of events, when connection wasn't accepted */
+ /* client dependent methods */
+ void (*post_connect_accept)(struct VerseSession *session);
+ void (*post_connect_terminated)(struct VerseSession *session);
+ void (*post_connect_update)(struct VerseSession *session);
+} VerseSession;
+
+typedef struct VerseServer {
+ struct VerseServer *next, *prev;
+ char *name; /* human-readable server name */
+ char *ip; /* string containing IP/domain name of verse server and number of port */
+ short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */
+ struct VerseSession *session; /* pointer to related session */
+} VerseServer;
+/*
+ * list of post callback functions
+ */
+typedef struct PostCallbackFunction {
+ void (*function)(void *arg);
+ void *param;
+} PostCallbackFunction;
+
+/* VerseSession->flag */
+#define VERSE_CONNECTING 1
+#define VERSE_CONNECTED 2
+#define VERSE_AUTOSUBSCRIBE 4
+
+/* max VerseSession->counter value */
+#define MAX_UNCONNECTED_EVENTS 100
+
+/* VNode flags */
+#define NODE_SENT 1
+#define NODE_RECEIVED 2
+#define NODE_DELTED 4
+#define NODE_OBSOLETE 8
+
+#ifdef VERSECHAT
+#define CHAT_NOTLOGGED 0
+#define CHAT_LOGGED 1
+#endif
+
+/* VLayer flags */
+#define LAYER_SENT 1
+#define LAYER_RECEIVED 2
+#define LAYER_DELETED 4
+#define LAYER_OBSOLETE 8
+
+/* VLink->flag */
+#define LINK_SEND_READY 1
+
+/* VObjectData->flag */
+#define POS_RECEIVE_READY 1
+#define ROT_RECEIVE_READY 2
+#define SCALE_RECEIVE_READY 4
+#define POS_SEND_READY 8
+#define ROT_SEND_READY 16
+#define SCALE_SEND_READY 32
+
+/* VLayer->content */
+#define VERTEX_LAYER 0
+#define POLYGON_LAYER 1
+
+/* VerseVert->flag */
+#define VERT_DELETED 1 /* vertex delete command was received from verse server */
+#define VERT_RECEIVED 2 /* VerseVert was received from verse server (is not in sending queue) */
+#define VERT_LOCKED 4 /* VerseVert is ready to send local position to verse server */
+#define VERT_POS_OBSOLETE 8 /* position of vertex was changed during sending to verse server */
+#define VERT_OBSOLETE 16 /* vertex delete command was sent to verse server; it means, that
+ * no information related to this vertex shoudln't be sent to verse
+ * until verse vertex is completely deleted ... then this vertex id
+ * can be reused again for new vertex */
+
+/* VerseFace->flag */
+#define FACE_SEND_READY 1 /* VerseFace is ready for sending to verse server */
+#define FACE_RECEIVED 2 /* VerseFace was received from verse server */
+#define FACE_SENT 4 /* VerseFace was sent to verse server and we expect receiving from verse server */
+#define FACE_DELETED 8 /* delete command was sent to verse server */
+#define FACE_CHANGED 16 /* VerseFace was only changed not created */
+#define FACE_OBSOLETE 32 /* VerseFace was changed during sending to verse server */
+
+/* Queue type */
+#define VERSE_NODE 1
+#define VERSE_LINK 2
+#define VERSE_LAYER 3
+#define VERSE_VERT 4
+#define VERSE_FACE 5
+
+#define VERSE_TAG 6
+#define VERSE_TAG_GROUP 7
+
+#define VERSE_VERT_UINT32 8
+#define VERSE_VERT_REAL32 9
+#define VERSE_VERT_VEC_REAL32 10
+
+#define VERSE_FACE_UINT8 11
+#define VERSE_FACE_UINT32 12
+#define VERSE_FACE_REAL32 13
+#define VERSE_FACE_QUAT_UINT32 14
+#define VERSE_FACE_QUAT_REAL32 15
+
+/* Verse Bitmap Layer flags */
+#define VBLAYER_SUBSCRIBED 1
+
+/* function prototypes */
+
+/* functions from verse_session.c */
+void set_verse_session_callbacks(void);
+struct VerseSession *versesession_from_vsession(VSession *vsession);
+struct VerseSession *current_verse_session(void);
+struct VerseSession *create_verse_session(const char *name, const char *pass, const char *address, uint8 *expected_key);
+void free_verse_session(struct VerseSession *session);
+void b_verse_update(void);
+void b_verse_ms_get(void);
+void b_verse_connect(char *address);
+void end_verse_session(struct VerseSession *session);
+void end_all_verse_sessions(void);
+
+/* functions from verse_node.c */
+void send_verse_tag(struct VTag *vtag);
+void send_verse_taggroup(struct VTagGroup *vtaggroup);
+void send_verse_node(struct VNode *vnode);
+void free_verse_node_data(struct VNode *vnode);
+void free_verse_node(struct VNode *vnode);
+struct VNode* lookup_vnode(VerseSession *session, VNodeID node_id);
+struct VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id);
+void set_node_callbacks(void);
+
+/* functions from verse_object_node.c */
+struct VLink *find_unsent_parent_vlink(struct VerseSession *session, struct VNode *vnode);
+struct VLink *find_unsent_child_vlink(struct VerseSession *session, struct VNode *vnode);
+struct VLink *create_verse_link(VerseSession *session, struct VNode *source, struct VNode *target, uint16 link_id, uint32 target_id, const char *label);
+void send_verse_object_position(struct VNode *vnode);
+void send_verse_object_rotation(struct VNode *vnode);
+void send_verse_object_scale(struct VNode *vnode);
+void send_verse_link(struct VLink *vlink);
+
+void free_object_data(struct VNode *vnode);
+void set_object_callbacks(void);
+struct VObjectData *create_object_data(void);
+
+
+/* functions from verse_method.c */
+void free_verse_methodgroup(VMethodGroup *vmg);
+#ifdef VERSECHAT
+void send_say(const char *chan, const char *utter);
+void send_login(struct VNode *vnode);
+void send_logout(struct VNode *vnode);
+void send_join(struct VNode *vnode, const char *chan);
+void send_leave(struct VNode *vnode, const char *chan);
+#endif
+void set_method_callbacks(void);
+
+/* functions from verse_geometry_node.c */
+struct VerseFace* create_verse_face(struct VLayer *vlayer, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+struct VerseVert* create_verse_vertex(struct VLayer *vlayer, uint32 vertex_id, real32 x, real32 y, real32 z);
+struct VLayer *create_verse_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
+struct VGeomData *create_geometry_data(void);
+
+void send_verse_layer(struct VLayer *vlayer);
+
+void send_verse_face_corner_quat_real32(struct quat_real32_item *item, short type);
+void send_verse_face_corner_quat_uint32(struct quat_uint32_item *item, short type);
+void send_verse_face_real32(struct real32_item *item, short type);
+void send_verse_face_uint32(struct uint32_item *item, short type);
+void send_verse_face_uint8(struct uint8_item *item, short type);
+
+void send_verse_vert_vec_real32(struct vec_real32_item *item, short type);
+void send_verse_vert_real32(struct real32_item *item, short type);
+void send_verse_vert_uint32(struct uint32_item *item, short type);
+
+void send_verse_vertex_delete(struct VerseVert *vvert);
+void send_verse_vertex(struct VerseVert *vvert);
+void send_verse_face_delete(struct VerseFace *vface);
+
+void destroy_geometry(struct VNode *vnode);
+
+struct VLayer* find_verse_layer_type(struct VGeomData *geom, short content);
+void add_item_to_send_queue(struct ListBase *lb, void *item, short type);
+void free_geom_data(struct VNode *vnode);
+void set_geometry_callbacks(void);
+
+/* functions prototypes from verse_bitmap.c */
+void set_bitmap_callbacks(void);
+void free_bitmap_layer_data(struct VBitmapLayer *vblayer);
+struct VBitmapLayer *create_bitmap_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNBLayerType type);
+void free_bitmap_node_data(struct VNode *vnode);
+struct VBitmapData *create_bitmap_data(void);
+
+#endif
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index dbc990d0613..ae522b029cb 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -10,6 +10,7 @@ incs += ' #/intern/iksolver/extern ../blenloader'
incs += ' #/extern/bullet2/src'
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
incs += ' ../gpu #/extern/glew/include'
+incs += ' ../bmesh'
incs += ' ' + env['BF_OPENGL_INC']
incs += ' ' + env['BF_ZLIB_INC']
diff --git a/source/blender/blenkernel/intern/BME_conversions.c b/source/blender/blenkernel/intern/BME_conversions.c
index 177bb4a136b..0f372790a9d 100644
--- a/source/blender/blenkernel/intern/BME_conversions.c
+++ b/source/blender/blenkernel/intern/BME_conversions.c
@@ -268,7 +268,7 @@ BME_Mesh *BME_editmesh_to_bmesh(EditMesh *em) {
CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
- CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata);
+ CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
@@ -463,7 +463,7 @@ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
/*copy face corner data*/
- CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
+ CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata, 0, 0);
/*initialize memory pools*/
CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
@@ -475,10 +475,10 @@ BME_Mesh *BME_derivedmesh_to_bmesh(DerivedMesh *dm)
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
mvert = dm->getVertArray(dm);
medge = dm->getEdgeArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
vert_array = MEM_mallocN(sizeof(*vert_array)*totvert,"BME_derivedmesh_to_bmesh BME_Vert* array");
@@ -574,7 +574,8 @@ DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
}
/*convert back to mesh*/
- result = CDDM_from_template(dm,totvert,totedge,totface);
+ /*BMESH_TODO this should add in mloops and mpolys as well*/
+ result = CDDM_from_template(dm,totvert,totedge,totface, 0, 0);
CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
@@ -613,7 +614,7 @@ DerivedMesh *BME_bmesh_to_derivedmesh(BME_Mesh *bm, DerivedMesh *dm)
}
}
if(totface){
- mface = CDDM_get_faces(result);
+ mface = CDDM_get_tessfaces(result);
/*make faces*/
for(i=0,f=bm->polys.first;f;f=f->next){
mf = &mface[i];
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index cee032f364e..c2fc626b8e1 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -2035,7 +2035,7 @@ int ccgSubSurf_getNumVerts(CCGSubSurf *ss) {
int ccgSubSurf_getNumEdges(CCGSubSurf *ss) {
return ss->eMap->numEntries;
}
-int ccgSubSurf_getNumFaces(CCGSubSurf *ss) {
+int ccgSubSurf_getNumTessFaces(CCGSubSurf *ss) {
return ss->fMap->numEntries;
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index fbd0aecc0a5..c7716314899 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -73,7 +73,7 @@ CCGError ccgSubSurf_setCalcVertexNormals (CCGSubSurf *ss, int useVertNormals, i
int ccgSubSurf_getNumVerts (CCGSubSurf *ss);
int ccgSubSurf_getNumEdges (CCGSubSurf *ss);
-int ccgSubSurf_getNumFaces (CCGSubSurf *ss);
+int ccgSubSurf_getNumTessFaces (CCGSubSurf *ss);
int ccgSubSurf_getSubdivisionLevels (CCGSubSurf *ss);
int ccgSubSurf_getEdgeSize (CCGSubSurf *ss);
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 090f256ab9f..a1068080927 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -76,6 +76,7 @@
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
#include "BKE_bvhutils.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -124,9 +125,9 @@ static MFace *dm_getFaceArray(DerivedMesh *dm)
if (!mface) {
mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL,
- dm->getNumFaces(dm));
+ dm->getNumTessFaces(dm));
CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
- dm->copyFaceArray(dm, mface);
+ dm->copyTessFaceArray(dm, mface);
}
return mface;
@@ -154,40 +155,73 @@ static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
static MFace *dm_dupFaceArray(DerivedMesh *dm)
{
- MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm),
+ MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumTessFaces(dm),
"dm_dupFaceArray tmp");
- if(tmp) dm->copyFaceArray(dm, tmp);
+ if(tmp) dm->copyTessFaceArray(dm, tmp);
return tmp;
}
+CustomData *dm_getVertCData(DerivedMesh *dm)
+{
+ return &dm->vertData;
+}
+
+CustomData *dm_getEdgeCData(DerivedMesh *dm)
+{
+ return &dm->edgeData;
+}
+
+CustomData *dm_getFaceCData(DerivedMesh *dm)
+{
+ return &dm->faceData;
+}
+
+CustomData *dm_getLoopCData(DerivedMesh *dm)
+{
+ return &dm->loopData;
+}
+
+CustomData *dm_getPolyCData(DerivedMesh *dm)
+{
+ return &dm->polyData;
+}
+
void DM_init_funcs(DerivedMesh *dm)
{
/* default function implementations */
dm->getVertArray = dm_getVertArray;
dm->getEdgeArray = dm_getEdgeArray;
- dm->getFaceArray = dm_getFaceArray;
+ dm->getTessFaceArray = dm_getFaceArray;
dm->dupVertArray = dm_dupVertArray;
dm->dupEdgeArray = dm_dupEdgeArray;
- dm->dupFaceArray = dm_dupFaceArray;
+ dm->dupTessFaceArray = dm_dupFaceArray;
+
+ dm->getVertDataLayout = dm_getVertCData;
+ dm->getEdgeDataLayout = dm_getEdgeCData;
+ dm->getTessFaceDataLayout = dm_getFaceCData;
+ dm->getLoopDataLayout = dm_getLoopCData;
+ dm->getFaceDataLayout = dm_getPolyCData;
dm->getVertData = DM_get_vert_data;
dm->getEdgeData = DM_get_edge_data;
- dm->getFaceData = DM_get_face_data;
+ dm->getTessFaceData = DM_get_face_data;
dm->getVertDataArray = DM_get_vert_data_layer;
dm->getEdgeDataArray = DM_get_edge_data_layer;
- dm->getFaceDataArray = DM_get_face_data_layer;
+ dm->getTessFaceDataArray = DM_get_face_data_layer;
bvhcache_init(&dm->bvhCache);
}
-void DM_init(DerivedMesh *dm,
- int numVerts, int numEdges, int numFaces)
+void DM_init(DerivedMesh *dm, int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPoly)
{
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
dm->numFaceData = numFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPoly;
DM_init_funcs(dm);
@@ -195,7 +229,8 @@ void DM_init(DerivedMesh *dm,
}
void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
- int numVerts, int numEdges, int numFaces)
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys)
{
CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH,
CD_CALLOC, numVerts);
@@ -203,10 +238,16 @@ void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
CD_CALLOC, numEdges);
CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH,
CD_CALLOC, numFaces);
+ CustomData_copy(&source->loopData, &dm->loopData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, numLoops);
+ CustomData_copy(&source->polyData, &dm->polyData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, numPolys);
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
dm->numFaceData = numFaces;
+ dm->numLoopData = numLoops;
+ dm->numPolyData = numPolys;
DM_init_funcs(dm);
@@ -221,6 +262,8 @@ int DM_release(DerivedMesh *dm)
CustomData_free(&dm->vertData, dm->numVertData);
CustomData_free(&dm->edgeData, dm->numEdgeData);
CustomData_free(&dm->faceData, dm->numFaceData);
+ CustomData_free(&dm->loopData, dm->numLoopData);
+ CustomData_free(&dm->polyData, dm->numPolyData);
return 1;
}
@@ -228,28 +271,105 @@ int DM_release(DerivedMesh *dm)
CustomData_free_temporary(&dm->vertData, dm->numVertData);
CustomData_free_temporary(&dm->edgeData, dm->numEdgeData);
CustomData_free_temporary(&dm->faceData, dm->numFaceData);
+ CustomData_free_temporary(&dm->loopData, dm->numLoopData);
+ CustomData_free_temporary(&dm->polyData, dm->numPolyData);
return 0;
}
}
+void dm_add_polys_from_iter(CustomData *ldata, CustomData *pdata, DerivedMesh *dm, int totloop)
+{
+ DMFaceIter *iter = dm->newFaceIter(dm);
+ DMLoopIter *liter;
+ MPoly *mpoly;
+ MLoop *mloop;
+ int i;
+
+ mloop = MEM_callocN(sizeof(MLoop)*totloop, "MLoop from dm_add_polys_from_iter");
+ mpoly = MEM_callocN(sizeof(MPoly)*dm->getNumFaces(dm), "MPoly from dm_add_polys_from_iter");
+
+ CustomData_add_layer(ldata, CD_MLOOP, CD_ASSIGN, mloop, totloop);
+ CustomData_add_layer(pdata, CD_MPOLY, CD_ASSIGN, mpoly, dm->getNumFaces(dm));
+
+ i = 0;
+ for (; !iter->done; iter->step(iter), mpoly++) {
+ mpoly->flag = iter->flags;
+ mpoly->loopstart = i;
+ mpoly->totloop = iter->len;
+ mpoly->mat_nr = iter->mat_nr;
+
+ liter = iter->getLoopsIter(iter);
+ for (; !liter->done; liter->step(liter), mloop++, i++) {
+ mloop->v = liter->vindex;
+ mloop->e = liter->eindex;
+ }
+ }
+ iter->free(iter);
+}
+
+void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
+{
+ DMFaceIter *iter = source->newFaceIter(source);
+ DMLoopIter *liter;
+ MPoly *mpoly;
+ MLoop *mloop;
+ int i;
+
+ mloop = MEM_callocN(sizeof(MLoop)*source->numLoopData, "MLoop from dm_add_polys_from_iter");
+ mpoly = MEM_callocN(sizeof(MPoly)*source->getNumFaces(source), "MPoly from dm_add_polys_from_iter");
+
+ CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData);
+ CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->getNumFaces(source));
+
+ target->numLoopData = source->numLoopData;
+ target->numPolyData = source->numPolyData;
+
+ i = 0;
+ for (; !iter->done; iter->step(iter), mpoly++) {
+ mpoly->flag = iter->flags;
+ mpoly->loopstart = i;
+ mpoly->totloop = iter->len;
+ mpoly->mat_nr = iter->mat_nr;
+
+ liter = iter->getLoopsIter(iter);
+ for (; !liter->done; liter->step(liter), mloop++, i++) {
+ mloop->v = liter->vindex;
+ mloop->e = liter->eindex;
+ }
+ }
+ iter->free(iter);
+}
+
void DM_to_mesh(DerivedMesh *dm, Mesh *me)
{
/* dm might depend on me, so we need to do everything with a local copy */
Mesh tmp = *me;
- int totvert, totedge, totface;
+ DMFaceIter *iter;
+ int totvert, totedge, totface, totloop, totpoly;
memset(&tmp.vdata, 0, sizeof(tmp.vdata));
memset(&tmp.edata, 0, sizeof(tmp.edata));
memset(&tmp.fdata, 0, sizeof(tmp.fdata));
+ memset(&tmp.ldata, 0, sizeof(tmp.ldata));
+ memset(&tmp.pdata, 0, sizeof(tmp.pdata));
totvert = tmp.totvert = dm->getNumVerts(dm);
totedge = tmp.totedge = dm->getNumEdges(dm);
- totface = tmp.totface = dm->getNumFaces(dm);
+ totface = tmp.totface = dm->getNumTessFaces(dm);
+ totpoly = tmp.totpoly = dm->getNumFaces(dm);
+
+ totloop = 0;
+ for (iter=dm->newFaceIter(dm); !iter->done; iter->step(iter)) {
+ totloop += iter->len;
+ }
+ iter->free(iter);
CustomData_copy(&dm->vertData, &tmp.vdata, CD_MASK_MESH, CD_DUPLICATE, totvert);
CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge);
CustomData_copy(&dm->faceData, &tmp.fdata, CD_MASK_MESH, CD_DUPLICATE, totface);
+ CustomData_copy(&dm->loopData, &tmp.ldata, CD_MASK_MESH, CD_DUPLICATE, totloop);
+ CustomData_copy(&dm->polyData, &tmp.pdata, CD_MASK_MESH, CD_DUPLICATE, totpoly);
/* not all DerivedMeshes store their verts/edges/faces in CustomData, so
we set them here in case they are missing */
@@ -258,13 +378,18 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me)
if(!CustomData_has_layer(&tmp.edata, CD_MEDGE))
CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, dm->dupEdgeArray(dm), totedge);
if(!CustomData_has_layer(&tmp.fdata, CD_MFACE))
- CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupFaceArray(dm), totface);
+ CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupTessFaceArray(dm), totface);
+
+ if(!CustomData_has_layer(&tmp.fdata, CD_MPOLY))
+ dm_add_polys_from_iter(&tmp.ldata, &tmp.pdata, dm, totloop);
mesh_update_customdata_pointers(&tmp);
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
/* if the number of verts has changed, remove invalid data */
if(tmp.totvert != me->totvert) {
@@ -356,13 +481,27 @@ void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest,
source_index, dest_index, count);
}
-void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest,
+void DM_copy_tessface_data(DerivedMesh *source, DerivedMesh *dest,
int source_index, int dest_index, int count)
{
CustomData_copy_data(&source->faceData, &dest->faceData,
source_index, dest_index, count);
}
+void DM_copy_loop_data(DerivedMesh *source, DerivedMesh *dest,
+ int source_index, int dest_index, int count)
+{
+ CustomData_copy_data(&source->loopData, &dest->loopData,
+ source_index, dest_index, count);
+}
+
+void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest,
+ int source_index, int dest_index, int count)
+{
+ CustomData_copy_data(&source->polyData, &dest->polyData,
+ source_index, dest_index, count);
+}
+
void DM_free_vert_data(struct DerivedMesh *dm, int index, int count)
{
CustomData_free_elem(&dm->vertData, index, count);
@@ -373,11 +512,21 @@ void DM_free_edge_data(struct DerivedMesh *dm, int index, int count)
CustomData_free_elem(&dm->edgeData, index, count);
}
-void DM_free_face_data(struct DerivedMesh *dm, int index, int count)
+void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count)
{
CustomData_free_elem(&dm->faceData, index, count);
}
+void DM_free_loop_data(struct DerivedMesh *dm, int index, int count)
+{
+ CustomData_free_elem(&dm->loopData, index, count);
+}
+
+void DM_free_face_data(struct DerivedMesh *dm, int index, int count)
+{
+ CustomData_free_elem(&dm->polyData, index, count);
+}
+
void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest,
int *src_indices, float *weights,
int count, int dest_index)
@@ -395,7 +544,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)
@@ -404,11 +553,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, int *corner_indices)
+
+void DM_swap_tessface_data(DerivedMesh *dm, int index, int *corner_indices)
{
CustomData_swap(&dm->faceData, index, corner_indices);
}
+void DM_interp_loop_data(DerivedMesh *source, DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index)
+{
+ CustomData_interp(&source->loopData, &dest->loopData, src_indices,
+ weights, NULL, count, dest_index);
+}
+
+void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
+ int *src_indices,
+ float *weights, int count, int dest_index)
+{
+ CustomData_interp(&source->polyData, &dest->polyData, src_indices,
+ weights, NULL, count, dest_index);
+}
+
///
static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3])
@@ -437,9 +603,9 @@ typedef struct {
float (*faceNos)[3];
} EditMeshDerivedMesh;
-static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
+static void emDM_foreachMappedVert(void *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditVert *eve;
int i;
@@ -451,9 +617,9 @@ static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData,
}
}
}
-static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
+static void emDM_foreachMappedEdge(void *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditEdge *eed;
int i;
@@ -469,9 +635,9 @@ static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData,
func(userData, i, eed->v1->co, eed->v2->co);
}
}
-static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+static void emDM_drawMappedEdges(void *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditEdge *eed;
int i;
@@ -500,13 +666,13 @@ static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *us
glEnd();
}
}
-static void emDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
+static void emDM_drawEdges(void *dm, int drawLooseEdges)
{
emDM_drawMappedEdges(dm, NULL, NULL);
}
-static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData)
+static void emDM_drawMappedEdgesInterp(void *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditEdge *eed;
int i;
@@ -540,9 +706,9 @@ static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(vo
}
}
-static void emDM_drawUVEdges(DerivedMesh *dm)
+static void emDM_drawUVEdges(void *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditFace *efa;
MTFace *tf;
@@ -591,9 +757,9 @@ static void emDM__calcFaceCent(EditFace *efa, float cent[3], float (*vertexCos)[
VecMulf(cent, 0.33333333333f);
}
}
-static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
+static void emDM_foreachMappedFaceCenter(void *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditVert *eve;
EditFace *efa;
float cent[3];
@@ -609,9 +775,9 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use
func(userData, i, cent, emdm->vertexCos?emdm->faceNos[i]:efa->n);
}
}
-static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
+static void emDM_drawMappedFaces(void *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditFace *efa;
int i, draw;
@@ -696,12 +862,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
}
}
-static void emDM_drawFacesTex_common(DerivedMesh *dm,
+static void emDM_drawFacesTex_common(void *dm,
int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
int (*drawParamsMapped)(void *userData, int index),
void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditMesh *em= emdm->em;
float (*vertexCos)[3]= emdm->vertexCos;
float (*vertexNos)[3]= emdm->vertexNos;
@@ -864,21 +1030,21 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm,
}
}
-static void emDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+static void emDM_drawFacesTex(void *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
{
emDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
}
-static void emDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+static void emDM_drawMappedFacesTex(void *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
{
emDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
}
-static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
+static void emDM_drawMappedFacesGLSL(void *dm,
int (*setMaterial)(int, void *attribs),
int (*setDrawOptions)(void *userData, int index), void *userData)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditMesh *em= emdm->em;
float (*vertexCos)[3]= emdm->vertexCos;
float (*vertexNos)[3]= emdm->vertexNos;
@@ -1024,15 +1190,15 @@ static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
}
}
-static void emDM_drawFacesGLSL(DerivedMesh *dm,
+static void emDM_drawFacesGLSL(void *dm,
int (*setMaterial)(int, void *attribs))
{
- dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
+ ((DerivedMesh*)dm)->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
}
-static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+static void emDM_getMinMax(void *dm, float min_r[3], float max_r[3])
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditVert *eve;
int i;
@@ -1048,28 +1214,28 @@ static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
}
}
-static int emDM_getNumVerts(DerivedMesh *dm)
+static int emDM_getNumVerts(void *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
return BLI_countlist(&emdm->em->verts);
}
-static int emDM_getNumEdges(DerivedMesh *dm)
+static int emDM_getNumEdges(void *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
return BLI_countlist(&emdm->em->edges);
}
-static int emDM_getNumFaces(DerivedMesh *dm)
+static int emDM_getNumTessFaces(void *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
return BLI_countlist(&emdm->em->faces);
}
-static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+static void emDM_getVert(void *dm, int index, MVert *vert_r)
{
EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
int i;
@@ -1087,7 +1253,7 @@ static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
}
-static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+static void emDM_getEdge(void *dm, int index, MEdge *edge_r)
{
EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
EditEdge *ee = em->edges.first;
@@ -1122,7 +1288,7 @@ static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
}
}
-static void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+static void emDM_getFace(void *dm, int index, MFace *face_r)
{
EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
EditFace *ef = em->faces.first;
@@ -1164,7 +1330,7 @@ static void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
test_index_face(face_r, NULL, 0, ef->v4?4:3);
}
-static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
+static void emDM_copyVertArray(void *dm, MVert *vert_r)
{
EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
@@ -1182,7 +1348,7 @@ static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
}
}
-static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+static void emDM_copyEdgeArray(void *dm, MEdge *edge_r)
{
EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
EditEdge *ee = em->edges.first;
@@ -1210,7 +1376,7 @@ static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
}
}
-static void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+static void emDM_copyFaceArray(void *dm, MFace *face_r)
{
EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
EditFace *ef = em->faces.first;
@@ -1235,9 +1401,9 @@ static void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
}
}
-static void *emDM_getFaceDataArray(DerivedMesh *dm, int type)
+static void *emDM_getFaceDataArray(void *dm, int type)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
EditMesh *em= emdm->em;
EditFace *efa;
char *data, *emdata;
@@ -1258,8 +1424,8 @@ static void *emDM_getFaceDataArray(DerivedMesh *dm, int type)
size = CustomData_sizeof(type);
DM_add_face_layer(dm, type, CD_CALLOC, NULL);
- index = CustomData_get_layer_index(&dm->faceData, type);
- dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
+ index = CustomData_get_layer_index(&emdm->dm.faceData, type);
+ emdm->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) {
@@ -1272,9 +1438,9 @@ static void *emDM_getFaceDataArray(DerivedMesh *dm, int type)
return datalayer;
}
-static void emDM_release(DerivedMesh *dm)
+static void emDM_release(void *dm)
{
- EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMeshDerivedMesh *emdm= dm;
if (DM_release(dm)) {
if (emdm->vertexCos) {
@@ -1293,21 +1459,22 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob,
EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm");
DM_init(&emdm->dm, BLI_countlist(&em->verts),
- BLI_countlist(&em->edges), BLI_countlist(&em->faces));
+ BLI_countlist(&em->edges), BLI_countlist(&em->faces),
+ 0, 0);
emdm->dm.getMinMax = emDM_getMinMax;
emdm->dm.getNumVerts = emDM_getNumVerts;
emdm->dm.getNumEdges = emDM_getNumEdges;
- emdm->dm.getNumFaces = emDM_getNumFaces;
+ emdm->dm.getNumTessFaces = emDM_getNumTessFaces;
emdm->dm.getVert = emDM_getVert;
emdm->dm.getEdge = emDM_getEdge;
- emdm->dm.getFace = emDM_getFace;
+ emdm->dm.getTessFace = emDM_getFace;
emdm->dm.copyVertArray = emDM_copyVertArray;
emdm->dm.copyEdgeArray = emDM_copyEdgeArray;
- emdm->dm.copyFaceArray = emDM_copyFaceArray;
- emdm->dm.getFaceDataArray = emDM_getFaceDataArray;
+ emdm->dm.copyTessFaceArray = emDM_copyFaceArray;
+ emdm->dm.getTessFaceDataArray = emDM_getFaceDataArray;
emdm->dm.foreachMappedVert = emDM_foreachMappedVert;
emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
@@ -1417,37 +1584,36 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, Modifier
return dm;
}
-static float *get_editmesh_orco_verts(EditMesh *em)
+static float *get_editbmesh_orco_verts(BMEditMesh *em)
{
- EditVert *eve;
+ BMIter iter;
+ BMVert *eve;
float *orco;
int a, totvert;
/* these may not really be the orco's, but it's only for preview.
* could be solver better once, but isn't simple */
- totvert= 0;
- for(eve=em->verts.first; eve; eve=eve->next)
- totvert++;
+ totvert= em->bm->totvert;
orco = MEM_mallocN(sizeof(float)*3*totvert, "EditMesh Orco");
- for(a=0, eve=em->verts.first; eve; eve=eve->next, a+=3)
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (a=0; eve; eve=BMIter_Step(&iter), a+=3)
VECCOPY(orco+a, eve->co);
return orco;
}
/* orco custom data layer */
-
-static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em)
+static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em)
{
DerivedMesh *dm;
float (*orco)[3];
if(em) {
- dm= CDDM_from_editmesh(em, me);
- orco= (float(*)[3])get_editmesh_orco_verts(em);
+ dm= CDDM_from_BMEditMesh(em, me);
+ orco= (float(*)[3])get_editbmesh_orco_verts(em);
}
else {
dm= CDDM_from_mesh(me, ob);
@@ -1461,7 +1627,7 @@ static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em)
return dm;
}
-static void add_orco_dm(Object *ob, EditMesh *em, DerivedMesh *dm, DerivedMesh *orcodm)
+static void add_orco_dm(Object *ob, BMEditMesh *em, DerivedMesh *dm, DerivedMesh *orcodm)
{
float (*orco)[3], (*layerorco)[3];
int totvert;
@@ -1477,7 +1643,7 @@ static void add_orco_dm(Object *ob, EditMesh *em, DerivedMesh *dm, DerivedMesh *
dm->getVertCos(dm, orco);
}
else {
- if(em) orco= (float(*)[3])get_editmesh_orco_verts(em);
+ if(em) orco= (float(*)[3])get_editbmesh_orco_verts(em);
else orco= (float(*)[3])get_mesh_orco_verts(ob);
}
@@ -1839,21 +2005,24 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
BLI_linklist_free(datamasks, NULL);
}
-static float (*editmesh_getVertexCos(EditMesh *em, int *numVerts_r))[3]
+static float (*editbmesh_getVertexCos(BMEditMesh *em, int *numVerts_r))[3]
{
- int i, numVerts = *numVerts_r = BLI_countlist(&em->verts);
+ int i, numVerts = *numVerts_r = em->bm->totvert;
float (*cos)[3];
- EditVert *eve;
+ BMIter iter;
+ BMVert *eve;
cos = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos");
- for (i=0,eve=em->verts.first; i<numVerts; i++,eve=eve->next) {
+
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
VECCOPY(cos[i], eve->co);
}
return cos;
}
-static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm)
+static int editbmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm)
{
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
@@ -1867,7 +2036,7 @@ static int editmesh_modifier_is_enabled(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)
{
@@ -1882,7 +2051,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
modifiers_clearErrors(ob);
if(cage_r && cageIndex == -1) {
- *cage_r = getEditMeshDerivedMesh(em, ob, NULL);
+ *cage_r = getEditDerivedBMesh(em, ob, NULL);
}
dm = NULL;
@@ -1899,7 +2068,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
md->scene= scene;
- if(!editmesh_modifier_is_enabled(md, dm))
+ if(!editbmesh_modifier_is_enabled(md, dm))
continue;
/* add an orco layer if needed by this modifier */
@@ -1927,7 +2096,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_getVertexCos(em, &numVerts);
+ deformedVerts = editbmesh_getVertexCos(em, &numVerts);
}
}
@@ -1951,7 +2120,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);
if(deformedVerts) {
CDDM_apply_vert_coords(dm, deformedVerts);
@@ -2006,7 +2175,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
*cage_r = dm;
} else {
*cage_r =
- getEditMeshDerivedMesh(em, ob,
+ getEditDerivedBMesh(em, ob,
deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
}
}
@@ -2030,7 +2199,7 @@ static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, Deri
} else if (!deformedVerts && cage_r && *cage_r) {
*final_r = *cage_r;
} else {
- *final_r = getEditMeshDerivedMesh(em, ob, deformedVerts);
+ *final_r = getEditDerivedBMesh(em, ob, deformedVerts);
deformedVerts = NULL;
}
@@ -2100,7 +2269,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask 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)
{
float min[3], max[3];
@@ -2119,7 +2288,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);
em->lastDataMask = dataMask;
INIT_MINMAX(min, max);
@@ -2134,10 +2303,10 @@ static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, Cust
em->derivedCage->needsFree = 0;
}
-void makeDerivedMesh(Scene *scene, Object *ob, EditMesh *em, CustomDataMask dataMask)
+void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em, CustomDataMask dataMask)
{
if (em) {
- editmesh_build_data(scene, ob, em, dataMask);
+ editbmesh_build_data(scene, ob, em, dataMask);
} else {
mesh_build_data(scene, ob, dataMask);
}
@@ -2227,7 +2396,7 @@ DerivedMesh *mesh_create_derived_no_deform_render(Scene *scene, Object *ob,
/***/
-DerivedMesh *editmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, EditMesh *em, DerivedMesh **final_r,
+DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, BMEditMesh *em, DerivedMesh **final_r,
CustomDataMask dataMask)
{
/* if there's no derived mesh or the last data mask used doesn't include
@@ -2235,27 +2404,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 *obedit, EditMesh *em)
+DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em)
{
- return getEditMeshDerivedMesh(em, obedit, NULL);
+ return getEditDerivedBMesh(em, obedit, NULL);
}
@@ -2317,7 +2486,7 @@ float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
/* ********* crazyspace *************** */
-int editmesh_get_first_deform_matrices(Object *ob, EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3])
+int editbmesh_get_first_deform_matrices(Object *ob, BMEditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3])
{
ModifierData *md;
DerivedMesh *dm;
@@ -2336,13 +2505,13 @@ int editmesh_get_first_deform_matrices(Object *ob, EditMesh *em, float (**deform
for(i = 0; md && i <= cageIndex; i++, md = md->next) {
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if(!editmesh_modifier_is_enabled(md, dm))
+ if(!editbmesh_modifier_is_enabled(md, dm))
continue;
if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
if(!defmats) {
- dm= getEditMeshDerivedMesh(em, ob, NULL);
- deformedVerts= editmesh_getVertexCos(em, &numVerts);
+ dm= getEditDerivedBMesh(em, ob, NULL);
+ deformedVerts= editbmesh_getVertexCos(em, &numVerts);
defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
for(a=0; a<numVerts; a++)
@@ -2357,7 +2526,7 @@ int editmesh_get_first_deform_matrices(Object *ob, EditMesh *em, float (**deform
}
for(; md && i <= cageIndex; md = md->next, i++)
- if(editmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md))
+ if(editbmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md))
numleft++;
if(dm)
@@ -2389,11 +2558,11 @@ void DM_add_tangent_layer(DerivedMesh *dm)
/* 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);
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 6c1b8eb9000..7d9d261f306 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -68,6 +68,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -450,7 +451,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 lay, totvert, a, oblay;
@@ -459,11 +460,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);
@@ -566,34 +566,31 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
Scene *sce = NULL;
Group *group = NULL;
GroupObject *go = NULL;
- EditMesh *em;
+ BMEditMesh *em;
float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
/* simple preventing of too deep nested groups */
if(level>MAX_DUPLI_RECUR) return;
Mat4CpyMat4(pmat, par->obmat);
-
- em = BKE_mesh_get_editmesh(me);
+ em = me->edit_btmesh;
+
if(em) {
int totvert;
+ dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
- dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
-
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp");
- dm->copyFaceArray(dm, mface);
+ dm->copyTessFaceArray(dm, mface);
totvert= dm->getNumVerts(dm);
mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp");
dm->copyVertArray(dm, mvert);
-
- BKE_mesh_end_editmesh(me, em);
}
else {
dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
- totface= dm->getNumFaces(dm);
- mface= dm->getFaceArray(dm);
+ totface= dm->getNumTessFaces(dm);
+ mface= dm->getTessFaceArray(dm);
mvert= dm->getVertArray(dm);
}
diff --git a/source/blender/blenkernel/intern/booleanops.c b/source/blender/blenkernel/intern/booleanops.c
index eb3aefe7ee6..b6d1f7612b0 100644
--- a/source/blender/blenkernel/intern/booleanops.c
+++ b/source/blender/blenkernel/intern/booleanops.c
@@ -178,14 +178,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 */
@@ -259,7 +259,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;
}
@@ -309,8 +309,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;
@@ -358,7 +358,7 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
int i;
// create a new DerivedMesh
- result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements);
+ result = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements, 0, 0);
CustomData_merge(&dm1->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
CD_DEFAULT, face_it->num_elements);
CustomData_merge(&dm2->faceData, &result->faceData, CD_MASK_DERIVEDMESH,
@@ -398,16 +398,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];
@@ -440,6 +440,8 @@ static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
CDDM_calc_edges(result);
CDDM_calc_normals(result);
+ CDDM_tessfaces_to_faces(result);
+
return result;
}
@@ -473,7 +475,7 @@ 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),
@@ -505,7 +507,7 @@ 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();
@@ -559,7 +561,7 @@ int NewBooleanMesh(Scene *scene, Base *base, Base *base_select, int int_op_type)
/* put some checks in for nice user feedback */
if (dm == NULL || dm_select == NULL) return 0;
- if (!dm->getNumFaces(dm) || !dm_select->getNumFaces(dm_select))
+ if (!dm->getNumTessFaces(dm) || !dm_select->getNumTessFaces(dm_select))
{
MEM_freeN(mat);
return -1;
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index d9e005811d0..08bcd9c2820 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -532,7 +532,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;
}
@@ -549,9 +549,9 @@ BVHTree* bvhtree_from_mesh_faces(BVHTreeFromMesh *data, DerivedMesh *mesh, float
if(tree == NULL)
{
int i;
- int numFaces= mesh->getNumFaces(mesh);
+ int numFaces= mesh->getNumTessFaces(mesh);
MVert *vert = mesh->getVertDataArray(mesh, CD_MVERT);
- MFace *face = mesh->getFaceDataArray(mesh, CD_MFACE);
+ MFace *face = mesh->getTessFaceDataArray(mesh, CD_MFACE);
if(vert != NULL && face != NULL)
{
@@ -597,7 +597,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 706eece108c..120e1360d48 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -44,6 +44,7 @@
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
@@ -76,8 +77,12 @@ typedef struct {
MVert *mvert;
MEdge *medge;
MFace *mface;
+ MLoop *mloop;
+ MPoly *mpoly;
} CDDerivedMesh;
+DMFaceIter *cdDM_newFaceIter(DerivedMesh *source);
+
/**************** DerivedMesh interface functions ****************/
static int cdDM_getNumVerts(DerivedMesh *dm)
{
@@ -89,11 +94,16 @@ static int cdDM_getNumEdges(DerivedMesh *dm)
return dm->numEdgeData;
}
-static int cdDM_getNumFaces(DerivedMesh *dm)
+static int cdDM_getNumTessFaces(DerivedMesh *dm)
{
return dm->numFaceData;
}
+static int cdDM_getNumFaces(DerivedMesh *dm)
+{
+ return dm->numPolyData;
+}
+
static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
{
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
@@ -255,7 +265,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *a
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) { \
@@ -391,8 +401,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mv = cddm->mvert;
MFace *mf = cddm->mface;
- MCol *mcol = dm->getFaceDataArray(dm, CD_MCOL);
- float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ MCol *mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
@@ -483,7 +493,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
MVert *mv = cddm->mvert;
MFace *mf = cddm->mface;
MCol *mc;
- float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
@@ -574,11 +584,11 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
DMVertexAttribs attribs;
MVert *mvert = cddm->mvert;
MFace *mface = cddm->mface;
- MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
- float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
+ MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
+ float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
int a, b, dodraw, smoothnormal, matnr, new_matnr;
int transp, new_transp, orig_transp;
- int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
matnr = -1;
smoothnormal = 0;
@@ -769,37 +779,45 @@ 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);
-
- for(i = 0; i < dm->numFaceData; i++, mf++) {
+ MPoly *mf = cddm->mpoly;
+ MLoop *ml = cddm->mloop;
+ float (*cents)[3];
+ float (*nors)[3];
+ int *flens;
+ int i, j, orig, *index;
+ int maxf=0;
+
+ index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ mf = cddm->mpoly;
+ for(i = 0; i < dm->numPolyData; i++, mf++) {
float cent[3];
float no[3];
if (index) {
orig = *index++;
if(orig == ORIGINDEX_NONE) continue;
- }
- else
+ } else
orig = i;
+
+ ml = &cddm->mloop[mf->loopstart];
+ cent[0] = cent[1] = cent[2] = 0.0f;
+ for (j=0; j<mf->totloop; j++, ml++) {
+ VecAddf(cent, cent, mv[ml->v].co);
+ }
+ VecMulf(cent, 1.0f / (float)j);
- VECCOPY(cent, mv[mf->v1].co);
- VecAddf(cent, cent, mv[mf->v2].co);
- VecAddf(cent, cent, mv[mf->v3].co);
-
- if (mf->v4) {
- CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
- mv[mf->v3].co, mv[mf->v4].co, no);
- VecAddf(cent, cent, mv[mf->v4].co);
- VecMulf(cent, 0.25f);
+ ml = &cddm->mloop[mf->loopstart];
+ if (j > 3) {
+ CalcNormFloat4(mv[ml->v].co, mv[(ml+1)->v].co,
+ mv[(ml+2)->v].co, mv[(ml+3)->v].co, no);
} else {
- CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
- mv[mf->v3].co, no);
- VecMulf(cent, 0.33333333333f);
+ CalcNormFloat(mv[ml->v].co, mv[(ml+1)->v].co,
+ mv[(ml+2)->v].co, no);
}
func(userData, orig, cent, no);
}
+
}
static void cdDM_release(DerivedMesh *dm)
@@ -822,21 +840,24 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->getMinMax = cdDM_getMinMax;
dm->getNumVerts = cdDM_getNumVerts;
- dm->getNumFaces = cdDM_getNumFaces;
dm->getNumEdges = cdDM_getNumEdges;
+ dm->getNumTessFaces = cdDM_getNumTessFaces;
+ dm->getNumFaces = cdDM_getNumFaces;
+
+ dm->newFaceIter = cdDM_newFaceIter;
dm->getVert = cdDM_getVert;
dm->getEdge = cdDM_getEdge;
- dm->getFace = cdDM_getFace;
+ dm->getTessFace = cdDM_getFace;
dm->copyVertArray = cdDM_copyVertArray;
dm->copyEdgeArray = cdDM_copyEdgeArray;
- dm->copyFaceArray = cdDM_copyFaceArray;
+ dm->copyTessFaceArray = cdDM_copyFaceArray;
dm->getVertData = DM_get_vert_data;
dm->getEdgeData = DM_get_edge_data;
- dm->getFaceData = DM_get_face_data;
+ dm->getTessFaceData = DM_get_face_data;
dm->getVertDataArray = DM_get_vert_data_layer;
dm->getEdgeDataArray = DM_get_edge_data_layer;
- dm->getFaceDataArray = DM_get_face_data_layer;
+ dm->getTessFaceDataArray = DM_get_face_data_layer;
dm->getVertCos = cdDM_getVertCos;
dm->getVertCo = cdDM_getVertCo;
@@ -866,24 +887,29 @@ static CDDerivedMesh *cdDM_create(const char *desc)
return cddm;
}
-DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
+DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, int numLoops, int numPolys)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_new dm");
DerivedMesh *dm = &cddm->dm;
- DM_init(dm, numVerts, numEdges, numFaces);
+ DM_init(dm, numVerts, numEdges, numFaces, numLoops, numPolys);
CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+ CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, numPolys);
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+ CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+ CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
return dm;
}
@@ -898,11 +924,13 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
/* this does a referenced copy, the only new layers being ORIGINDEX,
* with an exception for fluidsim */
- DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface);
+ DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface,
+ mesh->totloop, mesh->totpoly);
CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+ CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totpoly);
dm->deformedOnly = 1;
@@ -914,10 +942,16 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
mesh->totedge);
CustomData_merge(&mesh->fdata, &dm->faceData, mask, 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->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);
index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX);
for(i = 0; i < mesh->totvert; ++i, ++index)
@@ -931,6 +965,10 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
for(i = 0; i < mesh->totface; ++i, ++index)
*index = i;
+ index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ for(i = 0; i < mesh->totpoly; ++i, ++index)
+ *index = i;
+
return dm;
}
@@ -938,7 +976,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
{
DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
BLI_countlist(&em->edges),
- BLI_countlist(&em->faces));
+ BLI_countlist(&em->faces), 0, 0);
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
EditVert *eve;
EditEdge *eed;
@@ -956,6 +994,8 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
CD_CALLOC, dm->numEdgeData); */
CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
CD_CALLOC, dm->numFaceData);
+ CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numFaceData);
/* set eve->hash to vert index */
for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
@@ -1012,7 +1052,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
/* CustomData_from_em_block(&em->edata, &dm->edgeData, eed->data, i); */
}
- index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
for(i = 0, efa = em->faces.first; i < dm->numFaceData;
i++, efa = efa->next, index++) {
MFace *mf = &mface[i];
@@ -1033,6 +1073,321 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
return dm;
}
+
+static void loops_to_customdata_corners(BMesh *bm, CustomData *facedata,
+ int cdindex, BMLoop *l3[3],
+ int numCol, int numTex)
+{
+ int i, j;
+ BMLoop *l;
+ BMFace *f = l3[0]->f;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ for (j=0; j<3; i++) {
+ l = l3[j];
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_n(facedata, CD_MCOL, cdindex, i);
+
+ for (j=0; j<3; j++) {
+ l = l3[j];
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ }
+ }
+}
+
+DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
+{
+ DerivedMesh *dm = CDDM_new(em->bm->totvert, em->bm->totedge,
+ em->tottri, em->bm->totloop, em->bm->totface);
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ BMesh *bm = em->bm;
+ BMIter iter, liter;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ MVert *mvert = cddm->mvert;
+ MEdge *medge = cddm->medge;
+ MFace *mface = cddm->mface;
+ MLoop *mloop = cddm->mloop;
+ MPoly *mpoly = cddm->mpoly;
+ int numCol = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
+ int numTex = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
+ int i, j, *index, add_orig;
+
+ dm->deformedOnly = 1;
+
+ /*don't add origindex layer if one already exists*/
+ add_orig = !CustomData_has_layer(&em->bm->pdata, CD_ORIGINDEX);
+
+ CustomData_merge(&em->bm->vdata, &dm->vertData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numVertData);
+ CustomData_merge(&em->bm->edata, &dm->edgeData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numEdgeData);
+ CustomData_merge(&em->bm->pdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numFaceData);
+ CustomData_merge(&em->bm->ldata, &dm->loopData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numLoopData);
+ CustomData_merge(&em->bm->pdata, &dm->polyData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numPolyData);
+
+ /*add tesselation mface and mcol layers as necassary*/
+ for (i=0; i<numTex; i++) {
+ CustomData_add_layer(&dm->faceData, CD_MTFACE, CD_CALLOC, NULL, em->tottri);
+ }
+
+ for (i=0; i<numCol; i++) {
+ CustomData_add_layer(&dm->faceData, CD_MCOL, CD_CALLOC, NULL, em->tottri);
+ }
+
+ /* set vert index */
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+
+ index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++, index++) {
+ MVert *mv = &mvert[i];
+
+ VECCOPY(mv->co, eve->co);
+
+ BMINDEX_SET(eve, i);
+
+ mv->no[0] = eve->no[0] * 32767.0;
+ mv->no[1] = eve->no[1] * 32767.0;
+ mv->no[2] = eve->no[2] * 32767.0;
+ mv->bweight = (unsigned char) (eve->bweight * 255.0f);
+
+ mv->mat_nr = 0;
+ mv->flag = BMFlags_To_MEFlags(eve);
+
+ if (add_orig) *index = i;
+
+ CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i);
+ }
+
+ index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for (i=0; eed; eed=BMIter_Step(&iter), i++, index++) {
+ MEdge *med = &medge[i];
+
+ BMINDEX_SET(eed, i);
+
+ med->v1 = BMINDEX_GET(eed->v1);
+ med->v2 = BMINDEX_GET(eed->v2);
+ med->crease = (unsigned char) (eed->crease * 255.0f);
+ med->bweight = (unsigned char) (eed->bweight * 255.0f);
+ med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+
+ med->flag = BMFlags_To_MEFlags(eed);
+
+ CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i);
+ if (add_orig) *index = i;
+ }
+
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; i++, efa=BMIter_Step(&iter)) {
+ BMINDEX_SET(efa, i);
+ }
+
+ index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ for(i = 0; i < dm->numFaceData; i++, index++) {
+ MFace *mf = &mface[i];
+ BMLoop **l = em->looptris[i];
+ efa = l[0]->f;
+
+ mf->v1 = BMINDEX_GET(l[0]->v);
+ mf->v2 = BMINDEX_GET(l[1]->v);
+ mf->v3 = BMINDEX_GET(l[2]->v);
+ mf->v4 = 0;
+ mf->mat_nr = efa->mat_nr;
+ mf->flag = BMFlags_To_MEFlags(efa);
+
+ *index = add_orig ? BMINDEX_GET(efa) : *(int*)CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_ORIGINDEX);
+
+ loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex);
+ test_index_face(mf, &dm->faceData, i, 3);
+ }
+
+ index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+ j = 0;
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; i++, efa=BMIter_Step(&iter), index++) {
+ BMLoop *l;
+ MPoly *mp = &mpoly[i];
+
+ mp->totloop = efa->len;
+ mp->flag = BMFlags_To_MEFlags(efa);
+ mp->loopstart = j;
+ mp->mat_nr = efa->mat_nr;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ mloop->v = BMINDEX_GET(l->v);
+ mloop->e = BMINDEX_GET(l->e);
+ CustomData_from_bmesh_block(&bm->ldata, &dm->loopData, l->head.data, j);
+
+ j++;
+ mloop++;
+ }
+
+ CustomData_from_bmesh_block(&bm->pdata, &dm->polyData, efa->head.data, i);
+
+ if (add_orig) *index = i;
+ }
+
+ return dm;
+}
+
+typedef struct CDDM_LoopIter {
+ DMLoopIter head;
+ CDDerivedMesh *cddm;
+ int len, i;
+} CDDM_LoopIter;
+
+typedef struct CDDM_FaceIter {
+ DMFaceIter head;
+ CDDerivedMesh *cddm;
+ CDDM_LoopIter liter;
+} CDDM_FaceIter;
+
+void cddm_freeiter(void *self)
+{
+ MEM_freeN(self);
+}
+
+void cddm_stepiter(void *self)
+{
+ CDDM_FaceIter *iter = self;
+ MPoly *mp;
+
+ iter->head.index++;
+ if (iter->head.index >= iter->cddm->dm.numPolyData) {
+ iter->head.done = 1;
+ return;
+ }
+
+ mp = iter->cddm->mpoly + iter->head.index;
+
+ iter->head.flags = mp->flag;
+ iter->head.mat_nr = mp->mat_nr;
+ iter->head.len = mp->totloop;
+}
+
+void *cddm_faceiter_getcddata(void *self, int type, int layer)
+{
+ CDDM_FaceIter *iter = self;
+
+ if (layer == -1) return CustomData_get(&iter->cddm->dm.polyData,
+ iter->head.index, type);
+ else return CustomData_get_n(&iter->cddm->dm.polyData, type,
+ iter->head.index, layer);
+}
+
+void *cddm_loopiter_getcddata(void *self, int type, int layer)
+{
+ CDDM_FaceIter *iter = self;
+
+ if (layer == -1) return CustomData_get(&iter->cddm->dm.loopData,
+ iter->head.index, type);
+ else return CustomData_get_n(&iter->cddm->dm.loopData, type,
+ iter->head.index, layer);
+}
+
+void *cddm_loopiter_getvertcddata(void *self, int type, int layer)
+{
+ CDDM_FaceIter *iter = self;
+
+ if (layer == -1) return CustomData_get(&iter->cddm->dm.vertData,
+ iter->cddm->mloop[iter->head.index].v,
+ type);
+ else return CustomData_get_n(&iter->cddm->dm.vertData, type,
+ iter->cddm->mloop[iter->head.index].v, layer);
+}
+
+DMLoopIter *cddmiter_get_loopiter(void *self)
+{
+ CDDM_FaceIter *iter = self;
+ CDDM_LoopIter *liter = &iter->liter;
+ MPoly *mp = iter->cddm->mpoly + iter->head.index;
+
+ liter->i = -1;
+ liter->len = iter->head.len;
+ liter->head.index = mp->loopstart-1;
+ liter->head.done = 0;
+
+ liter->head.step(liter);
+
+ return (DMLoopIter*) liter;
+}
+
+void cddm_loopiter_step(void *self)
+{
+ CDDM_LoopIter *liter = self;
+ MLoop *ml;
+
+ liter->i++;
+ liter->head.index++;
+
+ if (liter->i == liter->len) {
+ liter->head.done = 1;
+ return;
+ }
+
+ ml = liter->cddm->mloop + liter->head.index;
+
+ liter->head.eindex = ml->e;
+ liter->head.v = liter->cddm->mvert[ml->v];
+ liter->head.vindex = ml->v;
+}
+
+DMFaceIter *cdDM_newFaceIter(DerivedMesh *source)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) source;
+ CDDM_FaceIter *iter = MEM_callocN(sizeof(CDDM_FaceIter), "DMFaceIter from cddm");
+
+ iter->head.free = cddm_freeiter;
+ iter->head.step = cddm_stepiter;
+ iter->head.getCDData = cddm_faceiter_getcddata;
+ iter->head.getLoopsIter = cddmiter_get_loopiter;
+
+ iter->liter.head.step = cddm_loopiter_step;
+ iter->liter.head.getLoopCDData = cddm_loopiter_getcddata;
+ iter->liter.head.getVertCDData = cddm_loopiter_getvertcddata;
+ iter->liter.cddm = cddm;
+
+ iter->cddm = cddm;
+ iter->head.index = -1;
+ iter->head.step(iter);
+
+ return (DMFaceIter*) iter;
+}
+
DerivedMesh *CDDM_copy(DerivedMesh *source)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
@@ -1040,44 +1395,59 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
int numVerts = source->numVertData;
int numEdges = source->numEdgeData;
int numFaces = source->numFaceData;
+ int numLoops = source->numLoopData;
+ int numPolys = source->numPolyData;
/* this initializes dm, and copies all non mvert/medge/mface layers */
- DM_from_template(dm, source, numVerts, numEdges, numFaces);
+ DM_from_template(dm, source, numVerts, numEdges, numFaces,
+ 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->loopData, &dm->loopData, 0, 0, numLoops);
+ CustomData_copy_data(&source->polyData, &dm->polyData, 0, 0, numPolys);
/* 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);
+
+ DM_DupPolys(source, dm);
+
+ cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+ cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
return dm;
}
DerivedMesh *CDDM_from_template(DerivedMesh *source,
- int numVerts, int numEdges, int numFaces)
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys)
{
CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
DerivedMesh *dm = &cddm->dm;
/* this does a copy of all non mvert/medge/mface layers */
- DM_from_template(dm, source, numVerts, numEdges, numFaces);
+ DM_from_template(dm, source, numVerts, numEdges, numFaces, numLoops, numPolys);
/* now add mvert/medge/mface layers */
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+ CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+ CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
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;
}
@@ -1138,7 +1508,7 @@ void CDDM_calc_normals(DerivedMesh *dm)
NULL, dm->numFaceData);
/* calculate face normals and add to vertex normals */
- mf = CDDM_get_faces(dm);
+ mf = CDDM_get_tessfaces(dm);
for(i = 0; i < numFaces; i++, mf++) {
float *f_no = face_nors[i];
@@ -1263,7 +1633,7 @@ MEdge *CDDM_get_edge(DerivedMesh *dm, int index)
return &((CDDerivedMesh*)dm)->medge[index];
}
-MFace *CDDM_get_face(DerivedMesh *dm, int index)
+MFace *CDDM_get_tessface(DerivedMesh *dm, int index)
{
return &((CDDerivedMesh*)dm)->mface[index];
}
@@ -1278,11 +1648,85 @@ 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;
}
+void CDDM_tessfaces_to_faces(DerivedMesh *dm)
+{
+ /*converts mfaces to mpolys/mloops*/
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ MFace *mf;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ EdgeHash *eh = BLI_edgehash_new();
+ int i, l, totloop, *index1, *index2;
+
+ me = cddm->medge;
+ for (i=0; i<cddm->dm.numEdgeData; i++, me++) {
+ BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
+ }
+
+ mf = cddm->mface;
+ totloop = 0;
+ for (i=0; i<cddm->dm.numFaceData; i++, mf++) {
+ totloop += mf->v4 ? 4 : 3;
+ }
+
+ CustomData_free(&cddm->dm.polyData, cddm->dm.numPolyData);
+ CustomData_free(&cddm->dm.loopData, cddm->dm.numLoopData);
+
+ cddm->dm.numLoopData = totloop;
+ cddm->dm.numPolyData = cddm->dm.numFaceData;
+
+ if (!totloop) return;
+
+ cddm->mloop = MEM_callocN(sizeof(MLoop)*totloop, "cddm->mloop in CDDM_tessfaces_to_faces");
+ cddm->mpoly = MEM_callocN(sizeof(MPoly)*cddm->dm.numFaceData, "cddm->mpoly in CDDM_tessfaces_to_faces");
+
+ CustomData_add_layer(&cddm->dm.loopData, CD_MLOOP, CD_ASSIGN, cddm->mloop, totloop);
+ CustomData_add_layer(&cddm->dm.polyData, CD_MPOLY, CD_ASSIGN, cddm->mpoly, cddm->dm.numPolyData);
+ CustomData_merge(&cddm->dm.faceData, &cddm->dm.polyData,
+ CD_MASK_DERIVEDMESH, CD_DUPLICATE, cddm->dm.numFaceData);
+
+ index1 = CustomData_get_layer(&cddm->dm.faceData, CD_ORIGINDEX);
+ index2 = CustomData_get_layer(&cddm->dm.polyData, CD_ORIGINDEX);
+
+ mf = cddm->mface;
+ mp = cddm->mpoly;
+ ml = cddm->mloop;
+ l = 0;
+ for (i=0; i<cddm->dm.numFaceData; i++, mf++, mp++) {
+ mp->flag = mf->flag;
+ mp->loopstart = l;
+ mp->mat_nr = mf->mat_nr;
+ mp->totloop = mf->v4 ? 4 : 3;
+
+ ml->v = mf->v1;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2));
+ ml++, l++;
+
+ ml->v = mf->v2;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v2, mf->v3));
+ ml++, l++;
+
+ ml->v = mf->v3;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v3, mf->v4?mf->v4:mf->v1));
+ ml++, l++;
+
+ if (mf->v4) {
+ ml->v = mf->v4;
+ ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v4, mf->v1));
+ ml++, l++;
+ }
+
+ }
+
+ BLI_edgehash_free(eh, NULL);
+}
+
/* Multires DerivedMesh, extends CDDM */
typedef struct MultiresDM {
CDDerivedMesh cddm;
@@ -1337,7 +1781,9 @@ static void MultiresDM_release(DerivedMesh *dm)
}
}
-DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts, int numEdges, int numFaces)
+DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig,
+ int numVerts, int numEdges, int numFaces,
+ int numLoops, int numPolys)
{
MultiresDM *mrdm = MEM_callocN(sizeof(MultiresDM), "MultiresDM");
CDDerivedMesh *cddm = cdDM_create("MultiresDM CDDM");
@@ -1355,7 +1801,8 @@ DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts
MVert *mvert;
int i;
- DM_from_template(dm, orig, numVerts, numEdges, numFaces);
+ DM_from_template(dm, orig, numVerts, numEdges, numFaces,
+ numLoops, numPolys);
CustomData_free_layers(&dm->faceData, CD_MDISPS, numFaces);
disps = CustomData_get_layer(&orig->faceData, CD_MDISPS);
@@ -1369,7 +1816,7 @@ DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts
VecCopyf(mrdm->orco[i], mvert[i].co);
}
else
- DM_init(dm, numVerts, numEdges, numFaces);
+ DM_init(dm, numVerts, numEdges, numFaces, numLoops, numPolys);
CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
@@ -1472,3 +1919,4 @@ void MultiresDM_mark_as_modified(DerivedMesh *dm)
{
((MultiresDM*)dm)->modified = 1;
}
+
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index 089dafeb8c7..b16a046cd58 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -1017,8 +1017,8 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
static void cloth_from_mesh ( Object *ob, ClothModifierData *clmd, DerivedMesh *dm )
{
unsigned int numverts = dm->getNumVerts ( dm );
- unsigned int numfaces = dm->getNumFaces ( dm );
- MFace *mface = CDDM_get_faces(dm);
+ unsigned int numfaces = dm->getNumTessFaces ( dm );
+ MFace *mface = CDDM_get_tessfaces(dm);
unsigned int i = 0;
/* Allocate our vertices. */
@@ -1130,9 +1130,9 @@ int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
int i = 0;
int numverts = dm->getNumVerts ( dm );
int numedges = dm->getNumEdges ( dm );
- int numfaces = dm->getNumFaces ( dm );
+ int numfaces = dm->getNumTessFaces ( dm );
MEdge *medge = CDDM_get_edges ( dm );
- MFace *mface = CDDM_get_faces ( dm );
+ MFace *mface = CDDM_get_tessfaces ( dm );
int index2 = 0; // our second vertex index
LinkNode **edgelist = NULL;
EdgeHash *edgehash = NULL;
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 88e73a00ba7..f1420db706f 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -66,6 +66,7 @@
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_idprop.h"
+#include "BKE_mesh.h"
#include "BKE_shrinkwrap.h"
#include "BKE_mesh.h"
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 705d0b66d7f..0173e660e18 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -45,6 +45,8 @@
#include "MEM_guardedalloc.h"
+#include "bmesh.h"
+
#include <math.h>
#include <string.h>
@@ -257,6 +259,7 @@ static void layerInterp_tface(void **sources, float *weights,
}
*tf = *(MTFace *)sources[0];
+
for(j = 0; j < 4; ++j) {
tf->uv[j][0] = uv[j][0];
tf->uv[j][1] = uv[j][1];
@@ -726,6 +729,8 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL},
{sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
+ {sizeof(MPoly), "MPoly", 1, "NGon Face", NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MLoop), "MLoop", 1, "NGon Face-Vertex", NULL, NULL, NULL, NULL, NULL},
};
const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -735,19 +740,22 @@ const char *LAYERTYPENAMES[CD_NUMTYPES] = {
"CDMloopCol", "CDTangent", "CDMDisps", "CDWeightMCol"};
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_MPOLY;
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
- CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
+ CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
+ CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP;
const CustomDataMask CD_MASK_EDITMESH =
- CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV |
+ CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
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_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL;
-const CustomDataMask CD_MASK_BMESH =
+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;
const CustomDataMask CD_MASK_FACECORNERS =
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
@@ -800,7 +808,7 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
if(layer->flag & CD_FLAG_NOCOPY) continue;
else if(!((int)mask & (int)(1 << (int)type))) continue;
- else if(number < CustomData_number_of_layers(dest, type)) continue;
+ else if(number+1 < CustomData_number_of_layers(dest, type)) continue;
if((alloctype == CD_ASSIGN) && (layer->flag & CD_FLAG_NOFREE))
newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE,
@@ -1480,6 +1488,19 @@ void *CustomData_get(const CustomData *data, int index, int type)
return (char *)data->layers[layer_index].data + offset;
}
+void *CustomData_get_n(const CustomData *data, int type, int index, int n)
+{
+ int layer_index;
+ int offset;
+
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ offset = layerType_getInfo(type)->size * index;
+ return (char *)data->layers[layer_index].data + offset;
+}
+
void *CustomData_get_layer(const CustomData *data, int type)
{
/* get the layer index of the active layer of type */
@@ -1814,16 +1835,17 @@ void CustomData_from_em_block(const CustomData *source, CustomData *dest,
/*Bmesh functions*/
/*needed to convert to/from different face reps*/
-void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata)
+void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata,
+ int totloop, int totpoly)
{
int i;
for(i=0; i < fdata->totlayer; i++){
if(fdata->layers[i].type == CD_MTFACE){
- CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), 0);
- CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), 0);
+ CustomData_add_layer(pdata, CD_MTEXPOLY, CD_CALLOC, &(fdata->layers[i].name), totpoly);
+ CustomData_add_layer(ldata, CD_MLOOPUV, CD_CALLOC, &(fdata->layers[i].name), totloop);
}
else if(fdata->layers[i].type == CD_MCOL)
- CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), 0);
+ CustomData_add_layer(ldata, CD_MLOOPCOL, CD_CALLOC, &(fdata->layers[i].name), totloop);
}
}
void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *pdata, CustomData *ldata, int total){
@@ -1843,6 +1865,54 @@ void CustomData_bmesh_init_pool(CustomData *data, int allocsize){
if(data->totlayer)data->pool = BLI_mempool_create(data->totsize, allocsize, allocsize);
}
+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 i, t;
+
+ CustomData_merge(source, dest, mask, alloctype, 0);
+ CustomData_bmesh_init_pool(dest, 512);
+
+ switch (type) {
+ case BM_VERT:
+ t = BM_VERTS_OF_MESH; break;
+ case BM_EDGE:
+ t = BM_EDGES_OF_MESH; break;
+ case BM_LOOP:
+ t = BM_LOOPS_OF_FACE; break;
+ case BM_FACE:
+ t = BM_FACES_OF_MESH; break;
+ }
+
+ if (t != BM_LOOPS_OF_FACE) {
+ /*ensure all current elements follow new customdata layout*/
+ BM_ITER(h, &iter, bm, t, NULL) {
+ CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
+ CustomData_bmesh_free_block(&destold, &h->data);
+ h->data = tmp;
+ }
+ } else {
+ BMFace *f;
+ BMLoop *l;
+ BMIter liter;
+
+ /*ensure all current elements follow new customdata layout*/
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp);
+ CustomData_bmesh_free_block(&destold, &h->data);
+ h->data = tmp;
+ }
+ }
+ }
+
+ if (destold.pool) BLI_mempool_destroy(destold.pool);
+}
+
void CustomData_bmesh_free_block(CustomData *data, void **block)
{
const LayerTypeInfo *typeInfo;
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index cdf4b90cee1..3136630ce93 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -526,10 +526,10 @@ static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, un
dm = mesh_get_derived_final(RE_GetScene(re), ob, dataMask);
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
- nors = dm->getFaceDataArray(dm, CD_NORMAL);
+ mface = dm->getTessFaceArray(dm);
+ nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
totvert = dm->getNumVerts(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
orco= dm->getVertDataArray(dm, CD_ORCO);
if (onlyForMesh) {
diff --git a/source/blender/blenkernel/intern/editderivedbmesh.c b/source/blender/blenkernel/intern/editderivedbmesh.c
new file mode 100644
index 00000000000..fa9747ec54f
--- /dev/null
+++ b/source/blender/blenkernel/intern/editderivedbmesh.c
@@ -0,0 +1,1526 @@
+/**
+ * $Id: editderivedbmesh.c 18571 2009-01-19 06:04:57Z joeedh $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Tbmple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "PIL_time.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_effect_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // N_T
+#include "DNA_scene_types.h" // N_T
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_particle_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+#include "BLI_scanfill.h"
+#include "BLI_ghash.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_fluidsim.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_particle.h"
+#include "BKE_tessmesh.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_material.h"
+
+#include "bmesh.h"
+
+BMEditMesh *BMEdit_Create(BMesh *bm)
+{
+ BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), "tm");
+
+ tm->bm = bm;
+
+ BMEdit_RecalcTesselation(tm);
+
+ return tm;
+}
+
+BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
+{
+ BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), "tm2");
+ *tm2 = *tm;
+
+ tm2->derivedCage = tm2->derivedFinal = NULL;
+
+ tm2->looptris = NULL;
+ tm2->bm = BM_Copy_Mesh(tm->bm);
+ BMEdit_RecalcTesselation(tm2);
+
+ tm2->vert_index = NULL;
+ tm2->edge_index = NULL;
+ tm2->face_index = NULL;
+
+ return tm2;
+}
+
+static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm)
+{
+ BMesh *bm = tm->bm;
+ BMLoop **looptris = NULL;
+ V_DYNDECLARE(looptris);
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l;
+ int i = 0, j;
+
+ if (tm->looptris) MEM_freeN(tm->looptris);
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for ( ; f; f=BMIter_Step(&iter)) {
+ /*don't consider two-edged faces*/
+ if (f->len < 3) continue;
+
+ if (f->len <= 4) {
+ /*triangle fan for quads. should be recoded to
+ just add one tri for tris, and two for quads,
+ but this code works for now too.*/
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (l == f->loopbase) continue;
+ if ((BMLoop*)l->head.next == f->loopbase) continue;
+
+ V_GROW(looptris);
+ V_GROW(looptris);
+ V_GROW(looptris);
+
+ looptris[i*3] = l;
+ looptris[i*3+1] = (BMLoop*)l->head.next;
+ looptris[i*3+2] = f->loopbase;
+
+ i += 1;
+ }
+ } else {
+ /*scanfill time*/
+ EditVert *v, *lastv=NULL, *firstv=NULL;
+ EditEdge *e;
+ EditFace *efa;
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BMIter_Step(&liter), j++) {
+ /*mark order*/
+ l->head.eflag2 = j;
+
+ v = BLI_addfillvert(l->v->co);
+ v->tmp.p = l;
+
+ if (lastv) {
+ e = BLI_addfilledge(lastv, v);
+ }
+
+ lastv = v;
+ if (firstv==NULL) firstv = v;
+ }
+
+ /*complete the loop*/
+ BLI_addfilledge(firstv, v);
+
+ BLI_edgefill(0, 0);
+
+ for (efa = fillfacebase.first; efa; efa=efa->next) {
+ V_GROW(looptris);
+ V_GROW(looptris);
+ V_GROW(looptris);
+
+ looptris[i*3] = efa->v1->tmp.p;
+ looptris[i*3+1] = efa->v2->tmp.p;
+ looptris[i*3+2] = efa->v3->tmp.p;
+
+ if (looptris[i*3]->head.eflag2 > looptris[i*3+1]->head.eflag2);
+ SWAP(BMLoop*, looptris[i*3], looptris[i*3+1]);
+ if (looptris[i*3+1]->head.eflag2 > looptris[i*3+2]->head.eflag2);
+ SWAP(BMLoop*, looptris[i*3+1], looptris[i*3+2]);
+ if (looptris[i*3]->head.eflag2 > looptris[i*3+1]->head.eflag2);
+ SWAP(BMLoop*, looptris[i*3], looptris[i*3+1]);
+
+ i += 1;
+ }
+ BLI_end_edgefill();
+ }
+ }
+
+ tm->tottri = i;
+ tm->looptris = looptris;
+}
+
+void BMEdit_RecalcTesselation(BMEditMesh *tm)
+{
+ BMEdit_RecalcTesselation_intern(tm);
+
+ if (tm->derivedFinal && tm->derivedFinal == tm->derivedCage) {
+ if (tm->derivedFinal->recalcTesselation)
+ tm->derivedFinal->recalcTesselation(tm->derivedFinal);
+ } else if (tm->derivedFinal) {
+ if (tm->derivedCage->recalcTesselation)
+ tm->derivedCage->recalcTesselation(tm->derivedCage);
+ if (tm->derivedFinal->recalcTesselation)
+ tm->derivedFinal->recalcTesselation(tm->derivedFinal);
+ }
+}
+
+/*does not free the BMEditMesh struct itself*/
+void BMEdit_Free(BMEditMesh *em)
+{
+ if(em->derivedFinal) {
+ if (em->derivedFinal!=em->derivedCage) {
+ em->derivedFinal->needsFree= 1;
+ em->derivedFinal->release(em->derivedFinal);
+ }
+ em->derivedFinal= NULL;
+ }
+ if(em->derivedCage) {
+ em->derivedCage->needsFree= 1;
+ em->derivedCage->release(em->derivedCage);
+ em->derivedCage= NULL;
+ }
+
+ em->retopo_paint_data= NULL;
+
+ if (em->looptris) MEM_freeN(em->looptris);
+
+ if (em->vert_index) MEM_freeN(em->vert_index);
+ if (em->edge_index) MEM_freeN(em->edge_index);
+ if (em->face_index) MEM_freeN(em->face_index);
+
+ BM_Free_Mesh(em->bm);
+}
+
+
+/*
+ok, basic design:
+
+the bmesh derivedmesh exposes the mesh as triangles. it stores pointers
+to three loops per triangle. the derivedmesh stores a cache of tesselations
+for each face. this cache will smartly update as needed (though at first
+it'll simply be more brute force). keeping track of face/edge counts may
+be a small problbm.
+
+this won't be the most efficient thing, considering that internal edges and
+faces of tesselations are exposed. looking up an edge by index in particular
+is likely to be a little slow.
+*/
+
+typedef struct EditDerivedBMesh {
+ DerivedMesh dm;
+
+ Object *ob;
+ BMEditMesh *tc;
+
+ float (*vertexCos)[3];
+ float (*vertexNos)[3];
+ float (*faceNos)[3];
+
+ /*lookup caches; these are rebuilt on dm->RecalcTesselation()
+ (or when the derivedmesh is created, of course)*/
+ GHash *vhash, *ehash, *fhash;
+ BMVert **vtable;
+ BMEdge **etable;
+ BMFace **ftable;
+
+ /*private variables, for number of verts/edges/faces
+ within the above hash/table members*/
+ int tv, te, tf;
+} EditDerivedBMesh;
+
+static void bmdm_recalc_lookups(EditDerivedBMesh *bmdm)
+{
+ BMIter iter;
+ BMHeader *h;
+ int a, i, iters[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+
+ bmdm->tv = bmdm->tc->bm->totvert;
+ bmdm->te = bmdm->tc->bm->totedge;
+ bmdm->tf = bmdm->tc->bm->totface;
+
+ if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
+ if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
+ if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
+
+ bmdm->vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ if (bmdm->vtable) MEM_freeN(bmdm->vtable);
+ if (bmdm->etable) MEM_freeN(bmdm->etable);
+ if (bmdm->ftable) MEM_freeN(bmdm->ftable);
+
+ if (bmdm->tc->bm->totvert)
+ bmdm->vtable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totvert, "bmdm->vtable");
+ else bmdm->vtable = NULL;
+
+ if (bmdm->tc->bm->totedge)
+ bmdm->etable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totedge, "bmdm->etable");
+ else bmdm->etable = NULL;
+
+ if (bmdm->tc->bm->totface)
+ bmdm->ftable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totface, "bmdm->ftable");
+ else bmdm->ftable = NULL;
+
+ for (a=0; a<3; a++) {
+ h = BMIter_New(&iter, bmdm->tc->bm, iters[a], NULL);
+ for (i=0; h; h=BMIter_Step(&iter), i++) {
+ switch (a) {
+ case 0:
+ bmdm->vtable[i] = (BMVert*) h;
+ BLI_ghash_insert(bmdm->vhash, h, SET_INT_IN_POINTER(i));
+ break;
+ case 1:
+ bmdm->etable[i] = (BMEdge*) h;
+ BLI_ghash_insert(bmdm->ehash, h, SET_INT_IN_POINTER(i));
+ break;
+ case 2:
+ bmdm->ftable[i] = (BMFace*) h;
+ BLI_ghash_insert(bmdm->fhash, h, SET_INT_IN_POINTER(i));
+ break;
+
+ }
+ }
+ }
+}
+
+static void bmDM_recalcTesselation(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ bmdm_recalc_lookups(bmdm);
+}
+
+static void bmDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; i++, eve=BMIter_Step(&iter)) {
+ if (bmdm->vertexCos) {
+ func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL);
+ } else {
+ func(userData, i, eve->co, eve->no, NULL);
+ }
+ }
+}
+static void bmDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+ BMIter viter;
+
+ eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&viter), i++) {
+ BMINDEX_SET(eve, i);
+ }
+
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter))
+ func(userData, i,
+ bmdm->vertexCos[BMINDEX_GET(eve)],
+ bmdm->vertexCos[BMINDEX_GET(eve)]);
+ } else {
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter))
+ func(userData, i, eed->v1->co, eed->v2->co);
+ }
+
+}
+
+static void bmDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+ BMIter viter;
+
+ eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&viter)) {
+ BMINDEX_SET(eve, i);
+ }
+
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v1)]);
+ glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v2)]);
+ }
+ }
+ glEnd();
+
+ } else {
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(eed->v1->co);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+static void bmDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
+{
+ bmDM_drawMappedEdges(dm, NULL, NULL);
+}
+
+static void bmDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMEdge *eed;
+ BMIter iter;
+ int i;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v1)]);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v2)]);
+ }
+ }
+ glEnd();
+ } else {
+ glBegin(GL_LINES);
+ eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
+ for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(eed->v1->co);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+static void bmDM_drawUVEdges(DerivedMesh *dm)
+{
+#if 0
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMFace *efa;
+ MTFace *tf;
+
+ glBegin(GL_LINES);
+ for(efa= bmdm->tc->bm->faces.first; efa; efa= efa->next) {
+ tf = CustomData_bm_get(&bmdm->tc->bm->pdata, efa->data, CD_MTFACE);
+
+ if(tf && !(efa->h)) {
+ glVertex2fv(tf->uv[0]);
+ glVertex2fv(tf->uv[1]);
+
+ glVertex2fv(tf->uv[1]);
+ glVertex2fv(tf->uv[2]);
+
+ if (!efa->v4) {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[0]);
+ } else {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[3]);
+ glVertex2fv(tf->uv[3]);
+ glVertex2fv(tf->uv[0]);
+ }
+ }
+ }
+ glEnd();
+#endif
+}
+
+static void bmDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3],
+ float (*vertexCos)[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ int tot = 0;
+
+ cent[0] = cent[1] = cent[2] = 0.0f;
+
+ /*simple (and stupid) median (average) based method :/ */
+
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&iter)) {
+ VECADD(cent, cent, l->v->co);
+ tot++;
+ }
+
+ if (tot==0) return;
+ VECMUL(cent, 1.0f/(float)tot);
+}
+
+static void bmDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMFace *efa;
+ BMIter iter;
+ float cent[3];
+ int i;
+
+ if (bmdm->vertexCos) {
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter));
+ BMINDEX_SET(eve, i);
+ }
+
+ efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BMIter_Step(&iter), i++) {
+ bmDM__calcFaceCent(bmdm->tc->bm, efa, cent, bmdm->vertexCos);
+ func(userData, i, cent, bmdm->vertexCos?bmdm->faceNos[i]:efa->no);
+ }
+}
+
+static void bmDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMFace *efa;
+ BMIter iter;
+ int i, draw;
+
+ if (bmdm->vertexCos) {
+ BMVert *eve;
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter))
+ BMINDEX_SET(eve, i);
+
+ efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BMIter_Step(&iter), i++)
+ BMINDEX_SET(efa, i);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ int drawSmooth;
+
+ drawSmooth = (efa->head.flag & BM_SMOOTH);
+ efa = l[0]->f;
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth);
+ if(draw) {
+ if (draw==2) { /* enabled with stipple */
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_quarttone);
+ }
+
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(GL_TRIANGLES);
+
+ if (!drawSmooth) {
+ glNormal3fv(efa->no);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]);
+ } else {
+ glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[0]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]);
+ glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[1]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]);
+ glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[2]->v)]);
+ glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]);
+ }
+ glEnd();
+
+ if (draw==2)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ } else {
+ efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
+ for (i=0; efa; efa=BMIter_Step(&iter), i++)
+ BMINDEX_SET(efa, i);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ int drawSmooth;
+
+ efa = l[0]->f;
+
+ drawSmooth = (efa->head.flag & BM_SMOOTH);
+
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth);
+ if(draw) {
+ if (draw==2) { /* enabled with stipple */
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(stipple_quarttone);
+ }
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(efa->no);
+ glVertex3fv(l[0]->v->co);
+ glVertex3fv(l[1]->v->co);
+ glVertex3fv(l[2]->v->co);
+ } else {
+ glNormal3fv(l[0]->v->no);
+ glVertex3fv(l[0]->v->co);
+ glNormal3fv(l[1]->v->no);
+ glVertex3fv(l[1]->v->co);
+ glNormal3fv(l[2]->v->no);
+ glVertex3fv(l[2]->v->co);
+ }
+ glEnd();
+
+ if (draw==2)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ }
+}
+
+static void bmDM_drawFacesTex_common(DerivedMesh *dm,
+ int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
+ int (*drawParamsMapped)(void *userData, int index),
+ void *userData)
+{
+#if 0
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMFace *efa;
+ BMIter iter;
+ int i;
+
+ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
+ glShadeModel(GL_SMOOTH);
+
+ if (vertexCos) {
+ BMVert *eve;
+
+ for (i=0,eve=bm->verts.first; eve; eve= eve->next)
+ BMINDEX_SET(eve, i++);
+
+ for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) {
+ MTFace *tf= CustomData_bm_get(&bm->pdata, efa->data, CD_MTFACE);
+ MCol *mcol= CustomData_bm_get(&bm->pdata, efa->data, CD_MCOL);
+ unsigned char *cp= NULL;
+ int drawSmooth= (efa->flag & ME_SMOOTH);
+ int flag;
+
+ if(drawParams)
+ flag= drawParams(tf, mcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, i);
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+
+ /* we always want smooth here since otherwise vertex colors dont interpolate */
+ if (mcol) {
+ if (flag==1) {
+ cp= (unsigned char*)mcol;
+ }
+ } else {
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ }
+
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(bmdm->faceNos[i]);
+
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ }
+ } else {
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ }
+ }
+ glEnd();
+ }
+ }
+ } else {
+ for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) {
+ MTFace *tf= CustomData_bm_get(&bm->pdata, efa->data, CD_MTFACE);
+ MCol *mcol= CustomData_bm_get(&bm->pdata, efa->data, CD_MCOL);
+ unsigned char *cp= NULL;
+ int drawSmooth= (efa->flag & ME_SMOOTH);
+ int flag;
+
+ if(drawParams)
+ flag= drawParams(tf, mcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, i);
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+ /* we always want smooth here since otherwise vertex colors dont interpolate */
+ if (mcol) {
+ if (flag==1) {
+ cp= (unsigned char*)mcol;
+ }
+ } else {
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ }
+
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(efa->n);
+
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(efa->v1->co);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glVertex3fv(efa->v2->co);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glVertex3fv(efa->v3->co);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glVertex3fv(efa->v4->co);
+ }
+ } else {
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glNormal3fv(efa->v1->no);
+ glVertex3fv(efa->v1->co);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glNormal3fv(efa->v2->no);
+ glVertex3fv(efa->v2->co);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glNormal3fv(efa->v3->no);
+ glVertex3fv(efa->v3->co);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glNormal3fv(efa->v4->no);
+ glVertex3fv(efa->v4->co);
+ }
+ }
+ glEnd();
+ }
+ }
+ }
+#endif
+}
+
+static void bmDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+{
+ bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+}
+
+static void bmDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+}
+
+static void bmDM_drawMappedFacesGLSL(DerivedMesh *dm,
+ int (*setMaterial)(int, void *attribs),
+ int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+#if 0
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ float (*vertexCos)[3]= bmdm->vertexCos;
+ float (*vertexNos)[3]= bmdm->vertexNos;
+ BMVert *eve;
+ BMFace *efa;
+ DMVertexAttribs attribs;
+ GPUVertexAttribs gattribs;
+ MTFace *tf;
+ int transp, new_transp, orig_transp, tfoffset;
+ int i, b, matnr, new_matnr, dodraw, layer;
+
+ dodraw = 0;
+ matnr = -1;
+
+ transp = GPU_get_material_blend_mode();
+ orig_transp = transp;
+ layer = CustomData_get_layer_index(&bm->pdata, CD_MTFACE);
+ tfoffset = (layer == -1)? -1: bm->pdata.layers[layer].offset;
+
+ memset(&attribs, 0, sizeof(attribs));
+
+ /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
+ glShadeModel(GL_SMOOTH);
+
+ for (i=0,eve=bm->verts.first; eve; eve= eve->next)
+ BMINDEX_SET(eve, i++);
+
+#define PASSATTRIB(efa, eve, vert) { \
+ if(attribs.totorco) { \
+ float *orco = attribs.orco.array[BMINDEX_GET(eve)]; \
+ glVertexAttrib3fvARB(attribs.orco.glIndex, orco); \
+ } \
+ for(b = 0; b < attribs.tottface; b++) { \
+ MTFace *_tf = (MTFace*)((char*)efa->data + attribs.tface[b].bmOffset); \
+ glVertexAttrib2fvARB(attribs.tface[b].glIndex, _tf->uv[vert]); \
+ } \
+ for(b = 0; b < attribs.totmcol; b++) { \
+ MCol *cp = (MCol*)((char*)efa->data + attribs.mcol[b].bmOffset); \
+ GLubyte col[4]; \
+ col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a; \
+ glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col); \
+ } \
+ if(attribs.tottang) { \
+ float *tang = attribs.tang.array[i*4 + vert]; \
+ glVertexAttrib3fvARB(attribs.tang.glIndex, tang); \
+ } \
+}
+
+ for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) {
+ int drawSmooth= (efa->flag & ME_SMOOTH);
+
+ if(setDrawOptions && !setDrawOptions(userData, i))
+ continue;
+
+ new_matnr = efa->mat_nr + 1;
+ if(new_matnr != matnr) {
+ dodraw = setMaterial(matnr = new_matnr, &gattribs);
+ if(dodraw)
+ DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ }
+
+ if(tfoffset != -1) {
+ tf = (MTFace*)((char*)efa->data)+tfoffset;
+ new_transp = tf->transp;
+
+ if(new_transp != transp) {
+ if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
+ GPU_set_material_blend_mode(orig_transp);
+ else
+ GPU_set_material_blend_mode(new_transp);
+ transp = new_transp;
+ }
+ }
+
+ if(dodraw) {
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ if(vertexCos) glNormal3fv(bmdm->faceNos[i]);
+ else glNormal3fv(efa->n);
+
+ PASSATTRIB(efa, efa->v1, 0);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+ else glVertex3fv(efa->v1->co);
+
+ PASSATTRIB(efa, efa->v2, 1);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+ else glVertex3fv(efa->v2->co);
+
+ PASSATTRIB(efa, efa->v3, 2);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+ else glVertex3fv(efa->v3->co);
+
+ if(efa->v4) {
+ PASSATTRIB(efa, efa->v4, 3);
+ if(vertexCos) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ else glVertex3fv(efa->v4->co);
+ }
+ } else {
+ PASSATTRIB(efa, efa->v1, 0);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v1->no);
+ glVertex3fv(efa->v1->co);
+ }
+
+ PASSATTRIB(efa, efa->v2, 1);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v2->no);
+ glVertex3fv(efa->v2->co);
+ }
+
+ PASSATTRIB(efa, efa->v3, 2);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v3->no);
+ glVertex3fv(efa->v3->co);
+ }
+
+ if(efa->v4) {
+ PASSATTRIB(efa, efa->v4, 3);
+ if(vertexCos) {
+ glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ }
+ else {
+ glNormal3fv(efa->v4->no);
+ glVertex3fv(efa->v4->co);
+ }
+ }
+ }
+ glEnd();
+ }
+ }
+#endif
+}
+
+static void bmDM_drawFacesGLSL(DerivedMesh *dm,
+ int (*setMaterial)(int, void *attribs))
+{
+ dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
+}
+
+static void bmDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMVert *eve;
+ BMIter iter;
+ int i;
+
+ if (bmdm->tc->bm->verts.first) {
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ if (bmdm->vertexCos) {
+ DO_MINMAX(bmdm->vertexCos[i], min_r, max_r);
+ } else {
+ DO_MINMAX(eve->co, min_r, max_r);
+ }
+ }
+ } else {
+ min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
+ }
+}
+static int bmDM_getNumVerts(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totvert;
+}
+
+static int bmDM_getNumEdges(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totedge;
+}
+
+static int bmDM_getNumTessFaces(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->tottri;
+}
+
+static int bmDM_getNumFaces(DerivedMesh *dm)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+
+ return bmdm->tc->bm->totface;
+}
+
+static int bmvert_to_mvert(BMVert *ev, MVert *vert_r)
+{
+ VECCOPY(vert_r->co, ev->co);
+
+ vert_r->no[0] = (short)(ev->no[0] * 32767.0f);
+ vert_r->no[1] = (short)(ev->no[1] * 32767.0f);
+ vert_r->no[2] = (short)(ev->no[2] * 32767.0f);
+
+ /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
+ vert_r->flag = BMFlags_To_MEFlags(ev);
+ vert_r->mat_nr = 0;
+ vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
+}
+
+static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+ BMVert *ev;
+ BMIter iter;
+ int i;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) {
+ printf("error in bmDM_getVert.\n");
+ return;
+ }
+
+ ev = ((EditDerivedBMesh *)dm)->vtable[index];
+ bmvert_to_mvert(ev, vert_r);
+}
+
+static void bmDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMEdge *e;
+ BMVert *ev, *v1, *v2;
+ BMIter iter;
+ int i;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) {
+ printf("error in bmDM_getEdge.\n");
+ return;
+ }
+
+ e = bmdm->etable[index];
+
+ edge_r->crease = (unsigned char) (e->crease*255.0f);
+ edge_r->bweight = (unsigned char) (e->bweight*255.0f);
+ /* TODO what to do with edge_r->flag? */
+ edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
+ edge_r->flag |= BMFlags_To_MEFlags(e);
+#if 0
+ /* this needs setup of f2 field */
+ if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+ edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1));
+ edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2));
+}
+
+static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = bmdm->tc->bm;
+ BMFace *ef;
+ BMIter iter;
+ BMLoop **l;
+ int i;
+
+ if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) {
+ printf("error in bmDM_getTessFace.\n");
+ return;
+ }
+
+ l = ((EditDerivedBMesh *)dm)->tc->looptris[index];
+
+ ef = l[0]->f;
+
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+ face_r->flag = BMFlags_To_MEFlags(ef);
+
+ face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v));
+ face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v));
+ face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v));
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
+}
+
+static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMVert *ev;
+ BMIter iter;
+
+ ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; ev; ev = BMIter_Step(&iter), ++vert_r) {
+ VECCOPY(vert_r->co, ev->co);
+
+ vert_r->no[0] = (short) (ev->no[0] * 32767.0);
+ vert_r->no[1] = (short) (ev->no[1] * 32767.0);
+ vert_r->no[2] = (short) (ev->no[2] * 32767.0);
+
+ /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
+ vert_r->mat_nr = 0;
+ vert_r->flag = BMFlags_To_MEFlags(ev);
+ vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
+ }
+}
+
+static void bmDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMEdge *ee;
+ BMIter iter;
+ BMVert *ev;
+ int i;
+
+ /* store vertex indices in tmp union */
+ ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; ev; ev=BMIter_Step(&iter), i++)
+ BMINDEX_SET(ev, i);
+
+ ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for( ; ee; ee=BMIter_Step(&iter)) {
+ 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->head.flag & BM_SEAM) edge_r->flag |= ME_SEAM;
+ if (ee->head.flag & BM_SHARP) edge_r->flag |= ME_SHARP;
+#if 0
+ /* this needs setup of f2 field */
+ if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+ edge_r->v1 = (int)BMINDEX_GET(ee->v1);
+ edge_r->v2 = (int)BMINDEX_GET(ee->v2);
+ }
+}
+
+static void bmDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+ EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
+ BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
+ BMFace *ef;
+ BMVert *ev;
+ BMIter iter;
+ BMLoop **l;
+ int i;
+
+ /* store vertexes indices in tmp union */
+ ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; ev; ev=BMIter_Step(&iter), i++)
+ BMINDEX_SET(ev, i);
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ l = bmdm->tc->looptris[i];
+ ef = l[0]->f;
+
+ face_r->mat_nr = (unsigned char) ef->mat_nr;
+
+ /*HACK/TODO: need to convert this*/
+ face_r->flag = ef->head.flag;
+
+ face_r->v1 = BMINDEX_GET(l[0]->v);
+ face_r->v2 = BMINDEX_GET(l[1]->v);
+ face_r->v3 = BMINDEX_GET(l[2]->v);
+ face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, 3);
+ }
+}
+
+static void *bmDM_getFaceDataArray(DerivedMesh *dm, int type)
+{
+ EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
+ BMesh *bm= bmdm->tc->bm;
+ BMFace *efa;
+ char *data, *bmdata;
+ void *datalayer;
+ int index, offset, size, i;
+
+ datalayer = DM_get_face_data_layer(dm, type);
+ if(datalayer)
+ return datalayer;
+
+ /* layers are store per face for editmesh, we convert to a tbmporary
+ * data layer array in the derivedmesh when these are requested */
+ if(type == CD_MTFACE || type == CD_MCOL) {
+ index = CustomData_get_layer_index(&bm->pdata, type);
+
+ if(index != -1) {
+ offset = bm->pdata.layers[index].offset;
+ size = CustomData_sizeof(type);
+
+ DM_add_face_layer(dm, type, CD_CALLOC, NULL);
+ index = CustomData_get_layer_index(&dm->faceData, type);
+ dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
+
+ data = datalayer = DM_get_face_data_layer(dm, type);
+ for (i=0; i<bmdm->tc->tottri; i++, data+=size) {
+ efa = bmdm->tc->looptris[i][0]->f;
+ /*BMESH_TODO: need to still add tface data,
+ derived from the loops.*/
+ bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, type);
+ memcpy(data, bmdata, size);
+ }
+ }
+ }
+
+ return datalayer;
+}
+
+typedef struct bmDM_loopIter {
+ DMLoopIter head;
+
+ BMFace *f;
+ BMLoop *l, *nextl;
+ BMIter iter;
+ BMesh *bm;
+} bmDM_loopIter;
+
+typedef struct bmDM_faceIter {
+ DMFaceIter head;
+
+ BMFace *f, *nextf;
+ BMIter iter;
+ BMesh *bm;
+
+ bmDM_loopIter loopiter;
+} bmDM_faceIter;
+
+void bmDM_faceIterStep(void *self)
+{
+ bmDM_faceIter *iter = self;
+
+ iter->f = iter->nextf;
+
+ iter->head.mat_nr = iter->f->mat_nr;
+ iter->head.flags = BMFlags_To_MEFlags(iter->f);
+ iter->head.index++;
+
+ iter->nextf = BMIter_Step(&iter->iter);
+
+ if (!iter->nextf) iter->head.done = 1;
+}
+
+void *bmDM_getFaceCDData(void *self, int type, int layer)
+{
+ bmDM_faceIter *iter = self;
+
+ if (layer == -1)
+ return CustomData_bmesh_get(&iter->bm->pdata, iter->f->head.data, type);
+ else return CustomData_bmesh_get_n(&iter->bm->pdata, iter->f->head.data, type, layer);
+}
+
+void bmDM_loopIterStep(void *self)
+{
+ bmDM_loopIter *iter = self;
+
+ iter->l = iter->nextl;
+
+ bmvert_to_mvert(iter->l->v, &iter->head.v);
+ iter->head.index++;
+ iter->head.vindex = BMINDEX_GET(iter->l->v);
+ iter->head.eindex = BMINDEX_GET(iter->l->e);
+
+ iter->nextl = BMIter_Step(&iter->iter);
+
+ if (!iter->nextl) iter->head.done = 1;
+}
+
+void *bmDM_getLoopCDData(void *self, int type, int layer)
+{
+ bmDM_loopIter *iter = self;
+
+ if (layer == -1)
+ return CustomData_bmesh_get(&iter->bm->ldata, iter->l->head.data, type);
+ else return CustomData_bmesh_get_n(&iter->bm->ldata, iter->l->head.data, type, layer);
+}
+
+void *bmDM_getVertCDData(void *self, int type, int layer)
+{
+ bmDM_loopIter *iter = self;
+
+ if (layer == -1)
+ return CustomData_bmesh_get(&iter->bm->vdata, iter->l->v->head.data, type);
+ else return CustomData_bmesh_get_n(&iter->bm->vdata, iter->l->v->head.data, type, layer);
+}
+
+void bmDM_iterFree(void *self)
+{
+ MEM_freeN(self);
+}
+
+void bmDM_nulliterFree(void *self)
+{
+}
+
+DMLoopIter *bmDM_newLoopsIter(void *faceiter)
+{
+ bmDM_faceIter *fiter = faceiter;
+ bmDM_loopIter *iter = &fiter->loopiter;
+
+ memset(&fiter->loopiter, 0, sizeof(bmDM_loopIter));
+
+ iter->bm = fiter->bm;
+ iter->f = fiter->f;
+ iter->nextl = BMIter_New(&iter->iter, iter->bm, BM_LOOPS_OF_FACE, iter->f);
+
+ iter->head.step = bmDM_loopIterStep;
+ iter->head.getLoopCDData = bmDM_getLoopCDData;
+ iter->head.getVertCDData = bmDM_getVertCDData;
+
+ bmvert_to_mvert(iter->nextl->v, &iter->head.v);
+ iter->head.vindex = BMINDEX_GET(iter->nextl->v);
+ iter->head.eindex = BMINDEX_GET(iter->nextl->e);
+
+ return (DMLoopIter*) iter;
+}
+
+static DMFaceIter *bmDM_getFaceIter(void *dm)
+{
+ EditDerivedBMesh *bmdm= dm;
+ bmDM_faceIter *iter = MEM_callocN(sizeof(bmDM_faceIter), "bmDM_faceIter");
+ BMIter biter;
+ BMVert *v;
+ BMEdge *e;
+ int i;
+
+ iter->bm = bmdm->tc->bm;
+ iter->f = iter->nextf = BMIter_New(&iter->iter, iter->bm, BM_FACES_OF_MESH, NULL);
+
+ iter->head.step = bmDM_faceIterStep;
+ iter->head.free = bmDM_iterFree;
+ iter->head.getCDData = bmDM_getFaceCDData;
+ iter->head.getLoopsIter = bmDM_newLoopsIter;
+
+ iter->head.mat_nr = iter->f->mat_nr;
+ iter->head.flags = BMFlags_To_MEFlags(iter->f);
+
+ /*set up vert/edge indices*/
+ i = 0;
+ BM_ITER(v, &biter, iter->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+ }
+
+ i = 0;
+ BM_ITER(e, &biter, iter->bm, BM_EDGES_OF_MESH, NULL) {
+ BMINDEX_SET(e, i);
+ i++;
+ }
+
+ return (DMFaceIter*) iter;
+}
+
+static void bmDM_release(void *dm)
+{
+ EditDerivedBMesh *bmdm= dm;
+
+ if (DM_release(dm)) {
+ if (bmdm->vertexCos) {
+ MEM_freeN(bmdm->vertexCos);
+ MEM_freeN(bmdm->vertexNos);
+ MEM_freeN(bmdm->faceNos);
+ }
+
+ BLI_ghash_free(bmdm->fhash, NULL, NULL);
+ BLI_ghash_free(bmdm->ehash, NULL, NULL);
+ BLI_ghash_free(bmdm->vhash, NULL, NULL);
+
+ if (bmdm->vtable) MEM_freeN(bmdm->vtable);
+ if (bmdm->etable) MEM_freeN(bmdm->etable);
+ if (bmdm->ftable) MEM_freeN(bmdm->ftable);
+
+ MEM_freeN(bmdm);
+ }
+}
+
+DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *ob,
+ float (*vertexCos)[3])
+{
+ EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), "bmdm");
+ BMesh *bm = em->bm;
+
+ bmdm->tc = em;
+
+ DM_init((DerivedMesh*)bmdm, em->bm->totvert, em->bm->totedge, em->tottri,
+ em->bm->totloop, em->bm->totface);
+
+ bmdm->dm.getMinMax = bmDM_getMinMax;
+
+ bmdm->dm.getNumVerts = bmDM_getNumVerts;
+ bmdm->dm.getNumEdges = bmDM_getNumEdges;
+ bmdm->dm.getNumTessFaces = bmDM_getNumTessFaces;
+ bmdm->dm.getNumFaces = bmDM_getNumFaces;
+
+ bmdm->dm.getVert = bmDM_getVert;
+ bmdm->dm.getEdge = bmDM_getEdge;
+ bmdm->dm.getTessFace = bmDM_getTessFace;
+ bmdm->dm.copyVertArray = bmDM_copyVertArray;
+ bmdm->dm.copyEdgeArray = bmDM_copyEdgeArray;
+ bmdm->dm.copyTessFaceArray = bmDM_copyFaceArray;
+ bmdm->dm.getTessFaceDataArray = bmDM_getFaceDataArray;
+
+ bmdm->dm.newFaceIter = bmDM_getFaceIter;
+ bmdm->dm.recalcTesselation = bmDM_recalcTesselation;
+
+ bmdm->dm.foreachMappedVert = bmDM_foreachMappedVert;
+ bmdm->dm.foreachMappedEdge = bmDM_foreachMappedEdge;
+ bmdm->dm.foreachMappedFaceCenter = bmDM_foreachMappedFaceCenter;
+
+ bmdm->dm.drawEdges = bmDM_drawEdges;
+ bmdm->dm.drawMappedEdges = bmDM_drawMappedEdges;
+ bmdm->dm.drawMappedEdgesInterp = bmDM_drawMappedEdgesInterp;
+ bmdm->dm.drawMappedFaces = bmDM_drawMappedFaces;
+ bmdm->dm.drawMappedFacesTex = bmDM_drawMappedFacesTex;
+ bmdm->dm.drawMappedFacesGLSL = bmDM_drawMappedFacesGLSL;
+ bmdm->dm.drawFacesTex = bmDM_drawFacesTex;
+ bmdm->dm.drawFacesGLSL = bmDM_drawFacesGLSL;
+ bmdm->dm.drawUVEdges = bmDM_drawUVEdges;
+
+ bmdm->dm.release = bmDM_release;
+
+ bmdm->vertexCos = vertexCos;
+
+ if(CustomData_has_layer(&bm->vdata, CD_MDEFORMVERT)) {
+ BMIter iter;
+ BMVert *eve;
+ int i;
+
+ DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+
+ eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
+ CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_MDEFORMVERT));
+ }
+
+ if(vertexCos) {
+ BMVert *eve;
+ BMIter iter;
+ int totface = bm->totface;
+ int i;
+
+ eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++)
+ BMINDEX_SET(eve, i);
+
+ bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos)*i, "bmdm_vno");
+ bmdm->faceNos = MEM_mallocN(sizeof(*bmdm->faceNos)*totface, "bmdm_vno");
+
+ for (i=0; i<bmdm->tc->tottri; i++) {
+ BMLoop **l = bmdm->tc->looptris[i];
+ float *v1 = vertexCos[(int) BMINDEX_GET(l[0]->v)];
+ float *v2 = vertexCos[(int) BMINDEX_GET(l[1]->v)];
+ float *v3 = vertexCos[(int) BMINDEX_GET(l[2]->v)];
+ float *no = bmdm->faceNos[i];
+
+ CalcNormFloat(v1, v2, v3, no);
+ VecAddf(bmdm->vertexNos[BMINDEX_GET(l[0]->v)], bmdm->vertexNos[BMINDEX_GET(l[0]->v)], no);
+ VecAddf(bmdm->vertexNos[BMINDEX_GET(l[1]->v)], bmdm->vertexNos[BMINDEX_GET(l[1]->v)], no);
+ VecAddf(bmdm->vertexNos[BMINDEX_GET(l[2]->v)], bmdm->vertexNos[BMINDEX_GET(l[2]->v)], no);
+ }
+
+ eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (i=0; eve; eve=BMIter_Step(&iter), i++) {
+ float *no = bmdm->vertexNos[i];
+ /* following Mesh convention; we use vertex coordinate itself
+ * for normal in this case */
+ if (Normalize(no)==0.0) {
+ VECCOPY(no, vertexCos[i]);
+ Normalize(no);
+ }
+ }
+ }
+
+ bmdm_recalc_lookups(bmdm);
+
+ return (DerivedMesh*) bmdm;
+}
diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c
index c7a8b150d3a..5566851db43 100644
--- a/source/blender/blenkernel/intern/exotic.c
+++ b/source/blender/blenkernel/intern/exotic.c
@@ -1851,8 +1851,8 @@ static void write_vert_stl(Object *ob, MVert *verts, int index, FILE *fpSTL)
static int write_derivedmesh_stl(FILE *fpSTL, Object *ob, DerivedMesh *dm)
{
MVert *mvert = dm->getVertArray(dm);
- MFace *mface = dm->getFaceArray(dm);
- int i, numfacets = 0, totface = dm->getNumFaces(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
+ int i, numfacets = 0, totface = dm->getNumTessFaces(dm);
float zero[3] = {0.0f, 0.0f, 0.0f};
for (i=0; i<totface; i++, mface++) {
diff --git a/source/blender/blenkernel/intern/fluidsim.c b/source/blender/blenkernel/intern/fluidsim.c
index 2b4032af503..6c684994e30 100644
--- a/source/blender/blenkernel/intern/fluidsim.c
+++ b/source/blender/blenkernel/intern/fluidsim.c
@@ -298,7 +298,7 @@ static DerivedMesh *fluidsim_read_obj(char *filename)
return NULL;
}
- dm = CDDM_new(numverts, 0, numfaces);
+ dm = CDDM_new(numverts, 0, numfaces, 0, 0);
if(!dm)
{
@@ -355,7 +355,7 @@ static DerivedMesh *fluidsim_read_obj(char *filename)
printf("Fluidsim: error in reading data from file.\n");
// read triangles from file
- mface = CDDM_get_faces(dm);
+ mface = CDDM_get_tessfaces(dm);
for(i=0; i<numfaces; i++)
{
int face[4];
@@ -391,6 +391,7 @@ static DerivedMesh *fluidsim_read_obj(char *filename)
CDDM_apply_vert_normals(dm, (short (*)[3])normals);
MEM_freeN(normals);
+ CDDM_tessfaces_to_faces(dm);
// CDDM_calc_normals(result);
return dm;
@@ -458,12 +459,12 @@ DerivedMesh *fluidsim_read_cache(Object *ob, DerivedMesh *orgdm, FluidsimModifie
}
// assign material + flags to new dm
- mface = orgdm->getFaceArray(orgdm);
+ mface = orgdm->getTessFaceArray(orgdm);
mat_nr = mface[0].mat_nr;
flag = mface[0].flag;
- mface = dm->getFaceArray(dm);
- numfaces = dm->getNumFaces(dm);
+ mface = dm->getTessFaceArray(dm);
+ numfaces = dm->getNumTessFaces(dm);
for(i=0; i<numfaces; i++)
{
mface[i].mat_nr = mat_nr;
@@ -617,9 +618,9 @@ void initElbeemMesh(struct Scene *scene, struct Object *ob,
//dm = mesh_create_derived_no_deform(ob,NULL);
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
totvert = dm->getNumVerts(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
*numVertices = totvert;
verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");
diff --git a/source/blender/blenkernel/intern/fmodifier.c b/source/blender/blenkernel/intern/fmodifier.c
deleted file mode 100644
index 64558d0b456..00000000000
--- a/source/blender/blenkernel/intern/fmodifier.c
+++ /dev/null
@@ -1,1197 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
- * All rights reserved.
- *
- * Contributor(s): Joshua Leung (full recode)
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-
-#include <math.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <string.h>
-#include <float.h>
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_anim_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_arithb.h"
-#include "BLI_noise.h"
-
-#include "BKE_fcurve.h"
-#include "BKE_curve.h"
-#include "BKE_global.h"
-#include "BKE_idprop.h"
-#include "BKE_utildefines.h"
-
-#include "RNA_access.h"
-#include "RNA_types.h"
-
-#ifndef DISABLE_PYTHON
-#include "BPY_extern.h" /* for BPY_pydriver_eval() */
-#endif
-
-#define SMALL -1.0e-10
-#define SELECT 1
-
-/* ******************************** F-Modifiers ********************************* */
-
-/* Info ------------------------------- */
-
-/* F-Modifiers are modifiers which operate on F-Curves. However, they can also be defined
- * on NLA-Strips to affect all of the F-Curves referenced by the NLA-Strip.
- */
-
-/* Template --------------------------- */
-
-/* Each modifier defines a set of functions, which will be called at the appropriate
- * times. In addition to this, each modifier should have a type-info struct, where
- * its functions are attached for use.
- */
-
-/* Template for type-info data:
- * - make a copy of this when creating new modifiers, and just change the functions
- * pointed to as necessary
- * - although the naming of functions doesn't matter, it would help for code
- * readability, to follow the same naming convention as is presented here
- * - any functions that a constraint doesn't need to define, don't define
- * for such cases, just use NULL
- * - these should be defined after all the functions have been defined, so that
- * forward-definitions/prototypes don't need to be used!
- * - keep this copy #if-def'd so that future constraints can get based off this
- */
-#if 0
-static FModifierTypeInfo FMI_MODNAME = {
- FMODIFIER_TYPE_MODNAME, /* type */
- sizeof(FMod_ModName), /* size */
- FMI_TYPE_SOME_ACTION, /* action type */
- FMI_REQUIRES_SOME_REQUIREMENT, /* requirements */
- "Modifier Name", /* name */
- "FMod_ModName", /* struct name */
- fcm_modname_free, /* free data */
- fcm_modname_relink, /* relink data */
- fcm_modname_copy, /* copy data */
- fcm_modname_new_data, /* new data */
- fcm_modname_verify, /* verify */
- fcm_modname_time, /* evaluate time */
- fcm_modname_evaluate /* evaluate */
-};
-#endif
-
-/* Generator F-Curve Modifier --------------------------- */
-
-/* Generators available:
- * 1) simple polynomial generator:
- * - Exanded form - (y = C[0]*(x^(n)) + C[1]*(x^(n-1)) + ... + C[n])
- * - Factorised form - (y = (C[0][0]*x + C[0][1]) * (C[1][0]*x + C[1][1]) * ... * (C[n][0]*x + C[n][1]))
- */
-
-static void fcm_generator_free (FModifier *fcm)
-{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
- /* free polynomial coefficients array */
- if (data->coefficients)
- MEM_freeN(data->coefficients);
-}
-
-static void fcm_generator_copy (FModifier *fcm, FModifier *src)
-{
- FMod_Generator *gen= (FMod_Generator *)fcm->data;
- FMod_Generator *ogen= (FMod_Generator *)src->data;
-
- /* copy coefficients array? */
- if (ogen->coefficients)
- gen->coefficients= MEM_dupallocN(ogen->coefficients);
-}
-
-static void fcm_generator_new_data (void *mdata)
-{
- FMod_Generator *data= (FMod_Generator *)mdata;
- float *cp;
-
- /* set default generator to be linear 0-1 (gradient = 1, y-offset = 0) */
- data->poly_order= 1;
- data->arraysize= 2;
- cp= data->coefficients= MEM_callocN(sizeof(float)*2, "FMod_Generator_Coefs");
- cp[0] = 0; // y-offset
- cp[1] = 1; // gradient
-}
-
-static void fcm_generator_verify (FModifier *fcm)
-{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
- /* requirements depend on mode */
- switch (data->mode) {
- case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
- {
- /* arraysize needs to be order+1, so resize if not */
- if (data->arraysize != (data->poly_order+1)) {
- float *nc;
-
- /* make new coefficients array, and copy over as much data as can fit */
- nc= MEM_callocN(sizeof(float)*(data->poly_order+1), "FMod_Generator_Coefs");
-
- if (data->coefficients) {
- if (data->arraysize > (data->poly_order+1))
- memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order+1));
- else
- memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
-
- /* free the old data */
- MEM_freeN(data->coefficients);
- }
-
- /* set the new data */
- data->coefficients= nc;
- data->arraysize= data->poly_order+1;
- }
- }
- break;
-
- case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* expanded polynomial expression */
- {
- /* arraysize needs to be 2*order, so resize if not */
- if (data->arraysize != (data->poly_order * 2)) {
- float *nc;
-
- /* make new coefficients array, and copy over as much data as can fit */
- nc= MEM_callocN(sizeof(float)*(data->poly_order*2), "FMod_Generator_Coefs");
-
- if (data->coefficients) {
- if (data->arraysize > (data->poly_order * 2))
- memcpy(nc, data->coefficients, sizeof(float)*(data->poly_order * 2));
- else
- memcpy(nc, data->coefficients, sizeof(float)*data->arraysize);
-
- /* free the old data */
- MEM_freeN(data->coefficients);
- }
-
- /* set the new data */
- data->coefficients= nc;
- data->arraysize= data->poly_order * 2;
- }
- }
- break;
- }
-}
-
-static void fcm_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
-
- /* behaviour depends on mode
- * NOTE: the data in its default state is fine too
- */
- switch (data->mode) {
- case FCM_GENERATOR_POLYNOMIAL: /* expanded polynomial expression */
- {
- /* we overwrite cvalue with the sum of the polynomial */
- float *powers = MEM_callocN(sizeof(float)*data->arraysize, "Poly Powers");
- float value= 0.0f;
- unsigned int i;
-
- /* for each x^n, precalculate value based on previous one first... this should be
- * faster that calling pow() for each entry
- */
- for (i=0; i < data->arraysize; i++) {
- /* first entry is x^0 = 1, otherwise, calculate based on previous */
- if (i)
- powers[i]= powers[i-1] * evaltime;
- else
- powers[0]= 1;
- }
-
- /* for each coefficient, add to value, which we'll write to *cvalue in one go */
- for (i=0; i < data->arraysize; i++)
- value += data->coefficients[i] * powers[i];
-
- /* only if something changed, write *cvalue in one go */
- if (data->poly_order) {
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue= value;
- }
-
- /* cleanup */
- if (powers)
- MEM_freeN(powers);
- }
- break;
-
- case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
- {
- float value= 1.0f, *cp=NULL;
- unsigned int i;
-
- /* for each coefficient pair, solve for that bracket before accumulating in value by multiplying */
- for (cp=data->coefficients, i=0; (cp) && (i < data->poly_order); cp+=2, i++)
- value *= (cp[0]*evaltime + cp[1]);
-
- /* only if something changed, write *cvalue in one go */
- if (data->poly_order) {
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue= value;
- }
- }
- break;
- }
-}
-
-static FModifierTypeInfo FMI_GENERATOR = {
- FMODIFIER_TYPE_GENERATOR, /* type */
- sizeof(FMod_Generator), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_NOTHING, /* requirements */
- "Generator", /* name */
- "FMod_Generator", /* struct name */
- fcm_generator_free, /* free data */
- fcm_generator_copy, /* copy data */
- fcm_generator_new_data, /* new data */
- fcm_generator_verify, /* verify */
- NULL, /* evaluate time */
- fcm_generator_evaluate /* evaluate */
-};
-
-/* Built-In Function Generator F-Curve Modifier --------------------------- */
-
-/* This uses the general equation for equations:
- * y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
- *
- * where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
- * x is the evaluation 'time', and 'y' is the resultant value
- *
- * Functions available are
- * sin, cos, tan, sinc (normalised sin), natural log, square root
- */
-
-static void fcm_fn_generator_new_data (void *mdata)
-{
- FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)mdata;
-
- /* set amplitude and phase multiplier to 1.0f so that something is generated */
- data->amplitude= 1.0f;
- data->phase_multiplier= 1.0f;
-}
-
-/* Unary 'normalised sine' function
- * y = sin(PI + x) / (PI * x),
- * except for x = 0 when y = 1.
- */
-static double sinc (double x)
-{
- if (fabs(x) < 0.0001)
- return 1.0;
- else
- return sin(M_PI * x) / (M_PI * x);
-}
-
-static void fcm_fn_generator_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_FunctionGenerator *data= (FMod_FunctionGenerator *)fcm->data;
- double arg= data->phase_multiplier*evaltime + data->phase_offset;
- double (*fn)(double v) = NULL;
-
- /* get function pointer to the func to use:
- * WARNING: must perform special argument validation hereto guard against crashes
- */
- switch (data->type)
- {
- /* simple ones */
- case FCM_GENERATOR_FN_SIN: /* sine wave */
- fn= sin;
- break;
- case FCM_GENERATOR_FN_COS: /* cosine wave */
- fn= cos;
- break;
- case FCM_GENERATOR_FN_SINC: /* normalised sine wave */
- fn= sinc;
- break;
-
- /* validation required */
- case FCM_GENERATOR_FN_TAN: /* tangent wave */
- {
- /* check that argument is not on one of the discontinuities (i.e. 90deg, 270 deg, etc) */
- if IS_EQ(fmod((arg - M_PI_2), M_PI), 0.0) {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- else
- fn= tan;
- }
- break;
- case FCM_GENERATOR_FN_LN: /* natural log */
- {
- /* check that value is greater than 1? */
- if (arg > 1.0f) {
- fn= log;
- }
- else {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- }
- break;
- case FCM_GENERATOR_FN_SQRT: /* square root */
- {
- /* no negative numbers */
- if (arg > 0.0f) {
- fn= sqrt;
- }
- else {
- if ((data->flag & FCM_GENERATOR_ADDITIVE) == 0)
- *cvalue = 0.0f; /* no value possible here */
- }
- }
- break;
-
- default:
- printf("Invalid Function-Generator for F-Modifier - %d \n", data->type);
- }
-
- /* execute function callback to set value if appropriate */
- if (fn) {
- float value= (float)(data->amplitude*fn(arg) + data->value_offset);
-
- if (data->flag & FCM_GENERATOR_ADDITIVE)
- *cvalue += value;
- else
- *cvalue= value;
- }
-}
-
-static FModifierTypeInfo FMI_FN_GENERATOR = {
- FMODIFIER_TYPE_FN_GENERATOR, /* type */
- sizeof(FMod_FunctionGenerator), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_NOTHING, /* requirements */
- "Built-In Function", /* name */
- "FMod_FunctionGenerator", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_fn_generator_new_data, /* new data */
- NULL, /* verify */
- NULL, /* evaluate time */
- fcm_fn_generator_evaluate /* evaluate */
-};
-
-/* Envelope F-Curve Modifier --------------------------- */
-
-static void fcm_envelope_free (FModifier *fcm)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-
- /* free envelope data array */
- if (env->data)
- MEM_freeN(env->data);
-}
-
-static void fcm_envelope_copy (FModifier *fcm, FModifier *src)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
- FMod_Envelope *oenv= (FMod_Envelope *)src->data;
-
- /* copy envelope data array */
- if (oenv->data)
- env->data= MEM_dupallocN(oenv->data);
-}
-
-static void fcm_envelope_new_data (void *mdata)
-{
- FMod_Envelope *env= (FMod_Envelope *)mdata;
-
- /* set default min/max ranges */
- env->min= -1.0f;
- env->max= 1.0f;
-}
-
-static void fcm_envelope_verify (FModifier *fcm)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
-
- /* if the are points, perform bubble-sort on them, as user may have changed the order */
- if (env->data) {
- // XXX todo...
- }
-}
-
-static void fcm_envelope_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
- FCM_EnvelopeData *fed, *prevfed, *lastfed;
- float min=0.0f, max=0.0f, fac=0.0f;
- int a;
-
- /* get pointers */
- if (env->data == NULL) return;
- prevfed= env->data;
- fed= prevfed + 1;
- lastfed= prevfed + (env->totvert-1);
-
- /* get min/max values for envelope at evaluation time (relative to mid-value) */
- if (prevfed->time >= evaltime) {
- /* before or on first sample, so just extend value */
- min= prevfed->min;
- max= prevfed->max;
- }
- else if (lastfed->time <= evaltime) {
- /* after or on last sample, so just extend value */
- min= lastfed->min;
- max= lastfed->max;
- }
- else {
- /* evaltime occurs somewhere between segments */
- // TODO: implement binary search for this to make it faster?
- for (a=0; prevfed && fed && (a < env->totvert-1); a++, prevfed=fed, fed++) {
- /* evaltime occurs within the interval defined by these two envelope points */
- if ((prevfed->time <= evaltime) && (fed->time >= evaltime)) {
- float afac, bfac, diff;
-
- diff= fed->time - prevfed->time;
- afac= (evaltime - prevfed->time) / diff;
- bfac= (fed->time - evaltime) / diff;
-
- min= bfac*prevfed->min + afac*fed->min;
- max= bfac*prevfed->max + afac*fed->max;
-
- break;
- }
- }
- }
-
- /* adjust *cvalue
- * - fac is the ratio of how the current y-value corresponds to the reference range
- * - thus, the new value is found by mapping the old range to the new!
- */
- fac= (*cvalue - (env->midval + env->min)) / (env->max - env->min);
- *cvalue= min + fac*(max - min);
-}
-
-static FModifierTypeInfo FMI_ENVELOPE = {
- FMODIFIER_TYPE_ENVELOPE, /* type */
- sizeof(FMod_Envelope), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- "Envelope", /* name */
- "FMod_Envelope", /* struct name */
- fcm_envelope_free, /* free data */
- fcm_envelope_copy, /* copy data */
- fcm_envelope_new_data, /* new data */
- fcm_envelope_verify, /* verify */
- NULL, /* evaluate time */
- fcm_envelope_evaluate /* evaluate */
-};
-
-/* Cycles F-Curve Modifier --------------------------- */
-
-/* This modifier changes evaltime to something that exists within the curve's frame-range,
- * then re-evaluates modifier stack up to this point using the new time. This re-entrant behaviour
- * is very likely to be more time-consuming than the original approach... (which was tighly integrated into
- * the calculation code...).
- *
- * NOTE: this needs to be at the start of the stack to be of use, as it needs to know the extents of the keyframes/sample-data
- * Possible TODO - store length of cycle information that can be initialised from the extents of the keyframes/sample-data, and adjusted
- * as appropriate
- */
-
-/* temp data used during evaluation */
-typedef struct tFCMED_Cycles {
- float cycyofs; /* y-offset to apply */
-} tFCMED_Cycles;
-
-static void fcm_cycles_new_data (void *mdata)
-{
- FMod_Cycles *data= (FMod_Cycles *)mdata;
-
- /* turn on cycles by default */
- data->before_mode= data->after_mode= FCM_EXTRAPOLATE_CYCLIC;
-}
-
-static float fcm_cycles_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
-{
- FMod_Cycles *data= (FMod_Cycles *)fcm->data;
- float prevkey[2], lastkey[2], cycyofs=0.0f;
- short side=0, mode=0;
- int cycles=0;
-
- /* check if modifier is first in stack, otherwise disable ourself... */
- // FIXME...
- if (fcm->prev) {
- fcm->flag |= FMODIFIER_FLAG_DISABLED;
- return evaltime;
- }
-
- /* calculate new evaltime due to cyclic interpolation */
- if (fcu && fcu->bezt) {
- BezTriple *prevbezt= fcu->bezt;
- BezTriple *lastbezt= prevbezt + fcu->totvert-1;
-
- prevkey[0]= prevbezt->vec[1][0];
- prevkey[1]= prevbezt->vec[1][1];
-
- lastkey[0]= lastbezt->vec[1][0];
- lastkey[1]= lastbezt->vec[1][1];
- }
- else if (fcu && fcu->fpt) {
- FPoint *prevfpt= fcu->fpt;
- FPoint *lastfpt= prevfpt + fcu->totvert-1;
-
- prevkey[0]= prevfpt->vec[0];
- prevkey[1]= prevfpt->vec[1];
-
- lastkey[0]= lastfpt->vec[0];
- lastkey[1]= lastfpt->vec[1];
- }
- else
- return evaltime;
-
- /* check if modifier will do anything
- * 1) if in data range, definitely don't do anything
- * 2) if before first frame or after last frame, make sure some cycling is in use
- */
- if (evaltime < prevkey[0]) {
- if (data->before_mode) {
- side= -1;
- mode= data->before_mode;
- cycles= data->before_cycles;
- }
- }
- else if (evaltime > lastkey[0]) {
- if (data->after_mode) {
- side= 1;
- mode= data->after_mode;
- cycles= data->after_cycles;
- }
- }
- if ELEM(0, side, mode)
- return evaltime;
-
- /* find relative place within a cycle */
- {
- float cycdx=0, cycdy=0, ofs=0;
- float cycle= 0;
-
- /* ofs is start frame of cycle */
- ofs= prevkey[0];
-
- /* calculate period and amplitude (total height) of a cycle */
- cycdx= lastkey[0] - prevkey[0];
- cycdy= lastkey[1] - prevkey[1];
-
- /* check if cycle is infinitely small, to be point of being impossible to use */
- if (cycdx == 0)
- return evaltime;
-
- /* calculate the 'number' of the cycle */
- cycle= ((float)side * (evaltime - ofs) / cycdx);
-
- /* check that cyclic is still enabled for the specified time */
- if (cycles == 0) {
- /* catch this case so that we don't exit when we have cycles=0
- * as this indicates infinite cycles...
- */
- }
- else if (cycle > (cycles+1)) {
- /* we are too far away from range to evaluate
- * TODO: but we should still hold last value...
- */
- return evaltime;
- }
-
- /* check if 'cyclic extrapolation', and thus calculate y-offset for this cycle */
- if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
- cycyofs = (float)floor((evaltime - ofs) / cycdx);
- cycyofs *= cycdy;
- }
-
- /* calculate where in the cycle we are (overwrite evaltime to reflect this) */
- if ((mode == FCM_EXTRAPOLATE_MIRROR) && ((int)(cycle) % 2)) {
- /* when 'mirror' option is used and cycle number is odd, this cycle is played in reverse
- * - for 'before' extrapolation, we need to flip in a different way, otherwise values past
- * then end of the curve get referenced (result of fmod will be negative, and with different phase)
- */
- if (side < 0)
- evaltime= (float)(prevkey[0] - fmod(evaltime-ofs, cycdx));
- else
- evaltime= (float)(lastkey[0] - fmod(evaltime-ofs, cycdx));
- }
- else {
- /* the cycle is played normally... */
- evaltime= (float)(fmod(evaltime-ofs, cycdx) + ofs);
- }
- if (evaltime < ofs) evaltime += cycdx;
- }
-
- /* store temp data if needed */
- if (mode == FCM_EXTRAPOLATE_CYCLIC_OFFSET) {
- tFCMED_Cycles *edata;
-
- /* for now, this is just a float, but we could get more stuff... */
- fcm->edata= edata= MEM_callocN(sizeof(tFCMED_Cycles), "tFCMED_Cycles");
- edata->cycyofs= cycyofs;
- }
-
- /* return the new frame to evaluate */
- return evaltime;
-}
-
-static void fcm_cycles_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- tFCMED_Cycles *edata= (tFCMED_Cycles *)fcm->edata;
-
- /* use temp data */
- if (edata) {
- /* add cyclic offset - no need to check for now, otherwise the data wouldn't exist! */
- *cvalue += edata->cycyofs;
-
- /* free temp data */
- MEM_freeN(edata);
- fcm->edata= NULL;
- }
-}
-
-static FModifierTypeInfo FMI_CYCLES = {
- FMODIFIER_TYPE_CYCLES, /* type */
- sizeof(FMod_Cycles), /* size */
- FMI_TYPE_EXTRAPOLATION, /* action type */
- FMI_REQUIRES_ORIGINAL_DATA, /* requirements */
- "Cycles", /* name */
- "FMod_Cycles", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_cycles_new_data, /* new data */
- NULL /*fcm_cycles_verify*/, /* verify */
- fcm_cycles_time, /* evaluate time */
- fcm_cycles_evaluate /* evaluate */
-};
-
-/* Noise F-Curve Modifier --------------------------- */
-
-static void fcm_noise_new_data (void *mdata)
-{
- FMod_Noise *data= (FMod_Noise *)mdata;
-
- /* defaults */
- data->size= 1.0f;
- data->strength= 1.0f;
- data->phase= 1.0f;
- data->depth = 0;
- data->modification = FCM_NOISE_MODIF_REPLACE;
-}
-
-static void fcm_noise_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Noise *data= (FMod_Noise *)fcm->data;
- float noise;
-
- noise = BLI_turbulence(data->size, evaltime, data->phase, 0.f, data->depth);
-
- switch (data->modification) {
- case FCM_NOISE_MODIF_ADD:
- *cvalue= *cvalue + noise * data->strength;
- break;
- case FCM_NOISE_MODIF_SUBTRACT:
- *cvalue= *cvalue - noise * data->strength;
- break;
- case FCM_NOISE_MODIF_MULTIPLY:
- *cvalue= *cvalue * noise * data->strength;
- break;
- case FCM_NOISE_MODIF_REPLACE:
- default:
- *cvalue= *cvalue + (noise - 0.5f) * data->strength;
- break;
- }
-}
-
-static FModifierTypeInfo FMI_NOISE = {
- FMODIFIER_TYPE_NOISE, /* type */
- sizeof(FMod_Noise), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- "Noise", /* name */
- "FMod_Noise", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- fcm_noise_new_data, /* new data */
- NULL /*fcm_noise_verify*/, /* verify */
- NULL, /* evaluate time */
- fcm_noise_evaluate /* evaluate */
-};
-
-/* Filter F-Curve Modifier --------------------------- */
-
-#if 0 // XXX not yet implemented
-static FModifierTypeInfo FMI_FILTER = {
- FMODIFIER_TYPE_FILTER, /* type */
- sizeof(FMod_Filter), /* size */
- FMI_TYPE_REPLACE_VALUES, /* action type */
- 0, /* requirements */
- "Filter", /* name */
- "FMod_Filter", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- NULL, /* new data */
- NULL /*fcm_filter_verify*/, /* verify */
- NULL, /* evlauate time */
- fcm_filter_evaluate /* evaluate */
-};
-#endif // XXX not yet implemented
-
-
-/* Python F-Curve Modifier --------------------------- */
-
-static void fcm_python_free (FModifier *fcm)
-{
- FMod_Python *data= (FMod_Python *)fcm->data;
-
- /* id-properties */
- IDP_FreeProperty(data->prop);
- MEM_freeN(data->prop);
-}
-
-static void fcm_python_new_data (void *mdata)
-{
- FMod_Python *data= (FMod_Python *)mdata;
-
- /* everything should be set correctly by calloc, except for the prop->type constant.*/
- data->prop = MEM_callocN(sizeof(IDProperty), "PyFModifierProps");
- data->prop->type = IDP_GROUP;
-}
-
-static void fcm_python_copy (FModifier *fcm, FModifier *src)
-{
- FMod_Python *pymod = (FMod_Python *)fcm->data;
- FMod_Python *opymod = (FMod_Python *)src->data;
-
- pymod->prop = IDP_CopyProperty(opymod->prop);
-}
-
-static void fcm_python_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
-#ifndef DISABLE_PYTHON
- //FMod_Python *data= (FMod_Python *)fcm->data;
-
- /* FIXME... need to implement this modifier...
- * It will need it execute a script using the custom properties
- */
-#endif /* DISABLE_PYTHON */
-}
-
-static FModifierTypeInfo FMI_PYTHON = {
- FMODIFIER_TYPE_PYTHON, /* type */
- sizeof(FMod_Python), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */
- FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
- "Python", /* name */
- "FMod_Python", /* struct name */
- fcm_python_free, /* free data */
- fcm_python_copy, /* copy data */
- fcm_python_new_data, /* new data */
- NULL /*fcm_python_verify*/, /* verify */
- NULL /*fcm_python_time*/, /* evaluate time */
- fcm_python_evaluate /* evaluate */
-};
-
-
-/* Limits F-Curve Modifier --------------------------- */
-
-static float fcm_limits_time (FCurve *fcu, FModifier *fcm, float cvalue, float evaltime)
-{
- FMod_Limits *data= (FMod_Limits *)fcm->data;
-
- /* check for the time limits */
- if ((data->flag & FCM_LIMIT_XMIN) && (evaltime < data->rect.xmin))
- return data->rect.xmin;
- if ((data->flag & FCM_LIMIT_XMAX) && (evaltime > data->rect.xmax))
- return data->rect.xmax;
-
- /* modifier doesn't change time */
- return evaltime;
-}
-
-static void fcm_limits_evaluate (FCurve *fcu, FModifier *fcm, float *cvalue, float evaltime)
-{
- FMod_Limits *data= (FMod_Limits *)fcm->data;
-
- /* value limits now */
- if ((data->flag & FCM_LIMIT_YMIN) && (*cvalue < data->rect.ymin))
- *cvalue= data->rect.ymin;
- if ((data->flag & FCM_LIMIT_YMAX) && (*cvalue > data->rect.ymax))
- *cvalue= data->rect.ymax;
-}
-
-static FModifierTypeInfo FMI_LIMITS = {
- FMODIFIER_TYPE_LIMITS, /* type */
- sizeof(FMod_Limits), /* size */
- FMI_TYPE_GENERATE_CURVE, /* action type */ /* XXX... err... */
- FMI_REQUIRES_RUNTIME_CHECK, /* requirements */
- "Limits", /* name */
- "FMod_Limits", /* struct name */
- NULL, /* free data */
- NULL, /* copy data */
- NULL, /* new data */
- NULL, /* verify */
- fcm_limits_time, /* evaluate time */
- fcm_limits_evaluate /* evaluate */
-};
-
-/* F-Curve Modifier API --------------------------- */
-/* All of the F-Curve Modifier api functions use FModifierTypeInfo structs to carry out
- * and operations that involve F-Curve modifier specific code.
- */
-
-/* These globals only ever get directly accessed in this file */
-static FModifierTypeInfo *fmodifiersTypeInfo[FMODIFIER_NUM_TYPES];
-static short FMI_INIT= 1; /* when non-zero, the list needs to be updated */
-
-/* This function only gets called when FMI_INIT is non-zero */
-static void fmods_init_typeinfo ()
-{
- fmodifiersTypeInfo[0]= NULL; /* 'Null' F-Curve Modifier */
- fmodifiersTypeInfo[1]= &FMI_GENERATOR; /* Generator F-Curve Modifier */
- fmodifiersTypeInfo[2]= &FMI_FN_GENERATOR; /* Built-In Function Generator F-Curve Modifier */
- fmodifiersTypeInfo[3]= &FMI_ENVELOPE; /* Envelope F-Curve Modifier */
- fmodifiersTypeInfo[4]= &FMI_CYCLES; /* Cycles F-Curve Modifier */
- fmodifiersTypeInfo[5]= &FMI_NOISE; /* Apply-Noise F-Curve Modifier */
- fmodifiersTypeInfo[6]= NULL/*&FMI_FILTER*/; /* Filter F-Curve Modifier */ // XXX unimplemented
- fmodifiersTypeInfo[7]= &FMI_PYTHON; /* Custom Python F-Curve Modifier */
- fmodifiersTypeInfo[8]= &FMI_LIMITS; /* Limits F-Curve Modifier */
-}
-
-/* This function should be used for getting the appropriate type-info when only
- * a F-Curve modifier type is known
- */
-FModifierTypeInfo *get_fmodifier_typeinfo (int type)
-{
- /* initialise the type-info list? */
- if (FMI_INIT) {
- fmods_init_typeinfo();
- FMI_INIT = 0;
- }
-
- /* only return for valid types */
- if ( (type >= FMODIFIER_TYPE_NULL) &&
- (type <= FMODIFIER_NUM_TYPES ) )
- {
- /* there shouldn't be any segfaults here... */
- return fmodifiersTypeInfo[type];
- }
- else {
- printf("No valid F-Curve Modifier type-info data available. Type = %i \n", type);
- }
-
- return NULL;
-}
-
-/* This function should always be used to get the appropriate type-info, as it
- * has checks which prevent segfaults in some weird cases.
- */
-FModifierTypeInfo *fmodifier_get_typeinfo (FModifier *fcm)
-{
- /* only return typeinfo for valid modifiers */
- if (fcm)
- return get_fmodifier_typeinfo(fcm->type);
- else
- return NULL;
-}
-
-/* API --------------------------- */
-
-/* Add a new F-Curve Modifier to the given F-Curve of a certain type */
-FModifier *add_fmodifier (ListBase *modifiers, int type)
-{
- FModifierTypeInfo *fmi= get_fmodifier_typeinfo(type);
- FModifier *fcm;
-
- /* sanity checks */
- if ELEM(NULL, modifiers, fmi)
- return NULL;
-
- /* special checks for whether modifier can be added */
- if ((modifiers->first) && (type == FMODIFIER_TYPE_CYCLES)) {
- /* cycles modifier must be first in stack, so for now, don't add if it can't be */
- // TODO: perhaps there is some better way, but for now,
- printf("Error: Cannot add 'Cycles' modifier to F-Curve, as 'Cycles' modifier can only be first in stack. \n");
- return NULL;
- }
-
- /* add modifier itself */
- fcm= MEM_callocN(sizeof(FModifier), "F-Curve Modifier");
- fcm->type = type;
- fcm->flag = FMODIFIER_FLAG_EXPANDED;
- BLI_addtail(modifiers, fcm);
-
- /* add modifier's data */
- fcm->data= MEM_callocN(fmi->size, fmi->structName);
-
- /* init custom settings if necessary */
- if (fmi->new_data)
- fmi->new_data(fcm->data);
-
- /* return modifier for further editing */
- return fcm;
-}
-
-/* Duplicate all of the F-Modifiers in the Modifier stacks */
-void copy_fmodifiers (ListBase *dst, ListBase *src)
-{
- FModifier *fcm, *srcfcm;
-
- if ELEM(NULL, dst, src)
- return;
-
- dst->first= dst->last= NULL;
- BLI_duplicatelist(dst, src);
-
- for (fcm=dst->first, srcfcm=src->first; fcm && srcfcm; srcfcm=srcfcm->next, fcm=fcm->next) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* make a new copy of the F-Modifier's data */
- fcm->data = MEM_dupallocN(fcm->data);
-
- /* only do specific constraints if required */
- if (fmi && fmi->copy_data)
- fmi->copy_data(fcm, srcfcm);
- }
-}
-
-/* Remove and free the given F-Modifier from the given stack */
-void remove_fmodifier (ListBase *modifiers, FModifier *fcm)
-{
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* sanity check */
- if (fcm == NULL)
- return;
-
- /* free modifier's special data (stored inside fcm->data) */
- if (fcm->data) {
- if (fmi && fmi->free_data)
- fmi->free_data(fcm);
-
- /* free modifier's data (fcm->data) */
- MEM_freeN(fcm->data);
- }
-
- /* remove modifier from stack */
- if (modifiers)
- BLI_freelinkN(modifiers, fcm);
- else {
- // XXX this case can probably be removed some day, as it shouldn't happen...
- printf("remove_fmodifier() - no modifier stack given \n");
- MEM_freeN(fcm);
- }
-}
-
-/* Remove all of a given F-Curve's modifiers */
-void free_fmodifiers (ListBase *modifiers)
-{
- FModifier *fcm, *fmn;
-
- /* sanity check */
- if (modifiers == NULL)
- return;
-
- /* free each modifier in order - modifier is unlinked from list and freed */
- for (fcm= modifiers->first; fcm; fcm= fmn) {
- fmn= fcm->next;
- remove_fmodifier(modifiers, fcm);
- }
-}
-
-/* Find the active F-Modifier */
-FModifier *find_active_fmodifier (ListBase *modifiers)
-{
- FModifier *fcm;
-
- /* sanity checks */
- if ELEM(NULL, modifiers, modifiers->first)
- return NULL;
-
- /* loop over modifiers until 'active' one is found */
- for (fcm= modifiers->first; fcm; fcm= fcm->next) {
- if (fcm->flag & FMODIFIER_FLAG_ACTIVE)
- return fcm;
- }
-
- /* no modifier is active */
- return NULL;
-}
-
-/* Set the active F-Modifier */
-void set_active_fmodifier (ListBase *modifiers, FModifier *fcm)
-{
- FModifier *fm;
-
- /* sanity checks */
- if ELEM(NULL, modifiers, modifiers->first)
- return;
-
- /* deactivate all, and set current one active */
- for (fm= modifiers->first; fm; fm= fm->next)
- fm->flag &= ~FMODIFIER_FLAG_ACTIVE;
-
- /* make given modifier active */
- if (fcm)
- fcm->flag |= FMODIFIER_FLAG_ACTIVE;
-}
-
-/* Do we have any modifiers which match certain criteria
- * - mtype - type of modifier (if 0, doesn't matter)
- * - acttype - type of action to perform (if -1, doesn't matter)
- */
-short list_has_suitable_fmodifier (ListBase *modifiers, int mtype, short acttype)
-{
- FModifier *fcm;
-
- /* if there are no specific filtering criteria, just skip */
- if ((mtype == 0) && (acttype == 0))
- return (modifiers && modifiers->first);
-
- /* sanity checks */
- if ELEM(NULL, modifiers, modifiers->first)
- return 0;
-
- /* find the first mdifier fitting these criteria */
- for (fcm= modifiers->first; fcm; fcm= fcm->next) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
- short mOk=1, aOk=1; /* by default 1, so that when only one test, won't fail */
-
- /* check if applicable ones are fullfilled */
- if (mtype)
- mOk= (fcm->type == mtype);
- if (acttype > -1)
- aOk= (fmi->acttype == acttype);
-
- /* if both are ok, we've found a hit */
- if (mOk && aOk)
- return 1;
- }
-
- /* no matches */
- return 0;
-}
-
-/* Evaluation API --------------------------- */
-
-/* evaluate time modifications imposed by some F-Curve Modifiers
- * - this step acts as an optimisation to prevent the F-Curve stack being evaluated
- * several times by modifiers requesting the time be modified, as the final result
- * would have required using the modified time
- * - modifiers only ever recieve the unmodified time, as subsequent modifiers should be
- * working on the 'global' result of the modified curve, not some localised segment,
- * so nevaltime gets set to whatever the last time-modifying modifier likes...
- * - we start from the end of the stack, as only the last one matters for now
- */
-float evaluate_time_fmodifiers (ListBase *modifiers, FCurve *fcu, float cvalue, float evaltime)
-{
- FModifier *fcm;
- float m_evaltime= evaltime;
-
- /* sanity checks */
- if ELEM(NULL, modifiers, modifiers->last)
- return evaltime;
-
- /* find the first modifier from end of stack that modifies time, and calculate the time the modifier
- * would calculate time at
- */
- for (fcm= modifiers->last; fcm; fcm= fcm->prev) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* only evaluate if there's a callback for this */
- // TODO: implement the 'influence' control feature...
- if (fmi && fmi->evaluate_modifier_time) {
- if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
- m_evaltime= fmi->evaluate_modifier_time(fcu, fcm, cvalue, evaltime);
- break;
- }
- }
-
- /* return the modified evaltime */
- return m_evaltime;
-}
-
-/* Evalautes the given set of F-Curve Modifiers using the given data
- * Should only be called after evaluate_time_fmodifiers() has been called...
- */
-void evaluate_value_fmodifiers (ListBase *modifiers, FCurve *fcu, float *cvalue, float evaltime)
-{
- FModifier *fcm;
-
- /* sanity checks */
- if ELEM(NULL, modifiers, modifiers->first)
- return;
-
- /* evaluate modifiers */
- for (fcm= modifiers->first; fcm; fcm= fcm->next) {
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* only evaluate if there's a callback for this */
- // TODO: implement the 'influence' control feature...
- if (fmi && fmi->evaluate_modifier) {
- if ((fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED)) == 0)
- fmi->evaluate_modifier(fcu, fcm, cvalue, evaltime);
- }
- }
-}
-
-/* ---------- */
-
-/* Bake modifiers for given F-Curve to curve sample data, in the frame range defined
- * by start and end (inclusive).
- */
-void fcurve_bake_modifiers (FCurve *fcu, int start, int end)
-{
- ChannelDriver *driver;
-
- /* sanity checks */
- // TODO: make these tests report errors using reports not printf's
- if ELEM(NULL, fcu, fcu->modifiers.first) {
- printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
- return;
- }
-
- /* temporarily, disable driver while we sample, so that they don't influence the outcome */
- driver= fcu->driver;
- fcu->driver= NULL;
-
- /* bake the modifiers, by sampling the curve at each frame */
- fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
-
- /* free the modifiers now */
- free_fmodifiers(&fcu->modifiers);
-
- /* restore driver */
- fcu->driver= driver;
-}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 3facf975992..8f67fdc74d2 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -66,19 +66,24 @@
/* -- */
#include "BKE_object.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
#include "BLI_arithb.h"
+#include "bmesh.h"
EditMesh *BKE_mesh_get_editmesh(Mesh *me)
{
- return me->edit_mesh;
+ return bmesh_to_editmesh(me->edit_btmesh->bm);
}
void BKE_mesh_end_editmesh(Mesh *me, EditMesh *em)
{
+ BM_Free_Mesh(me->edit_btmesh->bm);
+ me->edit_btmesh->bm = editmesh_to_bmesh(em);
+ BMEdit_RecalcTesselation(me->edit_btmesh);
}
@@ -93,6 +98,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
@@ -141,12 +153,14 @@ void free_mesh(Mesh *me)
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
if(me->mat) MEM_freeN(me->mat);
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)
@@ -205,6 +219,7 @@ Mesh *copy_mesh(Mesh *me)
{
Mesh *men;
MTFace *tface;
+ MTexPoly *txface;
int a, i;
men= copy_libblock(me);
@@ -218,6 +233,8 @@ Mesh *copy_mesh(Mesh *me)
CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert);
CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge);
CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface);
+ CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop);
+ CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly);
mesh_update_customdata_pointers(men);
/* ensure indirect linked data becomes lib-extern */
@@ -230,7 +247,17 @@ Mesh *copy_mesh(Mesh *me)
id_lib_extern((ID*)tface->tpage);
}
}
-
+
+ for(i=0; i<me->pdata.totlayer; i++) {
+ if(me->pdata.layers[i].type == CD_MTEXPOLY) {
+ txface= (MTexPoly*)me->pdata.layers[i].data;
+
+ for(a=0; a<me->totpoly; a++, txface++)
+ if(txface->tpage)
+ id_lib_extern((ID*)txface->tpage);
+ }
+ }
+
men->mselect= NULL;
men->bb= MEM_dupallocN(men->bb);
@@ -241,12 +268,43 @@ Mesh *copy_mesh(Mesh *me)
return men;
}
+BMesh *BKE_mesh_to_bmesh(Mesh *me)
+{
+ BMesh *bm;
+ int allocsize[4] = {512,512,2048,512};
+
+ bm = BM_Make_Mesh(allocsize);
+
+ BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p", me);
+
+ return bm;
+}
+
void make_local_tface(Mesh *me)
{
MTFace *tface;
+ MTexPoly *txface;
Image *ima;
int a, i;
+ for(i=0; i<me->pdata.totlayer; i++) {
+ if(me->pdata.layers[i].type == CD_MTEXPOLY) {
+ txface= (MTexPoly*)me->fdata.layers[i].data;
+
+ for(a=0; a<me->totpoly; a++, txface++) {
+ /* special case: ima always local immediately */
+ if(txface->tpage) {
+ ima= txface->tpage;
+ if(ima->id.lib) {
+ ima->id.lib= 0;
+ ima->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ima, 0);
+ }
+ }
+ }
+ }
+ }
+
for(i=0; i<me->fdata.totlayer; i++) {
if(me->fdata.layers[i].type == CD_MTFACE) {
tface= (MTFace*)me->fdata.layers[i].data;
@@ -264,6 +322,7 @@ void make_local_tface(Mesh *me)
}
}
}
+
}
void make_local_mesh(Mesh *me)
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 046dfcc9f87..fc4788d9ff3 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -24,7 +24,8 @@
* Ton Roosendaal,
* Ben Batt,
* Brecht Van Lommel,
-* Campbell Barton
+* Campbell Barton,
+* Joseph Eagar
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -100,6 +101,7 @@
#include "BKE_subsurf.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "depsgraph_private.h"
#include "BKE_deform.h"
@@ -263,12 +265,12 @@ static void curveModifier_deformVerts(
}
static void curveModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, 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);
curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0);
@@ -355,12 +357,12 @@ static void latticeModifier_deformVerts(
}
static void latticeModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, 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);
latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts, 0, 0);
@@ -416,7 +418,7 @@ static DerivedMesh *subsurfModifier_applyModifier(
}
static DerivedMesh *subsurfModifier_applyModifierEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData)
{
SubsurfModifierData *smd = (SubsurfModifierData*) md;
@@ -484,7 +486,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
"build modifier edgeMap");
for(i = 0; i < maxEdges; ++i) edgeMap[i] = i;
- maxFaces = dm->getNumFaces(dm);
+ maxFaces = dm->getNumTessFaces(dm);
faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces,
"build modifier faceMap");
for(i = 0; i < maxFaces; ++i) faceMap[i] = i;
@@ -497,7 +499,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
}
CLAMP(frac, 0.0, 1.0);
- numFaces = dm->getNumFaces(dm) * frac;
+ numFaces = dm->getNumTessFaces(dm) * frac;
numEdges = dm->getNumEdges(dm) * frac;
/* if there's at least one face, build based on faces */
@@ -513,7 +515,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
*/
for(i = 0; i < numFaces; ++i) {
MFace mf;
- dm->getFace(dm, faceMap[i], &mf);
+ dm->getTessFace(dm, faceMap[i], &mf);
if(!BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)))
BLI_ghash_insert(vertHash, SET_INT_IN_POINTER(mf.v1),
@@ -589,7 +591,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
* the mesh
*/
result = CDDM_from_template(dm, BLI_ghash_size(vertHash),
- BLI_ghash_size(edgeHash), numFaces);
+ BLI_ghash_size(edgeHash), numFaces, 0, 0);
/* copy the vertices across */
for(hashIter = BLI_ghashIterator_new(vertHash);
@@ -630,8 +632,8 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
MFace *dest;
int orig_v4;
- dm->getFace(dm, faceMap[i], &source);
- dest = CDDM_get_face(result, i);
+ dm->getTessFace(dm, faceMap[i], &source);
+ dest = CDDM_get_tessface(result, i);
orig_v4 = source.v4;
@@ -641,13 +643,14 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
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);
+ DM_copy_tessface_data(dm, result, faceMap[i], i, 1);
*dest = source;
test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3));
}
CDDM_calc_normals(result);
+ CDDM_tessfaces_to_faces(result);
BLI_ghash_free(vertHash, NULL, NULL);
BLI_ghash_free(edgeHash, NULL, NULL);
@@ -655,7 +658,7 @@ static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
MEM_freeN(vertMap);
MEM_freeN(edgeMap);
MEM_freeN(faceMap);
-
+
return result;
}
@@ -719,7 +722,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob,
/* get original number of verts, edges, and faces */
maxVerts= dm->getNumVerts(dm);
maxEdges= dm->getNumEdges(dm);
- maxFaces= dm->getNumFaces(dm);
+ maxFaces= dm->getNumTessFaces(dm);
/* check if we can just return the original mesh
* - must have verts and therefore verts assigned to vgroups to do anything useful
@@ -913,7 +916,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob,
for (i = 0; i < maxFaces; i++)
{
MFace mf;
- dm->getFace(dm, i, &mf);
+ dm->getTessFace(dm, i, &mf);
/* all verts must be available */
if ( BLI_ghash_haskey(vertHash, SET_INT_IN_POINTER(mf.v1)) &&
@@ -930,7 +933,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob,
/* now we know the number of verts, edges and faces,
* we can create the new (reduced) mesh
*/
- result = CDDM_from_template(dm, numVerts, numEdges, numFaces);
+ result = CDDM_from_template(dm, numVerts, numEdges, numFaces, 0, 0);
/* using ghash-iterators, map data into new mesh */
@@ -984,8 +987,8 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob,
int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
int orig_v4;
- dm->getFace(dm, oldIndex, &source);
- dest = CDDM_get_face(result, newIndex);
+ dm->getTessFace(dm, oldIndex, &source);
+ dest = CDDM_get_tessface(result, newIndex);
orig_v4 = source.v4;
@@ -995,7 +998,7 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob,
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);
+ DM_copy_tessface_data(dm, result, oldIndex, newIndex, 1);
*dest = source;
test_index_face(dest, &result->faceData, newIndex, (orig_v4 ? 4 : 3));
@@ -1010,6 +1013,8 @@ static DerivedMesh *maskModifier_applyModifier(ModifierData *md, Object *ob,
BLI_ghash_free(edgeHash, NULL, NULL);
BLI_ghash_free(faceHash, NULL, NULL);
+ CDDM_tessfaces_to_faces(result);
+
/* return the new mesh */
return result;
}
@@ -1157,6 +1162,7 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
}
}
+#if 0
static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
Scene *scene, Object *ob, DerivedMesh *dm,
int initFlags)
@@ -1259,18 +1265,18 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
*/
finalVerts = dm->getNumVerts(dm) * count;
finalEdges = dm->getNumEdges(dm) * count;
- finalFaces = dm->getNumFaces(dm) * count;
+ finalFaces = dm->getNumTessFaces(dm) * count;
if(start_cap) {
finalVerts += start_cap->getNumVerts(start_cap);
finalEdges += start_cap->getNumEdges(start_cap);
- finalFaces += start_cap->getNumFaces(start_cap);
+ finalFaces += start_cap->getNumTessFaces(start_cap);
}
if(end_cap) {
finalVerts += end_cap->getNumVerts(end_cap);
finalEdges += end_cap->getNumEdges(end_cap);
- finalFaces += end_cap->getNumFaces(end_cap);
+ finalFaces += end_cap->getNumTessFaces(end_cap);
}
- result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces);
+ result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces, 0, 0);
/* calculate the offset matrix of the final copy (for merging) */
MTC_Mat4One(final_offset);
@@ -1421,15 +1427,15 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
}
}
- maxFaces = dm->getNumFaces(dm);
- mface = CDDM_get_faces(result);
+ maxFaces = dm->getNumTessFaces(dm);
+ mface = CDDM_get_tessfaces(result);
for (i=0; i < maxFaces; i++) {
MFace inMF;
MFace *mf = &mface[numFaces];
- dm->getFace(dm, i, &inMF);
+ dm->getTessFace(dm, i, &inMF);
- DM_copy_face_data(dm, result, i, numFaces, 1);
+ DM_copy_tessface_data(dm, result, i, numFaces, 1);
*mf = inMF;
mf->v1 = indexMap[inMF.v1].new;
@@ -1465,7 +1471,7 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
{
MFace *mf2 = &mface[numFaces];
- DM_copy_face_data(dm, result, i, numFaces, 1);
+ DM_copy_tessface_data(dm, result, i, numFaces, 1);
*mf2 = *mf;
mf2->v1 = calc_mapping(indexMap, inMF.v1, j);
@@ -1498,10 +1504,10 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
capVerts = start_cap->getNumVerts(start_cap);
capEdges = start_cap->getNumEdges(start_cap);
- capFaces = start_cap->getNumFaces(start_cap);
+ capFaces = start_cap->getNumTessFaces(start_cap);
cap_mvert = start_cap->getVertArray(start_cap);
cap_medge = start_cap->getEdgeArray(start_cap);
- cap_mface = start_cap->getFaceArray(start_cap);
+ cap_mface = start_cap->getTessFaceArray(start_cap);
Mat4Invert(startoffset, offset);
@@ -1560,9 +1566,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
numEdges++;
}
}
- origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
+ origindex = result->getTessFaceDataArray(result, CD_ORIGINDEX);
for(i = 0; i < capFaces; i++) {
- DM_copy_face_data(start_cap, result, i, numFaces, 1);
+ DM_copy_tessface_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];
@@ -1599,10 +1605,10 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
capVerts = end_cap->getNumVerts(end_cap);
capEdges = end_cap->getNumEdges(end_cap);
- capFaces = end_cap->getNumFaces(end_cap);
+ capFaces = end_cap->getNumTessFaces(end_cap);
cap_mvert = end_cap->getVertArray(end_cap);
cap_medge = end_cap->getEdgeArray(end_cap);
- cap_mface = end_cap->getFaceArray(end_cap);
+ cap_mface = end_cap->getTessFaceArray(end_cap);
Mat4MulMat4(endoffset, final_offset, offset);
@@ -1661,9 +1667,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
numEdges++;
}
}
- origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
+ origindex = result->getTessFaceDataArray(result, CD_ORIGINDEX);
for(i = 0; i < capFaces; i++) {
- DM_copy_face_data(end_cap, result, i, numFaces, 1);
+ DM_copy_tessface_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];
@@ -1694,6 +1700,8 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
CDDM_lower_num_verts(result, numVerts);
CDDM_lower_num_edges(result, numEdges);
CDDM_lower_num_faces(result, numFaces);
+
+ CDDM_tessfaces_to_faces(result);
return result;
}
@@ -1714,11 +1722,19 @@ static DerivedMesh *arrayModifier_applyModifier(
}
static DerivedMesh *arrayModifier_applyModifierEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData)
{
return arrayModifier_applyModifier(md, ob, derivedData, 0, 1);
}
+#endif
+
+DerivedMesh *arrayModifier_applyModifier(ModifierData *md, Object *ob,
+ DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc);
+DerivedMesh *arrayModifier_applyModifierEM(ModifierData *md, Object *ob,
+ BMEditMesh *editData,
+ DerivedMesh *derivedData);
/* Mirror */
@@ -1877,6 +1893,7 @@ void vertgroup_flip_name (char *name, int strip_number)
sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
}
+#if 0
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
Object *ob,
DerivedMesh *dm,
@@ -1889,7 +1906,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
int numVerts, numEdges, numFaces;
int maxVerts = dm->getNumVerts(dm);
int maxEdges = dm->getNumEdges(dm);
- int maxFaces = dm->getNumFaces(dm);
+ int maxFaces = dm->getNumTessFaces(dm);
int vector_size=0, j, a, b;
bDeformGroup *def, *defb;
bDeformGroup **vector_def = NULL;
@@ -1900,7 +1917,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
- result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
+ result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2, 0, 0);
if (mmd->flag & MOD_MIR_VGROUP) {
@@ -2035,11 +2052,11 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
for(i = 0; i < maxFaces; i++) {
MFace inMF;
- MFace *mf = CDDM_get_face(result, numFaces);
+ MFace *mf = CDDM_get_tessface(result, numFaces);
- dm->getFace(dm, i, &inMF);
+ dm->getTessFace(dm, i, &inMF);
- DM_copy_face_data(dm, result, i, numFaces, 1);
+ DM_copy_tessface_data(dm, result, i, numFaces, 1);
*mf = inMF;
numFaces++;
@@ -2052,10 +2069,10 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
|| indexMap[inMF.v2][1]
|| indexMap[inMF.v3][1]
|| (mf->v4 && indexMap[inMF.v4][1])) {
- MFace *mf2 = CDDM_get_face(result, numFaces);
+ MFace *mf2 = CDDM_get_tessface(result, numFaces);
static int corner_indices[4] = {2, 1, 0, 3};
- DM_copy_face_data(dm, result, i, numFaces, 1);
+ DM_copy_tessface_data(dm, result, i, numFaces, 1);
*mf2 = *mf;
mf2->v1 += indexMap[inMF.v1][1];
@@ -2065,7 +2082,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
/* mirror UVs if enabled */
if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
- MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE);
+ MTFace *tf = result->getTessFaceData(result, numFaces, CD_MTFACE);
if(tf) {
int j;
for(j = 0; j < 4; ++j) {
@@ -2079,7 +2096,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
/* Flip face normal */
SWAP(int, mf2->v1, mf2->v3);
- DM_swap_face_data(result, numFaces, corner_indices);
+ DM_swap_tessface_data(result, numFaces, corner_indices);
test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
numFaces++;
@@ -2094,8 +2111,11 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
CDDM_lower_num_edges(result, numEdges);
CDDM_lower_num_faces(result, numFaces);
+ CDDM_tessfaces_to_faces(result);
+
return result;
}
+#endif
static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
Object *ob, DerivedMesh *dm,
@@ -2137,7 +2157,7 @@ static DerivedMesh *mirrorModifier_applyModifier(
}
static DerivedMesh *mirrorModifier_applyModifierEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData)
{
return mirrorModifier_applyModifier(md, ob, derivedData, 0, 1);
@@ -2428,7 +2448,7 @@ static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm)
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
mesh = smoothmesh_new(totvert, totedge, totface,
totvert, totedge, totface);
@@ -2460,7 +2480,7 @@ static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm)
MVert v1, v2, v3;
int j;
- dm->getFace(dm, i, &mf);
+ dm->getTessFace(dm, i, &mf);
dm->getVert(dm, mf.v1, &v1);
dm->getVert(dm, mf.v2, &v2);
@@ -2502,11 +2522,12 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
{
DerivedMesh *result = CDDM_from_template(mesh->dm,
mesh->num_verts,
- mesh->num_edges,
- mesh->num_faces);
+ mesh->num_edges,
+ mesh->num_faces,
+ 0, 0);
MVert *new_verts = CDDM_get_verts(result);
MEdge *new_edges = CDDM_get_edges(result);
- MFace *new_faces = CDDM_get_faces(result);
+ MFace *new_faces = CDDM_get_tessfaces(result);
int i;
for(i = 0; i < mesh->num_verts; ++i) {
@@ -2533,9 +2554,9 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
SmoothFace *face = &mesh->faces[i];
MFace *newMF = &new_faces[face->newIndex];
- DM_copy_face_data(mesh->dm, result,
+ DM_copy_tessface_data(mesh->dm, result,
face->oldIndex, face->newIndex, 1);
- mesh->dm->getFace(mesh->dm, face->oldIndex, newMF);
+ mesh->dm->getTessFace(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;
@@ -2548,6 +2569,8 @@ static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
}
}
+ CDDM_tessfaces_to_faces(result);
+
return result;
}
@@ -3360,7 +3383,7 @@ static DerivedMesh *edgesplitModifier_applyModifier(
}
static DerivedMesh *edgesplitModifier_applyModifierEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData)
{
return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1);
@@ -3444,7 +3467,7 @@ static DerivedMesh *bevelModifier_applyModifier(
}
static DerivedMesh *bevelModifier_applyModifierEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData)
{
return bevelModifier_applyModifier(md, ob, derivedData, 0, 1);
@@ -3580,12 +3603,12 @@ static void get_texture_coords(DisplaceModifierData *dmd, Object *ob,
/* UVs need special handling, since they come from faces */
if(texmapping == MOD_DISP_MAP_UV) {
- if(dm->getFaceDataArray(dm, CD_MTFACE)) {
- MFace *mface = dm->getFaceArray(dm);
+ if(dm->getTessFaceDataArray(dm, CD_MTFACE)) {
+ MFace *mface = dm->getTessFaceArray(dm);
MFace *mf;
char *done = MEM_callocN(sizeof(*done) * numVerts,
"get_texture_coords done");
- int numFaces = dm->getNumFaces(dm);
+ int numFaces = dm->getNumTessFaces(dm);
char uvname[32];
MTFace *tf;
@@ -3772,13 +3795,13 @@ static void displaceModifier_deformVerts(
}
static void displaceModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm;
if(derivedData) dm = CDDM_copy(derivedData);
- else dm = CDDM_from_editmesh(editData, ob->data);
+ else dm = CDDM_from_BMEditMesh(editData, ob->data);
CDDM_apply_vert_coords(dm, vertexCos);
CDDM_calc_normals(dm);
@@ -3898,7 +3921,7 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
if(num_projectors == 0) return dm;
/* make sure there are UV layers available */
- if(!dm->getFaceDataArray(dm, CD_MTFACE)) return dm;
+ if(!dm->getTessFaceDataArray(dm, CD_MTFACE)) return dm;
/* make sure we're using an existing layer */
validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name, uvname);
@@ -4004,8 +4027,8 @@ static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
for(i = 0, co = coords; i < numVerts; ++i, ++co)
Mat4MulVec3Project(projectors[0].projmat, *co);
- mface = dm->getFaceArray(dm);
- numFaces = dm->getNumFaces(dm);
+ mface = dm->getTessFaceArray(dm);
+ numFaces = dm->getNumTessFaces(dm);
/* apply coords as UVs, and apply image if tfaces are new */
for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
@@ -4103,7 +4126,7 @@ static DerivedMesh *uvprojectModifier_applyModifier(
}
static DerivedMesh *uvprojectModifier_applyModifierEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData)
{
return uvprojectModifier_applyModifier(md, ob, derivedData, 0, 1);
@@ -4139,9 +4162,9 @@ static DerivedMesh *decimateModifier_applyModifier(
int a, numTris;
mvert = dm->getVertArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
totvert = dm->getNumVerts(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
numTris = 0;
for (a=0; a<totface; a++) {
@@ -4217,7 +4240,7 @@ static DerivedMesh *decimateModifier_applyModifier(
}
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];
@@ -4456,13 +4479,13 @@ static void smoothModifier_deformVerts(
}
static void smoothModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm;
if(derivedData) dm = CDDM_copy(derivedData);
- else dm = CDDM_from_editmesh(editData, ob->data);
+ else dm = CDDM_from_BMEditMesh(editData, ob->data);
CDDM_apply_vert_coords(dm, vertexCos);
CDDM_calc_normals(dm);
@@ -5037,14 +5060,14 @@ static void castModifier_deformVerts(
}
static void castModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = derivedData;
CastModifierData *cmd = (CastModifierData *)md;
if (!dm && ob->type == OB_MESH)
- dm = CDDM_from_editmesh(editData, ob->data);
+ dm = CDDM_from_BMEditMesh(editData, ob->data);
if (cmd->type == MOD_CAST_TYPE_CUBOID) {
castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts);
@@ -5181,12 +5204,12 @@ static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob,
/* UVs need special handling, since they come from faces */
if(texmapping == MOD_WAV_MAP_UV) {
- if(dm->getFaceDataArray(dm, CD_MTFACE)) {
- MFace *mface = dm->getFaceArray(dm);
+ if(dm->getTessFaceDataArray(dm, CD_MTFACE)) {
+ MFace *mface = dm->getTessFaceArray(dm);
MFace *mf;
char *done = MEM_callocN(sizeof(*done) * numVerts,
"get_texture_coords done");
- int numFaces = dm->getNumFaces(dm);
+ int numFaces = dm->getNumTessFaces(dm);
char uvname[32];
MTFace *tf;
@@ -5443,7 +5466,7 @@ static void waveModifier_deformVerts(
}
static void waveModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm;
@@ -5452,7 +5475,7 @@ static void waveModifier_deformVertsEM(
if(!wmd->texture && !wmd->defgrp_name[0] && !(wmd->flag & MOD_WAVE_NORM))
dm = derivedData;
else if(derivedData) dm = CDDM_copy(derivedData);
- else dm = CDDM_from_editmesh(editData, ob->data);
+ else dm = CDDM_from_BMEditMesh(editData, ob->data);
if(wmd->flag & MOD_WAVE_NORM) {
CDDM_apply_vert_coords(dm, vertexCos);
@@ -5543,13 +5566,13 @@ static void armatureModifier_deformVerts(
}
static void armatureModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, 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);
armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts,
amd->deformflag, NULL, amd->defgrp_name);
@@ -5558,14 +5581,14 @@ static void armatureModifier_deformVertsEM(
}
static void armatureModifier_deformMatricesEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, 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);
armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts,
amd->deformflag, NULL, amd->defgrp_name);
@@ -5761,12 +5784,12 @@ static void hookModifier_deformVerts(
}
static void hookModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, 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);
hookModifier_deformVerts(md, ob, derivedData, vertexCos, numVerts, 0, 0);
@@ -6018,8 +6041,8 @@ static void collisionModifier_deformVerts(
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);
@@ -6218,8 +6241,8 @@ static DerivedMesh *booleanModifier_applyModifier(
DerivedMesh *dm = mesh_get_derived_final(md->scene, bmd->object, CD_MASK_BAREMESH);
/* we do a quick sanity check */
- if(dm && (derivedData->getNumFaces(derivedData) > 3)
- && bmd->object && dm->getNumFaces(dm) > 3) {
+ if(dm && (derivedData->getNumTessFaces(derivedData) > 3)
+ && bmd->object && dm->getNumTessFaces(dm) > 3) {
DerivedMesh *result = NewBooleanDerivedMesh(dm, bmd->object, derivedData, ob,
1 + bmd->operation);
@@ -6378,7 +6401,7 @@ static void particleSystemModifier_deformVerts(
/* 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){
/* in file read dm hasn't really changed but just wasn't saved in file */
psys->recalc |= PSYS_RECALC_RESET;
@@ -6386,7 +6409,7 @@ static void particleSystemModifier_deformVerts(
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){
@@ -6401,12 +6424,12 @@ static void particleSystemModifier_deformVerts(
* updates is coded */
#if 0
static void particleSystemModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, 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);
particleSystemModifier_deformVerts(md, ob, dm, vertexCos, numVerts);
@@ -6526,7 +6549,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
pars=psys->particles;
totvert=dm->getNumVerts(dm);
- totface=dm->getNumFaces(dm);
+ totface=dm->getNumTessFaces(dm);
maxvert=totvert*totpart;
maxface=totface*totpart;
@@ -6542,7 +6565,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
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);
@@ -6614,8 +6637,8 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
VECADD(mv->co,mv->co,state.co);
}
- mface=result->getFaceArray(result);
- orig_mface=dm->getFaceArray(dm);
+ mface=result->getTessFaceArray(result);
+ orig_mface=dm->getTessFaceArray(dm);
for(i=0; i<maxface; i++){
MFace *inMF;
@@ -6645,7 +6668,7 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
}
inMF = orig_mface + i%totface;
- DM_copy_face_data(dm, result, i%totface, i, 1);
+ DM_copy_tessface_data(dm, result, i%totface, i, 1);
*mf = *inMF;
mf->v1+=(i/totface)*totvert;
@@ -6662,14 +6685,15 @@ static DerivedMesh * particleInstanceModifier_applyModifier(
end_latt_deform(psys->lattice);
psys->lattice= NULL;
}
-
+
+ CDDM_tessfaces_to_faces(result);
if(size)
MEM_freeN(size);
return result;
}
static DerivedMesh *particleInstanceModifier_applyModifierEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData)
{
return particleInstanceModifier_applyModifier(md, ob, derivedData, 0, 1);
@@ -6728,8 +6752,8 @@ static void explodeModifier_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;
@@ -6811,12 +6835,12 @@ static int edgesplit_get(EdgeHash *edgehash, int v1, int v2)
static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, DerivedMesh *dm){
DerivedMesh *splitdm;
MFace *mf=0,*df1=0,*df2=0,*df3=0;
- MFace *mface=CDDM_get_faces(dm);
+ MFace *mface=CDDM_get_tessfaces(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");
@@ -6902,14 +6926,14 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
else if(*fs==4){
totfsplit+=3;
- mf=dm->getFaceData(dm,i,CD_MFACE);//CDDM_get_face(dm,i);
+ mf=dm->getTessFaceData(dm,i,CD_MFACE);//CDDM_get_tessface(dm,i);
if(vertpa[mf->v1]!=vertpa[mf->v2] && vertpa[mf->v2]!=vertpa[mf->v3])
totin++;
}
}
- splitdm= CDDM_from_template(dm, totesplit+totin, dm->getNumEdges(dm),totface+totfsplit);
+ splitdm= CDDM_from_template(dm, totesplit+totin, dm->getNumEdges(dm),totface+totfsplit, 0, 0);
/* copy new faces & verts (is it really this painful with custom data??) */
for(i=0; i<totvert; i++){
@@ -6924,10 +6948,10 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
for(i=0; i<totface; i++){
MFace source;
MFace *dest;
- dm->getFace(dm, i, &source);
- dest = CDDM_get_face(splitdm, i);
+ dm->getTessFace(dm, i, &source);
+ dest = CDDM_get_tessface(splitdm, i);
- DM_copy_face_data(dm, splitdm, i, i, 1);
+ DM_copy_tessface_data(dm, splitdm, i, i, 1);
*dest = source;
}
@@ -6961,7 +6985,7 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
curdupin=totesplit;
for(i=0,fs=facesplit; i<totface; i++,fs++){
if(*fs){
- mf=CDDM_get_face(splitdm,i);
+ mf=CDDM_get_tessface(splitdm,i);
v1=vertpa[mf->v1];
v2=vertpa[mf->v2];
@@ -6969,8 +6993,8 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
v4=vertpa[mf->v4];
/* ouch! creating new faces & remapping them to new verts is no fun */
if(*fs==1){
- df1=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df1=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df1=*mf;
curdupface++;
@@ -6993,13 +7017,13 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
test_index_face(df1, &splitdm->faceData, curdupface, (df1->v4 ? 4 : 3));
}
if(*fs==2){
- df1=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df1=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df1=*mf;
curdupface++;
- df2=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df2=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df2=*mf;
curdupface++;
@@ -7070,18 +7094,18 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3));
}
else if(*fs==3){
- df1=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df1=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df1=*mf;
curdupface++;
- df2=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df2=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df2=*mf;
curdupface++;
- df3=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df3=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df3=*mf;
curdupface++;
@@ -7171,18 +7195,18 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
VecMulf(dupve->co,0.25);
- df1=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df1=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df1=*mf;
curdupface++;
- df2=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df2=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df2=*mf;
curdupface++;
- df3=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df3=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df3=*mf;
curdupface++;
@@ -7211,18 +7235,18 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
test_index_face(df1, &splitdm->faceData, curdupface-1, (df1->v4 ? 4 : 3));
}
else{
- df1=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df1=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df1=*mf;
curdupface++;
- df2=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df2=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df2=*mf;
curdupface++;
- df3=CDDM_get_face(splitdm,curdupface);
- DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
+ df3=CDDM_get_tessface(splitdm,curdupface);
+ DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
*df3=*mf;
curdupface++;
@@ -7276,7 +7300,8 @@ static DerivedMesh * explodeModifier_splitEdges(ExplodeModifierData *emd, Derive
BLI_edgehash_free(edgehash, NULL);
MEM_freeN(facesplit);
MEM_freeN(vertpa);
-
+
+ CDDM_tessfaces_to_faces(splitdm);
return splitdm;
}
@@ -7298,7 +7323,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd,
int totdup=0,totvert=0,totface=0,totpart=0;
int i, j, v, mindex=0;
- totface= dm->getNumFaces(dm);
+ totface= dm->getNumTessFaces(dm);
totvert= dm->getNumVerts(dm);
totpart= psmd->psys->totpart;
@@ -7320,7 +7345,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd,
else
mindex = totvert+facepa[i];
- mf=CDDM_get_face(dm,i);
+ mf=CDDM_get_tessface(dm,i);
/* set face vertices to exist in particle group */
BLI_edgehash_insert(vertpahash, mf->v1, mindex, NULL);
@@ -7339,7 +7364,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd,
BLI_edgehashIterator_free(ehi);
/* the final duplicated vertices */
- explode= CDDM_from_template(dm, totdup, 0,totface);
+ explode= CDDM_from_template(dm, totdup, 0,totface, 0, 0);
/*dupvert= CDDM_get_verts(explode);*/
/* getting back to object space */
@@ -7405,8 +7430,8 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd,
if(pa->alive==PARS_DEAD && (emd->flag&eExplodeFlag_Dead)==0) continue;
}
- dm->getFace(dm,i,&source);
- mf=CDDM_get_face(explode,i);
+ dm->getTessFace(dm,i,&source);
+ mf=CDDM_get_tessface(explode,i);
orig_v4 = source.v4;
@@ -7421,7 +7446,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd,
if(source.v4)
source.v4 = edgesplit_get(vertpahash, source.v4, mindex);
- DM_copy_face_data(dm,explode,i,i,1);
+ DM_copy_tessface_data(dm,explode,i,i,1);
*mf = source;
@@ -7442,6 +7467,7 @@ static DerivedMesh * explodeModifier_explodeMesh(ExplodeModifierData *emd,
psmd->psys->lattice= NULL;
}
+ CDDM_tessfaces_to_faces(explode);
return explode;
}
@@ -7475,7 +7501,7 @@ static DerivedMesh * explodeModifier_applyModifier(
if(emd->facepa==0
|| psmd->flag&eParticleSystemFlag_Pars
|| emd->flag&eExplodeFlag_CalcFaces
- || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumFaces(dm)){
+ || MEM_allocN_len(emd->facepa)/sizeof(int) != dm->getNumTessFaces(dm)){
if(psmd->flag & eParticleSystemFlag_Pars)
psmd->flag &= ~eParticleSystemFlag_Pars;
@@ -7718,10 +7744,10 @@ static void meshdeformModifier_do(
{
MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
Mesh *me= ob->data;
+ BMEditMesh *bem = me->edit_btmesh;
DerivedMesh *tmpdm, *cagedm;
MDeformVert *dvert = NULL;
MDeformWeight *dw;
- EditMesh *em = BKE_mesh_get_editmesh(me);
MVert *cagemvert;
float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4];
float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3];
@@ -7731,11 +7757,10 @@ static void meshdeformModifier_do(
return;
/* get cage derivedmesh */
- if(em) {
- tmpdm= editmesh_get_derived_cage_and_final(md->scene, ob, em, &cagedm, 0);
+ if(bem) {
+ tmpdm= editbmesh_get_derived_cage_and_final(md->scene, ob, bem, &cagedm, 0);
if(tmpdm)
tmpdm->release(tmpdm);
- BKE_mesh_end_editmesh(me, em);
}
else
cagedm= mmd->object->derivedFinal;
@@ -7897,13 +7922,13 @@ static void meshdeformModifier_deformVerts(
}
static void meshdeformModifier_deformVertsEM(
- ModifierData *md, Object *ob, EditMesh *editData,
+ ModifierData *md, Object *ob, BMEditMesh *editData,
DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm;
if(!derivedData && ob->type == OB_MESH)
- dm = CDDM_from_editmesh(editData, ob->data);
+ dm = CDDM_from_BMEditMesh(editData, ob->data);
else
dm = derivedData;
@@ -8055,7 +8080,7 @@ static void shrinkwrapModifier_deformVerts(ModifierData *md, Object *ob, Derived
dm->release(dm);
}
-static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = NULL;
CustomDataMask dataMask = shrinkwrapModifier_requiredDataMask(ob, md);
@@ -8063,7 +8088,7 @@ static void shrinkwrapModifier_deformVertsEM(ModifierData *md, Object *ob, EditM
if(dataMask)
{
if(derivedData) dm = CDDM_copy(derivedData);
- else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob->data);
+ else if(ob->type==OB_MESH) dm = CDDM_from_BMEditMesh(editData, ob->data);
else if(ob->type==OB_LATTICE) dm = NULL;
else return;
@@ -8170,7 +8195,7 @@ static void simpledeformModifier_deformVerts(ModifierData *md, Object *ob, Deriv
}
-static void simpledeformModifier_deformVertsEM(ModifierData *md, Object *ob, EditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+static void simpledeformModifier_deformVertsEM(ModifierData *md, Object *ob, BMEditMesh *editData, DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
{
DerivedMesh *dm = NULL;
CustomDataMask dataMask = simpledeformModifier_requiredDataMask(ob, md);
@@ -8179,7 +8204,7 @@ static void simpledeformModifier_deformVertsEM(ModifierData *md, Object *ob, Edi
if(dataMask)
{
if(derivedData) dm = CDDM_copy(derivedData);
- else if(ob->type==OB_MESH) dm = CDDM_from_editmesh(editData, ob->data);
+ else if(ob->type==OB_MESH) dm = CDDM_from_BMEditMesh(editData, ob->data);
else if(ob->type==OB_LATTICE) dm = NULL;
else return;
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
new file mode 100644
index 00000000000..b3ce91855b2
--- /dev/null
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -0,0 +1,568 @@
+/*
+* $Id: modifier_bmesh.c 20831 2009-06-12 14:02:37Z joeedh $
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2005 by the Blender Foundation.
+* All rights reserved.
+*
+* Contributor(s): Joseph Eagar
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Modifier stack implementation.
+*
+* BKE_modifier.h contains the function prototypes for this file.
+*
+*/
+
+#include "string.h"
+#include "stdarg.h"
+#include "math.h"
+#include "float.h"
+#include "ctype.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_kdtree.h"
+#include "BLI_linklist.h"
+#include "BLI_rand.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_cloth_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_editVert.h"
+
+#include "MTC_matrixops.h"
+#include "MTC_vectorops.h"
+
+#include "BKE_main.h"
+#include "BKE_anim.h"
+#include "BKE_bmesh.h"
+// XXX #include "BKE_booleanops.h"
+#include "BKE_cloth.h"
+#include "BKE_collision.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_fluidsim.h"
+#include "BKE_global.h"
+#include "BKE_multires.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_softbody.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
+
+#include "depsgraph_private.h"
+#include "BKE_deform.h"
+#include "BKE_shrinkwrap.h"
+#include "BKE_simple_deform.h"
+
+#include "CCGSubSurf.h"
+#include "RE_shader_ext.h"
+#include "LOD_decimation.h"
+
+/*converts a cddm to a BMEditMesh. if existing is non-NULL, the
+ new geometry will be put in there.*/
+BMEditMesh *CDDM_To_BMesh(DerivedMesh *dm, BMEditMesh *existing)
+{
+ int allocsize[4] = {512, 512, 2048, 512};
+ BMesh *bm, bmold; /*bmold is for storing old customdata layout*/
+ BMEditMesh *em = existing;
+ MVert *mv;
+ MEdge *me;
+ DMFaceIter *dfiter;
+ DMLoopIter *dliter;
+ BMVert *v, **vtable, **verts=NULL;
+ BMEdge *e, **etable, **edges=NULL;
+ BMFace *f;
+ BMIter liter, iter;
+ V_DECLARE(verts);
+ V_DECLARE(edges);
+ void *tmp;
+ int numTex, numCol;
+ int i, j, k, tot, totvert, totedge, totface;
+
+ if (em) bm = em->bm;
+ else bm = BM_Make_Mesh(allocsize);
+
+ bmold = *bm;
+
+ /*merge custom data layout*/
+ CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_VERT);
+ CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_EDGE);
+ CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_LOOP);
+ CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_BMESH|CD_MASK_ORIGINDEX, CD_CALLOC, bm, BM_FACE);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+
+ vtable = MEM_callocN(sizeof(void**)*totvert, "vert table in BMDM_Copy");
+ etable = MEM_callocN(sizeof(void**)*totedge, "edge table in BMDM_Copy");
+
+ /*do verts*/
+ mv = dm->dupVertArray(dm);
+ for (i=0; i<totvert; i++, mv++) {
+ v = BM_Make_Vert(bm, mv->co, NULL);
+
+ v->bweight = mv->bweight;
+ VECCOPY(v->no, mv->no);
+ v->head.flag = MEFlags_To_BMFlags(mv->flag, BM_VERT);
+
+ CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data);
+ vtable[i] = v;
+ }
+
+ /*do edges*/
+ me = dm->dupEdgeArray(dm);
+ for (i=0; i<totedge; i++, me++) {
+ e = BM_Make_Edge(bm, vtable[me->v1], vtable[me->v2], NULL, 0);
+
+ e->bweight = me->bweight;
+ e->crease = me->crease;
+ e->head.flag = MEFlags_To_BMFlags(me->flag, BM_EDGE);
+
+ CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data);
+ etable[i] = e;
+ }
+
+ k = 0;
+ dfiter = dm->newFaceIter(dm);
+ for (; !dfiter->done; dfiter->step(dfiter)) {
+ BMLoop *l;
+
+ V_RESET(verts);
+ V_RESET(edges);
+
+ dliter = dfiter->getLoopsIter(dfiter);
+ for (j=0; !dliter->done; dliter->step(dliter), j++) {
+ V_GROW(verts);
+ V_GROW(edges);
+
+ verts[j] = vtable[dliter->vindex];
+ edges[j] = etable[dliter->eindex];
+ }
+
+ f = BM_Make_Ngon(bm, verts[0], verts[1], edges, dfiter->len, 0);
+ f->head.flag = MEFlags_To_BMFlags(dfiter->flags, BM_FACE);
+
+ if (!f)
+ continue;
+
+ dliter = dfiter->getLoopsIter(dfiter);
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (j=0; l; l=BMIter_Step(&liter)) {
+ CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data);
+ k += 1;
+ }
+
+ CustomData_to_bmesh_block(&dm->polyData, &bm->pdata,
+ dfiter->index, &f->head.data);
+ }
+
+ MEM_freeN(vtable);
+ MEM_freeN(etable);
+
+ if (!em) em = BMEdit_Create(bm);
+ else BMEdit_RecalcTesselation(em);
+
+ return em;
+}
+
+float vertarray_size(MVert *mvert, int numVerts, int axis);
+
+
+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;
+
+/* 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);
+ }
+}
+
+static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
+ Scene *scene, Object *ob, DerivedMesh *dm,
+ int initFlags)
+{
+ DerivedMesh *cddm = CDDM_copy(dm);
+ BMEditMesh *em = CDDM_To_BMesh(cddm, NULL);
+ BMOperator op, oldop, weldop;
+ int i, j, indexLen;
+ /* offset matrix */
+ float offset[4][4];
+ float final_offset[4][4];
+ float tmp_mat[4][4];
+ float length = amd->length;
+ int count = amd->count;
+ int numVerts, numEdges, numFaces;
+ int maxVerts, maxEdges, maxFaces;
+ int finalVerts, finalEdges, finalFaces;
+ int *indexMap;
+ DerivedMesh *result, *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 = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH);
+ if(amd->end_cap && amd->end_cap != ob)
+ end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH);
+
+ MTC_Mat4One(offset);
+
+ src_mvert = cddm->getVertArray(dm);
+ maxVerts = cddm->getNumVerts(dm);
+
+ if(amd->offset_type & MOD_ARR_OFF_CONST)
+ VecAddf(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,
+ maxVerts, j);
+ }
+
+ if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
+ float obinv[4][4];
+ float result_mat[4][4];
+
+ if(ob)
+ MTC_Mat4Invert(obinv, ob->obmat);
+ else
+ MTC_Mat4One(obinv);
+
+ MTC_Mat4MulSerie(result_mat, offset,
+ obinv, amd->offset_ob->obmat,
+ NULL, NULL, NULL, NULL, NULL);
+ MTC_Mat4CpyMat4(offset, result_mat);
+ }
+
+ if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
+ Curve *cu = amd->curve_ob->data;
+ if(cu) {
+ float tmp_mat[3][3];
+ float scale;
+
+ object_to_mat3(amd->curve_ob, tmp_mat);
+ scale = Mat3ToScalef(tmp_mat);
+
+ if(!cu->path) {
+ cu->flag |= CU_PATH; // needed for path & bevlist
+ makeDispListCurveTypes(scene, amd->curve_ob, 0);
+ }
+ if(cu->path)
+ length = scale*cu->path->totdist;
+ }
+ }
+
+ /* calculate the maximum number of copies which will fit within the
+ prescribed length */
+ if(amd->fit_type == MOD_ARR_FITLENGTH
+ || amd->fit_type == MOD_ARR_FITCURVE)
+ {
+ float dist = sqrt(MTC_dot3Float(offset[3], offset[3]));
+
+ if(dist > 1e-6f)
+ /* this gives length = first copy start to last copy end
+ add a tiny offset for floating point rounding errors */
+ count = (length + 1e-6f) / dist;
+ else
+ /* if the offset has no translation, just make one copy */
+ count = 1;
+ }
+
+ if(count < 1)
+ count = 1;
+
+ /* allocate memory for count duplicates (including original) plus
+ * start and end caps
+ */
+ finalVerts = dm->getNumVerts(dm) * count;
+ finalEdges = dm->getNumEdges(dm) * count;
+ finalFaces = dm->getNumFaces(dm) * count;
+ if(start_cap) {
+ finalVerts += start_cap->getNumVerts(start_cap);
+ finalEdges += start_cap->getNumEdges(start_cap);
+ finalFaces += start_cap->getNumFaces(start_cap);
+ }
+ if(end_cap) {
+ finalVerts += end_cap->getNumVerts(end_cap);
+ finalEdges += end_cap->getNumEdges(end_cap);
+ finalFaces += end_cap->getNumFaces(end_cap);
+ }
+
+ /* calculate the offset matrix of the final copy (for merging) */
+ MTC_Mat4One(final_offset);
+
+ for(j=0; j < count - 1; j++) {
+ MTC_Mat4MulMat4(tmp_mat, final_offset, offset);
+ MTC_Mat4CpyMat4(final_offset, tmp_mat);
+ }
+
+ cddm->needsFree = 1;
+ cddm->release(cddm);
+
+ BMO_Init_Op(&weldop, "weldverts");
+ BMO_InitOpf(em->bm, &op, "dupe geom=%avef");
+ oldop = op;
+ for (j=0; j < count; j++) {
+ BMVert *v, *v2;
+ BMOpSlot *s1;
+ BMOpSlot *s2;
+
+ BMO_InitOpf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
+ BMO_Exec_Op(em->bm, &op);
+
+ s1 = BMO_GetSlot(&op, "geom");
+ s2 = BMO_GetSlot(&op, "newout");
+
+ BMO_CallOpf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout");
+
+ #define _E(s, i) ((BMVert**)(s)->data.buf)[i]
+
+ /*calculate merge mapping*/
+ if (j == 0) {
+ BMOperator findop;
+ BMOIter oiter;
+ BMIter iter;
+ BMVert *v, *v2;
+ BMHeader *h;
+
+ BMO_InitOpf(em->bm, &findop,
+ "finddoubles verts=%av dist=%f keepverts=%s",
+ amd->merge_dist, &op, "geom");
+
+ i = 0;
+ BMO_ITER(h, &oiter, em->bm, &op, "geom", BM_ALL) {
+ BMINDEX_SET(h, i);
+ i++;
+ }
+
+ BMO_ITER(h, &oiter, em->bm, &op, "newout", BM_ALL) {
+ BMINDEX_SET(h, i);
+ i++;
+ }
+
+ BMO_Exec_Op(em->bm, &findop);
+
+ indexLen = i;
+ indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
+
+ /*element type argument doesn't do anything here*/
+ BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
+ v2 = BMO_IterMapValp(&oiter);
+
+ /*make sure merge pairs are duplicate-to-duplicate*/
+ /*if (BMINDEX_GET(v) >= s1->len && BMINDEX_GET(v2) >= s1->len)
+ continue;
+ else if (BMINDEX_GET(v) < s1->len && BMINDEX_GET(v2) < s1->len)
+ continue;*/
+
+ indexMap[BMINDEX_GET(v)] = BMINDEX_GET(v2)+1;
+ }
+
+ BMO_Finish_Op(em->bm, &findop);
+ }
+
+ /*generate merge mappping using index map. we do this by using the
+ operator slots as lookup arrays.*/
+ #define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len)
+
+ for (i=0; i<indexLen; i++) {
+ if (!indexMap[i]) continue;
+
+ v = E(i);
+ v2 = E(indexMap[i]-1);
+
+ BMO_Insert_MapPointer(em->bm, &weldop, "targetmap", v, v2);
+ }
+
+ #undef E
+ #undef _E
+
+ BMO_Finish_Op(em->bm, &oldop);
+ oldop = op;
+ }
+
+ if (j > 0) BMO_Finish_Op(em->bm, &op);
+
+ BMO_Exec_Op(em->bm, &weldop);
+ BMO_Finish_Op(em->bm, &weldop);
+
+ //BMO_CallOpf(em->bm, "removedoubles verts=%av dist=%f", amd->merge_dist);
+
+ BMEdit_RecalcTesselation(em);
+ cddm = CDDM_from_BMEditMesh(em, NULL);
+
+ BMEdit_Free(em);
+ MEM_freeN(indexMap);
+
+ return cddm;
+}
+
+DerivedMesh *arrayModifier_applyModifier(ModifierData *md, Object *ob,
+ DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ DerivedMesh *result;
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+
+ result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0);
+
+ //if(result != derivedData)
+ // CDDM_calc_normals(result);
+
+ return result;
+}
+
+DerivedMesh *arrayModifier_applyModifierEM(ModifierData *md, Object *ob,
+ BMEditMesh *editData,
+ DerivedMesh *derivedData)
+{
+ return arrayModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* Mirror */
+
+DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
+ Object *ob,
+ DerivedMesh *dm,
+ int initFlags,
+ int axis)
+{
+ int i;
+ float tolerance = mmd->tolerance;
+ DerivedMesh *result, *cddm;
+ BMEditMesh *em;
+ BMesh *bm;
+ int numVerts, numEdges, numFaces;
+ int maxVerts = dm->getNumVerts(dm);
+ int maxEdges = dm->getNumEdges(dm);
+ int maxFaces = dm->getNumTessFaces(dm);
+ int vector_size=0, j, a, b;
+ bDeformGroup *def, *defb;
+ bDeformGroup **vector_def = NULL;
+ int (*indexMap)[2];
+ float mtx[4][4], imtx[4][4];
+
+ cddm = CDDM_copy(dm);
+ em = CDDM_To_BMesh(dm, NULL);
+
+ cddm->needsFree = 1;
+ cddm->release(cddm);
+
+ /*convienence variable*/
+ bm = em->bm;
+
+ numVerts = numEdges = numFaces = 0;
+ indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
+ result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2, 0, 0);
+
+ if (mmd->flag & MOD_MIR_VGROUP) {
+ /* calculate the number of deformedGroups */
+ for(vector_size = 0, def = ob->defbase.first; def;
+ def = def->next, vector_size++);
+
+ /* load the deformedGroups for fast access */
+ vector_def =
+ (bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*) * vector_size,
+ "group_index");
+ for(a = 0, def = ob->defbase.first; def; def = def->next, a++) {
+ vector_def[a] = def;
+ }
+ }
+
+ if (mmd->mirror_ob) {
+ float obinv[4][4];
+
+ Mat4Invert(obinv, mmd->mirror_ob->obmat);
+ Mat4MulMat4(mtx, ob->obmat, obinv);
+ Mat4Invert(imtx, mtx);
+ }
+
+
+
+ BMEdit_RecalcTesselation(em);
+ result = CDDM_from_BMEditMesh(em, NULL);
+
+ BMEdit_Free(em);
+
+ return result;
+}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 5def910ddef..03838e3c258 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -469,7 +469,7 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int dista
mrdm = multires_dm_create_from_derived(&mmd_sub, orig, me, 0, 0);
totsubvert = mrdm->getNumVerts(mrdm);
totsubedge = mrdm->getNumEdges(mrdm);
- totsubface = mrdm->getNumFaces(mrdm);
+ totsubface = mrdm->getNumTessFaces(mrdm);
orig->needsFree = 1;
orig->release(orig);
@@ -1198,7 +1198,7 @@ static void multiresModifier_update(DerivedMesh *dm)
final = multires_subdisp_pre(dm, totlvl - lvl, 0);
multires_subdisp(orig, me, final, lvl, totlvl, dm->getNumVerts(dm), dm->getNumEdges(dm),
- dm->getNumFaces(dm), 1);
+ dm->getNumTessFaces(dm), 1);
subco_dm->release(subco_dm);
orig->release(orig);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 02c0d46a73f..82eca760a60 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -96,6 +96,7 @@
#include "BKE_lattice.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
@@ -862,7 +863,7 @@ void free_lamp(Lamp *la)
BKE_free_animdata((ID *)la);
- curvemapping_free(la->curfalloff);
+ curvemapping_free(la->curfalloff);
BKE_previewimg_free(&la->preview);
BKE_icon_delete(&la->id);
@@ -2314,12 +2315,11 @@ void object_handle_update(Scene *scene, Object *ob)
/* includes all keys and modifiers */
if(ob->type==OB_MESH) {
- EditMesh *em = BKE_mesh_get_editmesh(ob->data);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
- // here was vieweditdatamask? XXX
+ // here was vieweditdatamask? XXX
if(ob==scene->obedit) {
makeDerivedMesh(scene, ob, em, CD_MASK_BAREMESH);
- BKE_mesh_end_editmesh(ob->data, em);
} else
makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH);
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index cefeafcdd50..8e0e948f0a4 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -697,9 +697,9 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
return tot;
mvert= dm->getVertArray(dm);
- mface= dm->getFaceArray(dm);
- origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
- totface= dm->getNumFaces(dm);
+ mface= dm->getTessFaceArray(dm);
+ origindex= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ totface= dm->getNumTessFaces(dm);
totorigface= me->totface;
if(totface == 0 || totorigface == 0 || origindex == NULL)
@@ -1347,7 +1347,7 @@ float psys_interpolate_value_from_verts(DerivedMesh *dm, short from, int index,
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);
}
@@ -1395,11 +1395,11 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, float *
int quad, findex, totface;
float uv[2], (*faceuv)[2];
- mface = dm->getFaceDataArray(dm, CD_MFACE);
- origindex = dm->getFaceDataArray(dm, CD_ORIGINDEX);
- osface = dm->getFaceDataArray(dm, CD_ORIGSPACE);
+ mface = dm->getTessFaceDataArray(dm, CD_MFACE);
+ origindex = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
if(osface==NULL || origindex==NULL) {
/* Assume we dont need osface data */
@@ -1468,7 +1468,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;
@@ -1492,15 +1492,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;
@@ -1558,7 +1558,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);
@@ -2946,10 +2946,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)) { Mat4One(mat); return; }
+ if (i==-1 || i >= dm->getNumTessFaces(dm)) { Mat4One(mat); return; }
- mface=dm->getFaceData(dm,i,CD_MFACE);
- osface=dm->getFaceData(dm,i,CD_ORIGSPACE);
+ mface=dm->getTessFaceData(dm,i,CD_MFACE);
+ osface=dm->getTessFaceData(dm,i,CD_ORIGSPACE);
if(orco && (orcodata=dm->getVertDataArray(dm, CD_ORCO))) {
VECCOPY(v[0], orcodata[mface->v1]);
@@ -3309,7 +3309,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, fl
if(pa) {
i= (pa->num_dmcache==DMCACHE_NOTFOUND)? pa->num: pa->num_dmcache;
- if(i >= dm->getNumFaces(dm))
+ if(i >= dm->getNumTessFaces(dm))
i = -1;
}
else
@@ -3321,7 +3321,7 @@ static int get_particle_uv(DerivedMesh *dm, ParticleData *pa, int face_index, fl
texco[2]= 0.0f;
}
else {
- mf= dm->getFaceData(dm, i, CD_MFACE);
+ mf= dm->getTessFaceData(dm, i, CD_MFACE);
psys_interpolate_uvs(&tf[i], mf->v4, fuv, texco);
@@ -3962,7 +3962,7 @@ void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemMo
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);
}
@@ -3982,11 +3982,11 @@ void psys_get_dupli_texture(Object *ob, ParticleSettings *part, ParticleSystemMo
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;
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 56ca3e8e22b..9004f4b9973 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -410,7 +410,7 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
int amax= from==PART_FROM_FACE ? 3 : 1;
totface=dm->getNumFaces(dm);
- mface=dm->getFaceDataArray(dm,CD_MFACE);
+ mface=dm->getTessFaceDataArray(dm,CD_MFACE);
for(a=0; a<amax; a++){
if(a==0){ a0mul=res*res; a1mul=res; a2mul=1; }
@@ -419,7 +419,7 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
for(a1=0; a1<size[(a+1)%3]; a1++){
for(a2=0; a2<size[(a+2)%3]; a2++){
- mface=dm->getFaceDataArray(dm,CD_MFACE);
+ mface=dm->getTessFaceDataArray(dm,CD_MFACE);
pa=psys->particles + a1*a1mul + a2*a2mul;
VECCOPY(co1,pa->fuv);
@@ -633,7 +633,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C
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:
@@ -672,7 +672,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C
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;
@@ -734,7 +734,7 @@ void psys_thread_distribute_particle(ParticleThread *thread, ParticleData *pa, C
return;
}
- mf= dm->getFaceData(dm, ctx->index[p], CD_MFACE);
+ mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
//switch(distr){
// case PART_DISTR_JIT:
@@ -1165,7 +1165,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive
orcodata= dm->getVertDataArray(dm, CD_ORCO);
for(i=0; i<tot; i++){
- MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
+ MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
if(orcodata) {
VECCOPY(co1, orcodata[mf->v1]);
@@ -1234,7 +1234,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive
}
else { /* PART_FROM_FACE / PART_FROM_VOLUME */
for(i=0;i<tot; i++){
- MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
+ MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
if(mf->v4) {
@@ -1309,7 +1309,7 @@ int psys_threads_init_distribution(ParticleThread *threads, Scene *scene, Derive
}
else {
if(dm->numFaceData)
- COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
}
if(COMPARE_ORIG_INDEX) {
@@ -3031,7 +3031,7 @@ int psys_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, float *vert_cos
}
totface=dm->getNumFaces(dm);
- mface=dm->getFaceDataArray(dm,CD_MFACE);
+ mface=dm->getTessFaceDataArray(dm,CD_MFACE);
mvert=dm->getVertDataArray(dm,CD_MVERT);
/* lets intersect the faces */
@@ -3472,7 +3472,7 @@ static int boid_see_mesh(ListBase *lb, Scene *scene, Object *pob, ParticleSystem
psys_enable_all(ob);
}
- mface=dm->getFaceDataArray(dm,CD_MFACE);
+ mface=dm->getTessFaceDataArray(dm,CD_MFACE);
mface+=min_face;
mvert=dm->getVertDataArray(dm,CD_MVERT);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index 27357d92aae..577156ef453 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -50,6 +50,8 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_subsurf.h"
+#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BLI_arithb.h"
#include "BLI_kdtree.h"
@@ -98,14 +100,13 @@ typedef void ( *Shrinkwrap_ForeachVertexCallback) (DerivedMesh *target, float *c
DerivedMesh *object_get_derived_final(struct Scene *scene, Object *ob, CustomDataMask dataMask)
{
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
if (em)
{
DerivedMesh *final = NULL;
- editmesh_get_derived_cage_and_final(scene, ob, em, &final, dataMask);
-
- BKE_mesh_end_editmesh(me, em);
+ editbmesh_get_derived_cage_and_final(scene, ob, em, &final, dataMask);
+
return final;
}
else
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index bc6b487080c..3e6f30cde36 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -247,11 +247,11 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm)
/* first some paranoia checks */
if (!dm) return NULL;
- if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return NULL;
+ if (!dm->getNumVerts(dm) || !dm->getNumTessFaces(dm)) return NULL;
pccd_M = MEM_mallocN(sizeof(ccd_Mesh),"ccd_Mesh");
pccd_M->totvert = dm->getNumVerts(dm);
- pccd_M->totface = dm->getNumFaces(dm);
+ pccd_M->totface = dm->getNumTessFaces(dm);
pccd_M->savety = CCD_SAVETY;
pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
@@ -280,7 +280,7 @@ static ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm)
}
/* alloc and copy faces*/
- pccd_M->mface = dm->dupFaceArray(dm);
+ pccd_M->mface = dm->dupTessFaceArray(dm);
/* OBBs for idea1 */
pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax)*pccd_M->totface,"ccd_Mesh_Faces_mima");
@@ -343,10 +343,10 @@ static void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M, DerivedMesh *dm)
/* first some paranoia checks */
if (!dm) return ;
- if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return ;
+ if (!dm->getNumVerts(dm) || !dm->getNumTessFaces(dm)) return ;
if ((pccd_M->totvert != dm->getNumVerts(dm)) ||
- (pccd_M->totface != dm->getNumFaces(dm))) return;
+ (pccd_M->totface != dm->getNumTessFaces(dm))) return;
pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 6e95fe7ebc7..61f10239148 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -231,10 +231,11 @@ static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGV
}
static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MTFace *tface) {
- MFace *mface = dm->getFaceArray(dm);
+#if 0
+ MFace *mface = dm->getTessFaceArray(dm);
MVert *mvert = dm->getVertArray(dm);
int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
int i, j, seam;
UvMapVert *v;
UvVertMap *vmap;
@@ -324,6 +325,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
free_uv_vert_map(vmap);
ccgSubSurf_processSync(ss);
+#endif
return 1;
}
@@ -349,7 +351,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
}
/* get some info from CCGSubsurf */
- totface = ccgSubSurf_getNumFaces(uvss);
+ totface = ccgSubSurf_getNumTessFaces(uvss);
edgeSize = ccgSubSurf_getEdgeSize(uvss);
gridSize = ccgSubSurf_getGridSize(uvss);
gridFaces = gridSize - 1;
@@ -427,7 +429,7 @@ static unsigned int ss_getEdgeFlags(CCGSubSurf *ss, CCGEdge *e, int ssFromEditme
}
#endif
-/* face weighting */
+
static void calc_ss_weights(int gridFaces,
FaceVertWeight **qweight, FaceVertWeight **tweight)
{
@@ -471,6 +473,61 @@ static void calc_ss_weights(int gridFaces,
}
}
+/* face weighting */
+typedef struct FaceVertWeightEntry {
+ FaceVertWeight *weight;
+ int valid;
+} FaceVertWeightEntry;
+
+typedef struct WeightTable {
+ FaceVertWeightEntry *weight_table;
+ int len;
+} WeightTable;
+
+static FaceVertWeight *get_ss_weights(WeightTable *wtable, int gridFaces, int faceLen)
+{
+ int i;
+
+ /*ensure we have at least the triangle and quad weights*/
+ if (wtable->len < 4) {
+ wtable->weight_table = MEM_callocN(sizeof(FaceVertWeightEntry)*5, "weight table alloc");
+ wtable->len = 5;
+
+ calc_ss_weights(gridFaces, &wtable->weight_table[4].weight, &wtable->weight_table[3].weight);
+ wtable->weight_table[4].valid = wtable->weight_table[3].valid = 1;
+ }
+
+ if (wtable->len <= faceLen) {
+ void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry)*(faceLen+1), "weight table alloc 2");
+
+ 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) {
+ /*ok, need to calculate weights here*/
+ wtable->weight_table[faceLen].weight =
+ MEM_callocN(sizeof(FaceVertWeight)*gridFaces*gridFaces,
+ "vert face weight");
+ wtable->weight_table[faceLen].valid = 1;
+ }
+
+ return wtable->weight_table[faceLen].weight;
+}
+
+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].weight);
+ }
+}
+
static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
int drawInteriorEdges, int useSubsurfUv,
DerivedMesh *dm, MultiresSubsurf *ms)
@@ -481,6 +538,8 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
int gridFaces = gridSize - 1;
int edgeBase, faceBase;
int i, j, k, S, x, y, index;
+ int *vertIdx = NULL;
+ V_DECLARE(vertIdx);
CCGVertIterator *vi;
CCGEdgeIterator *ei;
CCGFaceIterator *fi;
@@ -490,11 +549,13 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
int totvert, totedge, totface;
MVert *mvert;
MEdge *med;
+ float *w = NULL;
+ WeightTable wtable;
+ V_DECLARE(w);
MFace *mf;
int *origIndex;
- FaceVertWeight *qweight, *tweight;
- calc_ss_weights(gridFaces, &qweight, &tweight);
+ memset(&wtable, 0, sizeof(wtable));
/* vert map */
totvert = ccgSubSurf_getNumVerts(ss);
@@ -516,7 +577,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
}
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap");
fi = ccgSubSurf_getFaceIterator(ss);
for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
@@ -529,17 +590,17 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
if(ms) {
result = MultiresDM_new(ms, dm, ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
- ccgSubSurf_getNumFinalFaces(ss));
+ ccgSubSurf_getNumFinalFaces(ss), 0, 0);
}
else {
if(dm) {
result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
- ccgSubSurf_getNumFinalFaces(ss));
+ ccgSubSurf_getNumFinalFaces(ss), 0, 0);
} else {
result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
- ccgSubSurf_getNumFinalFaces(ss));
+ ccgSubSurf_getNumFinalFaces(ss), 0, 0);
}
}
@@ -551,11 +612,13 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
for(index = 0; index < totface; index++) {
CCGFace *f = faceMap2[index];
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
- FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
- int vertIdx[4];
+ FaceVertWeight *weight = get_ss_weights(&wtable, gridFaces, numVerts);
+
+ V_RESET(vertIdx);
for(S = 0; S < numVerts; S++) {
CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+ V_GROW(vertIdx);
vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
}
@@ -567,17 +630,22 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
++origIndex;
i++;
+ V_RESET(w);
+ for (x=0; x<numVerts; x++) {
+ V_GROW(w);
+ }
+
for(S = 0; S < numVerts; S++) {
int prevS = (S - 1 + numVerts) % numVerts;
int nextS = (S + 1) % numVerts;
- int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ int otherS = (numVerts >= 4) ? (S + 2) % numVerts : 3;
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, result, vertIdx, w, numVerts, i);
VecCopyf(mvert->co,
ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
@@ -588,20 +656,25 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
i++;
}
}
+
+ V_RESET(w);
+ for (x=0; x<numVerts; x++) {
+ V_GROW(w);
+ }
for(S = 0; S < numVerts; S++) {
int prevS = (S - 1 + numVerts) % numVerts;
int nextS = (S + 1) % numVerts;
int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
-
+
for(y = 1; y < gridFaces; y++) {
for(x = 1; x < gridFaces; x++) {
- 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, result, vertIdx, w, numVerts, i);
+
VecCopyf(mvert->co,
ccgSubSurf_getFaceGridData(ss, f, S, x, y));
*origIndex = ORIGINDEX_NONE;
@@ -611,7 +684,6 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
}
}
}
-
*((int*)ccgSubSurf_getFaceUserData(ss, f)) = faceBase;
faceBase += 1 + numVerts * ((gridSize-2) + (gridSize-2) * (gridSize-2));
}
@@ -627,12 +699,14 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
v = ccgSubSurf_getEdgeVert1(e);
vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
-
+
for(x = 1; x < edgeSize - 1; x++) {
- float w[2];
- w[1] = (float) x / (edgeSize - 1);
- w[0] = 1 - w[1];
- DM_interp_vert_data(dm, result, vertIdx, w, 2, i);
+ float w2[2];
+
+ w2[1] = (float) x / (edgeSize - 1);
+ w2[0] = 1 - w2[1];
+ DM_interp_vert_data(dm, result, vertIdx, w2, 2, i);
+
VecCopyf(mvert->co, ccgSubSurf_getEdgeData(ss, e, x));
*origIndex = ORIGINDEX_NONE;
++mvert;
@@ -737,8 +811,8 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
// load faces
i = 0;
- mf = CDDM_get_faces(result);
- origIndex = result->getFaceData(result, 0, CD_ORIGINDEX);
+ mf = CDDM_get_tessfaces(result);
+ origIndex = result->getTessFaceData(result, 0, CD_ORIGINDEX);
for(index = 0; index < totface; index++) {
CCGFace *f = faceMap2[index];
@@ -750,7 +824,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
if(!ssFromEditmesh) {
MFace origMFace;
- dm->getFace(dm, faceIdx, &origMFace);
+ dm->getTessFace(dm, faceIdx, &origMFace);
mat_nr = origMFace.mat_nr;
flag = origMFace.flag;
@@ -761,8 +835,8 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
}
for(S = 0; S < numVerts; S++) {
- FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
-
+ FaceVertWeight *weight = get_ss_weights(&wtable, gridFaces, numVerts);
+
for(y = 0; y < gridFaces; y++) {
for(x = 0; x < gridFaces; x++) {
mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
@@ -775,7 +849,7 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
edgeSize, gridSize);
mf->mat_nr = mat_nr;
mf->flag = flag;
-
+#if 0 //BMESH_TODO
if(dm) {
int prevS = (S - 1 + numVerts) % numVerts;
int nextS = (S + 1) % numVerts;
@@ -789,10 +863,11 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
w[j][otherS] = (*weight)[j][3];
}
- DM_interp_face_data(dm, result, &faceIdx, NULL,
+ DM_interp_tessface_data(dm, result, &faceIdx, NULL,
&w, 1, i);
weight++;
}
+#endif
*origIndex = mapIndex;
++mf;
@@ -807,8 +882,9 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
MEM_freeN(edgeMap2);
MEM_freeN(vertMap2);
- MEM_freeN(tweight);
- MEM_freeN(qweight);
+ free_ss_weights(&wtable);
+
+ V_FREE(vertIdx);
if(useSubsurfUv) {
CustomData *fdata = &result->faceData;
@@ -821,7 +897,9 @@ static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
}
CDDM_calc_normals(result);
-
+ CDDM_tessfaces_to_faces(result);
+
+ V_FREE(w);
return result;
}
@@ -829,18 +907,22 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
float (*vertexCos)[3], int useFlatSubdiv)
{
float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
- CCGVertHDL fVerts[4];
+ CCGVertHDL *fVerts = NULL;
+ V_DECLARE(fVerts);
int totvert = dm->getNumVerts(dm);
int totedge = dm->getNumEdges(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
+ int totpoly = dm->getNumFaces(dm);
int i;
int *index;
MVert *mvert = dm->getVertArray(dm);
MEdge *medge = dm->getEdgeArray(dm);
- MFace *mface = dm->getFaceArray(dm);
+ MFace *mface = dm->getTessFaceArray(dm);
MVert *mv;
MEdge *me;
MFace *mf;
+ DMFaceIter *fiter;
+ DMLoopIter *liter;
ccgSubSurf_initFullSync(ss);
@@ -872,28 +954,31 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = *index;
}
-
- mf = mface;
- index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX);
- for (i = 0; i < totface; i++, mf++, index++) {
+
+ fiter = dm->newFaceIter(dm);
+ for (i=0; !fiter->done; fiter->step(fiter), i++) {
CCGFace *f;
+ V_RESET(fVerts);
- fVerts[0] = SET_INT_IN_POINTER(mf->v1);
- fVerts[1] = SET_INT_IN_POINTER(mf->v2);
- fVerts[2] = SET_INT_IN_POINTER(mf->v3);
- fVerts[3] = SET_INT_IN_POINTER(mf->v4);
+ index = (int*) fiter->getCDData(fiter, CD_ORIGINDEX, -1);
+ liter = fiter->getLoopsIter(fiter);
+
+ for (; !liter->done; liter->step(liter)) {
+ V_GROW(fVerts);
+ fVerts[V_COUNT(fVerts)-1] = SET_INT_IN_POINTER(liter->vindex);
+ }
- // this is very bad, means mesh is internally consistent.
- // it is not really possible to continue without modifying
- // other parts of code significantly to handle missing faces.
- // since this really shouldn't even be possible we just bail.
- if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fVerts[3] ? 4 : 3,
+ /* this is very bad, means mesh is internally inconsistent.
+ * it is not really possible to continue without modifying
+ * other parts of code significantly to handle missing faces.
+ * since this really shouldn't even be possible we just bail.*/
+ if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fiter->len,
fVerts, &f) == eCCGError_InvalidValue) {
static int hasGivenError = 0;
if(!hasGivenError) {
- //XXX error("Unrecoverable error in SubSurf calculation,"
- // " mesh is inconsistent.");
+ printf("Unrecoverable error in SubSurf calculation,"
+ " mesh is inconsistent.\n");
hasGivenError = 1;
}
@@ -975,7 +1060,7 @@ 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);
@@ -989,9 +1074,9 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
memset(mv, 0, sizeof(*mv));
- if((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
+ if((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumTessFaces(ss) > 0)) {
/* this vert comes from face data */
- int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ int lastface = ccgSubSurf_getNumTessFaces(ss) - 1;
CCGFace *f;
int x, y, grid, numVerts;
int offset;
@@ -1064,7 +1149,7 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
if(edgeNum < ccgdm->edgeMap[0].startEdge) {
/* this edge comes from face data */
- int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ int lastface = ccgSubSurf_getNumTessFaces(ss) - 1;
CCGFace *f;
int x, y, grid, numVerts;
int offset;
@@ -1146,8 +1231,8 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
int offset;
int grid;
int x, y;
- int lastface = ccgSubSurf_getNumFaces(ss) - 1;
- char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS);
+ int lastface = ccgSubSurf_getNumTessFaces(ss) - 1;
+ char *faceFlags = dm->getTessFaceDataArray(dm, CD_FLAGS);
memset(mf, 0, sizeof(*mf));
@@ -1183,7 +1268,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int i = 0;
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
for(index = 0; index < totface; index++) {
CCGFace *f = ccgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -1238,7 +1323,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
int i = 0;
int *edgeFlags = dm->getEdgeDataArray(dm, CD_FLAGS);
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
for(index = 0; index < totface; index++) {
CCGFace *f = ccgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -1308,6 +1393,138 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
}
}
+struct ccgDM_faceIter;
+
+typedef struct ccgDM_loopIter {
+ DMLoopIter head;
+ int curloop;
+ CCGDerivedMesh *ccgdm;
+ struct ccgDM_faceIter *fiter;
+} ccgDM_loopIter;
+
+typedef struct ccgDM_faceIter {
+ DMFaceIter head;
+ CCGDerivedMesh *ccgdm;
+ MFace mface;
+
+ ccgDM_loopIter liter;
+} ccgDM_faceIter;
+
+void ccgDM_faceIterStep(void *self)
+{
+ ccgDM_faceIter *fiter = self;
+
+ if (!fiter->ccgdm || !fiter->ccgdm->ss) {
+ fiter->head.done = 1;
+ return;
+ }
+
+ if (fiter->head.index >= ccgSubSurf_getNumTessFaces(fiter->ccgdm->ss)) {
+ fiter->head.done = 1;
+ return;
+ };
+
+ fiter->head.index++;
+
+ ccgDM_getFinalFace((DerivedMesh*)fiter->ccgdm, fiter->head.index, &fiter->mface);
+
+ fiter->head.flags = fiter->mface.flag;
+ fiter->head.mat_nr = fiter->mface.mat_nr;
+ fiter->head.len = fiter->mface.v4 ? 4 : 3;
+}
+
+void *ccgDM_faceIterCData(void *self, int type, int layer)
+{
+ ccgDM_faceIter *fiter = self;
+
+ if (layer == -1)
+ return CustomData_get(&fiter->ccgdm->dm.faceData, fiter->head.index, type);
+ else
+ return CustomData_get_n(&fiter->ccgdm->dm.faceData, type, fiter->head.index, layer);
+}
+
+void ccgDM_loopIterStep(void *self)
+{
+ ccgDM_loopIter *liter = self;
+ MFace *mf = &liter->fiter->mface;
+ int i, in;
+
+ if (liter->head.index >= liter->fiter->head.len) {
+ liter->head.done = 1;
+ return;
+ }
+
+ liter->head.index++;
+ i = liter->head.index;
+
+ switch (i) {
+ case 0:
+ in = liter->fiter->mface.v1;
+ break;
+ case 1:
+ in = liter->fiter->mface.v2;
+ break;
+ case 2:
+ in = liter->fiter->mface.v3;
+ break;
+ case 3:
+ in = liter->fiter->mface.v4;
+ break;
+ }
+
+ liter->head.vindex = in;
+
+ /*we don't set .eindex*/
+ ccgDM_getFinalVert((DerivedMesh*)liter->ccgdm, in, &liter->head.v);
+}
+
+void *ccgDM_loopIterGetVCData(void *self, int type, int layer)
+{
+ ccgDM_loopIter *liter = self;
+
+ if (layer == -1)
+ return CustomData_get(&liter->ccgdm->dm.vertData, liter->head.vindex, type);
+ else return CustomData_get_n(&liter->ccgdm->dm.vertData, type, liter->head.vindex, layer);
+}
+
+void *ccgDM_loopIterGetCData(void *self, int type, int layer)
+{
+ ccgDM_loopIter *liter = self;
+
+ /*BMESH_TODO
+ yeek, this has to convert mface-style uv/mcols to loop-style*/
+ return NULL;
+}
+
+DMLoopIter *ccgDM_faceIterGetLIter(void *self)
+{
+ ccgDM_faceIter *fiter = self;
+
+ fiter->liter.head.index = -1;
+ fiter->liter.head.done = 0;
+ fiter->liter.head.step(&fiter->liter);
+
+ return (DMLoopIter*) &fiter->liter;
+}
+
+DMFaceIter *ccgDM_newFaceIter(DerivedMesh *dm)
+{
+ ccgDM_faceIter *fiter = MEM_callocN(sizeof(ccgDM_faceIter), "ccgDM_faceIter");
+
+ fiter->head.free = MEM_freeN;
+ fiter->head.step = ccgDM_faceIterStep;
+ fiter->head.index = -1;
+ fiter->head.getCDData = ccgDM_faceIterCData;
+ fiter->head.getLoopsIter = ccgDM_faceIterGetLIter;
+
+ fiter->liter.fiter = fiter;
+ fiter->liter.head.getLoopCDData = ccgDM_loopIterGetCData;
+ fiter->liter.head.getVertCDData = ccgDM_loopIterGetVCData;
+ fiter->liter.head.step = ccgDM_loopIterStep;
+
+ fiter->head.step(fiter);
+}
+
static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
@@ -1317,9 +1534,9 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
int gridSize = ccgSubSurf_getGridSize(ss);
int edgeSize = ccgSubSurf_getEdgeSize(ss);
int i = 0;
- char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS);
+ char *faceFlags = dm->getTessFaceDataArray(dm, CD_FLAGS);
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
for(index = 0; index < totface; index++) {
CCGFace *f = ccgdm->faceMap[index].face;
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -1382,7 +1599,7 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
}
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap");
fi = ccgSubSurf_getFaceIterator(ss);
for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
@@ -1690,7 +1907,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
GPUVertexAttribs gattribs;
DMVertexAttribs attribs;
- MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
+ MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
int gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
int edgeSize = ccgSubSurf_getEdgeSize(ss);
@@ -1727,7 +1944,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
} \
}
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
for(a = 0, i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, drawSmooth;
@@ -1922,7 +2139,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
for(i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -2054,7 +2271,7 @@ static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void
static void ccgDM_drawUVEdges(DerivedMesh *dm)
{
- MFace *mf = dm->getFaceArray(dm);
+ MFace *mf = dm->getTessFaceArray(dm);
MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
int i;
@@ -2089,7 +2306,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u
CCGSubSurf *ss = ccgdm->ss;
CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
int i, gridSize = ccgSubSurf_getGridSize(ss);
- char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS);
+ char *faceFlags = dm->getTessFaceDataArray(dm, CD_FLAGS);
for (i=0; !ccgFaceIterator_isStopped(fi); i++,ccgFaceIterator_next(fi)) {
CCGFace *f = ccgFaceIterator_getCurrent(fi);
@@ -2274,6 +2491,8 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int edgeSize;
int gridSize;
int gridFaces;
+ int *vertIdx = NULL;
+ V_DECLARE(vertIdx);
int gridSideVerts;
/*int gridInternalVerts; - as yet unused */
int gridSideEdges;
@@ -2285,7 +2504,8 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
DM_from_template(&ccgdm->dm, dm, ccgSubSurf_getNumFinalVerts(ss),
ccgSubSurf_getNumFinalEdges(ss),
- ccgSubSurf_getNumFinalFaces(ss));
+ ccgSubSurf_getNumFinalFaces(ss),
+ 0, 0);
DM_add_face_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL);
DM_add_edge_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL);
@@ -2294,21 +2514,24 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.getMinMax = ccgDM_getMinMax;
ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
- ccgdm->dm.getNumFaces = ccgDM_getNumFaces;
+ ccgdm->dm.getNumTessFaces = ccgDM_getNumTessFaces;
+ ccgdm->dm.getNumFaces = ccgDM_getNumTessFaces;
+
+ ccgdm->dm.newFaceIter = ccgDM_newFaceIter;
ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
ccgdm->dm.getVert = ccgDM_getFinalVert;
ccgdm->dm.getEdge = ccgDM_getFinalEdge;
- ccgdm->dm.getFace = ccgDM_getFinalFace;
+ ccgdm->dm.getTessFace = ccgDM_getFinalFace;
ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
- ccgdm->dm.copyFaceArray = ccgDM_copyFinalFaceArray;
+ ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
ccgdm->dm.getVertData = DM_get_vert_data;
ccgdm->dm.getEdgeData = DM_get_edge_data;
- ccgdm->dm.getFaceData = DM_get_face_data;
+ ccgdm->dm.getTessFaceData = DM_get_face_data;
ccgdm->dm.getVertDataArray = DM_get_vert_data_layer;
ccgdm->dm.getEdgeDataArray = DM_get_edge_data_layer;
- ccgdm->dm.getFaceDataArray = DM_get_face_data_layer;
+ ccgdm->dm.getTessFaceDataArray = DM_get_face_data_layer;
ccgdm->dm.getVertCos = ccgdm_getVertCos;
ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
@@ -2355,7 +2578,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->edgeMap[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e;
}
- totface = ccgSubSurf_getNumFaces(ss);
+ totface = ccgSubSurf_getNumTessFaces(ss);
ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
fi = ccgSubSurf_getFaceIterator(ss);
for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
@@ -2381,7 +2604,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
/* mvert = dm->getVertArray(dm); - as yet unused */
medge = dm->getEdgeArray(dm);
- mface = dm->getFaceArray(dm);
+ mface = dm->getTessFaceArray(dm);
vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
/*edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);*/
@@ -2397,7 +2620,6 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
int S, x, y;
- int vertIdx[4];
ccgdm->faceMap[index].startVert = vertNum;
ccgdm->faceMap[index].startEdge = edgeNum;
@@ -2405,9 +2627,11 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
/* set the face base vert */
*((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum;
-
+
+ V_RESET(vertIdx);
for(S = 0; S < numVerts; S++) {
CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+ V_GROW(vertIdx);
vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
}
@@ -2418,18 +2642,22 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
++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;
+
for(x = 1; x < gridFaces; x++) {
float w[4];
+#if 0 //BMESH_TODO
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);
+#endif
*vertOrigIndex = ORIGINDEX_NONE;
++vertOrigIndex;
++vertNum;
@@ -2443,12 +2671,14 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
for(y = 1; y < gridFaces; y++) {
for(x = 1; x < gridFaces; x++) {
float w[4];
+#if 0 //BMESH_TODO
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);
+#endif
*vertOrigIndex = ORIGINDEX_NONE;
++vertOrigIndex;
++vertNum;
@@ -2472,6 +2702,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
FaceVertWeight w;
int j;
+#if 0 //BMESH_TODO
for(j = 0; j < 4; ++j) {
w[j][prevS] = (*weight)[j][0];
w[j][S] = (*weight)[j][1];
@@ -2479,9 +2710,10 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
w[j][otherS] = (*weight)[j][3];
}
- DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL,
+ DM_interp_tessface_data(dm, &ccgdm->dm, &origIndex, NULL,
&w, 1, faceNum);
weight++;
+#endif
*faceOrigIndex = mapIndex;
@@ -2572,6 +2804,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
MEM_freeN(qweight);
MEM_freeN(tweight);
+ V_FREE(vertIdx);
return ccgdm;
}
diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c
new file mode 100644
index 00000000000..d27f7a13f02
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_bitmap_node.c
@@ -0,0 +1,451 @@
+/**
+ * $Id: verse_bitmap_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+static void cb_b_dimension_set(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth);
+static void cb_b_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type);
+static void cb_b_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
+static void cb_b_tile_set(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile);
+
+static void change_layer_dimension(
+ VBitmapLayer *vblayer,
+ unsigned int old_width,
+ unsigned int old_height,
+ unsigned int t_old_width,
+ unsigned int t_old_height);
+static void *alloc_verse_bitmap_layer_data(struct VBitmapLayer *vblayer);
+
+/*
+ * resize/crop verse bitmap layer
+ */
+static void change_layer_dimension(
+ VBitmapLayer *vblayer,
+ unsigned int old_width,
+ unsigned int old_height,
+ unsigned int t_old_width,
+ unsigned int t_old_height)
+{
+ struct VNode *vnode = vblayer->vnode;
+ unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width;
+ unsigned int width = ((VBitmapData*)(vnode->data))->width;
+ unsigned int height = ((VBitmapData*)(vnode->data))->height;
+ unsigned int x, y, i, j;
+
+ i = j = 0;
+
+ /* "copy" old data to new data */
+ if(vblayer->type==VN_B_LAYER_UINT8) {
+ unsigned char *data = (unsigned char*)vblayer->data;
+ /* allocate new verse bitmap layer data */
+ unsigned char *new_data = (unsigned char*)alloc_verse_bitmap_layer_data(vblayer);
+ for(y=0; y<old_height && y<height; y++, i=y*t_width, j=y*t_old_width) {
+ for(x=0; x<old_width && y<width; x++, i++, j++) {
+ new_data[i] = data[j];
+ }
+ }
+ MEM_freeN(vblayer->data);
+ vblayer->data = new_data;
+ }
+}
+
+/*
+ * free data stored in verse bitmap layer
+ */
+void free_bitmap_layer_data(VBitmapLayer *vblayer)
+{
+ struct VerseSession *session = vblayer->vnode->session;
+
+ /* free name of bitmap layer */
+ MEM_freeN(vblayer->name);
+
+ /* unsubscribe from verse bitmap layer */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_b_layer_unsubscribe(vblayer->vnode->id, vblayer->id);
+
+ /* free image data of bitmap layer */
+ if(vblayer->data) MEM_freeN(vblayer->data);
+}
+
+/*
+ * allocate data of verse bitmap layer
+ */
+static void *alloc_verse_bitmap_layer_data(VBitmapLayer *vblayer)
+{
+ struct VNode *vnode = vblayer->vnode;
+ unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width;
+ unsigned int t_height = ((VBitmapData*)(vnode->data))->t_height;
+ unsigned int size;
+ void *data;
+
+ size = t_width*t_height;
+
+ /* allocation of own data stored in verse bitmap layer */
+ switch (vblayer->type) {
+ case VN_B_LAYER_UINT1:
+ data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint1");
+ break;
+ case VN_B_LAYER_UINT8:
+ data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint8");
+ break;
+ case VN_B_LAYER_UINT16:
+ data = (void*)MEM_mallocN(sizeof(unsigned int)*size, "VBLayer data uint16");
+ break;
+ case VN_B_LAYER_REAL32:
+ data = (void*)MEM_mallocN(sizeof(float)*size, "VBLayer data float16");
+ break;
+ case VN_B_LAYER_REAL64:
+ data = (void*)MEM_mallocN(sizeof(double)*size, "VBLayer data float32");
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+
+ return data;
+}
+
+/*
+ * create verse bitmap layer
+ */
+VBitmapLayer *create_bitmap_layer(
+ VNode *vnode,
+ VLayerID layer_id,
+ const char *name,
+ VNBLayerType type)
+{
+ struct VBitmapLayer *vblayer;
+ unsigned int width = ((VBitmapData*)(vnode->data))->width;
+ unsigned int height = ((VBitmapData*)(vnode->data))->height;
+
+ /* allocate memory for own verse bitmap layer */
+ vblayer = (VBitmapLayer*)MEM_mallocN(sizeof(VBitmapLayer), "Verse Bitmap Layer");
+
+ /* verse bitmap layer will include pointer at parent verse node and own id */
+ vblayer->vnode = vnode;
+ vblayer->id = layer_id;
+
+ /* name of verse layer */
+ vblayer->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "Verse Bitmap Layer name");
+ vblayer->name[0] = '\0';
+ strcpy(vblayer->name, name);
+
+ /* type of data stored in verse bitmap layer */
+ vblayer->type = type;
+
+ /* we can allocate memory for layer data, when we know dimmension of layers; when
+ * we don't know it, then we will allocate this data when we will receive dimmension */
+ if(width==0 || height==0)
+ vblayer->data = NULL;
+ else
+ vblayer->data = alloc_verse_bitmap_layer_data(vblayer);
+
+ vblayer->flag = 0;
+
+ return vblayer;
+}
+
+/*
+ * free data of bitmap node
+ */
+void free_bitmap_node_data(VNode *vnode)
+{
+ if(vnode->data) {
+ struct VBitmapLayer *vblayer = (VBitmapLayer*)((VBitmapData*)(vnode->data))->layers.lb.first;
+
+ /* free all VerseLayer data */
+ while(vblayer) {
+ free_bitmap_layer_data(vblayer);
+ vblayer = vblayer->next;
+ }
+
+ /* free all VerseLayers */
+ BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
+ }
+}
+
+/*
+ * create data of bitmap node
+ */
+VBitmapData *create_bitmap_data()
+{
+ struct VBitmapData *vbitmap;
+
+ vbitmap = (VBitmapData*)MEM_mallocN(sizeof(VBitmapData), "Verse Bitmap Data");
+
+ BLI_dlist_init(&(vbitmap->layers));
+ vbitmap->queue.first = vbitmap->queue.last = NULL;
+
+ vbitmap->width = 0;
+ vbitmap->height = 0;
+ vbitmap->depth = 0;
+
+ vbitmap->image = NULL;
+
+ vbitmap->post_bitmap_dimension_set = post_bitmap_dimension_set;
+ vbitmap->post_bitmap_layer_create = post_bitmap_layer_create;
+ vbitmap->post_bitmap_layer_destroy = post_bitmap_layer_destroy;
+ vbitmap->post_bitmap_tile_set = post_bitmap_tile_set;
+
+ return vbitmap;
+}
+
+/*
+ * callback function, dimension of image was changed, it is neccessary to
+ * crop all layers
+ */
+static void cb_b_dimension_set(
+ void *user_data,
+ VNodeID node_id,
+ uint16 width,
+ uint16 height,
+ uint16 depth)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+ unsigned int old_width, old_height, t_old_width, t_old_height;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_dimension_set()\n");
+#endif
+
+ /* backup old width and height */
+ old_width = ((VBitmapData*)(vnode->data))->width;
+ old_height = ((VBitmapData*)(vnode->data))->height;
+ t_old_width = ((VBitmapData*)(vnode->data))->t_width;
+ t_old_height = ((VBitmapData*)(vnode->data))->t_height;
+
+ /* set up new dimension of layers */
+ ((VBitmapData*)(vnode->data))->width = width;
+ ((VBitmapData*)(vnode->data))->height = height;
+ ((VBitmapData*)(vnode->data))->depth = depth;
+
+ /* we cache t_width because tiles aren't one pixel width */
+ if((width % VN_B_TILE_SIZE)!=0)
+ ((VBitmapData*)(vnode->data))->t_width = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE;
+ else
+ ((VBitmapData*)(vnode->data))->t_width = width;
+
+ /* we cache t_height because tiles aren't one pixel height */
+ if((height % VN_B_TILE_SIZE)!=0)
+ ((VBitmapData*)(vnode->data))->t_height = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE;
+ else
+ ((VBitmapData*)(vnode->data))->t_height = height;
+
+ /* crop resize all layers */
+ vblayer = ((VBitmapData*)vnode->data)->layers.lb.first;
+
+ while(vblayer) {
+ /* when this callback function received after cb_b_layer_create,
+ * then we have to allocate memory for verse bitmap layer data */
+ if(!vblayer->data) vblayer->data = alloc_verse_bitmap_layer_data(vblayer);
+ /* crop/resize all verse bitmap layers */
+ else change_layer_dimension(vblayer, old_width, old_height, t_old_width, t_old_height);
+
+ vblayer = vblayer->next;
+ }
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_dimension_set(vnode);
+}
+
+/*
+ * callback function, new layer channel of image was created
+ */
+static void cb_b_layer_create(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ const char *name,
+ VNBLayerType type)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_layer_create()\n");
+#endif
+
+ /* when no layer exists, then new layer will be created */
+ vblayer = create_bitmap_layer(vnode, layer_id, name, type);
+
+ /* add verse bitmap layer to list of layers */
+ BLI_dlist_add_item_index(&((VBitmapData*)vnode->data)->layers, vblayer, layer_id);
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_layer_create(vblayer);
+
+}
+
+/*
+ * callback function, existing layer of image was destroyed
+ */
+static void cb_b_layer_destroy(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+
+ if(!session) return;
+
+ /* find node of this layer*/
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id);
+ if(!vblayer) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_layer_destroy()\n");
+#endif
+
+ /* remove verse bitmap layer from list of layers */
+ BLI_dlist_rem_item(&(((VBitmapData*)vnode->data)->layers), layer_id);
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_layer_destroy(vblayer);
+
+ /* free data of verse bitmap layer */
+ free_bitmap_layer_data(vblayer);
+
+ /* free verse bitmap layer */
+ MEM_freeN(vblayer);
+}
+
+/*
+ * callback function, small part (8x8 pixels) was changed
+ */
+static void cb_b_tile_set(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint16 tile_x,
+ uint16 tile_y,
+ uint16 z,
+ VNBLayerType type,
+ const VNBTile *tile)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+ unsigned int x, y, xs, ys, width, height, t_height, t_width, i, j;
+
+ if(!session) return;
+
+ /* try to find verse node in dynamic list nodes */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find verse bitmap layer in list of layers */
+ vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id);
+ if(!vblayer) return;
+
+ /* we have to have allocated memory for bitmap layer */
+ if(!vblayer->data) return;
+
+ width = ((VBitmapData*)vnode->data)->width;
+ height = ((VBitmapData*)vnode->data)->height;
+
+ /* width of verse image including all tiles */
+ t_height = ((VBitmapData*)vnode->data)->t_height;
+ /* height of verse image including all tiles */
+ t_width = ((VBitmapData*)vnode->data)->t_width;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_tile_set()\n");
+#endif
+
+ xs = tile_x*VN_B_TILE_SIZE;
+ ys = tile_y*VN_B_TILE_SIZE;
+
+ /* initial position in one dimension vblayer->data (y_start*width + x_start) */
+ i = ys*t_width + xs;
+ /* intial position in one dimension tile array */
+ j = 0;
+
+ if(type==VN_B_LAYER_UINT8) {
+ unsigned char *data = (unsigned char*)vblayer->data;
+ for(y=ys; y<ys+VN_B_TILE_SIZE && y<height; y++, i=y*t_width+xs)
+ for(x=xs; x<xs+VN_B_TILE_SIZE && x<width; x++, i++, j++)
+ data[i] = (unsigned char)tile->vuint8[j];
+ }
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_tile_set(vblayer, xs, ys);
+}
+
+/*
+ * set up all callbacks functions for image nodes
+ */
+void set_bitmap_callbacks(void)
+{
+ /* dimension (size) of bitmap was set up or changes (image will be croped) */
+ verse_callback_set(verse_send_b_dimensions_set, cb_b_dimension_set, NULL);
+
+ /* new layer (chanell) of image was added or created */
+ verse_callback_set(verse_send_b_layer_create, cb_b_layer_create, NULL);
+
+ /* existing layer was destroyed */
+ verse_callback_set(verse_send_b_layer_destroy, cb_b_layer_destroy, NULL);
+
+ /* some tile (small part 8x8 pixels of image was changed) */
+ verse_callback_set(verse_send_b_tile_set, cb_b_tile_set, NULL);
+}
+
+#endif
+
diff --git a/source/blender/blenkernel/intern/verse_geometry_node.c b/source/blender/blenkernel/intern/verse_geometry_node.c
new file mode 100644
index 00000000000..a53ad2cb627
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_geometry_node.c
@@ -0,0 +1,2101 @@
+/**
+ * $Id: verse_geometry_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_verse.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+
+/* test functions for callback functions */
+static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+/* callback functions */
+static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
+static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
+static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z);
+static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id);
+static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id);
+static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
+static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
+
+/* other static functions */
+
+static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface);
+static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert);
+static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface);
+static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer);
+
+static void send_verse_face(struct VerseFace *vface);
+
+static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z);
+static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface);
+static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert);
+static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert);
+static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface);
+static void increase_verse_verts_references(struct VerseFace *vface);
+static void recalculate_verseface_normals(struct VNode *vnode);
+
+/* verse edge functions */
+static VerseEdge* find_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void insert_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
+static void remove_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
+static void remove_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void add_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void update_edgehash_of_deleted_verseface(struct VNode *vnode, struct VerseFace *vface);
+static void update_edgehash_of_changed_verseface(struct VNode *vnode, struct VerseFace *vface, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+static void update_edgehash_of_new_verseface(struct VNode *vnode, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+/*
+ * recalcute normals of all VerseFaces
+ */
+static void recalculate_verseface_normals(VNode *vnode)
+{
+ struct VLayer *vert_layer, *face_layer;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ vvert = vert_layer->dl.lb.first;
+ while(vvert) {
+ vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
+ vvert = vvert->next;
+ }
+
+ vface = face_layer->dl.lb.first;
+ while(vface) {
+ /* calculate face normals */
+ if(vface->vvert3) {
+ CalcNormFloat4(vface->vvert0->co, vface->vvert1->co,
+ vface->vvert2->co, vface->vvert3->co, vface->no);
+ VecAddf(vface->vvert3->no, vface->vvert3->no, vface->no);
+ }
+ else
+ CalcNormFloat(vface->vvert0->co, vface->vvert1->co,
+ vface->vvert2->co, vface->no);
+
+ /* calculate vertex normals ... it is averadge of all face normals using the vertex */
+ VecAddf(vface->vvert0->no, vface->vvert0->no, vface->no);
+ VecAddf(vface->vvert1->no, vface->vvert1->no, vface->no);
+ VecAddf(vface->vvert2->no, vface->vvert2->no, vface->no);
+
+ vface = vface->next;
+ }
+
+ /* we have to normalize all vertex normals */
+ vvert = vert_layer->dl.lb.first;
+ while(vvert) {
+ Normalize(vvert->no);
+ vvert = vvert->next;
+ }
+}
+
+/*
+ * add created item to the queue and send it if possible
+ */
+void add_item_to_send_queue(ListBase *lb, void *item, short type)
+{
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct VerseVert *vvert;
+ struct VerseFace *vface;
+
+ /* this prevent from adding duplicated faces */
+ if(type==VERSE_FACE) {
+ struct Link *link = (Link*)lb->first;
+ while(link) {
+ if(link==item) {
+ if(((VerseFace*)item)->flag & FACE_SENT) {
+/* printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/
+ ((VerseFace*)item)->flag |= FACE_OBSOLETE;
+ }
+ return;
+ }
+ link = link->next;
+ }
+ }
+
+ /* add item to sending queue (two way dynamic list) */
+ BLI_addtail(lb, item);
+
+ /* send item, when it is possible */
+ switch (type) {
+ case VERSE_NODE: /* only first node in queue can be sent */
+ if(lb->first==lb->last)
+ send_verse_node((VNode*)item);
+ break;
+ case VERSE_LINK: /* both object between have to exist */
+ if(((VLink*)item)->flag & LINK_SEND_READY)
+ send_verse_link((VLink*)item);
+ break;
+ case VERSE_LAYER:
+ if(((VLayer*)item)->vnode->flag & NODE_RECEIVED)
+ send_verse_layer((VLayer*)item);
+ break;
+ case VERSE_VERT:
+ if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED)
+ send_verse_vertex((VerseVert*)item);
+ break;
+ case VERSE_FACE: /* all vertexes of face have to be received */
+ if(((VerseFace*)item)->flag & FACE_SEND_READY)
+ send_verse_face((VerseFace*)item);
+ break;
+ case VERSE_TAG:
+ send_verse_tag((VTag*)item);
+ break;
+ case VERSE_TAG_GROUP:
+ send_verse_taggroup((VTagGroup*)item);
+ break;
+ case VERSE_VERT_UINT32: /* parent item has to exist */
+ vnode = (((uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
+ if(vvert != NULL)
+ send_verse_vert_uint32((uint32_item*)item, type);
+ break;
+ case VERSE_VERT_REAL32: /* parent item has to exist */
+ vnode = (((real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
+ if( vvert != NULL)
+ send_verse_vert_real32((real32_item*)item, type);
+ break;
+ case VERSE_VERT_VEC_REAL32: /* parent item has to exist */
+ vnode = (((vec_real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((vec_real32_item*)item)->id );
+ if(vvert != NULL)
+ send_verse_vert_vec_real32((vec_real32_item*)item, type);
+ break;
+ case VERSE_FACE_UINT8: /* parent item has to exist */
+ vnode = (((uint8_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint8_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_uint8((uint8_item*)item, type);
+ break;
+ case VERSE_FACE_UINT32: /* parent item has to exist */
+ vnode = (((uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_uint32((uint32_item*)item, type);
+ break;
+ case VERSE_FACE_REAL32: /* parent item has to exist */
+ vnode = (((real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_real32((real32_item*)item, type);
+ break;
+ case VERSE_FACE_QUAT_UINT32: /* parent item has to exist */
+ vnode = (((quat_uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_uint32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type);
+ break;
+ case VERSE_FACE_QUAT_REAL32: /* parent item has to exist */
+ vnode = (((quat_real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_real32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_corner_quat_real32((quat_real32_item*)item, type);
+ break;
+ }
+}
+
+/*
+ * return VerseLayer with certain content (vertexes, polygons, in the
+ * future: weight, red color, etc.)
+ */
+VLayer* find_verse_layer_type(VGeomData *geom, short content)
+{
+ struct VLayer *vlayer = NULL;
+
+ switch(content) {
+ case VERTEX_LAYER:
+ /* VERTEX_LAYER equals 0 and vertex layer is
+ * always in 1st layer */
+ vlayer = geom->layers.da.items[VERTEX_LAYER];
+ break;
+ case POLYGON_LAYER:
+ /* POLYGON_LAYER equals 1 and vertex layer is
+ * always in 2nd layer */
+ vlayer = geom->layers.da.items[POLYGON_LAYER];
+ break;
+ }
+
+ return vlayer;
+}
+
+/*
+ * increase references of VerseVerts of new VerseFace
+ */
+static void increase_verse_verts_references(VerseFace *vface)
+{
+ if(vface->vvert0) vface->vvert0->counter++;
+ if(vface->vvert1) vface->vvert1->counter++;
+ if(vface->vvert2) vface->vvert2->counter++;
+ if(vface->vvert3) vface->vvert3->counter++;
+}
+
+/*
+ * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed
+ * then this VerseFace is only removed from list of orphans)
+ */
+static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface)
+{
+ /* remove vface from list of orphans */
+ BLI_remlink(&(vlayer->orphans), vface);
+ /* increase references of all vertexes beying part of this face*/
+ increase_verse_verts_references(vface);
+
+ if(vface->flag & FACE_RECEIVED) {
+ /* set up vface flag */
+ vface->flag &= ~FACE_RECEIVED;
+ /* move vface to dynamic list of faces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
+ /* recalculate all vertex and faces normals */
+ recalculate_verseface_normals(vnode);
+ /* post create action (change local data) */
+ ((VGeomData*)vnode->data)->post_polygon_create(vface);
+ }
+ else if(vface->flag & FACE_CHANGED) {
+ /* set up vface flag */
+ vface->flag &= ~FACE_CHANGED;
+ /* move vface to dynamic list of faces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
+ /* recalculate all vertex and faces normals */
+ recalculate_verseface_normals(vnode);
+ /* post create action (change local data) */
+ ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
+ }
+}
+
+/*
+ * find all VerseFaces waiting in queue, which needs id of new VerseVert
+ */
+static void find_unsent_faces(VNode *vnode, VerseVert *vvert)
+{
+ VLayer *vlayer;
+ VerseFace *vface, *next_vface;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(vlayer) {
+ vface = vlayer->queue.first;
+ while(vface) {
+ next_vface = vface->next;
+ if(vface->vvert0==vvert) {
+ vface->v0 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert1==vvert) {
+ vface->v1 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert2==vvert) {
+ vface->v2 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert3==vvert){
+ vface->v3 = vvert->id;
+ vface->counter--;
+ }
+
+ if(vface->counter<1 && !(vface->flag & FACE_SENT))
+ send_verse_face(vface);
+
+ vface = next_vface;
+ }
+ }
+}
+
+/*
+ * find all VerseFace orphans, which needs incoming VerseVert
+ */
+static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert)
+{
+ VLayer *vlayer;
+ VerseFace *vface, *next_vface;
+ unsigned int vertex_id = vvert->id;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(vlayer) {
+ vface = vlayer->orphans.first;
+ while(vface){
+ next_vface = vface->next;
+ if(vface->v0 == vertex_id) {
+ vface->vvert0 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v1 == vertex_id) {
+ vface->vvert1 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v2 == vertex_id) {
+ vface->vvert2 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v3 == vertex_id) {
+ vface->vvert3 = vvert;
+ vface->counter--;
+ }
+ if(vface->counter<1) {
+ /* moving VerseFace orphan to dlist */
+ move_face_orphan_to_dlist(vnode, vlayer, vface);
+ }
+ vface = next_vface;
+ }
+ }
+}
+
+/*
+ * return number of VerseVerts missing to incoming VerseFace, set up pointers
+ * at VerseVerts
+ */
+static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface)
+{
+ struct VLayer *vert_layer;
+ struct VerseVert *vvert;
+ int counter=0;
+
+ vert_layer = find_verse_layer_type(geom, VERTEX_LAYER);
+
+ if(vface->v0 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0);
+ if(vvert==NULL) counter++;
+ else vface->vvert0 = vvert;
+ }
+ if(vface->v1 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1);
+ if(vvert==NULL) counter++;
+ else vface->vvert1 = vvert;
+ }
+ if(vface->v2 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2);
+ if(vvert==NULL) counter++;
+ else vface->vvert2 = vvert;
+ }
+ if(vface->v3 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3);
+ if(vvert==NULL) counter++;
+ else vface->vvert3 = vvert;
+ }
+
+ return counter;
+}
+
+/*
+ * try to find changed VerseFace in sending queue
+ */
+static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id)
+{
+ struct VerseFace *vface = vlayer->queue.first;
+
+ while(vface){
+ if(vface->id == polygon_id && vface->flag & FACE_CHANGED) {
+ return vface;
+ }
+ vface = vface->next;
+ }
+ return NULL;
+}
+
+/*
+ * try to find VerseFace in queue
+ */
+static VerseFace* find_verse_face_in_queue(
+ VLayer *vlayer,
+ VNodeID node_id,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseFace *vface = vlayer->queue.first;
+
+ while(vface){
+ if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){
+ vface->id = polygon_id;
+ vface->vlayer = vlayer;
+ return vface;
+ }
+ vface = vface->next;
+ }
+ return NULL;
+}
+
+/*
+ * try to find VerseVert in queue
+ */
+static VerseVert* find_verse_vert_in_queue(
+ VLayer *vlayer,
+ VNodeID node_id,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseVert *vvert = vlayer->queue.first;
+
+ while(vvert){
+ if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z))
+ {
+ vvert->id = vertex_id;
+ vvert->vlayer = vlayer;
+
+ return vvert;
+ }
+ vvert = vvert->next;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * send quat of float values to verse server (4x32 bits)
+ */
+void send_verse_face_corner_quat_real32(quat_real32_item *item, short type)
+{
+ verse_send_g_polygon_set_corner_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2],
+ item->value[3]);
+}
+
+/*
+ * send quat of unsigned int values to verse server (4x32 bits)
+ */
+void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type)
+{
+ verse_send_g_polygon_set_corner_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2],
+ item->value[3]);
+}
+
+/*
+ * send float value (32 bits) to verse server
+ */
+void send_verse_face_real32(real32_item *item, short type)
+{
+ verse_send_g_polygon_set_face_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned integer (32 bits) to verse server
+ */
+void send_verse_face_uint32(uint32_item *item, short type)
+{
+ verse_send_g_polygon_set_face_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned char (8 bits) to verse server
+ */
+void send_verse_face_uint8(uint8_item *item, short type)
+{
+ verse_send_g_polygon_set_face_uint8(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send vector of float values to verse server (3x32 bits)
+ */
+void send_verse_vert_vec_real32(vec_real32_item *item, short type)
+{
+ verse_send_g_vertex_set_xyz_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2]);
+}
+
+/*
+ * send float value (32 bits) to verse server
+ */
+void send_verse_vert_real32(real32_item *item, short type)
+{
+ verse_send_g_vertex_set_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned integer (32 bits) to verse server
+ */
+void send_verse_vert_uint32(uint32_item *item, short type)
+{
+ verse_send_g_vertex_set_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send delete command to verse server
+ */
+void send_verse_vertex_delete(VerseVert *vvert)
+{
+ verse_session_set(vvert->vlayer->vnode->session->vsession);
+
+ vvert->flag |= VERT_OBSOLETE;
+
+ verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id);
+}
+
+/*
+ * send VerseLayer to verse server
+ */
+void send_verse_layer(VLayer *vlayer)
+{
+ verse_session_set(vlayer->vnode->session->vsession);
+
+ verse_send_g_layer_create(
+ vlayer->vnode->id,
+ vlayer->id,
+ vlayer->name,
+ vlayer->type,
+ vlayer->def_int,
+ vlayer->def_real);
+}
+
+/*
+ * send VerseVert to verse server
+ */
+void send_verse_vertex(VerseVert *vvert)
+{
+ /* new vertex position will not be sent, when vertex was deleted */
+ if(vvert->flag & VERT_OBSOLETE) return;
+
+ verse_session_set(vvert->vlayer->vnode->session->vsession);
+
+ verse_send_g_vertex_set_xyz_real32(
+ vvert->vlayer->vnode->id,
+ vvert->vlayer->id,
+ vvert->id,
+ vvert->co[0],
+ vvert->co[2],
+ -vvert->co[1]);
+}
+
+/*
+ * send delete command to verse server
+ */
+void send_verse_face_delete(VerseFace *vface)
+{
+ verse_session_set(vface->vlayer->vnode->session->vsession);
+
+ vface->flag |= FACE_DELETED;
+
+ verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id);
+}
+
+/*
+ * send VerseFace to verse server
+ */
+static void send_verse_face(VerseFace *vface)
+{
+ verse_session_set(vface->vlayer->vnode->session->vsession);
+
+ vface->flag |= FACE_SENT;
+
+ if(vface->v3 != -1) {
+ verse_send_g_polygon_set_corner_uint32(
+ vface->vlayer->vnode->id,
+ vface->vlayer->id,
+ vface->id,
+ vface->v0,
+ vface->v3, /* verse use clock-wise winding */
+ vface->v2,
+ vface->v1); /* verse use clock-wise winding */
+ }
+ else {
+ verse_send_g_polygon_set_corner_uint32(
+ vface->vlayer->vnode->id,
+ vface->vlayer->id,
+ vface->id,
+ vface->v0,
+ vface->v2, /* verse use clock-wise winding */
+ vface->v1, /* verse use clock-wise winding */
+ vface->v3);
+ }
+}
+
+/*
+ * free VerseVert
+ */
+static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert)
+{
+ /* free VerseVert */
+ BLI_freelinkN(&(vlayer->orphans), vvert);
+}
+
+/*
+ * free VerseFace (and blender face)
+ */
+static void free_verse_face(VLayer *vlayer, VerseFace *vface)
+{
+ /* free VerseFace */
+ BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id);
+}
+
+/*
+ * free VerseLayer data
+ */
+static void free_verse_layer_data(VNode *vnode, VLayer *vlayer)
+{
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ /* set up EditVert->vvert and EditFace->vface pointers to NULL */
+ switch(vlayer->content) {
+ case VERTEX_LAYER:
+ vvert = (VerseVert*)vlayer->dl.lb.first;
+ while(vvert) {
+ ((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert);
+ vvert = vvert->next;
+ }
+ break;
+ case POLYGON_LAYER:
+ vface = (VerseFace*)vlayer->dl.lb.first;
+ while(vface) {
+ ((VGeomData*)vnode->data)->post_polygon_free_constraint(vface);
+ vface = vface->next;
+ }
+ break;
+ default:
+ break;
+ }
+ /* free Verse Layer name */
+ MEM_freeN(vlayer->name);
+ /* destroy VerseLayer data (vertexes, polygons, etc.) */
+ BLI_dlist_destroy(&(vlayer->dl));
+ /* free unsent data */
+ BLI_freelistN(&(vlayer->queue));
+ /* free orphans */
+ BLI_freelistN(&(vlayer->orphans));
+}
+
+/*
+ * free all unneeded VerseVerts waiting for deleting
+ */
+static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface)
+{
+ struct VLayer *vert_vlayer;
+
+ /* find layer containing vertexes */
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+
+ /* free all "deleted" VerseVert waiting for deleting this VerseFace */
+
+ if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
+ free_verse_vertex(vert_vlayer, vface->vvert0);
+ vface->vvert0 = NULL;
+ }
+ if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
+ free_verse_vertex(vert_vlayer, vface->vvert1);
+ vface->vvert1 = NULL;
+ }
+ if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
+ free_verse_vertex(vert_vlayer, vface->vvert2);
+ vface->vvert2 = NULL;
+ }
+ if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
+ free_verse_vertex(vert_vlayer, vface->vvert3);
+ vface->vvert3 = NULL;
+ }
+}
+
+/*
+ * This function create VerseVert and returns pointer on this vertex
+ */
+VerseVert* create_verse_vertex(
+ VLayer *vlayer,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseVert *vvert;
+
+ vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert");
+
+ /* set up pointer on parent node */
+ vvert->vlayer = vlayer;
+ vvert->id = vertex_id;
+ /* position */
+ vvert->co[0] = x;
+ vvert->co[1] = y;
+ vvert->co[2] = z;
+ /* normal */
+ vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
+ /* blender internals */
+ vvert->flag = 0;
+ vvert->counter = 0;
+ vvert->vertex = NULL;
+
+ /* increase layer counter of vertexes */
+ vlayer->counter++;
+
+ return vvert;
+}
+
+/*
+ * this function creates fake VerseEdge and returns pointer at this edge
+ */
+VerseEdge *create_verse_edge(uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = (VerseEdge*)MEM_mallocN(sizeof(VerseEdge), "VerseEdge");
+
+ vedge->v0 = v0;
+ vedge->v1 = v1;
+ vedge->counter = 0;
+
+ return vedge;
+}
+
+/*
+ * this function will create new VerseFace and will return pointer on such Face
+ */
+VerseFace* create_verse_face(
+ VLayer *vlayer,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseFace *vface;
+
+ vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace");
+
+ /* verse data */
+ vface->vlayer = vlayer;
+ vface->id = polygon_id;
+
+ vface->vvert0 = NULL;
+ vface->vvert1 = NULL;
+ vface->vvert2 = NULL;
+ vface->vvert3 = NULL;
+
+ vface->v0 = v0;
+ vface->v1 = v1;
+ vface->v2 = v2;
+ vface->v3 = v3;
+
+ /* blender data */
+ vface->face = NULL;
+ vface->flag = 0;
+ vface->counter = 4;
+
+ /* increase layer counter of faces */
+ vlayer->counter++;
+
+ return vface;
+}
+
+/*
+ * create and return VerseLayer
+ */
+VLayer *create_verse_layer(
+ VNode *vnode,
+ VLayerID layer_id,
+ const char *name,
+ VNGLayerType type,
+ uint32 def_integer,
+ real64 def_real)
+{
+ struct VLayer *vlayer;
+
+ /* add layer to the DynamicList */
+ vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer");
+
+ /* store all relevant info to the vlayer and set up vlayer */
+ vlayer->vnode = vnode;
+ vlayer->id = layer_id;
+ vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name");
+ strcpy(vlayer->name, name);
+ vlayer->type = type;
+ vlayer->def_int = def_integer;
+ vlayer->def_real = def_real;
+
+ if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0))
+ vlayer->content = VERTEX_LAYER;
+ else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1))
+ vlayer->content = POLYGON_LAYER;
+ else
+ vlayer->content = -1;
+
+ /* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/
+ BLI_dlist_init(&(vlayer->dl));
+ /* initialization of queue of layer */
+ vlayer->queue.first = vlayer->queue.last = NULL;
+ /* initialization of list of orphans */
+ vlayer->orphans.first = vlayer->orphans.last = NULL;
+ /* initialize number of sent items (vertexes, faces, etc) */
+ vlayer->counter = 0;
+ /* initialize flag */
+ vlayer->flag = 0;
+
+ /* set up methods */
+ vlayer->post_layer_create = post_layer_create;
+ vlayer->post_layer_destroy = post_layer_destroy;
+
+ return vlayer;
+}
+
+/*
+ * create geometry data
+ */
+VGeomData *create_geometry_data(void)
+{
+ struct VGeomData *geom;
+
+ geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData");
+ BLI_dlist_init(&(geom->layers));
+ geom->vlink = NULL;
+ geom->queue.first = geom->queue.last = NULL;
+ geom->mesh = NULL;
+ geom->editmesh = NULL;
+
+ /* initialize list of fake verse edges and initialize verse edge hash */
+ geom->edges.first = geom->edges.last = NULL;
+ geom->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ /* set up methods */
+ geom->post_vertex_create = post_vertex_create;
+ geom->post_vertex_set_xyz = post_vertex_set_xyz;
+ geom->post_vertex_delete = post_vertex_delete;
+ geom->post_vertex_free_constraint = post_vertex_free_constraint;
+ geom->post_polygon_create = post_polygon_create;
+ geom->post_polygon_set_corner = post_polygon_set_corner;
+ geom->post_polygon_delete = post_polygon_delete;
+ geom->post_polygon_free_constraint = post_polygon_free_constraint;
+ geom->post_geometry_free_constraint = post_geometry_free_constraint;
+ geom->post_polygon_set_uint8 = post_polygon_set_uint8;
+
+ return geom;
+}
+
+/* Create item containing 4 floats */
+static quat_real32_item *create_quat_real32_item(
+ VLayer *vlayer,
+ uint32 item_id,
+ real32 v0,
+ real32 v1,
+ real32 v2,
+ real32 v3)
+{
+ struct quat_real32_item *item;
+
+ item = (quat_real32_item*)MEM_mallocN(sizeof(quat_real32_item), "quat_real32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value[0] = v0;
+ item->value[1] = v1;
+ item->value[2] = v2;
+ item->value[3] = v3;
+
+ return item;
+}
+
+/* Create item containing 1 float */
+static real32_item *create_real32_item(VLayer *vlayer, uint32 item_id, real32 value)
+{
+ struct real32_item *item;
+
+ item = (real32_item*)MEM_mallocN(sizeof(real32_item), "real32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/* Create item containing 1 integer */
+static uint32_item *create_uint32_item(VLayer *vlayer, uint32 item_id, uint32 value)
+{
+ struct uint32_item *item;
+
+ item = (uint32_item*)MEM_mallocN(sizeof(uint32_item), "uint32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/* Create item containing 1 byte */
+static uint8_item *create_uint8_item(VLayer *vlayer, uint32 item_id, uint8 value)
+{
+ struct uint8_item *item;
+
+ item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/*
+ * callback function: vertex crease was set
+ */
+static void cb_g_crease_set_vertex(
+ void *user_data,
+ VNodeID node_id,
+ const char *layer,
+ uint32 def_crease)
+{
+}
+
+/*
+ * we have to test corretness of incoming data from verse server
+ * no two vertexes can have the same index
+ */
+static char test_polygon_set_corner_uint32(
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3))
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * try to find verse layer in sending queue of verse geometry node
+ */
+static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id)
+{
+ struct VLayer *vlayer;
+
+ /* try to find verse layyer in sending queue */
+ vlayer = ((VGeomData*)vnode->data)->queue.first;
+ while(vlayer) {
+ if(vlayer->id==layer_id) return vlayer;
+ vlayer = vlayer->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * this function will find edge in hash table, hash function isn't too optimal (it needs
+ * lot of memory for every verse node), but it works without any bug
+ */
+static VerseEdge* find_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct HashVerseEdge *hve;
+
+ if(((VGeomData*)vnode->data)->hash==NULL)
+ ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ hve = ((VGeomData*)vnode->data)->hash + VEDHASH(v0, v1);;
+ while(hve) {
+ /* edge v0---v1 is the same edge as v1---v0 */
+ if(hve->vedge && ((hve->vedge->v0==v0 && hve->vedge->v1==v1) || (hve->vedge->v0==v1 && hve->vedge->v1==v0))) return hve->vedge;
+ hve = hve->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * insert hash of verse edge to hash table
+ */
+static void insert_verse_edgehash(VNode *vnode, VerseEdge *vedge)
+{
+ struct HashVerseEdge *first, *hve;
+
+ if(((VGeomData*)vnode->data)->hash==NULL)
+ ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
+
+ if(first->vedge==NULL) {
+ first->vedge = vedge;
+ }
+ else {
+ hve = &(vedge->hash);
+ hve->vedge = vedge;
+ hve->next = first->next;
+ first->next = hve;
+ }
+}
+
+/*
+ * remove hash of verse edge from hash table
+ */
+static void remove_verse_edgehash(VNode *vnode, VerseEdge *vedge)
+{
+ struct HashVerseEdge *first, *hve, *prev;
+
+ hve = first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
+
+ while(hve) {
+ if(hve->vedge == vedge) {
+ if(hve==first) {
+ if(first->next) {
+ hve = first->next;
+ first->vedge = hve->vedge;
+ first->next = hve->next;
+ }
+ else {
+ hve->vedge = NULL;
+ }
+ }
+ else {
+ prev->next = hve->next;
+ }
+ return;
+ }
+ prev = hve;
+ hve = hve->next;
+ }
+}
+
+/*
+ * this function will try to remove existing fake verse edge, when this verse
+ * edge is still used by some faces, then counter will be only decremented
+ */
+static void remove_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = find_verse_edge(vnode, v0, v1);
+ if(vedge) {
+ vedge->counter--;
+ if(vedge->counter==0) {
+ remove_verse_edgehash(vnode, vedge);
+ BLI_freelinkN(&(((VGeomData*)vnode->data)->edges), vedge);
+ }
+ }
+ else {
+ printf("error: remove_verse_edge %d, %d\n", v0, v1);
+ }
+}
+
+/*
+ * this function will try to add new fake verse edge, when no such edge exist,
+ * when such edge exist, then only counter of edge will be incremented
+ */
+static void add_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = find_verse_edge(vnode, v0, v1);
+ if(!vedge) {
+ if(v0!=v1) {
+ vedge = create_verse_edge(v0, v1);
+ BLI_addtail(&(((VGeomData*)vnode->data)->edges), vedge);
+ insert_verse_edgehash(vnode, vedge);
+ }
+ else {
+ printf("error:add_verse_edge: %d, %d\n", v0, v1);
+ return;
+ }
+ }
+ vedge->counter++;
+}
+
+/*
+ * verse face was deleted ... update edge hash
+ */
+static void update_edgehash_of_deleted_verseface(VNode *vnode, VerseFace *vface)
+{
+ uint32 v0, v1, v2, v3; /* verse vertex indexes of deleted verse face */
+
+ v0 = vface->vvert0->id;
+ v1 = vface->vvert1->id;
+ v2 = vface->vvert2->id;
+ v3 = vface->vvert3 ? vface->vvert3->id : -1;
+
+ remove_verse_edge(vnode, v0, v1);
+ remove_verse_edge(vnode, v1, v2);
+ if(v3!=-1) {
+ remove_verse_edge(vnode, v2, v3);
+ remove_verse_edge(vnode, v3, v0);
+ }
+ else {
+ remove_verse_edge(vnode, v2, v0);
+ }
+}
+
+/*
+ * existing verse face was changed ... update edge hash
+ */
+static void update_edgehash_of_changed_verseface(
+ VNode *vnode,
+ VerseFace *vface,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ uint32 ov0, ov1, ov2, ov3; /* old indexes at verse vertexes*/
+
+ ov0 = vface->vvert0->id;
+ ov1 = vface->vvert1->id;
+ ov2 = vface->vvert2->id;
+ ov3 = vface->vvert3 ? vface->vvert3->id : -1;
+
+ /* 1st edge */
+ if(v0!=ov0 || v1!=ov1) {
+ remove_verse_edge(vnode, ov0, ov1);
+ add_verse_edge(vnode, v0, v1);
+ }
+
+ /* 2nd edge */
+ if(v1!=ov1 || v2!=ov2) {
+ remove_verse_edge(vnode, ov1, ov2);
+ add_verse_edge(vnode, v1, v2);
+ }
+
+ /* 3rd edge */
+ if(v2!=ov2 || v3!=ov3 || v0!=ov0) {
+ if(ov3!=-1) {
+ remove_verse_edge(vnode, ov2, ov3);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3); /* new 3rd edge (quat->quat) */
+ }
+ else {
+ remove_verse_edge(vnode, ov3, ov0); /* old edge v3,v0 of quat have to be removed */
+ add_verse_edge(vnode, v2, v0); /* new 3rd edge (quat->triangle) */
+ }
+ }
+ else {
+ remove_verse_edge(vnode, ov2, ov0);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3); /* new 3rd edge (triangle->quat) */
+ }
+ else {
+ add_verse_edge(vnode, v2, v0); /* new 3rd edge (triangle->triangle) */
+ }
+ }
+ }
+
+ /* 4th edge */
+ if(v3!=-1 && (v3!=ov3 || v0!=ov0)) {
+ remove_verse_edge(vnode, ov3, ov0);
+ add_verse_edge(vnode, v3, v0);
+ }
+}
+
+/*
+ * new verse face was created ... update list of edges and edge has
+ */
+static void update_edgehash_of_new_verseface(
+ VNode *vnode,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ /* when edge already exists, then only its counter is incremented,
+ * look at commentary of add_verse_edge() function */
+ add_verse_edge(vnode, v0, v1);
+ add_verse_edge(vnode, v1, v2);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3);
+ add_verse_edge(vnode, v3, v0);
+ }
+ else {
+ add_verse_edge(vnode, v2, v0);
+ }
+}
+
+/*
+ * callback function: edge crease was set
+ */
+static void cb_g_crease_set_edge(
+ void *user_data,
+ VNodeID node_id,
+ const char *layer,
+ uint32 def_crease)
+{
+}
+
+/*
+ * callback function: float value for polygon was set up
+ */
+static void cb_g_polygon_set_face_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ real32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_real32_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: int values for polygon was set up
+ */
+static void cb_g_polygon_set_face_uint32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint32_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: uint8 value for polygon was set up
+ */
+static void cb_g_polygon_set_face_uint8(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint8 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint8_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint8_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: float value for polygon corner was set up
+ */
+static void cb_g_polygon_set_corner_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ real32 v0,
+ real32 v1,
+ real32 v2,
+ real32 v3)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct quat_real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value[0] = v0;
+ item->value[1] = v1;
+ item->value[2] = v2;
+ item->value[3] = v3;
+ }
+ else {
+ item = create_quat_real32_item(vlayer, polygon_id, v0, v1, v2, v3);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: polygon is deleted
+ */
+static void cb_g_polygon_delete(
+ void *user_data,
+ VNodeID node_id,
+ uint32 polygon_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ VNode *vnode;
+ VLayer *vlayer;
+ VerseFace *vface;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+
+ /* find layer containing faces */
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ /* find wanted VerseFace */
+ vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(!vface) return;
+
+ /* update edge hash */
+ update_edgehash_of_deleted_verseface(vnode, vface);
+
+ ((VGeomData*)vnode->data)->post_polygon_delete(vface);
+
+ /* decrease references at coresponding VerseVertexes */
+ vface->vvert0->counter--;
+ vface->vvert1->counter--;
+ vface->vvert2->counter--;
+ if(vface->vvert3) vface->vvert3->counter--;
+
+ /* delete unneeded VerseVertexes */
+ free_unneeded_verseverts_of_verseface(vnode, vface);
+
+ free_verse_face(vlayer, vface);
+}
+
+/*
+ * callback function: new polygon (face) created or existing polygon was changed
+ */
+static void cb_g_polygon_set_corner_uint32(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct VerseFace *vface=NULL;
+
+ if(!session) return;
+
+ /* try to find VerseNode */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find VerseLayer */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+ if(!vlayer) return;
+
+ /* we have to test coretness of incoming data */
+ if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return;
+
+ /* Blender uses different order of vertexes */
+ if(v3!=-1) { /* quat swap */
+ unsigned int v; v = v1; v1 = v3; v3 = v;
+ }
+ else { /* triangle swap */
+ unsigned int v; v = v1; v1 = v2; v2 = v;
+ }
+
+ /* try to find VerseFace */
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id);
+
+ /* try to find modified VerseFace */
+ if(!vface) {
+ vface = find_changed_verse_face_in_queue(vlayer, polygon_id);
+ if(vface) {
+ BLI_remlink(&(vlayer->queue), (void*)vface);
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
+ }
+ }
+
+ if(!vface) {
+ /* try to find VerseFace in list of VerseVaces created by me and set up polygon and
+ * layer ids */
+ vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3);
+
+ /* update edge hash */
+ update_edgehash_of_new_verseface(vnode, v0, v1, v2, v3);
+
+ if(vface){
+ /* I creeated this face ... remove VerseFace from queue */
+ BLI_remlink(&(vlayer->queue), (void*)vface);
+ }
+ else {
+ /* some other client created this face*/
+ vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3);
+ }
+
+ vface->flag &= ~FACE_SENT;
+
+ /* return number of missing verse vertexes */
+ vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface);
+
+ if(vface->counter < 1) {
+ /* when VerseFace received all needed VerseFaces, then it is moved
+ * to list of VerseFaces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
+ increase_verse_verts_references(vface);
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_polygon_create(vface);
+ }
+ else {
+ /* when all needed VerseVertexes weren't received, then VerseFace is moved to
+ * the list of orphans waiting on needed vertexes */
+ vface->flag |= FACE_RECEIVED;
+ BLI_addtail(&(vlayer->orphans), (void*)vface);
+ }
+ }
+ else {
+ VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ /* VerseVertexes of existing VerseFace were changed (VerseFace will use some different
+ * VerseVertexes or it will use them in different order) */
+
+ /* update fake verse edges */
+ update_edgehash_of_changed_verseface(vnode, vface, v0, v1, v2, v3);
+
+ /* initialize count of unreceived vertexes needed for this face */
+ vface->counter = 4;
+
+ /* 1st corner */
+ if(vface->vvert0->id != v0) {
+ /* decrease references of obsolete vertexes*/
+ vface->vvert0->counter--;
+ /* delete this vertex, when it isn't used by any face and it was marked as deleted */
+ if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
+ free_verse_vertex(vert_vlayer, vface->vvert0);
+ }
+ /* try to set up new pointer at verse vertex */
+ vface->v0 = v0;
+ vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0);
+ if(vface->vvert0) {
+ /* increase references at new vertex */
+ vface->vvert0->counter++;
+ /* decrease count of needed vertex to receive */
+ vface->counter--;
+ }
+
+ }
+ else
+ /* this corner wasn't changed */
+ vface->counter--;
+
+ /* 2nd corner */
+ if(vface->vvert1->id != v1) {
+ vface->vvert1->counter--;
+ if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
+ free_verse_vertex(vert_vlayer, vface->vvert1);
+ }
+ vface->v1 = v1;
+ vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1);
+ if(vface->vvert1) {
+ vface->vvert1->counter++;
+ vface->counter--;
+ }
+ }
+ else
+ vface->counter--;
+
+ /* 3rd corner */
+ if(vface->vvert2->id != v2) {
+ vface->vvert2->counter--;
+ if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
+ free_verse_vertex(vert_vlayer, vface->vvert2);
+ }
+ vface->v2 = v2;
+ vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2);
+ if(vface->vvert2) {
+ vface->vvert2->counter++;
+ vface->counter--;
+ }
+ }
+ else
+ vface->counter--;
+
+ /* 4th corner */
+ if(vface->vvert3) {
+ if(vface->vvert3->id != v3) {
+ vface->vvert3->counter--;
+ if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
+ free_verse_vertex(vert_vlayer, vface->vvert3);
+ }
+ vface->v3 = v3;
+ if(v3 != -1) {
+ vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
+ if(vface->vvert3) {
+ vface->vvert3->counter++;
+ vface->counter--;
+ }
+ }
+ else {
+ /* this is some special case, this face hase now only 3 corners
+ * quat -> triangle */
+ vface->vvert3 = NULL;
+ vface->counter--;
+ }
+ }
+ }
+ else if(v3 != -1)
+ /* this is some special case, 4th corner of this polygon was created
+ * triangle -> quat */
+ vface->v3 = v3;
+ vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
+ if(vface->vvert3) {
+ vface->vvert3->counter++;
+ vface->counter--;
+ }
+ else {
+ vface->v3 = -1;
+ vface->counter--;
+ }
+
+ vface->flag &= ~FACE_SENT;
+ vface->flag |= FACE_CHANGED;
+
+ if(vface->counter<1) {
+ vface->flag &= ~FACE_CHANGED;
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
+ }
+ else {
+ /* when all needed VerseVertexes weren't received, then VerseFace is added to
+ * the list of orphans waiting on needed vertexes */
+ BLI_dlist_rem_item(&(vlayer->dl), vface->id);
+ BLI_addtail(&(vlayer->orphans), (void*)vface);
+ }
+ }
+}
+
+/*
+ * callback function: float value was set up for VerseVert with vertex_id
+ */
+static void cb_g_vertex_set_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ real32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_real32_item(vlayer, vertex_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: int value was set up for VerseVert with vertex_id
+ */
+static void cb_g_vertex_set_uint32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ uint32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint32_item(vlayer, vertex_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: polygon was deleted
+ */
+static void cb_g_vertex_delete_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 vertex_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ VNode *vnode=NULL;
+ VLayer *vert_vlayer=NULL;
+ VerseVert *vvert=NULL;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+
+ vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id);
+
+ if(!vvert) return;
+
+ if(vvert->counter < 1) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vvert);
+ BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
+ }
+ else {
+ /* some VerseFace(s) still need VerseVert, remove verse vert from
+ * list verse vertexes and put it to list of orphans */
+ vvert->flag |= VERT_DELETED;
+ BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
+ BLI_addtail(&(vert_vlayer->orphans), vvert);
+ }
+}
+
+/*
+ * callback function: position of one vertex was changed or new vertex was created
+ */
+static void cb_g_vertex_set_xyz_real32(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode = NULL;
+ struct VLayer *vlayer = NULL;
+ struct VerseVert *vvert = NULL;
+ real32 tmp;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode)return;
+
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+ if(!vlayer) return;
+
+ /* switch axis orientation */
+ tmp = y;
+ y = -z;
+ z = tmp;
+
+ if(vlayer->id == 0) {
+ /* try to pick up verse vert from DynamicList */
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id);
+
+ if(vvert) {
+ if(vvert->flag & VERT_OBSOLETE) return;
+
+ if (vvert->flag & VERT_LOCKED) {
+ /* this application changed position of this vertex */
+ if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) {
+ /* unlock vertex position */
+ vvert->flag &= ~VERT_LOCKED;
+ /* call post_vertex_set_xyz only, when position of vertex is
+ * obsolete ... the new vertex position will be sent to
+ * verse server */
+ if (vvert->flag & VERT_POS_OBSOLETE) {
+ ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
+ }
+ }
+ }
+ else {
+ /* somebody else changed position of this vertex*/
+ if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) {
+ vvert->co[0] = x;
+ vvert->co[1] = y;
+ vvert->co[2] = z;
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
+ }
+ }
+ }
+ else {
+ /* create new verse vert */
+
+ /* test if we are authors of this vertex :-) */
+ vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z);
+
+ if(vvert) {
+ /* remove vert from queue */
+ BLI_remlink(&(vlayer->queue), (void*)vvert);
+ /* add vvert to the dynamic list */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
+ /* set VerseVert flags */
+ vvert->flag |= VERT_RECEIVED;
+ if(!(vvert->flag & VERT_POS_OBSOLETE))
+ vvert->flag &= ~VERT_LOCKED;
+ /* find VerseFaces orphans */
+ find_vlayer_orphans(vnode, vvert);
+ /* find unsent VerseFaces */
+ find_unsent_faces(vnode, vvert);
+ }
+ else {
+ /* create new VerseVert */
+ vvert = create_verse_vertex(vlayer, vertex_id, x, y, z);
+ /* add VerseVert to list of VerseVerts */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
+ /* set VerseVert flags */
+ vvert->flag |= VERT_RECEIVED;
+ /* find VerseFaces orphans */
+ find_vlayer_orphans(vnode, vvert);
+ }
+
+ ((VGeomData*)vnode->data)->post_vertex_create(vvert);
+ }
+ }
+}
+
+/*
+ * callback function for destroyng of verse layer
+ */
+static void cb_g_layer_destroy(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id);
+ if(!vnode) return;
+
+ vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id);
+
+ if(vlayer){
+ /* free VerseLayer data */
+ free_verse_layer_data(vnode, vlayer);
+ /* remove VerseLayer from list of verse layers */
+ BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id);
+ /* do client dependent actions */
+ vlayer->post_layer_destroy(vlayer);
+ /* free vlayer itself */
+ MEM_freeN(vlayer);
+ }
+
+}
+
+/*
+ * callback function: new layer was created
+ */
+static void cb_g_layer_create(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ const char *name,
+ VNGLayerType type,
+ uint32 def_integer,
+ real64 def_real)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode=NULL;
+ struct VLayer *vlayer=NULL;
+
+ if(!session) return;
+
+ /* find node of this layer*/
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ if(!vnode) return;
+
+ /* when we created this layer, then subscribe to this layer */
+ if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE)
+ verse_send_g_layer_subscribe(node_id, layer_id, 0);
+
+ /* try to find */
+ if(vnode->owner_id == VN_OWNER_MINE)
+ vlayer = find_vlayer_in_sending_queue(vnode, layer_id);
+
+ if(vlayer) {
+ /* remove vlayer form sending queue add verse layer to list of verse layers */
+ BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer);
+ BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id);
+ /* send all not sent vertexes to verse server
+ * other items waiting in sending queue will be automaticaly sent to verse server,
+ * when verse vertexes will be received from verse server */
+ if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) {
+ struct VerseVert *vvert = (VerseVert*)vlayer->queue.first;
+ while(vvert) {
+ send_verse_vertex(vvert);
+ vvert = vvert->next;
+ }
+ }
+ }
+ else {
+ /* create new VerseLayer */
+ vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real);
+ /* add layer to the list of VerseLayers */
+ BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id);
+ }
+
+ vlayer->flag |= LAYER_RECEIVED;
+
+ /* post callback function */
+ vlayer->post_layer_create(vlayer);
+}
+
+/*
+ * this function will send destroy commands for all VerseVertexes and
+ * VerseFaces to verse server, but it will not send destroy commands
+ * for VerseLayers or geometry node, it can be used in other functions
+ * (undo, destroy geom node, some edit mesh commands, ... ), parameter of
+ * this function has to be geometry verse node
+ */
+void destroy_geometry(VNode *vnode)
+{
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+ vface = face_vlayer->dl.lb.first;
+
+ while(vface) {
+ send_verse_face_delete(vface);
+ vface = vface->next;
+ }
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ vvert = vert_vlayer->dl.lb.first;
+
+ while(vvert) {
+ send_verse_vertex_delete(vvert);
+ vvert = vvert->next;
+ }
+
+ /* own destruction of local verse date will be executed, when client will
+ * receive apropriate callback commands from verse server */
+}
+
+/*
+ * free VGeomData
+ */
+void free_geom_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VLayer *vlayer;
+
+ if(vnode->data){
+ vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first;
+ while(vlayer){
+ /* unsubscribe from layer */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_g_layer_unsubscribe(vnode->id, vlayer->id);
+ /* free VerseLayer data */
+ free_verse_layer_data(vnode, vlayer);
+ /* next layer */
+ vlayer = vlayer->next;
+ }
+ /* free constraint between vnode and mesh */
+ ((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode);
+ /* free all VerseLayers */
+ BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
+ /* free fake verse edges */
+ BLI_freelistN(&((VGeomData*)vnode->data)->edges);
+ /* free edge hash */
+ MEM_freeN(((VGeomData*)vnode->data)->hash);
+ }
+}
+
+void set_geometry_callbacks(void)
+{
+ /* new layer created */
+ verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL);
+ /* layer was destroyed */
+ verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL);
+
+ /* position of vertex was changed */
+ verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL);
+ /* vertex was deleted */
+ verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL);
+
+ /* callback functions for values being associated with vertexes */
+ verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL);
+ verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL);
+
+ /* new polygon was created / vertex(es) of polygon was set */
+ verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL);
+ /* polygon was deleted */
+ verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL);
+
+ /* callback functions for values being associated with polygon corners */
+ verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL);
+ /* callback functions for values being associated with faces */
+ verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL);
+ verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL);
+ verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL);
+
+ /* crease of vertex was set */
+ verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL);
+ /* crease of edge was set */
+ verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_method.c b/source/blender/blenkernel/intern/verse_method.c
new file mode 100644
index 00000000000..89b5282acfd
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_method.c
@@ -0,0 +1,523 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Nathan Letwory.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+#include "DNA_text_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_library.h"
+#include "BKE_text.h"
+#include "BKE_verse.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "verse.h"
+
+/* helper struct for creating method descriptions */
+typedef struct VMethodInfo {
+ const char *name;
+ uint8 param_count;
+ const VNOParamType param_type[4];
+ const char *param_name[4];
+ uint16 id;
+} VMethodInfo;
+
+#ifdef VERSECHAT
+/* array with methods for verse chat */
+static VMethodInfo vmethod_info[] = {
+ { "join", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
+ { "leave", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
+ { "hear", 3, { VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING }, { "channel", "from", "msg"}}
+};
+#endif
+
+/* lookup a method group based on its name */
+struct VMethodGroup *lookup_vmethodgroup_name(ListBase *lb, const char *name) {
+ struct VMethodGroup *vmg;
+
+ for(vmg= lb->first; vmg; vmg= vmg->next)
+ if(strcmp(vmg->name,name)==0) break;
+
+ return vmg;
+}
+
+/* lookup a method group based on its group_id */
+struct VMethodGroup *lookup_vmethodgroup(ListBase *lb, uint16 group_id) {
+ struct VMethodGroup *vmg;
+
+ for(vmg= lb->first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ return vmg;
+}
+
+/* lookup a method based on its name */
+struct VMethod *lookup_vmethod_name(ListBase *lb, const char *name) {
+ struct VMethod *vm;
+ for(vm= lb->first; vm; vm= vm->next)
+ if(strcmp(vm->name,name)==0) break;
+
+ return vm;
+}
+
+/* lookup a method based on its method_id */
+struct VMethod *lookup_vmethod(ListBase *lb, uint8 method_id) {
+ struct VMethod *vm;
+ for(vm= lb->first; vm; vm= vm->next)
+ if(vm->id==method_id) break;
+
+ return vm;
+}
+
+#ifdef VERSECHAT
+/*
+ * send say command
+ */
+void send_say(const char *chan, const char *utter)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *utterpack;
+ VNOParam args[2];
+
+ vnode= (VNode *)(session->nodes.lb.first);
+
+ for( ; vnode; vnode= vnode->next) {
+ if(strcmp(vnode->name, "tawksrv")==0) {
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) break;
+ vm= lookup_vmethod_name(&(vmg->methods), "say");
+ if(!vm) break;
+ args[0].vstring= (char *)chan;
+ args[1].vstring= (char *)utter;
+ if((utterpack= verse_method_call_pack(vm->param_count, vm->param_type, args))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, utterpack);
+ }
+ break;
+ }
+
+ }
+}
+
+/*
+ * send logout command
+ */
+void send_logout(VNode *vnode)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *pack;
+
+ vnode->chat_flag = CHAT_LOGGED;
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "logout");
+ if(!vm) return;
+
+ if((pack= verse_method_call_pack(vm->param_count, vm->param_type, NULL))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, pack);
+ }
+ vnode->chat_flag = CHAT_NOTLOGGED;
+}
+
+/*
+ * send join command
+ */
+void send_join(VNode *vnode, const char *chan)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *join;
+ VNOParam channel[1];
+
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "join");
+ if(!vm) return;
+
+ channel[0].vstring= (char *)chan;
+ if((join= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, join);
+ }
+}
+
+/*
+ * send leave command
+ */
+void send_leave(VNode *vnode, const char *chan)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *leave;
+ VNOParam channel[1];
+
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "leave");
+ if(!vm) return;
+
+ channel[0].vstring= (char *)chan;
+ if((leave= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, leave);
+ }
+}
+
+/*
+ * send login command
+ */
+void send_login(VNode *vnode)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *login;
+ VNOParam param[1];
+
+ vnode->chat_flag = CHAT_LOGGED;
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "login");
+ if(!vm) return;
+
+ param[0].vstring= U.verseuser;
+
+ if((login= verse_method_call_pack(vm->param_count, vm->param_type, param))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, login);
+ }
+ vnode->chat_flag = CHAT_LOGGED;
+
+ vnode= lookup_vnode(vnode->session, vnode->session->avatar);
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk-client");
+ if(!vmg)
+ verse_send_o_method_group_create(vnode->session->avatar, ~0, "tawk-client");
+}
+#endif
+
+/*
+ * Free a VMethod
+ */
+void free_verse_method(VMethod *vm) {
+ if(!vm) return;
+
+ MEM_freeN(vm->param_type);
+}
+
+/*
+ * Free methods for VMethodGroup
+ */
+void free_verse_methodgroup(VMethodGroup *vmg)
+{
+ struct VMethod *vm, *tmpvm;
+
+ if(!vmg) return;
+
+ vm= vmg->methods.first;
+ while(vm) {
+ tmpvm=vm->next;
+ free_verse_method(vm);
+ vm= tmpvm;
+ }
+ BLI_freelistN(&(vmg->methods));
+}
+
+/* callback for method group creation */
+static void cb_o_method_group_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vmg = lookup_vmethodgroup(&(vnode->methodgroups), group_id);
+
+ /* create method group holder in node node_id */
+ if(!vmg) {
+ vmg= MEM_mallocN(sizeof(VMethodGroup), "VMethodGroup");
+ vmg->group_id = group_id;
+ vmg->methods.first = vmg->methods.last = NULL;
+ BLI_addtail(&(vnode->methodgroups), vmg);
+ printf("new method group with name %s (group_id %d) for node %u created\n", name, group_id, node_id);
+ }
+
+ /* this ensures name of an existing group gets updated, in case it is changed */
+ BLI_strncpy(vmg->name, (char *)name, 16);
+
+ /* subscribe to method group */
+ verse_send_o_method_group_subscribe(node_id, group_id);
+
+#ifdef VERSECHAT
+ /* if this is our own method group, register our methods */
+ if(node_id==session->avatar) {
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[0].name,
+ vmethod_info[0].param_count,
+ (VNOParamType *)vmethod_info[0].param_type,
+ (const char **)vmethod_info[0].param_name);
+ b_verse_update();
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[1].name,
+ vmethod_info[1].param_count,
+ (VNOParamType *)vmethod_info[1].param_type,
+ (const char **)vmethod_info[1].param_name);
+ b_verse_update();
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[2].name,
+ vmethod_info[2].param_count,
+ (VNOParamType *)vmethod_info[2].param_type,
+ (const char **)vmethod_info[2].param_name);
+ b_verse_update();
+ }
+#endif
+}
+
+/* callback for method group destruction */
+static void cb_o_method_group_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+
+ printf("method group %d destroyed\n", group_id);
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ if(!vmg) return; /* method group doesn't exist? */
+
+ vmg->group_id = 0;
+ vmg->name[0] = '\0';
+ vm= vmg->methods.first;
+ while(vm) {
+ /* free vm */
+
+ }
+
+ /* TODO: unsubscribe from method group */
+ BLI_remlink(&(vnode->methodgroups),vmg);
+ MEM_freeN(vmg);
+}
+
+/* callback for method creation */
+static void cb_o_method_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 method_id,
+ const char *name,
+ uint8 param_count,
+ const VNOParamType *param_type,
+ const char *param_name[])
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ unsigned int size;
+ unsigned int i;
+ char *put;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vmg= lookup_vmethodgroup((&vnode->methodgroups), group_id);
+
+ if(!vmg) return;
+
+ vm= lookup_vmethod((&vmg->methods), method_id);
+
+ if(!vm) {
+ vm= MEM_mallocN(sizeof(VMethod), "VMethod");
+ vm->id= method_id;
+ vm->param_count= param_count;
+ size= param_count* (sizeof(*vm->param_type) + sizeof(*vm->param_name));
+ for(i= 0; i <param_count; i++) {
+ size+=strlen(param_name[i])+1;
+ }
+ vm->param_type= MEM_mallocN(size, "param_type and param_name");
+ memcpy(vm->param_type, param_type, sizeof(VNOParamType)*param_count);
+ vm->param_name= (char **)(vm->param_type + param_count);
+ put= (char *)(vm->param_name + param_count);
+ for(i= 0; i < param_count; i++) {
+ vm->param_name[i]= put;
+ strcpy(put, param_name[i]);
+ put += strlen(param_name[i]) + 1;
+ }
+
+ BLI_addtail(&(vmg->methods), vm);
+#ifdef VERSECHAT
+ if(strcmp(vmethod_info[0].name, name)==0) {
+ vmethod_info[0].id = method_id;
+ }
+#endif
+ printf("method %s in group %d of node %u created\n", name, group_id, node_id);
+ }
+
+ BLI_strncpy(vm->name, (char *)name, 500);
+}
+
+/* callback for method destruction */
+static void cb_o_method_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 method_id,
+ const char *name,
+ uint8 param_count,
+ const VNOParamType *param_type,
+ const char *param_name[])
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ if(!vmg) return; /* method group doesn't exist? */
+
+ for(vm= vmg->methods.first; vm; vm= vm->next)
+ if(vm->id==method_id) break;
+
+ if(!vm) return;
+
+ BLI_remlink(&(vmg->methods), vm);
+ MEM_freeN(vm->param_type);
+ MEM_freeN(vm);
+}
+
+/* callback for method calls */
+static void cb_o_method_call(void *user_data, VNodeID node_id, uint8 group_id, uint8 method_id, VNodeID sender, VNOPackedParams *params)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ Text *text;
+ int method_idx= -1;
+
+ VNOParam arg[3];
+
+ if(!session) return;
+
+ if(session->avatar!=node_id) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ vmg= lookup_vmethodgroup(&(vnode->methodgroups), group_id);
+ if(!vmg) return;
+
+ vm= lookup_vmethod(&(vmg->methods), method_id);
+ if(!vm) return;
+#ifdef VERSECHAT
+ if(strcmp(vm->name, "join")==0) method_idx=0;
+ if(strcmp(vm->name, "leave")==0) method_idx=1;
+ if(strcmp(vm->name, "hear")==0) method_idx=2;
+ if(method_idx>-1)
+ verse_method_call_unpack(params, vmethod_info[method_idx].param_count, vmethod_info[method_idx].param_type, arg);
+
+ switch(method_idx) {
+ case 0:
+ printf("Joining channel %s\n",arg[0].vstring);
+ text=add_empty_text();
+ text->flags |= TXT_ISCHAT;
+ rename_id(&(text->id), arg[0].vstring);
+ break;
+ case 1:
+ printf("Leaving channel %s\n",arg[0].vstring);
+ break;
+ case 2:
+ {
+ ListBase lb = G.main->text;
+ ID *id= (ID *)lb.first;
+ char showstr[1024];
+ showstr[0]='\0';
+ text = NULL;
+ sprintf(showstr, "%s: %s\n", arg[1].vstring, arg[2].vstring);
+ for(; id; id= id->next) {
+ if(strcmp(id->name+2, arg[0].vstring)==0 && strcmp(arg[0].vstring, "#server")!=0) {
+ text = (Text *)id;
+ break;
+ }
+ }
+ if(text) {
+ txt_insert_buf(text, showstr);
+ txt_move_eof(text, 0);
+ allqueue(REDRAWCHAT, 0);
+ } else {
+ printf("%s> %s: %s\n",arg[0].vstring, arg[1].vstring, arg[2].vstring);
+ }
+ }
+ break;
+ }
+#endif
+}
+
+void set_method_callbacks(void)
+{
+ /* create and destroy method groups */
+ verse_callback_set(verse_send_o_method_group_create, cb_o_method_group_create, NULL);
+ verse_callback_set(verse_send_o_method_group_destroy, cb_o_method_group_destroy, NULL);
+
+ /* create and destroy methods */
+ verse_callback_set(verse_send_o_method_create, cb_o_method_create, NULL);
+ verse_callback_set(verse_send_o_method_destroy, cb_o_method_destroy, NULL);
+
+ /* call methods */
+ verse_callback_set(verse_send_o_method_call, cb_o_method_call, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_node.c b/source/blender/blenkernel/intern/verse_node.c
new file mode 100644
index 00000000000..682ae773da5
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_node.c
@@ -0,0 +1,750 @@
+/**
+ * $Id: verse_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+ /* for tags */
+static void free_verse_tag_data(struct VTag *vtag);
+static struct VTag *find_tag_in_queue(struct VTagGroup *vtaggroup, const char *name);
+static struct VTag *create_verse_tag(struct VTagGroup *vtaggroup, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag);
+ /* for verse tag groups */
+static void free_verse_taggroup_data(struct VTagGroup *taggroup);
+static struct VTagGroup *find_taggroup_in_queue(struct VNode *vnode, const char *name);
+static struct VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name);
+ /* for verse nodes */
+static void move_verse_node_to_dlist(struct VerseSession *session, VNodeID vnode_id);
+ /* function prototypes of node callback functions */
+static void cb_tag_destroy(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id);
+static void cb_tag_create(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag);
+static void cb_tag_group_destroy(void *user_data, VNodeID node_id, uint16 group_id);
+static void cb_tag_group_create(void *user_data, VNodeID node_id, uint16 group_id, const char *name);
+static void cb_node_name_set(void *user_data, VNodeID node_id, const char *name);
+static void cb_node_destroy(void *user_data, VNodeID node_id);
+static void cb_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeID owner_id);
+
+/*
+ * send new tag to verse server
+ */
+void send_verse_tag(VTag *vtag)
+{
+ verse_send_tag_create(vtag->vtaggroup->vnode->id,
+ vtag->vtaggroup->id,
+ vtag->id,
+ vtag->name,
+ vtag->type,
+ vtag->tag);
+}
+
+/*
+ * free tag data
+ */
+static void free_verse_tag_data(VTag *vtag)
+{
+ /* free name of verse tag */
+ MEM_freeN(vtag->name);
+ /* free value of tag */
+ MEM_freeN(vtag->tag);
+}
+
+/*
+ * try to find tag in sending queue ... if tag will be found, then
+ * this function will removed tag from queue and will return pointer
+ * at this tag
+ */
+static VTag *find_tag_in_queue(VTagGroup *vtaggroup, const char *name)
+{
+ struct VTag *vtag;
+
+ vtag = vtaggroup->queue.first;
+
+ while(vtag) {
+ if(strcmp(vtag->name, name)==0) {
+ BLI_remlink(&(vtaggroup->queue), vtag);
+ break;
+ }
+ vtag = vtag->next;
+ }
+
+ return vtag;
+}
+
+/*
+ * create new verse tag
+ */
+static VTag *create_verse_tag(
+ VTagGroup *vtaggroup,
+ uint16 tag_id,
+ const char *name,
+ VNTagType type,
+ const VNTag *tag)
+{
+ struct VTag *vtag;
+
+ vtag = (VTag*)MEM_mallocN(sizeof(VTag), "VTag");
+
+ vtag->vtaggroup = vtaggroup;
+ vtag->id = tag_id;
+ vtag->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTag name");
+ strcpy(vtag->name, name);
+ vtag->type = type;
+
+ vtag->tag = (VNTag*)MEM_mallocN(sizeof(VNTag), "VNTag");
+ *vtag->tag = *tag;
+
+ vtag->value = NULL;
+
+ return vtag;
+}
+
+/*
+ * send taggroup to verse server
+ */
+void send_verse_taggroup(VTagGroup *vtaggroup)
+{
+ verse_send_tag_group_create(
+ vtaggroup->vnode->id,
+ vtaggroup->id,
+ vtaggroup->name);
+}
+
+/*
+ * free taggroup data
+ */
+static void free_verse_taggroup_data(VTagGroup *taggroup)
+{
+ struct VerseSession *session = taggroup->vnode->session;
+ struct VTag *vtag;
+
+ vtag = taggroup->tags.lb.first;
+
+ while(vtag) {
+ free_verse_tag_data(vtag);
+ vtag = vtag->next;
+ }
+
+ /* unsubscribe from taggroup */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_tag_group_unsubscribe(taggroup->vnode->id, taggroup->id);
+
+ BLI_dlist_destroy(&(taggroup->tags));
+ MEM_freeN(taggroup->name);
+}
+
+/*
+ * move taggroup from queue to dynamic list with access array,
+ * set up taggroup id and return pointer at this taggroup
+ */
+static VTagGroup *find_taggroup_in_queue(VNode *vnode, const char *name)
+{
+ struct VTagGroup *vtaggroup;
+
+ vtaggroup = vnode->queue.first;
+
+ while(vtaggroup) {
+ if(strcmp(vtaggroup->name, name)==0) {
+ BLI_remlink(&(vnode->queue), vtaggroup);
+ break;
+ }
+ vtaggroup = vtaggroup->next;
+ }
+
+ return vtaggroup;
+}
+
+/*
+ * create new verse group of tags
+ */
+static VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name)
+{
+ struct VTagGroup *taggroup;
+
+ taggroup = (VTagGroup*)MEM_mallocN(sizeof(VTagGroup), "VTagGroup");
+
+ taggroup->vnode = vnode;
+ taggroup->id = group_id;
+ taggroup->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTagGroup name");
+ strcpy(taggroup->name, name);
+
+ BLI_dlist_init(&(taggroup->tags));
+ taggroup->queue.first = taggroup->queue.last = NULL;
+
+ taggroup->post_tag_change = post_tag_change;
+ taggroup->post_taggroup_create = post_taggroup_create;
+
+ return taggroup;
+}
+
+/*
+ * move first VerseNode waiting in sending queue to dynamic list of VerseNodes
+ * (it usually happens, when "our" VerseNode was received from verse server)
+ */
+static void move_verse_node_to_dlist(VerseSession *session, VNodeID vnode_id)
+{
+ VNode *vnode;
+
+ vnode = session->queue.first;
+
+ if(vnode) {
+ BLI_remlink(&(session->queue), vnode);
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, vnode_id);
+ }
+}
+
+/*
+ * send VerseNode to verse server
+ */
+void send_verse_node(VNode *vnode)
+{
+ verse_send_node_create(
+ vnode->id,
+ vnode->type,
+ vnode->session->avatar);
+}
+
+/*
+ * free Verse Node data
+ */
+void free_verse_node_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VTagGroup *vtaggroup;
+
+ /* free node data (object, geometry, etc.) */
+ switch(vnode->type){
+ case V_NT_OBJECT:
+ free_object_data(vnode);
+ break;
+ case V_NT_GEOMETRY:
+ free_geom_data(vnode);
+ break;
+ case V_NT_BITMAP:
+ free_bitmap_node_data(vnode);
+ break;
+ default:
+ break;
+ }
+
+ /* free all tag groups in dynamic list with access array */
+ vtaggroup = vnode->taggroups.lb.first;
+ while(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ vtaggroup = vtaggroup->next;
+ }
+ BLI_dlist_destroy(&(vnode->taggroups));
+
+ /* free all tag groups still waiting in queue */
+ vtaggroup = vnode->queue.first;
+ while(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ vtaggroup = vtaggroup->next;
+ }
+ BLI_freelistN(&(vnode->queue));
+
+ /* unsubscribe from node */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_node_unsubscribe(vnode->id);
+
+ /* free node name */
+ MEM_freeN(vnode->name);
+ vnode->name = NULL;
+
+ /* free node data */
+ MEM_freeN(vnode->data);
+ vnode->data = NULL;
+
+}
+
+/*
+ * free VerseNode
+ */
+void free_verse_node(VNode *vnode)
+{
+ free_verse_node_data(vnode);
+
+ BLI_dlist_free_item(&(vnode->session->nodes), vnode->id);
+}
+
+/*
+ * Find a Verse Node from session
+ */
+VNode* lookup_vnode(VerseSession *session, VNodeID node_id)
+{
+ struct VNode *vnode;
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ return vnode;
+}
+
+/*
+ * create new Verse Node
+ */
+VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id)
+{
+ struct VNode *vnode;
+
+ vnode = (VNode*)MEM_mallocN(sizeof(VNode), "VerseNode");
+
+ vnode->session = session;
+ vnode->id = node_id;
+ vnode->owner_id = owner_id;
+ vnode->name = NULL;
+ vnode->type = type;
+
+ BLI_dlist_init(&(vnode->taggroups));
+ vnode->queue.first = vnode->queue.last = NULL;
+ vnode->methodgroups.first = vnode->methodgroups.last = NULL;
+
+ vnode->data = NULL;
+
+ vnode->counter = 0;
+
+ vnode->flag = 0;
+#ifdef VERSECHAT
+ vnode->chat_flag = CHAT_NOTLOGGED;
+#endif
+
+ vnode->post_node_create = post_node_create;
+ vnode->post_node_destroy = post_node_destroy;
+ vnode->post_node_name_set = post_node_name_set;
+
+ return vnode;
+}
+
+/*
+ * callback function: tag was destroyed
+ */
+static void cb_tag_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 tag_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+ struct VTag *vtag;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) return;
+
+ /* try to find verse tag in dynamic list of tags in tag group */
+ vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id);
+
+ if(vtag) {
+ free_verse_tag_data(vtag);
+ BLI_dlist_free_item(&(vtaggroup->tags), vtag->id);
+ }
+}
+
+/*
+ * callback function: new tag was created
+ */
+static void cb_tag_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 tag_id,
+ const char *name,
+ VNTagType type,
+ const VNTag *tag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+ struct VTag *vtag;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) return;
+
+ /* try to find verse tag in dynamic list of tags in tag group */
+ vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id);
+
+ if(!vtag) {
+ /* we will try to find vtag in sending queue */
+ vtag = find_tag_in_queue(vtaggroup, name);
+
+ /* when we didn't create this tag, then we will have to create one */
+ if(!vtag) vtag = create_verse_tag(vtaggroup, tag_id, name, type, tag);
+ else vtag->id = tag_id;
+
+ /* add tag to the list of tags in tag group */
+ BLI_dlist_add_item_index(&(vtaggroup->tags), vtag, tag_id);
+
+ /* post change/create method */
+ vtaggroup->post_tag_change(vtag);
+ }
+ else {
+ /* this tag exists, then we will propably change value of this tag */
+ if((vtag->type != type) || (strcmp(vtag->name, name)!=0)) {
+ /* changes of type or name are not allowed and such
+ * stupid changes will be returned back */
+ send_verse_tag(vtag);
+ }
+ else {
+ /* post change/create method */
+ vtaggroup->post_tag_change(vtag);
+ }
+ }
+}
+
+/*
+ * callback function: tag group was destroyed
+ */
+static void cb_tag_group_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ BLI_dlist_free_item(&(vnode->taggroups), vtaggroup->id);
+ }
+}
+
+/*
+ * callback function: new tag group was created
+ */
+static void cb_tag_group_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* name of taggroup has to begin with string "blender:" */
+ if(strncmp("blender:", name, 8)) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) {
+ /* subscribe to tag group (when new tag will be created, then blender will
+ * receive command about it) */
+ verse_send_tag_group_subscribe(vnode->id, group_id);
+ verse_callback_update(0);
+
+ /* try to find taggroup in waiting queue */
+ vtaggroup = find_taggroup_in_queue(vnode, name);
+
+ /* if no taggroup exist, then new has to be created */
+ if(!vtaggroup) vtaggroup = create_verse_taggroup(vnode, group_id, name);
+ else vtaggroup->id = group_id;
+
+ /* add tag group to dynamic list with access array */
+ BLI_dlist_add_item_index(&(vnode->taggroups), (void*)vtaggroup, (unsigned int)group_id);
+
+ /* post create method */
+ vtaggroup->post_taggroup_create(vtaggroup);
+ }
+ else {
+ /* this taggroup exist and somebody try to change its name */
+ if(strcmp(vtaggroup->name, name)!=0) {
+ /* blender doesn't allow such stupid and dangerous things */
+ send_verse_taggroup(vtaggroup);
+ }
+ }
+}
+
+/*
+ * callback function: change name of node
+ */
+static void cb_node_name_set(
+ void *user_data,
+ VNodeID node_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(vnode && name) {
+ if(!vnode->name) {
+ vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name");
+ }
+ else if(strlen(name) > strlen(vnode->name)) {
+ MEM_freeN(vnode->name);
+ vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name");
+ }
+ strcpy(vnode->name, name);
+
+ vnode->post_node_name_set(vnode);
+ }
+}
+
+/*
+ * callback function for deleting node
+ */
+static void cb_node_destroy(
+ void *user_data,
+ VNodeID node_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ if(vnode) {
+ /* remove VerseNode from dynamic list */
+ BLI_dlist_rem_item(&(session->nodes), (unsigned int)node_id);
+ /* do post destroy operations */
+ vnode->post_node_destroy(vnode);
+ /* free verse data */
+ free_verse_node_data(vnode);
+ /* free VerseNode */
+ MEM_freeN(vnode);
+ };
+}
+
+
+/*
+ * callback function for new created node
+ */
+static void cb_node_create(
+ void *user_data,
+ VNodeID node_id,
+ uint8 type,
+ VNodeID owner_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode = NULL;
+
+ if(!session) return;
+
+ /* subscribe to node */
+ if((type==V_NT_OBJECT) || (type==V_NT_GEOMETRY) || (type==V_NT_BITMAP))
+ verse_send_node_subscribe(node_id);
+ else
+ return;
+
+ switch(type){
+ case V_NT_OBJECT :
+ if(owner_id==VN_OWNER_MINE) {
+ struct VLink *vlink;
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* find unsent link pointing at this VerseNode */
+ vlink = find_unsent_child_vlink(session, vnode);
+ /* send VerseLink */
+ if(vlink) send_verse_link(vlink);
+ /* send name of object node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* subscribe to changes of object node transformations */
+ verse_send_o_transform_subscribe(node_id, 0);
+ /* send object transformation matrix */
+ send_verse_object_position(vnode);
+ send_verse_object_rotation(vnode);
+ send_verse_object_scale(vnode);
+ }
+ else {
+ /* create new VerseNode */
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to list of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create object data */
+ vnode->data = create_object_data();
+ /* set up avatar's name */
+ if(node_id == session->avatar) {
+ verse_send_node_name_set(node_id, U.verseuser);
+ }
+ else if(session->flag & VERSE_AUTOSUBSCRIBE) {
+ /* subscribe to changes of object node transformations */
+ verse_send_o_transform_subscribe(node_id, 0);
+ }
+ }
+ break;
+ case V_NT_GEOMETRY :
+ if(owner_id==VN_OWNER_MINE){
+ struct VLink *vlink;
+ struct VLayer *vlayer;
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* find unsent link pointing at this VerseNode */
+ vlink = find_unsent_parent_vlink(session, vnode);
+ /* send VerseLink */
+ if(vlink) send_verse_link(vlink);
+ /* send name of geometry node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* send all not sent layer to verse server */
+ vlayer = (VLayer*)((VGeomData*)vnode->data)->queue.first;
+ if(vlayer) {
+ while(vlayer) {
+ send_verse_layer(vlayer);
+ vlayer = vlayer->next;
+ }
+ }
+ else {
+ /* send two verse layers to verse server */
+/* verse_send_g_layer_create(node_id, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0);
+ verse_send_g_layer_create(node_id, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);*/
+ }
+ }
+ else {
+ /* create new VerseNode*/
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to dlist of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create geometry data */
+ vnode->data = (void*)create_geometry_data();
+ }
+ break;
+ case V_NT_BITMAP :
+ if(owner_id==VN_OWNER_MINE) {
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* send name of object node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* send dimension of image to verse server */
+ verse_send_b_dimensions_set(node_id,
+ ((VBitmapData*)vnode->data)->width,
+ ((VBitmapData*)vnode->data)->height,
+ ((VBitmapData*)vnode->data)->depth);
+ }
+ else {
+ /* create new VerseNode*/
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to dlist of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create bitmap data */
+ vnode->data = (void*)create_bitmap_data();
+ }
+ break;
+ default:
+ vnode = NULL;
+ break;
+ }
+
+ if(vnode) vnode->post_node_create(vnode);
+}
+
+/*
+ * set up all callbacks for verse nodes
+ */
+void set_node_callbacks(void)
+{
+ /* new node created */
+ verse_callback_set(verse_send_node_create, cb_node_create, NULL);
+ /* node was deleted */
+ verse_callback_set(verse_send_node_destroy, cb_node_destroy, NULL);
+ /* name of node was set */
+ verse_callback_set(verse_send_node_name_set, cb_node_name_set, NULL);
+
+ /* new tag group was created */
+ verse_callback_set(verse_send_tag_group_create, cb_tag_group_create, NULL);
+ /* tag group was destroy */
+ verse_callback_set(verse_send_tag_group_destroy, cb_tag_group_destroy, NULL);
+
+ /* new tag was created */
+ verse_callback_set(verse_send_tag_create, cb_tag_create, NULL);
+ /* tag was destroy */
+ verse_callback_set(verse_send_tag_destroy, cb_tag_destroy, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_object_node.c b/source/blender/blenkernel/intern/verse_object_node.c
new file mode 100644
index 00000000000..9f4dcc72237
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_object_node.c
@@ -0,0 +1,620 @@
+/**
+ * $Id: verse_object_node.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+#include "BKE_utildefines.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+
+/* callback functions */
+static void cb_o_transform_pos_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag);
+static void cb_o_transform_rot_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *temp, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag);
+static void cb_o_transform_scale_real32(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z);
+static void cb_o_link_set(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id);
+static void cb_o_link_destroy(void *user_data, VNodeID node_id,uint16 link_id);
+
+/* other functions */
+static void set_target_node_link_pointer(struct VNode *vnode, struct VLink *vlink);
+static void free_verse_link_data(struct VLink *vlink);
+
+/*
+ * find noy sent VerseLink in queue
+ */
+VLink *find_unsent_child_vlink(VerseSession *session, VNode *vnode)
+{
+ struct VLink *vlink;
+
+ if(vnode->type!=V_NT_OBJECT) return NULL;
+
+ vlink = ((VObjectData*)vnode->data)->queue.first;
+ while(vlink) {
+ if(vlink->target->id != -1) {
+ printf("\t vlink found, vnode target id %d\n", vlink->target->id);
+ return vlink;
+ }
+ vlink = vlink->next;
+ }
+ return NULL;
+}
+
+/*
+ * find unsent VerseLink "pointing at this VerseNode"
+ */
+VLink *find_unsent_parent_vlink(VerseSession *session, VNode *vnode)
+{
+ struct VNode *tmp;
+ struct VLink *vlink;
+
+ tmp = session->nodes.lb.first;
+
+ while(tmp) {
+ if(tmp->type==V_NT_OBJECT) {
+ vlink = ((VObjectData*)tmp->data)->queue.first;
+ while(vlink) {
+ if(vlink->target == vnode)
+ return vlink;
+ vlink = vlink->next;
+ }
+ }
+ tmp = tmp->next;
+ }
+ return NULL;
+}
+
+/*
+ * send object position to verse server
+ */
+void send_verse_object_position(VNode *vnode)
+{
+ float tmp;
+
+ ((VObjectData*)vnode->data)->flag &= ~POS_SEND_READY;
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = -((VObjectData*)vnode->data)->pos[1];
+ ((VObjectData*)vnode->data)->pos[1] = ((VObjectData*)vnode->data)->pos[2];
+ ((VObjectData*)vnode->data)->pos[2] = tmp;
+
+ verse_send_o_transform_pos_real32(
+ vnode->id, /* node id */
+ 0, /* time_s ... no interpolation */
+ 0, /* time_f ... no interpolation */
+ ((VObjectData*)vnode->data)->pos,
+ NULL, /* speed ... no interpolation */
+ NULL, /* accelerate ... no interpolation */
+ NULL, /* drag normal ... no interpolation */
+ 0.0); /* drag ... no interpolation */
+}
+
+/*
+ * send object rotation to verse server
+ */
+void send_verse_object_rotation(VNode *vnode)
+{
+ VNQuat32 quat;
+ float q[4] = {cos(-M_PI/4), -sin(-M_PI/4), 0, 0}, v[4], tmp[4];
+
+ /* inverse transformation to transformation in function cb_o_transform_rot_real32 */
+ QuatMul(v, ((VObjectData*)vnode->data)->quat, q);
+ q[1]= sin(-M_PI/4);
+ QuatMul(tmp, q, v);
+
+ quat.x = tmp[1];
+ quat.y = tmp[2];
+ quat.z = tmp[3];
+ quat.w = tmp[0];
+
+ ((VObjectData*)vnode->data)->flag &= ~ROT_SEND_READY;
+
+ verse_send_o_transform_rot_real32(
+ vnode->id, /* node id */
+ 0, /* time_s ... no interpolation */
+ 0, /* time_f ... no interpolation */
+ &quat,
+ NULL, /* speed ... no interpolation */
+ NULL, /* accelerate ... no interpolation */
+ NULL, /* drag normal ... no interpolation */
+ 0.0); /* drag ... no interpolation */
+}
+
+/*
+ * send object rotation to verse server
+ */
+void send_verse_object_scale(VNode *vnode)
+{
+ float tmp;
+
+ ((VObjectData*)vnode->data)->flag &= ~SCALE_SEND_READY;
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = ((VObjectData*)vnode->data)->scale[1];
+ ((VObjectData*)vnode->data)->scale[1] = ((VObjectData*)vnode->data)->scale[2];
+ ((VObjectData*)vnode->data)->scale[2] = tmp;
+
+ verse_send_o_transform_scale_real32(
+ vnode->id,
+ ((VObjectData*)vnode->data)->scale[0],
+ ((VObjectData*)vnode->data)->scale[1],
+ ((VObjectData*)vnode->data)->scale[2]);
+}
+
+/*
+ * send VerseLink to verse server
+ */
+void send_verse_link(VLink *vlink)
+{
+ verse_session_set(vlink->session->vsession);
+
+ verse_send_o_link_set(
+ vlink->source->id,
+ vlink->id,
+ vlink->target->id,
+ vlink->label,
+ vlink->target_id);
+}
+
+/*
+ * set up pointer at VerseLink of target node (geometry node, material node, etc.)
+ */
+static void set_target_node_link_pointer(VNode *vnode, VLink *vlink)
+{
+ switch (vnode->type) {
+ case V_NT_GEOMETRY:
+ ((VGeomData*)vnode->data)->vlink = vlink;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * free VerseLink and it's label
+ */
+static void free_verse_link_data(VLink *vlink)
+{
+ MEM_freeN(vlink->label);
+}
+
+/*
+ * create new VerseLink
+ */
+VLink *create_verse_link(
+ VerseSession *session,
+ VNode *source,
+ VNode *target,
+ uint16 link_id,
+ uint32 target_id,
+ const char *label)
+{
+ struct VLink *vlink;
+
+ vlink = (VLink*)MEM_mallocN(sizeof(VLink), "VerseLink");
+ vlink->session = session;
+ vlink->source = source;
+ vlink->target = target;
+ vlink->id = link_id;
+ vlink->target_id = target_id;
+
+ set_target_node_link_pointer(target, vlink);
+
+ vlink->label = (char*)MEM_mallocN(sizeof(char)*(strlen(label)+1), "VerseLink label");
+ vlink->label[0] = '\0';
+ strcat(vlink->label, label);
+
+ vlink->flag = 0;
+
+ vlink->post_link_set = post_link_set;
+ vlink->post_link_destroy = post_link_destroy;
+
+ return vlink;
+}
+
+/*
+ * free ObjectData (links, links in queue and lables of links)
+ */
+void free_object_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VObjectData *obj = (VObjectData*)vnode->data;
+ struct VLink *vlink;
+ struct VMethodGroup *vmg;
+
+ if(!obj) return;
+
+ /* free all labels of links in dlist */
+ vlink = obj->links.lb.first;
+ while(vlink){
+ free_verse_link_data(vlink);
+ vlink = vlink->next;
+ }
+
+ /* free all labels of links waiting in queue */
+ vlink = obj->queue.first;
+ while(vlink){
+ free_verse_link_data(vlink);
+ vlink = vlink->next;
+ }
+ /* free dynamic list and sendig queue of links */
+ BLI_dlist_destroy(&(obj->links));
+ BLI_freelistN(&(obj->queue));
+
+ /* free method groups and their methods */
+ for(vmg = vnode->methodgroups.first; vmg; vmg= vmg->next) {
+ free_verse_methodgroup(vmg);
+ }
+ BLI_freelistN(&(vnode->methodgroups));
+
+ /* free constraint between VerseNode and Object */
+ obj->post_object_free_constraint(vnode);
+
+ /* unsubscribe from receiving changes of transformation matrix */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_o_transform_unsubscribe(vnode->id, 0);
+}
+
+/*
+ * create new object data
+ */
+VObjectData *create_object_data(void)
+{
+ VObjectData *obj;
+
+ obj = (VObjectData*)MEM_mallocN(sizeof(VObjectData), "VerseObjectData");
+ obj->object = NULL;
+ BLI_dlist_init(&(obj->links));
+ obj->queue.first = obj->queue.last = NULL;
+ obj->flag = 0;
+
+ /* transformation matrix */
+ obj->pos[0] = obj->pos[1] = obj->pos[2] = 0.0;
+ obj->quat[0] = obj->quat[1] = obj->quat[2] = 0.0; obj->quat[3] = 1;
+ obj->scale[0] = obj->scale[1] = obj->scale[2] = 1.0;
+
+ /* transformation flags */
+ obj->flag |= POS_SEND_READY;
+ obj->flag |= ROT_SEND_READY;
+ obj->flag |= SCALE_SEND_READY;
+
+ /* set up pointers at post callback functions */
+/* obj->post_transform = post_transform;*/
+ obj->post_transform_pos = post_transform_pos;
+ obj->post_transform_rot = post_transform_rot;
+ obj->post_transform_scale = post_transform_scale;
+ obj->post_object_free_constraint = post_object_free_constraint;
+
+ return obj;
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_pos_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 time_s,
+ uint32 time_f,
+ const real32 *pos,
+ const real32 *speed,
+ const real32 *accelerate,
+ const real32 *drag_normal,
+ real32 drag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ float vec[3], dt, tmp;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= POS_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & POS_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY;
+ return;
+ }
+
+ dt = time_s + time_f/(0xffff);
+
+ if(pos) {
+ vec[0] = pos[0];
+ vec[1] = pos[1];
+ vec[2] = pos[2];
+ }
+ else {
+ vec[0] = 0.0f;
+ vec[1] = 0.0f;
+ vec[2] = 0.0f;
+ }
+
+ if(speed) {
+ vec[0] += speed[0]*dt;
+ vec[1] += speed[1]*dt;
+ vec[2] += speed[2]*dt;
+ }
+
+ if(accelerate) {
+ vec[0] += accelerate[0]*dt*dt/2;
+ vec[1] += accelerate[1]*dt*dt/2;
+ vec[2] += accelerate[2]*dt*dt/2;
+ }
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = vec[1];
+ vec[1] = -vec[2];
+ vec[2] = tmp;
+
+ if( (((VObjectData*)vnode->data)->pos[0] != vec[0]) ||
+ (((VObjectData*)vnode->data)->pos[1] != vec[1]) ||
+ (((VObjectData*)vnode->data)->pos[2] != vec[2]))
+ {
+ ((VObjectData*)vnode->data)->pos[0] = vec[0];
+ ((VObjectData*)vnode->data)->pos[1] = vec[1];
+ ((VObjectData*)vnode->data)->pos[2] = vec[2];
+
+ ((VObjectData*)vnode->data)->post_transform_pos(vnode);
+ }
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_rot_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 time_s,
+ uint32 time_f,
+ const VNQuat32 *quat,
+ const VNQuat32 *speed,
+ const VNQuat32 *accelerate,
+ const VNQuat32 *drag_normal,
+ real32 drag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ float temp[4]={0, 0, 0, 0}, v[4], dt; /* temporary quaternions */
+ float q[4]={cos(M_PI/4), -sin(M_PI/4), 0, 0}; /* conjugate quaternion (represents rotation
+ around x-axis +90 degrees) */
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & ROT_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY;
+ return;
+ }
+
+ dt = time_s + time_f/(0xffff);
+
+ if(quat) {
+ temp[1] = quat->x;
+ temp[2] = quat->y;
+ temp[3] = quat->z;
+ temp[0] = quat->w;
+ }
+
+ if(speed) {
+ temp[1] += speed->x*dt;
+ temp[2] += speed->y*dt;
+ temp[3] += speed->z*dt;
+ temp[0] += speed->w*dt;
+ }
+
+ if(accelerate) {
+ temp[1] += accelerate->x*dt*dt/2;
+ temp[2] += accelerate->y*dt*dt/2;
+ temp[3] += accelerate->z*dt*dt/2;
+ temp[0] += accelerate->w*dt*dt/2;
+ }
+
+ /* following matematical operation transform rotation:
+ *
+ * v' = quaternion * v * conjugate_quaternion
+ *
+ *, where v is original representation of rotation */
+
+ QuatMul(v, temp, q);
+ q[1]= sin(M_PI/4); /* normal quaternion */
+ QuatMul(temp, q, v);
+
+ if( (((VObjectData*)vnode->data)->quat[0] != temp[0]) ||
+ (((VObjectData*)vnode->data)->quat[1] != temp[1]) ||
+ (((VObjectData*)vnode->data)->quat[2] != temp[2]) ||
+ (((VObjectData*)vnode->data)->quat[3] != temp[3]))
+ {
+ QUATCOPY(((VObjectData*)vnode->data)->quat, temp);
+
+ ((VObjectData*)vnode->data)->post_transform_rot(vnode);
+ }
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_scale_real32(
+ void *user_data,
+ VNodeID node_id,
+ real32 scale_x,
+ real32 scale_y,
+ real32 scale_z)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ real32 tmp;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & SCALE_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY;
+ return;
+ }
+
+ /* flip axis (verse spec) */
+ tmp = scale_y;
+ scale_y = scale_z;
+ scale_z = tmp;
+
+ /* z and y axis are flipped here too */
+ if( (((VObjectData*)vnode->data)->scale[0] != scale_x) ||
+ (((VObjectData*)vnode->data)->scale[1] != scale_y) ||
+ (((VObjectData*)vnode->data)->scale[2] != scale_z))
+ {
+ ((VObjectData*)vnode->data)->scale[0] = scale_x;
+ ((VObjectData*)vnode->data)->scale[1] = scale_y;
+ ((VObjectData*)vnode->data)->scale[2] = scale_z;
+
+ ((VObjectData*)vnode->data)->post_transform_scale(vnode);
+ }
+}
+
+/*
+ * callback function: link between object node and some other node was created
+ */
+static void cb_o_link_set(
+ void *user_data,
+ VNodeID node_id,
+ uint16 link_id,
+ VNodeID link,
+ const char *label,
+ uint32 target_id)
+{
+ struct VLink *vlink;
+ struct VNode *source;
+ struct VNode *target;
+
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+
+ if(!session) return;
+
+ source = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ target = BLI_dlist_find_link(&(session->nodes), (unsigned int)link);
+
+ if(!(source && target)) return;
+
+ vlink = ((VObjectData*)source->data)->queue.first;
+
+ if(vlink && (vlink->source==source) && (vlink->target==target)) {
+ /* remove VerseLink from sending queue */
+ BLI_remlink(&(((VObjectData*)source->data)->queue), vlink);
+ /* add VerseLink to dynamic list of VerseLinks */
+ BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id);
+ /* send next link from sending queue */
+ if(((VObjectData*)source->data)->queue.first)
+ send_verse_link(((VObjectData*)source->data)->queue.first);
+ /* set up VerseLink variables */
+ vlink->flag = 0;
+ vlink->id = link_id;
+ vlink->target_id = target_id;
+ }
+ else {
+ /* create new VerseLink */
+ vlink = create_verse_link(session, source, target, link_id, target_id, label);
+ /* add VerseLink to dynamic list of VerseLinks */
+ BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id);
+ }
+
+ target->counter++;
+
+ vlink->post_link_set(vlink);
+}
+
+/*
+ * callback function: destroy link between two VerseNodes
+ */
+static void cb_o_link_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 link_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLink *vlink;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vlink = BLI_dlist_find_link(&(((VObjectData*)vnode->data)->links), link_id);
+
+ if(vlink) {
+ vlink->target->counter--;
+ free_verse_link_data(vlink);
+ BLI_dlist_free_item(&(((VObjectData*)vnode->data)->links), link_id);
+ }
+
+ vlink->post_link_destroy(vlink);
+}
+
+void set_object_callbacks(void)
+{
+ /* position of object was changed */
+ verse_callback_set(verse_send_o_transform_pos_real32, cb_o_transform_pos_real32, NULL);
+ /* rotation of object was changed */
+ verse_callback_set(verse_send_o_transform_rot_real32, cb_o_transform_rot_real32, NULL);
+ /* size of object was changed */
+ verse_callback_set(verse_send_o_transform_scale_real32, cb_o_transform_scale_real32, NULL);
+ /* new link between nodes was created */
+ verse_callback_set(verse_send_o_link_set, cb_o_link_set, NULL);
+ /* link between nodes was destroyed */
+ verse_callback_set(verse_send_o_link_destroy, cb_o_link_destroy, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_session.c b/source/blender/blenkernel/intern/verse_session.c
new file mode 100644
index 00000000000..64d6b9885fe
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_session.c
@@ -0,0 +1,480 @@
+/**
+ * $Id: verse_session.c 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h" /* temp */
+#include "DNA_listBase.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_screen.h"
+#include "BIF_verse.h"
+
+#include "BKE_global.h"
+#include "BKE_verse.h"
+
+struct ListBase session_list={NULL, NULL};
+struct ListBase server_list={NULL, NULL};
+
+static int cb_ping_registered = 0;
+
+/* list of static function prototypes */
+static void cb_connect_terminate(const char *address, const char *bye);
+static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id);
+static void set_all_callbacks(void);
+static void free_verse_session_data(struct VerseSession *session);
+static void add_verse_server(VMSServer *server);
+static void check_connection_state(struct VerseServer *server);
+
+static void check_connection_state(struct VerseServer *server)
+{
+ struct VerseSession *session;
+ session = session_list.first;
+ while(session) {
+ if(strcmp(server->ip,session->address)==0) {
+ server->flag = session->flag;
+ return;
+ }
+ session = session->next;
+ }
+}
+/*
+ * add verse server to server_list. Prevents duplicate
+ * entries
+ */
+static void add_verse_server(VMSServer *server)
+{
+ struct VerseServer *iter, *niter;
+ VerseServer *newserver;
+ const char *name = verse_ms_field_value(server, "DE");
+ iter = server_list.first;
+
+ while(iter) {
+ niter = iter->next;
+ if(strcmp(iter->ip, server->ip)==0) {
+ return;
+ }
+ iter = niter;
+ }
+
+ newserver = (VerseServer *)MEM_mallocN(sizeof(VerseServer), "VerseServer");
+ newserver->ip = (char *)MEM_mallocN(sizeof(char)*(strlen(server->ip)+1), "VerseServer ip");
+ strcpy(newserver->ip, server->ip);
+
+ if(name) {
+ newserver->name = (char *)MEM_mallocN(sizeof(char)*(strlen(name)+strlen(newserver->ip)+4), "VerseServer name");
+ strcpy(newserver->name, name);
+ strcat(newserver->name, " (");
+ strcat(newserver->name, newserver->ip);
+ strcat(newserver->name, ")");
+ }
+
+ newserver->flag = 0;
+ check_connection_state(newserver);
+
+ printf("Adding new verse server: %s at %s\n", newserver->name, newserver->ip);
+
+ BLI_addtail(&server_list, newserver);
+ post_server_add();
+}
+
+/*
+ * callback function for ping
+ */
+static void cb_ping(void *user, const char *address, const char *message)
+{
+ VMSServer **servers = verse_ms_list_parse(message);
+ if(servers != NULL)
+ {
+ int i;
+
+ for(i = 0; servers[i] != NULL; i++)
+ add_verse_server(servers[i]);
+
+ free(servers);
+ }
+}
+
+/*
+ * callback function for connection terminated
+ */
+static void cb_connect_terminate(const char *address, const char *bye)
+{
+ VerseSession *session = (VerseSession*)current_verse_session();
+
+ if(!session) return;
+
+ /* remove session from list of session */
+ BLI_remlink(&session_list, session);
+ /* do post connect operations */
+ session->post_connect_terminated(session);
+ /* free session data */
+ free_verse_session_data(session);
+ /* free session */
+ MEM_freeN(session);
+}
+
+/*
+ * callback function for accepted connection to verse server
+ */
+static void cb_connect_accept(
+ void *user_data,
+ uint32 avatar,
+ void *address,
+ void *connection,
+ const uint8 *host_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VerseServer *server = server_list.first;
+ uint32 i, mask=0;
+
+ if(!session) return;
+
+ session->flag |= VERSE_CONNECTED;
+ session->flag &= ~VERSE_CONNECTING;
+
+ while(server) {
+ if(strcmp(session->address, server->ip)==0) {
+ server->flag |= VERSE_CONNECTED;
+ server->flag &= ~VERSE_CONNECTING;
+ server->session = session;
+ break;
+ }
+ server = server->next;
+ }
+
+ printf("\tBlender is connected to verse server: %s\n", (char*)address);
+ printf("\tVerseSession->counter: %d\n", session->counter);
+
+ session->avatar = avatar;
+
+ session->post_connect_accept(session);
+
+ for(i = 0; i < V_NT_NUM_TYPES; i++)
+ mask = mask | (1 << i);
+ verse_send_node_index_subscribe(mask);
+ verse_send_node_subscribe(session->avatar); /* subscribe to avatar node, as well */
+
+ /* create our own method group and method */
+ /*verse_send_o_method_group_create(session->avatar, ~0, "tawk-client");*/
+}
+
+/*
+ * set up all callbacks for sessions
+ */
+void set_verse_session_callbacks(void)
+{
+ /* connection */
+ verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL);
+ /* connection was terminated */
+ verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL);
+
+}
+
+/*
+ * set all callbacks used in Blender
+ */
+static void set_all_callbacks(void)
+{
+ /* set up all callbacks for sessions */
+ set_verse_session_callbacks();
+
+ /* set up callbacks for nodes */
+ set_node_callbacks();
+
+ /* set up all callbacks for object nodes */
+ set_object_callbacks();
+
+ /* set up all callbacks for geometry nodes */
+ set_geometry_callbacks();
+
+ /* set up all callbacks for bitmap nodes */
+ set_bitmap_callbacks();
+
+ /* set up all callbacks for method groups and methods */
+ set_method_callbacks();
+}
+
+/*
+ * this function sends and receive all packets for all sessions
+ */
+void b_verse_update(void)
+{
+ VerseSession *session, *next_session;
+
+ session = session_list.first;
+ while(session){
+ next_session = session->next;
+ verse_session_set(session->vsession);
+ if((session->flag & VERSE_CONNECTED) || (session->flag & VERSE_CONNECTING)) {
+ verse_callback_update(10);
+ session->post_connect_update(session);
+ }
+ session = next_session;
+ }
+ if(cb_ping_registered>0) {
+ verse_callback_update(10);
+ }
+}
+
+/*
+ * returns VerseSession coresponding to vsession pointer
+ */
+VerseSession *versesession_from_vsession(VSession *vsession)
+{
+ struct VerseSession *session;
+
+ session = session_list.first;
+
+ while(session) {
+ if(session->vsession==vsession) return session;
+ session = session->next;
+ }
+
+ return session;
+}
+
+/*
+ * returns pointer at current VerseSession
+ */
+VerseSession *current_verse_session(void)
+{
+ struct VerseSession *session;
+ VSession vsession = verse_session_get();
+
+ session = session_list.first;
+
+ while(session){
+ if(session->vsession == vsession)
+ return session;
+ session = session->next;
+ }
+
+ printf("error: non-existing SESSION occured!\n");
+ return NULL;
+}
+
+/*
+ * free VerseSession
+ */
+static void free_verse_session_data(VerseSession *session)
+{
+ struct VNode *vnode;
+
+ /* free data of all nodes */
+ vnode = session->nodes.lb.first;
+ while(vnode){
+ free_verse_node_data(vnode);
+ vnode = vnode->next;
+ }
+
+ /* free data of nodes waiting in queue */
+ vnode = session->queue.first;
+ while(vnode){
+ free_verse_node_data(vnode);
+ vnode = vnode->next;
+ }
+
+ /* free all VerseNodes */
+ BLI_dlist_destroy(&(session->nodes));
+ /* free all VerseNodes waiting in queque */
+ BLI_freelistN(&(session->queue));
+
+ /* free name of verse host for this session */
+ MEM_freeN(session->address);
+}
+
+/*
+ * free VerseSession
+ */
+void free_verse_session(VerseSession *session)
+{
+ /* remove session from session list*/
+ BLI_remlink(&session_list, session);
+ /* do post terminated operations */
+ session->post_connect_terminated(session);
+ /* free session data (nodes, layers) */
+ free_verse_session_data(session);
+ /* free session */
+ MEM_freeN(session);
+}
+
+/*
+ * create new verse session and return coresponding data structure
+ */
+VerseSession *create_verse_session(
+ const char *name,
+ const char *pass,
+ const char *address,
+ uint8 *expected_key)
+{
+ struct VerseSession *session;
+ VSession *vsession;
+
+ vsession = verse_send_connect(name, pass, address, expected_key);
+
+ if(!vsession) return NULL;
+
+ session = (VerseSession*)MEM_mallocN(sizeof(VerseSession), "VerseSession");
+
+ session->flag = VERSE_CONNECTING;
+
+ session->vsession = vsession;
+ session->avatar = -1;
+
+ session->address = (char*)MEM_mallocN(sizeof(char)*(strlen(address)+1),"session adress name");
+ strcpy(session->address, address);
+
+ session->connection = NULL;
+ session->host_id = NULL;
+ session->counter = 0;
+
+ /* initialize dynamic list of nodes and node queue */
+ BLI_dlist_init(&(session->nodes));
+ session->queue.first = session->queue.last = NULL;
+
+ /* set up all client dependent functions */
+ session->post_connect_accept = post_connect_accept;
+ session->post_connect_terminated = post_connect_terminated;
+ session->post_connect_update = post_connect_update;
+
+ post_server_add();
+
+ return session;
+}
+
+/*
+ * end verse session and free all session data
+ */
+void end_verse_session(VerseSession *session)
+{
+ /* send terminate command to verse server */
+ verse_send_connect_terminate(session->address, "blender: bye bye");
+ /* update callbacks */
+ verse_callback_update(1000);
+ /* send destroy session command to verse server */
+ verse_session_destroy(session->vsession);
+ /* set up flag of verse session */
+ session->flag &= ~VERSE_CONNECTED;
+ /* do post connect operations */
+ session->post_connect_terminated(session);
+ /* free structure of verse session */
+ free_verse_session(session);
+}
+
+void free_all_servers(void)
+{
+ VerseServer *server, *nextserver;
+
+ server = server_list.first;
+
+ while(server) {
+ nextserver = server->next;
+ BLI_remlink(&server_list, server);
+ MEM_freeN(server->name);
+ MEM_freeN(server->ip);
+ MEM_freeN(server);
+ server = nextserver;
+ }
+
+ BLI_freelistN(&server_list);
+}
+
+/*
+ * end connection to all verse hosts (servers) ... free all VerseSessions
+ * free all VerseServers
+ */
+void end_all_verse_sessions(void)
+{
+ VerseSession *session,*nextsession;
+
+ session = session_list.first;
+
+ while(session) {
+ nextsession= session->next;
+ end_verse_session(session);
+ /* end next session */
+ session = nextsession;
+ }
+
+ BLI_freelistN(&session_list);
+
+ free_all_servers();
+}
+
+/*
+ * do a get from ms
+ */
+void b_verse_ms_get(void)
+{
+ if(cb_ping_registered==0) {
+ /* handle ping messages (for master server) */
+ verse_callback_set(verse_send_ping, cb_ping, NULL);
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
+ cb_ping_registered++;
+ }
+ free_all_servers();
+
+ verse_ms_get_send(U.versemaster, VERSE_MS_FIELD_DESCRIPTION, NULL);
+ verse_callback_update(10);
+}
+
+/*
+ * connect to verse host, set up all callbacks, create session
+ */
+void b_verse_connect(char *address)
+{
+ VerseSession *session = NULL;
+
+ /* if no session was created before, then set up all callbacks */
+ if((session_list.first==NULL) && (session_list.last==NULL))
+ set_all_callbacks();
+
+ /* create new session */
+ if(address)
+ session = create_verse_session("Blender", "pass", address, NULL);
+
+ if(session) {
+ /* add new session to the list of sessions */
+ BLI_addtail(&session_list, session);
+
+ /* add verse handler if this is first session */
+ if(session_list.first == session_list.last)
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
+
+ }
+}
+
+#endif
diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h
deleted file mode 100644
index 325798f325f..00000000000
--- a/source/blender/blenkernel/nla_private.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Joshua Leung (full recode)
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef NLA_PRIVATE
-#define NLA_PRIVATE
-
-/* --------------- NLA Evaluation DataTypes ----------------------- */
-
-/* used for list of strips to accumulate at current time */
-typedef struct NlaEvalStrip {
- struct NlaEvalStrip *next, *prev;
-
- NlaTrack *track; /* track that this strip belongs to */
- NlaStrip *strip; /* strip that's being used */
-
- short track_index; /* the index of the track within the list */
- short strip_mode; /* which end of the strip are we looking at */
-
- float strip_time; /* time at which which strip is being evaluated */
-} NlaEvalStrip;
-
-/* NlaEvalStrip->strip_mode */
-enum {
- /* standard evaluation */
- NES_TIME_BEFORE = -1,
- NES_TIME_WITHIN,
- NES_TIME_AFTER,
-
- /* transition-strip evaluations */
- NES_TIME_TRANSITION_START,
- NES_TIME_TRANSITION_END,
-} eNlaEvalStrip_StripMode;
-
-
-/* temp channel for accumulating data from NLA (avoids needing to clear all values first) */
-// TODO: maybe this will be used as the 'cache' stuff needed for editable values too?
-typedef struct NlaEvalChannel {
- struct NlaEvalChannel *next, *prev;
-
- PointerRNA ptr; /* pointer to struct containing property to use */
- PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */
- int index; /* array index (where applicable) */
-
- float value; /* value of this channel */
-} NlaEvalChannel;
-
-/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */
-
-/* convert from strip time <-> global time */
-float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
-
-/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
-/* these functions are only defined here to avoid problems with the order in which they get defined... */
-
-NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime);
-void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes);
-void nladata_flush_channels(ListBase *channels);
-
-#endif // NLA_PRIVATE
diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h
index 787579250ed..bcc2ac3deec 100644
--- a/source/blender/blenlib/BLI_arithb.h
+++ b/source/blender/blenlib/BLI_arithb.h
@@ -75,6 +75,7 @@ void CalcCent3f(float *cent, float *v1, float *v2, float *v3);
void CalcCent4f(float *cent, float *v1, float *v2, float *v3, float *v4);
void Crossf(float *c, float *a, float *b);
+void Crossd(double *c, double *a, double *b);
void Projf(float *c, float *v1, float *v2);
float Inpf(float *v1, float *v2);
@@ -82,6 +83,7 @@ float Inp2f(float *v1, float *v2);
float Normalize(float *n);
float Normalize2(float *n);
+double Normalize_d(double *n);
float Sqrt3f(float f);
double Sqrt3d(double d);
@@ -267,6 +269,7 @@ void Vec2Subf(float *v, float *v1, float *v2);
void Vec2Copyf(float *v1, float *v2);
void Vec2Lerpf(float *target, float *a, float *b, float t);
+void AxisAngleToQuatd(float *q, float *axis, double angle);
void AxisAngleToQuat(float *q, float *axis, float angle);
void RotationBetweenVectorsToQuat(float *q, float v1[3], float v2[3]);
void vectoquat(float *vec, short axis, short upflag, float *q);
diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h
index 56a20d8462a..60b7f74954d 100644
--- a/source/blender/blenlib/BLI_editVert.h
+++ b/source/blender/blenlib/BLI_editVert.h
@@ -42,6 +42,7 @@
struct DerivedMesh;
struct RetopoPaintData;
+struct BLI_mempool;
/* note; changing this also might affect the undo copy in editmesh.c */
typedef struct EditVert
@@ -154,6 +155,8 @@ typedef struct EditMesh
HashEdge *hashedgetab;
/* this is for the editmesh_fastmalloc */
+ struct BLI_mempool *vertpool, *edgepool, *facepool;
+
EditVert *allverts, *curvert;
EditEdge *alledges, *curedge;
EditFace *allfaces, *curface;
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 80cd507520c..d835ed18476 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
+#include "BLI_mempool.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -63,6 +64,7 @@ struct GHash {
GHashCmpFP cmpfp;
Entry **buckets;
+ struct BLI_mempool *entrypool;
int nbuckets, nentries, cursize;
};
@@ -72,7 +74,8 @@ GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp) {
GHash *gh= MEM_mallocN(sizeof(*gh), "GHash");
gh->hashfp= hashfp;
gh->cmpfp= cmpfp;
-
+ gh->entrypool = BLI_mempool_create(sizeof(Entry), 1, 32);
+
gh->cursize= 0;
gh->nentries= 0;
gh->nbuckets= hashsizes[gh->cursize];
@@ -85,7 +88,7 @@ GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp) {
void BLI_ghash_insert(GHash *gh, void *key, void *val) {
unsigned int hash= gh->hashfp(key)%gh->nbuckets;
- Entry *e= malloc(sizeof(*e));
+ Entry *e= BLI_mempool_alloc(gh->entrypool);
e->key= key;
e->val= val;
@@ -141,7 +144,7 @@ int BLI_ghash_remove (GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFr
if (keyfreefp) keyfreefp(e->key);
if (valfreefp) valfreefp(e->val);
- free(e);
+ BLI_mempool_free(gh->entrypool, e);
e= n;
@@ -185,13 +188,13 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef
if (keyfreefp) keyfreefp(e->key);
if (valfreefp) valfreefp(e->val);
- free(e);
-
+
e= n;
}
}
free(gh->buckets);
+ BLI_mempool_destroy(gh->entrypool);
gh->buckets = 0;
gh->nentries = 0;
gh->nbuckets = 0;
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 7ac7b8b1791..493bbba3567 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -65,7 +65,8 @@ BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk)
pool->chunks.first = pool->chunks.last = NULL;
maxchunks = tote / pchunk;
-
+ if (maxchunks==0) maxchunks = 1;
+
/*allocate the actual chunks*/
for(i=0; i < maxchunks; i++){
BLI_mempool_chunk *mpchunk = MEM_mallocN(sizeof(BLI_mempool_chunk), "BLI_Mempool Chunk");
@@ -85,6 +86,7 @@ BLI_mempool *BLI_mempool_create(int esize, int tote, int pchunk)
/*set the end of this chunks memoryy to the new tail for next iteration*/
lasttail = curnode;
}
+
/*terminate the list*/
curnode->next = NULL;
return pool;
diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c
index f111e94a141..0c7db0331e1 100644
--- a/source/blender/blenlib/intern/arithb.c
+++ b/source/blender/blenlib/intern/arithb.c
@@ -111,6 +111,26 @@ float Normalize(float *n)
return d;
}
+/*original function from shadeoutput.c*/
+double Normalize_d(double *n)
+{
+ double d;
+
+ d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+
+ if(d>0.00000000000000001) {
+ d= sqrt(d);
+
+ n[0]/=d;
+ n[1]/=d;
+ n[2]/=d;
+ } else {
+ n[0]=n[1]=n[2]= 0.0;
+ d= 0.0;
+ }
+ return d;
+}
+
void Crossf(float *c, float *a, float *b)
{
c[0] = a[1] * b[2] - a[2] * b[1];
@@ -118,6 +138,13 @@ void Crossf(float *c, float *a, float *b)
c[2] = a[0] * b[1] - a[1] * b[0];
}
+void Crossd(double *c, double *a, double *b)
+{
+ c[0] = a[1] * b[2] - a[2] * b[1];
+ c[1] = a[2] * b[0] - a[0] * b[2];
+ c[2] = a[0] * b[1] - a[1] * b[0];
+}
+
/* Inpf returns the dot product, also called the scalar product and inner product */
float Inpf( float *v1, float *v2)
{
@@ -845,7 +872,7 @@ void Mat4MulVec( float mat[][4], int *vec)
vec[2]=(int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]);
}
-void Mat4MulVecfl( float mat[][4], float *vec)
+void Mat4MulVecfl(float mat[][4], float *vec)
{
float x,y;
@@ -1404,6 +1431,28 @@ void AxisAngleToQuat(float *q, float *axis, float angle)
q[3] = nor[2] * si;
}
+void AxisAngleToQuatd(float *q, float *axis, double angle)
+{
+ double nor[3];
+ double si, l;
+
+ nor[0] = axis[0];
+ nor[1] = axis[1];
+ nor[2] = axis[2];
+
+ l = sqrt(nor[0]*nor[0] + nor[1]*nor[1] + nor[2]*nor[2]);
+ nor[0] /= l;
+ nor[1] /= l;
+ nor[2] /= l;
+
+ angle /= 2;
+ si = sin(angle);
+ q[0] = cos(angle);
+ q[1] = nor[0] * si;
+ q[2] = nor[1] * si;
+ q[3] = nor[2] * si;
+}
+
void vectoquat(float *vec, short axis, short upflag, float *q)
{
float q2[4], nor[3], *fp, mat[3][3], angle, si, co, x2, y2, z2, len1;
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 603c85655d7..8976059d153 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -62,20 +62,19 @@ struct EdgeHash {
/***/
EdgeHash *BLI_edgehash_new(void) {
- EdgeHash *eh= MEM_mallocN(sizeof(*eh), "EdgeHash");
+ EdgeHash *eh= MEM_callocN(sizeof(*eh), "EdgeHash");
eh->cursize= 0;
eh->nentries= 0;
eh->nbuckets= hashsizes[eh->cursize];
- eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets));
- memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets));
+ eh->buckets= MEM_callocN(eh->nbuckets*sizeof(*eh->buckets), "eh buckets 2");
return eh;
}
void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) {
unsigned int hash;
- Entry *e= malloc(sizeof(*e));
+ Entry *e= MEM_callocN(sizeof(*e), "edgehash e");
if (v1<v0) {
v0 ^= v1;
@@ -95,7 +94,7 @@ void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) {
int i, nold= eh->nbuckets;
eh->nbuckets= hashsizes[++eh->cursize];
- eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets));
+ eh->buckets= MEM_mallocN(eh->nbuckets*sizeof(*eh->buckets), "eh buckets");
memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets));
for (i=0; i<nold; i++) {
@@ -110,7 +109,7 @@ void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) {
}
}
- free(old);
+ MEM_freeN(old);
}
}
@@ -155,7 +154,7 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
Entry *n= e->next;
if (valfreefp) valfreefp(e->val);
- free(e);
+ MEM_freeN(e);
e= n;
}
@@ -168,7 +167,7 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
BLI_edgehash_clear(eh, valfreefp);
- free(eh->buckets);
+ MEM_freeN(eh->buckets);
MEM_freeN(eh);
}
@@ -182,7 +181,7 @@ struct EdgeHashIterator {
};
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) {
- EdgeHashIterator *ehi= malloc(sizeof(*ehi));
+ EdgeHashIterator *ehi= MEM_mallocN(sizeof(*ehi), "eh iter");
ehi->eh= eh;
ehi->curEntry= NULL;
ehi->curBucket= -1;
@@ -195,7 +194,7 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) {
return ehi;
}
void BLI_edgehashIterator_free(EdgeHashIterator *ehi) {
- free(ehi);
+ MEM_freeN(ehi);
}
void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, int *v0_r, int *v1_r) {
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 06092cc97d4..5cc9698f79a 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3118,6 +3118,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;
@@ -3144,6 +3164,7 @@ static void lib_link_mesh(FileData *fd, Main *main)
me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh);
lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
+ lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
if(me->mr && me->mr->levels.first)
lib_link_customdata_mtface(fd, me, &me->mr->fdata,
((MultiresLevel*)me->mr->levels.first)->totface);
@@ -3199,6 +3220,124 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count)
}
}
+
+void bmesh_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol)
+{
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ MFace *mf;
+ int i;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, i);
+ mf = me->mface + findex;
+
+ texpoly->tpage = texface->tpage;
+ texpoly->flag = texface->flag;
+ texpoly->transp = texface->transp;
+ texpoly->mode = texface->mode;
+ texpoly->tile = texface->tile;
+ texpoly->unwrap = texface->unwrap;
+
+ mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i);
+ mloopuv->uv[0] = texface->uv[0][0]; mloopuv->uv[1] = texface->uv[0][1]; mloopuv++;
+ mloopuv->uv[0] = texface->uv[1][0]; mloopuv->uv[1] = texface->uv[1][1]; mloopuv++;
+ mloopuv->uv[0] = texface->uv[2][0]; mloopuv->uv[1] = texface->uv[2][1]; mloopuv++;
+
+ if (mf->v4) {
+ mloopuv->uv[0] = texface->uv[3][0]; mloopuv->uv[1] = texface->uv[3][1]; mloopuv++;
+ }
+ }
+
+ for(i=0; i < numCol; i++){
+ mf = me->mface + findex;
+ mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i);
+ mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
+
+ mloopcol->r = mcol[0].r; mloopcol->g = mcol[0].g; mloopcol->b = mcol[0].b; mloopcol->a = mcol[0].a; mloopcol++;
+ mloopcol->r = mcol[1].r; mloopcol->g = mcol[1].g; mloopcol->b = mcol[1].b; mloopcol->a = mcol[1].a; mloopcol++;
+ mloopcol->r = mcol[2].r; mloopcol->g = mcol[2].g; mloopcol->b = mcol[2].b; mloopcol->a = mcol[2].a; mloopcol++;
+ if (mf->v4) {
+ mloopcol->r = mcol[3].r; mloopcol->g = mcol[3].g; mloopcol->b = mcol[3].b; mloopcol->a = mcol[3].a; mloopcol++;
+ }
+ }
+}
+
+static void convert_mfaces_to_mpolys(Mesh *mesh)
+{
+ MFace *mf;
+ MLoop *ml;
+ MPoly *mp;
+ MEdge *me;
+ EdgeHash *eh;
+ int numTex, numCol;
+ int i, j, totloop;
+
+ mesh->totpoly = mesh->totface;
+ mesh->mpoly = MEM_callocN(sizeof(MPoly)*mesh->totpoly, "mpoly converted");
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly);
+
+ numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE);
+ numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL);
+
+ totloop = 0;
+ mf = mesh->mface;
+ for (i=0; i<mesh->totface; i++, mf++) {
+ totloop += mf->v4 ? 4 : 3;
+ }
+
+ mesh->totloop = totloop;
+ mesh->mloop = MEM_callocN(sizeof(MLoop)*mesh->totloop, "mloop converted");
+
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop);
+ CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata,
+ mesh->totloop, mesh->totpoly);
+
+ eh = BLI_edgehash_new();
+
+ /*build edge hash*/
+ me = mesh->medge;
+ for (i=0; i<mesh->totedge; i++, me++) {
+ BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
+ }
+
+ j = 0; /*current loop index*/
+ ml = mesh->mloop;
+ mf = mesh->mface;
+ mp = mesh->mpoly;
+ for (i=0; i<mesh->totface; i++, mf++, mp++) {
+ mp->loopstart = j;
+
+ mp->totloop = mf->v4 ? 4 : 3;
+
+ mp->mat_nr = mf->mat_nr;
+ mp->flag = mf->flag;
+
+ #define ML(v1, v2) {ml->v = mf->##v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->##v1, mf->##v2)); ml++; j++;}
+
+ ML(v1, v2);
+ ML(v2, v3);
+ if (mf->v4) {
+ ML(v3, v4);
+ ML(v4, v1);
+ } else {
+ ML(v3, v1);
+ }
+
+ #undef ML
+
+ bmesh_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol);
+ }
+
+ /*BMESH_TODO now to deal with fgons*/
+
+ BLI_edgehash_free(eh, NULL);
+}
+
static void direct_link_mesh(FileData *fd, Mesh *mesh)
{
mesh->mat= newdataadr(fd, mesh->mat);
@@ -3207,12 +3346,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);
+
/* Partial-mesh visibility (do this before using totvert, totface, or totedge!) */
mesh->pv= newdataadr(fd, mesh->pv);
if(mesh->pv) {
@@ -3229,10 +3373,12 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
direct_link_customdata(fd, &mesh->vdata, mesh->pv ? mesh->pv->totvert : mesh->totvert);
direct_link_customdata(fd, &mesh->edata, mesh->pv ? mesh->pv->totedge : mesh->totedge);
direct_link_customdata(fd, &mesh->fdata, mesh->pv ? mesh->pv->totface : mesh->totface);
-
+ direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
+ direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
+
mesh->bb= NULL;
mesh->mselect = NULL;
- mesh->edit_mesh= NULL;
+ mesh->edit_btmesh= NULL;
/* Multires data */
mesh->mr= newdataadr(fd, mesh->mr);
@@ -3282,6 +3428,11 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
SWITCH_INT(tf->col[3]);
}
}
+
+ /*check if we need to convert mfaces to mpolys*/
+ if (mesh->totface && !mesh->totpoly) {
+ convert_mfaces_to_mpolys(mesh);
+ }
}
/* ************ READ LATTICE ***************** */
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index ebec409ddf4..c7cc1aacb18 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -1404,6 +1404,8 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
write_customdata(wd, mesh->totvert, &mesh->vdata, -1, 0);
write_customdata(wd, mesh->totedge, &mesh->edata, -1, 0);
write_customdata(wd, mesh->totface, &mesh->fdata, -1, 0);
+ write_customdata(wd, mesh->totloop, &mesh->ldata, -1, 0);
+ write_customdata(wd, mesh->totpoly, &mesh->pdata, -1, 0);
}
/* PMV data */
diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript
new file mode 100644
index 00000000000..d7cfa9ca942
--- /dev/null
+++ b/source/blender/bmesh/SConscript
@@ -0,0 +1,38 @@
+#!/usr/bin/python
+Import ('env')
+
+cflags=''
+"""
+sources = ['intern/bmesh_eulers.c']
+sources.append('intern/bmesh_mesh.c')
+sources.append('intern/bmesh_polygon.c')
+sources.append('intern/bmesh_structure.c')
+sources.append('intern/bmesh_marking.c')
+
+sources.append('intern/bmesh_construct.c')
+sources.append('intern/bmesh_interp.c')
+sources.append('intern/bmesh_filters.c')
+sources.append('intern/bmesh_iterators.c')
+sources.append('intern/bmesh_mods.c')
+sources.append('intern/bmesh_queries.c')
+sources.append('intern/bmesh_operators.c')
+"""
+#sources.append('api/BME_walkers.c')
+
+
+sources = env.Glob('intern/*.c')
+sources += env.Glob('operators/*.c')
+
+#sources += env.Glob('tools/*.c')
+
+incs = ['#/intern/guardedalloc']
+incs.append('../blenlib')
+incs.append('../makesdna')
+incs.append('../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..443e04c8711
--- /dev/null
+++ b/source/blender/bmesh/bmesh.h
@@ -0,0 +1,355 @@
+/**
+ * bmesh.h jan 2007
+ *
+ * BMesh API.
+ *
+ * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BMESH_H
+#define BMESH_H
+
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+#include "DNA_scene_types.h"
+#include "BLI_mempool.h"
+#include "BKE_customdata.h"
+
+/*
+short introduction:
+
+the bmesh structure is a boundary representation, supporting non-manifold
+locally modifiable topology. the API is designed to allow clean, maintainable
+code, that never (or almost never) directly inspects the underlying structure.
+
+The API includes iterators, including many useful topological iterators;
+walkers, which walk over a mesh, without the risk of hitting the recursion
+limit; operators, which are logical, reusable mesh modules; topological
+modification functions (like split face, join faces, etc), which are used for
+topological manipulations; and some (not yet finished) geometric utility
+functions.
+
+some definitions:
+
+tool flags: private flags for tools. each operator has it's own private
+ tool flag "layer", which it can use to flag elements.
+ tool flags are also used by various other parts of the api.
+header flags: stores persistent flags, such as selection state, hide state,
+ etc. be careful of touching these.
+*/
+
+/*forward declarations*/
+struct 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 flags/markings (sharp, seam, select, hidden, ect)
+ * 3: Unique ID in the bmesh.
+ * 4: some elements for internal record keeping.
+ *
+*/
+
+/*BMHeader->type*/
+#define BM_VERT 1
+#define BM_EDGE 2
+#define BM_FACE 4
+#define BM_LOOP 8
+#define BM_ALL (BM_VERT | BM_EDGE | BM_FACE | BM_LOOP)
+
+/*BMHeader->flag*/
+#define BM_SELECT (1<<0)
+
+#define BM_SEAM (1<<1)
+#define BM_FGON (1<<2)
+#define BM_HIDDEN (1<<3)
+#define BM_SHARP (1<<4)
+#define BM_SMOOTH (1<<5)
+#define BM_ACTIVE (1<<6)
+#define BM_NONORMCALC (1<<7)
+
+typedef struct BMHeader {
+ struct BMHeader *next, *prev;
+ int EID; /*Consider removing this/making it ifdeffed for debugging*/
+
+ /*don't confuse this with tool flags. this flag
+ member is what "header flag" means.*/
+ int flag;
+ int type;
+ int eflag1, eflag2; /*Flags used by eulers. Try and get rid of/minimize some of these*/
+
+ //this can only be used to store a temporary index. don't use it for anything else.
+ //use the BMINDEX_GET and BMINDEX_SET macros!!
+ int index;
+ struct BMFlagLayer *flags; /*Dynamically allocated block of flag layers for operators to use*/
+ void *data; /*customdata*/
+} BMHeader;
+
+typedef struct BMFlagLayer {
+ int f1;
+ short mask, pflag;
+} BMFlagLayer;
+
+#define BM_OVERLAP (1<<14) /*used by bmesh_verts_in_face*/
+#define BM_EDGEVERT (1<<15) /*used by bmesh_make_ngon*/
+
+/*
+ * BMNode
+ *
+ * Used for circular/linked list functions that form basis of
+ * adjacency system in BMesh. This should probably be hidden
+ * somewhere since tool authors never need to know about it.
+ *
+*/
+
+typedef struct BMNode {
+ struct BMNode *next, *prev;
+ void *data;
+} BMNode;
+
+typedef struct BMesh {
+ ListBase verts, edges, polys;
+ struct BLI_mempool *vpool;
+ struct BLI_mempool *epool;
+ struct BLI_mempool *lpool;
+ struct BLI_mempool *ppool;
+ struct BMVert **vtar;
+ struct BMEdge **edar;
+ struct BMLoop **lpar;
+ struct BMFace **plar;
+ int vtarlen, edarlen, lparlen, plarlen;
+ int totvert, totedge, totface, totloop;
+ int totvertsel, totedgesel, totfacesel;
+ int nextv, nexte, nextp, nextl;
+ struct CustomData vdata, edata, pdata, ldata;
+ int selectmode; /*now uses defines in DNA_scene_types.h*/
+ struct BLI_mempool *flagpool; /*memory pool for dynamically allocated flag layers*/
+ int stackdepth; /*current depth of operator stack*/
+ int totflags, walkers; /*total number of tool flag layers*/
+ ListBase errorstack;
+
+ /*active face pointer*/
+ struct BMFace *act_face;
+} BMesh;
+
+typedef struct BMVert {
+ struct BMHeader head;
+ float co[3];
+ float no[3];
+ struct BMEdge *edge;
+ void *tmp; /*what?*/
+ float bweight; /*please, someone just get rid of me...*/
+} BMVert;
+
+typedef struct BMEdge {
+ struct BMHeader head;
+ struct BMVert *v1, *v2;
+ struct BMNode d1, d2;
+ struct BMLoop *loop;
+ float crease, bweight; /*make these custom data.... no really, please....*/
+} BMEdge;
+
+typedef struct BMLoop {
+ struct BMHeader head;
+ struct BMNode radial;
+ struct BMVert *v;
+ struct BMEdge *e;
+ struct BMFace *f;
+} BMLoop;
+
+typedef struct BMFace {
+ struct BMHeader head;
+ struct BMLoop *loopbase;
+ int len;
+ float no[3];
+
+ /*custom data again*/
+ short mat_nr;
+} BMFace;
+
+/*stub */
+void bmesh_error(void);
+
+/*Mesh Level Ops */
+struct BMesh *BM_Make_Mesh(int allocsize[4]);
+BMesh *BM_Copy_Mesh(BMesh *bmold);
+void BM_Free_Mesh(struct BMesh *bm);
+
+/*frees mesh, but not actual BMesh struct*/
+void BM_Free_Mesh_Data(BMesh *bm);
+void BM_Compute_Normals(struct BMesh *bm);
+
+/*Construction*/
+struct BMVert *BM_Make_Vert(struct BMesh *bm, float co[3], struct BMVert *example);
+struct BMEdge *BM_Make_Edge(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge *example, int nodouble);
+struct BMFace *BM_Make_Quadtriangle(struct BMesh *bm, struct BMVert **verts, BMEdge **edges, int len, struct BMFace *example, int nodouble);
+
+/*more easier to use version of BM_Make_Quadtriangle.
+ creates edges if necassary.*/
+BMFace *BM_Make_QuadTri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3,
+ BMVert *v4, BMFace *example, int nodouble);
+
+/*makes an ngon from an unordered list of edges. v1 and v2 must be the verts
+defining edges[0], and define the winding of the new face.*/
+struct BMFace *BM_Make_Ngon(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge **edges, int len, int nodouble);
+
+/*stuff for dealing with header flags*/
+#define BM_TestHFlag(ele, f) (((BMHeader*)ele)->flag & (f))
+#define BM_SetHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag | (f))
+#define BM_ClearHFlag(ele, f) (((BMHeader*)ele)->flag = ((BMHeader*)ele)->flag & ~(f))
+
+/*stuff for setting indices in elements.*/
+#define BMINDEX_SET(ele, i) (((BMHeader*)ele)->index = i)
+#define BMINDEX_GET(ele) ((BMHeader*)ele)->index
+
+/*copies loop data from adjacent faces*/
+void BM_Face_CopyShared(BMesh *bm, BMFace *f);
+
+/*copies attributes, e.g. customdata, header flags, etc, from one element
+ to another of the same type.*/
+void BM_Copy_Attributes(struct BMesh *source_mesh, struct BMesh *target_mesh, void *source, void *target);
+
+/*remove tool flagged elements*/
+void BM_remove_tagged_faces(struct BMesh *bm, int flag);
+void BM_remove_tagged_edges(struct BMesh *bm, int flag);
+void BM_remove_tagged_verts(struct BMesh *bm, int flag);
+
+
+/*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.*/
+struct BMFace *BM_Join_Faces(struct BMesh *bm, struct BMFace *f1,
+ struct BMFace *f2, struct BMEdge *e);
+
+/*split a face along two vertices. returns the newly made face, and sets
+ the nl member to a loop in the newly created edge.*/
+struct BMFace *BM_Split_Face(struct BMesh *bm, struct BMFace *f,
+ struct BMVert *v1, struct BMVert *v2,
+ struct BMLoop **nl, struct BMEdge *example);
+
+/*dissolves a vert shared only by two edges*/
+void BM_Collapse_Vert(struct BMesh *bm, struct BMEdge *ke, struct BMVert *kv,
+ float fac);
+
+/*splits an edge. ne is set to the new edge created.*/
+struct BMVert *BM_Split_Edge(struct BMesh *bm, struct BMVert *v,
+ struct BMEdge *e, struct BMEdge **ne,
+ float percent);
+
+/*split an edge multiple times evenly*/
+struct BMVert *BM_Split_Edge_Multi(struct BMesh *bm, struct BMEdge *e,
+ int numcuts);
+
+/*connect two verts together, through a face they share. this function may
+ be removed in the future.*/
+BMEdge *BM_Connect_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf);
+
+
+/*updates a face normal*/
+void BM_Face_UpdateNormal(BMesh *bm, BMFace *f);
+
+/*updates face and vertex normals incident on an edge*/
+void BM_Edge_UpdateNormals(BMesh *bm, BMEdge *e);
+
+/*update a vert normal (but not the faces incident on it)*/
+void BM_Vert_UpdateNormal(BMesh *bm, BMVert *v);
+
+
+/*dissolves all faces around a vert, and removes it.*/
+int BM_Dissolve_Disk(BMesh *bm, BMVert *v);
+
+/*dissolves vert, in more situations then BM_Dissolve_Disk
+ (e.g. if the vert is part of a wire edge, etc).*/
+int BM_Dissolve_Vert(BMesh *bm, BMVert *v);
+
+
+/*Interpolation*/
+void BM_Data_Interp_From_Verts(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, float fac);
+void BM_Data_Facevert_Edgeinterp(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMVert *v, struct BMEdge *e1, float fac);
+//void bmesh_data_interp_from_face(struct BMesh *bm, struct BMFace *source, struct BMFace *target);
+void BM_add_data_layer(BMesh *em, CustomData *data, int type);
+void BM_free_data_layer(BMesh *em, CustomData *data, int type);
+
+
+/*computes the centroid of a face, using the center of the bounding box*/
+int BM_Compute_Face_Center(BMesh *bm, BMFace *f, float center[3]);
+void BM_SelectMode_Flush(BMesh *bm);
+
+/*convert an editmesh to a bmesh*/
+BMesh *editmesh_to_bmesh(struct EditMesh *em);
+
+/*initializes editmesh to bmesh operator, but doesn't execute.
+ this is used in situations where you need to get access to the
+ conversion operator's editmesh->bmesh mapping slot (e.g. if you
+ need to find the bmesh edge that corrusponds to a specific editmesh
+ edge).*/
+BMesh *init_editmesh_to_bmesh(struct EditMesh *em, struct BMOperator *op);
+
+/*converts a bmesh to an editmesh*/
+struct EditMesh *bmesh_to_editmesh(BMesh *bm);
+
+/*convert between bmesh and Mesh flags*/
+int BMFlags_To_MEFlags(void *element);
+
+/*convert between Mesh and bmesh flags
+ type must be BM_VERT/BM_EDGE/BM_FACE,
+ and represents the type of the element
+ parameter (the three defines map to
+ MVert, MEdge, and MPoly, respectively).*/
+int MEFlags_To_BMFlags(int flag, int type);
+
+/*convert MLoop*** in a bmface to mtface and mcol in
+ an MFace*/
+void BM_loops_to_corners(BMesh *bm, struct Mesh *me, int findex,
+ BMFace *f, int numTex, int numCol);
+
+/*include the rest of the API*/
+#include "bmesh_filters.h"
+#include "bmesh_iterators.h"
+#include "bmesh_marking.h"
+#include "bmesh_operator_api.h"
+#include "bmesh_operators.h"
+#include "bmesh_error.h"
+#include "bmesh_queries.h"
+#include "bmesh_walkers.h"
+
+#endif /* BMESH_H */
diff --git a/source/blender/bmesh/bmesh_error.h b/source/blender/bmesh/bmesh_error.h
new file mode 100644
index 00000000000..77204f57e0d
--- /dev/null
+++ b/source/blender/bmesh/bmesh_error.h
@@ -0,0 +1,53 @@
+#ifndef _BMESH_ERROR_H
+#define _BMESH_ERROR_H
+
+/*----------- bmop error system ----------*/
+
+/*pushes an error onto the bmesh error stack.
+ if msg is null, then the default message for the errorcode is used.*/
+void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, char *msg);
+
+/*gets the topmost error from the stack.
+ returns error code or 0 if no error.*/
+int BMO_GetError(BMesh *bm, char **msg, BMOperator **op);
+int BMO_HasError(BMesh *bm);
+
+/*same as geterror, only pops the error off the stack as well*/
+int BMO_PopError(BMesh *bm, char **msg, BMOperator **op);
+void BMO_ClearStack(BMesh *bm);
+
+#if 0
+//this is meant for handling errors, like self-intersection test failures.
+//it's dangerous to handle errors in general though, so disabled for now.
+
+/*catches an error raised by the op pointed to by catchop.
+ errorcode is either the errorcode, or BMERR_ALL for any
+ error.*/
+int BMO_CatchOpError(BMesh *bm, BMOperator *catchop, int errorcode, char **msg);
+#endif
+
+/*------ error code defines -------*/
+
+/*error messages*/
+#define BMERR_SELF_INTERSECTING 1
+#define BMERR_DISSOLVEDISK_FAILED 2
+#define BMERR_CONNECTVERT_FAILED 3
+#define BMERR_WALKER_FAILED 4
+#define BMERR_DISSOLVEFACES_FAILED 5
+#define BMERR_DISSOLVEVERTS_FAILED 6
+#define BMERR_TESSELATION 7
+#define BMERR_NONMANIFOLD 8
+
+static char *bmop_error_messages[] = {
+ 0,
+ "Self intersection error",
+ "Could not dissolve vert",
+ "Could not connect vertices",
+ "Could not traverse mesh",
+ "Could not dissolve faces",
+ "Could not dissolve vertices",
+ "Tesselation error",
+ "Can not deal with non-manifold geometry"
+};
+
+#endif /* _BMESH_ERROR_H */ \ No newline at end of file
diff --git a/source/blender/bmesh/bmesh_filters.h b/source/blender/bmesh/bmesh_filters.h
new file mode 100644
index 00000000000..9eed4e509fa
--- /dev/null
+++ b/source/blender/bmesh/bmesh_filters.h
@@ -0,0 +1,4 @@
+#ifndef BM_FILTER_H
+#define BM_FILTER_H
+
+#endif
diff --git a/source/blender/bmesh/bmesh_iterators.h b/source/blender/bmesh/bmesh_iterators.h
new file mode 100644
index 00000000000..7c3f91f2334
--- /dev/null
+++ b/source/blender/bmesh/bmesh_iterators.h
@@ -0,0 +1,70 @@
+/*
+ * BMESH ITERATORS
+ *
+ * The functions and structures in this file
+ * provide a unified method for iterating over
+ * the elements of a mesh and answering simple
+ * adjacency queries. Tool authors should use
+ * the iterators provided in this file instead
+ * of inspecting the structure directly.
+ *
+*/
+
+#ifndef BM_ITERATORS_H
+#define BM_ITERATORS_H
+
+/*Defines for passing to BMIter_New.
+
+ "OF" can be substituted for "around"
+ so BM_VERTS_OF_MESH_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
+
+#define BM_ITER(ele, iter, bm, type, data) \
+ ele = BMIter_New(iter, bm, type, data); \
+ for ( ; ele; ele=BMIter_Step(iter))
+
+/*these are topological iterators.*/
+#define BM_EDGES_OF_VERT 4
+#define BM_FACES_OF_VERT 5
+#define BM_FACES_OF_EDGE 6
+#define BM_VERTS_OF_FACE 7
+#define BM_FACEVERTS_OF_FACE 8
+#define BM_EDGES_OF_FACE 9
+#define BM_LOOPS_OF_FACE 10
+
+/*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 11
+
+
+/*Iterator Structure*/
+typedef struct BMIter{
+ struct BMVert *firstvert, *nextvert, *vdata;
+ struct BMEdge *firstedge, *nextedge, *edata;
+ struct BMLoop *firstloop, *nextloop, *ldata, *l;
+ struct BMFace *firstpoly, *nextpoly, *pdata;
+ struct BMesh *bm;
+ void (*begin)(struct BMIter *iter);
+ void *(*step)(struct BMIter *iter);
+ union{
+ void *p;
+ int i;
+ long l;
+ float f;
+ }filter;
+ int type, count;
+}BMIter;
+
+void *BMIter_New(struct BMIter *iter, struct BMesh *bm, int type, void *data);
+void *BMIter_Step(struct BMIter *iter);
+void *BMIter_AtIndex(struct BMesh *bm, int type, void *data, int index);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_marking.h b/source/blender/bmesh/bmesh_marking.h
new file mode 100644
index 00000000000..1074b057eba
--- /dev/null
+++ b/source/blender/bmesh/bmesh_marking.h
@@ -0,0 +1,16 @@
+#ifndef BM_MARKING_H
+#define BM_MARKING_H
+
+/*Selection code*/
+void BM_Select_Vert(struct BMesh *bm, struct BMVert *v, int select);
+void BM_Select_Edge(struct BMesh *bm, struct BMEdge *e, int select);
+void BM_Select_Face(struct BMesh *bm, struct BMFace *f, int select);
+void BM_Selectmode_Set(struct BMesh *bm, int selectmode);
+
+/*counts number of elements with flag set*/
+int BM_CountFlag(struct BMesh *bm, int type, int flag);
+
+void BM_Select(struct BMesh *bm, void *element, int select);
+int BM_Is_Selected(BMesh *bm, void *element);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_operator_api.h b/source/blender/bmesh/bmesh_operator_api.h
new file mode 100644
index 00000000000..0c0e0db0e6e
--- /dev/null
+++ b/source/blender/bmesh/bmesh_operator_api.h
@@ -0,0 +1,338 @@
+#ifndef _BMESH_OPERATOR_H
+#define _BMESH_OPERATOR_H
+
+#include "BLI_memarena.h"
+#include "BLI_ghash.h"
+
+#include <stdarg.h>
+
+/*
+operators represent logical, executable mesh modules. all topological
+operations involving a bmesh has to go through them.
+
+operators are nested, as are tool flags, which are private to an operator
+when it's executed. tool flags are allocated in layers, one per operator
+execution, and are used for all internal flagging a tool needs to do.
+
+each operator has a series of "slots," which can be of the following types:
+* simple numerical types
+* arrays of elements (e.g. arrays of faces).
+* hash mappings.
+
+each slot is identified by a slot code, as are each operator.
+operators, and their slots, are defined in bmesh_opdefines.c (with their
+execution functions prototyped in bmesh_operators_private.h), with all their
+operator code and slot codes defined in bmesh_operators.h. see
+bmesh_opdefines.c and the BMOpDefine struct for how to define new operators.
+
+in general, operators are fed arrays of elements, created using either
+BM_HeaderFlag_To_Slot or BM_Flag_To_Slot (or through one of the format
+specifyers in BMO_CallOpf or BMO_InitOpf). Note that multiple element
+types (e.g. faces and edges) can be fed to the same slot array. Operators
+act on this data, and possibly spit out data into output slots.
+
+some notes:
+* operators should never read from header flags (e.g. element->head.flag). for
+ example, if you want an operator to only operate on selected faces, you
+ should use BM_HeaderFlag_To_Slot to put the selected elements into a slot.
+* when you read from an element slot array or mapping, you can either tool-flag
+ all the elements in it, or read them using an iterator APi (which is
+ semantically similar to the iterator api in bmesh_iterators.h).
+*/
+
+struct GHashIterator;
+
+/*slot type arrays are terminated by the last member
+ having a slot type of 0.*/
+#define BMOP_OPSLOT_SENTINEL 0
+#define BMOP_OPSLOT_INT 1
+#define BMOP_OPSLOT_FLT 2
+#define BMOP_OPSLOT_PNT 3
+#define BMOP_OPSLOT_MAT 4
+#define BMOP_OPSLOT_VEC 7
+
+/*after BMOP_OPSLOT_VEC, everything is
+
+ dynamically allocated arrays. we
+ leave a space in the identifiers
+ for future growth.
+
+ */
+//it's very important this remain a power of two
+#define BMOP_OPSLOT_ELEMENT_BUF 8
+#define BMOP_OPSLOT_MAPPING 9
+#define BMOP_OPSLOT_TYPES 10
+
+/*please ignore all these structures, don't touch them in tool code, except
+ for when your defining an operator with BMOpDefine.*/
+
+typedef struct BMOpSlot{
+ int slottype;
+ int len;
+ int flag;
+ int index; /*index within slot array*/
+ union {
+ int i;
+ float f;
+ void *p;
+ float vec[3];
+ void *buf;
+ GHash *ghash;
+ } data;
+}BMOpSlot;
+
+#define BMOP_MAX_SLOTS 16 /*way more than probably needed*/
+
+typedef struct BMOperator {
+ int type;
+ int slottype;
+ int needflag;
+ struct BMOpSlot slots[BMOP_MAX_SLOTS];
+ void (*exec)(struct BMesh *bm, struct BMOperator *op);
+ MemArena *arena;
+} BMOperator;
+
+#define MAX_SLOTNAME 32
+
+typedef struct slottype {
+ int type;
+ char name[MAX_SLOTNAME];
+} slottype;
+
+typedef struct BMOpDefine {
+ char *name;
+ slottype slottypes[BMOP_MAX_SLOTS];
+ void (*exec)(BMesh *bm, BMOperator *op);
+ int flag; /*doesn't do anything right now*/
+} BMOpDefine;
+
+/*------------- Operator API --------------*/
+
+/*data types that use pointers (arrays, etc) should never
+ have it set directly. and never use BMO_Set_Pnt to
+ pass in a list of edges or any arrays, really.*/
+
+void BMO_Init_Op(struct BMOperator *op, char *opname);
+
+/*executes an operator, pushing and popping a new tool flag
+ layer as appropriate.*/
+void BMO_Exec_Op(struct BMesh *bm, struct BMOperator *op);
+
+/*finishes an operator (though note the operator's tool flag is removed
+ after it finishes executing in BMO_Exec_Op).*/
+void BMO_Finish_Op(struct BMesh *bm, struct BMOperator *op);
+
+
+/*tool flag API. never, ever ever should tool code put junk in
+ header flags (element->head.flag), nor should they use
+ element->head.eflag1/eflag2. instead, use this api to set
+ flags.
+
+ if you need to store a value per element, use a
+ ghash or a mapping slot to do it.*/
+/*flags 15 and 16 (1<<14 and 1<<15) are reserved for bmesh api use*/
+void BMO_SetFlag(struct BMesh *bm, void *element, int flag);
+void BMO_ClearFlag(struct BMesh *bm, void *element, int flag);
+int BMO_TestFlag(struct BMesh *bm, void *element, int flag);
+
+/*count the number of elements with a specific flag. type
+ can be a bitmask of BM_FACE, BM_EDGE, or BM_FACE.*/
+int BMO_CountFlag(struct BMesh *bm, int flag, int type);
+
+/*---------formatted operator initialization/execution-----------*/
+/*
+ this system is used to execute or initialize an operator,
+ using a formatted-string system.
+
+ for example, BMO_CallOpf(bm, "del geom=%hf context=%d", BM_SELECT, DEL_FACES);
+ . . .will execute the delete operator, feeding in selected faces, deleting them.
+
+ the basic format for the format string is:
+ [operatorname] [slotname]=%[code] [slotname]=%[code]
+
+ as in printf, you pass in one additional argument to the function
+ for every code.
+
+ the formatting codes are:
+ %d - put int in slot
+ %f - put float in slot
+ %p - put pointer in slot
+ %h[f/e/v] - put elements with a header flag in slot.
+ the letters after %h define which element types to use,
+ so e.g. %hf will do faces, %hfe will do faces and edges,
+ %hv will do verts, etc. must pass in at least one
+ element type letter.
+ %f[f/e/v] - same as %h, except it deals with tool flags instead of
+ header flags.
+ %a[f/e/v] - pass all elements (of types specified by f/e/v) to the
+ slot.
+ %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.
+*/
+/*executes an operator*/
+int BMO_CallOpf(BMesh *bm, char *fmt, ...);
+
+/*initializes, but doesn't execute an operator. this is so you can
+ gain access to the outputs of the operator. note that you have
+ to execute/finitsh (BMO_Exec_Op and BMO_Finish_Op) yourself.*/
+int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...);
+
+/*va_list version, used to implement the above two functions,
+ plus EDBM_CallOpf in bmeshutils.c.*/
+int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist);
+
+/*get a point to a slot. this may be removed layer on from the public API.*/
+BMOpSlot *BMO_GetSlot(struct BMOperator *op, char *slotname);
+
+/*copies the data of a slot from one operator to another. src and dst are the
+ source/destination slot codes, respectively.*/
+void BMO_CopySlot(struct BMOperator *source_op, struct BMOperator *dest_op,
+ char *src, char *dst);
+
+
+void BMO_Set_Float(struct BMOperator *op, char *slotname, float f);
+float BMO_Get_Float(BMOperator *op, char *slotname);
+void BMO_Set_Int(struct BMOperator *op, char *slotname, int i);
+int BMO_Get_Int(BMOperator *op, char *slotname);
+
+/*don't pass in arrays that are supposed to map to elements this way.
+
+ so, e.g. passing in list of floats per element in another slot is bad.
+ passing in, e.g. pointer to an editmesh for the conversion operator is fine
+ though.*/
+void BMO_Set_Pnt(struct BMOperator *op, char *slotname, void *p);
+void *BMO_Get_Pnt(BMOperator *op, char *slotname);
+void BMO_Set_Vec(struct BMOperator *op, char *slotname, float *vec);
+void BMO_Get_Vec(BMOperator *op, char *slotname, float *vec_out);
+
+/*only supports square mats*/
+/*size must be 3 or 4; this api is meant only for transformation matrices.
+ note that internally the matrix is stored in 4x4 form, and it's safe to
+ call whichever BMO_Get_Mat* function you want.*/
+void BMO_Set_Mat(struct BMOperator *op, char *slotname, float *mat, int size);
+void BMO_Get_Mat4(struct BMOperator *op, char *slotname, float mat[4][4]);
+void BMO_Get_Mat3(struct BMOperator *op, char *slotname, float mat[3][3]);
+
+/*puts every element of type type (which is a bitmask) with tool flag flag,
+ into a slot.*/
+void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag, int type);
+
+/*tool-flags all elements inside an element slot array with flag flag.*/
+void BMO_Flag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag);
+/*clears tool-flag flag from all elements inside a slot array.*/
+void BMO_Unflag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag);
+
+/*tool-flags all elements inside an element slot array with flag flag.*/
+void BMO_HeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag);
+/*clears tool-flag flag from all elements inside a slot array.*/
+void BMO_UnHeaderFlag_Buffer(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag);
+
+/*puts every element of type type (which is a bitmask) with header flag
+ flag, into a slot.*/
+void BMO_HeaderFlag_To_Slot(struct BMesh *bm, struct BMOperator *op, char *slotname, int flag, int type);
+
+/*counts number of elements inside a slot array.*/
+int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, char *slotname);
+
+
+/*inserts a key/value mapping into a mapping slot. note that it copies the
+ value, it doesn't store a reference to it.*/
+void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, char *slotname,
+ void *element, void *data, int len);
+
+/*inserts a key/float mapping pair into a mapping slot.*/
+void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, char *slotname,
+ void *element, float val);
+
+//returns 1 if the specified pointer is in the map.
+int BMO_InMap(BMesh *bm, BMOperator *op, char *slotname, void *element);
+
+/*returns a point to the value of a specific key.*/
+void *BMO_Get_MapData(BMesh *bm, BMOperator *op, char *slotname, void *element);
+
+/*returns the float part of a key/float pair.*/
+float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, char *slotname, void *element);
+
+/*flags all elements in a mapping. note that the mapping must only have
+ bmesh elements in it.*/
+void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op,
+ char *slotname, int flag);
+
+/*pointer versoins of BMO_Get_MapFloat and BMO_Insert_MapFloat.
+
+ do NOT use these for non-operator-api-allocated memory! instead
+ use BMO_Get_MapData and BMO_Insert_Mapping, which copies the data.*/
+void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, char *slotname,
+ void *key, void *val);
+void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, char *slotname,
+ void *key);
+
+/*this part of the API is used to iterate over element buffer or
+ mapping slots.
+
+ for example, iterating over the faces in a slot is:
+
+ BMOIter oiter;
+ BMFace *f;
+
+ f = BMO_IterNew(&oiter, bm, some_operator, "slotname", BM_FACE);
+ for (; f; f=BMO_IterStep(&oiter)) {
+ /do something with the face
+ }
+
+ another example, iterating over a mapping:
+ BMOIter oiter;
+ void *key;
+ void *val;
+
+ key = BMO_IterNew(&oiter, bm, some_operator, "slotname", 0);
+ for (; key; key=BMO_IterStep(&oiter)) {
+ val = BMO_IterMapVal(&oiter);
+ //do something with the key/val pair
+ //note that val is a pointer to the val data,
+ //whether it's a float, pointer, whatever.
+ //
+ // so to get a pointer, for example, use:
+ // *((void**)BMO_IterMapVal(&oiter));
+ //or something like that.
+ }
+
+ */
+
+/*contents of this structure are private,
+ don't directly access.*/
+typedef struct BMOIter {
+ BMOpSlot *slot;
+ int cur; //for arrays
+ struct GHashIterator giter;
+ void *val;
+ int restrict;
+} BMOIter;
+
+/*restrictmask restricts the iteration to certain element types
+ (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
+ over an element buffer (not a mapping).*/
+void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op,
+ char *slotname, int restrictmask);
+void *BMO_IterStep(BMOIter *iter);
+
+/*returns a pointer to the key value when iterating over mappings.
+ remember for pointer maps this will be a pointer to a pointer.*/
+void *BMO_IterMapVal(BMOIter *iter);
+
+/*use this for pointer mappings*/
+void *BMO_IterMapValp(BMOIter *iter);
+
+/*use this for float mappings*/
+float BMO_IterMapValf(BMOIter *iter);
+
+#define BMO_ITER(ele, iter, bm, op, slotname, restrict) \
+ ele = BMO_IterNew(iter, bm, op, slotname, restrict); \
+ for ( ; ele; ele=BMO_IterStep(iter))
+
+#endif /* _BMESH_OPERATOR_H */ \ No newline at end of file
diff --git a/source/blender/bmesh/bmesh_operators.h b/source/blender/bmesh/bmesh_operators.h
new file mode 100644
index 00000000000..3ef229f00c6
--- /dev/null
+++ b/source/blender/bmesh/bmesh_operators.h
@@ -0,0 +1,40 @@
+#ifndef BM_OPERATORS_H
+#define BM_OPERATORS_H
+
+/*--------defines/enumerations for specific operators-------*/
+
+/*del operator "context" slot values*/
+enum {
+ DEL_VERTS = 1,
+ DEL_EDGES,
+ DEL_ONLYFACES,
+ DEL_EDGESFACES,
+ DEL_FACES,
+ DEL_ALL ,
+ DEL_ONLYTAGGED,
+};
+
+extern BMOpDefine *opdefines[];
+extern int bmesh_total_ops;
+
+/*------specific operator helper functions-------*/
+
+/*executes the duplicate operation, feeding elements of
+ type flag etypeflag and header flag flag to it. note,
+ to get more useful information (such as the mapping from
+ original to new elements) you should run the dupe op manually.*/
+struct Object;
+struct EditMesh;
+
+void BMOP_DupeFromFlag(struct BMesh *bm, int etypeflag, int flag);
+void BM_esubdivideflag(struct Object *obedit, BMesh *bm, int flag, float smooth,
+ float fractal, int beauty, int numcuts, int seltype);
+void BM_extrudefaceflag(BMesh *bm, int flag);
+
+/*this next one return 1 if they did anything, or zero otherwise.
+ they're kindof a hackish way to integrate with fkey, until
+ such time as fkey is completely bmeshafied.*/
+/*this doesn't display errors to the user, btw*/
+int BM_ConnectVerts(struct EditMesh *em, int flag);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_queries.h b/source/blender/bmesh/bmesh_queries.h
new file mode 100644
index 00000000000..ee2b8605a17
--- /dev/null
+++ b/source/blender/bmesh/bmesh_queries.h
@@ -0,0 +1,86 @@
+#ifndef BMESH_QUERIES_H
+#define BMESH_QUERIES_H
+#include <stdio.h>
+
+/*Queries*/
+/*counts number of elements of type type are in the mesh.*/
+int BM_Count_Element(struct BMesh *bm, int type);
+
+/*returns true if v is in f*/
+int BM_Vert_In_Face(struct BMFace *f, struct BMVert *v);
+
+// int BM_VERTS_OF_MESH_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 BMVert *v1, struct BMVert *v2, BMEdge *e);
+
+
+/*get opposing vert from v in edge e.*/
+struct BMVert *BM_OtherEdgeVert(struct BMEdge *e, struct BMVert *v);
+
+/*finds other loop that shares v with e's loop in f.*/
+struct BMLoop *BM_OtherFaceLoop(BMEdge *e, BMFace *f, BMVert *v);
+
+//#define BM_OtherEdgeVert(e, v) (v==e->v1?e->v2:e->v1)
+
+/*returns the edge existing between v1 and v2, or NULL if there isn't one.*/
+struct BMEdge *BM_Edge_Exist(struct BMVert *v1, struct BMVert *v2);
+
+
+/*returns number of edges aroudn a vert*/
+int BM_Vert_EdgeCount(struct BMVert *v);
+
+/*returns number of faces around an edge*/
+int BM_Edge_FaceCount(struct BMEdge *e);
+
+/*returns number of faces around a vert.*/
+int BM_Vert_FaceCount(struct BMVert *v);
+
+
+/*returns true if v is a wire vert*/
+int BM_Wire_Vert(struct BMesh *bm, struct BMVert *v);
+
+/*returns true if e is a wire edge*/
+int BM_Wire_Edge(struct BMesh *bm, struct BMEdge *e);
+
+/*returns true if v is part of a non-manifold edge in the mesh,
+ I believe this includes if it's part of both a wire edge and
+ a face.*/
+int BM_Nonmanifold_Vert(struct BMesh *bm, struct BMVert *v);
+
+/*returns true if e is shared by more then two faces.*/
+int BM_Nonmanifold_Edge(struct BMesh *bm, struct BMEdge *e);
+
+/*returns true if e is a boundary edge, e.g. has only 1 face bordering it.*/
+int BM_Boundary_Edge(struct BMEdge *e);
+
+
+/*returns angle of two faces surrounding an edge. note there must be
+ exactly two faces sharing the edge.*/
+float BM_Face_Angle(struct BMesh *bm, struct BMEdge *e);
+
+/*checks overlapping of existing faces with the verts in varr.*/
+int BM_Exist_Face_Overlaps(struct BMesh *bm, struct BMVert **varr, int len, struct BMFace **existface);
+
+/*checks if a face defined by varr already exists.*/
+int BM_Face_Exists(BMesh *bm, BMVert **varr, int len, BMFace **existface);
+
+
+/*returns number of edges f1 and f2 share.*/
+int BM_Face_Sharededges(struct BMFace *f1, struct BMFace *f2);
+
+/*returns number of faces e1 and e2 share.*/
+int BM_Edge_Share_Faces(struct BMEdge *e1, struct BMEdge *e2);
+
+/*checks if a face is valid in the data structure*/
+int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err);
+
+/*each pair of loops defines a new edge, a split. this function goes
+ through and sets pairs that are geometrically invalid to null. a
+ split is invalid, if it forms a concave angle or it intersects other
+ edges in the face.*/
+void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len);
+
+#endif
diff --git a/source/blender/bmesh/bmesh_walkers.h b/source/blender/bmesh/bmesh_walkers.h
new file mode 100644
index 00000000000..2fdb9e18a3a
--- /dev/null
+++ b/source/blender/bmesh/bmesh_walkers.h
@@ -0,0 +1,64 @@
+#ifndef BM_WALKERS_H
+#define BM_WALKERS_H
+
+#include "BLI_ghash.h"
+
+/*
+ NOTE: do NOT modify topology while walking a mesh!
+*/
+
+/*Walkers*/
+typedef struct BMWalker {
+ BLI_mempool *stack;
+ BMesh *bm;
+ void *currentstate;
+ void (*begin) (struct BMWalker *walker, void *start);
+ void *(*yield)(struct BMWalker *walker);
+ void *(*step) (struct BMWalker *walker);
+ int restrictflag;
+ GHash *visithash;
+} BMWalker;
+
+/*initialize a walker. searchmask restricts some (not all) walkers to
+ elements with a specific tool flag set.*/
+void BMW_Init(struct BMWalker *walker, BMesh *bm, int type, int searchmask);
+void *BMW_Begin(BMWalker *walker, void *start);
+void *BMW_Step(struct BMWalker *walker);
+void BMW_End(struct BMWalker *walker);
+
+/*
+example of usage, walking over an island of tool flagged faces:
+
+BMWalker walker;
+BMFace *f;
+
+BMW_Init(&walker, bm, BMW_ISLAND, SOME_OP_FLAG);
+f = BMW_Begin(&walker, some_start_face);
+for (; f; f=BMW_Step(&walker)) {
+ //do something with f
+}
+BMW_End(&walker);
+*/
+
+enum {
+ /*walk over connected geometry. can restrict to a search flag,
+ or not, it's optional.*/
+ BMW_SHELL,
+ /*walk over an edge loop. search flag doesn't do anything.*/
+ BMW_LOOP,
+ BMW_FACELOOP,
+ BMW_EDGERING,
+ /*#define BMW_RING 2
+ #define BMW_UVISLANDS 3*/
+ /*walk over an island of flagged faces. note, that this doesn't work on
+ non-manifold geometry. it might be better to rewrite this to extract
+ boundary info from the island walker, rather then directly walking
+ over the boundary. raises an error if it encouters nonmanifold
+ geometry.*/
+ BMW_ISLANDBOUND,
+ /*walk over all faces in an island of tool flagged faces.*/
+ BMW_ISLAND,
+ BMW_MAXWALKERS,
+};
+
+#endif \ No newline at end of file
diff --git a/source/blender/bmesh/editmesh_tools.c b/source/blender/bmesh/editmesh_tools.c
new file mode 100644
index 00000000000..e2b83c6e111
--- /dev/null
+++ b/source/blender/bmesh/editmesh_tools.c
@@ -0,0 +1,7244 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Johnny Matthews, Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_cursors.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_resources.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+#include "transform.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+
+#include "blendef.h"
+#include "multires.h"
+#include "mydevice.h"
+
+#include "editmesh.h"
+
+#include "MTC_vectorops.h"
+
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/* local prototypes ---------------*/
+void bevel_menu(void);
+static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa);
+
+/********* 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;
+}
+
+
+/* *********************************** */
+
+void convert_to_triface(int direction)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *efan, *next;
+ float fac;
+
+ if(multires_test()) return;
+
+ efa= em->faces.last;
+ while(efa) {
+ next= efa->prev;
+ if(efa->v4) {
+ if(efa->f & SELECT) {
+ /* choose shortest diagonal for split */
+ fac= VecLenf(efa->v1->co, efa->v3->co) - VecLenf(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(efa, NULL, 0, 1, 2, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ efan= EM_face_from_faces(efa, NULL, 0, 2, 3, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ }
+ else {
+ efan= EM_face_from_faces(efa, NULL, 0, 1, 3, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ efan= EM_face_from_faces(efa, NULL, 1, 2, 3, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ }
+
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ }
+ efa= next;
+ }
+
+ EM_fgon_flags(); // redo flags and indices for fgons
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Convert Quads to Triangles");
+
+}
+
+int removedoublesflag(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.
+ */
+
+ EditMesh *em = G.editMesh;
+ /* 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;
+
+ if(multires_test()) return 0;
+
+
+ /* 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(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(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(eed->v1, eed->v2, eed);
+
+ if(e1) {
+ e1->f2= 1;
+ if(eed->f & SELECT)
+ e1->f |= SELECT;
+ }
+ if(e1!=eed) free_editedge(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(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(efa);
+ amount--;
+ }
+ }
+ else {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ amount--;
+ }
+ }
+
+ if(test==0) {
+ /* set edge pointers */
+ efa->e1= findedgelist(efa->v1, efa->v2);
+ efa->e2= findedgelist(efa->v2, efa->v3);
+ if(efa->v4==0) {
+ efa->e3= findedgelist(efa->v3, efa->v1);
+ efa->e4= 0;
+ }
+ else {
+ efa->e3= findedgelist(efa->v3, efa->v4);
+ efa->e4= findedgelist(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(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(eve);
+ }
+ }
+ eve= nextve;
+ }
+
+#ifdef WITH_VERSE
+ if((a>0) && (G.editMesh->vnode)) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ }
+#endif
+
+ return a; /* amount */
+}
+
+/* called from buttons */
+static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y, int index)
+{
+ xvertsort *sortblock = userData;
+
+ sortblock[index].x = x;
+}
+void xsortvert_flag(int flag)
+{
+ EditMesh *em = G.editMesh;
+ /* all verts with (flag & 'flag') are sorted */
+ EditVert *eve;
+ xvertsort *sortblock;
+ ListBase tbase;
+ int i, amount = BLI_countlist(&em->verts);
+
+ if(multires_test()) return;
+
+ sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
+ for (i=0,eve=em->verts.first; eve; i++,eve=eve->next)
+ if(eve->f & flag)
+ sortblock[i].v1 = eve;
+ mesh_foreachScreenVert(xsortvert_flag__doSetX, sortblock, 0);
+ qsort(sortblock, amount, sizeof(xvertsort), vergxco);
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ for (i=0; i<amount; i++) {
+ eve = sortblock[i].v1;
+
+ if (eve) {
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ }
+ }
+
+ addlisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Xsort");
+
+}
+
+/* called from buttons */
+void hashvert_flag(int flag)
+{
+ /* switch vertex order using hash table */
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ struct xvertsort *sortblock, *sb, onth, *newsort;
+ ListBase tbase;
+ int amount, a, b;
+
+ if(multires_test()) return;
+
+ /* count */
+ eve= em->verts.first;
+ amount= 0;
+ 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++;
+ }
+
+ addlisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Hash");
+
+}
+
+/* generic extern called extruder */
+void extrude_mesh(void)
+{
+ float nor[3]= {0.0, 0.0, 0.0};
+ short nr, transmode= 0;
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if(G.totvertsel==0) nr= 0;
+ else if(G.totvertsel==1) nr= 4;
+ else if(G.totedgesel==0) nr= 4;
+ else if(G.totfacesel==0)
+ nr= pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
+ else if(G.totfacesel==1)
+ nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ if (G.totedgesel==0) nr = 0;
+ else if (G.totedgesel==1) nr = 3;
+ else if(G.totfacesel==0) nr = 3;
+ else if(G.totfacesel==1)
+ nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3");
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
+ }
+ else {
+ if (G.totfacesel == 0) nr = 0;
+ else if (G.totfacesel == 1) nr = 1;
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
+ }
+
+ if(nr<1) return;
+
+ if(nr==1) transmode= extrudeflag(SELECT, nor);
+ else if(nr==4) transmode= extrudeflag_verts_indiv(SELECT, nor);
+ else if(nr==3) transmode= extrudeflag_edges_indiv(SELECT, nor);
+ else transmode= extrudeflag_face_indiv(SELECT, nor);
+
+ if(transmode==0) {
+ error("No valid selection");
+ }
+ else {
+ EM_fgon_flags();
+ countall();
+
+ /* We need to force immediate calculation here because
+ * transform may use derived objects (which are now stale).
+ *
+ * This shouldn't be necessary, derived queries should be
+ * automatically building this data if invalid. Or something.
+ */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ object_handle_update(G.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') {
+ Mat4MulVecfl(G.obedit->obmat, nor);
+ VecSubf(nor, nor, G.obedit->obmat[3]);
+ BIF_setSingleAxisConstraint(nor, "along normal");
+ }
+ Transform();
+ }
+ }
+
+}
+
+void split_mesh(void)
+{
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ if(okee(" Split ")==0) return;
+
+ waitcursor(1);
+
+ /* make duplicate first */
+ adduplicateflag(SELECT);
+ /* old faces have flag 128 set, delete them */
+ delfaceflag(128);
+ recalc_editnormals();
+
+ waitcursor(0);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Split");
+
+}
+
+void extrude_repeat_mesh(int steps, float offs)
+{
+ float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
+ short a;
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ /* dvec */
+ dvec[0]= G.vd->persinv[2][0];
+ dvec[1]= G.vd->persinv[2][1];
+ dvec[2]= G.vd->persinv[2][2];
+ Normalize(dvec);
+ dvec[0]*= offs;
+ dvec[1]*= offs;
+ dvec[2]*= offs;
+
+ /* base correction */
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(tmat, bmat);
+ Mat3MulVecfl(tmat, dvec);
+
+ for(a=0; a<steps; a++) {
+ extrudeflag(SELECT, nor);
+ translateflag(SELECT, dvec);
+ }
+
+ recalc_editnormals();
+
+ EM_fgon_flags();
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ BIF_undo_push("Extrude Repeat");
+}
+
+void spin_mesh(int steps, float degr, float *dvec, int mode)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*nextve;
+ float nor[3]= {0.0, 0.0, 0.0};
+ float *curs, si,n[3],q[4],cmat[3][3],imat[3][3], tmat[3][3];
+ float cent[3],bmat[3][3];
+ float phi;
+ short a,ok;
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ /* imat and center and size */
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat,bmat);
+
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
+ Mat3MulVecfl(imat, cent);
+
+ phi= degr*M_PI/360.0;
+ phi/= steps;
+ if(G.scene->toolsettings->editbutflag & B_CLOCKWISE) phi= -phi;
+
+ if(dvec) {
+ n[0]= G.vd->viewinv[1][0];
+ n[1]= G.vd->viewinv[1][1];
+ n[2]= G.vd->viewinv[1][2];
+ } else {
+ n[0]= G.vd->viewinv[2][0];
+ n[1]= G.vd->viewinv[2][1];
+ n[2]= G.vd->viewinv[2][2];
+ }
+ Normalize(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;
+ QuatToMat3(q, cmat);
+
+ Mat3MulMat3(tmat,cmat,bmat);
+ Mat3MulMat3(bmat,imat,tmat);
+
+ if(mode==0) if(G.scene->toolsettings->editbutflag & B_KEEPORIG) adduplicateflag(1);
+ ok= 1;
+
+ for(a=0;a<steps;a++) {
+ if(mode==0) ok= extrudeflag(SELECT, nor);
+ else adduplicateflag(SELECT);
+ if(ok==0) {
+ error("No valid vertices are selected");
+ break;
+ }
+ rotateflag(SELECT, cent, bmat);
+ if(dvec) {
+ Mat3MulVecfl(bmat,dvec);
+ translateflag(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(eve);
+ }
+ eve= nextve;
+ }
+ }
+ recalc_editnormals();
+
+ EM_fgon_flags();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+
+ if(dvec==NULL) BIF_undo_push("Spin");
+}
+
+void screw_mesh(int steps, int turns)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1=0,*v2=0;
+ EditEdge *eed;
+ float dvec[3], nor[3];
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ /* clear flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f1= 0;
+ eve= eve->next;
+ }
+ /* edges set flags in verts */
+ eed= em->edges.first;
+ while(eed) {
+ 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++;
+ }
+ }
+ eed= eed->next;
+ }
+ /* find two vertices with eve->f1==1, more or less is wrong */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f1==1) {
+ if(v1==0) v1= eve;
+ else if(v2==0) v2= eve;
+ else {
+ v1=0;
+ break;
+ }
+ }
+ eve= eve->next;
+ }
+ if(v1==0 || v2==0) {
+ error("You have to select a string of connected vertices too");
+ return;
+ }
+
+ /* calculate dvec */
+ dvec[0]= ( (v1->co[0]- v2->co[0]) )/(steps);
+ dvec[1]= ( (v1->co[1]- v2->co[1]) )/(steps);
+ dvec[2]= ( (v1->co[2]- v2->co[2]) )/(steps);
+
+ VECCOPY(nor, G.obedit->obmat[2]);
+
+ if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) {
+ dvec[0]= -dvec[0];
+ dvec[1]= -dvec[1];
+ dvec[2]= -dvec[2];
+ }
+
+ spin_mesh(turns*steps, turns*360, dvec, 0);
+
+ BIF_undo_push("Spin");
+}
+
+
+static void erase_edges(ListBase *l)
+{
+ EditEdge *ed, *nexted;
+
+ ed = (EditEdge *) l->first;
+ while(ed) {
+ nexted= ed->next;
+ if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) {
+ remedge(ed);
+ free_editedge(ed);
+ }
+ ed= nexted;
+ }
+}
+
+static void erase_faces(ListBase *l)
+{
+ EditFace *f, *nextf;
+
+ f = (EditFace *) l->first;
+
+ while(f) {
+ nextf= f->next;
+ if( faceselectedOR(f, SELECT) ) {
+ BLI_remlink(l, f);
+ free_editface(f);
+ }
+ f = nextf;
+ }
+}
+
+static void erase_vertices(ListBase *l)
+{
+ EditVert *v, *nextv;
+
+ v = (EditVert *) l->first;
+ while(v) {
+ nextv= v->next;
+ if(v->f & 1) {
+ BLI_remlink(l, v);
+ free_editvert(v);
+ }
+ v = nextv;
+ }
+}
+
+void delete_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *nextvl;
+ EditVert *eve,*nextve;
+ EditEdge *eed,*nexted;
+ short event;
+ int count;
+ char *str="Erase";
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5|Edge Loop%x6");
+ if(event<1) return;
+
+ if(event==10 ) {
+ str= "Erase Vertices";
+ erase_edges(&em->edges);
+ erase_faces(&em->faces);
+ erase_vertices(&em->verts);
+ }
+ else if(event==6) {
+ if(!EdgeLoopDelete())
+ 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(efa);
+ }
+ efa= nextvl;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f & SELECT) {
+ remedge(eed);
+ free_editedge(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(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(efa);
+ }
+ efa= nextvl;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f & SELECT) {
+ remedge(eed);
+ free_editedge(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(eve);
+ }
+ eve= nextve;
+ }
+
+ }
+ else if(event==2) {
+ str="Erase Faces";
+ delfaceflag(SELECT);
+ }
+ else if(event==3) {
+ str= "Erase All";
+ if(em->verts.first) free_vertlist(&em->verts);
+ if(em->edges.first) free_edgelist(&em->edges);
+ if(em->faces.first) free_facelist(&em->faces);
+ if(em->selected.first) BLI_freelistN(&(em->selected));
+ }
+ else if(event==5) {
+ str= "Erase Only Faces";
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f & SELECT) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ }
+
+ EM_fgon_flags(); // redo flags and indices for fgons
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push(str);
+}
+
+
+/* Got this from scanfill.c. You will need to juggle around the
+ * callbacks for the scanfill.c code a bit for this to work. */
+void fill_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1;
+ EditEdge *eed,*e1,*nexted;
+ EditFace *efa,*nextvl, *efan;
+ short ok;
+
+ if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return;
+ if(multires_test()) 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(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) {
+ efa= fillfacebase.first;
+ while(efa) {
+ /* normals default pointing up */
+ efan= addfacelist(efa->v3->tmp.v, efa->v2->tmp.v,
+ efa->v1->tmp.v, 0, NULL, NULL);
+ if(efan) EM_select_face(efan, 1);
+ efa= efa->next;
+ }
+ }
+
+ BLI_end_edgefill();
+
+ waitcursor(0);
+ EM_select_flush();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Fill");
+}
+/*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 rad, int beauty, float perc)
+{
+ float vec1[3], fac;
+
+ if(beauty & B_SMOOTH) {
+ /* we calculate an offset vector vec1[], to be added to *co */
+ float len, fac, nor[3], nor1[3], nor2[3];
+
+ VecSubf(nor, edge->v1->co, edge->v2->co);
+ len= 0.5f*Normalize(nor);
+
+ VECCOPY(nor1, edge->v1->no);
+ VECCOPY(nor2, edge->v2->no);
+
+ /* cosine angle */
+ fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
+
+ vec1[0]= fac*nor1[0];
+ vec1[1]= fac*nor1[1];
+ vec1[2]= fac*nor1[2];
+
+ /* cosine angle */
+ fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
+
+ vec1[0]+= fac*nor2[0];
+ vec1[1]+= fac*nor2[1];
+ vec1[2]+= fac*nor2[2];
+
+ vec1[0]*= rad*len;
+ vec1[1]*= rad*len;
+ vec1[2]*= rad*len;
+
+ co[0] += vec1[0];
+ co[1] += vec1[1];
+ co[2] += vec1[2];
+ }
+ else {
+ if(rad > 0.0) { /* subdivide sphere */
+ Normalize(co);
+ co[0]*= rad;
+ co[1]*= rad;
+ co[2]*= rad;
+ }
+ else if(rad< 0.0) { /* fractal subdivide */
+ fac= rad* VecLenf(edge->v1->co, edge->v2->co);
+ vec1[0]= fac*(float)(0.5-BLI_drand());
+ vec1[1]= fac*(float)(0.5-BLI_drand());
+ vec1[2]= fac*(float)(0.5-BLI_drand());
+ VecAddf(co, co, vec1);
+ }
+
+ }
+}
+
+/* assumes in the edge is the correct interpolated vertices already */
+/* percent defines the interpolation, rad and beauty are for special options */
+/* results in new vertex with correct coordinate, vertex normal and weight group info */
+static EditVert *subdivide_edge_addvert(EditEdge *edge, float rad, int beauty, float percent)
+{
+ EditVert *ev;
+ float co[3];
+
+ co[0] = (edge->v2->co[0]-edge->v1->co[0])*percent + edge->v1->co[0];
+ co[1] = (edge->v2->co[1]-edge->v1->co[1])*percent + edge->v1->co[1];
+ co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2];
+
+ /* offset for smooth or sphere or fractal */
+ alter_co(co, edge, rad, beauty, percent);
+
+ /* clip if needed by mirror modifier */
+ if (edge->v1->f2) {
+ if ( edge->v1->f2 & edge->v2->f2 & 1) {
+ 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(co, NULL);
+
+ /* vert data (vgroups, ..) */
+ EM_data_interp_from_verts(edge->v1, edge->v2, ev, percent);
+
+ /* normal */
+ ev->no[0] = (edge->v2->no[0]-edge->v1->no[0])*percent + edge->v1->no[0];
+ ev->no[1] = (edge->v2->no[1]-edge->v1->no[1])*percent + edge->v1->no[1];
+ ev->no[2] = (edge->v2->no[2]-edge->v1->no[2])*percent + edge->v1->no[2];
+ Normalize(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(EditFace *source, EditFace *target)
+{
+ EditMesh *em= G.editMesh;
+ float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co;
+ float *v4 = source->v4? source->v4->co: NULL;
+ float w[4][4];
+
+ 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;
+
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v1->co, w[0]);
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v2->co, w[1]);
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v3->co, w[2]);
+ if (target->v4)
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v4->co, w[3]);
+
+ CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data);
+}
+
+static void fill_quad_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype)
+{
+ EditEdge *cedge=NULL;
+ EditVert *v[4], **verts;
+ EditFace *hold;
+ short start=0, end, left, right, vertsize,i;
+
+ 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;
+ 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(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(verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL);
+ hold->e1->f2 |= EDGEINNER;
+ hold->e3->f2 |= EDGEINNER;
+ }
+ facecopy(efa,hold);
+
+ // Make side faces
+ for(i=0;i<(vertsize-1)/2;i++) {
+ hold = addfacelist(verts[i],verts[i+1],v[right],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ if(i+1 != (vertsize-1)/2) {
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e2->f2 |= EDGEINNER;
+ }
+ }
+ hold = addfacelist(verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ if(i+1 != (vertsize-1)/2) {
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e3->f2 |= EDGEINNER;
+ }
+ }
+ }
+}
+
+static void fill_tri_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype)
+{
+ EditEdge *cedge=NULL;
+ EditVert *v[3], **verts;
+ EditFace *hold;
+ short start=0, end, op, vertsize,i;
+
+ 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;
+ 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(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(efa,hold);
+ }
+}
+
+static void fill_quad_double_op(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], **verts[2];
+ EditFace *hold;
+ short start=0, end, left, right, vertsize,i;
+
+ 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;
+ left = (start+2)%4;
+ right = (start+3)%4;
+ if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ |---*---*---|
+ | |
+ | |
+ | |
+ |---*---*---|
+ 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(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(efa,hold);
+ }
+}
+
+static void fill_quad_double_adj_path(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], **verts[2];
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+
+ 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(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 (G.qual != LR_CTRLKEY)
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ hold = addfacelist(verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL);
+ /* when ctrl is depressed, only want verts on the cutline selected */
+ if (G.qual != LR_CTRLKEY)
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e1->h |= EM_FGON;
+ //}
+ // Make side faces
+
+ for(i=0;i<numcuts;i++) {
+ hold = addfacelist(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(efa,hold);
+ }
+ //EM_fgon_flags();
+
+}
+
+static void fill_quad_double_adj_fan(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], *op=NULL, **verts[2];
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ 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;
+
+ // 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(op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL);
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ hold = addfacelist(op,verts[0][i],verts[0][i+1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+}
+
+static void fill_quad_double_adj_inner(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], *op=NULL, **verts[2],**inner;
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+ float co[3];
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ 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;
+
+ // 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(co, NULL);
+ inner[i]->f2 |= EDGEINNER;
+
+ EM_data_interp_from_verts(verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f);
+ }
+
+ // Add Corner Quad
+ hold = addfacelist(verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Add Bottom Quads
+ hold = addfacelist(verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ hold = addfacelist(op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e1->h |= EM_FGON;
+ //}
+ // Add Fill Quads (if # cuts > 1)
+
+ for(i=0;i<numcuts-1;i++) {
+ hold = addfacelist(inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL);
+ hold->e1->f2 |= EDGEINNER;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ hold = addfacelist(inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ hold->e4->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e1->h |= EM_FGON;
+ //}
+ }
+
+ //EM_fgon_flags();
+
+ MEM_freeN(inner);
+}
+
+static void fill_tri_double(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[3], **verts[2];
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+
+ 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(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Make side faces
+
+ for(i=0;i<numcuts;i++) {
+ hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+}
+
+static void fill_quad_triple(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[3]={0};
+ EditVert *v[4], **verts[3];
+ EditFace *hold;
+ short start=0, start2=0, start3=0, vertsize, i, repeats;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ 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(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ hold = addfacelist(verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Make bottom quad
+ hold = addfacelist(verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ //If it is even cuts, add the 2nd lower quad
+ if(numcuts % 2 == 0) {
+ hold = addfacelist(verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Also Make inner quad
+ hold = addfacelist(verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e3->h |= EM_FGON;
+ //}
+ facecopy(efa,hold);
+ repeats = (numcuts / 2) -1;
+ } else {
+ // Make inner tri
+ hold = addfacelist(verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e2->h |= EM_FGON;
+ //}
+ facecopy(efa,hold);
+ repeats = ((numcuts+1) / 2)-1;
+ }
+
+ // cuts for 1 and 2 do not have the repeating quads
+ if(numcuts < 3) {repeats = 0;}
+ for(i=0;i<repeats;i++) {
+ //Make side repeating Quads
+ hold = addfacelist(verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ hold = addfacelist(verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL);
+ hold->e4->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+ // Do repeating bottom quads
+ for(i=0;i<repeats;i++) {
+ if(numcuts % 2 == 1) {
+ hold = addfacelist(verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL);
+ } else {
+ hold = addfacelist(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(efa,hold);
+ }
+ //EM_fgon_flags();
+}
+
+static void fill_quad_quadruple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty)
+{
+ EditVert **verts[4], ***innerverts;
+ EditFace *hold;
+ EditEdge temp;
+ short vertsize, i, j;
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, efa->e1);
+ verts[1] = BLI_ghash_lookup(gh, efa->e2);
+ 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;
+
+ // 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(&temp, rad, beauty, percent);
+ }
+ }
+ // Fill with faces
+ for(i=0;i<numcuts+1;i++) {
+ for(j=0;j<numcuts+1;j++) {
+ hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL);
+ hold->e1->f2 = EDGENEW;
+ hold->e2->f2 = EDGENEW;
+ hold->e3->f2 = EDGENEW;
+ hold->e4->f2 = EDGENEW;
+
+ if(i != 0) { hold->e1->f2 |= EDGEINNER; }
+ if(j != 0) { hold->e2->f2 |= EDGEINNER; }
+ if(i != numcuts) { hold->e3->f2 |= EDGEINNER; }
+ if(j != numcuts) { hold->e4->f2 |= EDGEINNER; }
+
+ facecopy(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(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty)
+{
+ EditVert **verts[3], ***innerverts;
+ short vertsize, 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;
+
+ // 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(&temp, rad, beauty, 1-percent);
+ }
+ }
+
+ // Now fill the verts with happy little tris :)
+ for(i=0;i<=numcuts+1;i++) {
+ for(j=0;j<(numcuts+1)-i;j++) {
+ //We always do the first tri
+ hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ if(i != 0) { hold->e1->f2 |= EDGEINNER; }
+ if(j != 0) { hold->e2->f2 |= EDGEINNER; }
+ if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;}
+
+ facecopy(efa,hold);
+ //if there are more to come, we do the 2nd
+ if(j+1 <= numcuts-i) {
+ hold = addfacelist(innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ }
+ }
+ }
+
+ // Clean up our dynamic multi-dim array
+ for(i=0;i<numcuts+2;i++) {
+ MEM_freeN(innerverts[i]);
+ }
+ MEM_freeN(innerverts);
+}
+
+//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(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(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(efa, hold);
+
+ hold= addfacelist(efa->v1, efa->v3, efa->v4, 0, efa, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ }
+ else{
+ hold= addfacelist(efa->v1, efa->v2, efa->v4, 0, efa, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+
+ hold= addfacelist(efa->v2, efa->v3, efa->v4, 0, efa, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ }
+}
+
+static void fill_quad_singlevert(EditFace *efa, struct GHash *gh)
+{
+ EditEdge *cedge=NULL;
+ EditVert *v[4], **verts;
+ EditFace *hold;
+ short start=0, end, left, right, vertsize;
+
+ 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;
+
+ // 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(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(efa, hold);
+
+ //quad is composed of cutvert, left, right and start
+ hold = addfacelist(verts[1],v[left],v[right],v[start], NULL, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e4->f2 |= EDGENEW;
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ }
+ else if(v[right]->f1){
+ //triangle is composed of cutvert, right and start
+ hold = addfacelist(verts[1],v[right],v[start], NULL, NULL, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ //quad is composed of cutvert, end, left, right
+ hold = addfacelist(verts[1],v[end], v[left], v[right], NULL, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e4->f2 |= EDGENEW;
+ hold->e4->f2 |= EDGEINNER;
+ facecopy(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(EditEdge *edge, int curpoint, int totpoint, float rad, int beauty)
+{
+ EditVert *ev;
+ float percent;
+
+ if (beauty & (B_PERCENTSUBD) && totpoint == 1)
+ //percent=(float)(edge->tmp.l)/32768.0f;
+ percent= edge->tmp.fp;
+ else
+ percent= (float)curpoint/(float)(totpoint+1);
+
+ ev= subdivide_edge_addvert(edge, rad, beauty, percent);
+ ev->f = edge->v1->f;
+
+ return ev;
+}
+
+#if 1
+#include "bmesh.h"
+
+void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype)
+{
+ BMesh *bm;
+ BMOperator subdop, conv;
+ EditMesh *em = G.editMesh;
+ BMEdge **list, *bed;
+ BMIter iter;
+ int tot;
+
+ /*convert from editmesh*/
+ bm = editmesh_to_bmesh(G.editMesh);
+
+ BMO_Init_Op(&subdop, BMOP_ESUBDIVIDE);
+ for (tot=0, bed=BMIter_New(&iter, bm, BM_EDGES, NULL); bed; bed=BMIter_Step(&iter)) {
+ if (BM_Is_Selected(bm, bed)) tot++;
+ }
+
+ list = MEM_callocN(sizeof(void*)*tot, "vert ptr list");
+
+ for (tot=0, bed=BMIter_New(&iter, bm, BM_EDGES, NULL); bed; bed=BMIter_Step(&iter)) {
+ if (BM_Is_Selected(bm, bed)) list[tot++] = bed;
+ }
+
+ BMO_Set_PntBuf(&subdop, BMOP_ESUBDIVIDE_EDGES, list, tot);
+ BMO_Exec_Op(bm, &subdop);
+ BMO_Finish_Op(bm, &subdop);
+
+ free_editMesh(G.editMesh);
+ bmesh_to_editmesh(bm);
+ BM_Free_Mesh(bm);
+
+ if (list) MEM_freeN(list);
+}
+#else
+void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *ef;
+ EditEdge *eed, *cedge, *sort[4];
+ EditVert *eve, **templist;
+ struct GHash *gh;
+ float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3];
+ int i, j, edgecount, touchcount, facetype,hold;
+ ModifierData *md= G.obedit->modifiers.first;
+
+ if(multires_test()) return;
+
+ //Set faces f1 to 0 cause we need it later
+ for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0;
+ 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) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ eve->f2= 0;
+ switch(mmd->axis){
+ case 0:
+ if (fabs(eve->co[0]) < mmd->tolerance)
+ eve->f2 |= 1;
+ break;
+ case 1:
+ if (fabs(eve->co[1]) < mmd->tolerance)
+ eve->f2 |= 2;
+ break;
+ case 2:
+ if (fabs(eve->co[2]) < mmd->tolerance)
+ eve->f2 |= 4;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //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);
+ Mat4Mul3Vecfl(G.obedit->obmat, v1mat);
+ Mat4Mul3Vecfl(G.obedit->obmat, v2mat);
+ Mat4Mul3Vecfl(G.obedit->obmat, v3mat);
+ Mat4Mul3Vecfl(G.obedit->obmat, v4mat);
+
+ length[0] = VecLenf(v1mat, v2mat);
+ length[1] = VecLenf(v2mat, v3mat);
+ length[2] = VecLenf(v3mat, v4mat);
+ length[3] = VecLenf(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;
+ }
+ }
+ }
+ 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;
+ }
+ }
+ }
+ sort[hold]->f &= ~SELECT;
+ sort[hold]->f2 |= EDGENEW;
+ length[hold] = -1;
+ }
+ }
+ }
+ }
+ }
+
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut
+ if(beauty & B_KNIFE) {
+ for(eed= em->edges.first;eed;eed=eed->next) {
+ if( 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(eed, i+1, numcuts, rad, beauty);
+ //while we are here, we can copy edge info from the original edge
+ cedge = addedgelist(templist[i],templist[i+1],eed);
+ // Also set the edge f2 to EDGENEW so that we can use this info later
+ cedge->f2 = EDGENEW;
+ }
+ templist[i+1] = eed->v2;
+ //Do the last edge too
+ cedge = addedgelist(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_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ // Now for each face in the mesh we need to figure out How many edges were cut
+ // and which filling method to use for that face
+ for(ef = em->faces.first;ef;ef = ef->next) {
+ 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(ef, 1, 3);
+ }
+ else if(ef->v2->f1 && ef->v4->f1){
+ ef->f1 = SELECT;
+ fill_quad_doublevert(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(ef, gh);
+ }
+ else{
+ ef->f1 = SELECT;
+ fill_quad_single(ef, gh, numcuts, seltype);
+ }
+ }
+ else{
+ ef->f1 = SELECT;
+ fill_quad_single(ef, gh, numcuts, seltype);
+ }
+ }
+ else{
+ ef->f1 = SELECT;
+ fill_quad_single(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(ef, gh, numcuts);
+ }else{
+ switch(G.scene->toolsettings->cornertype) {
+ case 0: fill_quad_double_adj_path(ef, gh, numcuts); break;
+ case 1: fill_quad_double_adj_inner(ef, gh, numcuts); break;
+ case 2: fill_quad_double_adj_fan(ef, gh, numcuts); break;
+ }
+
+ }
+ break;
+ case 3: ef->f1 = SELECT;
+ fill_quad_triple(ef, gh, numcuts);
+ break;
+ case 4: ef->f1 = SELECT;
+ fill_quad_quadruple(ef, gh, numcuts, rad, beauty);
+ break;
+ }
+ } else {
+ switch(edgecount) {
+ case 0: break;
+ case 1: ef->f1 = SELECT;
+ fill_tri_single(ef, gh, numcuts, seltype);
+ break;
+ case 2: ef->f1 = SELECT;
+ fill_tri_double(ef, gh, numcuts);
+ break;
+ case 3: ef->f1 = SELECT;
+ fill_tri_triple(ef, gh, numcuts, rad, beauty);
+ break;
+ }
+ }
+ }
+
+ // Delete Old Edges and Faces
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(BLI_ghash_haskey(gh,eed)) {
+ eed->f1 = SELECT;
+ } else {
+ eed->f1 = 0;
+ }
+ }
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
+ if(seltype == SUBDIV_SELECT_ORIG && G.qual != LR_CTRLKEY) {
+ /* bugfix: vertex could get flagged as "not-selected"
+ // solution: clear flags before, not at the same time as setting SELECT flag -dg
+ */
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) {
+ eed->f &= !flag;
+ EM_select_edge(eed,0);
+ }
+ }
+ 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)|| G.qual == LR_CTRLKEY) {
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(eed->f2 & EDGEINNER) {
+ eed->f |= flag;
+ EM_select_edge(eed,1);
+ 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(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(eed->f & SELECT) {
+ eed->v1->f |= SELECT;
+ eed->v2->f |= SELECT;
+ }
+ }
+ }
+
+ //fix hide flags for edges. First pass, hide edges of hidden faces
+ for(ef=em->faces.first; ef; ef=ef->next){
+ if(ef->h){
+ 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;
+ }
+ }
+
+ // 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();
+ 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();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+#endif
+
+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;
+ vindex[2]= 0;
+ vindex[3]= 1;
+ }
+ else if VTEST(efa1, 2, efa) {
+ *v3= efa1->v2;
+ *v4= efa1->v3;
+ vindex[2]= 1;
+ vindex[3]= 2;
+ }
+ else if VTEST(efa1, 3, efa) {
+ *v3= efa1->v3;
+ *v4= efa1->v1;
+ vindex[2]= 2;
+ vindex[3]= 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(EditEdge *eed, EditFace *efa)
+{
+ EditMesh *em= G.editMesh;
+ EditEdge *nexted;
+ EditFace *nextvl;
+
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f1) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ else
+ /* avoid deleting edges that are still in use */
+ untag_edges(efa);
+ efa= nextvl;
+ }
+
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f1) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+}
+
+/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the
+ edge/face flags, with very mixed results.... */
+void beauty_fill(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1, *v2, *v3, *v4;
+ EditEdge *eed, *nexted;
+ EditEdge dia1, dia2;
+ EditFace *efa, *w;
+ // void **efaar, **efaa;
+ EVPTuple *efaar;
+ EVPtr *efaa;
+ float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
+ int totedge, ok, notbeauty=8, onedone, vindex[4];
+
+ if(multires_test()) return;
+
+ /* - all selected edges with two faces
+ * - find the faces: store them in edges (using datablock)
+ * - per edge: - test convex
+ * - test edge: flip?
+ * - if true: remedge, addedge, all edges at the edge get new face pointers
+ */
+
+ EM_selectmode_set(); // makes sure in selectmode 'face' the edges of selected faces are selected too
+
+ totedge = count_selected_edges(em->edges.first);
+ if(totedge==0) return;
+
+ /* temp block with face pointers */
+ efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
+
+ while (notbeauty) {
+ notbeauty--;
+
+ ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
+
+ /* there we go */
+ onedone= 0;
+
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+
+ /* f2 is set in collect_quadedges() */
+ if(eed->f2==2 && eed->h==0) {
+
+ efaa = (EVPtr *) eed->tmp.p;
+
+ /* none of the faces should be treated before, nor be part of fgon */
+ ok= 1;
+ efa= efaa[0];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+ if(efa->fgonf) ok= 0;
+ efa= efaa[1];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+ if(efa->fgonf) ok= 0;
+
+ if(ok) {
+ /* test convex */
+ givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
+ if(v1 && v2 && v3 && v4) {
+ if( convex(v1->co, v2->co, v3->co, v4->co) ) {
+
+ /* test edges */
+ if( (v1) > (v3) ) {
+ dia1.v1= v3;
+ dia1.v2= v1;
+ }
+ else {
+ dia1.v1= v1;
+ dia1.v2= v3;
+ }
+
+ if( (v2) > (v4) ) {
+ dia2.v1= v4;
+ dia2.v2= v2;
+ }
+ else {
+ dia2.v1= v2;
+ dia2.v2= v4;
+ }
+
+ /* testing rule:
+ * the area divided by the total edge lengths
+ */
+
+ len1= VecLenf(v1->co, v2->co);
+ len2= VecLenf(v2->co, v3->co);
+ len3= VecLenf(v3->co, v4->co);
+ len4= VecLenf(v4->co, v1->co);
+ len5= VecLenf(v1->co, v3->co);
+ len6= VecLenf(v2->co, v4->co);
+
+ opp1= AreaT3Dfl(v1->co, v2->co, v3->co);
+ opp2= AreaT3Dfl(v1->co, v3->co, v4->co);
+
+ fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
+
+ opp1= AreaT3Dfl(v2->co, v3->co, v4->co);
+ opp2= AreaT3Dfl(v2->co, v4->co, v1->co);
+
+ fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
+
+ ok= 0;
+ if(fac1 > fac2) {
+ if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
+ eed->f1= 1;
+ efa= efaa[0];
+ efa->f1= 1;
+ efa= efaa[1];
+ efa->f1= 1;
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], vindex[1], 4+vindex[2], -1);
+ w->f |= SELECT;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], 4+vindex[2], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+ onedone= 1;
+ }
+ }
+ else if(fac1 < fac2) {
+ if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
+ eed->f1= 1;
+ efa= efaa[0];
+ efa->f1= 1;
+ efa= efaa[1];
+ efa->f1= 1;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[1], 4+vindex[2], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], 4+vindex[1], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+ onedone= 1;
+ }
+ }
+ }
+ }
+ }
+
+ }
+ eed= nexted;
+ }
+
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
+ if(onedone==0) break;
+
+ EM_selectmode_set(); // new edges/faces were added
+ }
+
+ MEM_freeN(efaar);
+
+ EM_select_flush();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Beauty Fill");
+}
+
+
+/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
+static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit){
+
+ /*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*/
+ CalcNormFloat(v1->co, v2->co, v3->co, noA1);
+ CalcNormFloat(v1->co, v3->co, v4->co, noA2);
+
+ if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0;
+ else normalADiff = VecAngle2(noA1, noA2);
+ //if(!normalADiff) normalADiff = 179;
+ CalcNormFloat(v2->co, v3->co, v4->co, noB1);
+ CalcNormFloat(v4->co, v1->co, v2->co, noB2);
+
+ if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0;
+ else normalBDiff = VecAngle2(noB1, noB2);
+ //if(!normalBDiff) normalBDiff = 179;
+
+ measure += (normalADiff/360) + (normalBDiff/360);
+ if(measure > limit) return measure;
+
+ /*Second test: Colinearity*/
+ VecSubf(edgeVec1, v1->co, v2->co);
+ VecSubf(edgeVec2, v2->co, v3->co);
+ VecSubf(edgeVec3, v3->co, v4->co);
+ VecSubf(edgeVec4, v4->co, v1->co);
+
+ diff = 0.0;
+
+ diff = (
+ fabs(VecAngle2(edgeVec1, edgeVec2) - 90) +
+ fabs(VecAngle2(edgeVec2, edgeVec3) - 90) +
+ fabs(VecAngle2(edgeVec3, edgeVec4) - 90) +
+ fabs(VecAngle2(edgeVec4, edgeVec1) - 90)) / 360;
+ if(!diff) return 0.0;
+
+ measure += diff;
+ if(measure > limit) return measure;
+
+ /*Third test: Concavity*/
+ areaA = AreaT3Dfl(v1->co, v2->co, v3->co) + AreaT3Dfl(v1->co, v3->co, v4->co);
+ areaB = AreaT3Dfl(v2->co, v3->co, v4->co) + AreaT3Dfl(v4->co, v1->co, v2->co);
+
+ if(areaA <= areaB) minarea = areaA;
+ else minarea = areaB;
+
+ if(areaA >= areaB) maxarea = areaA;
+ else maxarea = areaB;
+
+ if(!maxarea) measure += 1;
+ else measure += (1 - (minarea / maxarea));
+
+ return measure;
+}
+
+#define T2QUV_LIMIT 0.005
+#define T2QCOL_LIMIT 3
+static int compareFaceAttribs(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 = G.scene->toolsettings->editbutflag, fe1[2], fe2[2];
+
+ tf1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MTFACE);
+ tf2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MTFACE);
+
+ col1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MCOL);
+ col2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MCOL);
+
+ /*store indices for faceedges*/
+ f1->v1->f1 = 0;
+ f1->v2->f1 = 1;
+ f1->v3->f1 = 2;
+
+ fe1[0] = eed->v1->f1;
+ fe1[1] = eed->v2->f1;
+
+ f2->v1->f1 = 0;
+ f2->v2->f1 = 1;
+ f2->v3->f1 = 2;
+
+ fe2[0] = eed->v1->f1;
+ fe2[1] = eed->v2->f1;
+
+ /*compare faceedges for each face attribute. Additional per face attributes can be added later*/
+ /*do UVs*/
+ if(flag & B_JOINTRIA_UV){
+
+ if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV;
+ else if(tf1->tpage != tf2->tpage); /*do nothing*/
+ else{
+ 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(void)
+{
+ EditMesh *em=G.editMesh;
+ 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 = G.scene->toolsettings->jointrilimit;
+ int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
+
+ /*test for multi-resolution data*/
+ if(multires_test()) return;
+
+ /*if we take a long time on very dense meshes we want waitcursor to display*/
+ waitcursor(1);
+
+ totseledge = count_selected_edges(em->edges.first);
+ if(totseledge==0) return;
+
+ /*abusing crease value to store weights for edge pairs. Nasty*/
+ for(eed=em->edges.first; eed; eed=eed->next) totedge++;
+ if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array");
+ 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){
+ if( convex(v1->co, v2->co, v3->co, v4->co) ){
+ eed->f1 |= T2QJOIN;
+ efaa[0]->f1 = 1; //mark for join
+ efaa[1]->f1 = 1; //mark for join
+ }
+ }
+ else{
+
+ /* 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.
+ */
+
+ if(G.scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/
+ else if(G.scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/
+ else if(((G.scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (G.scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) &&
+ compareFaceAttribs(efaa[0], efaa[1], eed) == 0); /*do nothing*/
+ else{
+ measure = measure_facepair(v1, v2, v3, v4, limit);
+ if(measure < limit){
+ complexedges++;
+ eed->f1 |= T2QCOMPLEX;
+ eed->crease = measure; /*we dont mark edges for join yet*/
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*Quicksort the complex edges according to their weighting*/
+ if(complexedges){
+ edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array");
+ 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(v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be adressed.*/
+ /*flag for delete*/
+ eed->f1 |= T2QDELETE;
+ /*create new quad and select*/
+ efa = EM_face_from_faces(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->edges.first, em->faces.first);
+ if(efaar) MEM_freeN(efaar);
+ if(edsortblock) MEM_freeN(edsortblock);
+
+ EM_selectmode_flush();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ #ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ #endif
+ waitcursor(0);
+ BIF_undo_push("Convert Triangles to Quads");
+}
+/* ******************** END TRIANGLE TO QUAD ************************************* */
+
+#define FACE_MARKCLEAR(f) (f->f1 = 1)
+
+/* quick hack, basically a copy of beauty_fill */
+void edge_flip(void)
+{
+ EditMesh *em = G.editMesh;
+ 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(); // 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(v1, v2, v3, v4)==0) {
+ /* outch this may break seams */
+ w= EM_face_from_faces(efaa[0], efaa[1], vindex[0],
+ vindex[1], 4+vindex[2], -1);
+
+ EM_select_face(w, 1);
+
+ /* outch this may break seams */
+ w= EM_face_from_faces(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->edges.first, em->faces.first);
+
+ MEM_freeN(efaar);
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Flip Triangle Edges");
+
+}
+
+static void edge_rotate(EditEdge *eed,int dir)
+{
+ EditMesh *em = G.editMesh;
+ EditVert **verts[2];
+ EditFace *face[2], *efa, *newFace[2];
+ EditEdge **edges[2], **hiddenedges, *srchedge;
+ int facecount, p1, p2, p3, p4, fac1, fac2, i, j;
+ int numhidden, numshared, p[2][4];
+
+ /* check to make sure that the edge is only part of 2 faces */
+ facecount = 0;
+ for(efa = em->faces.first;efa;efa = efa->next) {
+ 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;
+
+ /* coplaner faces only please */
+ if(Inpf(face[0]->n,face[1]->n) <= 0.000001)
+ return;
+
+ /* we want to construct an array of vertex indicis in both faces, starting at
+ the last vertex of the edge being rotated.
+ - first we find the two vertices that lie on the rotating edge
+ - 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) {
+ error("Malloc Was not happy!");
+ 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]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
+ }
+ else if(fac1 == 4 && fac2 == 3) {
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1);
+
+ verts[0][p[0][2]]->f |= SELECT;
+ verts[1][p[1][1]]->f |= SELECT;
+ }
+ }
+ else if(fac1 == 3 && fac2 == 4) {
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]);
+
+ verts[0][p[0][1]]->f |= SELECT;
+ verts[1][p[1][2]]->f |= SELECT;
+ }
+
+ }
+ else if(fac1 == 4 && fac2 == 4) {
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]);
+
+ verts[0][p[0][2]]->f |= SELECT;
+ verts[1][p[1][2]]->f |= SELECT;
+ }
+ }
+ else
+ return; /* This should never happen */
+
+ if(dir == 1 || (fac1 == 3 && fac2 == 3)) {
+ verts[0][p[0][1]]->f |= SELECT;
+ verts[1][p[1][1]]->f |= SELECT;
+ }
+
+ /* copy old edge's flags to new center edge*/
+ for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) {
+ if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) {
+ srchedge->f = eed->f;
+ srchedge->h = eed->h;
+ srchedge->dir = eed->dir;
+ srchedge->seam = eed->seam;
+ 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(eed);
+ free_editedge(eed);
+ BLI_remlink(&em->faces, face[0]);
+ free_editface(face[0]);
+ BLI_remlink(&em->faces, face[1]);
+ free_editface(face[1]);
+}
+
+/* only accepts 1 selected edge, or 2 selected faces */
+void edge_rotate_selected(int dir)
+{
+ EditEdge *eed;
+ EditFace *efa;
+ short edgeCount = 0;
+
+ /*clear new flag for new edges, count selected edges */
+ for(eed= G.editMesh->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= G.editMesh->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ }
+ edgeCount= 0;
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
+ if(eed->f1==2) edgeCount++;
+ }
+ if(edgeCount==1) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
+ if(eed->f1==2) {
+ edge_rotate(eed,dir);
+ break;
+ }
+ }
+ }
+ else error("Select one edge or two adjacent faces");
+ }
+ else if(edgeCount==1) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
+ if(eed->f & SELECT) {
+ EM_select_edge(eed, 0);
+ edge_rotate(eed,dir);
+ break;
+ }
+ }
+ }
+ else error("Select one edge or two adjacent faces");
+
+
+ /* flush selected vertices (again) to edges/faces */
+ EM_select_flush();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Rotate Edge");
+}
+
+/******************* BEVEL CODE STARTS HERE ********************/
+
+static void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3])
+{
+ float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac;
+
+ VecSubf(a, v1, v2);
+ VecSubf(c, v3, v2);
+
+ Crossf(n_a, a, no);
+ Normalize(n_a);
+ Crossf(n_c, no, c);
+ Normalize(n_c);
+
+ Normalize(a);
+ Normalize(c);
+ ac = Inpf(a, c);
+
+ if (ac == 1 || ac == -1) {
+ midvec[0] = midvec[1] = midvec[2] = 0;
+ return;
+ }
+ ac2 = ac * ac;
+ fac = (float)sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1);
+ VecAddf(mid, n_c, n_a);
+ Normalize(mid);
+ VecMulf(mid, d * fac);
+ VecAddf(mid, mid, v2);
+ VecCopyf(midvec, mid);
+}
+
+/* Finds the new point using the sinus law to extrapolate a triangle
+ Lots of sqrts which would not be good for a real time algo
+ Using the mid point of the extrapolation of both sides
+ Useless for coplanar quads, but that doesn't happen too often */
+static void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3])
+{
+ float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3];
+
+ VecSubf(a, v3, v2);
+ l_a = Normalize(a);
+ VecSubf(b, v4, v3);
+ Normalize(b);
+ VecSubf(c, v1, v2);
+ Normalize(c);
+
+ s_b = Inpf(a, c);
+ s_b = (float)sqrt(1 - (s_b * s_b));
+ s_a = Inpf(b, c);
+ s_a = (float)sqrt(1 - (s_a * s_a));
+ VecMulf(a, -1);
+ s_c = Inpf(a, b);
+ s_c = (float)sqrt(1 - (s_c * s_c));
+
+ l_b = s_b * l_a / s_a;
+ l_c = s_c * l_a / s_a;
+
+ VecMulf(b, l_b);
+ VecMulf(c, l_c);
+
+ VecAddf(Pos1, v2, c);
+ VecAddf(Pos2, v3, b);
+
+ VecAddf(Dir, Pos1, Pos2);
+ VecMulf(Dir, 0.5);
+
+ bevel_displace_vec(midvec, v3, Dir, v2, d, no);
+
+}
+
+
+static char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no)
+{
+ float o_a[3], a[3], o_c[3], c[3];
+
+ VecSubf(o_a, o_v1, o_v2);
+ VecSubf(a, v1, v2);
+
+ Crossf(o_c, o_a, no);
+ Crossf(c, a, no);
+
+ if (Inpf(c, o_c) <= 0)
+ return 1;
+ else
+ return 0;
+}
+
+// Detects and fix a quad wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal
+static void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no)
+{
+ float vec[3];
+ char wrap[4];
+
+ // Quads can wrap partially. Watch out
+ wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2
+ wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3
+ wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4
+ wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1
+
+ // Edge 1 inverted
+ if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ }
+ // Edge 2 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+ // Edge 3 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) {
+ fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no);
+ VECCOPY(v4, vec);
+ VECCOPY(v1, vec);
+ }
+ // Edge 2 and 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) {
+ VecAddf(vec, v2, v3);
+ VecMulf(vec, 0.5);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ VecAddf(vec, v1, v4);
+ VecMulf(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 1 and 3 inverted
+ else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ VecAddf(vec, v1, v2);
+ VecMulf(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VecAddf(vec, v3, v4);
+ VecMulf(vec, 0.5);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Totally inverted
+ else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) {
+ VecAddf(vec, v1, v2);
+ VecAddf(vec, vec, v3);
+ VecAddf(vec, vec, v4);
+ VecMulf(vec, 0.25);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+
+}
+
+// Detects and fix a tri wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and the normal
+// Triangles cannot wrap partially (not in this situation
+static void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no)
+{
+ if (detect_wrap(o_v1, o_v2, v1, v2, no)) {
+ float vec[3];
+ VecAddf(vec, o_v1, o_v2);
+ VecAddf(vec, vec, o_v3);
+ VecMulf(vec, 1.0f/3.0f);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+}
+
+static void bevel_shrink_faces(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centers */
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & flag) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, efa->v1->co, efa->v2->co, efa->v3->co, no);
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(efa->v4->co, vec);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, d, no);
+ }
+ }
+ efa= efa->next;
+ }
+}
+
+static void bevel_shrink_draw(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centers */
+ efa= em->faces.first;
+ while (efa) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv3);
+ glEnd();
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(fv4, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv3);
+ glVertex3fv(fv4);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv4);
+ glEnd();
+ }
+ efa= efa->next;
+ }
+}
+
+static void bevel_mesh(float bsize, int allfaces)
+{
+ EditMesh *em = G.editMesh;
+//#define BEV_DEBUG
+/* Enables debug printfs and assigns material indices: */
+/* 2 = edge quad */
+/* 3 = fill polygon (vertex clusters) */
+
+ EditFace *efa, *example; //, *nextvl;
+ EditEdge *eed, *eed2;
+ EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4;
+ //short found4, search;
+ //float f1, f2, f3, f4;
+ float cent[3], min[3], max[3];
+ int a, b, c;
+ float limit= 0.001f;
+
+ if(multires_test()) return;
+
+ waitcursor(1);
+
+ removedoublesflag(1, 0, limit);
+
+ /* tag all original faces */
+ efa= em->faces.first;
+ while (efa) {
+ efa->f1= 0;
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 1;
+ efa->v1->f |= 128;
+ efa->v2->f |= 128;
+ efa->v3->f |= 128;
+ if (efa->v4) efa->v4->f |= 128;
+ }
+ efa->v1->f &= ~64;
+ efa->v2->f &= ~64;
+ efa->v3->f &= ~64;
+ if (efa->v4) efa->v4->f &= ~64;
+
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: split\n");
+#endif
+
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & 1) {
+ efa->f1-= 1;
+ v1= addvertlist(efa->v1->co, efa->v1);
+ v1->f= efa->v1->f & ~128;
+ efa->v1->tmp.v = v1;
+
+ v1= addvertlist(efa->v2->co, efa->v2);
+ v1->f= efa->v2->f & ~128;
+ efa->v2->tmp.v = v1;
+
+ v1= addvertlist(efa->v3->co, efa->v3);
+ v1->f= efa->v3->f & ~128;
+ efa->v3->tmp.v = v1;
+
+ if (efa->v4) {
+ v1= addvertlist(efa->v4->co, efa->v4);
+ v1->f= efa->v4->f & ~128;
+ efa->v4->tmp.v = v1;
+ }
+
+ /* Needs better adaption of creases? */
+ addedgelist(efa->e1->v1->tmp.v,
+ efa->e1->v2->tmp.v,
+ efa->e1);
+ addedgelist(efa->e2->v1->tmp.v,
+ efa->e2->v2->tmp.v,
+ efa->e2);
+ addedgelist(efa->e3->v1->tmp.v,
+ efa->e3->v2->tmp.v,
+ efa->e3);
+ if (efa->e4) addedgelist(efa->e4->v1->tmp.v,
+ efa->e4->v2->tmp.v,
+ efa->e4);
+
+ if(efa->v4) {
+ v1 = efa->v1->tmp.v;
+ v2 = efa->v2->tmp.v;
+ v3 = efa->v3->tmp.v;
+ v4 = efa->v4->tmp.v;
+ addfacelist(v1, v2, v3, v4, efa,NULL);
+ } else {
+ v1= efa->v1->tmp.v;
+ v2= efa->v2->tmp.v;
+ v3= efa->v3->tmp.v;
+ addfacelist(v1, v2, v3, 0, efa,NULL);
+ }
+
+ efa= efa-> next;
+ } else {
+ efa= efa->next;
+ }
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if( (efa->v1->f & 128) && (efa->v2->f & 128) && (efa->v3->f & 128) ) {
+ if(efa->v4==NULL || (efa->v4->f & 128)) efa->f |= 128;
+ }
+ }
+
+ delfaceflag(128); // works with face flag now
+
+ /* tag all faces for shrink*/
+ efa= em->faces.first;
+ while (efa) {
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 2;
+ }
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: make edge quads\n");
+#endif
+
+ /* find edges that are on each other and make quads between them */
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= eed->f1= 0;
+ if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces)
+ eed->f1 |= 4; /* original edges */
+ eed->tmp.v = 0;
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while (eed) {
+ if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) {
+ eed2= em->edges.first;
+ while (eed2) {
+ if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) {
+ if (
+ (eed->v1 != eed2->v1) &&
+ (eed->v1 != eed2->v2) &&
+ (eed->v2 != eed2->v1) &&
+ (eed->v2 != eed2->v2) && (
+ ( VecCompare(eed->v1->co, eed2->v1->co, limit) &&
+ VecCompare(eed->v2->co, eed2->v2->co, limit) ) ||
+ ( VecCompare(eed->v1->co, eed2->v2->co, limit) &&
+ VecCompare(eed->v2->co, eed2->v1->co, limit) ) ) )
+ {
+
+#ifdef BEV_DEBUG
+ fprintf(stderr, "bevel_mesh: edge quad\n");
+#endif
+
+ eed->f1 |= 2; /* these edges are finished */
+ eed2->f1 |= 2;
+
+ example= NULL;
+ efa= em->faces.first; /* search example face (for mat_nr, ME_SMOOTH, ...) */
+ while (efa) {
+ if ( (efa->e1 == eed) ||
+ (efa->e2 == eed) ||
+ (efa->e3 == eed) ||
+ (efa->e4 && (efa->e4 == eed)) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+
+ neweve[0]= eed->v1; neweve[1]= eed->v2;
+ neweve[2]= eed2->v1; neweve[3]= eed2->v2;
+
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ efa= NULL;
+
+ if (VecCompare(eed->v1->co, eed2->v2->co, limit)) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example,NULL);
+ } else {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example,NULL);
+ }
+
+ if(efa) {
+ float inp;
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 1;
+#endif
+ } else fprintf(stderr,"bevel_mesh: error creating face\n");
+ }
+ eed2= NULL;
+ }
+ }
+ if (eed2) eed2= eed2->next;
+ }
+ }
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= eed->f1= 0;
+ eed->f1= 0;
+ eed->v1->f1 &= ~1;
+ eed->v2->f1 &= ~1;
+ eed->tmp.v = 0;
+ eed= eed->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: find clusters\n");
+#endif
+
+ /* Look for vertex clusters */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~(64|128);
+ eve->tmp.v = NULL;
+ eve= eve->next;
+ }
+
+ /* eve->f: 128: first vertex in a list (->tmp.v) */
+ /* 64: vertex is in a list */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve2= em->verts.first;
+ eve3= NULL;
+ while (eve2) {
+ if ((eve2 != eve) && ((eve2->f & (64|128))==0)) {
+ if (VecCompare(eve->co, eve2->co, limit)) {
+ if ((eve->f & (128|64)) == 0) {
+ /* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */
+ eve->f |= 128;
+ eve->tmp.v = eve2;
+ eve3= eve2;
+ } else if ((eve->f & 64) == 0) {
+ /* fprintf(stderr," *\n"); */
+ if (eve3) eve3->tmp.v = eve2;
+ eve2->f |= 64;
+ eve3= eve2;
+ }
+ }
+ }
+ eve2= eve2->next;
+ if (!eve2) {
+ if (eve3) eve3->tmp.v = NULL;
+ }
+ }
+ eve= eve->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: shrink faces\n");
+#endif
+
+ bevel_shrink_faces(bsize, 2);
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: fill clusters\n");
+#endif
+
+ /* Make former vertex clusters faces */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~64;
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ if (eve->f & 128) {
+ eve->f &= ~128;
+ a= 0;
+ neweve[a]= eve;
+ eve2 = eve->tmp.v;
+ while (eve2) {
+ a++;
+ neweve[a]= eve2;
+ eve2 = eve2->tmp.v;
+ }
+ a++;
+ efa= NULL;
+ if (a>=3) {
+ example= NULL;
+ efa= em->faces.first; /* search example face */
+ while (efa) {
+ if ( (efa->v1 == neweve[0]) ||
+ (efa->v2 == neweve[0]) ||
+ (efa->v3 == neweve[0]) ||
+ (efa->v4 && (efa->v4 == neweve[0])) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: Making %d-gon\n", a);
+#endif
+ if (a>4) {
+ cent[0]= cent[1]= cent[2]= 0.0;
+ INIT_MINMAX(min, max);
+ for (b=0; b<a; b++) {
+ VecAddf(cent, cent, neweve[b]->co);
+ DO_MINMAX(neweve[b]->co, min, max);
+ }
+ cent[0]= (min[0]+max[0])/2;
+ cent[1]= (min[1]+max[1])/2;
+ cent[2]= (min[2]+max[2])/2;
+ eve2= addvertlist(cent, NULL);
+ eve2->f |= 1;
+ eed= em->edges.first;
+ while (eed) {
+ c= 0;
+ for (b=0; b<a; b++)
+ if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++;
+ if (c==2) {
+ if(exist_face(eed->v1, eed->v2, eve2, 0)==0) {
+ efa= addfacelist(eed->v1, eed->v2, eve2, 0, example,NULL);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ eed= eed->next;
+ }
+ } else if (a==4) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ /* the order of vertices can be anything, three cases to check */
+ if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
+ }
+ }
+ }
+ else if (a==3) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0)
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, example, NULL);
+ }
+ if(efa) {
+ float inp;
+ CalcNormFloat(neweve[0]->co, neweve[1]->co, neweve[2]->co, efa->n);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ }
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f1= 0;
+ eve->f &= ~(128|64);
+ eve->tmp.v= NULL;
+ eve= eve->next;
+ }
+
+ recalc_editnormals();
+ waitcursor(0);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ removedoublesflag(1, 0, limit);
+
+ /* flush selected vertices to edges/faces */
+ EM_select_flush();
+
+#undef BEV_DEBUG
+}
+
+static void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
+{
+ float d;
+ short nr;
+
+ d= bsize;
+ for (nr=0; nr<recurs; nr++) {
+ bevel_mesh(d, allfaces);
+ if (nr==0) d /= 3; else d /= 2;
+ }
+}
+
+void bevel_menu(void) {
+ BME_Mesh *bm;
+ BME_TransData_Head *td;
+ TransInfo *t;
+ 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(G.editMesh);
+ BIF_undo_push("Pre-Bevel");
+ free_editMesh(G.editMesh);
+ BME_bevel(bm,0.1f,res,options,0,0,&td);
+ BME_bmesh_to_editmesh(bm, td);
+ EM_selectmode_flush();
+ 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;
+ }
+}
+
+
+void bevel_menu_old()
+{
+ char Finished = 0, Canceled = 0, str[100], Recalc = 0;
+ short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr;
+ float vec[3], d, drawd=0.0, center[3], fac = 1;
+
+ getmouseco_areawin(mval);
+ oval[0] = mval[0]; oval[1] = mval[1];
+
+ // Silly hackish code to initialise the variable (warning if not done)
+ // while still drawing in the first iteration (and without using another variable)
+ curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
+
+ // Init grabz for window to vec conversions
+ initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
+ window_to_3d(center, mval[0], mval[1]);
+
+ if(button(&recurs, 1, 4, "Recursion:")==0) return;
+
+ for (nr=0; nr<recurs-1; nr++) {
+ if (nr==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * nr * 2.0f);
+ }
+
+ EM_set_flag_all(SELECT);
+
+ SetBlenderCursor(SYSCURSOR);
+
+ while (Finished == 0)
+ {
+ getmouseco_areawin(mval);
+ if (mval[0] != curval[0] || mval[1] != curval[1] || (Recalc == 1))
+ {
+ Recalc = 0;
+ curval[0] = mval[0];
+ curval[1] = mval[1];
+
+ window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]);
+ d = Normalize(vec) / 10;
+
+
+ drawd = d * fac;
+ if (G.qual & LR_CTRLKEY)
+ drawd = (float) floor(drawd * 10.0f)/10.0f;
+ if (G.qual & LR_SHIFTKEY)
+ drawd /= 10;
+
+ /*------------- Preview lines--------------- */
+
+ /* uses callback mechanism to draw it all in current area */
+ scrarea_do_windraw(curarea);
+
+ /* set window matrix to perspective, default an area returns with buttons transform */
+ persp(PERSP_VIEW);
+ /* make a copy, for safety */
+ glPushMatrix();
+ /* multiply with the object transformation */
+ mymultmatrix(G.obedit->obmat);
+
+ glColor3ub(255, 255, 0);
+
+ // PREVIEW CODE GOES HERE
+ bevel_shrink_draw(drawd, 2);
+
+ /* restore matrix transform */
+ glPopMatrix();
+
+ sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd);
+ headerprint(str);
+
+ /* this also verifies other area/windows for clean swap */
+ screen_swapbuffers();
+
+ persp(PERSP_WIN);
+
+ glDrawBuffer(GL_FRONT);
+
+ BIF_ThemeColor(TH_WIRE);
+
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ glVertex2sv(mval);
+ glVertex2sv(oval);
+ glEnd();
+ setlinestyle(0);
+
+ persp(PERSP_VIEW);
+ bglFlush(); // flush display for frontbuffer
+ glDrawBuffer(GL_BACK);
+ }
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
+
+ /* val==0 on key-release event */
+ if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)) {
+ if (event==RIGHTMOUSE || event==ESCKEY)
+ Canceled = 1;
+ Finished = 1;
+ }
+ else if (val && event==SPACEKEY) {
+ if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) {
+ drawd = d * fac;
+ Finished = 1;
+ }
+ }
+ else if (val) {
+ /* On any other keyboard event, recalc */
+ Recalc = 1;
+ }
+
+ }
+ }
+ if (Canceled==0) {
+ SetBlenderCursor(BC_WAITCURSOR);
+ bevel_mesh_recurs(drawd/fac, recurs, 1);
+ righthandfaces(1);
+ SetBlenderCursor(SYSCURSOR);
+ BIF_undo_push("Bevel");
+ }
+}
+
+/* *********** END BEVEL *********/
+typedef struct SlideUv {
+ float origuv[2];
+ float *uv_up, *uv_down;
+ //float *fuv[4];
+ LinkNode *fuv_list;
+} SlideUv;
+
+typedef struct SlideVert {
+ EditEdge *up,*down;
+ EditVert origvert;
+} SlideVert;
+
+int EdgeLoopDelete(void) {
+
+ /* temporal flag setting so we keep UVs when deleting edge loops,
+ * this is a bit of a hack but it works how you would want in almost all cases */
+ short uvcalc_flag_orig = G.scene->toolsettings->uvcalc_flag;
+ G.scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
+
+ if(!EdgeSlide(1, 1)) {
+ return 0;
+ }
+
+ /* restore uvcalc flag */
+ G.scene->toolsettings->uvcalc_flag = uvcalc_flag_orig;
+
+ EM_select_more();
+ removedoublesflag(1,0, 0.001);
+ EM_select_flush();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ return 1;
+}
+
+int EdgeSlide(short immediate, float imperc)
+{
+ NumInput num;
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL;
+ EditVert *ev, *nearest;
+ LinkNode *edgelist = NULL, *vertlist=NULL, *look;
+ GHash *vertgh;
+
+ SlideVert *tempsv;
+ float perc = 0, percp = 0,vertdist, projectMat[4][4], viewMat[4][4];
+ float shiftlabda= 0.0f,len = 0.0f;
+ int i = 0,j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0;
+ int wasshift = 0;
+
+ /* UV correction vars */
+ GHash **uvarray= NULL;
+ int uvlay_tot= CustomData_number_of_layers(&G.editMesh->fdata, CD_MTFACE);
+ int uvlay_idx;
+ SlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL;
+ float uv_tmp[2];
+ LinkNode *fuv_link;
+
+ short event, draw=1;
+ short mval[2], mvalo[2];
+ char str[128];
+ float labda = 0.0f;
+
+ initNumInput(&num);
+
+ view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat);
+
+ mvalo[0] = -1; mvalo[1] = -1;
+ numsel =0;
+
+ // Get number of selected edges and clear some flags
+ for(eed=em->edges.first;eed;eed=eed->next) {
+ eed->f1 = 0;
+ eed->f2 = 0;
+ if(eed->f & SELECT) numsel++;
+ }
+
+ for(ev=em->verts.first;ev;ev=ev->next) {
+ ev->f1 = 0;
+ }
+
+ //Make sure each edge only has 2 faces
+ // make sure loop doesn't cross face
+ for(efa=em->faces.first;efa;efa=efa->next) {
+ int ct = 0;
+ if(efa->e1->f & SELECT) {
+ ct++;
+ efa->e1->f1++;
+ if(efa->e1->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ if(efa->e2->f & SELECT) {
+ ct++;
+ efa->e2->f1++;
+ if(efa->e2->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ if(efa->e3->f & SELECT) {
+ ct++;
+ efa->e3->f1++;
+ if(efa->e3->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ if(efa->e4 && efa->e4->f & SELECT) {
+ ct++;
+ efa->e4->f1++;
+ if(efa->e4->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ // Make sure loop is not 2 edges of same face
+ if(ct > 1) {
+ error("loop crosses itself");
+ return 0;
+ }
+ }
+ // Get # of selected verts
+ for(ev=em->verts.first;ev;ev=ev->next) {
+ if(ev->f & SELECT) vertsel++;
+ }
+
+ // Test for multiple segments
+ if(vertsel > numsel+1) {
+ error("Was not a single edge loop");
+ return 0;
+ }
+
+ // Get the edgeloop in order - mark f1 with SELECT once added
+ for(eed=em->edges.first;eed;eed=eed->next) {
+ if((eed->f & SELECT) && !(eed->f1 & SELECT)) {
+ // 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++;
+ }
+
+ // It looks like there was an unexpected case - Hopefully should not happen
+ if(timesthrough >= numsel*2) {
+ BLI_linklist_free(edgelist,NULL);
+ error("could not order loop");
+ 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;
+
+ //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);
+ look = vertlist;
+ while(look) {
+ i=0;
+ j=0;
+ ev = look->link;
+ tempsv = (struct SlideVert*)MEM_mallocN(sizeof(struct SlideVert),"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(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;
+ }
+
+ // make sure the UPs nad DOWNs are 'faceloops'
+ // Also find the nearest slidevert to the cursor
+ getmouseco_areawin(mval);
+ look = vertlist;
+ nearest = NULL;
+ vertdist = -1;
+ while(look) {
+ tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
+
+ if(!tempsv->up || !tempsv->down) {
+ error("Missing rails");
+ BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
+ return 0;
+ }
+
+ if(G.f & G_DRAW_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;
+ }
+ }
+
+ if(look->next != NULL) {
+ SlideVert *sv;
+
+ sv = BLI_ghash_lookup(vertgh,(EditVert*)look->next->link);
+
+ if(sv) {
+ float tempdist, co[2];
+
+ if(!sharesFace(tempsv->up,sv->up)) {
+ EditEdge *swap;
+ swap = sv->up;
+ sv->up = sv->down;
+ sv->down = swap;
+ }
+
+ view3d_project_float(curarea, tempsv->origvert.co, co, projectMat);
+
+ tempdist = sqrt(pow(co[0] - mval[0],2)+pow(co[1] - mval[1],2));
+
+ if(vertdist < 0) {
+ vertdist = tempdist;
+ nearest = (EditVert*)look->link;
+ } else if ( tempdist < vertdist ) {
+ vertdist = tempdist;
+ nearest = (EditVert*)look->link;
+ }
+ }
+ }
+
+
+
+ look = look->next;
+ }
+
+
+ if (uvlay_tot && (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
+ int maxnum = 0;
+ uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array");
+ suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(SlideUv), "SlideUVs"); /* uvLayers * verts */
+ suv = NULL;
+
+ for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
+
+ uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ 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 (fabs(suv->origuv[0]-uv_new[0]) > 0.0001 || fabs(suv->origuv[1]-uv_new[1])) {
+ 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);
+ }
+ }
+ }
+ }
+ look = look->next;
+ }
+ } /* end uv layer loop */
+ } /* end uvlay_tot */
+
+
+
+ // we should have enough info now to slide
+
+ len = 0.0f;
+
+ percp = -1;
+ while(draw) {
+ /* For the % calculation */
+ short mval[2];
+ float rc[2];
+ float v2[2], v3[2];
+ EditVert *centerVert, *upVert, *downVert;
+
+ getmouseco_areawin(mval);
+
+ if (!immediate && (mval[0] == mvalo[0] && mval[1] == mvalo[1])) {
+ PIL_sleep_ms(10);
+ } else {
+ char *p = str;;
+
+ mvalo[0] = mval[0];
+ mvalo[1] = mval[1];
+
+
+ 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);
+
+ view3d_project_float(curarea, upVert->co, v2, projectMat);
+ view3d_project_float(curarea, downVert->co, v3, projectMat);
+
+ /* Determine the % on which the loop should be cut */
+
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
+ len= rc[0]*rc[0]+ rc[1]*rc[1];
+ if (len==0) {len = 0.0001;}
+
+ if ((G.qual & LR_SHIFTKEY)==0) {
+ wasshift = 0;
+ labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len;
+ }
+ else {
+ if (wasshift==0) {
+ wasshift = 1;
+ shiftlabda = labda;
+ }
+ labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda;
+ }
+
+
+ if(labda<=0.0) labda=0.0;
+ else if(labda>=1.0)labda=1.0;
+
+ perc=((1-labda)*2)-1;
+
+ if(G.qual == 0) {
+ perc *= 100;
+ perc = floor(perc);
+ perc /= 100;
+ } else if (G.qual == LR_CTRLKEY) {
+ perc *= 10;
+ perc = floor(perc);
+ perc /= 10;
+ }
+
+ if(prop == 0) {
+ len = VecLenf(upVert->co,downVert->co)*((perc+1)/2);
+ if(flip == 1) {
+ len = VecLenf(upVert->co,downVert->co) - len;
+ }
+ }
+
+ if (hasNumInput(&num))
+ {
+ applyNumInput(&num, &perc);
+
+ if (prop)
+ {
+ perc = MIN2(perc, 1);
+ perc = MAX2(perc, -1);
+ }
+ else
+ {
+ len = MIN2(perc, VecLenf(upVert->co,downVert->co));
+ len = MAX2(len, 0);
+ }
+ }
+
+ //Adjust Edgeloop
+ if(immediate) {
+ perc = imperc;
+ }
+ percp = perc;
+ 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);
+ VecLerpf(ev->co, tempsv->origvert.co, tempev->co, fabs(perc));
+
+ if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
+ for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
+ suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
+ if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
+ Vec2Lerpf(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc));
+ fuv_link = suv->fuv_list;
+ while (fuv_link) {
+ VECCOPY2D(((float *)fuv_link->link), uv_tmp);
+ fuv_link = fuv_link->next;
+ }
+ }
+ }
+ }
+
+ look = look->next;
+ }
+ }
+ else {
+ //Non prop code
+ look = vertlist;
+ while(look) {
+ float newlen;
+ ev = look->link;
+ tempsv = BLI_ghash_lookup(vertgh,ev);
+ newlen = (len / VecLenf(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co));
+ if(newlen > 1.0) {newlen = 1.0;}
+ if(newlen < 0.0) {newlen = 0.0;}
+ if(flip == 0) {
+ VecLerpf(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen));
+ if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
+ /* dont do anything if no UVs */
+ for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
+ suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
+ if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
+ Vec2Lerpf(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen));
+ fuv_link = suv->fuv_list;
+ while (fuv_link) {
+ VECCOPY2D(((float *)fuv_link->link), uv_tmp);
+ fuv_link = fuv_link->next;
+ }
+ }
+ }
+ }
+ } else{
+ VecLerpf(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen));
+
+ if (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
+ /* dont do anything if no UVs */
+ for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
+ suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
+ if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
+ Vec2Lerpf(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen));
+ fuv_link = suv->fuv_list;
+ while (fuv_link) {
+ VECCOPY2D(((float *)fuv_link->link), uv_tmp);
+ fuv_link = fuv_link->next;
+ }
+ }
+ }
+ }
+ }
+ look = look->next;
+ }
+
+ }
+
+ // Highlight the Control Edges
+ scrarea_do_windraw(curarea);
+ persp(PERSP_VIEW);
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
+
+ glColor3ub(0, 255, 0);
+ glBegin(GL_LINES);
+ glVertex3fv(upVert->co);
+ glVertex3fv(downVert->co);
+ glEnd();
+
+ if(prop == 0) {
+ // draw start edge for non-prop
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ glColor3ub(255,0,255);
+ if(flip) {
+ glVertex3fv(upVert->co);
+ } else {
+ glVertex3fv(downVert->co);
+ }
+ glEnd();
+ }
+
+
+ glPopMatrix();
+
+ if(prop) {
+ p += sprintf(str, "(P)ercentage: ");
+ } else {
+ p += sprintf(str, "Non (P)rop Length: ");
+ }
+
+ if (hasNumInput(&num))
+ {
+ char num_str[20];
+
+ outputNumInput(&num, num_str);
+ p += sprintf(p, "%s", num_str);
+ }
+ else
+ {
+ if (prop)
+ {
+ p += sprintf(p, "%f", perc);
+ }
+ else
+ {
+ p += sprintf(p, "%f", len);
+ }
+ }
+
+
+ if (prop == 0) {
+ p += sprintf(p, ", Press (F) to flip control side");
+ }
+
+ headerprint(str);
+ screen_swapbuffers();
+ }
+ if(!immediate) {
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
+
+ /* val==0 on key-release event */
+ if (val) {
+ if(ELEM(event, ESCKEY, RIGHTMOUSE)) {
+ prop = 1; // Go back to prop mode
+ imperc = 0; // This is the % that gets set for immediate
+ immediate = 1; //Run through eval code 1 more time
+ cancel = 1; // Return -1
+ mvalo[0] = -1;
+ } else if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)) {
+ draw = 0; // End looping now
+ } else if(event==MIDDLEMOUSE) {
+ perc = 0;
+ immediate = 1;
+ } else if(event==PKEY) {
+ initNumInput(&num); /* reset num input */
+ if (prop) {
+ prop = 0;
+ num.flag |= NUM_NO_NEGATIVE;
+ }
+ else {
+ prop = 1;
+ }
+ mvalo[0] = -1;
+ } else if(event==FKEY) {
+ (flip == 1) ? (flip = 0):(flip = 1);
+ mvalo[0] = -1;
+ } else if(ELEM(event, RIGHTARROWKEY, WHEELUPMOUSE)) { // Scroll through Control Edges
+ look = vertlist;
+ while(look) {
+ if(nearest == (EditVert*)look->link) {
+ if(look->next == NULL) {
+ nearest = (EditVert*)vertlist->link;
+ } else {
+ nearest = (EditVert*)look->next->link;
+ }
+ mvalo[0] = -1;
+ break;
+ }
+ look = look->next;
+ }
+ } else if(ELEM(event, LEFTARROWKEY, WHEELDOWNMOUSE)) { // Scroll through Control Edges
+ look = vertlist;
+ while(look) {
+ if(look->next) {
+ if(look->next->link == nearest) {
+ nearest = (EditVert*)look->link;
+ mvalo[0] = -1;
+ break;
+ }
+ } else {
+ if((EditVert*)vertlist->link == nearest) {
+ nearest = look->link;
+ mvalo[0] = -1;
+ break;
+ }
+ }
+ look = look->next;
+ }
+ }
+
+ if (handleNumInput(&num, event))
+ {
+ mvalo[0] = -1; /* NEED A BETTER WAY TO TRIGGER REDRAW */
+ }
+ }
+
+ }
+ } else {
+ draw = 0;
+ }
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+
+
+ if(G.f & G_DRAW_EDGELEN) {
+ look = vertlist;
+ while(look) {
+ tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
+ if(tempsv != NULL) {
+ tempsv->up->f &= !SELECT;
+ tempsv->down->f &= !SELECT;
+ }
+ look = look->next;
+ }
+ }
+
+ force_draw(0);
+
+ if(!immediate)
+ EM_automerge(0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ scrarea_queue_winredraw(curarea);
+
+ //BLI_ghash_free(edgesgh, freeGHash, NULL);
+ BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
+
+ if (uvlay_tot && (G.scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
+ for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
+ BLI_ghash_free(uvarray[uvlay_idx], NULL, NULL);
+ }
+ MEM_freeN(uvarray);
+ MEM_freeN(slideuvs);
+
+ suv = suv_last-1;
+ while (suv >= slideuvs) {
+ if (suv->fuv_list) {
+ BLI_linklist_free(suv->fuv_list,NULL);
+ }
+ suv--;
+ }
+
+ allqueue(REDRAWIMAGE, 0);
+ }
+
+ if(cancel == 1) {
+ return -1;
+ }
+ else {
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ }
+#endif
+ }
+ return 1;
+}
+
+/* -------------------- More tools ------------------ */
+
+void mesh_set_face_flags(short mode)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+ short m_tex=0, m_tiles=0, m_shared=0,
+ m_light=0, m_invis=0, m_collision=0,
+ m_twoside=0, m_obcolor=0, m_halo=0,
+ m_billboard=0, m_shadow=0, m_text=0,
+ m_sort=0;
+ short flag = 0, change = 0;
+
+ if (!EM_texFaceCheck()) {
+ error("not a mesh with uv/image layers");
+ return;
+ }
+
+ add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL);
+ add_numbut(1, TOG|SHO, "Tiles", 0, 0, &m_tiles, NULL);
+ add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL);
+ add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL);
+ add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL);
+ 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_tiles) flag |= TF_TILES;
+ 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;
+ }
+
+ if (change) {
+ BIF_undo_push((mode ? "Set Flags" : "Clear Flags"));
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+void mesh_set_smooth_faces(short event)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ if(G.obedit==0) return;
+
+ if(G.obedit->type != OB_MESH) return;
+
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f & SELECT) {
+ if(event==1) efa->flag |= ME_SMOOTH;
+ else if(event==0) efa->flag &= ~ME_SMOOTH;
+ }
+ efa= efa->next;
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+
+ if(event==1) BIF_undo_push("Set Smooth");
+ else if(event==0) BIF_undo_push("Set Solid");
+}
+
+/* helper to find edge for edge_rip */
+static float mesh_rip_edgedist(float mat[][4], float *co1, float *co2, short *mval)
+{
+ float vec1[3], vec2[3], mvalf[2];
+
+ view3d_project_float(curarea, co1, vec1, mat);
+ view3d_project_float(curarea, co2, vec2, mat);
+ mvalf[0]= (float)mval[0];
+ mvalf[1]= (float)mval[1];
+
+ return PdistVL2Dfl(mvalf, vec1, vec2);
+}
+
+/* helper for below */
+static void mesh_rip_setface(EditFace *sefa)
+{
+ /* put new vertices & edges in best face */
+ if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
+ if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
+ if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
+ if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
+
+ sefa->e1= addedgelist(sefa->v1, sefa->v2, sefa->e1);
+ sefa->e2= addedgelist(sefa->v2, sefa->v3, sefa->e2);
+ if(sefa->v4) {
+ sefa->e3= addedgelist(sefa->v3, sefa->v4, sefa->e3);
+ sefa->e4= addedgelist(sefa->v4, sefa->v1, sefa->e4);
+ }
+ else
+ sefa->e3= addedgelist(sefa->v3, sefa->v1, sefa->e3);
+
+}
+
+/* based on mouse cursor position, it defines how is being ripped */
+void mesh_rip(void)
+{
+ extern void faceloop_select(EditEdge *startedge, int select);
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *nextve;
+ EditEdge *eed, *seed= NULL;
+ EditFace *efa, *sefa= NULL;
+ float projectMat[4][4], viewMat[4][4], vec[3], dist, mindist;
+ short doit= 1, mval[2],propmode,prop;
+
+ propmode = G.scene->prop_mode;
+ G.scene->prop_mode = 0;
+ prop = G.scene->proportional;
+ G.scene->proportional = 0;
+
+ /* select flush... vertices are important */
+ EM_selectmode_set();
+
+ getmouseco_areawin(mval);
+ view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat);
+
+ /* find best face, exclude triangles and break on face select or faces with 2 edges select */
+ mindist= 1000000.0f;
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ if( efa->f & 1)
+ break;
+ if(efa->v4 && faceselectedOR(efa, SELECT) ) {
+ int totsel=0;
+
+ if(efa->e1->f & SELECT) totsel++;
+ if(efa->e2->f & SELECT) totsel++;
+ if(efa->e3->f & SELECT) totsel++;
+ if(efa->e4->f & SELECT) totsel++;
+
+ if(totsel>1)
+ break;
+ view3d_project_float(curarea, efa->cent, vec, projectMat);
+ dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
+ if(dist<mindist) {
+ mindist= dist;
+ sefa= efa;
+ }
+ }
+ }
+
+ if(efa) {
+ error("Can't perform ripping with faces selected this way");
+ return;
+ }
+ if(sefa==NULL) {
+ error("No proper selection or faces included");
+ return;
+ }
+
+
+ /* duplicate vertices, new vertices get selected */
+ for(eve = em->verts.last; eve; eve= eve->prev) {
+ eve->tmp.v = NULL;
+ if(eve->f & SELECT) {
+ eve->tmp.v = addvertlist(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(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(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(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(projectMat,
+ sefa->e4->v1->co,
+ sefa->e4->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e4;
+ mindist= dist;
+ }
+ }
+ }
+
+ if(seed==NULL) { // never happens?
+ error("No proper edge found to start");
+ return;
+ }
+
+ faceloop_select(seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
+
+ /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
+ for(eed = em->edges.last; eed; eed= eed->prev) {
+ eed->tmp.v = NULL;
+ if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
+ EditEdge *newed;
+
+ newed= addedgelist(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) {
+ eed->f &= ~SELECT;
+ newed->f |= SELECT;
+ }
+ 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(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(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(eed);
+ free_editedge(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(eve);
+ }
+ }
+
+ countall(); // apparently always needed when adding stuff, derived mesh
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ }
+#endif
+
+ BIF_TransformSetUndo("Rip");
+ initTransform(TFM_TRANSLATION, 0);
+ Transform();
+
+ G.scene->prop_mode = propmode;
+ G.scene->proportional = prop;
+}
+
+void shape_propagate(){
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ Mesh* me = (Mesh*)G.obedit->data;
+ Key* ky = NULL;
+ KeyBlock* kb = NULL;
+ Base* base=NULL;
+
+
+ if(me->key){
+ ky = me->key;
+ } else {
+ error("Object Has No Key");
+ return;
+ }
+
+ if(ky->block.first){
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ for(kb=ky->block.first;kb;kb = kb->next){
+ float *data;
+ data = kb->data;
+ VECCOPY(data+(ev->keyindex*3),ev->co);
+ }
+ }
+ }
+ } else {
+ error("Object Has No Blendshapes");
+ return;
+ }
+
+ //TAG Mesh Objects that share this data
+ for(base = G.scene->base.first; base; base = base->next){
+ if(base->object && base->object->data == me){
+ base->object->recalc = OB_RECALC_DATA;
+ }
+ }
+
+ BIF_undo_push("Propagate Blendshape Verts");
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ return;
+}
+
+void shape_copy_from_lerp(KeyBlock* thisBlock, KeyBlock* fromBlock)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ short mval[2], curval[2], event = 0, finished = 0, canceled = 0, fullcopy=0 ;
+ float perc = 0;
+ char str[64];
+ float *data, *odata;
+
+ data = fromBlock->data;
+ odata = thisBlock->data;
+
+ getmouseco_areawin(mval);
+ curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
+
+ while (finished == 0)
+ {
+ getmouseco_areawin(mval);
+ if (mval[0] != curval[0] || mval[1] != curval[1])
+ {
+
+ if(mval[0] > curval[0])
+ perc += 0.1;
+ else if(mval[0] < curval[0])
+ perc -= 0.1;
+
+ if(perc < 0) perc = 0;
+ if(perc > 1) perc = 1;
+
+ curval[0] = mval[0];
+ curval[1] = mval[1];
+
+ if(fullcopy == 1){
+ perc = 1;
+ }
+
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ VecLerpf(ev->co,odata+(ev->keyindex*3),data+(ev->keyindex*3),perc);
+ }
+ }
+ sprintf(str,"Blending at %d%c MMB to Copy at 100%c",(int)(perc*100),'%','%');
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ headerprint(str);
+ force_draw(0);
+
+ if(fullcopy == 1){
+ break;
+ }
+
+ } else {
+ PIL_sleep_ms(10);
+ }
+
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val);
+ if(val){
+ if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)){
+ finished = 1;
+ }
+ else if (event == MIDDLEMOUSE){
+ fullcopy = 1;
+ }
+ else if (ELEM3(event,ESCKEY,RIGHTMOUSE,RIGHTMOUSE)){
+ canceled = 1;
+ finished = 1;
+ }
+ }
+ }
+ }
+ if(!canceled)
+ BIF_undo_push("Copy Blendshape Verts");
+ else
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ VECCOPY(ev->co, odata+(ev->keyindex*3));
+ }
+ }
+ return;
+}
+
+
+
+void shape_copy_select_from()
+{
+ Mesh* me = (Mesh*)G.obedit->data;
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ int totverts = 0,curshape = G.obedit->shapenr;
+
+ Key* ky = NULL;
+ KeyBlock *kb = NULL,*thisBlock = NULL;
+ int maxlen=32, nr=0, a=0;
+ char *menu;
+
+ if(me->key){
+ ky = me->key;
+ } else {
+ error("Object Has No Key");
+ return;
+ }
+
+ if(ky->block.first){
+ for(kb=ky->block.first;kb;kb = kb->next){
+ maxlen += 40; // Size of a block name
+ if(a == curshape-1){
+ thisBlock = kb;
+ }
+
+ a++;
+ }
+ a=0;
+ menu = MEM_callocN(maxlen, "Copy Shape Menu Text");
+ strcpy(menu, "Copy Vert Positions from Shape %t|");
+ for(kb=ky->block.first;kb;kb = kb->next){
+ if(a != curshape-1){
+ sprintf(menu,"%s %s %cx%d|",menu,kb->name,'%',a);
+ }
+ a++;
+ }
+ nr = pupmenu_col(menu, 20);
+ MEM_freeN(menu);
+ } else {
+ error("Object Has No Blendshapes");
+ return;
+ }
+
+ a = 0;
+
+ for(kb=ky->block.first;kb;kb = kb->next){
+ if(a == nr){
+
+ for(ev = em->verts.first;ev;ev = ev->next){
+ totverts++;
+ }
+
+ if(me->totvert != totverts){
+ error("Shape Has had Verts Added/Removed, please cycle editmode before copying");
+ return;
+ }
+ shape_copy_from_lerp(thisBlock,kb);
+
+ return;
+ }
+ a++;
+ }
+ return;
+}
+
+/* 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(ListBase *allcollections)
+{
+ EditEdge *eed;
+ Collection *edgecollection, *newcollection;
+ CollectedEdge *newedge;
+
+ int currtag = 1;
+ short ebalanced = 0;
+ short collectionfound = 0;
+
+ for (eed=G.editMesh->edges.first; eed; eed = eed->next){
+ eed->tmp.l = 0;
+ eed->v1->tmp.l = 0;
+ eed->v2->tmp.l = 0;
+ }
+
+ /*1st pass*/
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f&SELECT){
+ eed->v1->tmp.l = currtag;
+ eed->v2->tmp.l = currtag;
+ currtag +=1;
+ }
+ }
+
+ /*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */
+ while(ebalanced == 0){
+ ebalanced = 1;
+ for(eed=G.editMesh->edges.first; eed; eed = eed->next){
+ if(eed->f&SELECT){
+ if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{
+ if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l;
+ else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l;
+ ebalanced = 0;
+ }
+ }
+ }
+ }
+
+ /*3rd pass, set all the edge flags (unnessecary?)*/
+ for(eed=G.editMesh->edges.first; eed; eed = eed->next){
+ if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l;
+ }
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f&SELECT){
+ if(allcollections->first){
+ for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){
+ 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 boundries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it.
+ The welded UV edges can then be sorted and collapsed.
+*/
+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(EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts)
+{
+ wUV *curwvert, *newwvert;
+ wUVNode *newnode;
+ int found;
+ MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ found = 0;
+
+ for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
+ if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){
+ newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
+ 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(ListBase *uvverts)
+{
+ EditFace *efa;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->v1->f1) append_weldedUV(efa, efa->v1, 0, uvverts);
+ if(efa->v2->f1) append_weldedUV(efa, efa->v2, 1, uvverts);
+ if(efa->v3->f1) append_weldedUV(efa, efa->v3, 2, uvverts);
+ if(efa->v4 && efa->v4->f1) append_weldedUV(efa, efa->v4, 3, uvverts);
+ }
+}
+
+static void append_weldedUVEdge(EditFace *efa, EditEdge *eed, ListBase *uvedges)
+{
+ wUVEdge *curwedge, *newwedge;
+ int v1tfindex, v2tfindex, found;
+ MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ found = 0;
+
+ if(eed->v1 == efa->v1) v1tfindex = 0;
+ else if(eed->v1 == efa->v2) v1tfindex = 1;
+ else if(eed->v1 == efa->v3) v1tfindex = 2;
+ else /* if(eed->v1 == efa->v4) */ v1tfindex = 3;
+
+ if(eed->v2 == efa->v1) v2tfindex = 0;
+ else if(eed->v2 == efa->v2) v2tfindex = 1;
+ else if(eed->v2 == efa->v3) v2tfindex = 2;
+ 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(ListBase *uvedges, ListBase *uvverts)
+{
+ wUV *curwvert;
+ wUVEdge *curwedge;
+ EditFace *efa;
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->e1->f1) append_weldedUVEdge(efa, efa->e1, uvedges);
+ if(efa->e2->f1) append_weldedUVEdge(efa, efa->e2, uvedges);
+ if(efa->e3->f1) append_weldedUVEdge(efa, efa->e3, uvedges);
+ if(efa->e4 && efa->e4->f1) append_weldedUVEdge(efa, efa->e4, uvedges);
+ }
+
+
+ //link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers
+ for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){
+ for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
+ 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(void)
+{
+ 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())
+ return;
+
+ uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL;
+
+ build_weldedUVs(&uvverts);
+ build_weldedUVEdges(&uvedges, &uvverts);
+
+ curtag = 0;
+
+ for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
+ curwedge->v1->f = curtag;
+ curwedge->v2->f = curtag;
+ curtag +=1;
+ }
+
+ balanced = 0;
+ while(!balanced){
+ balanced = 1;
+ 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(EditVert *mergevert)
+{
+ EditFace *efa;
+ MTFace *tf;
+ int uvcount;
+ float uvav[2];
+
+ if (!EM_texFaceCheck())
+ return;
+
+ uvcount = 0;
+ uvav[0] = 0;
+ uvav[1] = 0;
+
+ for(efa = G.editMesh->faces.first; efa; efa=efa->next){
+ tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) {
+ uvav[0] += tf->uv[0][0];
+ 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 = G.editMesh->faces.first; efa; efa=efa->next){
+ tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ if(efa->v1->f1){
+ tf->uv[0][0] = uvav[0];
+ tf->uv[0][1] = uvav[1];
+ }
+ if(efa->v2->f1){
+ tf->uv[1][0] = uvav[0];
+ tf->uv[1][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];
+ }
+ }
+ }
+}
+
+int collapseEdges(void)
+{
+ EditVert *eve;
+ EditEdge *eed;
+
+ ListBase allcollections;
+ CollectedEdge *curredge;
+ Collection *edgecollection;
+
+ int totedges, groupcount, mergecount,vcount;
+ float avgcount[3];
+
+ allcollections.first = 0;
+ allcollections.last = 0;
+
+ mergecount = 0;
+
+ if(multires_test()) return 0;
+
+ build_edgecollection(&allcollections);
+ groupcount = BLI_countlist(&allcollections);
+
+
+ for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){
+ totedges = BLI_countlist(&(edgecollection->collectionbase));
+ mergecount += totedges;
+ avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0;
+
+ vcount = 0;
+
+ for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
+ avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0];
+ avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1];
+ avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2];
+
+ avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0];
+ avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1];
+ avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2];
+
+ vcount +=2;
+ }
+
+ avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount;
+
+ for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
+ VECCOPY(((EditEdge*)curredge->eed)->v1->co,avgcount);
+ VECCOPY(((EditEdge*)curredge->eed)->v2->co,avgcount);
+ }
+
+ if (EM_texFaceCheck()) {
+ /*uv collapse*/
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+ for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
+ curredge->eed->v1->f1 = 1;
+ curredge->eed->v2->f1 = 1;
+ curredge->eed->f1 = 1;
+ }
+ collapse_edgeuvs();
+ }
+
+ }
+ freecollections(&allcollections);
+ removedoublesflag(1, 0, MERGELIMIT);
+ /*get rid of this!*/
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ return mergecount;
+}
+
+int merge_firstlast(int first, int uvmerge)
+{
+ EditVert *eve,*mergevert;
+ EditSelection *ese;
+
+ if(multires_test()) return 0;
+
+ /* do sanity check in mergemenu in edit.c ?*/
+ if(first == 0){
+ ese = G.editMesh->selected.last;
+ mergevert= (EditVert*)ese->data;
+ }
+ else{
+ ese = G.editMesh->selected.first;
+ mergevert = (EditVert*)ese->data;
+ }
+
+ if(mergevert->f&SELECT){
+ for (eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if (eve->f&SELECT)
+ VECCOPY(eve->co,mergevert->co);
+ }
+ }
+
+ if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){
+
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f&SELECT) eve->f1 = 1;
+ }
+ collapseuvs(mergevert);
+ }
+
+ countall();
+ return removedoublesflag(1, 0, MERGELIMIT);
+}
+
+int merge_target(int target, int uvmerge)
+{
+ EditVert *eve;
+
+ if(multires_test()) return 0;
+
+ if(target) snap_sel_to_curs();
+ else snap_to_center();
+
+ if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f&SELECT) eve->f1 = 1;
+ }
+ collapseuvs(NULL);
+ }
+
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ return removedoublesflag(1, 0, MERGELIMIT);
+
+}
+#undef MERGELIMIT
+
+typedef struct PathNode{
+ int u;
+ int visited;
+ ListBase edges;
+} PathNode;
+
+typedef struct PathEdge{
+ struct PathEdge *next, *prev;
+ int v;
+ float w;
+} PathEdge;
+
+void pathselect(void)
+{
+ EditVert *eve, *s, *t;
+ EditEdge *eed;
+ EditSelection *ese;
+ PathEdge *newpe, *currpe;
+ PathNode *currpn;
+ PathNode *Q;
+ int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
+ int unbalanced, totnodes;
+ short physical;
+ float *cost;
+ Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
+
+ s = t = NULL;
+
+ countall(); /*paranoid?*/
+
+ ese = ((EditSelection*)G.editMesh->selected.last);
+ if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
+ physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
+
+ t = (EditVert*)ese->data;
+ s = (EditVert*)ese->prev->data;
+
+ /*need to find out if t is actually reachable by s....*/
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ eve->f1 = 0;
+ }
+
+ s->f1 = 1;
+
+ unbalanced = 1;
+ totnodes = 1;
+ while(unbalanced){
+ unbalanced = 0;
+ for(eed=G.editMesh->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=G.editMesh->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=G.editMesh->edges.first; eed; eed=eed->next){
+ if(!eed->h){
+ if(eed->v1->f1){
+ currpn = ((PathNode*)eed->v1->tmp.p);
+
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
+ if(physical){
+ newpe->w = VecLenf(eed->v1->co, eed->v2->co);
+ }
+ else newpe->w = 1;
+ newpe->next = 0;
+ newpe->prev = 0;
+ BLI_addtail(&(currpn->edges), newpe);
+ }
+ if(eed->v2->f1){
+ currpn = ((PathNode*)eed->v2->tmp.p);
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
+ if(physical){
+ newpe->w = VecLenf(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=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f1){
+ if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
+ }
+ }
+ pathvert = previous[pathvert];
+ }
+
+ for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
+ MEM_freeN(Q);
+ MEM_freeN(cost);
+ MEM_freeN(previous);
+ BLI_heap_free(heap, NULL);
+ EM_select_flush();
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ else{
+ error("Path Selection requires that exactly two vertices be selected");
+ return;
+ }
+}
+
+void region_to_loop(void)
+{
+ EditEdge *eed;
+ EditFace *efa;
+
+ if(G.totfacesel){
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->f&SELECT){
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4)
+ efa->e4->f1++;
+ }
+ }
+
+ EM_clear_flag_all(SELECT);
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f1 == 1) EM_select_edge(eed, 1);
+ }
+
+ G.scene->selectmode = SCE_SELECT_EDGE;
+ EM_selectmode_set();
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Face Region to Edge Loop");
+
+ }
+}
+
+static int validate_loop(Collection *edgecollection)
+{
+ EditEdge *eed;
+ EditFace *efa;
+ CollectedEdge *curredge;
+
+ /*1st test*/
+ for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
+ curredge->eed->v1->f1 = 0;
+ 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 = G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ 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(Collection *edgecollection){
+
+ EditFace *efa, *sf1, *sf2;
+ EditEdge *eed, *sed;
+ CollectedEdge *curredge;
+ int totsf1, totsf2, unbalanced,balancededges;
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next) efa->f1 = 0;
+
+ for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1;
+
+ sf1 = sf2 = NULL;
+ sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed;
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(sf2) break;
+ else if(sf1){
+ if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa;
+ }
+ 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=G.editMesh->faces.first; efa; efa=efa->next){
+ balancededges = 0;
+ if(efa->f1 == 0){
+ if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){
+ 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=G.editMesh->faces.first; efa; efa=efa->next){
+ balancededges = 0;
+ if(efa->f1 == 0){
+ if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){
+ 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);
+}
+
+void loop_to_region(void)
+{
+ EditFace *efa;
+ ListBase allcollections={NULL,NULL};
+ Collection *edgecollection;
+ int testflag;
+
+ build_edgecollection(&allcollections);
+
+ for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){
+ if(validate_loop(edgecollection)){
+ testflag = loop_bisect(edgecollection);
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->f1 == testflag){
+ if(efa->f&SELECT) EM_select_face(efa, 0);
+ else EM_select_face(efa,1);
+ }
+ }
+ }
+ }
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){ /*fix this*/
+ if(efa->f&SELECT) EM_select_face(efa,1);
+ }
+
+ countall();
+ freecollections(&allcollections);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Edge Loop to Face Region");
+}
+
+
+/* texface and vertex color editmode tools for the face menu */
+
+void mesh_rotate_uvs(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0, ccw;
+ MTFace *tf;
+ float u1, v1;
+
+ if (!EM_texFaceCheck()) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+
+ ccw = (G.qual == LR_SHIFTKEY);
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ u1= tf->uv[0][0];
+ v1= tf->uv[0][1];
+
+ if (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;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Rotate UV face");
+ }
+}
+
+void mesh_mirror_uvs(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0, altaxis;
+ MTFace *tf;
+ float u1, v1;
+
+ if (!EM_texFaceCheck()) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+
+ altaxis = (G.qual == LR_SHIFTKEY);
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (altaxis) {
+ u1= tf->uv[1][0];
+ v1= tf->uv[1][1];
+ if(efa->v4) {
+
+ tf->uv[1][0]= tf->uv[2][0];
+ tf->uv[1][1]= tf->uv[2][1];
+
+ tf->uv[2][0]= u1;
+ tf->uv[2][1]= v1;
+
+ 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;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Mirror UV face");
+ }
+}
+
+void mesh_rotate_colors(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0, ccw;
+ MCol tmpcol, *mcol;
+ if (!EM_vertColorCheck()) {
+ error("mesh has no color layers");
+ return;
+ }
+
+ ccw = (G.qual == LR_SHIFTKEY);
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ tmpcol= mcol[0];
+
+ if (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;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Rotate Color face");
+ }
+}
+
+void mesh_mirror_colors(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0, altaxis;
+ MCol tmpcol, *mcol;
+ if (!EM_vertColorCheck()) {
+ error("mesh has no color layers");
+ return;
+ }
+
+ altaxis = (G.qual == LR_SHIFTKEY);
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ if (altaxis) {
+ 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;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Mirror Color face");
+ }
+}
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
new file mode 100644
index 00000000000..58025fd33cc
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -0,0 +1,566 @@
+/**
+ * bmesh_construct.c August 2008
+ *
+ * BM construction functions.
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "math.h"
+#include "stdio.h"
+#include "string.h"
+
+#define SELECT 1
+
+/*prototypes*/
+static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh,
+ BMLoop *source_loop, BMLoop *target_loop);
+
+/*
+ * BM_CONSTRUCT.C
+ *
+ * This file contains functions for making and destroying
+ * individual elements like verts, edges and faces.
+ *
+*/
+
+/*
+ * BMESH MAKE VERT
+ *
+ * Creates a new vertex and returns a pointer
+ * to it. If a pointer to an example vertex is
+ * passed in, it's custom data and properties
+ * will be copied to the new vertex.
+ *
+*/
+
+BMVert *BM_Make_Vert(BMesh *bm, float co[3], BMVert *example)
+{
+ BMVert *v = NULL;
+ v = bmesh_mv(bm, co);
+ if(example)
+ CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->head.data, &v->head.data);
+ return v;
+}
+
+/*
+ * BMESH MAKE EDGE
+ *
+ * Creates a new edge betweeen two vertices and returns a
+ * pointer to it. If 'nodouble' equals 1, then a check is
+ * is done to make sure that an edge between those two vertices
+ * does not already exist. If it does, that edge is returned instead
+ * of creating a new one.
+ *
+ * If a new edge is created, and a pointer to an example edge is
+ * provided, it's custom data and properties will be copied to the
+ * new edge.
+ *
+*/
+
+BMEdge *BM_Make_Edge(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example, int nodouble)
+{
+ BMEdge *e = NULL;
+
+ if(nodouble) /*test if edge already exists.*/
+ e = bmesh_disk_existedge(v1, v2);
+
+ if(!e){
+ e = bmesh_me(bm, v1, v2);
+
+ if(example)
+ CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->head.data, &e->head.data);
+ }
+
+ return e;
+
+}
+
+/*
+ * BMESH MAKE QUADTRIANGLE
+ *
+ * Creates a new quad or triangle from
+ * a list of 3 or 4 vertices. If nodouble
+ * equals 1, then a check is done to see
+ * if a face with these vertices already
+ * exists and returns it instead. If a pointer
+ * to an example face is provided, it's custom
+ * data and properties will be copied to the new
+ * face.
+ *
+ * Note that the winding of the face is determined
+ * by the order of the vertices in the vertex array
+ *
+*/
+
+BMFace *BM_Make_QuadTri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3,
+ BMVert *v4, BMFace *example, int nodouble)
+{
+ BMEdge *edar[4];
+ BMVert *vtar[4];
+
+ edar[0] = bmesh_disk_existedge(v1, v2);
+ edar[1] = bmesh_disk_existedge(v2, v3);
+ edar[2] = bmesh_disk_existedge(v3, v4? v4 : v1);
+ if (v4) edar[3] = bmesh_disk_existedge(v4, v1);
+ else edar[3] = NULL;
+
+ if (!edar[0]) edar[0] = BM_Make_Edge(bm, v1, v2, NULL, 0);
+ if (!edar[1]) edar[1] = BM_Make_Edge(bm, v2, v3, NULL, 0);
+ if (!edar[2]) edar[2] = BM_Make_Edge(bm, v3, v4?v4:v1, NULL, 0);
+ if (!edar[0] && v4) edar[0] = BM_Make_Edge(bm, v4, v1, NULL, 0);
+
+ vtar[0] = v1;
+ vtar[1] = v2;
+ vtar[2] = v3;
+ vtar[3] = v4;
+
+ return BM_Make_Quadtriangle(bm, vtar, edar, v4?4:3, example, nodouble);
+}
+
+/*remove the edge array bits from this. Its not really needed?*/
+BMFace *BM_Make_Quadtriangle(BMesh *bm, BMVert **verts, BMEdge **edges, int len, BMFace *example, int nodouble)
+{
+ BMEdge *edar[4];
+ BMFace *f = NULL;
+ int overlap = 0;
+
+ edar[0] = edar[1] = edar[2] = edar[3] = NULL;
+
+ if(edges){
+ edar[0] = edges[0];
+ edar[1] = edges[1];
+ edar[2] = edges[2];
+ if(len == 4) edar[3] = edges[3];
+ }else{
+ edar[0] = bmesh_disk_existedge(verts[0],verts[1]);
+ edar[1] = bmesh_disk_existedge(verts[1],verts[2]);
+ if(len == 4){
+ edar[2] = bmesh_disk_existedge(verts[2],verts[3]);
+ edar[3] = bmesh_disk_existedge(verts[3],verts[0]);
+
+ }else{
+ edar[2] = bmesh_disk_existedge(verts[2],verts[0]);
+ }
+ }
+
+ if(nodouble){
+ /*check if face exists or overlaps*/
+ if(len == 4){
+ overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
+ }else{
+ overlap = BM_Exist_Face_Overlaps(bm, verts, len, &f);
+ }
+ }
+
+ /*make new face*/
+ if((!f) && (!overlap)){
+ if(!edar[0]) edar[0] = bmesh_me(bm, verts[0], verts[1]);
+ if(!edar[1]) edar[1] = bmesh_me(bm, verts[1], verts[2]);
+ if(len == 4){
+ if(!edar[2]) edar[2] = bmesh_me(bm, verts[2], verts[3]);
+ if(!edar[3]) edar[3] = bmesh_me(bm, verts[3], verts[0]);
+ } else {
+ if(!edar[2]) edar[2] = bmesh_me(bm, verts[2], verts[0]);
+ }
+
+ if(len == 4) f = bmesh_mf(bm, verts[0], verts[1], edar, 4);
+ else f = bmesh_mf(bm, verts[0], verts[1], edar, 3);
+
+ if(example)
+ CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->head.data, &f->head.data);
+
+ }
+
+ return f;
+}
+
+
+/*copies face data from shared adjacent faces*/
+void BM_Face_CopyShared(BMesh *bm, BMFace *f) {
+ BMIter iter;
+ BMLoop *l, *l2;
+
+ if (!f) return;
+
+ l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&iter)) {
+ l2 = l->radial.next->data;
+
+ if (l2 && l2 != l) {
+ if (l2->v == l->v) {
+ bm_copy_loop_attributes(bm, bm, l2, l);
+ } else {
+ l2 = (BMLoop*) l2->head.next;
+ bm_copy_loop_attributes(bm, bm, l2, l);
+ }
+ }
+ }
+}
+
+/*
+ * BMESH MAKE NGON
+ *
+ * Attempts to make a new Ngon from a list of edges.
+ * If nodouble equals one, a check for overlaps or existing
+ *
+ *
+ *
+*/
+#define VERT_BUF_SIZE 100
+BMFace *BM_Make_Ngon(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **edges, int len, int nodouble)
+{
+ BMVert *vert_buf[VERT_BUF_SIZE];
+ BMVert **verts = vert_buf, *lastv;
+ BMFace *f = NULL;
+ int overlap = 0, i, j;
+
+ /*note: need to make sure this is correct*/
+ if(bmesh_verts_in_edge(v1,v2,edges[0]) == 0) {
+ if (v1 == edges[0]->v1)
+ v2 = edges[0]->v2;
+ else {
+ v1 = edges[0]->v2;
+ v2 = edges[0]->v1;
+ }
+ }
+
+ if(nodouble) {
+ if(len > VERT_BUF_SIZE)
+ verts = MEM_callocN(sizeof(BMVert *) * len, "bmesh make ngon vertex array");
+
+ /*if ((edges[i]->v1 == edges[i]->v1) ||
+ (edges[i]->v1 == edges[i]->v2))
+ {
+ lastv = edges[i]->v2;
+ } else lastv = edges[i]->v1;
+ verts[0] = lastv;
+
+ for (i=1; i<len; i++) {
+ if (!BMO_TestFlag
+ }*/
+
+ for(i = 0, j=0; i < len; i++){
+ if(!BMO_TestFlag(bm, edges[i]->v1, BM_EDGEVERT)){
+ BMO_SetFlag(bm, edges[i]->v1, BM_EDGEVERT);
+ verts[j++] = edges[i]->v1;
+ }
+ if(!BMO_TestFlag(bm, edges[i]->v2, BM_EDGEVERT)) {
+ BMO_SetFlag(bm, edges[i]->v2, BM_EDGEVERT);
+ verts[j++] = edges[i]->v2;
+ }
+ }
+
+ if (j != len) {
+ /*sanity check*/
+ return NULL;
+ }
+
+ overlap = BM_Face_Exists(bm, verts, len, &f);
+
+ /*clear flags*/
+ for(i = 0; i < len; i++){
+ BMO_ClearFlag(bm, edges[i]->v1, BM_EDGEVERT);
+ BMO_ClearFlag(bm, edges[i]->v2, BM_EDGEVERT);
+ }
+
+ if(len > VERT_BUF_SIZE)
+ MEM_freeN(verts);
+ }
+
+ if((!f) && (!overlap)) {
+ f = bmesh_mf(bm, v1, v2, edges, len);
+ }
+
+ return f;
+}
+
+
+/*bmesh_make_face_from_face(BMesh *bm, BMFace *source, BMFace *target) */
+
+
+/*
+ * REMOVE TAGGED XXX
+ *
+ * Called by operators to remove elements that they have marked for
+ * removal.
+ *
+*/
+
+void BM_remove_tagged_faces(BMesh *bm, int flag)
+{
+ BMHeader *current, *next;
+
+ current = bm->polys.first;
+ while(current){
+ next = current->next;
+ if(BMO_TestFlag(bm, current, flag)) bmesh_kf(bm, (BMFace*)current);
+ current = next;
+ }
+}
+void BM_remove_tagged_edges(BMesh *bm, int flag)
+{
+ BMHeader *current, *next;
+
+ current = bm->edges.first;
+
+ while(current){
+ next = current->next;
+ if(BMO_TestFlag(bm, current, flag)) bmesh_ke(bm, (BMEdge*)current);
+ current = next;
+ }
+}
+
+void BM_remove_tagged_verts(BMesh *bm, int flag)
+{
+ BMHeader *current, *next;
+
+ current = bm->verts.first;
+
+ while(current){
+ next = current->next;
+ if(BMO_TestFlag(bm, current, flag)) bmesh_kv(bm,(BMVert*)current);
+ current = next;
+ }
+}
+
+static void bm_copy_vert_attributes(BMesh *source_mesh, BMesh *target_mesh, BMVert *source_vertex, BMVert *target_vertex)
+{
+ CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->head.data, &target_vertex->head.data);
+ target_vertex->bweight = source_vertex->bweight;
+}
+
+static void bm_copy_edge_attributes(BMesh *source_mesh, BMesh *target_mesh, BMEdge *source_edge, BMEdge *target_edge)
+{
+ CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->head.data, &target_edge->head.data);
+ target_edge->crease = source_edge->crease;
+ target_edge->bweight = source_edge->bweight;
+}
+
+static void bm_copy_loop_attributes(BMesh *source_mesh, BMesh *target_mesh, BMLoop *source_loop, BMLoop *target_loop)
+{
+ CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->head.data, &target_loop->head.data);
+}
+
+static void bm_copy_face_attributes(BMesh *source_mesh, BMesh *target_mesh, BMFace *source_face, BMFace *target_face)
+{
+ CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->head.data, &target_face->head.data);
+ target_face->mat_nr = source_face->mat_nr;
+}
+
+/*Todo: Special handling for hide flags?*/
+
+void BM_Copy_Attributes(BMesh *source_mesh, BMesh *target_mesh, void *source, void *target)
+{
+ BMHeader *sheader = source, *theader = target;
+
+ if(sheader->type != theader->type)
+ return;
+
+ /*First we copy select*/
+ if(BM_Is_Selected(source_mesh, source)) BM_Select(target_mesh, target, 1);
+
+ /*Now we copy flags*/
+ theader->flag = sheader->flag;
+
+ /*Copy specific attributes*/
+ if(theader->type == BM_VERT)
+ bm_copy_vert_attributes(source_mesh, target_mesh, (BMVert*)source, (BMVert*)target);
+ else if(theader->type == BM_EDGE)
+ bm_copy_edge_attributes(source_mesh, target_mesh, (BMEdge*)source, (BMEdge*)target);
+ else if(theader->type == BM_LOOP)
+ bm_copy_loop_attributes(source_mesh, target_mesh, (BMLoop*)source, (BMLoop*)target);
+ else if(theader->type == BM_FACE)
+ bm_copy_face_attributes(source_mesh, target_mesh, (BMFace*)source, (BMFace*)target);
+}
+
+BMesh *BM_Copy_Mesh(BMesh *bmold)
+{
+ BMesh *bm;
+ BMVert *v, *v2, **vtable = NULL;
+ V_DECLARE(vtable);
+ BMEdge *e, *e2, **edges = NULL, **etable = NULL;
+ V_DECLARE(edges);
+ V_DECLARE(etable);
+ BMLoop *l, *l2, **loops = NULL;
+ V_DECLARE(loops);
+ BMFace *f, *f2;
+
+ BMIter iter, liter;
+ int allocsize[4] = {512,512,2048,512}, numTex, numCol;
+ int i;
+
+ /*allocate a bmesh*/
+ bm = BM_Make_Mesh(allocsize);
+
+ CustomData_copy(&bmold->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmold->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmold->ldata, &bm->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bmold->pdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ v = BMIter_New(&iter, bmold, BM_VERTS_OF_MESH, NULL);
+ for (i=0; v; v=BMIter_Step(&iter), i++) {
+ v2 = BM_Make_Vert(bm, v->co, NULL);
+ BM_Copy_Attributes(bmold, bm, v, v2);
+ V_GROW(vtable);
+ VECCOPY(v2->no, v->no);
+
+ vtable[V_COUNT(vtable)-1] = v2;
+
+ BMINDEX_SET(v, i);
+ BMINDEX_SET(v2, i);
+ }
+
+ e = BMIter_New(&iter, bmold, BM_EDGES_OF_MESH, NULL);
+ for (i=0; e; e=BMIter_Step(&iter), i++) {
+ e2 = BM_Make_Edge(bm, vtable[BMINDEX_GET(e->v1)],
+ vtable[BMINDEX_GET(e->v2)], e, 0);
+
+ BM_Copy_Attributes(bmold, bm, e, e2);
+ V_GROW(etable);
+ etable[V_COUNT(etable)-1] = e2;
+
+ BMINDEX_SET(e, i);
+ BMINDEX_SET(e2, i);
+ }
+
+ f = BMIter_New(&iter, bmold, BM_FACES_OF_MESH, NULL);
+ for (; f; f=BMIter_Step(&iter)) {
+ V_RESET(loops);
+ V_RESET(edges);
+ l = BMIter_New(&liter, bmold, BM_LOOPS_OF_FACE, f);
+ for (i=0; i<f->len; i++, l = BMIter_Step(&liter)) {
+ V_GROW(loops);
+ V_GROW(edges);
+ loops[i] = l;
+ edges[i] = etable[BMINDEX_GET(l->e)];
+ }
+
+ v = vtable[BMINDEX_GET(loops[0]->v)];
+ v2 = vtable[BMINDEX_GET(loops[1]->v)];
+
+ if (!bmesh_verts_in_edge(v, v2, edges[0])) {
+ v = vtable[BMINDEX_GET(loops[V_COUNT(loops)-1]->v)];
+ v2 = vtable[BMINDEX_GET(loops[0]->v)];
+ }
+
+ f2 = BM_Make_Ngon(bm, v, v2, edges, f->len, 0);
+ BM_Copy_Attributes(bmold, bm, f, f2);
+ VECCOPY(f2->no, f->no);
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f2);
+ for (i=0; i<f->len; i++, l = BMIter_Step(&liter)) {
+ BM_Copy_Attributes(bmold, bm, loops[i], l);
+ }
+
+ if (f == bmold->act_face) bm->act_face = f2;
+ }
+
+ V_FREE(etable);
+ V_FREE(vtable);
+ V_FREE(loops);
+ V_FREE(edges);
+
+ return bm;
+}
+
+/*
+ BM FLAGS TO ME FLAGS
+
+ Returns the flags stored in element,
+ which much be either a BMVert, BMEdge,
+ or BMFace, converted to mesh flags.
+*/
+int BMFlags_To_MEFlags(void *element) {
+ BMHeader *h = element;
+ int f = 0;
+
+ if (h->flag & BM_HIDDEN) f |= ME_HIDE;
+
+ if (h->type == BM_FACE) {
+ if (h->flag & BM_SELECT) f |= ME_FACE_SEL;
+ if (h->flag & BM_SMOOTH) f |= ME_SMOOTH;
+ } else if (h->type == BM_EDGE) {
+ if (h->flag & BM_SELECT) f |= BM_SELECT;
+ if (h->flag & BM_SEAM) f |= ME_SEAM;
+ if (h->flag & BM_SHARP) f |= ME_SHARP;
+ if (BM_Wire_Edge(NULL, element)) f |= ME_LOOSEEDGE;
+ } else if (h->type == BM_VERT) {
+ if (h->flag & BM_SELECT) f |= BM_SELECT;
+ if (h->flag & BM_HIDDEN) f |= ME_HIDE;
+ }
+
+ return f;
+}
+
+/*
+ BM FLAGS TO ME FLAGS
+
+ Returns the flags stored in element,
+ which much be either a MVert, MEdge,
+ or MPoly, converted to mesh flags.
+ type must be either BM_VERT, BM_EDGE,
+ or BM_FACE.
+*/
+int MEFlags_To_BMFlags(int flag, int type) {
+ int f = 0;
+
+ if (type == BM_FACE) {
+ if (flag & ME_FACE_SEL) f |= BM_SELECT;
+ if (flag & ME_SMOOTH) f |= BM_SMOOTH;
+ if (flag & ME_HIDE) f |= BM_HIDDEN;
+ } else if (type == BM_EDGE) {
+ if (flag & SELECT) f |= BM_SELECT;
+ if (flag & ME_SEAM) f |= BM_SEAM;
+ if (flag & ME_SHARP) f |= BM_SHARP;
+ if (flag & ME_HIDE) f |= BM_HIDDEN;
+ } else if (type == BM_VERT) {
+ if (flag & SELECT) f |= BM_SELECT;
+ if (flag & ME_HIDE) f |= BM_HIDDEN;
+ }
+
+ return f;
+} \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_eulers.c b/source/blender/bmesh/intern/bmesh_eulers.c
new file mode 100644
index 00000000000..6a68989a42a
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_eulers.c
@@ -0,0 +1,1186 @@
+/**
+ * bmesh_eulers.c jan 2007
+ *
+ * BM Euler construction API.
+ *
+ * $Id: bmesh_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+/*********************************************************
+ * "Euler API" *
+ * *
+ * *
+ * Primitive construction operators for mesh tools. *
+ * *
+ **********************************************************/
+
+
+/*
+ The functions in this file represent the 'primitive' or 'atomic' operators that
+ mesh tools use to manipulate the topology of the structure.* The purpose of these
+ functions is to provide a trusted set of operators to manipulate the mesh topology
+ and which can also be combined together like building blocks to create more
+ sophisticated tools. It needs to be stressed that NO manipulation of an existing
+ mesh structure should be done outside of these functions.
+
+ In the BM system, each euler is named by an ancronym which describes what it actually does.
+ Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that
+ through a Euler's logical inverse you can 'undo' an operation. (Special note should
+ be taken of bmesh_loop_reverse, which is its own inverse).
+
+ bmesh_MF/KF: Make Face and Kill Face
+ bmesh_ME/KE: Make Edge and Kill Edge
+ bmesh_MV/KV: Make Vert and Kill Vert
+ bmesh_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
+ bmesh_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
+ bmesh_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one)
+
+ Using a combination of these eleven eulers any non-manifold modelling operation can be achieved.
+ Each Euler operator has a detailed explanation of what is does in the comments preceding its
+ code.
+
+ *The term "Euler Operator" is actually a misnomer when referring to a non-manifold
+ data structure. Its use is in keeping with the convention established by others.
+
+ TODO:
+ -Make seperate 'debug levels' of validation
+ -Add in the UnglueFaceRegionMakeVert and GlueFaceRegionKillVert eulers.
+
+ NOTE:
+ -The functions in this file are notoriously difficult to debug and even understand sometimes.
+ better code comments would be nice....
+
+*/
+
+
+/*MAKE Eulers*/
+
+/**
+ * bmesh_MV
+ *
+ * MAKE VERT EULER:
+ *
+ * Makes a single loose vertex.
+ *
+ * Returns -
+ * A BMVert pointer.
+ */
+
+BMVert *bmesh_mv(BMesh *bm, float *vec){
+ BMVert *v = bmesh_addvertlist(bm, NULL);
+ VECCOPY(v->co,vec);
+ return v;
+}
+
+/**
+ * bmesh_ME
+ *
+ * MAKE EDGE EULER:
+ *
+ * Makes a single wire edge between two vertices.
+ * If the caller does not want there to be duplicate
+ * edges between the vertices, it is up to them to check
+ * for this condition beforehand.
+ *
+ * Returns -
+ * A BMEdge pointer.
+ */
+
+BMEdge *bmesh_me(BMesh *bm, BMVert *v1, BMVert *v2){
+ BMEdge *e=NULL;
+ BMNode *d1=NULL, *d2=NULL;
+ int valance1=0, valance2=0, edok;
+
+ /*edge must be between two distinct vertices...*/
+ if(v1 == v2) return NULL;
+
+ #ifndef bmesh_FASTEULER
+ /*count valance of v1*/
+ if(v1->edge){
+ d1 = bmesh_disk_getpointer(v1->edge,v1);
+ if(d1) valance1 = bmesh_cycle_length(d1);
+ else bmesh_error();
+ }
+ if(v2->edge){
+ d2 = bmesh_disk_getpointer(v2->edge,v2);
+ if(d2) valance2 = bmesh_cycle_length(d2);
+ else bmesh_error();
+ }
+ #endif
+
+ /*go ahead and add*/
+ e = bmesh_addedgelist(bm, v1, v2, NULL);
+ bmesh_disk_append_edge(e, e->v1);
+ bmesh_disk_append_edge(e, e->v2);
+
+ #ifndef bmesh_FASTEULER
+ /*verify disk cycle lengths*/
+ d1 = bmesh_disk_getpointer(e, e->v1);
+ edok = bmesh_cycle_validate(valance1+1, d1);
+ if(!edok) bmesh_error();
+ d2 = bmesh_disk_getpointer(e, e->v2);
+ edok = bmesh_cycle_validate(valance2+1, d2);
+ if(!edok) bmesh_error();
+
+ /*verify that edge actually made it into the cycle*/
+ edok = bmesh_disk_hasedge(v1, e);
+ if(!edok) bmesh_error();
+ edok = bmesh_disk_hasedge(v2, e);
+ if(!edok) bmesh_error();
+ #endif
+ return e;
+}
+
+
+
+/**
+ * bmesh_MF
+ *
+ * MAKE FACE EULER:
+ * Takes a list of edge pointers which form a closed loop and makes a face
+ * from them. The first edge in elist is considered to be the start of the
+ * polygon, and v1 and v2 are its vertices and determine the winding of the face
+ * Other than the first edge, no other assumptions are made about the order of edges
+ * in the elist array. To verify that it is a single closed loop and derive the correct
+ * order a simple series of verifications is done and all elements are visited.
+ *
+ * Returns -
+ * A BMFace pointer
+ */
+
+#define MF_CANDIDATE 1
+#define MF_VISITED 2
+#define MF_TAKEN 4
+
+BMFace *bmesh_mf(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **elist, int len)
+{
+ BMFace *f = NULL;
+ BMEdge *curedge;
+ BMVert *curvert, *tv, **vlist;
+ int i, j, done, cont, edok;
+
+ if(len < 2) return NULL;
+
+ /*make sure that v1 and v2 are in elist[0]*/
+ if(bmesh_verts_in_edge(v1,v2,elist[0]) == 0)
+ return NULL;
+
+ /*clear euler flags*/
+ for(i=0;i<len;i++) elist[i]->head.eflag1=elist[i]->head.eflag2 = 0;
+ for(i=0;i<len;i++){
+ elist[i]->head.eflag1 |= MF_CANDIDATE;
+
+ /*if elist[i] has a loop, count its radial length*/
+ if(elist[i]->loop) elist[i]->head.eflag2 = bmesh_cycle_length(&(elist[i]->loop->radial));
+ else elist[i]->head.eflag2 = 0;
+ }
+
+ /* For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it
+ Note that this does not gauruntee that face is a single closed loop. At best it gauruntees
+ that elist contains a finite number of seperate closed loops.
+ */
+ for(i=0; i<len; i++){
+ edok = bmesh_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
+ if(edok != 2) return NULL;
+ edok = bmesh_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
+ if(edok != 2) return NULL;
+ }
+
+ /*set start edge, start vert and target vert for our loop traversal*/
+ curedge = elist[0];
+ tv = v1;
+ curvert = v2;
+
+ if(bm->vtarlen < len){
+ if (bm->vtar) MEM_freeN(bm->vtar);
+ bm->vtar = MEM_callocN(sizeof(BMVert *)* len, "BM Vert pointer array");
+ bm->vtarlen = len;
+ }
+ /*insert tv into vlist since its the first vertex in face*/
+
+ i=0;
+ vlist=bm->vtar;
+ vlist[i] = tv;
+
+ /* Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't
+ been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE
+ edge, loop until we find TV. We know TV is reachable because of test we did earlier.
+ */
+ done=0;
+ while(!done){
+ /*add curvert to vlist*/
+ /*insert some error cheking here for overflows*/
+ i++;
+ vlist[i] = curvert;
+
+ /*mark curedge as visited*/
+ curedge->head.eflag1 |= MF_VISITED;
+
+ /*find next edge and vert*/
+ curedge = bmesh_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
+ curvert = bmesh_edge_getothervert(curedge, curvert);
+ if(curvert == tv){
+ curedge->head.eflag1 |= MF_VISITED;
+ done=1;
+ }
+ }
+
+ /* Verify that all edges have been visited It's possible that we did reach tv
+ from sv, but that several unconnected loops were passed in via elist.
+ */
+ cont=1;
+ for(i=0; i<len; i++){
+ if((elist[i]->head.eflag1 & MF_VISITED) == 0) cont = 0;
+ }
+
+ /*if we get this far, its ok to allocate the face and add the loops*/
+ if(cont){
+ BMLoop *l;
+ BMEdge *e;
+ f = bmesh_addpolylist(bm, NULL);
+ f->len = len;
+ for(i=0;i<len;i++){
+ curvert = vlist[i];
+ l = bmesh_create_loop(bm,curvert,NULL,f,NULL);
+ if(!(f->loopbase)) f->loopbase = l;
+ bmesh_cycle_append(f->loopbase, l);
+ }
+
+ /*take care of edge pointers and radial cycle*/
+ for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->head.next))){
+ e = NULL;
+ if(l == f->loopbase) e = elist[0]; /*first edge*/
+
+ else{/*search elist for others*/
+ for(j=1; j<len; j++){
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, elist[j]);
+ if(edok){
+ e = elist[j];
+ break;
+ }
+ }
+ }
+ l->e = e; /*set pointer*/
+ bmesh_radial_append(e, l); /*append into radial*/
+ }
+
+ f->len = len;
+
+ /*Validation Loop cycle*/
+ edok = bmesh_cycle_validate(len, f->loopbase);
+ if(!edok) bmesh_error();
+ for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->head.next))){
+ /*validate loop vert pointers*/
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, l->e);
+ if(!edok) bmesh_error();
+ /*validate the radial cycle of each edge*/
+ edok = bmesh_cycle_length(&(l->radial));
+ if(edok != (l->e->head.eflag2 + 1)) bmesh_error();
+ }
+ }
+
+ for(i=0;i<len;i++) elist[i]->head.eflag1=elist[i]->head.eflag2 = 0;
+ return f;
+}
+
+/* KILL Eulers */
+
+/**
+ * bmesh_KV
+ *
+ * KILL VERT EULER:
+ *
+ * Kills a single loose vertex.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_kv(BMesh *bm, BMVert *v){
+ if(v->edge == NULL){
+ if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel--;
+
+ BLI_remlink(&(bm->verts), &(v->head));
+ bmesh_free_vert(bm,v);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * bmesh_KE
+ *
+ * KILL EDGE EULER:
+ *
+ * Kills a wire edge.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_ke(BMesh *bm, BMEdge *e){
+ int edok;
+
+ /*Make sure that no faces!*/
+ if(e->loop == NULL){
+ bmesh_disk_remove_edge(e, e->v1);
+ bmesh_disk_remove_edge(e, e->v2);
+
+ /*verify that edge out of disk*/
+ edok = bmesh_disk_hasedge(e->v1, e);
+ if(edok) bmesh_error();
+ edok = bmesh_disk_hasedge(e->v2, e);
+ if(edok) bmesh_error();
+
+ /*remove and deallocate*/
+ if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel--;
+ BLI_remlink(&(bm->edges), &(e->head));
+ bmesh_free_edge(bm, e);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * bmesh_KF
+ *
+ * KILL FACE EULER:
+ *
+ * The logical inverse of bmesh_MF.
+ * Kills a face and removes each of its loops from the radial that it belongs to.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+*/
+
+int bmesh_kf(BMesh *bm, BMFace *bply){
+ BMLoop *newbase,*oldbase, *curloop;
+ int i,len=0;
+
+ /*add validation to make sure that radial cycle is cleaned up ok*/
+ /*deal with radial cycle first*/
+ len = bmesh_cycle_length(bply->loopbase);
+ for(i=0, curloop=bply->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)))
+ bmesh_radial_remove_loop(curloop, curloop->e);
+
+ /*now deallocate the editloops*/
+ for(i=0; i < len; i++){
+ newbase = ((BMLoop*)(bply->loopbase->head.next));
+ oldbase = bply->loopbase;
+ bmesh_cycle_remove(oldbase, oldbase);
+ bmesh_free_loop(bm, oldbase);
+ bply->loopbase = newbase;
+ }
+
+ if (BM_TestHFlag(bply, BM_SELECT)) bm->totfacesel--;
+ BLI_remlink(&(bm->polys), &(bply->head));
+ bmesh_free_poly(bm, bply);
+ return 1;
+}
+
+/*SPLIT Eulers*/
+
+/**
+ * bmesh_SEMV
+ *
+ * SPLIT EDGE MAKE VERT:
+ * Takes a given edge and splits it into two, creating a new vert.
+ *
+ *
+ * Before: OV---------TV
+ * After: OV----NV---TV
+ *
+ * Returns -
+ * BMVert pointer.
+ *
+*/
+
+BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **re){
+ BMVert *nv, *ov;
+ BMNode *diskbase;
+ BMEdge *ne;
+ int i, edok, valance1=0, valance2=0;
+
+ if(bmesh_vert_in_edge(e,tv) == 0) return NULL;
+ ov = bmesh_edge_getothervert(e,tv);
+ //v2 = tv;
+
+ /*count valance of v1*/
+ diskbase = bmesh_disk_getpointer(e, ov);
+ valance1 = bmesh_cycle_length(diskbase);
+ /*count valance of v2*/
+ diskbase = bmesh_disk_getpointer(e, tv);
+ valance2 = bmesh_cycle_length(diskbase);
+
+ nv = bmesh_addvertlist(bm, tv);
+ ne = bmesh_addedgelist(bm, nv, tv, e);
+
+ //e->v2 = nv;
+ /*remove e from v2's disk cycle*/
+ bmesh_disk_remove_edge(e, tv);
+ /*swap out tv for nv in e*/
+ bmesh_edge_swapverts(e, tv, nv);
+ /*add e to nv's disk cycle*/
+ bmesh_disk_append_edge(e, nv);
+ /*add ne to nv's disk cycle*/
+ bmesh_disk_append_edge(ne, nv);
+ /*add ne to tv's disk cycle*/
+ bmesh_disk_append_edge(ne, tv);
+ /*verify disk cycles*/
+ diskbase = bmesh_disk_getpointer(ov->edge,ov);
+ edok = bmesh_cycle_validate(valance1, diskbase);
+ if(!edok) bmesh_error();
+ diskbase = bmesh_disk_getpointer(tv->edge,tv);
+ edok = bmesh_cycle_validate(valance2, diskbase);
+ if(!edok) bmesh_error();
+ diskbase = bmesh_disk_getpointer(nv->edge,nv);
+ edok = bmesh_cycle_validate(2, diskbase);
+ if(!edok) bmesh_error();
+
+ /*Split the radial cycle if present*/
+ if(e->loop){
+ BMLoop *nl,*l;
+ BMNode *radEBase=NULL, *radNEBase=NULL;
+ int radlen = bmesh_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++;
+ bmesh_radial_remove_loop(l,e);
+
+ nl = bmesh_create_loop(bm,NULL,NULL,l->f,l);
+ nl->head.prev = (BMHeader*)l;
+ nl->head.next = (BMHeader*)(l->head.next);
+ nl->head.prev->next = (BMHeader*)nl;
+ nl->head.next->prev = (BMHeader*)nl;
+ nl->v = nv;
+
+ /*assign the correct edge to the correct loop*/
+ if(bmesh_verts_in_edge(nl->v, ((BMLoop*)(nl->head.next))->v, e)){
+ nl->e = e;
+ l->e = ne;
+
+ /*append l into ne's rad cycle*/
+ if(!radNEBase){
+ radNEBase = &(l->radial);
+ radNEBase->next = NULL;
+ radNEBase->prev = NULL;
+ }
+
+ if(!radEBase){
+ radEBase = &(nl->radial);
+ radEBase->next = NULL;
+ radEBase->prev = NULL;
+ }
+
+ bmesh_cycle_append(radEBase,&(nl->radial));
+ bmesh_cycle_append(radNEBase,&(l->radial));
+
+ }
+ else if(bmesh_verts_in_edge(nl->v,((BMLoop*)(nl->head.next))->v,ne)){
+ nl->e = ne;
+ l->e = e;
+
+ if(!radNEBase){
+ radNEBase = &(nl->radial);
+ radNEBase->next = NULL;
+ radNEBase->prev = NULL;
+ }
+ if(!radEBase){
+ radEBase = &(l->radial);
+ radEBase->next = NULL;
+ radEBase->prev = NULL;
+ }
+ bmesh_cycle_append(radEBase,&(l->radial));
+ bmesh_cycle_append(radNEBase,&(nl->radial));
+ }
+
+ }
+
+ e->loop = radEBase->data;
+ ne->loop = radNEBase->data;
+
+ /*verify length of radial cycle*/
+ edok = bmesh_cycle_validate(radlen,&(e->loop->radial));
+ if(!edok) bmesh_error();
+ edok = bmesh_cycle_validate(radlen,&(ne->loop->radial));
+ if(!edok) bmesh_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)) bmesh_error();
+ if(!(l->radial.data == l)) bmesh_error();
+ if( ((BMLoop*)(l->head.prev))->e != ne && ((BMLoop*)(l->head.next))->e != ne) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, e);
+ if(!edok) bmesh_error();
+ if(l->v == ((BMLoop*)(l->head.next))->v) bmesh_error();
+ if(l->e == ((BMLoop*)(l->head.next))->e) bmesh_error();
+ /*verify loop cycle for kloop->f*/
+ edok = bmesh_cycle_validate(l->f->len, l->f->loopbase);
+ if(!edok) bmesh_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)) bmesh_error();
+ if(!(l->radial.data == l)) bmesh_error();
+ if( ((BMLoop*)(l->head.prev))->e != e && ((BMLoop*)(l->head.next))->e != e) bmesh_error();
+ edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, ne);
+ if(!edok) bmesh_error();
+ if(l->v == ((BMLoop*)(l->head.next))->v) bmesh_error();
+ if(l->e == ((BMLoop*)(l->head.next))->e) bmesh_error();
+ /*verify loop cycle for kloop->f. Redundant*/
+ edok = bmesh_cycle_validate(l->f->len, l->f->loopbase);
+ if(!edok) bmesh_error();
+ }
+ }
+
+ if(re) *re = ne;
+ return nv;
+}
+
+/**
+ * bmesh_SFME
+ *
+ * SPLIT FACE MAKE EDGE:
+ *
+ * Takes as input two vertices in a single face. An edge is created which divides the original face
+ * into two distinct regions. One of the regions is assigned to the original face and it is closed off.
+ * The second region has a new face assigned to it.
+ *
+ * Examples:
+ *
+ * Before: After:
+ * ---------- ----------
+ * | | | |
+ * | | | f1 |
+ * v1 f1 v2 v1======v2
+ * | | | f2 |
+ * | | | |
+ * ---------- ----------
+ *
+ * Note that the input vertices can be part of the same edge. This will result in a two edged face.
+ * This is desirable for advanced construction tools and particularly essential for edge bevel. Because
+ * of this it is up to the caller to decide what to do with the extra edge.
+ *
+ * Note that the tesselator abuses eflag2 while using this euler! (don't ever ever do this....)
+ *
+ * Returns -
+ * A BMFace pointer
+ */
+BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **rl){
+
+ BMFace *f2;
+ BMLoop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
+ BMEdge *e;
+ int i, len, f1len, f2len;
+
+
+ /*verify that v1 and v2 are in face.*/
+ len = bmesh_cycle_length(f->loopbase);
+ for(i = 0, curloop = f->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ if(curloop->v == v1) v1loop = curloop;
+ else if(curloop->v == v2) v2loop = curloop;
+ }
+
+ if(!v1loop || !v2loop) return NULL;
+
+ /*allocate new edge between v1 and v2*/
+ e = bmesh_addedgelist(bm, v1, v2,NULL);
+ bmesh_disk_append_edge(e, v1);
+ bmesh_disk_append_edge(e, v2);
+
+ f2 = bmesh_addpolylist(bm,f);
+ f1loop = bmesh_create_loop(bm,v2,e,f,v2loop);
+ f2loop = bmesh_create_loop(bm,v1,e,f2,v1loop);
+
+ f1loop->head.prev = v2loop->head.prev;
+ f2loop->head.prev = v1loop->head.prev;
+ v2loop->head.prev->next = (BMHeader*)f1loop;
+ v1loop->head.prev->next = (BMHeader*)f2loop;
+
+ f1loop->head.next = (BMHeader*)v1loop;
+ f2loop->head.next = (BMHeader*)v2loop;
+ v1loop->head.prev = (BMHeader*)f1loop;
+ v2loop->head.prev = (BMHeader*)f2loop;
+
+ f2->loopbase = f2loop;
+ f->loopbase = f1loop;
+
+ /*validate both loops*/
+ /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
+
+ /*go through all of f2's loops and make sure they point to it properly.*/
+ f2len = bmesh_cycle_length(f2->loopbase);
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->f = f2;
+
+ /*link up the new loops into the new edges radial*/
+ bmesh_radial_append(e, f1loop);
+ bmesh_radial_append(e, f2loop);
+
+
+ f2->len = f2len;
+
+ f1len = bmesh_cycle_length(f->loopbase);
+ f->len = f1len;
+
+ if(rl) *rl = f2loop;
+ return f2;
+}
+
+
+/**
+ * bmesh_JEKV
+ *
+ * JOIN EDGE KILL VERT:
+ * Takes a an edge and pointer to one of its vertices and collapses
+ * the edge on that vertex.
+ *
+ * Before: OE KE
+ * ------- -------
+ * | || |
+ * OV KV TV
+ *
+ *
+ * After: OE
+ * ---------------
+ * | |
+ * OV TV
+ *
+ *
+ * Restrictions:
+ * KV is a vertex that must have a valance of exactly two. Furthermore
+ * both edges in KV's disk cycle (OE and KE) must be unique (no double
+ * edges).
+ *
+ * It should also be noted that this euler has the possibility of creating
+ * faces with just 2 edges. It is up to the caller to decide what to do with
+ * these faces.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+int bmesh_jekv(BMesh *bm, BMEdge *ke, BMVert *kv)
+{
+ BMEdge *oe;
+ BMVert *ov, *tv;
+ BMNode *diskbase;
+ BMLoop *killoop,*nextl;
+ int len,radlen=0, halt = 0, i, valance1, valance2,edok;
+
+ if(bmesh_vert_in_edge(ke,kv) == 0) return 0;
+ diskbase = bmesh_disk_getpointer(kv->edge, kv);
+ len = bmesh_cycle_length(diskbase);
+
+ if(len == 2){
+ oe = bmesh_disk_nextedge(ke, kv);
+ tv = bmesh_edge_getothervert(ke, kv);
+ ov = bmesh_edge_getothervert(oe, kv);
+ halt = bmesh_verts_in_edge(kv, tv, oe); //check for double edges
+
+ if(halt) return 0;
+ else{
+
+ /*For verification later, count valance of ov and tv*/
+ diskbase = bmesh_disk_getpointer(ov->edge, ov);
+ valance1 = bmesh_cycle_length(diskbase);
+ diskbase = bmesh_disk_getpointer(tv->edge, tv);
+ valance2 = bmesh_cycle_length(diskbase);
+
+ /*remove oe from kv's disk cycle*/
+ bmesh_disk_remove_edge(oe,kv);
+ /*relink oe->kv to be oe->tv*/
+ bmesh_edge_swapverts(oe, kv, tv);
+ /*append oe to tv's disk cycle*/
+ bmesh_disk_append_edge(oe, tv);
+ /*remove ke from tv's disk cycle*/
+ bmesh_disk_remove_edge(ke, tv);
+
+
+
+ /*deal with radial cycle of ke*/
+ if(ke->loop){
+ /*first step, fix the neighboring loops of all loops in ke's radial cycle*/
+ radlen = bmesh_cycle_length(&(ke->loop->radial));
+ for(i=0,killoop = ke->loop; i<radlen; i++, killoop = bmesh_radial_nextloop(killoop)){
+ /*relink loops and fix vertex pointer*/
+ killoop->head.next->prev = killoop->head.prev;
+ killoop->head.prev->next = killoop->head.next;
+ if( ((BMLoop*)(killoop->head.next))->v == kv) ((BMLoop*)(killoop->head.next))->v = tv;
+
+ /*fix len attribute of face*/
+ killoop->f->len--;
+ if(killoop->f->loopbase == killoop) killoop->f->loopbase = ((BMLoop*)(killoop->head.next));
+ }
+ /*second step, remove all the hanging loops attached to ke*/
+ killoop = ke->loop;
+ radlen = bmesh_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(BMLoop *)* radlen, "BM Loop pointer array");
+ bm->lparlen = bm->lparlen * radlen;
+ }
+ /*this should be wrapped into a bme_free_radial function to be used by bmesh_KF as well...*/
+ i=0;
+ while(i<radlen){
+ bm->lpar[i] = killoop;
+ killoop = killoop->radial.next->data;
+ i++;
+ }
+ i=0;
+ while(i<radlen){
+ bmesh_free_loop(bm,bm->lpar[i]);
+ i++;
+ }
+ /*Validate radial cycle of oe*/
+ edok = bmesh_cycle_validate(radlen,&(oe->loop->radial));
+
+ }
+
+
+ /*Validate disk cycles*/
+ diskbase = bmesh_disk_getpointer(ov->edge,ov);
+ edok = bmesh_cycle_validate(valance1, diskbase);
+ if(!edok) bmesh_error();
+ diskbase = bmesh_disk_getpointer(tv->edge,tv);
+ edok = bmesh_cycle_validate(valance2, diskbase);
+ if(!edok) bmesh_error();
+
+ /*Validate loop cycle of all faces attached to oe*/
+ for(i=0,nextl = oe->loop; i<radlen; i++, nextl = bmesh_radial_nextloop(nextl)){
+ edok = bmesh_cycle_validate(nextl->f->len,nextl->f->loopbase);
+ if(!edok) bmesh_error();
+ }
+ /*deallocate edge*/
+ BLI_remlink(&(bm->edges), &(ke->head));
+ bmesh_free_edge(bm, ke);
+ /*deallocate vertex*/
+ BLI_remlink(&(bm->verts), &(kv->head));
+ bmesh_free_vert(bm, kv);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * bmesh_loop_reverse
+ *
+ * FLIP FACE EULER
+ *
+ * Changes the winding order of a face from CW to CCW or vice versa.
+ * This euler is a bit peculiar in compairson to others as it is its
+ * own inverse.
+ *
+ * TODO: reinsert validation code.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_loop_reverse(BMesh *bm, BMFace *f){
+ BMLoop *l = f->loopbase, *curloop, *oldprev, *oldnext;
+ int i, j, edok, len = 0;
+
+ len = bmesh_cycle_length(l);
+ if(bm->edarlen < len){
+ MEM_freeN(bm->edar);
+ bm->edar = MEM_callocN(sizeof(BMEdge *)* len, "BM Edge pointer array");
+ bm->edarlen = len;
+ }
+
+ for(i=0, curloop = l; i< len; i++, curloop= ((BMLoop*)(curloop->head.next)) ){
+ curloop->e->head.eflag1 = 0;
+ curloop->e->head.eflag2 = bmesh_cycle_length(&curloop->radial);
+ bmesh_radial_remove_loop(curloop, curloop->e);
+ /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
+ curloop->radial.next = curloop->radial.prev = NULL;
+ bm->edar[i] = curloop->e;
+ }
+
+ /*actually reverse the loop. This belongs in bmesh_cycle_reverse!*/
+ for(i=0, curloop = l; i < len; i++){
+ oldnext = ((BMLoop*)(curloop->head.next));
+ oldprev = ((BMLoop*)(curloop->head.prev));
+ curloop->head.next = (BMHeader*)oldprev;
+ curloop->head.prev = (BMHeader*)oldnext;
+ curloop = oldnext;
+ }
+
+ if(len == 2){ //two edged face
+ //do some verification here!
+ l->e = bm->edar[1];
+ ((BMLoop*)(l->head.next))->e = bm->edar[0];
+ }
+ else{
+ for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ edok = 0;
+ for(j=0; j < len; j++){
+ edok = bmesh_verts_in_edge(curloop->v, ((BMLoop*)(curloop->head.next))->v, bm->edar[j]);
+ if(edok){
+ curloop->e = bm->edar[j];
+ break;
+ }
+ }
+ }
+ }
+ /*rebuild radial*/
+ for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) bmesh_radial_append(curloop->e, curloop);
+
+ /*validate radial*/
+ for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ edok = bmesh_cycle_validate(curloop->e->head.eflag2, &(curloop->radial));
+ if(!edok){
+ bmesh_error();
+ }
+ }
+ return 1;
+}
+
+/**
+ * bmesh_JFKE
+ *
+ * JOIN FACE KILL EDGE:
+ *
+ * Takes two faces joined by a single 2-manifold edge and fuses them togather.
+ * The edge shared by the faces must not be connected to any other edges which have
+ * Both faces in its radial cycle
+ *
+ * Examples:
+ *
+ * A B
+ * ---------- ----------
+ * | | | |
+ * | f1 | | f1 |
+ * v1========v2 = Ok! v1==V2==v3 == Wrong!
+ * | f2 | | f2 |
+ * | | | |
+ * ---------- ----------
+ *
+ * In the example A, faces f1 and f2 are joined by a single edge, and the euler can safely be used.
+ * In example B however, f1 and f2 are joined by multiple edges and will produce an error. The caller
+ * in this case should call bmesh_JEKV on the extra edges before attempting to fuse f1 and f2.
+ *
+ * Also note that the order of arguments decides whether or not certain per-face attributes are present
+ * in the resultant face. For instance vertex winding, material index, smooth flags, ect are inherited
+ * from f1, not f2.
+ *
+ * Returns -
+ * A BMFace pointer
+*/
+
+//disregarding f1loop and f2loop, if a vertex appears in a joined face more than once, we cancel
+
+BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
+{
+
+ BMLoop *curloop, *f1loop=NULL, *f2loop=NULL;
+ int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok, shared;
+
+ if(f1 == f2) return NULL; //can't join a face to itself
+ /*verify that e is in both f1 and f2*/
+ f1len = bmesh_cycle_length(f1->loopbase);
+ f2len = bmesh_cycle_length(f2->loopbase);
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ if(curloop->e == e){
+ f1loop = curloop;
+ break;
+ }
+ }
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ if(curloop->e==e){
+ f2loop = curloop;
+ break;
+ }
+ }
+ if(!(f1loop && f2loop)) return NULL;
+
+ /*validate that edge is 2-manifold edge*/
+ radlen = bmesh_cycle_length(&(f1loop->radial));
+ if(radlen != 2) return NULL;
+
+ /*validate direction of f2's loop cycle is compatible.*/
+ if(f1loop->v == f2loop->v) return NULL;
+
+ /*
+ validate that for each face, each vertex has another edge in its disk cycle that is
+ not e, and not shared.
+ */
+ if(bmesh_radial_find_face( ((BMLoop*)(f1loop->head.next))->e,f2)) return NULL;
+ if(bmesh_radial_find_face( ((BMLoop*)(f1loop->head.prev))->e,f2)) return NULL;
+ if(bmesh_radial_find_face( ((BMLoop*)(f2loop->head.next))->e,f1)) return NULL;
+ if(bmesh_radial_find_face( ((BMLoop*)(f2loop->head.prev))->e,f1)) return NULL;
+
+ /*validate only one shared edge*/
+ shared = BM_Face_Sharededges(f1,f2);
+ if(shared > 1) return NULL;
+
+ /*validate no internal joins*/
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->v->head.eflag1 = 0;
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->v->head.eflag1 = 0;
+
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ if(curloop != f1loop)
+ curloop->v->head.eflag1++;
+ }
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ if(curloop != f2loop)
+ curloop->v->head.eflag1++;
+ }
+
+ for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ if(curloop->v->head.eflag1 > 1)
+ return NULL;
+ }
+
+ for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
+ if(curloop->v->head.eflag1 > 1)
+ return NULL;
+ }
+
+ /*join the two loops*/
+ f1loop->head.prev->next = f2loop->head.next;
+ f2loop->head.next->prev = f1loop->head.prev;
+
+ f1loop->head.next->prev = f2loop->head.prev;
+ f2loop->head.prev->next = f1loop->head.next;
+
+ /*if f1loop was baseloop, give f1loop->next the base.*/
+ if(f1->loopbase == f1loop) f1->loopbase = ((BMLoop*)(f1loop->head.next));
+
+ /*validate the new loop*/
+ loopok = bmesh_cycle_validate((f1len+f2len)-2, f1->loopbase);
+ if(!loopok) bmesh_error();
+
+ /*make sure each loop points to the proper face*/
+ newlen = bmesh_cycle_length(f1->loopbase);
+ for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->f = f1;
+
+ f1->len = newlen;
+
+ edok = bmesh_cycle_validate(f1->len, f1->loopbase);
+ if(!edok) bmesh_error();
+
+ /*remove edge from the disk cycle of its two vertices.*/
+ bmesh_disk_remove_edge(f1loop->e, f1loop->e->v1);
+ bmesh_disk_remove_edge(f1loop->e, f1loop->e->v2);
+
+ /*deallocate edge and its two loops as well as f2*/
+ BLI_remlink(&(bm->edges), &(f1loop->e->head));
+ BLI_remlink(&(bm->polys), &(f2->head));
+ bmesh_free_edge(bm, f1loop->e);
+ bmesh_free_loop(bm, f1loop);
+ bmesh_free_loop(bm, f2loop);
+ bmesh_free_poly(bm, f2);
+ return f1;
+}
+
+/**
+* bmesh_URMV
+*
+* UNGLUE REGION MAKE VERT:
+*
+* Takes a locally manifold disk of face corners and 'unglues' it
+* creating a new vertex
+*
+**/
+
+#define URMV_VISIT 1
+#define URMV_VISIT2 2
+
+BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv)
+{
+ BMVert *nv = NULL;
+ BMLoop *l = NULL, *sl = NULL;
+ BMEdge *curedge = NULL;
+ int numloops = 0, numedges = 0, i, maxedges, maxloops;
+
+
+ /*Todo: Validation*/
+ /*validate radial cycle of all collected loops*/
+ /*validate the disk cycle of sv, and nv*/
+ /*validate the face length of all faces? overkill?*/
+ /*validate the l->e pointers of all affected faces, ie: l->v and l->next->v should be equivalent to l->e*/
+
+ /*verify that sv has edges*/
+ if(sv->edge == NULL)
+ return NULL;
+
+ /*first verify no wire edges on sv*/
+ curedge = sv->edge;
+ do{
+ if(curedge->loop == NULL)
+ return NULL;
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->edge);
+
+ /*next verify that sv is in sf*/
+ l = sf->loopbase;
+ do{
+ if(l->v == sv){
+ sl = l;
+ break;
+ }
+ l = (BMLoop*)(l->head.next);
+ }while(l != sf->loopbase);
+
+ if(sl == NULL)
+ return NULL;
+
+ /*clear euler flags*/
+ sv->head.eflag1 = 0;
+
+ curedge = sv->edge;
+ do{
+ curedge->head.eflag1 = 0;
+ l = curedge->loop;
+ do{
+ l->head.eflag1 = 0;
+ l->f->head.eflag1 = 0;
+ l = bmesh_radial_nextloop(l);
+ }while(l != curedge->loop);
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->edge);
+
+ /*search through face disk and flag elements as we go.*/
+ /*Note, test this to make sure that it works correct on
+ non-manifold faces!
+ */
+ l = sl;
+ l->e->head.eflag1 |= URMV_VISIT;
+ l->f->head.eflag1 |= URMV_VISIT;
+ do{
+ if(l->v == sv)
+ l = bmesh_radial_nextloop((BMLoop*)(l->head.prev));
+ else
+ l = bmesh_radial_nextloop((BMLoop*)(l->head.next));
+ l->e->head.eflag1 |= URMV_VISIT;
+ l->f->head.eflag1 |= URMV_VISIT;
+ }while(l != sl && (bmesh_cycle_length(&(l->radial)) > 1) );
+
+ /*Verify that all visited edges are at least 1 or 2 manifold*/
+ curedge = sv->edge;
+ do{
+ if(curedge->head.eflag1 && (bmesh_cycle_length(&(curedge->loop->radial)) > 2) )
+ return NULL;
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->edge);
+
+ /*allocate temp storage - we overallocate here instead of trying to be clever*/
+ maxedges = 0;
+ maxloops = 0;
+ curedge = sv->edge;
+ do{
+ if(curedge->loop){
+ l = curedge->loop;
+ do{
+ maxloops += l->f->len;
+ l = bmesh_radial_nextloop(l);
+ }while(l != curedge->loop);
+ }
+ maxedges+= 1;
+ curedge = bmesh_disk_nextedge(curedge,sv);
+ }while(curedge != sv->edge);
+
+ if(bm->edarlen < maxedges){
+ MEM_freeN(bm->edar);
+ bm->edar = MEM_callocN(sizeof(BMEdge *) * maxedges, "BM Edge pointer array");
+ bm->edarlen = maxedges;
+ }
+ if(bm->lparlen < maxloops){
+ MEM_freeN(bm->lpar);
+ bm->lpar = MEM_callocN(sizeof(BMLoop *) * maxloops, "BM Loop pointer array");
+ bm->lparlen = maxloops;
+ }
+
+ /*first get loops by looping around edges and loops around that edges faces*/
+ curedge = sv->edge;
+ do{
+ if(curedge->loop){
+ l = curedge->loop;
+ do{
+ if( (l->head.eflag1 & URMV_VISIT) && (!(l->head.eflag1 & URMV_VISIT2)) ){
+ bm->lpar[numloops] = l;
+ l->head.eflag1 |= URMV_VISIT2;
+ numloops++;
+ }
+ l = bmesh_radial_nextloop(l);
+ }while(l != curedge->loop);
+ }
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->edge);
+
+ /*now collect edges by looping around edges and looking at visited flags*/
+ curedge = sv->edge;
+ do{
+ if(curedge->head.eflag1 & URMV_VISIT){
+ bm->edar[numedges] = curedge;
+ numedges++;
+ }
+ curedge = bmesh_disk_nextedge(curedge, sv);
+ }while(curedge != sv->edge);
+
+ /*make new vertex*/
+ nv = bmesh_addvertlist(bm, sv);
+
+ /*go through and relink edges*/
+ for(i = 0; i < numedges; i++){
+ curedge = bm->edar[i];
+ /*remove curedge from sv*/
+ bmesh_disk_remove_edge(curedge, sv);
+ /*swap out sv for nv in curedge*/
+ bmesh_edge_swapverts(curedge, sv, nv);
+ /*add curedge to nv's disk cycle*/
+ bmesh_disk_append_edge(curedge, nv);
+ }
+
+ /*go through and relink loops*/
+ for(i = 0; i < numloops; i ++){
+ l = bm->lpar[i];
+ if(l->v == sv)
+ l->v = nv;
+ }
+ return nv;
+}
diff --git a/source/blender/bmesh/intern/bmesh_filters.c b/source/blender/bmesh/intern/bmesh_filters.c
new file mode 100644
index 00000000000..c31139a8f93
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_filters.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "bmesh.h"
+#include "bmesh_private.h"
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
new file mode 100644
index 00000000000..ae0904a75df
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -0,0 +1,246 @@
+/**
+ * BME_interp.c August 2008
+ *
+ * BM interpolation functions.
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ * BME_INTERP.C
+ *
+ * Functions for interpolating data across the surface of a mesh.
+ *
+*/
+
+/**
+ * bmesh_data_interp_from_verts
+ *
+ * Interpolates per-vertex data from two sources to a target.
+ *
+ * Returns -
+ * Nothing
+ */
+void BM_Data_Interp_From_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, float fac)
+{
+ void *src[2];
+ float w[2];
+ if (v1->head.data && v2->head.data) {
+ src[0]= v1->head.data;
+ src[1]= v2->head.data;
+ w[0] = 1.0f-fac;
+ w[1] = fac;
+ CustomData_bmesh_interp(&bm->vdata, src, w, NULL, 2, v->head.data);
+ }
+}
+
+/**
+ * bmesh_data_facevert_edgeinterp
+ *
+ * Walks around the faces of an edge and interpolates the per-face-edge
+ * data between two sources to a target.
+ *
+ * Returns -
+ * Nothing
+*/
+
+void BM_Data_Facevert_Edgeinterp(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, BMEdge *e1, float fac){
+ void *src[2];
+ float w[2];
+ BMLoop *l=NULL, *v1loop = NULL, *vloop = NULL, *v2loop = NULL;
+
+ w[1] = 1.0f - fac;
+ w[0] = fac;
+
+ if(!e1->loop) return;
+ l = e1->loop;
+ do{
+ if(l->v == v1){
+ v1loop = l;
+ vloop = (BMLoop*)(v1loop->head.next);
+ v2loop = (BMLoop*)(vloop->head.next);
+ }else if(l->v == v){
+ v1loop = (BMLoop*)(l->head.next);
+ vloop = l;
+ v2loop = (BMLoop*)(l->head.prev);
+
+ }
+
+ src[0] = v1loop->head.data;
+ src[1] = v2loop->head.data;
+
+ CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, vloop->head.data);
+ l = l->radial.next->data;
+ }while(l!=e1->loop);
+}
+
+void BM_loops_to_corners(BMesh *bm, Mesh *me, int findex,
+ BMFace *f, int numTex, int numCol)
+{
+ BMLoop *l;
+ BMIter iter;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ int i, j;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ j = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+
+ j++;
+ }
+
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
+
+ j = 0;
+ BM_ITER(l, &iter, bm, BM_LOOPS_OF_FACE, f) {
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+
+ j++;
+ }
+ }
+}
+
+//static void bmesh_data_interp_from_face(BME_Mesh *bm, BMFace *source, BMFace *target)
+//{
+//
+//}
+/*insert BM_data_interp_from_face here for mean value coordinates...*/
+
+
+static void update_data_blocks(BMesh *bm, CustomData *olddata, CustomData *data)
+{
+ BMIter iter;
+ void *block;
+
+ if (data == &bm->vdata) {
+ BMVert *eve;
+
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, eve->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &eve->head.data);
+ eve->head.data= block;
+ }
+ }
+ else if (data == &bm->edata) {
+ BMEdge *eed;
+
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, eed->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &eed->head.data);
+ eed->head.data= block;
+ }
+ }
+ else if (data == &bm->pdata || data == &bm->ldata) {
+ BMIter liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (data == &bm->pdata) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, efa->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &efa->head.data);
+ efa->head.data= block;
+ }
+
+ if (data == &bm->ldata) {
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+ block = NULL;
+ CustomData_bmesh_set_default(data, &block);
+ CustomData_bmesh_copy_data(olddata, data, l->head.data, &block);
+ CustomData_bmesh_free_block(olddata, &l->head.data);
+ l->head.data= block;
+ }
+ }
+ }
+ }
+}
+
+
+void BM_add_data_layer(BMesh *bm, CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata= *data;
+ olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+ CustomData_add_layer(data, type, CD_CALLOC, NULL, 0);
+
+ update_data_blocks(bm, &olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+void BM_free_data_layer(BMesh *bm, CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata= *data;
+ olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+ CustomData_free_layer_active(data, type, 0);
+
+ update_data_blocks(bm, &olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+} \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
new file mode 100644
index 00000000000..73c76817254
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -0,0 +1,393 @@
+#include <string.h>
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+
+void *BMIter_AtIndex(struct BMesh *bm, int type, void *data, int index)
+{
+ BMIter iter;
+ void *val;
+ int i;
+
+ /*sanity check*/
+ if (index < 0) return NULL;
+
+ val=BMIter_New(&iter, bm, type, data);
+
+ i = 0;
+ while (i < index) {
+ val=BMIter_Step(&iter);
+ i++;
+ }
+
+ return val;
+}
+
+/*
+ * BMESH ITERATOR STEP
+ *
+ * Calls an iterators step fucntion to return
+ * the next element.
+*/
+
+void *BMIter_Step(BMIter *iter)
+{
+ return iter->step(iter);
+}
+
+/*
+ * INIT ITERATOR
+ *
+ * Clears the internal state of an iterator
+ * For begin() callbacks.
+ *
+*/
+
+static void init_iterator(BMIter *iter)
+{
+ iter->firstvert = iter->nextvert = NULL;
+ iter->firstedge = iter->nextedge = NULL;
+ iter->firstloop = iter->nextloop = NULL;
+ iter->firstpoly = iter->nextpoly = NULL;
+ iter->ldata = NULL;
+}
+
+/*
+ * Notes on iterator implementation:
+ *
+ * Iterators keep track of the next element
+ * in a sequence. When a step() callback is
+ * invoked the current value of 'next' is stored
+ * to be returned later and the next variable is
+ * incremented.
+ *
+ * When the end of a sequence is
+ * reached, next should always equal NULL
+ *
+*/
+
+/*
+ * VERT OF MESH CALLBACKS
+ *
+*/
+
+static void vert_of_mesh_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ if(iter->bm->verts.first){
+ iter->firstvert = iter->bm->verts.first;
+ iter->nextvert = iter->bm->verts.first;
+ }
+}
+
+static void *vert_of_mesh_step(BMIter *iter)
+{
+ BMVert *current = iter->nextvert;
+
+ if(iter->nextvert)
+ iter->nextvert = (BMVert*)(iter->nextvert->head.next);
+
+ return current;
+}
+
+/*
+ * EDGE OF MESH CALLBACKS
+ *
+*/
+
+static void edge_of_mesh_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ if(iter->bm->edges.first){
+ iter->firstedge = iter->bm->edges.first;
+ iter->nextedge = iter->bm->edges.first;
+ }
+}
+
+static void *edge_of_mesh_step(BMIter *iter)
+{
+ BMEdge *current = iter->nextedge;
+
+ if(iter->nextedge)
+ iter->nextedge = (BMEdge*)(iter->nextedge->head.next);
+
+ return current;
+}
+
+/*
+ * FACE OF MESH CALLBACKS
+ *
+*/
+
+static void face_of_mesh_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ if(iter->bm->polys.first){
+ iter->firstpoly = iter->bm->polys.first;
+ iter->nextpoly = iter->bm->polys.first;
+ }
+}
+
+static void *face_of_mesh_step(BMIter *iter)
+{
+ BMFace *current = iter->nextpoly;
+
+ if(iter->nextpoly)
+ iter->nextpoly = (BMFace*)(iter->nextpoly->head.next);
+ return current;
+}
+
+/*
+ * EDGE OF VERT CALLBACKS
+ *
+*/
+
+static void edge_of_vert_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ if(iter->vdata->edge){
+ iter->firstedge = iter->vdata->edge;
+ iter->nextedge = iter->vdata->edge;
+ }
+}
+
+static void *edge_of_vert_step(BMIter *iter)
+{
+ BMEdge *current = iter->nextedge;
+
+ if(iter->nextedge)
+ iter->nextedge = bmesh_disk_nextedge(iter->nextedge, iter->vdata);
+
+ if(iter->nextedge == iter->firstedge) iter->nextedge = NULL;
+
+ return current;
+}
+
+/*
+ * FACE OF VERT CALLBACKS
+ *
+*/
+
+static void face_of_vert_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->count = 0;
+ if(iter->vdata->edge)
+ iter->count = bmesh_disk_count_facevert(iter->vdata);
+ if(iter->count){
+ iter->firstedge = bmesh_disk_find_first_faceedge(iter->vdata->edge, iter->vdata);
+ iter->nextedge = iter->firstedge;
+ iter->firstloop = bmesh_radial_find_first_facevert(iter->firstedge->loop, iter->vdata);
+ iter->nextloop = iter->firstloop;
+ }
+}
+static void *face_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->loop, iter->vdata);
+ iter->nextloop = iter->firstloop;
+ }
+ }
+
+ if(!iter->count) iter->nextloop = NULL;
+
+
+ if(current) return current->f;
+ return NULL;
+}
+
+static void loops_of_loop_begin(BMIter *iter)
+{
+ BMLoop *l;
+
+ l = iter->ldata;
+
+ /*note sure why this sets ldata. . .*/
+ init_iterator(iter);
+
+ iter->firstloop = l;
+ iter->nextloop = bmesh_radial_nextloop(iter->firstloop);
+}
+
+static void *loops_of_loop_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
+
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+ if(current) return current;
+ return NULL;
+}
+
+/*
+ * FACE OF EDGE CALLBACKS
+ *
+*/
+
+static void face_of_edge_begin(BMIter *iter)
+{
+ init_iterator(iter);
+
+ if(iter->edata->loop){
+ iter->firstloop = iter->edata->loop;
+ iter->nextloop = iter->edata->loop;
+ }
+}
+
+static void *face_of_edge_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = bmesh_radial_nextloop(iter->nextloop);
+
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+ if(current) return current->f;
+ return NULL;
+}
+
+/*
+ * VERT OF FACE CALLBACKS
+ *
+*/
+
+static void vert_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = iter->pdata->loopbase;
+}
+
+static void *vert_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->head.next));
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ if(current) return current->v;
+ return NULL;
+}
+
+/*
+ * EDGE OF FACE CALLBACKS
+ *
+*/
+
+static void edge_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = iter->pdata->loopbase;
+}
+
+static void *edge_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->head.next));
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ if(current) return current->e;
+ return NULL;
+}
+
+/*
+ * LOOP OF FACE CALLBACKS
+ *
+*/
+
+static void loop_of_face_begin(BMIter *iter)
+{
+ init_iterator(iter);
+ iter->firstloop = iter->nextloop = iter->pdata->loopbase;
+}
+
+static void *loop_of_face_step(BMIter *iter)
+{
+ BMLoop *current = iter->nextloop;
+
+ if(iter->nextloop) iter->nextloop = ((BMLoop*)(iter->nextloop->head.next));
+ if(iter->nextloop == iter->firstloop) iter->nextloop = NULL;
+
+ return current;
+}
+
+/*
+ * BMESH ITERATOR INIT
+ *
+ * Takes a bmesh iterator structure and fills
+ * it with the appropriate function pointers based
+ * upon its type and then calls BMeshIter_step()
+ * to return the first element of the iterator.
+ *
+*/
+void *BMIter_New(BMIter *iter, BMesh *bm, int type, void *data)
+{
+ int argtype;
+ iter->type = type;
+ iter->bm = bm;
+
+ switch(type){
+ case BM_VERTS_OF_MESH:
+ iter->begin = vert_of_mesh_begin;
+ iter->step = vert_of_mesh_step;
+ iter->bm = bm;
+ break;
+ case BM_EDGES_OF_MESH:
+ iter->begin = edge_of_mesh_begin;
+ iter->step = edge_of_mesh_step;
+ iter->bm = bm;
+ break;
+ case BM_FACES_OF_MESH:
+ iter->begin = face_of_mesh_begin;
+ iter->step = face_of_mesh_step;
+ iter->bm = bm;
+ break;
+ case BM_EDGES_OF_VERT:
+ iter->begin = edge_of_vert_begin;
+ iter->step = edge_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_FACES_OF_VERT:
+ iter->begin = face_of_vert_begin;
+ iter->step = face_of_vert_step;
+ iter->vdata = data;
+ break;
+ case BM_FACES_OF_EDGE:
+ iter->begin = face_of_edge_begin;
+ iter->step = face_of_edge_step;
+ iter->edata = data;
+ break;
+ case BM_VERTS_OF_FACE:
+ iter->begin = vert_of_face_begin;
+ iter->step = vert_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_EDGES_OF_FACE:
+ iter->begin = edge_of_face_begin;
+ iter->step = edge_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_LOOPS_OF_FACE:
+ iter->begin = loop_of_face_begin;
+ iter->step = loop_of_face_step;
+ iter->pdata = data;
+ break;
+ case BM_LOOPS_OF_LOOP:
+ iter->begin = loops_of_loop_begin;
+ iter->step = loops_of_loop_step;
+ iter->ldata = data;
+ break;
+ default:
+ break;
+ }
+
+ iter->begin(iter);
+ return BMIter_Step(iter);
+}
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
new file mode 100644
index 00000000000..5923add3025
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -0,0 +1,307 @@
+#include <string.h>
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+
+/*
+ * BM_MARK.C
+ *
+ * Selection routines for bmesh structures.
+ * This is actually all old code ripped from
+ * editmesh_lib.c and slightly modified to work
+ * for bmesh's. This also means that it has some
+ * of the same problems.... something that
+ * that should be addressed eventually.
+ *
+*/
+
+
+/*
+ * BMESH SELECTMODE FLUSH
+ *
+ * Makes sure to flush selections
+ * 'upwards' (ie: all verts of an edge
+ * selects the edge and so on). This
+ * should only be called by system and not
+ * tool authors.
+ *
+*/
+
+static void recount_totsels(BMesh *bm)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+ int *tots[3];
+ int i;
+
+ /*recount tot*sel variables*/
+ bm->totvertsel = bm->totedgesel = bm->totfacesel = 0;
+ tots[0] = &bm->totvertsel;
+ tots[1] = &bm->totedgesel;
+ tots[2] = &bm->totfacesel;
+
+ for (i=0; i<3; i++) {
+ ele = BMIter_New(&iter, bm, types[i], NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(ele, BM_SELECT)) *tots[i] += 1;
+ }
+ }
+}
+
+void BM_SelectMode_Flush(BMesh *bm)
+{
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ int totsel;
+
+ if(bm->selectmode & SCE_SELECT_VERTEX) {
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)) {
+ if(BM_TestHFlag(e->v1, BM_SELECT) && BM_TestHFlag(e->v2, BM_SELECT)) BM_SetHFlag(e, BM_SELECT);
+ else BM_ClearHFlag(e, BM_SELECT);
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
+ totsel = 0;
+ l=f->loopbase;
+ do{
+ if(BM_TestHFlag(l->v, BM_SELECT))
+ totsel++;
+ l = ((BMLoop*)(l->head.next));
+ } while(l != f->loopbase);
+
+ if(totsel == f->len)
+ BM_SetHFlag(f, BM_SELECT);
+ else
+ BM_ClearHFlag(f, BM_SELECT);
+ }
+ }
+ else if(bm->selectmode & SCE_SELECT_EDGE) {
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)) {
+ totsel = 0;
+ l=f->loopbase;
+ do{
+ if(bmesh_test_sysflag(&(l->e->head), BM_SELECT))
+ totsel++;
+ l = ((BMLoop*)(l->head.next));
+ }while(l!=f->loopbase);
+
+ if(totsel == f->len)
+ BM_SetHFlag(f, BM_SELECT);
+ else
+ BM_ClearHFlag(f, BM_SELECT);
+ }
+ }
+
+ recount_totsels(bm);
+}
+
+/*
+ * BMESH SELECT VERT
+ *
+ * Changes selection state of a single vertex
+ * in a mesh
+ *
+*/
+
+void BM_Select_Vert(BMesh *bm, BMVert *v, int select)
+{
+ if(select) {
+ if (!BM_TestHFlag(v, BM_SELECT)) bm->totvertsel += 1;
+ BM_SetHFlag(v, BM_SELECT);
+ } else {
+ if (BM_TestHFlag(v, BM_SELECT)) bm->totvertsel -= 1;
+ BM_ClearHFlag(v, BM_SELECT);
+ }
+}
+
+/*
+ * BMESH SELECT EDGE
+ *
+ * Changes selection state of a single edge
+ * in a mesh. Note that this is actually not
+ * 100 percent reliable. Deselecting an edge
+ * will also deselect both its vertices
+ * regardless of the selection state of
+ * other edges incident upon it. Fixing this
+ * issue breaks multi-select mode though...
+ *
+*/
+
+void BM_Select_Edge(BMesh *bm, BMEdge *e, int select)
+{
+ int candesel;
+ int testiso = 1;
+
+ /*I might move this logic to bmeshutils_mods.c, where it'd be invoked
+ by the selection tools. in that case, we'd still retain the checks
+ for if an edge's verts can be deselected.*/
+
+ /*ensure vert selections are valid, only if not in a multiselect
+ mode that shares SCE_SELECT_VERT*/
+ if (bm->selectmode & (SCE_SELECT_VERTEX|SCE_SELECT_EDGE)) testiso = 1;
+ else if (bm->selectmode & (SCE_SELECT_VERTEX|SCE_SELECT_FACE)) testiso = 1;
+
+ if (testiso && !select) {
+ BMIter eiter;
+ BMEdge *e2;
+ int i;
+
+ for (i=0; i<2; i++) {
+ candesel = 1;
+ e2 = BMIter_New(&eiter, bm, BM_EDGES_OF_VERT, !i?e->v1:e->v2);
+ for (; e2; e2=BMIter_Step(&eiter)) {
+ if (e2 == e) continue;
+ if (BM_TestHFlag(e2, BM_SELECT)) {
+ candesel = 0;
+ break;
+ }
+ }
+
+ if (candesel) BM_Select_Vert(bm, !i?e->v1:e->v2, 0);
+ }
+ }
+
+ if(select) {
+ if (!BM_TestHFlag(e, BM_SELECT)) bm->totedgesel += 1;
+
+ BM_SetHFlag(&(e->head), BM_SELECT);
+ BM_SetHFlag(e->v1, BM_SELECT);
+ BM_SetHFlag(e->v2, BM_SELECT);
+ }
+ else{
+ if (BM_TestHFlag(e, BM_SELECT)) bm->totedgesel -= 1;
+
+ BM_ClearHFlag(&(e->head), BM_SELECT);
+ }
+}
+
+/*
+ *
+ * BMESH SELECT FACE
+ *
+ * Changes selection state of a single
+ * face in a mesh. This (might) suffer
+ * from same problems as edge select
+ * code...
+ *
+*/
+
+void BM_Select_Face(BMesh *bm, BMFace *f, int select)
+{
+ BMLoop *l;
+
+ if(select){
+ if (!BM_TestHFlag(f, BM_SELECT)) bm->totfacesel += 1;
+
+ BM_SetHFlag(&(f->head), BM_SELECT);
+ l = f->loopbase;
+ do{
+ BM_SetHFlag(&(l->v->head), BM_SELECT);
+ BM_SetHFlag(&(l->e->head), BM_SELECT);
+ l = ((BMLoop*)(l->head.next));
+ }while(l != f->loopbase);
+ }
+ else{
+ if (BM_TestHFlag(f, BM_SELECT)) bm->totfacesel -= 1;
+
+ BM_ClearHFlag(&(f->head), BM_SELECT);
+ l = f->loopbase;
+ do {
+ BM_ClearHFlag(&(l->v->head), BM_SELECT);
+ BM_ClearHFlag(&(l->e->head), BM_SELECT);
+ l = ((BMLoop*)(l->head.next));
+ } while(l != f->loopbase);
+ }
+}
+
+/*
+ * BMESH SELECTMODE SET
+ *
+ * Sets the selection mode for the bmesh
+ *
+*/
+
+void BM_Selectmode_Set(BMesh *bm, int selectmode)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ bm->selectmode = selectmode;
+
+ if(bm->selectmode & SCE_SELECT_VERTEX) {
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
+ BM_ClearHFlag(e, 0);
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces))
+ BM_ClearHFlag(f, 0);
+ BM_SelectMode_Flush(bm);
+ }
+ else if(bm->selectmode & SCE_SELECT_EDGE) {
+ for(v= BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v= BMIter_Step(&verts))
+ BM_ClearHFlag(v, 0);
+ for(e= BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges)){
+ if(BM_TestHFlag(&(e->head), BM_SELECT))
+ BM_Select_Edge(bm, e, 1);
+ }
+ BM_SelectMode_Flush(bm);
+ }
+ else if(bm->selectmode & SCE_SELECT_FACE) {
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e= BMIter_Step(&edges))
+ BM_ClearHFlag(e, 0);
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f= BMIter_Step(&faces)){
+ if(BM_TestHFlag(&(f->head), BM_SELECT))
+ BM_Select_Face(bm, f, 1);
+ }
+ BM_SelectMode_Flush(bm);
+ }
+}
+
+
+int BM_CountFlag(struct BMesh *bm, int type, int flag)
+{
+ BMHeader *head;
+ BMIter iter;
+ int tot = 0;
+
+ if (type & BM_VERT) {
+ for (head = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
+ if (head->flag & flag) tot++;
+ }
+ }
+ if (type & BM_EDGE) {
+ for (head = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
+ if (head->flag & flag) tot++;
+ }
+ }
+ if (type & BM_FACE) {
+ for (head = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); head; head=BMIter_Step(&iter)) {
+ if (head->flag & flag) tot++;
+ }
+ }
+
+ return tot;
+}
+
+void BM_Select(struct BMesh *bm, void *element, int select)
+{
+ BMHeader *head = element;
+
+ if(head->type == BM_VERT) BM_Select_Vert(bm, (BMVert*)element, select);
+ else if(head->type == BM_EDGE) BM_Select_Edge(bm, (BMEdge*)element, select);
+ else if(head->type == BM_FACE) BM_Select_Face(bm, (BMFace*)element, select);
+}
+
+int BM_Is_Selected(BMesh *bm, void *element)
+{
+ BMHeader *head = element;
+ return BM_TestHFlag(head, BM_SELECT);
+} \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
new file mode 100644
index 00000000000..48b0d117843
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -0,0 +1,277 @@
+/**
+ * BME_mesh.c jan 2007
+ *
+ * BM mesh level functions.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+#include "DNA_listBase.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+void BME_error(void);
+
+/*bmesh_error stub*/
+void bmesh_error(void)
+{
+ printf("BM modelling error!");
+}
+
+/*
+ * BMESH SET SYSFLAG
+ *
+ * Sets a bitflag for a given element.
+ *
+*/
+
+void bmesh_set_sysflag(BMHeader *head, int flag)
+{
+ head->flag |= flag;
+}
+
+/*
+ * BMESH CLEAR SYSFLAG
+ *
+ * Clears a bitflag for a given element.
+ *
+*/
+
+void bmesh_clear_sysflag(BMHeader *head, int flag)
+{
+ head->flag &= ~flag;
+}
+
+
+/*
+ * BMESH TEST SYSFLAG
+ *
+ * Tests whether a bitflag is set for a given element.
+ *
+*/
+
+int bmesh_test_sysflag(BMHeader *head, int flag)
+{
+ if(head->flag & flag)
+ return 1;
+ return 0;
+}
+
+/*
+ * BMESH MAKE MESH
+ *
+ * Allocates a new BMesh structure.
+ * Returns -
+ * Pointer to a BM
+ *
+*/
+
+BMesh *BM_Make_Mesh(int allocsize[4])
+{
+ /*allocate the structure*/
+ BMesh *bm = MEM_callocN(sizeof(BMesh),"BM");
+ /*allocate the memory pools for the mesh elements*/
+ bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize[0], allocsize[0]);
+ bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize[1], allocsize[1]);
+ bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize[2], allocsize[2]);
+ bm->ppool = BLI_mempool_create(sizeof(BMFace), allocsize[3], allocsize[3]);
+
+ /*allocate one flag pool that we dont get rid of.*/
+ bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer), 512, 512);
+ bm->totflags = 1;
+
+ return bm;
+}
+/*
+ * BMESH FREE MESH
+ *
+ * Frees a BMesh structure.
+*/
+
+void BM_Free_Mesh_Data(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BMIter loops;
+
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v = BMIter_Step(&verts)) CustomData_bmesh_free_block( &(bm->vdata), &(v->head.data) );
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm ); e; e = BMIter_Step(&edges)) CustomData_bmesh_free_block( &(bm->edata), &(e->head.data) );
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){
+ CustomData_bmesh_free_block( &(bm->pdata), &(f->head.data) );
+ for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops)) CustomData_bmesh_free_block( &(bm->ldata), &(l->head.data) );
+ }
+
+ /*Free custom data pools, This should probably go in CustomData_free?*/
+ if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
+ if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
+ if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
+ if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
+
+ /*free custom data*/
+ CustomData_free(&bm->vdata,0);
+ CustomData_free(&bm->edata,0);
+ CustomData_free(&bm->ldata,0);
+ CustomData_free(&bm->pdata,0);
+
+ /*destroy element pools*/
+ BLI_mempool_destroy(bm->vpool);
+ BLI_mempool_destroy(bm->epool);
+ BLI_mempool_destroy(bm->ppool);
+ BLI_mempool_destroy(bm->lpool);
+
+ /*destroy flag pool*/
+ BLI_mempool_destroy(bm->flagpool);
+
+ BMO_ClearStack(bm);
+}
+
+void BM_Free_Mesh(BMesh *bm)
+{
+ BM_Free_Mesh_Data(bm);
+ MEM_freeN(bm);
+}
+
+/*
+ * BMESH COMPUTE NORMALS
+ *
+ * Updates the normals of a mesh.
+ * Note that this can only be called
+ *
+*/
+
+void BM_Compute_Normals(BMesh *bm)
+{
+ BMVert *v;
+ BMFace *f;
+ BMLoop *l;
+
+ BMIter verts;
+ BMIter faces;
+ BMIter loops;
+
+ unsigned int maxlength = 0;
+ float (*projectverts)[3];
+
+ /*first, find out the largest face in mesh*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){
+ 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*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){
+ if (f->head.flag & BM_NONORMCALC) continue;
+ bmesh_update_face_normal(bm, f, projectverts);
+ }
+
+ /*Zero out vertex normals*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v = BMIter_Step(&verts)) v->no[0] = v->no[1] = v->no[2] = 0.0;
+
+ /*add face normals to vertices*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm ); f; f = BMIter_Step(&faces)){
+ for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops)) VecAddf(l->v->no, l->v->no, f->no);
+ }
+
+ /*average the vertex normals*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm ); v; v= BMIter_Step(&verts)){
+ if (Normalize(v->no)==0.0) {
+ VECCOPY(v->no, v->co);
+ Normalize(v->no);
+ }
+ }
+
+ MEM_freeN(projectverts);
+}
+
+/*
+ * BMESH BEGIN/END EDIT
+ *
+ * Functions for setting up a mesh for editing and cleaning up after
+ * the editing operations are done. These are called by the tools/operator
+ * API for each time a tool is executed.
+ *
+ * Returns -
+ * Nothing
+ *
+*/
+
+void bmesh_begin_edit(BMesh *bm){
+
+ /*Initialize some scratch pointer arrays used by eulers*/
+ bm->vtar = MEM_callocN(sizeof(BMVert *) * 1024, "BM scratch vert array");
+ bm->edar = MEM_callocN(sizeof(BMEdge *) * 1024, "BM scratch edge array");
+ bm->lpar = MEM_callocN(sizeof(BMLoop *) * 1024, "BM scratch loop array");
+ bm->plar = MEM_callocN(sizeof(BMFace *) * 1024, "BM scratch poly array");
+
+ bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024;
+}
+
+void bmesh_end_edit(BMesh *bm, int flag){
+ int totvert, totedge, totface;
+ /*verify element counts*/
+ totvert = BLI_countlist(&(bm->verts));
+ totedge = BLI_countlist(&(bm->edges));
+ totface = BLI_countlist(&(bm->polys));
+
+ if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totface!=totface) BME_error();
+
+ /*free temp storage*/
+ 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);
+
+ /*zero out pointers*/
+ bm->vtar = NULL;
+ bm->edar = NULL;
+ bm->lpar = NULL;
+ bm->plar = NULL;
+ bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0;
+
+ /*compute normals, clear temp flags and flush selections*/
+ BM_Compute_Normals(bm);
+ BM_SelectMode_Flush(bm);
+}
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
new file mode 100644
index 00000000000..433b8a74387
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -0,0 +1,417 @@
+#include <limits.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_ghash.h"
+#include "BLI_arithb.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * BME_MODS.C
+ *
+ * This file contains functions for locally modifying
+ * the topology of existing mesh data. (split, join, flip ect).
+ *
+*/
+
+/**
+ * bmesh_dissolve_disk
+ *
+ * Turns the face region surrounding a manifold vertex into
+ * A single polygon.
+ *
+ *
+ * Example:
+ *
+ * |=========| |=========|
+ * | \ / | | |
+ * Before: | V | After: | |
+ * | / \ | | |
+ * |=========| |=========|
+ *
+ *
+ */
+#if 1
+int BM_Dissolve_Vert(BMesh *bm, BMVert *v) {
+ BMIter iter;
+ BMEdge *e;
+ int len=0;
+
+ if (!v) return 0;
+
+ e = BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v);
+ for (; e; e=BMIter_Step(&iter)) {
+ len++;
+ }
+
+ if (len == 1) {
+ bmesh_ke(bm, v->edge);
+ bmesh_kv(bm, v);
+ return 1;
+ }
+
+ if(BM_Nonmanifold_Vert(bm, v)) {
+ if (!v->edge) bmesh_kv(bm, v);
+ else if (!v->edge->loop) {
+ bmesh_ke(bm, v->edge);
+ bmesh_kv(bm, v);
+ } else return 0;
+
+ return 1;
+ }
+
+ return BM_Dissolve_Disk(bm, v);
+}
+
+int BM_Dissolve_Disk(BMesh *bm, BMVert *v) {
+ BMFace *f, *f2;
+ BMEdge *e, *keepedge=NULL, *baseedge=NULL;
+ BMLoop *loop;
+ int done, len;
+
+ if(BM_Nonmanifold_Vert(bm, v)) {
+ return 0;
+ }
+
+ if(v->edge){
+ /*v->edge we keep, what else?*/
+ e = v->edge;
+ len = 0;
+ do{
+ e = bmesh_disk_nextedge(e,v);
+ if(!(BM_Edge_Share_Faces(e, v->edge))){
+ keepedge = e;
+ baseedge = v->edge;
+ break;
+ }
+ len++;
+ }while(e != v->edge);
+ }
+
+ /*this code for handling 2 and 3-valence verts
+ may be totally bad.*/
+ if (keepedge == NULL && len == 3) {
+ /*handle specific case for three-valence. solve it by
+ increasing valence to four. this may be hackish. . .*/
+ loop = e->loop;
+ if (loop->v == v) loop = (BMLoop*) loop->head.next;
+ if (!BM_Split_Face(bm, loop->f, v, loop->v, NULL, NULL))
+ return 0;
+
+ BM_Dissolve_Disk(bm, v);
+ return 1;
+ } else if (keepedge == NULL && len == 2) {
+ /*handle two-valence*/
+ f = v->edge->loop->f;
+ f2 = ((BMLoop*)v->edge->loop->radial.next->data)->f;
+ /*collapse the vertex*/
+ BM_Collapse_Vert(bm, v->edge, v, 1.0);
+ BM_Join_Faces(bm, f, f2, NULL);
+
+ return 1;
+ }
+
+ if(keepedge){
+ done = 0;
+ while(!done){
+ done = 1;
+ e = v->edge;
+ do{
+ f = NULL;
+ len = bmesh_cycle_length(&(e->loop->radial));
+ if(len == 2 && (e!=baseedge) && (e!=keepedge)) {
+ f = BM_Join_Faces(bm, e->loop->f, ((BMLoop*)(e->loop->radial.next->data))->f, e);
+ /*return if couldn't join faces in manifold
+ conditions.*/
+ //!disabled for testing why bad things happen
+ if (!f) return 0;
+ }
+
+ if(f){
+ done = 0;
+ break;
+ }
+ e = bmesh_disk_nextedge(e, v);
+ }while(e != v->edge);
+ }
+
+ /*get remaining two faces*/
+ f = v->edge->loop->f;
+ f2 = ((BMLoop*)v->edge->loop->radial.next->data)->f;
+
+ /*collapse the vertex*/
+ BM_Collapse_Vert(bm, baseedge, v, 1.0);
+
+ if (f != f2) {
+ /*join two remaining faces*/
+ if (!BM_Join_Faces(bm, f, f2, NULL)) return 0;
+ }
+ }
+
+ return 1;
+}
+#else
+void BM_Dissolve_Disk(BMesh *bm, BMVert *v){
+ BMFace *f;
+ BMEdge *e;
+ BMIter iter;
+ int done, len;
+
+ if(v->edge){
+ done = 0;
+ while(!done){
+ done = 1;
+
+ /*loop the edges looking for an edge to dissolve*/
+ for (e=BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v); e;
+ e = BMIter_Step(&iter)) {
+ f = NULL;
+ len = bmesh_cycle_length(&(e->loop->radial));
+ if(len == 2){
+ f = BM_Join_Faces(bm,e->loop->f,((BMLoop*)
+ (e->loop->radial.next->data))->f,
+ e);
+ }
+ if(f){
+ done = 0;
+ break;
+ }
+ };
+ }
+ BM_Collapse_Vert(bm, v->edge, v, 1.0);
+ }
+}
+#endif
+
+/**
+ * bmesh_join_faces
+ *
+ * joins two adjacenct faces togather.
+ *
+ * Returns -
+ * BMFace pointer
+ */
+
+BMFace *BM_Join_Faces(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) {
+
+ BMLoop *l1, *l2;
+ BMEdge *jed=NULL;
+
+ jed = e;
+ if(!jed){
+ /*search for an edge that has both these faces in its radial cycle*/
+ l1 = f1->loopbase;
+ do{
+ if( ((BMLoop*)l1->radial.next->data)->f == f2 ){
+ jed = l1->e;
+ break;
+ }
+ l1 = ((BMLoop*)(l1->head.next));
+ }while(l1!=f1->loopbase);
+ }
+
+ l1 = jed->loop;
+ l2 = l1->radial.next->data;
+ if (l1->v == l2->v) {
+ bmesh_loop_reverse(bm, f2);
+ }
+
+ f1 = bmesh_jfke(bm, f1, f2, jed);
+
+ return f1;
+}
+
+/*connects two verts together, automatically (if very naively) finding the
+ face they both share (if there is one) and splittling it. use this at your
+ own risk, as it doesn't handle the many complex cases it should (like zero-area faces,
+ multiple faces, etc).
+
+ this is really only meant for cases where you don't know before hand the face
+ the two verts belong to for splitting (e.g. the subdivision operator).
+*/
+
+BMEdge *BM_Connect_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) {
+ BMIter iter, iter2;
+ BMVert *v;
+ BMLoop *nl;
+ BMFace *face;
+
+ /*this isn't the best thing in the world. it doesn't handle cases where there's
+ multiple faces yet. that might require a convexity test to figure out which
+ face is "best," and who knows what for non-manifold conditions.*/
+ for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) {
+ for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) {
+ if (v == v2) {
+ face = BM_Split_Face(bm, face, v1, v2, &nl, NULL);
+
+ if (nf) *nf = face;
+ return nl->e;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * BM_split_face
+ *
+ * Splits a single face into two.
+ *
+ * Returns -
+ * BMFace pointer
+ */
+
+BMFace *BM_Split_Face(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *example)
+{
+ BMFace *nf;
+ nf = bmesh_sfme(bm,f,v1,v2,nl);
+
+ if (nf) {
+ BM_Copy_Attributes(bm, bm, f, nf);
+ VECCOPY(nf->no, f->no);
+ }
+
+ return nf;
+}
+
+/**
+ * bmesh_collapse_vert
+ *
+ * Collapses a vertex that has only two manifold edges
+ * onto a vertex it shares an edge with. Fac defines
+ * the amount of interpolation for Custom Data.
+ *
+ * Note that this is not a general edge collapse function. For
+ * that see BM_manifold_edge_collapse
+ *
+ * TODO:
+ * Insert error checking for KV valance.
+ *
+ * Returns -
+ * Nothing
+ */
+
+void BM_Collapse_Vert(BMesh *bm, BMEdge *ke, BMVert *kv, float fac){
+ void *src[2];
+ float w[2];
+ BMLoop *l=NULL, *kvloop=NULL, *tvloop=NULL;
+ BMVert *tv = bmesh_edge_getothervert(ke,kv);
+
+ w[0] = 1.0f - fac;
+ w[1] = fac;
+
+ if(ke->loop){
+ l = ke->loop;
+ do{
+ if(l->v == tv && ((BMLoop*)(l->head.next))->v == kv){
+ tvloop = l;
+ kvloop = ((BMLoop*)(l->head.next));
+
+ src[0] = kvloop->head.data;
+ src[1] = tvloop->head.data;
+ CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, kvloop->head.data);
+ }
+ l=l->radial.next->data;
+ }while(l!=ke->loop);
+ }
+ BM_Data_Interp_From_Verts(bm, kv, tv, kv, fac);
+ bmesh_jekv(bm,ke,kv);
+}
+
+/**
+ * BM_split_edge
+ *
+ * Splits an edge. v should be one of the vertices in e and
+ * defines the direction of the splitting operation for interpolation
+ * purposes.
+ *
+ * Returns -
+ * the new vert
+ */
+
+BMVert *BM_Split_Edge(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent) {
+ BMVert *nv, *v2;
+
+ v2 = bmesh_edge_getothervert(e,v);
+ nv = bmesh_semv(bm,v,e,ne);
+ if (nv == NULL) return NULL;
+ VECSUB(nv->co,v2->co,v->co);
+ VECADDFAC(nv->co,v->co,nv->co,percent);
+ if (ne) {
+ if(bmesh_test_sysflag(&(e->head), BM_SELECT)) {
+ bmesh_set_sysflag((BMHeader*)*ne, BM_SELECT);
+ bmesh_set_sysflag((BMHeader*)nv, BM_SELECT);
+ }
+ if(bmesh_test_sysflag(&(e->head), BM_HIDDEN)) {
+ bmesh_set_sysflag((BMHeader*)*ne, BM_HIDDEN);
+ bmesh_set_sysflag((BMHeader*)nv, BM_HIDDEN);
+ }
+ }
+ /*v->nv->v2*/
+ BM_Data_Facevert_Edgeinterp(bm,v2, v, nv, e, percent);
+ BM_Data_Interp_From_Verts(bm, v2, v, nv, percent);
+ return nv;
+}
+
+BMVert *BM_Split_Edge_Multi(BMesh *bm, BMEdge *e, int numcuts)
+{
+ int i;
+ float percent;
+ BMVert *nv = NULL;
+
+ for(i=0; i < numcuts; i++){
+ percent = 1.0f / (float)(numcuts + 1 - i);
+ nv = BM_Split_Edge(bm, e->v2, e, NULL, percent);
+ }
+ return nv;
+}
+
+int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err)
+{
+ BMIter iter;
+ V_DECLARE(verts);
+ BMVert **verts = NULL;
+ BMLoop *l;
+ int ret = 1, i, j;
+
+ if (face->len == 2) {
+ fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
+ fflush(err);
+ }
+
+ for (l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, face);l;l=BMIter_Step(&iter)) {
+ V_GROW(verts);
+ verts[V_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<V_COUNT(verts); i++) {
+ for (j=0; j<V_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;
+ }
+ }
+ }
+
+ V_FREE(verts);
+ return ret;
+}
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
new file mode 100644
index 00000000000..07f1144b37e
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -0,0 +1,324 @@
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include <stdio.h>
+
+/*do not rename any operator or slot names! otherwise you must go
+ through the code and find all references to them!*/
+
+BMOpDefine def_finddoubles = {
+ "finddoubles",
+ /*maps welded vertices to verts they should weld to.*/
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ //list of verts to keep
+ {BMOP_OPSLOT_ELEMENT_BUF, "keepverts"},
+ {BMOP_OPSLOT_FLT, "dist"},
+ {BMOP_OPSLOT_MAPPING, "targetmapout"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_finddoubles_exec,
+ 0,
+};
+
+BMOpDefine def_removedoubles = {
+ "removedoubles",
+ /*maps welded vertices to verts they should weld to.*/
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {BMOP_OPSLOT_FLT, "dist"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_removedoubles_exec,
+ 0,
+};
+
+BMOpDefine def_weldverts = {
+ "weldverts",
+ /*maps welded vertices to verts they should weld to.*/
+ {{BMOP_OPSLOT_MAPPING, "targetmap"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_weldverts_exec,
+ 0,
+};
+
+BMOpDefine def_makevert = {
+ "makevert",
+ {{BMOP_OPSLOT_VEC, "co"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "newvertout"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_makevert_exec,
+ 0,
+};
+
+/*contextual_create is fkey, it creates
+ new faces, makes stuff from edge nets,
+ makes wire edges, etc. it also dissolves
+ faces.*/
+BMOpDefine def_contextual_create= {
+ "contextual_create",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_contextual_create_exec,
+ 0,
+};
+
+BMOpDefine def_edgenet_fill= {
+ "edgenet_fill",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_edgenet_fill_exec,
+ 0,
+};
+
+BMOpDefine def_rotate = {
+ "rotate",
+ {{BMOP_OPSLOT_VEC, "cent"},
+ {BMOP_OPSLOT_MAT, "mat"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_rotate_exec,
+ 0,
+};
+
+BMOpDefine def_translate= {
+ "translate",
+ {{BMOP_OPSLOT_VEC, "vec"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_translate_exec,
+ 0,
+};
+
+
+/*applies a transform to vertices*/
+BMOpDefine def_transform = {
+ "transform",
+ {{BMOP_OPSLOT_MAT, "mat"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_transform_exec,
+ 0,
+};
+
+/*loads a bmesh into an object*/
+BMOpDefine def_object_load_bmesh = {
+ "object_load_bmesh",
+ {{BMOP_OPSLOT_PNT, "scene"},
+ {BMOP_OPSLOT_PNT, "object"},
+ {0, /*null-terminating sentinel*/}},
+ bmesh_to_mesh_exec,
+ 0,
+};
+
+
+BMOpDefine def_mesh_to_bmesh = {
+ "mesh_to_bmesh",
+ {{BMOP_OPSLOT_PNT, "mesh"},
+ {0, /*null-terminating sentinel*/}},
+ mesh_to_bmesh_exec,
+ 0
+};
+
+BMOpDefine def_extrudeverts_indiv = {
+ "extrude_vert_indiv",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "vertout"},
+ {0} /*null-terminating sentinel*/},
+ extrude_vert_indiv_exec,
+ 0
+};
+
+#if 0
+BMOpDefine def_makeprim = {
+ "makeprim",
+ {{BMOP_OPSLOT_INT, "type"},
+ {BMOP_OPSLOT_INT, "tot", /*rows/cols also applies to spheres*/
+ {BMOP_OPSLOT_INT, "seg",
+ {BMOP_OPSLOT_INT, "subdiv"},
+ {BMOP_OPSLOT_INT, "ext"},
+ {BMOP_OPSLOT_INT, "fill"},
+ {BMOP_OPSLOT_FLT, "dia"},
+ {BMOP_OPSLOT_FLT, "depth"},
+ {BMOP_OPSLOT_PNT, "mat"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //won't be implemented right away
+ {0}}
+ makeprim_exec,
+ 0
+};
+#endif
+
+BMOpDefine def_connectverts = {
+ "connectverts",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
+ {0} /*null-terminating sentinel*/},
+ connectverts_exec,
+ 0
+};
+
+BMOpDefine def_extrudefaceregion = {
+ "extrudefaceregion",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edgefacein"},
+ {BMOP_OPSLOT_MAPPING, "exclude"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"},
+ {0} /*null-terminating sentinel*/},
+ extrude_edge_context_exec,
+ 0
+};
+
+BMOpDefine def_makefgonsop = {
+ "makefgon",
+ {{BMOP_OPSLOT_INT, "trifan"}, /*use triangle fans instead of
+ real interpolation*/
+ {0} /*null-terminating sentinel*/},
+ bmesh_make_fgons_exec,
+ 0
+};
+
+BMOpDefine def_dissolvevertsop = {
+ "dissolveverts",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
+ {0} /*null-terminating sentinel*/},
+ dissolveverts_exec,
+ 0
+};
+
+BMOpDefine def_dissolveedgessop = {
+ "dissolveedges",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
+ {0} /*null-terminating sentinel*/},
+ dissolveedges_exec,
+ 0
+};
+
+BMOpDefine def_dissolveedgeloopsop = {
+ "dissolveedgeloop",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
+ {0} /*null-terminating sentinel*/},
+ dissolve_edgeloop_exec,
+ 0
+};
+
+BMOpDefine def_dissolvefacesop = {
+ "dissolvefaces",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
+ {0} /*null-terminating sentinel*/},
+ dissolvefaces_exec,
+ 0
+};
+
+
+BMOpDefine def_triangop = {
+ "triangulate",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "faceout"},
+ {BMOP_OPSLOT_MAPPING, "facemap"},
+ {0} /*null-terminating sentinel*/},
+ triangulate_exec,
+ 0
+};
+
+BMOpDefine def_subdop = {
+ "esubd",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
+ {BMOP_OPSLOT_INT, "numcuts"},
+ {BMOP_OPSLOT_FLT, "smooth"},
+ {BMOP_OPSLOT_FLT, "fractal"},
+ {BMOP_OPSLOT_INT, "beauty"},
+ {BMOP_OPSLOT_MAPPING, "custompatterns"},
+ {BMOP_OPSLOT_MAPPING, "edgepercents"},
+
+ /*these next two can have multiple types of elements in them.*/
+ {BMOP_OPSLOT_ELEMENT_BUF, "outinner"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "outsplit"},
+ {0} /*null-terminating sentinel*/,
+ },
+ esubdivide_exec,
+ 0
+};
+
+BMOpDefine def_edit2bmesh = {
+ "editmesh_to_bmesh",
+ {{BMOP_OPSLOT_PNT, "em"}, {BMOP_OPSLOT_MAPPING, "map"},
+ {0} /*null-terminating sentinel*/},
+ edit2bmesh_exec,
+ 0
+};
+
+BMOpDefine def_bmesh2edit = {
+ "bmesh_to_editmesh",
+ {{BMOP_OPSLOT_PNT, "emout"},
+ {0} /*null-terminating sentinel*/},
+ bmesh2edit_exec,
+ 0
+};
+
+BMOpDefine def_delop = {
+ "del",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, {BMOP_OPSLOT_INT, "context"},
+ {0} /*null-terminating sentinel*/},
+ delop_exec,
+ 0
+};
+
+BMOpDefine def_dupeop = {
+ "dupe",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "origout"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "newout"},
+ /*facemap maps from source faces to dupe
+ faces, and from dupe faces to source faces.*/
+ {BMOP_OPSLOT_MAPPING, "facemap"},
+ {BMOP_OPSLOT_MAPPING, "boundarymap"},
+ {BMOP_OPSLOT_MAPPING, "isovertmap"},
+ {0} /*null-terminating sentinel*/},
+ dupeop_exec,
+ 0
+};
+
+BMOpDefine def_splitop = {
+ "split",
+ {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
+ {BMOP_OPSLOT_ELEMENT_BUF, "geomout"},
+ {BMOP_OPSLOT_MAPPING, "boundarymap"},
+ {BMOP_OPSLOT_MAPPING, "isovertmap"},
+ {0} /*null-terminating sentinel*/},
+ splitop_exec,
+ 0
+};
+
+BMOpDefine *opdefines[] = {
+ &def_splitop,
+ &def_dupeop,
+ &def_delop,
+ &def_edit2bmesh,
+ &def_bmesh2edit,
+ &def_subdop,
+ &def_triangop,
+ &def_dissolvefacesop,
+ &def_dissolveedgessop,
+ &def_dissolveedgeloopsop,
+ &def_dissolvevertsop,
+ &def_makefgonsop,
+ &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,
+};
+
+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..d168d85b025
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -0,0 +1,1305 @@
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_blenlib.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "stdarg.h"
+
+#include <string.h>
+
+/*forward declarations*/
+static void alloc_flag_layer(BMesh *bm);
+static void free_flag_layer(BMesh *bm);
+static void clear_flag_layer(BMesh *bm);
+static int bmesh_name_to_slotcode(BMOpDefine *def, char *name);
+static int bmesh_opname_to_opcode(char *opname);
+
+typedef void (*opexec)(struct BMesh *bm, struct BMOperator *op);
+
+/*mappings map elements to data, which
+ follows the mapping struct in memory.*/
+typedef struct element_mapping {
+ BMHeader *element;
+ int len;
+} element_mapping;
+
+
+/*operator slot type information - size of one element of the type given.*/
+const int BMOP_OPSLOT_TYPEINFO[] = {
+ 0,
+ sizeof(int),
+ sizeof(float),
+ sizeof(void*),
+ 0, /* unused */
+ 0, /* unused */
+ 0, /* unused */
+ sizeof(void*), /* pointer buffer */
+ sizeof(element_mapping)
+};
+
+/*
+ * BMESH OPSTACK PUSH
+ *
+ * Pushes the opstack down one level
+ * and allocates a new flag layer if
+ * appropriate.
+ *
+*/
+
+void BMO_push(BMesh *bm, BMOperator *op)
+{
+ bm->stackdepth++;
+
+ /*add flag layer, if appropriate*/
+ if (bm->stackdepth > 1)
+ alloc_flag_layer(bm);
+ else
+ clear_flag_layer(bm);
+}
+
+/*
+ * BMESH OPSTACK POP
+ *
+ * Pops the opstack one level
+ * and frees a flag layer if appropriate
+ * TODO: investigate NOT freeing flag
+ * layers.
+ *
+*/
+void BMO_pop(BMesh *bm)
+{
+ if(bm->stackdepth > 1)
+ free_flag_layer(bm);
+
+ bm->stackdepth--;
+}
+
+/*
+ * BMESH OPSTACK INIT OP
+ *
+ * Initializes an operator structure
+ * to a certain type
+ *
+*/
+
+void BMO_Init_Op(BMOperator *op, char *opname)
+{
+ int i, opcode = bmesh_opname_to_opcode(opname);
+
+ memset(op, 0, sizeof(BMOperator));
+ op->type = opcode;
+
+ /*initialize the operator slot types*/
+ for(i = 0; opdefines[opcode]->slottypes[i].type; i++) {
+ op->slots[i].slottype = opdefines[opcode]->slottypes[i].type;
+ op->slots[i].index = i;
+ }
+
+ /*callback*/
+ op->exec = opdefines[opcode]->exec;
+
+ /*memarena, used for operator's slot buffers*/
+ op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ BLI_memarena_use_calloc (op->arena);
+}
+
+/*
+ * BMESH OPSTACK EXEC OP
+ *
+ * Executes a passed in operator. This handles
+ * the allocation and freeing of temporary flag
+ * layers and starting/stopping the modelling
+ * loop. Can be called from other operators
+ * exec callbacks as well.
+ *
+*/
+
+void BMO_Exec_Op(BMesh *bm, BMOperator *op)
+{
+
+ BMO_push(bm, op);
+
+ if(bm->stackdepth == 1)
+ bmesh_begin_edit(bm);
+ op->exec(bm, op);
+
+ if(bm->stackdepth == 1)
+ bmesh_end_edit(bm,0);
+
+ BMO_pop(bm);
+}
+
+/*
+ * BMESH OPSTACK FINISH OP
+ *
+ * Does housekeeping chores related to finishing
+ * up an operator.
+ *
+*/
+
+void BMO_Finish_Op(BMesh *bm, BMOperator *op)
+{
+ BMOpSlot *slot;
+ int i;
+
+ for (i=0; opdefines[op->type]->slottypes[i].type; i++) {
+ slot = &op->slots[i];
+ if (slot->slottype == BMOP_OPSLOT_MAPPING) {
+ if (slot->data.ghash)
+ BLI_ghash_free(slot->data.ghash, NULL, NULL);
+ }
+ }
+
+ BLI_memarena_free(op->arena);
+}
+
+/*
+ * BMESH OPSTACK GET SLOT
+ *
+ * Returns a pointer to the slot of
+ * type 'slotcode'
+ *
+*/
+
+BMOpSlot *BMO_GetSlot(BMOperator *op, char *slotname)
+{
+ int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
+
+ return &(op->slots[slotcode]);
+}
+
+/*
+ * BMESH OPSTACK COPY SLOT
+ *
+ * Copies data from one slot to another
+ *
+*/
+
+void BMO_CopySlot(BMOperator *source_op, BMOperator *dest_op, char *src, char *dst)
+{
+ BMOpSlot *source_slot = BMO_GetSlot(source_op, src);
+ BMOpSlot *dest_slot = BMO_GetSlot(dest_op, dst);
+
+ if(source_slot == dest_slot)
+ return;
+
+ if(source_slot->slottype != dest_slot->slottype)
+ return;
+
+ if (dest_slot->slottype > BMOP_OPSLOT_VEC) {
+ if (dest_slot->slottype != BMOP_OPSLOT_MAPPING) {
+ /*do buffer copy*/
+ dest_slot->data.buf = NULL;
+ dest_slot->len = source_slot->len;
+ if(dest_slot->len){
+ dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
+ memcpy(dest_slot->data.buf, source_slot->data.buf, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
+ }
+ } else {
+ GHashIterator it;
+ element_mapping *srcmap, *dstmap;
+
+ /*sanity check*/
+ if (!source_slot->data.ghash) return;
+
+ if (!dest_slot->data.ghash) {
+ dest_slot->data.ghash =
+ BLI_ghash_new(BLI_ghashutil_ptrhash,
+ BLI_ghashutil_ptrcmp);
+ }
+
+ BLI_ghashIterator_init(&it, source_slot->data.ghash);
+ for (;srcmap=BLI_ghashIterator_getValue(&it);
+ BLI_ghashIterator_step(&it))
+ {
+ dstmap = BLI_memarena_alloc(dest_op->arena,
+ sizeof(*dstmap) + srcmap->len);
+
+ dstmap->element = srcmap->element;
+ dstmap->len = srcmap->len;
+ memcpy(dstmap+1, srcmap+1, srcmap->len);
+
+ BLI_ghash_insert(dest_slot->data.ghash,
+ dstmap->element, dstmap);
+ }
+ }
+ } else {
+ dest_slot->data = source_slot->data;
+ }
+}
+
+/*
+ * BMESH OPSTACK SET XXX
+ *
+ * Sets the value of a slot depending on it's type
+ *
+*/
+
+
+void BMO_Set_Float(BMOperator *op, char *slotname, float f)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_FLT) )
+ return;
+
+ slot->data.f = f;
+}
+
+void BMO_Set_Int(BMOperator *op, char *slotname, int i)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_INT) )
+ return;
+
+ slot->data.i = i;
+}
+
+/*only supports square mats*/
+void BMO_Set_Mat(struct BMOperator *op, char *slotname, float *mat, int size)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_MAT) )
+ return;
+
+ slot->len = 4;
+ slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float)*4*4);
+
+ if (size == 4) {
+ memcpy(slot->data.p, mat, sizeof(float)*4*4);
+ } else if (size == 3) {
+ Mat4CpyMat3(slot->data.p, mat);
+ } else {
+ printf("yeek! invalid size in BMO_Set_Mat!\n");
+
+ memset(slot->data.p, 0, sizeof(float)*4*4);
+ return;
+ }
+}
+
+void BMO_Get_Mat4(struct BMOperator *op, char *slotname, float mat[4][4])
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_MAT) )
+ return;
+
+ memcpy(mat, slot->data.p, sizeof(float)*4*4);
+}
+
+void BMO_Get_Mat3(struct BMOperator *op, char *slotname, float mat[3][3])
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_MAT) )
+ return;
+
+ Mat3CpyMat4(mat, slot->data.p);
+}
+
+void BMO_Set_Pnt(BMOperator *op, char *slotname, void *p)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_PNT) )
+ return;
+
+ slot->data.p = p;
+}
+
+void BMO_Set_Vec(BMOperator *op, char *slotname, float *vec)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_VEC) )
+ return;
+
+ VECCOPY(slot->data.vec, vec);
+}
+
+
+float BMO_Get_Float(BMOperator *op, char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_FLT) )
+ return 0.0f;
+
+ return slot->data.f;
+}
+
+int BMO_Get_Int(BMOperator *op, char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_INT) )
+ return 0;
+
+ return slot->data.i;
+}
+
+
+void *BMO_Get_Pnt(BMOperator *op, char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_PNT) )
+ return NULL;
+
+ return slot->data.p;
+}
+
+void BMO_Get_Vec(BMOperator *op, char *slotname, float *vec_out)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ if( !(slot->slottype == BMOP_OPSLOT_VEC) )
+ return;
+
+ VECCOPY(vec_out, slot->data.vec);
+}
+
+/*
+ * BMO_SETFLAG
+ *
+ * Sets a flag for a certain element
+ *
+*/
+void BMO_SetFlag(BMesh *bm, void *element, int flag)
+{
+ BMHeader *head = element;
+ head->flags[bm->stackdepth-1].mask |= flag;
+}
+
+/*
+ * BMO_CLEARFLAG
+ *
+ * Clears a specific flag from a given element
+ *
+*/
+
+void BMO_ClearFlag(BMesh *bm, void *element, int flag)
+{
+ BMHeader *head = element;
+ head->flags[bm->stackdepth-1].mask &= ~flag;
+}
+
+/*
+ * BMO_TESTFLAG
+ *
+ * Tests whether or not a flag is set for a specific element
+ *
+ *
+*/
+
+int BMO_TestFlag(BMesh *bm, void *element, int flag)
+{
+ BMHeader *head = element;
+ if(head->flags[bm->stackdepth-1].mask & flag)
+ return 1;
+ return 0;
+}
+
+/*
+ * BMO_COUNTFLAG
+ *
+ * Counts the number of elements of a certain type that
+ * have a specific flag set.
+ *
+*/
+
+int BMO_CountFlag(BMesh *bm, int flag, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ int count = 0;
+
+ if(type & BM_VERT){
+ for(e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)){
+ if(BMO_TestFlag(bm, e, flag))
+ count++;
+ }
+ }
+ if(type & BM_EDGE){
+ for(e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)){
+ if(BMO_TestFlag(bm, e, flag))
+ count++;
+ }
+ }
+ if(type & BM_FACE){
+ for(e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)){
+ if(BMO_TestFlag(bm, e, flag))
+ count++;
+ }
+ }
+
+ return count;
+}
+
+int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, char *slotname)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*check if its actually a buffer*/
+ if( !(slot->slottype > BMOP_OPSLOT_VEC) )
+ return 0;
+
+ return slot->len;
+}
+
+#if 0
+void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd) {
+ BMOpSlot *slot = &op->slots[slotcode];
+ void *tmp;
+
+ /*check if its actually a buffer*/
+ if( !(slot->slottype > BMOP_OPSLOT_VEC) )
+ return NULL;
+
+ if (slot->flag & BMOS_DYNAMIC_ARRAY) {
+ if (slot->len >= slot->size) {
+ slot->size = (slot->size+1+totadd)*2;
+
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->size);
+ MEM_freeN(tmp);
+ }
+
+ slot->len += totadd;
+ } else {
+ slot->flag |= BMOS_DYNAMIC_ARRAY;
+ slot->len += totadd;
+ slot->size = slot->len+2;
+ tmp = slot->data.buf;
+ slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len, "opslot dynamic array");
+ memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * slot->len);
+ }
+
+ return slot->data.buf;
+}
+#endif
+
+void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, char *slotname,
+ void *element, void *data, int len) {
+ element_mapping *mapping;
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
+
+ mapping = BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
+
+ mapping->element = 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);
+ }
+
+ BLI_ghash_insert(slot->data.ghash, element, mapping);
+}
+
+void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op,
+ char *slotname, int flag)
+{
+ GHashIterator it;
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader *ele;
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
+ if (!slot->data.ghash) return;
+
+ BLI_ghashIterator_init(&it, slot->data.ghash);
+ for (;ele=BLI_ghashIterator_getKey(&it);BLI_ghashIterator_step(&it)) {
+ BMO_SetFlag(bm, ele, flag);
+ }
+}
+
+void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, char *slotname,
+ void *element, float val)
+{
+ BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(float));
+}
+
+void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, char *slotname,
+ void *element, void *val)
+{
+ BMO_Insert_Mapping(bm, op, slotname, element, &val, sizeof(void*));
+}
+
+int BMO_InMap(BMesh *bm, BMOperator *op, char *slotname, void *element)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return 0;
+ if (!slot->data.ghash) return 0;
+
+ return BLI_ghash_haskey(slot->data.ghash, element);
+}
+
+void *BMO_Get_MapData(BMesh *bm, BMOperator *op, char *slotname,
+ void *element)
+{
+ element_mapping *mapping;
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ /*sanity check*/
+ if (slot->slottype != BMOP_OPSLOT_MAPPING) return NULL;
+ if (!slot->data.ghash) return NULL;
+
+ mapping = BLI_ghash_lookup(slot->data.ghash, element);
+
+ if (!mapping) return NULL;
+
+ return mapping + 1;
+}
+
+float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, char *slotname,
+ void *element)
+{
+ float *val = BMO_Get_MapData(bm, op, slotname, element);
+ if (val) return *val;
+
+ return 0.0f;
+}
+
+void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, char *slotname,
+ void *element)
+{
+ void **val = BMO_Get_MapData(bm, op, slotname, element);
+ if (val) return *val;
+
+ return NULL;
+}
+
+static void *alloc_slot_buffer(BMOperator *op, char *slotname, int len){
+ int slotcode = bmesh_name_to_slotcode(opdefines[op->type], slotname);
+
+ /*check if its actually a buffer*/
+ if( !(op->slots[slotcode].slottype > BMOP_OPSLOT_VEC) )
+ return NULL;
+
+ op->slots[slotcode].len = len;
+ if(len)
+ op->slots[slotcode].data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode].type] * len);
+ return op->slots[slotcode].data.buf;
+}
+
+
+/*
+ *
+ * BMO_ALL_TO_SLOT
+ *
+ * Copies all elements of a certain type into an operator slot.
+ *
+*/
+
+void BMO_All_To_Slot(BMesh *bm, BMOperator *op, char *slotname, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_GetSlot(op, slotname);
+ int totelement=0, i=0;
+
+ if (type & BM_VERT) totelement += bm->totvert;
+ if (type & BM_EDGE) totelement += bm->totedge;
+ if (type & BM_FACE) totelement += bm->totface;
+
+ if(totelement){
+ alloc_slot_buffer(op, slotname, totelement);
+
+ if (type & BM_VERT) {
+ for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (type & BM_EDGE) {
+ for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+
+ if (type & BM_FACE) {
+ for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+}
+
+/*
+ *
+ * BMO_HEADERFLAG_TO_SLOT
+ *
+ * Copies elements of a certain type, which have a certain header flag set
+ * into a slot for an operator.
+ *
+*/
+
+void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, char *slotname, int flag, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_GetSlot(op, slotname);
+ int totelement=0, i=0;
+
+ totelement = BM_CountFlag(bm, type, flag);
+
+ if(totelement){
+ alloc_slot_buffer(op, slotname, totelement);
+
+ if (type & BM_VERT) {
+ for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(e->flag & flag) {
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_EDGE) {
+ for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(e->flag & flag){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_FACE) {
+ for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(e->flag & flag){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_TO_SLOT
+ *
+ * Copies elements of a certain type, which have a certain flag set
+ * into an output slot for an operator.
+ *
+*/
+void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, char *slotname, int flag, int type)
+{
+ BMIter elements;
+ BMHeader *e;
+ BMOpSlot *output = BMO_GetSlot(op, slotname);
+ int totelement = BMO_CountFlag(bm, flag, type), i=0;
+
+ if(totelement){
+ alloc_slot_buffer(op, slotname, totelement);
+
+ if (type & BM_VERT) {
+ for (e = BMIter_New(&elements, bm, BM_VERTS_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(BMO_TestFlag(bm, e, flag)){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_EDGE) {
+ for (e = BMIter_New(&elements, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(BMO_TestFlag(bm, e, flag)){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+
+ if (type & BM_FACE) {
+ for (e = BMIter_New(&elements, bm, BM_FACES_OF_MESH, bm); e; e = BMIter_Step(&elements)) {
+ if(BMO_TestFlag(bm, e, flag)){
+ ((BMHeader**)output->data.p)[i] = e;
+ i++;
+ }
+ }
+ }
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Header Flags elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ *
+*/
+
+void BMO_HeaderFlag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++) {
+ BM_SetHFlag(data[i], flag);
+ if (flag & BM_SELECT)
+ BM_Select(bm, data[i], 1);
+ }
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer, automatically
+ * using the selection API where appropriate.
+ *
+*/
+
+void BMO_UnHeaderFlag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++) {
+ BM_ClearHFlag(data[i], flag);
+ if (flag & BM_SELECT)
+ BM_Select(bm, data[i], 0);
+ }
+}
+
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Flags elements in a slots buffer
+ *
+*/
+
+void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++)
+ BMO_SetFlag(bm, data[i], flag);
+}
+
+/*
+ *
+ * BMO_FLAG_BUFFER
+ *
+ * Removes flags from elements in a slots buffer
+ *
+*/
+
+void BMO_Unflag_Buffer(BMesh *bm, BMOperator *op, char *slotname, int flag)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+ BMHeader **data = slot->data.p;
+ int i;
+
+ for(i = 0; i < slot->len; i++)
+ BMO_ClearFlag(bm, data[i], flag);
+}
+
+
+/*
+ *
+ * ALLOC/FREE FLAG LAYER
+ *
+ * Used by operator stack to free/allocate
+ * private flag data. This is allocated
+ * using a mempool so the allocation/frees
+ * should be quite fast.
+ *
+ * TODO:
+ * Investigate not freeing flag layers until
+ * all operators have been executed. This would
+ * save a lot of realloc potentially.
+ *
+*/
+
+static void alloc_flag_layer(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BLI_mempool *oldpool = bm->flagpool; /*old flag pool*/
+ void *oldflags;
+
+ /*allocate new flag pool*/
+ bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*(bm->totflags+1), 512, 512 );
+
+ /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ oldflags = v->head.flags;
+ v->head.flags = BLI_mempool_calloc(bm->flagpool);
+ memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*dont know if this memcpy usage is correct*/
+ }
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ oldflags = e->head.flags;
+ e->head.flags = BLI_mempool_calloc(bm->flagpool);
+ memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ oldflags = f->head.flags;
+ f->head.flags = BLI_mempool_calloc(bm->flagpool);
+ memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
+ }
+ bm->totflags++;
+ BLI_mempool_destroy(oldpool);
+}
+
+static void free_flag_layer(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BLI_mempool *oldpool = bm->flagpool;
+ void *oldflags;
+
+ /*de-increment the totflags first...*/
+ bm->totflags--;
+ /*allocate new flag pool*/
+ bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512);
+
+ /*now go through and memcpy all the flags*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ oldflags = v->head.flags;
+ v->head.flags = BLI_mempool_calloc(bm->flagpool);
+ memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*correct?*/
+ }
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ oldflags = e->head.flags;
+ e->head.flags = BLI_mempool_calloc(bm->flagpool);
+ memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ oldflags = f->head.flags;
+ f->head.flags = BLI_mempool_calloc(bm->flagpool);
+ memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
+ }
+
+ BLI_mempool_destroy(oldpool);
+}
+
+static void clear_flag_layer(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ /*now go through and memcpy all the flags*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ memset(v->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer));
+ }
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ memset(e->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer));
+ }
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ memset(f->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer));
+ }
+}
+
+void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op,
+ char *slotname, int restrict)
+{
+ BMOpSlot *slot = BMO_GetSlot(op, slotname);
+
+ memset(iter, 0, sizeof(BMOIter));
+
+ iter->slot = slot;
+ iter->cur = 0;
+ iter->restrict = restrict;
+
+ if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
+ if (iter->slot->data.ghash)
+ BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
+ else return NULL;
+ }
+
+ return BMO_IterStep(iter);
+}
+
+void *BMO_IterStep(BMOIter *iter)
+{
+ if (iter->slot->slottype == BMOP_OPSLOT_ELEMENT_BUF) {
+ BMHeader *h;
+
+ if (iter->cur >= iter->slot->len) return NULL;
+
+ h = ((void**)iter->slot->data.buf)[iter->cur++];
+ while (!(iter->restrict & h->type)) {
+ if (iter->cur >= iter->slot->len) return NULL;
+ h = ((void**)iter->slot->data.buf)[iter->cur++];
+ }
+
+ return h;
+ } else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
+ struct element_mapping *map;
+ void *ret = BLI_ghashIterator_getKey(&iter->giter);
+ map = BLI_ghashIterator_getValue(&iter->giter);
+
+ iter->val = map + 1;
+
+ BLI_ghashIterator_step(&iter->giter);
+
+ return ret;
+ }
+
+ return NULL;
+}
+
+/*used for iterating over mappings*/
+void *BMO_IterMapVal(BMOIter *iter)
+{
+ return iter->val;
+}
+
+void *BMO_IterMapValp(BMOIter *iter)
+{
+ return *((void**)iter->val);
+}
+
+float BMO_IterMapValf(BMOIter *iter)
+{
+ return *((float*)iter->val);
+}
+
+/*error system*/
+typedef struct bmop_error {
+ struct bmop_error *next, *prev;
+ int errorcode;
+ BMOperator *op;
+ char *msg;
+} bmop_error;
+
+void BMO_ClearStack(BMesh *bm)
+{
+ while (BMO_PopError(bm, NULL, NULL));
+}
+
+void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, char *msg)
+{
+ bmop_error *err = MEM_callocN(sizeof(bmop_error), "bmop_error");
+
+ err->errorcode = errcode;
+ if (!msg) msg = bmop_error_messages[errcode];
+ err->msg = msg;
+ err->op = owner;
+
+ BLI_addhead(&bm->errorstack, err);
+}
+
+int BMO_HasError(BMesh *bm)
+{
+ return bm->errorstack.first != NULL;
+}
+
+/*returns error code or 0 if no error*/
+int BMO_GetError(BMesh *bm, char **msg, BMOperator **op)
+{
+ bmop_error *err = bm->errorstack.first;
+ if (!err) return 0;
+
+ if (msg) *msg = err->msg;
+ if (op) *op = err->op;
+
+ return err->errorcode;
+}
+
+int BMO_PopError(BMesh *bm, char **msg, BMOperator **op)
+{
+ int errorcode = BMO_GetError(bm, msg, op);
+
+ if (errorcode) {
+ bmop_error *err = bm->errorstack.first;
+
+ BLI_remlink(&bm->errorstack, bm->errorstack.first);
+ MEM_freeN(err);
+ }
+
+ return errorcode;
+}
+
+/*
+typedef struct bflag {
+ char *str;
+ int flag;
+} bflag;
+
+#define b(f) {#f, f},
+static char *bmesh_flags = {
+ b(BM_SELECT);
+ b(BM_SEAM);
+ b(BM_FGON);
+ b(BM_HIDDEN);
+ b(BM_SHARP);
+ b(BM_SMOOTH);
+ {NULL, 0};
+};
+
+int bmesh_str_to_flag(char *str)
+{
+ int i;
+
+ while (bmesh_flags[i]->name) {
+ if (!strcmp(bmesh_flags[i]->name, str))
+ return bmesh_flags[i]->flag;
+ }
+
+ return -1;
+}
+*/
+
+//example:
+//BMO_CallOp(bm, "del %d %hv", DEL_ONLYFACES, BM_SELECT);
+/*
+ d - int
+ i - int
+ f - float
+ hv - header flagged verts
+ he - header flagged edges
+ hf - header flagged faces
+ fv - flagged verts
+ fe - flagged edges
+ ff - flagged faces
+
+*/
+
+#define nextc(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
+
+static int bmesh_name_to_slotcode(BMOpDefine *def, char *name)
+{
+ int i;
+
+ for (i=0; def->slottypes[i].type; i++) {
+ if (!strcmp(name, def->slottypes[i].name)) return i;
+ }
+
+ printf("yeek! could not find bmesh slot for name %s!\n", name);
+ return 0;
+}
+
+static int bmesh_opname_to_opcode(char *opname) {
+ int i;
+
+ for (i=0; i<bmesh_total_ops; i++) {
+ if (!strcmp(opname, opdefines[i]->name)) break;
+ }
+
+ if (i == bmesh_total_ops) {
+ printf("yeek!! invalid op name %s!\n", opname);
+ return 0;
+ }
+
+ return i;
+}
+
+int BMO_VInitOpf(BMesh *bm, BMOperator *op, char *fmt, va_list vlist)
+{
+ BMOpDefine *def;
+ char *opname, *ofmt;
+ char slotname[64] = {0};
+ int i, n=strlen(fmt), stop, slotcode = -1, ret, type, state, c;
+ int noslot=0;
+
+ /*we muck around in here, so dup it*/
+ fmt = ofmt = strdup(fmt);
+
+ /*find operator name*/
+ i = strcspn(fmt, " \t");
+
+ opname = fmt;
+ if (!opname[i]) noslot = 1;
+ opname[i] = 0;
+
+ fmt += i + (noslot ? 0 : 1);
+
+ for (i=0; i<bmesh_total_ops; i++) {
+ if (!strcmp(opname, opdefines[i]->name)) break;
+ }
+
+ if (i == bmesh_total_ops) return 0;
+
+ BMO_Init_Op(op, opname);
+ def = opdefines[i];
+
+ i = 0;
+ state = 1; //0: not inside slotcode name, 1: inside slotcode name
+ c = 0;
+
+ while (*fmt) {
+ if (state) {
+ /*jump past leading whitespace*/
+ i = strspn(fmt, " \t");
+ fmt += i;
+
+ /*ignore trailing whitespace*/
+ if (!fmt[i])
+ break;
+
+ /*find end of slot name. currently this is
+ a little flexible, allowing "slot=%f",
+ "slot %f", "slot%f", and "slot\t%f". */
+ i = strcspn(fmt, "= \t%");
+ if (!fmt[i]) goto error;
+
+ fmt[i] = 0;
+
+ if (bmesh_name_to_slotcode(def, fmt) < 0) goto error;
+
+ strcpy(slotname, fmt);
+
+ state = 0;
+ fmt += i;
+ } else {
+ switch (*fmt) {
+ case ' ':
+ case '\t':
+ case '=':
+ case '%':
+ break;
+ case 'm': {
+ int size, c;
+
+ c = nextc(fmt);
+ fmt++;
+
+ if (c == '3') size = 3;
+ else if (c == '4') size = 4;
+ else goto error;
+
+ BMO_Set_Mat(op, slotname, va_arg(vlist, void*), size);
+ state = 1;
+ break;
+ }
+ case 'v': {
+ BMO_Set_Vec(op, slotname, va_arg(vlist, float*));
+ state = 1;
+ break;
+ }
+ case 's': {
+ BMOperator *op2 = va_arg(vlist, void*);
+ char *slotname2 = va_arg(vlist, char*);
+
+ BMO_CopySlot(op2, op, slotname2, slotname);
+ state = 1;
+ break;
+ }
+ case 'i':
+ case 'd':
+ BMO_Set_Int(op, slotname, va_arg(vlist, int));
+ state = 1;
+ break;
+ case 'p':
+ BMO_Set_Pnt(op, slotname, va_arg(vlist, void*));
+ state = 1;
+ break;
+ case 'f':
+ case 'h':
+ case 'a':
+ type = *fmt;
+
+ if (nextc(fmt) == ' ' || nextc(fmt) == '\t' ||
+ nextc(fmt)==0)
+ {
+ BMO_Set_Float(op,slotname,va_arg(vlist,double));
+ } else {
+ ret = 0;
+ stop = 0;
+ while (1) {
+ switch (nextc(fmt)) {
+ case 'f': ret |= BM_FACE;break;
+ case 'e': ret |= BM_EDGE;break;
+ case 'v': ret |= BM_VERT;break;
+ default:
+ stop = 1;
+ break;
+ }
+ if (stop) break;
+ fmt++;
+ }
+
+ if (type == 'h')
+ BMO_HeaderFlag_To_Slot(bm, op,
+ slotname, va_arg(vlist, int), ret);
+ else if (type == 'a')
+ BMO_All_To_Slot(bm, op, slotname, ret);
+ else
+ BMO_Flag_To_Slot(bm, op, slotname,
+ va_arg(vlist, int), ret);
+ }
+
+ state = 1;
+ break;
+ default:
+ printf("unrecognized bmop format char: %c\n", *fmt);
+ break;
+ }
+ }
+ fmt++;
+ }
+
+ free(ofmt);
+ return 1;
+error:
+ BMO_Finish_Op(bm, op);
+ free(fmt);
+ return 0;
+}
+
+
+int BMO_InitOpf(BMesh *bm, BMOperator *op, char *fmt, ...) {
+ va_list list;
+
+ va_start(list, fmt);
+ if (!BMO_VInitOpf(bm, op, fmt, list)) {
+ printf("BMO_InitOpf failed\n");
+ va_end(list);
+ return 0;
+ }
+ va_end(list);
+
+ return 1;
+}
+
+int BMO_CallOpf(BMesh *bm, char *fmt, ...) {
+ va_list list;
+ BMOperator op;
+
+ va_start(list, fmt);
+ if (!BMO_VInitOpf(bm, &op, fmt, list)) {
+ printf("BMO_CallOpf failed\n");
+ va_end(list);
+ return 0;
+ }
+
+ BMO_Exec_Op(bm, &op);
+ BMO_Finish_Op(bm, &op);
+
+ va_end(list);
+ return 1;
+}
+
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..3eaaf4e8913
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -0,0 +1,38 @@
+#ifndef BM_OPERATORS_PRIVATE_H
+#define BM_OPERATORS_PRIVATE_H
+
+struct BMesh;
+struct BMOperator;
+
+void BMO_push(BMesh *bm, BMOperator *op);
+void BMO_pop(BMesh *bm);
+
+void splitop_exec(BMesh *bm, BMOperator *op);
+void dupeop_exec(BMesh *bm, BMOperator *op);
+void delop_exec(BMesh *bm, BMOperator *op);
+void esubdivide_exec(BMesh *bmesh, BMOperator *op);
+void edit2bmesh_exec(BMesh *bmesh, BMOperator *op);
+void bmesh2edit_exec(BMesh *bmesh, BMOperator *op);
+void triangulate_exec(BMesh *bmesh, BMOperator *op);
+void dissolvefaces_exec(BMesh *bmesh, BMOperator *op);
+void dissolveverts_exec(BMesh *bmesh, BMOperator *op);
+void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op);
+void extrude_edge_context_exec(BMesh *bm, BMOperator *op);
+void connectverts_exec(BMesh *bm, BMOperator *op);
+void makeprim_exec(BMesh *bm, BMOperator *op);
+void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op);
+void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op);
+void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op);
+void bmesh_translate_exec(BMesh *bm, BMOperator *op);
+void bmesh_transform_exec(BMesh *bm, BMOperator *op);
+void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op);
+void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op);
+void bmesh_rotate_exec(BMesh *bm, BMOperator *op);
+void bmesh_makevert_exec(BMesh *bm, BMOperator *op);
+void dissolveedges_exec(BMesh *bm, BMOperator *op);
+void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op);
+void bmesh_weldverts_exec(BMesh *bm, BMOperator *op);
+void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op);
+void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op);
+
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
new file mode 100644
index 00000000000..c013952a622
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -0,0 +1,838 @@
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+/*
+ *
+ * BME POLYGON.C
+ *
+ * This file contains code for dealing
+ * with polygons (normal/area calculation,
+ * tesselation, ect)
+ *
+ * TODO:
+ * -Add in Tesselator frontend that creates
+ * BMTriangles from copied faces
+ * -Add in Function that checks for and flags
+ * degenerate faces.
+ *
+*/
+
+/*
+ * TEST EDGE SIDE and POINT IN TRIANGLE
+ *
+ * Point in triangle tests stolen from scanfill.c.
+ * Used for tesselator
+ *
+*/
+
+static short testedgeside(double *v1, double *v2, double *v3)
+/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
+{
+ double inp;
+
+ //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
+ inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
+
+ if(inp<0.0) return 0;
+ else if(inp==0) {
+ if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
+ if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
+ }
+ return 1;
+}
+
+static short testedgesidef(float *v1, float *v2, float *v3)
+/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
+{
+ double inp;
+
+ //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
+ inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
+
+ if(inp<0.0) return 0;
+ else if(inp==0) {
+ if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
+ if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
+ }
+ return 1;
+}
+
+static int point_in_triangle(double *v1, double *v2, double *v3, double *pt)
+{
+ if(testedgeside(v1,v2,pt) && testedgeside(v2,v3,pt) && testedgeside(v3,v1,pt))
+ return 1;
+ return 0;
+}
+
+/*
+ * COMPUTE POLY NORMAL
+ *
+ * Computes the normal of a planar
+ * polygon See Graphics Gems for
+ * computing newell normal.
+ *
+*/
+static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts)
+{
+
+ float *u, *v;/*, *w, v1[3], v2[3];*/
+ double n[3] = {0.0, 0.0, 0.0}, l;
+ int i;
+
+ /*this fixes some weird numerical error*/
+ verts[0][0] += 0.0001f;
+ verts[0][1] += 0.0001f;
+ verts[0][2] += 0.0001f;
+
+ for(i = 0; i < nverts; i++){
+ u = verts[i];
+ v = verts[(i+1) % nverts];
+
+ /* 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 = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
+
+ if (l == 0.0) {
+ normal[0] = 0.0f;
+ normal[1] = 0.0f;
+ normal[2] = 1.0f;
+
+ return;
+ }
+
+ n[0] /= l;
+ n[1] /= l;
+ n[2] /= l;
+
+ normal[0] = (float) n[0];
+ normal[1] = (float) n[1];
+ normal[2] = (float) n[2];
+}
+
+/*
+ * COMPUTE POLY CENTER
+ *
+ * Computes the centroid and
+ * area of a polygon in the X/Y
+ * plane.
+ *
+*/
+
+static int compute_poly_center(float center[3], float *area, float (*verts)[3], int nverts)
+{
+ int i, j;
+ float atmp = 0.0, xtmp = 0.0, ytmp = 0.0, ai;
+
+ center[0] = center[1] = center[2] = 0.0;
+
+ if(nverts < 3)
+ return 0;
+
+ i = nverts-1;
+ j = 0;
+
+ while(j < nverts){
+ ai = verts[i][0] * verts[j][1] - verts[j][0] * verts[i][1];
+ atmp += ai;
+ xtmp += (verts[j][0] + verts[i][0]) * ai;
+ ytmp += (verts[j][1] + verts[i][1]) * ai;
+ i = j;
+ j += 1;
+ }
+
+ if(area)
+ *area = atmp / 2.0f;
+
+ if (atmp != 0){
+ center[0] = xtmp / (3.0f * atmp);
+ center[1] = xtmp / (3.0f * atmp);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+computes center of face in 3d. uses center of bounding box.
+*/
+
+int BM_Compute_Face_Center(BMesh *bm, BMFace *f, float center[3])
+{
+ BMIter iter;
+ BMLoop *l;
+ float min[3], max[3];
+ int i;
+
+ INIT_MINMAX(min, max);
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (i=0; l; l=BMIter_Step(&iter), i++) {
+ DO_MINMAX(l->v->co, min, max);
+ }
+
+ VECADD(center, min, max);
+ VECMUL(center, 0.5f);
+}
+
+/*
+ * COMPUTE POLY PLANE
+ *
+ * Projects a set polygon's vertices to
+ * a plane defined by the average
+ * of its edges cross products
+ *
+*/
+
+void compute_poly_plane(float (*verts)[3], int nverts)
+{
+
+ float avgc[3], norm[3], temp[3], mag, avgn[3];
+ float *v1, *v2, *v3;
+ int i;
+
+ if(nverts < 3)
+ return;
+
+ avgn[0] = avgn[1] = avgn[2] = 0.0;
+ avgc[0] = avgc[1] = avgc[2] = 0.0;
+
+ for(i = 0; i < nverts; i++){
+ v1 = verts[i];
+ v2 = verts[(i+1) % nverts];
+ v3 = verts[(i+2) % nverts];
+ CalcNormFloat(v1, v2, v3, norm);
+
+ avgn[0] += norm[0];
+ avgn[1] += norm[1];
+ avgn[2] += norm[2];
+ }
+
+ /*what was this bit for?*/
+ if(avgn[0] == 0.0 && avgn[1] == 0.0 && avgn[2] == 0.0){
+ avgn[0] = 0.0;
+ avgn[1] = 0.0;
+ avgn[2] = 1.0;
+ } else {
+ avgn[0] /= nverts;
+ avgn[1] /= nverts;
+ avgn[2] /= nverts;
+ Normalize(avgn);
+ }
+
+ for(i = 0; i < nverts; i++){
+ v1 = verts[i];
+ VECCOPY(temp, v1);
+ mag = 0.0;
+ mag += (temp[0] * avgn[0]);
+ mag += (temp[1] * avgn[1]);
+ mag += (temp[2] * avgn[2]);
+
+ temp[0] = (avgn[0] * mag);
+ temp[1] = (avgn[1] * mag);
+ temp[2] = (avgn[2] * mag);
+
+ VecSubf(v1, v1, temp);
+ }
+}
+
+/*
+ BM LEGAL EDGES
+
+ takes in a face and a list of edges, and sets to NULL any edge in
+ the list that bridges a concave region of the face or intersects
+ any of the faces's edges.
+*/
+static void shrink_edged(double *v1, double *v2, double fac)
+{
+ double mid[3];
+
+ VECADD(mid, v1, v2);
+ VECMUL(mid, 0.5);
+
+ VECSUB(v1, v1, mid);
+ VECSUB(v2, v2, mid);
+
+ VECMUL(v1, fac);
+ VECMUL(v2, fac);
+
+ VECADD(v1, v1, mid);
+ VECADD(v2, v2, mid);
+}
+
+static void shrink_edgef(float *v1, float *v2, float fac)
+{
+ float mid[3];
+
+ VECADD(mid, v1, v2);
+ VECMUL(mid, 0.5);
+
+ VECSUB(v1, v1, mid);
+ VECSUB(v2, v2, mid);
+
+ VECMUL(v1, fac);
+ VECMUL(v2, fac);
+
+ VECADD(v1, v1, mid);
+ VECADD(v2, v2, mid);
+}
+
+/*
+ * POLY ROTATE PLANE
+ *
+ * Rotates a polygon so that it's
+ * normal is pointing towards the mesh Z axis
+ *
+*/
+
+void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts)
+{
+
+ float up[3] = {0.0f,0.0f,1.0f}, axis[3], q[4];
+ float mat[3][3];
+ double angle;
+ int i;
+
+ Crossf(axis, up, normal);
+ axis[0] *= -1;
+ axis[1] *= -1;
+ axis[2] *= -1;
+
+ angle = saacos(normal[0]*up[0]+normal[1]*up[1] + normal[2]*up[2]);
+
+ if (angle == 0.0f) return;
+
+ AxisAngleToQuatd(q, axis, angle);
+ QuatToMat3(q, mat);
+
+ for(i = 0; i < nverts; i++)
+ Mat3MulVecfl(mat, verts[i]);
+}
+
+/*
+ * BMESH UPDATE FACE NORMAL
+ *
+ * Updates the stored normal for the
+ * given face. Requires that a buffer
+ * of sufficient length to store projected
+ * coordinates for all of the face's vertices
+ * is passed in as well.
+ *
+*/
+
+void BM_Face_UpdateNormal(BMesh *bm, BMFace *f)
+{
+ float projverts[12][3];
+ float (*proj)[3] = f->len < 12 ? projverts : MEM_mallocN(sizeof(float)*f->len*3, "projvertsn");
+ BMLoop *l = f->loopbase;
+ int i=0;
+
+ if (f->len < 3) return;
+
+ do {
+ VECCOPY(proj[i], l->v->co);
+ i += 1;
+ } while (l != f->loopbase);
+
+ bmesh_update_face_normal(bm, f, proj);
+
+ if (projverts != proj) MEM_freeN(proj);
+}
+
+void BM_Edge_UpdateNormals(BMesh *bm, BMEdge *e)
+{
+ BMIter iter;
+ BMFace *f;
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_EDGE, e);
+ for (; f; f=BMIter_Step(&iter)) {
+ BM_Face_UpdateNormal(bm, f);
+ }
+
+ BM_Vert_UpdateNormal(bm, e->v1);
+ BM_Vert_UpdateNormal(bm, e->v2);
+}
+
+void BM_Vert_UpdateNormal(BMesh *bm, BMVert *v)
+{
+ BMIter iter;
+ BMFace *f;
+ int len=0;
+
+ v->no[0] = v->no[1] = v->no[2] = 0.0f;
+
+ f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&iter), len++) {
+ VecAddf(v->no, f->no, v->no);
+ }
+
+ if (!len) return;
+
+ VecMulf(v->no, 1.0f/(int)len);
+}
+
+void bmesh_update_face_normal(BMesh *bm, BMFace *f, float (*projectverts)[3])
+{
+ BMLoop *l;
+ int i;
+
+ if(f->len > 4){
+ i = 0;
+ l = f->loopbase;
+ do{
+ VECCOPY(projectverts[i], l->v->co);
+ l = (BMLoop*)(l->head.next);
+ i += 1;
+ }while(l!=f->loopbase);
+
+ compute_poly_plane(projectverts, f->len);
+ compute_poly_normal(f->no, projectverts, f->len);
+ }
+ else if(f->len == 3){
+ BMVert *v1, *v2, *v3;
+ v1 = f->loopbase->v;
+ v2 = ((BMLoop*)(f->loopbase->head.next))->v;
+ v3 = ((BMLoop*)(f->loopbase->head.next->next))->v;
+ CalcNormFloat(v1->co, v2->co, v3->co, f->no);
+ }
+ else if(f->len == 4){
+ BMVert *v1, *v2, *v3, *v4;
+ v1 = f->loopbase->v;
+ v2 = ((BMLoop*)(f->loopbase->head.next))->v;
+ v3 = ((BMLoop*)(f->loopbase->head.next->next))->v;
+ v4 = ((BMLoop*)(f->loopbase->head.prev))->v;
+ CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, f->no);
+ }
+ else{ /*horrible, two sided face!*/
+ f->no[0] = 0.0;
+ f->no[1] = 0.0;
+ f->no[2] = 1.0;
+ }
+
+}
+
+
+/*
+ * BMESH FLIP NORMAL
+ *
+ * Reverses the winding of a faces
+ * Note that this does *not* update the calculated
+ * Normal
+*/
+void BM_flip_normal(BMesh *bm, BMFace *f)
+{
+ bmesh_loop_reverse(bm, f);
+}
+
+/* detects if two line segments cross each other (intersects).
+ note, there could be more winding cases then there needs to be. */
+int linecrosses(double *v1, double *v2, double *v3, double *v4)
+{
+ int w1, w2, w3, w4, w5;
+
+ /*w1 = winding(v1, v3, v4);
+ w2 = winding(v2, v3, v4);
+ w3 = winding(v3, v1, v2);
+ w4 = winding(v4, v1, v2);
+
+ return (w1 == w2) && (w3 == w4);*/
+
+ w1 = testedgeside(v1, v3, v2);
+ w2 = testedgeside(v2, v4, v1);
+ w3 = !testedgeside(v1, v2, v3);
+ w4 = testedgeside(v3, v2, v4);
+ w5 = !testedgeside(v3, v1, v4);
+ return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
+}
+
+/* detects if two line segments cross each other (intersects).
+ note, there could be more winding cases then there needs to be. */
+int linecrossesf(float *v1, float *v2, float *v3, float *v4)
+{
+ int w1, w2, w3, w4, w5;
+
+/* int test1_a, test1_a, test2_a, test2_a;
+
+ test1_a = check_tri_clock_dir(l1p1, l1p2, l2p1);
+ test1_b = check_tri_clock_dir(l1p1, l1p2, l2p2);
+ if (test1_a != test1_b)
+ {
+ test2_a = check_tri_clock_dir(l2p1, l2p2, l1p1);
+ test2_b = check_tri_clock_dir(l2p1, l2p2, l1p2);
+ if (test2_a != test2_b)
+ {
+ return 1;
+ }
+ }*/
+ /*w1 = testedgesidef(v1, v2, v3);
+ w2 = testedgesidef(v1, v2, v4);
+ if(w1 != w2) {
+ w3 = testedgesidef(v3, v4, v1);
+ w4 = testedgesidef(v3, v4, v2);
+ if (w3 != w4) return 1;
+ }
+
+ return 0;*/
+
+ /*w1 = testedgesidef(v1, v3, v4);
+ w2 = testedgesidef(v2, v3, v4);
+ w3 = testedgesidef(v3, v1, v2);
+ w4 = testedgesidef(v4, v1, v2);
+
+ return (w1 == w2) && (w2 == w3) && (w3 == w4);*/
+
+ w1 = testedgesidef(v1, v3, v2);
+ w2 = testedgesidef(v2, v4, v1);
+ w3 = !testedgesidef(v1, v2, v3);
+ w4 = testedgesidef(v3, v2, v4);
+ w5 = !testedgesidef(v3, v1, v4);
+ return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
+}
+
+int goodline(float (*projectverts)[3], BMFace *f, int v1i,
+ int v2i, int v3i, int nvert) {
+ BMLoop *l = f->loopbase;
+ double v1[3], v2[3], v3[3], pv1[3], pv2[3];
+ int i;
+
+ VECCOPY(v1, projectverts[v1i]);
+ VECCOPY(v2, projectverts[v2i]);
+ VECCOPY(v3, projectverts[v3i]);
+
+ if (testedgeside(v1, v2, v3)) return 0;
+
+ //for (i=0; i<nvert; i++) {
+ do {
+ i = l->v->head.eflag2;
+ if (i == v1i || i == v2i || i == v3i) {
+ l = (BMLoop*)l->head.next;
+ continue;
+ }
+
+ VECCOPY(pv1, projectverts[l->v->head.eflag2]);
+ VECCOPY(pv2, projectverts[((BMLoop*)l->head.next)->v->head.eflag2]);
+
+ //if (linecrosses(pv1, pv2, v1, v3)) return 0;
+ if (point_in_triangle(v1, v2, v3, pv1)) return 0;
+ if (point_in_triangle(v3, v2, v1, pv1)) return 0;
+
+ l = (BMLoop*)l->head.next;
+ } while (l != f->loopbase);
+ return 1;
+}
+/*
+ * FIND EAR
+ *
+ * Used by tesselator to find
+ * the next triangle to 'clip off'
+ * of a polygon while tesselating.
+ *
+*/
+
+static BMLoop *find_ear(BMesh *bm, BMFace *f, float (*verts)[3],
+ int nvert)
+{
+ BMVert *v1, *v2, *v3;
+ BMLoop *bestear = NULL, *l;
+ float angle, bestangle = 180.0f;
+ int isear, i=0;
+
+ l = f->loopbase;
+ do {
+ isear = 1;
+
+ v1 = ((BMLoop*)(l->head.prev))->v;
+ v2 = l->v;
+ v3 = ((BMLoop*)(l->head.next))->v;
+
+ if (BM_Edge_Exist(v1, v3)) isear = 0;
+
+ if (isear && !goodline(verts, f, v1->head.eflag2, v2->head.eflag2,
+ v3->head.eflag2, nvert))
+ isear = 0;
+
+ if(isear) {
+ /*angle = VecAngle3(verts[v1->head.eflag2], verts[v2->head.eflag2], verts[v3->head.eflag2]);
+ if(!bestear || ABS(angle-45.0f) < bestangle) {
+ bestear = l;
+ bestangle = ABS(45.0f-angle);
+ }
+
+ if (angle > 20 && angle < 90) break;
+ if (angle < 100 && i > 5) break;
+ i += 1;*/
+ bestear = l;
+ break;
+ }
+ l = (BMLoop*)(l->head.next);
+ }
+ while(l != f->loopbase);
+
+ return bestear;
+}
+
+/*
+ * BMESH TRIANGULATE FACE
+ *
+ * Triangulates a face using a
+ * simple 'ear clipping' algorithm
+ * that tries to favor non-skinny
+ * triangles (angles less than
+ * 90 degrees). If the triangulator
+ * has bits left over (or cannot
+ * triangulate at all) it uses a
+ * simple fan triangulation
+ *
+ * newfaces, if non-null, must be an array of BMFace pointers,
+ * with a length equal to f->len. it will be filled with the new
+ * triangles, and will be NULL-terminated.
+*/
+void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3],
+ int newedgeflag, int newfaceflag, BMFace **newfaces)
+{
+ int i, done, nvert, nf_i = 0;
+ BMLoop *l, *newl, *nextloop;
+ BMVert *v;
+
+ /*copy vertex coordinates to vertspace array*/
+ i = 0;
+ l = f->loopbase;
+ do{
+ VECCOPY(projectverts[i], l->v->co);
+ l->v->head.eflag2 = i; /*warning, abuse! never duplicate in tools code! never you hear?*/ /*actually, get rid of this completely, use a new structure for this....*/
+ i++;
+ l = (BMLoop*)(l->head.next);
+ }while(l != f->loopbase);
+
+ ///bmesh_update_face_normal(bm, f, projectverts);
+
+ compute_poly_normal(f->no, projectverts, f->len);
+ poly_rotate_plane(f->no, projectverts, i);
+
+ nvert = f->len;
+
+ //compute_poly_plane(projectverts, i);
+ for (i=0; i<nvert; i++) {
+ projectverts[i][2] = 0.0f;
+ }
+
+ done = 0;
+ while(!done && f->len > 3){
+ done = 1;
+ l = find_ear(bm, f, projectverts, nvert);
+ if(l) {
+ done = 0;
+ v = l->v;
+ f = BM_Split_Face(bm, l->f, ((BMLoop*)(l->head.prev))->v,
+ ((BMLoop*)(l->head.next))->v,
+ &newl, NULL);
+ VECCOPY(f->no, l->f->no);
+
+ if (!f) {
+ printf("yeek! triangulator failed to split face!\n");
+ break;
+ }
+
+ BMO_SetFlag(bm, newl->e, newedgeflag);
+ BMO_SetFlag(bm, f, newfaceflag);
+
+ if (newfaces) newfaces[nf_i++] = f;
+
+ /*l = f->loopbase;
+ do {
+ if (l->v == v) {
+ f->loopbase = l;
+ break;
+ }
+ l = l->head.next;
+ } while (l != f->loopbase);*/
+ }
+ }
+
+ if (f->len > 3){
+ l = f->loopbase;
+ while (l->f->len > 3){
+ nextloop = ((BMLoop*)(l->head.next->next));
+ f = BM_Split_Face(bm, l->f, l->v, nextloop->v,
+ &newl, NULL);
+ if (!f) {
+ printf("triangle fan step of triangulator failed.\n");
+
+ /*NULL-terminate*/
+ if (newfaces) newfaces[nf_i] = NULL;
+ return;
+ }
+
+ if (newfaces) newfaces[nf_i++] = f;
+
+ BMO_SetFlag(bm, newl->e, newedgeflag);
+ BMO_SetFlag(bm, f, newfaceflag);
+ l = nextloop;
+ }
+ }
+
+ /*NULL-terminate*/
+ if (newfaces) newfaces[nf_i] = NULL;
+}
+
+/*each pair of loops defines a new edge, a split. this function goes
+ through and sets pairs that are geometrically invalid to null. a
+ split is invalid, if it forms a concave angle or it intersects other
+ edges in the face, or it intersects another split. in the case of
+ intersecting splits, only the first of the set of intersecting
+ splits survives.*/
+void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
+{
+ BMIter iter;
+ BMLoop *l;
+ float v1[3], v2[3], v3[3], v4[3], no[3], mid[3], *p1, *p2, *p3, *p4;
+ float out[3] = {-234324.0f, -234324.0f, 0.0f};
+ float projectverts[100][3];
+ float edgevertsstack[200][3];
+ float (*projverts)[3] = projectverts;
+ float (*edgeverts)[3] = edgevertsstack;
+ float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f;
+ int i, j, a=0, clen;
+
+ if (f->len > 100) projverts = MEM_mallocN(sizeof(float)*3*f->len, "projvertsb");
+ if (len > 100) edgeverts = MEM_mallocN(sizeof(float)*3*2*len, "edgevertsb");
+
+ i = 0;
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&iter)) {
+ l->head.eflag2 = i;
+ VECCOPY(projverts[i], l->v->co);
+ i++;
+ }
+
+ for (i=0; i<len; i++) {
+ VECCOPY(v1, loops[i][0]->v->co);
+ VECCOPY(v2, loops[i][1]->v->co);
+
+ shrink_edgef(v1, v2, fac2);
+
+ VECCOPY(edgeverts[a], v1);
+ a++;
+ VECCOPY(edgeverts[a], v2);
+ a++;
+ }
+
+ compute_poly_normal(no, projverts, f->len);
+ poly_rotate_plane(no, projverts, f->len);
+ poly_rotate_plane(no, edgeverts, len*2);
+
+ l = f->loopbase;
+ for (i=0; i<f->len; i++) {
+ p1 = projverts[i];
+ out[0] = MAX2(out[0], p1[0]) + 0.01f;
+ out[1] = MAX2(out[1], p1[1]) + 0.01f;
+ out[2] = 0.0f;
+ p1[2] = 0.0f;
+
+ //VECCOPY(l->v->co, p1);
+
+ l = (BMLoop*) l->head.next;
+ }
+
+ for (i=0; i<len; i++) {
+ edgeverts[i*2][2] = 0.0f;
+ edgeverts[i*2+1][2] = 0.0f;
+ }
+
+ /*do convexity test*/
+ for (i=0; i<len; i++) {
+ VECCOPY(v2, edgeverts[i*2]);
+ VECCOPY(v3, edgeverts[i*2+1]);
+
+ VecAddf(mid, v2, v3);
+ VecMulf(mid, 0.5f);
+
+ clen = 0;
+ for (j=0; j<f->len; j++) {
+ p1 = projverts[j];
+ p2 = projverts[(j+1)%f->len];
+
+ VECCOPY(v1, p1);
+ VECCOPY(v2, p2);
+
+ shrink_edgef(v1, v2, fac1);
+
+ if (linecrossesf(p1, p2, mid, out)) clen++;
+ }
+
+ if (clen%2 == 0) {
+ loops[i][0] = NULL;
+ }
+ }
+
+ /*do line crossing tests*/
+ for (i=0; i<f->len; i++) {
+ p1 = projverts[i];
+ p2 = projverts[(i+1)%f->len];
+
+ VECCOPY(v1, p1);
+ VECCOPY(v2, p2);
+
+ shrink_edgef(v1, v2, fac1);
+
+ for (j=0; j<len; j++) {
+ if (!loops[j][0]) continue;
+
+ p3 = edgeverts[j*2];
+ p4 = edgeverts[j*2+1];
+
+ if (linecrossesf(v1, v2, p3, p4))
+ {
+ loops[j][0] = NULL;
+ }
+ }
+ }
+
+ for (i=0; i<len; i++) {
+ for (j=0; j<len; j++) {
+ if (j == i) continue;
+ if (!loops[i][0]) continue;
+ if (!loops[j][0]) continue;
+
+ p1 = edgeverts[i*2];
+ p2 = edgeverts[i*2+1];
+ p3 = edgeverts[j*2];
+ p4 = edgeverts[j*2+1];
+
+ VECCOPY(v1, p1);
+ VECCOPY(v2, p2);
+
+ shrink_edgef(v1, v2, fac1);
+
+ if (linecrossesf(v1, v2, p3, p4)) {
+ loops[i][0]=NULL;
+ }
+ }
+ }
+
+ if (projverts != projectverts) MEM_freeN(projverts);
+ if (edgeverts != edgevertsstack) MEM_freeN(edgeverts);
+}
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
new file mode 100644
index 00000000000..999285a6d12
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -0,0 +1,84 @@
+/**
+ * bmesh_private.h jan 2007
+ *
+ * Private function prototypes for bmesh public API.
+ * This file is a grab-bag of functions from various
+ * parts of the bmesh internals.
+ *
+ *
+ * $Id: BKE_bmesh.h,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BMESH_PRIVATE_H
+#define BMESH_PRIVATE_H
+
+#include "bmesh.h"
+
+/*start/stop edit*/
+void bmesh_begin_edit(struct BMesh *bm);
+void bmesh_end_edit(struct BMesh *bm, int flag);
+
+/*internal selection flushing*/
+void bmesh_selectmode_flush(struct BMesh *bm);
+
+/*internal filter API*/
+void *bmesh_get_filter_callback(int type);
+int bmesh_get_filter_argtype(int type);
+
+/*system flag access*/
+void bmesh_set_sysflag(struct BMHeader *element, int flag);
+void bmesh_clear_sysflag(struct BMHeader *element, int flag);
+int bmesh_test_sysflag(struct BMHeader *element, int flag);
+
+/*NOTE: ensure different parts of the API do not conflict
+ on using this! sets and gets the API index member
+ of the current flag layer.*/
+#define bmesh_api_seti(bm, head, i) ((head)->flags[bm->stackdepth-1].pflag = i)
+#define bmesh_api_geti(bm, head) ((head)->flags[bm->stackdepth-1].pflag)
+
+/*Polygon Utilities ? FIXME... where do these each go?*/
+/*newedgeflag sets a flag layer flag, obviously not the header flag.*/
+void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3],
+ int newedgeflag, int newfaceflag, BMFace **newfaces);
+void bmesh_update_face_normal(struct BMesh *bm, struct BMFace *f,
+ float (*projectverts)[3]);
+void compute_poly_plane(float (*verts)[3], int nverts);
+void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts);
+void bmesh_flip_normal(struct BMesh *bm, struct BMFace *f);
+
+/*Error reporting. Shouldnt be called by tools ever.*/
+void BME_error(void);
+
+/*include the rest of our private declarations*/
+#include "bmesh_structure.h"
+#include "bmesh_operators_private.h"
+
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
new file mode 100644
index 00000000000..c5a9916ae24
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -0,0 +1,548 @@
+#include <string.h>
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+
+#include "BLI_arithb.h"
+#include "MTC_vectorops.h"
+
+/*
+ * BM_QUERIES.C
+ *
+ * This file contains functions for answering common
+ * Topological and geometric queries about a mesh, such
+ * as, "What is the angle between these two faces?" or,
+ * "How many faces are incident upon this vertex?" Tool
+ * authors should use the functions in this file instead
+ * of inspecting the mesh structure directly.
+ *
+*/
+
+/*
+ * BMESH COUNT ELEMENT
+ *
+ * Return the amount of element of
+ * type 'type' in a given bmesh.
+ *
+ *
+*/
+
+int BM_Count_Element(BMesh *bm, int type)
+{
+ if(type == BM_VERT) return bm->totvert;
+ else if(type == BM_EDGE) return bm->totedge;
+ else if(type == BM_FACE) return bm->totface;
+
+ return 0;
+}
+
+
+/*
+ * BMESH VERT IN EDGE
+ *
+ * Returns whether or not a given vertex is
+ * is part of a given edge.
+ *
+*/
+
+int BM_Vert_In_Edge(BMEdge *e, BMVert *v)
+{
+ return bmesh_vert_in_edge(e, v);
+}
+
+/*
+ * BMESH OTHER EDGE IN FACE SHARING A VERTEX
+ *
+ * Returns an opposing loop that shares the same face.
+ *
+*/
+
+BMLoop *BM_OtherFaceLoop(BMEdge *e, BMFace *f, BMVert *v)
+{
+ BMLoop *l = f->loopbase, *l2, *l3;
+ int found = 0;
+
+ do {
+ if (l->e == e) break;
+ found = 1;
+ l = l->head.next;
+ } while (l != f->loopbase);
+
+ return l->v == v ? l->head.prev : l->head.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;
+
+ l = f->loopbase;
+ do{
+ if(l->v == v) return 1;
+ l = ((BMLoop*)(l->head.next));
+ }while(l != f->loopbase);
+ return 0;
+}
+
+/*
+ * BMESH VERTS IN FACE
+ *
+ * Compares the number of vertices in an array
+ * that appear in a given face
+ *
+*/
+int BM_Verts_In_Face(BMesh *bm, BMFace *f, BMVert **varr, int len)
+{
+ BMLoop *curloop = NULL;
+ int i, count = 0;
+
+ for(i=0; i < len; i++) BMO_SetFlag(bm, varr[i], BM_OVERLAP);
+
+ curloop = f->loopbase;
+ do{
+ if(BMO_TestFlag(bm, curloop->v, BM_OVERLAP)) count++;
+ curloop = (BMLoop*)(curloop->head.next);
+ } while(curloop != f->loopbase);
+
+ for(i=0; i < len; i++) BMO_ClearFlag(bm, varr[i], BM_OVERLAP);
+
+ return count;
+}
+
+/*
+ * BMESH EDGE IN FACE
+ *
+ * Returns whether or not a given edge is
+ * is part of a given face.
+ *
+*/
+
+int BM_Edge_In_Face(BMFace *f, BMEdge *e)
+{
+ BMLoop *l;
+
+ l = f->loopbase;
+ do{
+
+ if(l->e == e) return 1;
+ l = ((BMLoop*)(l->head.next));
+ }while(l != f->loopbase);
+
+ return 0;
+}
+
+/*
+ * BMESH VERTS IN EDGE
+ *
+ * Returns whether or not two vertices are in
+ * a given edge
+ *
+*/
+
+int BM_Verts_In_Edge(BMVert *v1, BMVert *v2, BMEdge *e)
+{
+ return bmesh_verts_in_edge(v1,v2,e);
+}
+
+/*
+ * BMESH GET OTHER EDGEVERT
+ *
+ * Given a edge and one of its vertices, returns
+ * the other vertex.
+ *
+*/
+
+BMVert *BM_OtherEdgeVert(BMEdge *e, BMVert *v)
+{
+ return bmesh_edge_getothervert(e,v);
+}
+
+/**
+ * BMESH EDGE EXIST
+ *
+ * Finds out if two vertices already have an edge
+ * connecting them. Note that multiple edges may
+ * exist between any two vertices, and therefore
+ * This function only returns the first one found.
+ *
+ * Returns -
+ * BMEdge pointer
+ */
+
+BMEdge *BM_Edge_Exist(BMVert *v1, BMVert *v2)
+{
+ BMNode *diskbase;
+ BMEdge *curedge;
+ int i, len=0;
+
+ if(v1->edge){
+ diskbase = bmesh_disk_getpointer(v1->edge,v1);
+ len = bmesh_cycle_length(diskbase);
+
+ for(i=0,curedge=v1->edge;i<len;i++,curedge = bmesh_disk_nextedge(curedge,v1)){
+ if(bmesh_verts_in_edge(v1,v2,curedge)) return curedge;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * BMESH VERT EDGECOUNT
+ *
+ * Returns the number of edges around this vertex.
+ */
+
+int BM_Vert_EdgeCount(BMVert *v)
+{
+ if (v == v->edge->v1) return bmesh_cycle_length(&v->edge->d1);
+ else return bmesh_cycle_length(&v->edge->d2);
+}
+
+/**
+ * BMESH EDGE FACECOUNT
+ *
+ * Returns the number of faces around this edge
+*/
+
+int BM_Edge_FaceCount(BMEdge *e)
+{
+ int count = 0;
+ BMLoop *curloop = NULL;
+
+ if(e->loop){
+ curloop = e->loop;
+ do{
+ count++;
+ curloop = bmesh_radial_nextloop(curloop);
+ }while(curloop != e->loop);
+ }
+
+ return count;
+}
+
+/**
+ * BMESH VERT FACECOUNT
+ *
+ * Returns the number of faces around this vert
+*/
+
+int BM_Vert_FaceCount(BMVert *v){
+ int count = 0;
+ BMEdge *curedge = NULL;
+
+ if(v->edge){
+ curedge = v->edge;
+ do{
+ if(curedge->loop) count += BM_Edge_FaceCount(curedge);
+ curedge = bmesh_disk_nextedge(curedge,v);
+ }while(curedge != v->edge);
+ }
+ return count;
+}
+
+/**
+ * BMESH WIRE VERT
+ *
+ * Tests whether or not the vertex is part of a wire edge.
+ * (ie: has no faces attached to it)
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Wire_Vert(BMesh *bm, BMVert *v)
+{
+ BMEdge *curedge;
+
+ if(!(v->edge)) return 0;
+
+ curedge = v->edge;
+ do{
+ if(curedge->loop) return 0;
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }while(curedge != v->edge);
+
+ return 1;
+}
+
+/**
+ * BMESH WIRE EDGE
+ *
+ * Tests whether or not the edge is part of a wire.
+ * (ie: has no faces attached to it)
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Wire_Edge(BMesh *bm, BMEdge *e)
+{
+ if(e->loop) return 0;
+ return 1;
+}
+
+/**
+ * BMESH NONMANIFOLD VERT
+ *
+ * A vertex is non-manifold if it meets the following conditions:
+ * 1: Loose - (has no edges/faces incident upon it)
+ * 2: Joins two distinct regions - (two pyramids joined at the tip)
+ * 3: Is part of a non-manifold edge (edge with more than 2 faces)
+ * 4: Is part of a wire edge
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Nonmanifold_Vert(BMesh *bm, BMVert *v) {
+ BMEdge *e, *oe;
+ BMLoop *l;
+ int len, count, flag;
+
+ if (v->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=bmesh_disk_nextedge(e,v)) {
+ if (e->loop == NULL) {
+ /* loose edge */
+ return 1;
+ }
+
+ if (bmesh_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 = ((BMLoop*)(l->head.prev));
+ else l = ((BMLoop*)(l->head.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;
+}
+
+/**
+ * BMESH NONMANIFOLD EDGE
+ *
+ * Tests whether or not this edge is manifold.
+ * A manifold edge either has 1 or 2 faces attached
+ * to it.
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Nonmanifold_Edge(BMesh *bm, BMEdge *e)
+{
+ int count = BM_Edge_FaceCount(e);
+ if(count != 2 && count != 1) return 1;
+ return 0;
+}
+
+/**
+ * BMESH BOUNDARY EDGE
+ *
+ * Tests whether or not an edge is on the boundary
+ * of a shell (has one face associated with it)
+ *
+ * Returns -
+ * 1 for true, 0 for false.
+ */
+
+int BM_Boundary_Edge(BMEdge *e)
+{
+ int count = BM_Edge_FaceCount(e);
+ if(count == 1) return 1;
+ return 0;
+}
+
+/**
+ * BMESH FACE SHAREDEDGES
+ *
+ * Counts the number of edges two faces share (if any)
+ *
+ * TODO:
+ * Move this to structure, and wrap.
+ *
+ * Returns -
+ * Integer
+ */
+
+int BM_Face_Sharededges(BMFace *f1, BMFace *f2){
+ BMLoop *l;
+ int count = 0;
+
+ l = f1->loopbase;
+ do{
+ if(bmesh_radial_find_face(l->e,f2)) count++;
+ l = ((BMLoop*)(l->head.next));
+ }while(l != f1->loopbase);
+
+ 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->loop && e2->loop){
+ l = e1->loop;
+ do{
+ f = l->f;
+ if(bmesh_radial_find_face(e2,f)){
+ return 1;
+ }
+ l = (BMLoop*)(l->radial.next->data);
+ }while(l != e1->loop);
+ }
+ return 0;
+}
+
+
+
+/**
+ * BMESH FACE ANGLE
+ *
+ * Calculates the angle between two faces. Assumes
+ * That face normals are correct.
+ *
+ * Returns -
+ * Float.
+ */
+
+float BM_Face_Angle(BMesh *bm, BMEdge *e)
+{
+ BMLoop *l1, *l2;
+ int radlen;
+ float edge_angle_cos = 0.0;
+
+ radlen = BM_Edge_FaceCount(e);
+ if(radlen == 2){
+ l1 = e->loop;
+ l2 = e->loop->radial.next->data;
+ edge_angle_cos = MTC_dot3Float(l1->f->no, l2->f->no);
+ }
+ return edge_angle_cos;
+
+}
+
+/*
+ * BMESH EXIST FACE OVERLAPS
+ *
+ * Given a set of vertices (varr), find out if
+ * all those vertices overlap an existing face.
+ *
+ * Returns:
+ * 0 for no overlap
+ * 1 for overlap
+ *
+ *
+*/
+
+int BM_Exist_Face_Overlaps(BMesh *bm, BMVert **varr, int len, BMFace **overlapface)
+{
+ BMIter vertfaces;
+ BMFace *f;
+ int i, amount;
+
+ if (overlapface) *overlapface = NULL;
+
+ for(i=0; i < len; i++){
+ f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] );
+ while(f){
+ amount = BM_Verts_In_Face(bm, f, varr, len);
+ if(amount >= len){
+ if (overlapface) *overlapface = f;
+ return 1;
+ }
+ f = BMIter_Step(&vertfaces);
+ }
+ }
+ return 0;
+}
+
+/*
+ * BMESH FACE EXISTS
+ *
+ * Given a set of vertices (varr), find out if
+ * there is a face with exactly those vertices
+ * (and only those vertices).
+ *
+ * Returns:
+ * 0 for no face found
+ * 1 for face found
+ *
+ *
+*/
+
+int BM_Face_Exists(BMesh *bm, BMVert **varr, int len, BMFace **existface)
+{
+ BMIter vertfaces;
+ BMFace *f;
+ int i, amount;
+
+ if (existface) *existface = NULL;
+
+ for(i=0; i < len; i++){
+ f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] );
+ while(f){
+ amount = BM_Verts_In_Face(bm, f, varr, len);
+ if(amount == len && amount == f->len){
+ if (existface) *existface = f;
+ return 1;
+ }
+ f = BMIter_Step(&vertfaces);
+ }
+ }
+ return 0;
+}
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
new file mode 100644
index 00000000000..a14f1d662ae
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -0,0 +1,775 @@
+/**
+ * bmesh_structure.c jan 2007
+ *
+ * Low level routines for manipulating the BM structure.
+ *
+ * $Id: bmesh_structure.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <limits.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "BKE_utildefines.h"
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_ghash.h"
+/**
+ * MISC utility functions.
+ *
+ */
+
+int bmesh_vert_in_edge(BMEdge *e, BMVert *v){
+ if(e->v1 == v || e->v2 == v) return 1;
+ return 0;
+}
+int bmesh_verts_in_edge(BMVert *v1, BMVert *v2, BMEdge *e){
+ if(e->v1 == v1 && e->v2 == v2) return 1;
+ else if(e->v1 == v2 && e->v2 == v1) return 1;
+ return 0;
+}
+
+BMVert *bmesh_edge_getothervert(BMEdge *e, BMVert *v){
+ if(e->v1 == v) return e->v2;
+ else if(e->v2 == v) return e->v1;
+ return NULL;
+}
+
+int bmesh_edge_swapverts(BMEdge *e, BMVert *orig, BMVert *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
+ */
+
+BMVert *bmesh_addvertlist(BMesh *bm, BMVert *example){
+ BMVert *v=NULL;
+ v = BLI_mempool_calloc(bm->vpool);
+ v->head.next = v->head.prev = NULL;
+ v->head.flag = 0;
+ v->head.EID = bm->nextv;
+ v->head.type = BM_VERT;
+ 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->head.data = NULL;
+ v->bweight = 0.0f;
+ BLI_addtail(&(bm->verts), &(v->head));
+ bm->nextv++;
+ bm->totvert++;
+
+ if(example){
+ VECCOPY(v->co,example->co);
+ CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, example->head.data, &v->head.data);
+ }
+ else
+ CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
+
+ /*allocate flags*/
+ v->head.flags = BLI_mempool_calloc(bm->flagpool);
+
+ return v;
+}
+BMEdge *bmesh_addedgelist(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge *example){
+ BMEdge *e=NULL;
+ e = BLI_mempool_calloc(bm->epool);
+ e->head.next = e->head.prev = NULL;
+ e->head.EID = bm->nexte;
+ e->head.type = BM_EDGE;
+ e->head.flag = 0;
+ 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->head.data = NULL;
+ e->crease = e->bweight = 0.0f;
+ bm->nexte++;
+ bm->totedge++;
+ BLI_addtail(&(bm->edges), &(e->head));
+
+ if(example)
+ CustomData_bmesh_copy_data(&bm->edata, &bm->edata, example->head.data, &e->head.data);
+ else
+ CustomData_bmesh_set_default(&bm->edata, &e->head.data);
+
+ /*allocate flags*/
+ e->head.flags = BLI_mempool_calloc(bm->flagpool);
+
+ return e;
+}
+BMLoop *bmesh_create_loop(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f, BMLoop *example){
+ BMLoop *l=NULL;
+ l = BLI_mempool_calloc(bm->lpool);
+ l->head.next = l->head.prev = NULL;
+ l->head.EID = bm->nextl;
+ l->head.type = BM_LOOP;
+ l->head.flag = 0;
+ l->radial.next = l->radial.prev = NULL;
+ l->radial.data = l;
+ l->v = v;
+ l->e = e;
+ l->f = f;
+ l->head.data = NULL;
+ bm->nextl++;
+ 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;
+}
+
+BMFace *bmesh_addpolylist(BMesh *bm, BMFace *example){
+ BMFace *f = NULL;
+ f = BLI_mempool_calloc(bm->ppool);
+ f->head.flag = 0;
+ f->head.next = f->head.prev = NULL;
+ f->head.EID = bm->nextp;
+ f->head.type = BM_FACE;
+ f->loopbase = NULL;
+ f->len = 0;
+ f->head.data = NULL;
+ f->mat_nr = 0;
+ BLI_addtail(&(bm->polys),&(f->head));
+ bm->nextp++;
+ bm->totface++;
+
+ if(example)
+ CustomData_bmesh_copy_data(&bm->pdata, &bm->pdata, example->head.data, &f->head.data);
+ else
+ CustomData_bmesh_set_default(&bm->pdata, &f->head.data);
+
+ /*allocate flags*/
+ f->head.flags = BLI_mempool_calloc(bm->flagpool);
+
+ 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 bmesh_free_vert(BMesh *bm, BMVert *v){
+ bm->totvert--;
+ CustomData_bmesh_free_block(&bm->vdata, &v->head.data);
+ BLI_mempool_free(bm->flagpool, v->head.flags);
+ BLI_mempool_free(bm->vpool, v);
+}
+void bmesh_free_edge(BMesh *bm, BMEdge *e){
+ bm->totedge--;
+ CustomData_bmesh_free_block(&bm->edata, &e->head.data);
+ BLI_mempool_free(bm->flagpool, e->head.flags);
+ BLI_mempool_free(bm->epool, e);
+}
+void bmesh_free_poly(BMesh *bm, BMFace *f){
+ if (f == bm->act_face)
+ bm->act_face = NULL;
+
+ bm->totface--;
+ CustomData_bmesh_free_block(&bm->pdata, &f->head.data);
+ BLI_mempool_free(bm->flagpool, f->head.flags);
+ BLI_mempool_free(bm->ppool, f);
+}
+void bmesh_free_loop(BMesh *bm, BMLoop *l){
+ bm->totloop--;
+ CustomData_bmesh_free_block(&bm->ldata, &l->head.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
+ * 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->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 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->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:
+ *
+ * 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.
+ *
+*/
+
+
+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(void *h){
+
+ int len = 0;
+ BMNode *head, *curnode;
+ head = (BMNode*)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;
+}
+
+
+/**
+ * bmesh_cycle_remove
+ *
+ * Removes a node from a cycle.
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_cycle_remove(void *h, void *remn)
+{
+ int i, len;
+ BMNode *head, *remnode, *curnode;
+
+ head = (BMNode*)h;
+ remnode = (BMNode*)remn;
+ len = bmesh_cycle_length(h);
+
+ if(len == 1 && head == remnode){
+ head->next = NULL;
+ head->prev = NULL;
+ return 1;
+ }
+ else{
+ for(i=0, curnode = head; i < len; curnode = curnode->next){
+ if(curnode == remnode){
+ remnode->prev->next = remnode->next;
+ remnode->next->prev = remnode->prev;
+ /*zero out remnode pointers, important!*/
+ //remnode->next = NULL;
+ //remnode->prev = NULL;
+ return 1;
+
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * bmesh_cycle_validate
+ *
+ * Validates a cycle. Takes as an argument the expected length of the cycle and
+ * a pointer to the cycle head or base.
+ *
+ *
+ * Returns -
+ * 1 for success, 0 for failure.
+ */
+
+int bmesh_cycle_validate(int len, void *h){
+ int i;
+ BMNode *curnode, *head;
+ head = (BMNode*)h;
+
+ /*forward validation*/
+ for(i = 0, curnode = head; i < len; i++, curnode = curnode->next);
+ if(curnode != head) return 0;
+
+ /*reverse validation*/
+ for(i = 0, curnode = head; i < len; i++, curnode = curnode->prev);
+ if(curnode != head) return 0;
+
+ return 1;
+}
+
+/*Begin Disk Cycle routines*/
+
+/**
+ * bmesh_disk_nextedge
+ *
+ * Find the next edge in a disk cycle
+ *
+ * Returns -
+ * Pointer to the next edge in the disk cycle for the vertex v.
+ */
+
+BMEdge *bmesh_disk_nextedge(BMEdge *e, BMVert *v)
+{
+ if(bmesh_vert_in_edge(e, v)){
+ if(e->v1 == v) return e->d1.next->data;
+ else if(e->v2 == v) return e->d2.next->data;
+ }
+ return NULL;
+}
+
+/**
+ * bmesh_disk_getpointer
+ *
+ * Given an edge and one of its vertices, find the apporpriate CycleNode
+ *
+ * Returns -
+ * Pointer to bmesh_CycleNode.
+ */
+BMNode *bmesh_disk_getpointer(BMEdge *e, BMVert *v){
+ /*returns pointer to the cycle node for the appropriate vertex in this disk*/
+ if(e->v1 == v) return &(e->d1);
+ else if (e->v2 == v) return &(e->d2);
+ return NULL;
+}
+
+/**
+ * bmesh_disk_append_edge
+ *
+ * Appends edge to the end of a vertex disk cycle.
+ *
+ * Returns -
+ * 1 for success, 0 for failure
+ */
+
+int bmesh_disk_append_edge(BMEdge *e, BMVert *v)
+{
+
+ BMNode *base, *tail;
+
+ if(bmesh_vert_in_edge(e, v) == 0) return 0; /*check to make sure v is in e*/
+
+ /*check for loose vert first*/
+ if(v->edge == NULL){
+ v->edge = e;
+ base = tail = bmesh_disk_getpointer(e, v);
+ bmesh_cycle_append(base, tail); /*circular reference is ok!*/
+ return 1;
+ }
+
+ /*insert e at the end of disk cycle and make it the new v->edge*/
+ base = bmesh_disk_getpointer(v->edge, v);
+ tail = bmesh_disk_getpointer(e, v);
+ bmesh_cycle_append(base, tail);
+ return 1;
+}
+
+/**
+ * bmesh_disk_remove_edge
+ *
+ * Removes an edge from a disk cycle. If the edge to be removed is
+ * at the base of the cycle, the next edge becomes the new base.
+ *
+ *
+ * Returns -
+ * Nothing
+ */
+
+void bmesh_disk_remove_edge(BMEdge *e, BMVert *v)
+{
+ BMNode *base, *remnode;
+ BMEdge *newbase;
+ int len;
+
+ base = bmesh_disk_getpointer(v->edge, v);
+ remnode = bmesh_disk_getpointer(e, v);
+
+ /*first deal with v->edge pointer...*/
+ len = bmesh_cycle_length(base);
+ if(len == 1) newbase = NULL;
+ else if(v->edge == e) newbase = base->next-> data;
+ else newbase = v->edge;
+
+ /*remove and rebase*/
+ bmesh_cycle_remove(base, remnode);
+ v->edge = 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->edge){
+ if(eflag && tflag) return 0; /*tflag and eflag are reserved for different functions!*/
+ diskbase = bmesh_disk_getpointer(v->edge, v);
+ len = bmesh_cycle_length(diskbase);
+
+ for(i = 0, curedge=v->edge; 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->edge){
+ diskbase = bmesh_disk_getpointer(v->edge,v);
+ len = bmesh_cycle_length(diskbase);
+
+ for(i = 0, curedge=v->edge; i<len; i++){
+ if(curedge == e) return 1;
+ else curedge=bmesh_disk_nextedge(curedge, v);
+ }
+ }
+ return 0;
+}
+
+BMEdge *bmesh_disk_existedge(BMVert *v1, BMVert *v2){
+ BMNode *diskbase;
+ BMEdge *curedge;
+ int i, len=0;
+
+ if(v1->edge){
+ diskbase = bmesh_disk_getpointer(v1->edge,v1);
+ len = bmesh_cycle_length(diskbase);
+
+ for(i=0,curedge=v1->edge;i<len;i++,curedge = bmesh_disk_nextedge(curedge,v1)){
+ if(bmesh_verts_in_edge(v1,v2,curedge)) return curedge;
+ }
+ }
+
+ return NULL;
+}
+
+/*end disk cycle routines*/
+
+BMLoop *bmesh_radial_nextloop(BMLoop *l){
+ return (BMLoop*)(l->radial.next->data);
+}
+
+void bmesh_radial_append(BMEdge *e, BMLoop *l){
+ if(e->loop == NULL) e->loop = l;
+ bmesh_cycle_append(&(e->loop->radial), &(l->radial));
+}
+
+void bmesh_radial_remove_loop(BMLoop *l, BMEdge *e)
+{
+ BMLoop *newbase;
+ int len;
+
+ /*deal with edge->loop pointer*/
+ len = bmesh_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*/
+ bmesh_cycle_remove(&(e->loop->radial), &(l->radial));
+ e->loop = newbase;
+}
+
+int bmesh_radial_find_face(BMEdge *e,BMFace *f)
+{
+
+ BMLoop *curloop;
+ int i, len;
+
+ len = bmesh_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;
+}
+
+
+/*
+ * 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->edge)
+ return count;
+
+ /*first, loop around edges*/
+ curedge = v->edge;
+ do{
+ if(curedge->loop) count += bmesh_radial_count_facevert(curedge->loop, v);
+ curedge = bmesh_disk_nextedge(curedge, v);
+ }while(curedge != v->edge);
+
+ 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->loop && bmesh_radial_count_facevert(searchedge->loop,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->loop && bmesh_radial_count_facevert(searchedge->loop,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->loopbase);
+ for (i = 0, l=f->loopbase; i < len; i++, l=((BMLoop*)(l->head.next)) ) {
+ if (l->v == v) return l;
+ }
+ return NULL;
+}
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
new file mode 100644
index 00000000000..ba63bb8f65f
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -0,0 +1,100 @@
+/**
+ * bmesh_structure.h jan 2007
+ *
+ * The lowest level of functionality for manipulating bmesh structures.
+ * None of these functions should ever be exported to the rest of Blender.
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BM_STRUCTURE_H
+#define BM_STRUCTURE_H
+
+/*ALLOCATION/DEALLOCATION*/
+struct BMVert *bmesh_addvertlist(struct BMesh *bm, struct BMVert *example);
+struct BMEdge *bmesh_addedgelist(struct BMesh *bm, struct BMVert *v1, struct BMVert *v2, struct BMEdge *example);
+struct BMFace *bmesh_addpolylist(struct BMesh *bm, struct BMFace *example);
+struct BMLoop *bmesh_create_loop(struct BMesh *bm, struct BMVert *v, struct BMEdge *e, struct BMFace *f, struct BMLoop *example);
+
+void bmesh_free_vert(struct BMesh *bm, struct BMVert *v);
+void bmesh_free_edge(struct BMesh *bm, struct BMEdge *e);
+void bmesh_free_poly(struct BMesh *bm, struct BMFace *f);
+void bmesh_free_loop(struct BMesh *bm, struct BMLoop *l);
+
+/*DOUBLE CIRCULAR LINKED LIST FUNCTIONS*/
+void bmesh_cycle_append(void *h, void *nt);
+int bmesh_cycle_remove(void *h, void *remn);
+int bmesh_cycle_validate(int len, void *h);
+int bmesh_cycle_length(void *h);
+
+/*DISK CYCLE MANAGMENT*/
+int bmesh_disk_append_edge(struct BMEdge *e, struct BMVert *v);
+void bmesh_disk_remove_edge(struct BMEdge *e, struct BMVert *v);
+struct BMEdge *bmesh_disk_nextedge(struct BMEdge *e, struct BMVert *v);
+struct BMNode *bmesh_disk_getpointer(struct BMEdge *e, struct BMVert *v);
+int bmesh_disk_count_facevert(struct BMVert *v);
+struct BMEdge *bmesh_disk_find_first_faceedge(struct BMEdge *e, struct BMVert *v);
+struct BMEdge *bmesh_disk_find_next_faceedge(struct BMEdge *e, struct BMVert *v);
+
+/*RADIAL CYCLE MANAGMENT*/
+void bmesh_radial_append(struct BMEdge *e, struct BMLoop *l);
+void bmesh_radial_remove_loop(struct BMLoop *l, struct BMEdge *e);
+int bmesh_radial_find_face(struct BMEdge *e, struct BMFace *f);
+struct BMLoop *bmesh_radial_nextloop(struct BMLoop *l);
+int bmesh_radial_count_facevert(struct BMLoop *l, struct BMVert *v);
+struct BMLoop *bmesh_radial_find_first_facevert(struct BMLoop *l, struct BMVert *v);
+struct BMLoop *bmesh_radial_find_next_facevert(struct BMLoop *l, struct BMVert *v);
+
+/*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 *new); /*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);
+
+/*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);
+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, BMFace *f2, BMEdge *e);
+
+struct BMVert *bmesh_urmv(struct BMesh *bm, struct BMFace *sf, struct BMVert *sv);
+//int *bmesh_grkv(struct BMesh *bm, struct BMFace *sf, struct BMVert *kv);
+
+#endif
diff --git a/source/blender/bmesh/intern/bmesh_to_editmesh.c b/source/blender/bmesh/intern/bmesh_to_editmesh.c
new file mode 100644
index 00000000000..4654d353255
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_to_editmesh.c
@@ -0,0 +1,312 @@
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+
+#include "bmesh.h"
+
+/*
+ * BMESH TO EDITMESH
+ *
+ * This file contains functions for converting
+ * from a bmesh to an editmesh
+ *
+*/
+
+/*
+ * LOOPS TO EDITMESH CORNERS
+ *
+ * Converts N-Gon loop (face-edge)
+ * data (UVs, Verts Colors, ect) to
+ * face corner data.
+ *
+*/
+
+static void loops_to_editmesh_corners(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texface->tpage = texpoly->tpage;
+ texface->flag = texpoly->flag;
+ texface->transp = texpoly->transp;
+ texface->mode = texpoly->mode;
+ texface->tile = texpoly->tile;
+ texface->unwrap = texpoly->unwrap;
+
+ j = 0;
+ l = f->loopbase;
+ do {
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ texface->uv[j][0] = mloopuv->uv[0];
+ texface->uv[j][1] = mloopuv->uv[1];
+ j++;
+ l = ((BMLoop*)(l->head.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->head.data, CD_MLOOPCOL, i);
+ mcol[j].r = mloopcol->r;
+ mcol[j].g = mloopcol->g;
+ mcol[j].b = mloopcol->b;
+ mcol[j].a = mloopcol->a;
+ j++;
+ l = ((BMLoop*)(l->head.next));
+ } while(l!=f->loopbase);
+ }
+}
+
+static EditVert *bmeshvert_to_editvert(BMesh *bm, EditMesh *em, BMVert *v, int index, EditVert **evlist)
+{
+ EditVert *eve = NULL;
+
+ v->head.eflag1 = index; /*abuse!*/
+ eve = addvertlist(em, v->co, NULL);
+ eve->keyindex = index;
+ evlist[index]= eve;
+
+ /*copy flags*/
+ if(v->head.flag & BM_HIDDEN) eve->h = 1;
+ if (v->head.flag & BM_SELECT) eve->f |= SELECT;
+
+ eve->bweight = v->bweight;
+ CustomData_em_copy_data(&bm->vdata, &em->vdata, v->head.data, &eve->data);
+ /*copy normal*/
+ eve->no[0] = v->no[0];
+ eve->no[1] = v->no[1];
+ eve->no[2] = v->no[2];
+
+ return eve;
+}
+
+static void bmeshedge_to_editedge_internal(BMesh *bm, EditMesh *em, BMEdge *e, EditEdge *eed)
+{
+ eed->crease = e->crease;
+ eed->bweight = e->bweight;
+
+ //copy relavent flags
+ if (e->head.flag & BM_SELECT) eed->f |= SELECT;
+ if (e->head.flag & BM_SEAM) eed->seam = 1;
+ if (e->head.flag & BM_SHARP) eed->sharp = 1;
+ if (e->head.flag & BM_HIDDEN) eed->h = 1;
+ if (e->head.flag & BM_FGON) eed->h |= EM_FGON;
+
+ CustomData_em_copy_data(&bm->edata, &em->edata, e->head.data, &eed->data);
+}
+
+static EditEdge *bmeshedge_to_editedge(BMesh *bm, EditMesh *em, BMEdge *e, EditVert **evlist)
+{
+ EditEdge *eed = NULL;
+
+ if(!(findedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1]))){
+ eed= addedgelist(em, evlist[e->v1->head.eflag1], evlist[e->v2->head.eflag1], NULL);
+ bmeshedge_to_editedge_internal(bm, em, e, eed);
+ }
+
+ return eed;
+}
+
+static EditFace *bmeshface_to_editface(BMesh *bm, EditMesh *em, BMFace *f, EditVert **evlist, int numCol, int numTex)
+{
+ EditVert *eve1, *eve2, *eve3, *eve4;
+ EditFace *efa = NULL;
+ int len;
+
+ len = f->len;
+
+ eve1= evlist[f->loopbase->v->head.eflag1];
+ eve2= evlist[((BMLoop*)(f->loopbase->head.next))->v->head.eflag1];
+ eve3= evlist[((BMLoop*)(f->loopbase->head.next->next))->v->head.eflag1];
+ if (len == 4) {
+ eve4= evlist[ ((BMLoop*)(f->loopbase->head.prev))->v->head.eflag1];
+ }
+ else {
+ eve4= NULL;
+ }
+
+ if (eve1==eve2 || eve1==eve3 || eve1==eve4 || eve2==eve3 || eve3==eve4
+ || eve2==eve4) return NULL;
+
+ efa = addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL);
+ if (!efa) return NULL;
+
+ bmeshedge_to_editedge_internal(bm, em, f->loopbase->e, efa->e1);
+ bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.next))->e, efa->e2);
+ bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.next->next))->e, efa->e3);
+ if(eve4)
+ bmeshedge_to_editedge_internal(bm, em, ((BMLoop*)(f->loopbase->head.prev))->e, efa->e4);
+
+ efa->mat_nr = (unsigned char)f->mat_nr;
+
+ /*Copy normal*/
+ efa->n[0] = f->no[0];
+ efa->n[1] = f->no[1];
+ efa->n[2] = f->no[2];
+
+ //copy relavent original flags
+ if (f->head.flag & BM_SELECT) efa->f |= SELECT;
+ if (f->head.flag & BM_HIDDEN) efa->h = 1;
+ if (f->head.flag & BM_SMOOTH) efa->flag |= ME_SMOOTH;
+ if (f->head.flag & BM_ACTIVE) EM_set_actFace(em, efa);
+
+ CustomData_em_copy_data(&bm->pdata, &em->fdata, f->head.data, &efa->data);
+ loops_to_editmesh_corners(bm, &em->fdata, efa->data, f, numCol,numTex);
+
+ return efa;
+}
+
+EditMesh *bmesh_to_editmesh_intern(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ EditMesh *em;
+ EditVert *eve, **evlist;
+
+ int totvert, i, numTex, numCol;
+
+ em = MEM_callocN(sizeof(EditMesh), "EditMesh from bmesh");
+
+ em->selectmode = bm->selectmode;
+
+ 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);
+
+ totvert = BM_Count_Element(bm, BM_VERT);
+ evlist= MEM_mallocN(totvert*sizeof(EditVert *),"evlist");
+
+ /* make vertices */
+ for(i=0, v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts), i++)
+ eve = bmeshvert_to_editvert(bm, em, v, i, evlist);
+
+ /* make edges */
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
+ bmeshedge_to_editedge(bm, em, e, evlist);
+
+ /* make faces */
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
+ bmeshface_to_editface(bm, em, f, evlist, numCol, numTex);
+
+ MEM_freeN(evlist);
+
+ EM_fgon_flags(em);
+
+ EM_nvertices_selected(em);
+ EM_nedges_selected(em);
+ EM_nfaces_selected(em);
+
+ return em;
+}
+
+void bmesh2edit_exec(BMesh *bmesh, BMOperator *op)
+{
+ BMO_Set_Pnt(op, "emout", bmesh_to_editmesh_intern(bmesh));
+}
+
+#define FACE_NGON 1
+
+void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op)
+{
+ BMOperator triop;
+ BMFace *face;
+ BMIter iter, liter;
+ BMEdge *edge;
+ BMLoop *l, *nl;
+ BMOpSlot *eout;
+ int i, trifan = BMO_Get_Int(op, "trifan");
+
+ if (!trifan) BMO_Init_Op(&triop, "triangulate");
+
+ /*instead of properly tesselate, just make a triangle fan, this
+ should make bmesh -> editmesh -> bmesh conversions always properly
+ work.*/
+ for (face = BMIter_New(&iter, bmesh, BM_FACES_OF_MESH, NULL); face; face=BMIter_Step(&iter)) {
+ if (face->len > 4) {
+ BMO_SetFlag(bmesh, face, FACE_NGON);
+ if (trifan) {
+ while (face->len > 4) {
+ BM_Split_Face(bmesh, face,
+ face->loopbase->v,
+ ((BMLoop*)face->loopbase->head.next->next)->v,
+ &nl, NULL);
+ BM_SetHFlag(nl->e, BM_FGON);
+ }
+ }
+ }
+ }
+
+ if (!trifan) {
+ BMO_Flag_To_Slot(bmesh, &triop, "faces", FACE_NGON, BM_FACE);
+ BMO_Exec_Op(bmesh, &triop);
+
+ eout = BMO_GetSlot(&triop, "edgeout");
+ for (i=0; i<eout->len; i++) {
+ edge = ((BMEdge**)eout->data.buf)[i];
+ edge->head.flag |= BM_FGON;
+ face = BMIter_New(&iter, bmesh, BM_FACES_OF_EDGE, edge);
+
+ for (; face; face=BMIter_Step(&iter)) {
+ face->head.flag |= BM_NONORMCALC;
+ }
+ }
+
+ BMO_Finish_Op(bmesh, &triop);
+ }
+}
+
+EditMesh *bmesh_to_editmesh(BMesh *bmesh)
+{
+ BMOperator conv, makefgon;
+ EditMesh *em;
+
+ /*first fgon-afy the mesh*/
+ BMO_Init_Op(&makefgon, "makefgon");
+ BMO_Set_Int(&makefgon, "trifan", 1);
+ BMO_Exec_Op(bmesh, &makefgon);
+ BMO_Finish_Op(bmesh, &makefgon);
+
+ BMO_Init_Op(&conv, "bmesh_to_editmesh");
+ BMO_Exec_Op(bmesh, &conv);
+ em = BMO_Get_Pnt(&conv, "emout");
+ BMO_Finish_Op(bmesh, &conv);
+
+ return em;
+} \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
new file mode 100644
index 00000000000..40f787bf6c2
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -0,0 +1,667 @@
+#include <stdio.h>
+#include <string.h>
+#include "BLI_mempool.h"
+
+#include "bmesh_private.h"
+#include "bmesh_walkers.h"
+
+#include "bmesh.h"
+
+/*
+ - joeedh -
+ design notes:
+
+ original desing: walkers directly emulation recursive functions.
+ functions save their state onto a stack, and also push new states
+ to implement recursive or looping behaviour. generally only one
+ state push per call with a specific state is desired.
+
+ basic design pattern: the walker step function goes through it's
+ list of possible choices for recursion, and recurses (by pushing a new state)
+ using the first non-visited one. this choise is the flagged as visited using
+ the ghash. each time this happens, only one state is pushed.
+
+ * walkers use tool flags, not header flags
+ * walkers now use ghash for storing visited elements,
+ rather then stealing flags. ghash can be rewritten
+ to be faster if necassary, in the far future :) .
+ * tools should ALWAYS have necassary error handling
+ for if walkers fail.
+*/
+
+typedef struct shellWalker{
+ struct shellWalker *prev;
+ BMVert *base;
+ BMEdge *curedge, *current;
+} shellWalker;
+
+typedef struct islandboundWalker {
+ struct islandboundWalker *prev;
+ BMLoop *base;
+ BMVert *lastv;
+ BMLoop *curloop;
+} islandboundWalker;
+
+typedef struct islandWalker {
+ struct islandWalker * prev;
+ BMFace *cur;
+} islandWalker;
+
+typedef struct loopWalker {
+ struct loopWalker * prev;
+ BMEdge *cur, *start;
+ BMVert *lastv, *startv;
+ int startrad, stage2;
+} loopWalker;
+
+typedef struct faceloopWalker {
+ struct faceloopWalker * prev;
+ BMLoop *l;
+} faceloopWalker;
+
+/* NOTE: this comment is out of date, update it - joeedh
+ * BMWalker - change this to use the filters functions.
+ *
+ * A generic structure for maintaing the state and callbacks nessecary for walking over
+ * the surface of a mesh. An example of usage:
+ *
+ * BMEdge *edge;
+ * BMWalker *walker = BMW_create(BM_SHELLWALKER, BM_SELECT);
+ * walker->begin(walker, vert);
+ * for(edge = BMW_walk(walker); edge; edge = bmeshWwalker_walk(walker)){
+ * bmesh_select_edge(edge);
+ * }
+ * BMW_free(walker);
+ *
+ * The above example creates a walker that walks over the surface a mesh by starting at
+ * a vertex and traveling across its edges to other vertices, and repeating the process
+ * over and over again until it has visited each vertex in the shell. An additional restriction
+ * is passed into the BMW_create function stating that we are only interested
+ * in walking over edges that have been flagged with the bitmask 'BM_SELECT'.
+ *
+ *
+*/
+
+/*Forward declerations*/
+static void *BMW_walk(struct BMWalker *walker);
+static void BMW_popstate(struct BMWalker *walker);
+static void BMW_pushstate(struct BMWalker *walker);
+
+static void shellWalker_begin(struct BMWalker *walker, void *data);
+static void *shellWalker_yield(struct BMWalker *walker);
+static void *shellWalker_step(struct BMWalker *walker);
+
+static void islandboundWalker_begin(BMWalker *walker, void *data);
+static void *islandboundWalker_yield(BMWalker *walker);
+static void *islandboundWalker_step(BMWalker *walker);
+
+static void islandWalker_begin(BMWalker *walker, void *data);
+static void *islandWalker_yield(BMWalker *walker);
+static void *islandWalker_step(BMWalker *walker);
+
+static void loopWalker_begin(BMWalker *walker, void *data);
+static void *loopWalker_yield(BMWalker *walker);
+static void *loopWalker_step(BMWalker *walker);
+
+static void faceloopWalker_begin(BMWalker *walker, void *data);
+static void *faceloopWalker_yield(BMWalker *walker);
+static void *faceloopWalker_step(BMWalker *walker);
+
+/* Pointer hiding*/
+typedef struct bmesh_walkerGeneric{
+ struct bmesh_walkerGeneric *prev;
+} bmesh_walkerGeneric;
+
+
+void *BMW_Begin(BMWalker *walker, void *start) {
+ walker->begin(walker, start);
+
+ return walker->step(walker);
+}
+
+/*
+ * BMW_CREATE
+ *
+ * Allocates and returns a new mesh walker of
+ * a given type. The elements visited are filtered
+ * by the bitmask 'searchmask'.
+ *
+*/
+
+void BMW_Init(BMWalker *walker, BMesh *bm, int type, int searchmask)
+{
+ int size = 0;
+
+ memset(walker, 0, sizeof(BMWalker));
+ walker->bm = bm;
+ walker->restrictflag = searchmask;
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ switch(type){
+ case BMW_SHELL:
+ walker->begin = shellWalker_begin;
+ walker->step = shellWalker_step;
+ walker->yield = shellWalker_yield;
+ size = sizeof(shellWalker);
+ break;
+ case BMW_ISLANDBOUND:
+ walker->begin = islandboundWalker_begin;
+ walker->step = islandboundWalker_step;
+ walker->yield = islandboundWalker_yield;
+ size = sizeof(islandboundWalker);
+ break;
+ case BMW_ISLAND:
+ walker->begin = islandWalker_begin;
+ walker->step = islandWalker_step;
+ walker->yield = islandWalker_yield;
+ size = sizeof(islandWalker);
+ break;
+ case BMW_LOOP:
+ walker->begin = loopWalker_begin;
+ walker->step = loopWalker_step;
+ walker->yield = loopWalker_yield;
+ size = sizeof(loopWalker);
+ break;
+ case BMW_FACELOOP:
+ walker->begin = faceloopWalker_begin;
+ walker->step = faceloopWalker_step;
+ walker->yield = faceloopWalker_yield;
+ size = sizeof(faceloopWalker);
+ break;
+ default:
+ break;
+ }
+ walker->stack = BLI_mempool_create(size, 100, 100);
+ walker->currentstate = NULL;
+}
+
+/*
+ * BMW_End
+ *
+ * Frees a walker's stack.
+ *
+*/
+
+void BMW_End(BMWalker *walker)
+{
+ BLI_mempool_destroy(walker->stack);
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+}
+
+
+/*
+ * BMW_Step
+ *
+*/
+
+void *BMW_Step(BMWalker *walker)
+{
+ BMHeader *head;
+
+ head = BMW_walk(walker);
+
+ return head;
+}
+
+/*
+ * BMW_WALK
+ *
+ * Steps a mesh walker forward by one element
+ *
+ * TODO:
+ * -add searchmask filtering
+ *
+*/
+
+static void *BMW_walk(BMWalker *walker)
+{
+ void *current = NULL;
+
+ while(walker->currentstate){
+ current = walker->step(walker);
+ if(current) return current;
+ }
+ return NULL;
+}
+
+/*
+ * BMW_popstate
+ *
+ * Pops the current walker state off the stack
+ * and makes the previous state current
+ *
+*/
+
+static void BMW_popstate(BMWalker *walker)
+{
+ void *oldstate;
+ oldstate = walker->currentstate;
+ walker->currentstate
+ = ((bmesh_walkerGeneric*)walker->currentstate)->prev;
+ BLI_mempool_free(walker->stack, oldstate);
+}
+
+/*
+ * BMW_pushstate
+ *
+ * Pushes the current state down the stack and allocates
+ * a new one.
+ *
+*/
+
+static void BMW_pushstate(BMWalker *walker)
+{
+ bmesh_walkerGeneric *newstate;
+ newstate = BLI_mempool_alloc(walker->stack);
+ newstate->prev = walker->currentstate;
+ walker->currentstate = newstate;
+}
+
+void BMW_reset(BMWalker *walker) {
+ while (walker->currentstate) {
+ BMW_popstate(walker);
+ }
+}
+
+/* Shell Walker:
+ *
+ * Starts at a vertex on the mesh and walks over the 'shell' it belongs
+ * to via visiting connected edges.
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void shellWalker_begin(BMWalker *walker, void *data){
+ BMVert *v = data;
+ shellWalker *shellWalk = NULL;
+
+ BMW_pushstate(walker);
+
+ shellWalk = walker->currentstate;
+ shellWalk->base = NULL;
+ shellWalk->curedge = NULL;
+
+ if(v->edge){
+ shellWalk->base = v;
+ shellWalk->curedge = v->edge;
+ }
+}
+static void *shellWalker_yield(BMWalker *walker)
+{
+ shellWalker *shellWalk = walker->currentstate;
+ return shellWalk->curedge;
+}
+
+static void *shellWalker_step(BMWalker *walker)
+{
+ BMEdge *curedge, *next = NULL;
+ BMVert *ov = NULL;
+ int restrictpass = 1;
+ shellWalker *shellWalk = walker->currentstate;
+
+ if (!BLI_ghash_lookup(walker->visithash, shellWalk->base))
+ BLI_ghash_insert(walker->visithash, shellWalk->base, NULL);
+
+ /*find the next edge whose other vertex has not been visited*/
+ curedge = shellWalk->curedge;
+ do{
+ if (!BLI_ghash_lookup(walker->visithash, curedge)) {
+ BLI_ghash_insert(walker->visithash, curedge, NULL);
+ if(walker->restrictflag &&
+ (!BMO_TestFlag(walker->bm, curedge, walker->restrictflag)))
+ {
+ restrictpass = 0;
+ }
+ if(restrictpass) {
+ ov = BM_OtherEdgeVert(curedge, shellWalk->base);
+
+ /*save current state*/
+ shellWalk->curedge = curedge;
+
+ /*push a new state onto the stack*/
+ BMW_pushstate(walker);
+
+ /*populate the new state*/
+ ((shellWalker*)walker->currentstate)->base = ov;
+ ((shellWalker*)walker->currentstate)->curedge = curedge;
+ /*break out of loop*/
+
+ next = curedge;
+ break;
+ }
+ }
+ curedge = bmesh_disk_nextedge(curedge, shellWalk->base);
+ }while(curedge != shellWalk->curedge);
+
+ shellWalk->current = next;
+ return next;
+}
+
+/* Island Boundary Walker:
+ *
+ * Starts at a edge on the mesh and walks over the boundary of an
+ * island it belongs to.
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void islandboundWalker_begin(BMWalker *walker, void *data){
+ BMLoop *l = data;
+ islandboundWalker *iwalk = NULL;
+
+ BMW_pushstate(walker);
+
+ iwalk = walker->currentstate;
+
+ iwalk->base = iwalk->curloop = l;
+ iwalk->lastv = l->v;
+
+ BLI_ghash_insert(walker->visithash, data, NULL);
+
+}
+
+static void *islandboundWalker_yield(BMWalker *walker)
+{
+ islandboundWalker *iwalk = walker->currentstate;
+
+ return iwalk->curloop;
+}
+
+static void *islandboundWalker_step(BMWalker *walker)
+{
+ islandboundWalker *iwalk = walker->currentstate, owalk;
+ BMVert *v;
+ BMEdge *e = iwalk->curloop->e;
+ BMFace *f;
+ BMLoop *l = iwalk->curloop;
+ int found=0;
+
+ owalk = *iwalk;
+
+ if (iwalk->lastv == e->v1) v = e->v2;
+ else v = e->v1;
+
+ if (BM_Nonmanifold_Vert(walker->bm, v)) {
+ BMW_reset(walker);
+ BMO_RaiseError(walker->bm, NULL,BMERR_WALKER_FAILED,
+ "Non-manifold vert"
+ " while searching region boundary");
+ return NULL;
+ }
+
+ /*pop off current state*/
+ BMW_popstate(walker);
+
+ f = l->f;
+
+ while (1) {
+ l = BM_OtherFaceLoop(e, f, v);
+ if (bmesh_radial_nextloop(l) != l) {
+ l = bmesh_radial_nextloop(l);
+ f = l->f;
+ e = l->e;
+ if(!BMO_TestFlag(walker->bm, f, walker->restrictflag)){
+ l = l->radial.next->data;
+ break;
+ }
+ } else {
+ f = l->f;
+ e = l->e;
+ break;
+ }
+ }
+
+ if (l == owalk.curloop) return NULL;
+ if (BLI_ghash_haskey(walker->visithash, l)) return owalk.curloop;
+
+ BLI_ghash_insert(walker->visithash, l, NULL);
+ BMW_pushstate(walker);
+ iwalk = walker->currentstate;
+ iwalk->base = owalk.base;
+
+ //if (!BMO_TestFlag(walker->bm, l->f, walker->restrictflag))
+ // iwalk->curloop = l->radial.next->data;
+ iwalk->curloop = l; //else iwalk->curloop = l;
+ iwalk->lastv = v;
+
+ return owalk.curloop;
+}
+
+
+/* Island Walker:
+ *
+ * Starts at a tool flagged-face and walks over the face region
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void islandWalker_begin(BMWalker *walker, void *data){
+ islandWalker *iwalk = NULL;
+
+ BMW_pushstate(walker);
+
+ iwalk = walker->currentstate;
+ BLI_ghash_insert(walker->visithash, data, NULL);
+
+ iwalk->cur = data;
+}
+
+static void *islandWalker_yield(BMWalker *walker)
+{
+ islandWalker *iwalk = walker->currentstate;
+
+ return iwalk->cur;
+}
+
+static void *islandWalker_step(BMWalker *walker)
+{
+ islandWalker *iwalk = walker->currentstate, *owalk;
+ BMIter iter, liter;
+ BMFace *f, *curf = iwalk->cur;
+ BMLoop *l;
+ owalk = iwalk;
+
+ BMW_popstate(walker);
+
+ l = BMIter_New(&liter, walker->bm, BM_LOOPS_OF_FACE, iwalk->cur);
+ for (; l; l=BMIter_Step(&liter)) {
+ f = BMIter_New(&iter, walker->bm, BM_FACES_OF_EDGE, l->e);
+ for (; f; f=BMIter_Step(&iter)) {
+ if (!BMO_TestFlag(walker->bm, f, walker->restrictflag))
+ continue;
+ if (BLI_ghash_haskey(walker->visithash, f)) continue;
+
+ BMW_pushstate(walker);
+ iwalk = walker->currentstate;
+ iwalk->cur = f;
+ BLI_ghash_insert(walker->visithash, f, NULL);
+ break;
+
+ }
+ }
+
+ return curf;
+}
+
+
+/* Island Walker:
+ *
+ * Starts at a tool flagged-face and walks over the face region
+ *
+ * TODO:
+ *
+ * Add restriction flag/callback for wire edges.
+ *
+*/
+
+static void loopWalker_begin(BMWalker *walker, void *data){
+ loopWalker *lwalk = NULL, owalk;
+ BMEdge *e = data;
+ BMVert *v;
+ int found=1, val;
+
+ v = e->v1;
+
+ val = BM_Vert_EdgeCount(v);
+
+ BMW_pushstate(walker);
+
+ lwalk = walker->currentstate;
+ BLI_ghash_insert(walker->visithash, e, NULL);
+
+ lwalk->cur = lwalk->start = e;
+ lwalk->lastv = lwalk->startv = v;
+ lwalk->stage2 = 0;
+ lwalk->startrad = BM_Edge_FaceCount(e);
+
+ /*rewind*/
+ while (walker->currentstate) {
+ owalk = *((loopWalker*)walker->currentstate);
+ BMW_walk(walker);
+ }
+
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ *lwalk = owalk;
+
+ if (lwalk->lastv == owalk.cur->v1) lwalk->lastv = owalk.cur->v2;
+ else lwalk->lastv = owalk.cur->v1;
+
+ lwalk->startv = lwalk->lastv;
+
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ BLI_ghash_insert(walker->visithash, owalk.cur, NULL);
+}
+
+static void *loopWalker_yield(BMWalker *walker)
+{
+ loopWalker *lwalk = walker->currentstate;
+
+ return lwalk->cur;
+}
+
+static void *loopWalker_step(BMWalker *walker)
+{
+ loopWalker *lwalk = walker->currentstate, owalk;
+ BMEdge *e = lwalk->cur, *nexte = NULL;
+ BMLoop *l, *l2;
+ BMVert *v;
+ int val, rlen, found=0, i=0, stopi;
+
+ owalk = *lwalk;
+
+ if (e->v1 == lwalk->lastv) v = e->v2;
+ else v = e->v1;
+
+ val = BM_Vert_EdgeCount(v);
+
+ BMW_popstate(walker);
+
+ rlen = owalk.startrad;
+ l = e->loop;
+
+ if (val == 4 || val == 2 || rlen == 1) {
+ i = 0;
+ stopi = val / 2;
+ while (1) {
+ if (rlen != 1 && i == stopi) break;
+
+ l = BM_OtherFaceLoop(l->e, l->f, v);
+ l2 = bmesh_radial_nextloop(l);
+
+ if (l2 == l) {
+ break;
+ }
+
+ l = l2;
+
+ i += 1;
+ }
+ }
+
+ if (l != e->loop && !BLI_ghash_haskey(walker->visithash, l->e)) {
+ if (!(rlen != 1 && i != stopi)) {
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ *lwalk = owalk;
+ lwalk->cur = l->e;
+ lwalk->lastv = v;
+ BLI_ghash_insert(walker->visithash, l->e, NULL);
+ }
+ }
+
+ return owalk.cur;
+}
+
+static void faceloopWalker_begin(BMWalker *walker, void *data)
+{
+ faceloopWalker *lwalk, owalk;
+ BMEdge *e = data;
+
+ BMW_pushstate(walker);
+
+ if (!e->loop) return;
+
+ lwalk = walker->currentstate;
+ lwalk->l = e->loop;
+ BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL);
+
+ /*rewind*/
+ while (walker->currentstate) {
+ owalk = *((faceloopWalker*)walker->currentstate);
+ BMW_walk(walker);
+ }
+
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ *lwalk = owalk;
+
+ BLI_ghash_free(walker->visithash, NULL, NULL);
+ walker->visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ BLI_ghash_insert(walker->visithash, lwalk->l->f, NULL);
+}
+
+static void *faceloopWalker_yield(BMWalker *walker)
+{
+ faceloopWalker *lwalk = walker->currentstate;
+
+ if (!lwalk) return NULL;
+
+ return lwalk->l->f;
+}
+
+static void *faceloopWalker_step(BMWalker *walker)
+{
+ faceloopWalker *lwalk = walker->currentstate;
+ BMFace *f = lwalk->l->f;
+ BMLoop *l = lwalk->l;
+
+ BMW_popstate(walker);
+
+ l = l->head.next->next;
+ if (l == l->radial.next->data) {
+ l = l->head.prev->prev;
+ }
+ l = l->radial.next->data;
+
+ if (l->f->len == 4 && !BLI_ghash_haskey(walker->visithash, l->f)) {
+ BMW_pushstate(walker);
+ lwalk = walker->currentstate;
+ lwalk->l = l;
+
+ BLI_ghash_insert(walker->visithash, l->f, NULL);
+ }
+
+ return f;
+}
+
diff --git a/source/blender/bmesh/intern/editmesh_to_bmesh.c b/source/blender/bmesh/intern/editmesh_to_bmesh.c
new file mode 100644
index 00000000000..81e3572dec6
--- /dev/null
+++ b/source/blender/bmesh/intern/editmesh_to_bmesh.c
@@ -0,0 +1,473 @@
+
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+
+#include "bmesh.h"
+
+/*
+ * EDITMESH TO BMESH.C
+ *
+ * This file contains functions
+ * for converting an editmesh
+ * into a Bmesh
+ *
+*/
+
+/*
+ * EDITMESH CORNERS TO LOOPS
+ *
+ * Converts editmesh face corner data
+ * (UVs, Vert colors, ect) to N-Gon
+ * face-edge ('loop') data.
+ *
+*/
+
+static void editmesh_corners_to_loops(BMesh *bm, CustomData *facedata, void *face_block, BMFace *f,int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+ BMIter iter;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_em_get_n(facedata, face_block, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+
+ texpoly->tpage = texface->tpage;
+ texpoly->flag = texface->flag;
+ texpoly->transp = texface->transp;
+ texpoly->mode = texface->mode;
+ texpoly->tile = texface->tile;
+ texpoly->unwrap = texface->unwrap;
+
+ for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) {
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+ mloopuv->uv[0] = texface->uv[j][0];
+ mloopuv->uv[1] = texface->uv[j][1];
+ }
+
+ }
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_em_get_n(facedata, face_block, CD_MCOL, i);
+ for (j=0, l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f); l; j++, l=BMIter_Step(&iter)) {
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+ mloopcol->r = mcol[j].r;
+ mloopcol->g = mcol[j].g;
+ mloopcol->b = mcol[j].b;
+ mloopcol->a = mcol[j].a;
+ }
+ }
+}
+
+/*
+ * EDITVERT TO BMVert
+ *
+ * Converts an editvert to
+ * a BMVert.
+ *
+*/
+
+static BMVert *editvert_to_BMVert(BMesh *bm, BMOperator *op, EditMesh *em, EditVert *eve)
+{
+ BMVert *v = NULL;
+
+ v = BM_Make_Vert(bm, eve->co, NULL);
+ VECCOPY(v->no, eve->no);
+
+ /*transfer flags*/
+ v->head.flag = eve->h ? BM_HIDDEN : 0;
+ if(eve->f & SELECT) BM_Select_Vert(bm, v, 1);
+ v->bweight = eve->bweight;
+
+ BMO_Insert_MapPointer(bm, op, "map", eve, v);
+
+ /*Copy Custom Data*/
+ CustomData_bmesh_copy_data(&em->vdata, &bm->vdata, eve->data, &v->head.data);
+
+ return v;
+}
+
+/*
+ * EDITEDGE TO BMEdge
+ *
+ * Converts an editedge to
+ * a BMEdge
+ *
+*/
+
+static void editedge_to_BMEdge_internal(BMesh *bm, BMOperator *op, EditMesh *em, BMEdge *e, EditEdge *eed)
+{
+ e->crease = eed->crease;
+ e->bweight = eed->bweight;
+
+ BM_Select(bm, e, eed->f & SELECT);
+ e->head.flag |= eed->seam ? BM_SEAM : 0;
+ e->head.flag |= eed->h & 1 ? BM_HIDDEN : 0;
+ e->head.flag |= eed->h & EM_FGON ? BM_FGON : 0;
+ e->head.flag |= eed->sharp ? BM_SHARP : 0;
+
+ CustomData_bmesh_copy_data(&em->edata, &bm->edata, eed->data, &e->head.data);
+
+ BMO_Insert_MapPointer(bm, op, "map", eed, e);
+}
+
+static BMEdge *editedge_to_BMEdge(BMesh *bm, BMOperator *op, EditMesh *em, EditEdge *eed)
+{
+ BMVert *v1 = NULL, *v2 = NULL;
+ BMEdge *e = NULL;
+
+ v1 = eed->v1->tmp.p;
+ v2 = eed->v2->tmp.p;
+
+ e = BM_Make_Edge(bm, v1, v2,NULL, 0);
+
+ editedge_to_BMEdge_internal(bm, op, em, e, eed);
+
+ return e;
+}
+/*
+ * EDITFACE TO BMFace
+ *
+ * Converts an editface to a BMFace.
+ * Note that this also convert per-face
+ * corner data as well.
+ *
+*/
+
+static BMFace *editface_to_BMFace(BMesh *bm, BMOperator *op, EditMesh *em, EditFace *efa, int numCol, int numTex)
+{
+ BMVert *v1 = NULL, *v2 = NULL;
+ BMFace *f = NULL;
+ BMEdge *edar[4];
+ int len;
+
+ edar[0] = BM_Make_Edge(bm, efa->v1->tmp.p, efa->v2->tmp.p, NULL, 1);
+ edar[1] = BM_Make_Edge(bm, efa->v2->tmp.p, efa->v3->tmp.p, NULL, 1);
+ if(efa->v4){
+ edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v4->tmp.p, NULL, 1);
+ edar[3] = BM_Make_Edge(bm, efa->v4->tmp.p, efa->v1->tmp.p, NULL, 1);
+ }else{
+ edar[2] = BM_Make_Edge(bm, efa->v3->tmp.p, efa->v1->tmp.p, NULL, 1);
+ }
+
+ editedge_to_BMEdge_internal(bm, op, em, edar[0], efa->e1);
+ editedge_to_BMEdge_internal(bm, op, em, edar[1], efa->e2);
+ editedge_to_BMEdge_internal(bm, op, em, edar[2], efa->e3);
+ if(efa->v4)
+ editedge_to_BMEdge_internal(bm, op, em, edar[3], efa->e4);
+
+
+ if(efa->e1->fgoni) edar[0]->head.flag |= BM_FGON;
+ if(efa->e2->fgoni) edar[1]->head.flag |= BM_FGON;
+ if(efa->e3->fgoni) edar[2]->head.flag |= BM_FGON;
+ if(efa->v4 && efa->e4->fgoni) edar[3]->head.flag |= BM_FGON;
+
+ if(efa->v4) len = 4;
+ else len = 3;
+
+ /*find v1 and v2*/
+ v1 = efa->v1->tmp.p;
+ v2 = efa->v2->tmp.p;
+
+ f = BM_Make_Ngon(bm, v1, v2, edar, len, 0);
+
+ VECCOPY(f->no, efa->n);
+
+ BMO_Insert_MapPointer(bm, op, "map", efa, f);
+
+ f->head.flag = 0;
+ f->mat_nr = efa->mat_nr;
+ if(efa->f & SELECT) BM_Select_Face(bm, f, 1);
+ if (efa->flag & ME_SMOOTH) f->head.flag |= BM_SMOOTH;
+ if(efa->h) f->head.flag |= BM_HIDDEN;
+
+ if (efa == em->act_face) f->head.flag |= BM_ACTIVE;
+
+ CustomData_bmesh_copy_data(&em->fdata, &bm->pdata, efa->data, &f->head.data);
+ editmesh_corners_to_loops(bm, &em->fdata, efa->data, f,numCol,numTex);
+
+ return f;
+}
+
+/*
+ * BMESH FGONCONVERT
+ *
+ * This function and its associated structures
+ * /helpers (fgonsort, sortfgon, fuse_fgon) are
+ * used to convert f-gons to bmesh n-gons. This
+ * is accomplished by sorting a list of fgon faces
+ * such that faces that are part of the same fgon
+ * are next to each other. These faces are then
+ * converted as is into bmesh faces and
+ * fused togather.
+ *
+ * Note that currently, there is no support for
+ * holes in faces in the bmesh structure, so
+ * f-gons with holes will only partially convert.
+ *
+*/
+
+typedef struct fgonsort {
+ unsigned long x;
+ struct EditFace *efa;
+ struct BMFace *f;
+ int done;
+}fgonsort;
+
+static int sortfgon(const void *v1, const void *v2)
+{
+ const struct fgonsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+static void fuse_fgon(BMesh *bm, BMFace *f)
+{
+ BMFace *sf;
+ BMLoop *l;
+ int done, act=0;
+
+ sf = f;
+ done = 0;
+ while(!done){
+ done = 1;
+ l = sf->loopbase;
+ do{
+ if(l->e->head.flag & BM_FGON) {
+ if (l->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
+ if (((BMLoop*)l->radial.next->data)->f->head.flag & BM_ACTIVE) act = BM_ACTIVE;
+
+ sf = BM_Join_Faces(bm,l->f, ((BMLoop*)l->radial.next->data)->f, l->e);
+ if (!sf) {
+ //tesselation error
+ break;
+ }
+
+ sf->head.flag |= act;
+ if(sf){
+ done = 0;
+ break;
+ } else { /*we have to get out of here...*/
+ return;
+ }
+ }
+ l = ((BMLoop*)(l->head.next));
+ }while(l != sf->loopbase);
+ }
+}
+
+static BM_fgonconvert(BMesh *bm, BMOperator *op, EditMesh *em, int numCol, int numTex)
+{
+ EditFace *efa;
+ BMFace *f;
+ BMIter iter;
+ struct fgonsort *sortblock, *sb, *sb1;
+ int a, b, amount=0;
+
+ /*
+ for (efa=em->faces.first; efa; efa=efa->next) {
+ f = editface_to_BMFace(bm, em, efa, numCol, numTex);
+ }
+
+ for (f=bm->polys.first; f; f=f->head.next) {
+ fuse_fgon(bm, f);
+ }
+
+ return;*/
+
+ EM_fgon_flags(em);
+
+ /*zero out efa->tmp, we store fgon index here*/
+ for(efa = em->faces.first; efa; efa = efa->next){
+ efa->tmp.l = 0;
+ amount++;
+ }
+ /*go through and give each editface an fgon index*/
+ for(efa = em->faces.first; efa; efa = efa->next){
+ if(efa->e1->fgoni) efa->tmp.l = efa->e1->fgoni;
+ else if(efa->e2->fgoni) efa->tmp.l = efa->e2->fgoni;
+ else if(efa->e3->fgoni) efa->tmp.l = efa->e3->fgoni;
+ else if(efa->e4 && efa->e4->fgoni) efa->tmp.l = efa->e4->fgoni;
+ }
+
+ sb= sortblock= MEM_mallocN(sizeof(fgonsort)* amount,"fgon sort block");
+
+ for(efa = em->faces.first; efa; efa=efa->next){
+ sb->x = efa->tmp.l;
+ sb->efa = efa;
+ sb->done = 0;
+ sb++;
+ }
+
+ qsort(sortblock, amount, sizeof(fgonsort), sortfgon);
+
+ sb = sortblock;
+ for(a=0; a<amount; a++, sb++) {
+ if(sb->x && sb->done == 0){
+ /*first pass: add in faces for this fgon*/
+ for(b=a, sb1 = sb; b<amount && sb1->x == sb->x; b++, sb1++){
+ efa = sb1->efa;
+ sb1->f = editface_to_BMFace(bm, op, em, efa, numCol, numTex);
+ sb1->done = 1;
+ }
+ /*fuse fgon*/
+ fuse_fgon(bm, sb->f);
+ }
+ }
+ MEM_freeN(sortblock);
+}
+
+/*
+ * TAG WIRE EDGES
+ *
+ * Flags editedges 'f1' member
+ * if the edge has no faces.
+ *
+*/
+
+static void tag_wire_edges(EditMesh *em){
+ EditFace *efa;
+ EditEdge *eed;
+ for(eed = em->edges.first; eed; eed = eed->next) eed->f1 = 1;
+ for(efa = em->faces.first; efa; efa = efa->next){
+ efa->e1->f1 = 0;
+ efa->e2->f1 = 0;
+ efa->e3->f1 = 0;
+ if(efa->e4) efa->e4->f1 = 0;
+ }
+}
+
+/*
+ * EDITMESH TO BMESH
+ *
+ * Function to convert an editmesh to a bmesh
+ * Currently all custom data as well as
+ * f-gons should be converted correctly.
+ *
+*/
+
+BMesh *editmesh_to_bmesh_intern(EditMesh *em, BMesh *bm, BMOperator *op) {
+ BMVert *v;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ BMEdge *e;
+ BMIter iter;
+ int allocsize[4] = {512,512,2048,512}, numTex, numCol;
+
+ /*make sure to update FGon flags*/
+ EM_fgon_flags(em);
+
+ /*copy custom data layout*/
+ CustomData_copy(&em->vdata, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->edata, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->fdata, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ /*copy face corner data*/
+ CustomData_to_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata, 0, 0);
+
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ /*copy over selection mode*/
+ bm->selectmode = 0;
+ if(em->selectmode & SCE_SELECT_VERTEX) bm->selectmode |= SCE_SELECT_VERTEX;
+ if(em->selectmode & SCE_SELECT_EDGE) bm->selectmode |= SCE_SELECT_EDGE;
+ if(em->selectmode & SCE_SELECT_FACE) bm->selectmode |= SCE_SELECT_FACE;
+
+
+ /*begin editloop*/
+ //BM_Begin_Edit(bm);
+
+ /*tag wire edges*/
+ tag_wire_edges(em);
+
+ /*add verts*/
+ for(eve = em->verts.first; eve; eve = eve->next){
+ v = editvert_to_BMVert(bm, op, em, eve);
+ eve->tmp.p = v;
+ }
+ /*convert f-gons*/
+ BM_fgonconvert(bm, op, em, numCol, numTex);
+
+ /*clean up any dangling fgon flags*/
+ for (e=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); e; e=BMIter_Step(&iter)){
+ e->head.flag &= ~BM_FGON;
+ }
+
+ /*do quads + triangles*/
+ for(efa = em->faces.first; efa; efa = efa->next){
+ if(!efa->tmp.l) editface_to_BMFace(bm, op, em, efa, numCol, numTex);
+ }
+
+ /*add wire edges*/
+ for(eed = em->edges.first; eed; eed = eed->next){
+ if(eed->f1) editedge_to_BMEdge(bm, op, em, eed);
+ }
+ //BM_end_edit(bm, BM_CALC_NORM);
+ return bm;
+}
+
+void edit2bmesh_exec(BMesh *bmesh, BMOperator *op)
+{
+ editmesh_to_bmesh_intern(BMO_Get_Pnt(op, "em"), bmesh, op);
+}
+
+BMesh *editmesh_to_bmesh(EditMesh *em)
+{
+ BMOperator conv;
+ BMesh *bm;
+ int allocsize[4] = {512,512,2048,512};
+
+ /*allocate a bmesh*/
+ bm = BM_Make_Mesh(allocsize);
+
+ BMO_Init_Op(&conv, "editmesh_to_bmesh");
+ BMO_Set_Pnt(&conv, "em", em);
+ BMO_Exec_Op(bm, &conv);
+ BMO_Finish_Op(bm, &conv);
+
+ return bm;
+}
+
+BMesh *init_editmesh_to_bmesh(EditMesh *em, BMOperator *op)
+{
+ BMesh *bm;
+ int allocsize[4] = {512,512,2048,512}, numTex, numCol;
+
+ /*allocate a bmesh*/
+ bm = BM_Make_Mesh(allocsize);
+
+ BMO_Init_Op(op, "editmesh_to_bmesh");
+ BMO_Set_Pnt(op, "em", em);
+
+ return bm;
+} \ No newline at end of file
diff --git a/source/blender/bmesh/intern/in-progress/BME_conversions.c b/source/blender/bmesh/intern/in-progress/BME_conversions.c
new file mode 100644
index 00000000000..d39bf689e76
--- /dev/null
+++ b/source/blender/bmesh/intern/in-progress/BME_conversions.c
@@ -0,0 +1,478 @@
+/**
+ * BME_conversions.c August 2008
+ *
+ * BM to Derived Mesh conversion functions.
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle, Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "bmesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+#include "bmesh_private.h"
+
+
+
+/*
+ * BMESH DERIVED MESH CONVERSION FUNCTIONS
+ *
+ * The functions in this file provides
+ * methods for converting to and from
+ * a bmesh.
+ *
+*/
+
+
+/*
+ * DMCORNERS TO LOOPS
+ *
+ * Function to convert derived mesh per-face
+ * corner data (uvs, vertex colors), to n-gon
+ * per-loop data.
+ *
+*/
+
+static void DMcorners_to_loops(BMMesh *bm, CustomData *facedata, int index, BMFace *f, int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+
+ for(i=0; i< numTex; i++){
+ texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
+
+ texpoly->tpage = texface[index].tpage;
+ texpoly->flag = texface[index].flag;
+ texpoly->transp = texface[index].transp;
+ texpoly->mode = texface[index].mode;
+ texpoly->tile = texface[index].tile;
+ texpoly->unwrap = texface[index].unwrap;
+
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
+ mloopuv->uv[0] = texface[index].uv[j][0];
+ mloopuv->uv[1] = texface[index].uv[j][1];
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+ }
+
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_layer_n(facedata, CD_MCOL, i);
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
+ mloopcol->r = mcol[(index*4)+j].r;
+ mloopcol->g = mcol[(index*4)+j].g;
+ mloopcol->b = mcol[(index*4)+j].b;
+ mloopcol->a = mcol[(index*4)+j].a;
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+ }
+}
+
+/*
+ * LOOPS TO DMCORNERS
+ *
+ * Function to convert n-gon per-loop data
+ * (uvs, vertex colors, ect)to derived mesh
+ * face corner data.
+ *
+*/
+
+static void loops_to_DMcorners(BMMesh *bm, CustomData *facedata, int index, BMFace *f,int numCol, int numTex){
+ int i, j;
+ BMLoop *l;
+ MTFace *texface;
+ MTexPoly *texpoly;
+ MCol *mcol;
+ MLoopCol *mloopcol;
+ MLoopUV *mloopuv;
+
+ for(i=0; i < numTex; i++){
+ texface = CustomData_get_layer_n(facedata, CD_MTFACE, i);
+ texpoly = CustomData_bmesh_get_n(&bm->pdata, f->data, CD_MTEXPOLY, i);
+
+ texface[index].tpage = texpoly->tpage;
+ texface[index].flag = texpoly->flag;
+ texface[index].transp = texpoly->transp;
+ texface[index].mode = texpoly->mode;
+ texface[index].tile = texpoly->tile;
+ texface[index].unwrap = texpoly->unwrap;
+
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPUV, i);
+ texface[index].uv[j][0] = mloopuv->uv[0];
+ texface[index].uv[j][1] = mloopuv->uv[1];
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+
+ }
+ for(i=0; i < numCol; i++){
+ mcol = CustomData_get_layer_n(facedata,CD_MCOL, i);
+ j = 0;
+ l = f->loopbase;
+ do{
+ mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->data, CD_MLOOPCOL, i);
+ mcol[(index*4) + j].r = mloopcol->r;
+ mcol[(index*4) + j].g = mloopcol->g;
+ mcol[(index*4) + j].b = mloopcol->b;
+ mcol[(index*4) + j].a = mloopcol->a;
+ j++;
+ l = l->next;
+ }while(l!=f->loopbase);
+ }
+}
+
+/*
+ * MVERT TO BMESHVERT
+ *
+ * Converts a MVert to a BMVert
+ *
+*/
+static BMVert *mvert_to_bmeshvert(BMMesh *bm, BMVert **vert_array, int index, MVert *mv, CustomData *data)
+{
+ BMVert *v = NULL;
+
+ v = bmesh_make_vert(bm, mv->co, NULL);
+ vert_array[index] = v;
+ if(mv->flag & SELECT) bmesh_set_flag(v, BMESH_SELECT);
+ v->bweight = mv->bweight/255.0f;
+ CustomData_to_bmesh_block(data, &bm->vdata, index, &v->data);
+
+ return v;
+}
+
+/*
+ * MEDGE TO BMESHEDGE
+ *
+ * Converts a MEdge to a BMEdge
+ *
+*/
+
+static BMEdge *medge_to_bmeshedge(BMMesh *bm, BMVert **vert_array, int index, MEdge *me, CustomData *data, Edge_Hash *edge_hash)
+{
+ BMVert *v1, *v2;
+ BMEdge *e = NULL;
+
+ v1 = vert_array[me->v1];
+ v2 = vert_array[me->v2];
+ e = bmesh_make_edge(bm, v1, v2, NULL, 0);
+ e->crease = me->crease/255.0f;
+ e->bweight = me->bweight/255.0f;
+ if(me->flag & 1) bmesh_set_flag(e, BMESH_SELECT);
+ if(me->flag & ME_SEAM) bmesh_set_flag(e, BMESH_SEAM);
+ BLI_edgehash_insert(edge_hash,me->v1,me->v2,e);
+ CustomData_to_bmesh_block(data, &bm->edata, index, &e->data);
+
+ return e;
+}
+
+/*
+ * MFACE TO BMESHFACE
+ *
+ * Converts a MFace to a BMFace.
+ * Note that this will fail on eekadoodle
+ * faces.
+ *
+*/
+
+static BMFace *mface_to_bmeshface(BMMesh *bm, BMVert **vert_array, int index, MFace *mf, CustomData *data, Edge_Hash *edge_hash)
+{
+ BMVert *v1, *v2;
+ BMEdge *edar[4];
+ BMFace *f = NULL;
+ int len;
+
+ if(mf->v4) len = 4;
+ else len = 3;
+
+ edar[0] = BLI_edgehash_lookup(edge_hash,mf->v1,mf->v2);
+ edar[1] = BLI_edgehash_lookup(edge_hash,mf->v2,mf->v3);
+ if(len == 4){
+ edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v4);
+ edar[3] = BLI_edgehash_lookup(edge_hash,mf->v4,mf->v1);
+ }
+ else
+ edar[2] = BLI_edgehash_lookup(edge_hash,mf->v3,mf->v1);
+
+ /*find v1 and v2*/
+ v1 = vert_array[mf->v1];
+ v2 = vert_array[mf->v2];
+
+ f = bmesh_make_ngon(bm, v1, v2, edar, len, 0);
+ f->mat_nr = mf->mat_nr;
+ if(mf->flag & 1) bmesh_set_flag(f, BMESH_SELECT);
+ if(mf->flag & ME_HIDE) bmesh_set_flag(f, BMESH_HIDDEN);
+ CustomData_to_bmesh_block(data, &bm->pdata, index, &f->data);
+
+ return f;
+}
+
+/*
+ * DERIVEDMESH TO BMESH
+ *
+ * Converts a derived mesh to a bmesh.
+ *
+*/
+
+BMMesh *derivedmesh_to_bmesh(DerivedMesh *dm)
+{
+
+ BMMesh *bm;
+ BMVert **vert_array;
+ BMFace *f=NULL;
+
+ MVert *mvert, *mv;
+ MEdge *medge, *me;
+ MFace *mface, *mf;
+
+ int totface,totedge,totvert,i,len, numTex, numCol;
+ int allocsize[4] = {512,512,2048,512};
+
+ EdgeHash *edge_hash = BLI_edgehash_new();
+
+ /*allocate a new bmesh*/
+ bm = bmesh_make_mesh(allocsize);
+
+ /*copy custom data layout*/
+ CustomData_copy(&dm->vertData, &bm->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&dm->edgeData, &bm->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&dm->faceData, &bm->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ /*copy face corner data*/
+ CustomData_to_bmeshpoly(&dm->faceData, &bm->pdata, &bm->ldata);
+ /*initialize memory pools*/
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ /*needed later*/
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+ mvert = dm->getVertArray(dm);
+ medge = dm->getEdgeArray(dm);
+ mface = dm->getFaceArray(dm);
+
+ vert_array = MEM_mallocN(sizeof(BMVert *)* totvert,"derivedmesh to bmesh vertex pointer array");
+
+ bmesh_begin_edit(bm);
+ /*add verts*/
+ for(i=0, mv = mvert; i < totvert; i++, mv++)
+ mvert_to_bmeshvert(bm, vert_array, i, mv, &dm->vertData);
+
+ /*add edges*/
+ for(i=0, me = medge; i < totedge; i++, me++)
+ medge_to_bmeshedge(bm, vert_array, i, me, &dm->edgeData, edge_hash);
+
+ /*add faces.*/
+ for(i=0, mf = mface; i < totface; i++, mf++){
+ f = mface_to_bmeshface(bm, vert_array, mf, &dm->faceData, edge_hash);
+ if(f) DMcorners_to_loops(bm, &dm->faceData, i, f, numCol, numTex);
+ }
+
+ bmesh_end__edit(bm);
+ BLI_edgehash_free(edge_hash, NULL);
+ MEM_freeN(vert_array);
+ return bm;
+}
+
+static void bmeshvert_to_mvert(BMMesh *bm, BMVert *v, MVert *mv, int index, CustomData *data)
+{
+ VECCOPY(mv->co,v->co);
+ if(bmesh_test_flag(v, BMESH_SELECT)) mv->flag |= 1;
+ if(bmesh_test_flag(v, BMESH_HIDDEN)) mv->flag |= ME_HIDE;
+ mv->bweight = (char)(255.0*v1->bweight);
+ CustomData_from_bmesh_block(&bm->vdata, data, &v1->data, index);
+}
+
+static int bmeshedge_to_medge(BMMesh *bm, BMEdge *e, MEdge *me, int index, CustomData *data)
+{
+ if(e->head.eflag2){
+ if(e->v1->head.eflag1 < e->v2->head.eflag1){
+ me->v1 = e->v1->head.eflag1;
+ me->v2 = e->v2->head.eflag1;
+ }
+ else{
+ me->v1 = e->v2->head.eflag1;
+ me->v2 = e->v1->eflag1;
+ }
+
+ me->crease = (char)(255.0*e->crease);
+ me->bweight = (char)(255.0*e->bweight);
+ if(bmesh_test_flag(e, BMESH_SELECT)) me->flag |= 1;
+ if(bmesh_test_flag(e, BMESH_HIDDEN)) me->flag |= ME_HIDE;
+ CustomData_from_bmesh_block(&bm->edata, data, &e->data, index);
+ return 1;
+ }
+ return 0;
+}
+
+static int bmeshface_to_mface(BMMesh *bm, BMFace *f, MFace *mf, int index, CustomData *data)
+{
+ if(f->len==3 || f->len==4){
+ mf->v1 = f->loopbase->v->head.eflag1;
+ mf->v2 = f->loopbase->next->v->head.eflag1;
+ mf->v3 = f->loopbase->next->next->v->head.eflag1;
+ if(len == 4){
+ mf->v4 = f->loopbase->prev->v->head.eflag1;
+ }
+ /* test and rotate indexes if necessary so that verts 3 and 4 aren't index 0 */
+ if(mf->v3 == 0 || (f->len == 4 && mf->v4 == 0)){
+ test_index_face(mf, NULL, index, f->len);
+ }
+ mf->mat_nr = (unsigned char)f->mat_nr;
+ if(bmesh_test_flag(f, BMESH_SELECT)) mf->flag |= 1;
+ if(bmesh_test_flag(f, BMESH_HIDDEN)) mf->flag |= ME_HIDE;
+ CustomData_from_bmesh_block(&bm->pdata, data, &f->data, index);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * BMESH TO DERIVEDMESH
+ *
+ * Converts a bmesh to a derived mesh.
+ *
+*/
+
+DerivedMesh *bmesh_to_derivedmesh(BMMesh *bm, DerivedMesh *dm)
+{
+ MFace *mface = NULL, *mf = NULL;
+ MEdge *medge = NULL, *me = NULL;
+ MVert *mvert = NULL, *mv = NULL;
+ DerivedMesh *result = NULL;
+
+ BMVert *v=NULL;
+ BMEdge *e=NULL, *oe=NULL;
+ BMFace *f=NULL;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ int totface = 0,totedge = 0,totvert = 0,i = 0, numTex, numCol;
+
+ EdgeHash *edge_hash = BLI_edgehash_new();
+
+ /*get element counts*/
+ totvert = bmesh_count_element(bm, BMESH_VERT);
+
+ /*store element indices. Note that the abuse of eflag here should NOT be duplicated!*/
+ for(i=0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++)
+ v->head.eflag1 = i;
+
+ /*we cannot have double edges in a derived mesh!*/
+ for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
+ oe = BLI_edgehash_lookup(edge_hash,e->v1->head.eflag1, e->v2->head.eflag1);
+ if(!oe){
+ totedge++;
+ BLI_edgehash_insert(edge_hash,e->v1->head.eflag1,e->v2->head.eflag1,e);
+ e->head.eflag2 = 1;
+ }
+ else{
+ e->head.eflag2 = 0;
+ }
+ }
+
+ /*count quads and tris*/
+ for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
+ if(f->len == 3 || f->len == 4) totface++;
+ }
+
+ /*Allocate derivedmesh and copy custom data*/
+ result = CDDM_from_template(dm,totvert,totedge,totface);
+ CustomData_merge(&bm->vdata, &result->vertData, CD_MASK_BMESH, CD_CALLOC, totvert);
+ CustomData_merge(&bm->edata, &result->edgeData, CD_MASK_BMESH, CD_CALLOC, totedge);
+ CustomData_merge(&bm->pdata, &result->faceData, CD_MASK_BMESH, CD_CALLOC, totface);
+ CustomData_from_bmeshpoly(&result->faceData, &bm->pdata, &bm->ldata,totface);
+ numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
+ numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
+
+ /*Make Verts*/
+ mvert = CDDM_get_verts(result);
+ for(i = 0, v = bmeshIterator_init(verts, BM_VERTS, bm, 0); v; v = bmeshIterator_step(verts), i++, mv++){
+ bmeshvert_to_mvert(bm,v,mv,i,&result->vertData);
+ }
+
+ /*Make Edges*/
+ medge = CDDM_get_edges(result);
+ i=0;
+ for(e = bmeshIterator_init(edges, BM_EDGES, bm, 0); e; e = bmeshIterator_step(edges)){
+ me = &medge[i];
+ if(bmeshedge_to_medge(bm, e, me, i, &result->edgeData){
+ me++;
+ i++;
+ }
+ }
+ /*Make Faces*/
+ if(totface){
+ mface = CDDM_get_faces(result);
+ i=0;
+ for(f = bmeshIterator_init(faces, BM_FACES, bm, 0); f; f = bmeshIterator_step(faces)){
+ mf = &mface[i];
+ if(bmeshface_to_mface(bm, f, mf, i, &result->faceData)){
+ loops_to_DMcorners(bm, &result->faceData, i, f, numCol, numTex);
+ i++;
+ }
+ }
+ }
+ BLI_edgehash_free(edge_hash, NULL);
+ return result;
+}
diff --git a/source/blender/bmesh/operators/bmesh_dupeops.c b/source/blender/bmesh/operators/bmesh_dupeops.c
new file mode 100644
index 00000000000..b5c327bc24c
--- /dev/null
+++ b/source/blender/bmesh/operators/bmesh_dupeops.c
@@ -0,0 +1,570 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "bmesh.h"
+#include "bmesh_operators_private.h"
+
+/*local flag defines*/
+#define DUPE_INPUT 1 /*input from operator*/
+#define DUPE_NEW 2
+#define DUPE_DONE 4
+#define DUPE_MAPPED 8
+
+/*
+ * COPY VERTEX
+ *
+ * Copy an existing vertex from one bmesh to another.
+ *
+*/
+static BMVert *copy_vertex(BMesh *source_mesh, BMVert *source_vertex, BMesh *target_mesh, GHash *vhash)
+{
+ BMVert *target_vertex = NULL;
+
+ /*Create a new vertex*/
+ target_vertex = BM_Make_Vert(target_mesh, source_vertex->co, NULL);
+
+ /*Insert new vertex into the vert hash*/
+ BLI_ghash_insert(vhash, source_vertex, target_vertex);
+
+ /*Copy attributes*/
+ BM_Copy_Attributes(source_mesh, target_mesh, source_vertex, target_vertex);
+
+ /*Set internal op flags*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_vertex, DUPE_NEW);
+
+ return target_vertex;
+}
+
+/*
+ * COPY EDGE
+ *
+ * Copy an existing edge from one bmesh to another.
+ *
+*/
+static BMEdge *copy_edge(BMOperator *op, BMesh *source_mesh,
+ BMEdge *source_edge, BMesh *target_mesh,
+ GHash *vhash, GHash *ehash)
+{
+ BMEdge *target_edge = NULL;
+ BMVert *target_vert1, *target_vert2;
+ BMFace *face;
+ BMIter fiter;
+ int rlen;
+
+ /*see if any of the neighboring faces are
+ not being duplicated. in that case,
+ add it to the new/old map.*/
+ rlen = 0;
+ for (face=BMIter_New(&fiter,source_mesh, BM_FACES_OF_EDGE,source_edge);
+ face; face=BMIter_Step(&fiter)) {
+ if (BMO_TestFlag(source_mesh, face, DUPE_INPUT)) {
+ rlen++;
+ }
+ }
+
+ /*Lookup v1 and v2*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
+ target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
+
+ /*Create a new edge*/
+ target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0);
+
+ /*add to new/old edge map if necassary*/
+ if (rlen < 2) {
+ /*not sure what non-manifold cases of greater then three
+ radial should do.*/
+ BMO_Insert_MapPointer(source_mesh,op, "boundarymap",
+ source_edge, target_edge);
+ }
+
+ /*Insert new edge into the edge hash*/
+ BLI_ghash_insert(ehash, source_edge, target_edge);
+
+ /*Copy attributes*/
+ BM_Copy_Attributes(source_mesh, target_mesh, source_edge, target_edge);
+
+ /*Set internal op flags*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_edge, DUPE_NEW);
+
+ return target_edge;
+}
+
+/*
+ * COPY FACE
+ *
+ * Copy an existing face from one bmesh to another.
+ *
+*/
+static BMFace *copy_face(BMOperator *op, BMesh *source_mesh,
+ BMFace *source_face, BMesh *target_mesh,
+ BMEdge **edar, GHash *vhash, GHash *ehash)
+{
+ BMVert *target_vert1, *target_vert2;
+ BMLoop *source_loop, *target_loop;
+ BMFace *target_face = NULL;
+ BMIter iter, iter2;
+ int i;
+
+ /*lookup the first and second verts*/
+ target_vert1 = BLI_ghash_lookup(vhash, BMIter_New(&iter, source_mesh, BM_VERTS_OF_FACE, source_face));
+ target_vert2 = BLI_ghash_lookup(vhash, BMIter_Step(&iter));
+
+ /*lookup edges*/
+ for (i=0,source_loop=BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face);
+ source_loop; source_loop=BMIter_Step(&iter), i++) {
+ edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
+ }
+
+ /*create new face*/
+ target_face = BM_Make_Ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0);
+ BMO_Insert_MapPointer(source_mesh, op,
+ "facemap", source_face, target_face);
+ BMO_Insert_MapPointer(source_mesh, op,
+ "facemap", target_face, source_face);
+
+ BM_Copy_Attributes(source_mesh, target_mesh, source_face, target_face);
+
+ /*mark the face for output*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_face, DUPE_NEW);
+
+ /*copy per-loop custom data*/
+ for (i=0,source_loop=BMIter_New(&iter, source_mesh, BM_LOOPS_OF_FACE, source_face),
+ target_loop=BMIter_New(&iter2, target_mesh, BM_LOOPS_OF_FACE, target_face);
+ source_loop && target_loop; source_loop=BMIter_Step(&iter), target_loop=BMIter_Step(&iter2),
+ i++) {
+ BM_Copy_Attributes(source_mesh, target_mesh, source_loop, target_loop);
+ }
+
+
+ return target_face;
+}
+ /*
+ * COPY MESH
+ *
+ * Internal Copy function.
+*/
+
+static void copy_mesh(BMOperator *op, BMesh *source, BMesh *target)
+{
+
+ BMVert *v = NULL, *v2;
+ BMEdge *e = NULL, **edar = NULL;
+ BMLoop *l = NULL;
+ BMFace *f = NULL;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ GHash *vhash;
+ GHash *ehash;
+
+ int maxlength = 0;
+
+ /*initialize pointer hashes*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ /*initialize edge pointer array*/
+ for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f = BMIter_Step(&faces)){
+ if(f->len > maxlength) maxlength = f->len;
+ }
+ edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array");
+
+ for(v = BMIter_New(&verts, source, BM_VERTS_OF_MESH, source); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE))){
+ BMIter iter;
+ int iso = 1;
+
+ v2 = copy_vertex(source, v, target, vhash);
+
+ BM_ITER(f, &iter, source, BM_FACES_OF_VERT, v) {
+ if (BMO_TestFlag(source, f, DUPE_INPUT)) {
+ iso = 0;
+ break;
+ }
+ }
+
+ if (iso) {
+ BM_ITER(e, &iter, source, BM_EDGES_OF_VERT, v) {
+ if (BMO_TestFlag(source, e, DUPE_INPUT)) {
+ iso = 0;
+ break;
+ }
+ }
+ }
+
+ if (iso)
+ BMO_Insert_MapPointer(source, op, "isovertmap", v, v2);
+
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*now we dupe all the edges*/
+ for(e = BMIter_New(&edges, source, BM_EDGES_OF_MESH, source); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE))){
+ /*make sure that verts are copied*/
+ if(!BMO_TestFlag(source, (BMHeader*)e->v1, DUPE_DONE)) {
+ copy_vertex(source, e->v1, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v1, DUPE_DONE);
+ }
+ if(!BMO_TestFlag(source, (BMHeader*)e->v2, DUPE_DONE)) {
+ copy_vertex(source, e->v2, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v2, DUPE_DONE);
+ }
+ /*now copy the actual edge*/
+ copy_edge(op, source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+
+ /*first we dupe all flagged faces and their elements from source*/
+ for(f = BMIter_New(&faces, source, BM_FACES_OF_MESH, source); f; f= BMIter_Step(&faces)){
+ if(BMO_TestFlag(source, (BMHeader*)f, DUPE_INPUT)){
+ /*vertex pass*/
+ for(v = BMIter_New(&verts, source, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts)){
+ if(!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE)){
+ copy_vertex(source,v, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*edge pass*/
+ for(e = BMIter_New(&edges, source, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges)){
+ if(!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE)){
+ copy_edge(op, source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+ copy_face(op, source, f, target, edar, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)f, DUPE_DONE);
+ }
+ }
+
+ /*free pointer hashes*/
+ BLI_ghash_free(vhash, NULL, NULL);
+ BLI_ghash_free(ehash, NULL, NULL);
+
+ /*free edge pointer array*/
+ if(edar)
+ MEM_freeN(edar);
+}
+
+/*
+BMesh *bmesh_make_mesh_from_mesh(BMesh *bm, int allocsize[4])
+{
+ BMesh *target = NULL;
+ target = bmesh_make_mesh(allocsize);
+
+
+ CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+
+ CustomData_bmesh_init_pool(&target->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&target->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&target->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&target->pdata, allocsize[3]);
+
+ bmesh_begin_edit(bm);
+ bmesh_begin_edit(target);
+
+ bmesh_copy_mesh(bm, target, 0);
+
+ bmesh_end_edit(bm);
+ bmesh_end_edit(target);
+
+ return target;
+
+}
+*/
+
+/*
+ * Duplicate Operator
+ *
+ * Duplicates verts, edges and faces of a mesh.
+ *
+ * INPUT SLOTS:
+ *
+ * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be duplicated
+ * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be duplicated
+ * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be duplicated
+ *
+ * OUTPUT SLOTS:
+ *
+ * BMOP_DUPE_VORIGINAL: Buffer containing pointers to the original mesh vertices
+ * BMOP_DUPE_EORIGINAL: Buffer containing pointers to the original mesh edges
+ * BMOP_DUPE_FORIGINAL: Buffer containing pointers to the original mesh faces
+ * BMOP_DUPE_VNEW: Buffer containing pointers to the new mesh vertices
+ * BMOP_DUPE_ENEW: Buffer containing pointers to the new mesh edges
+ * BMOP_DUPE_FNEW: Buffer containing pointers to the new mesh faces
+ *
+*/
+
+void dupeop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator *dupeop = op;
+
+ /*flag input*/
+ BMO_Flag_Buffer(bm, dupeop, "geom", DUPE_INPUT);
+ /*use the internal copy function*/
+ copy_mesh(dupeop, bm, bm);
+
+ /*Output*/
+ /*First copy the input buffers to output buffers - original data*/
+ BMO_CopySlot(dupeop, dupeop, "geom", "origout");
+
+ /*Now alloc the new output buffers*/
+ BMO_Flag_To_Slot(bm, dupeop, "newout", DUPE_NEW, BM_ALL);
+}
+
+/*executes the duplicate operation, feeding elements of
+ type flag etypeflag and header flag flag to it. note,
+ to get more useful information (such as the mapping from
+ original to new elements) you should run the dupe op manually.*/
+void BMOP_DupeFromFlag(BMesh *bm, int etypeflag, int flag)
+{
+ BMOperator dupeop;
+
+ BMO_Init_Op(&dupeop, "dupe");
+ BMO_HeaderFlag_To_Slot(bm, &dupeop, "geom", flag, etypeflag);
+
+ BMO_Exec_Op(bm, &dupeop);
+ BMO_Finish_Op(bm, &dupeop);
+}
+
+/*
+ * Split Operator
+ *
+ * Duplicates verts, edges and faces of a mesh but also deletes the originals.
+ *
+ * INPUT SLOTS:
+ *
+ * BMOP_DUPE_VINPUT: Buffer containing pointers to mesh vertices to be split
+ * BMOP_DUPE_EINPUT: Buffer containing pointers to mesh edges to be split
+ * BMOP_DUPE_FINPUT: Buffer containing pointers to mesh faces to be split
+ *
+ * OUTPUT SLOTS:
+ *
+ * BMOP_DUPE_VOUTPUT: Buffer containing pointers to the split mesh vertices
+ * BMOP_DUPE_EOUTPUT: Buffer containing pointers to the split mesh edges
+ * BMOP_DUPE_FOUTPUT: Buffer containing pointers to the split mesh faces
+ *
+*/
+
+#define SPLIT_INPUT 1
+void splitop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator *splitop = op;
+ BMOperator dupeop;
+ BMOperator delop;
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BMIter iter, iter2;
+ int found;
+
+ /*initialize our sub-operators*/
+ BMO_Init_Op(&dupeop, "dupe");
+ BMO_Init_Op(&delop, "del");
+
+ BMO_CopySlot(splitop, &dupeop, "geom", "geom");
+ BMO_Exec_Op(bm, &dupeop);
+
+ BMO_Flag_Buffer(bm, splitop, "geom", SPLIT_INPUT);
+
+ /*make sure to remove edges and verts we don't need.*/
+ for (e= BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);e;e=BMIter_Step(&iter)) {
+ found = 0;
+ f = BMIter_New(&iter2, bm, BM_FACES_OF_EDGE, e);
+ for (; f; f=BMIter_Step(&iter2)) {
+ if (!BMO_TestFlag(bm, f, SPLIT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) BMO_SetFlag(bm, e, SPLIT_INPUT);
+ }
+
+ for (v= BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);v;v=BMIter_Step(&iter)) {
+ found = 0;
+ e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, v);
+ for (; e; e=BMIter_Step(&iter2)) {
+ if (!BMO_TestFlag(bm, e, SPLIT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) BMO_SetFlag(bm, v, SPLIT_INPUT);
+
+ }
+
+ /*connect outputs of dupe to delete, exluding keep geometry*/
+ BMO_Set_Int(&delop, "context", DEL_FACES);
+ BMO_Flag_To_Slot(bm, &delop, "geom", SPLIT_INPUT, BM_ALL);
+
+ BMO_Exec_Op(bm, &delop);
+
+ /*now we make our outputs by copying the dupe outputs*/
+ BMO_CopySlot(&dupeop, splitop, "newout", "geom");
+ BMO_CopySlot(&dupeop, splitop, "boundarymap",
+ "boundarymap");
+ BMO_CopySlot(&dupeop, splitop, "isovertmap",
+ "isovertmap");
+
+ /*cleanup*/
+ BMO_Finish_Op(bm, &delop);
+ BMO_Finish_Op(bm, &dupeop);
+}
+
+#define DEL_INPUT 1
+#define DEL_WIREVERT 2
+
+static void delete_verts(BMesh *bm);
+static void delete_context(BMesh *bm, int type);
+
+void delop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator *delop = op;
+
+ /*Mark Buffers*/
+ BMO_Flag_Buffer(bm, delop, "geom", DEL_INPUT);
+
+ delete_context(bm, BMO_Get_Int(op, "context"));
+}
+
+static void delete_verts(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMLoop *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT)) {
+ /*Visit edges*/
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_VERT, v); e; e = BMIter_Step(&edges))
+ BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
+ /*Visit faces*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_VERT, v); f; f = BMIter_Step(&faces))
+ BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
+ }
+ }
+
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+}
+
+static void delete_edges(BMesh *bm){
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter edges;
+ BMIter faces;
+
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)) {
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_EDGE, e); f; f = BMIter_Step(&faces)){
+ BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
+ }
+ }
+ }
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+}
+
+/*you need to make remove tagged verts/edges/faces
+ api functions that take a filter callback.....
+ and this new filter type will be for opstack flags.
+ This is because the BM_remove_taggedXXX functions bypass iterator API.
+ -Ops dont care about 'UI' considerations like selection state, hide state, ect. If you want to work on unhidden selections for instance,
+ copy output from a 'select context' operator to another operator....
+*/
+
+/*Break this into smaller functions*/
+
+static void delete_context(BMesh *bm, int type){
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ if(type == DEL_VERTS) delete_verts(bm);
+ else if(type == DEL_EDGES){
+ /*flush down to verts*/
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(bm, (BMHeader*)e, DEL_INPUT)){
+ BMO_SetFlag(bm, (BMHeader*)(e->v1), DEL_INPUT);
+ BMO_SetFlag(bm, (BMHeader*)(e->v2), DEL_INPUT);
+ }
+ }
+ delete_edges(bm);
+ /*remove loose vertices*/
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(bm, (BMHeader*)v, DEL_INPUT) && (!(v->edge)))
+ BMO_SetFlag(bm, (BMHeader*)v, DEL_WIREVERT);
+ }
+ BM_remove_tagged_verts(bm, DEL_WIREVERT);
+ }
+ else if(type == DEL_EDGESFACES) delete_edges(bm);
+ else if(type == DEL_ONLYFACES) BM_remove_tagged_faces(bm, DEL_INPUT);
+ else if (type == DEL_ONLYTAGGED) {
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+ } else if(type == DEL_FACES){
+ /*go through and mark all edges and all verts of all faces for delete*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ if(BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e = BMIter_Step(&edges))
+ BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v = BMIter_Step(&verts))
+ BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT);
+ }
+ }
+ /*now go through and mark all remaining faces all edges for keeping.*/
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces)){
+ if(!BMO_TestFlag(bm, (BMHeader*)f, DEL_INPUT)){
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_FACE, f); e; e= BMIter_Step(&edges))
+ BMO_ClearFlag(bm, (BMHeader*)e, DEL_INPUT);
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_FACE, f); v; v= BMIter_Step(&verts))
+ BMO_ClearFlag(bm, (BMHeader*)v, DEL_INPUT);
+ }
+ }
+ /*now delete marked faces*/
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ /*delete marked edges*/
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ /*remove loose vertices*/
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+ }
+ /*does this option even belong in here?*/
+ else if(type == DEL_ALL){
+ for(f = BMIter_New(&faces, bm, BM_FACES_OF_MESH, bm); f; f = BMIter_Step(&faces))
+ BMO_SetFlag(bm, (BMHeader*)f, DEL_INPUT);
+ for(e = BMIter_New(&edges, bm, BM_EDGES_OF_MESH, bm); e; e = BMIter_Step(&edges))
+ BMO_SetFlag(bm, (BMHeader*)e, DEL_INPUT);
+ for(v = BMIter_New(&verts, bm, BM_VERTS_OF_MESH, bm); v; v = BMIter_Step(&verts))
+ BMO_SetFlag(bm, (BMHeader*)v, DEL_INPUT);
+
+ BM_remove_tagged_faces(bm, DEL_INPUT);
+ BM_remove_tagged_edges(bm, DEL_INPUT);
+ BM_remove_tagged_verts(bm, DEL_INPUT);
+ }
+} \ No newline at end of file
diff --git a/source/blender/bmesh/operators/connectops.c b/source/blender/bmesh/operators/connectops.c
new file mode 100644
index 00000000000..a8f5899fd65
--- /dev/null
+++ b/source/blender/bmesh/operators/connectops.c
@@ -0,0 +1,126 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "bmesh_private.h"
+#include "BLI_arithb.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define VERT_INPUT 1
+#define EDGE_OUT 1
+#define FACE_NEW 2
+
+void connectverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter iter, liter;
+ BMFace *f, *nf;
+ BMLoop **loops = NULL, *lastl = NULL;
+ V_DECLARE(loops);
+ BMLoop *l, *nl;
+ BMVert *v1, *v2, **verts = NULL;
+ V_DECLARE(verts);
+ int i;
+
+ BMO_Flag_Buffer(bm, op, "verts", VERT_INPUT);
+
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)){
+ V_RESET(loops);
+ V_RESET(verts);
+
+ if (BMO_TestFlag(bm, f, FACE_NEW)) continue;
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ v1 = v2 = NULL;
+ lastl = NULL;
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BMO_TestFlag(bm, l->v, VERT_INPUT)) {
+ if (!lastl) {
+ lastl = l;
+ continue;
+ }
+
+ if (lastl != l->head.prev && lastl !=
+ l->head.next)
+ {
+ V_GROW(loops);
+ loops[V_COUNT(loops)-1] = lastl;
+
+ V_GROW(loops);
+ loops[V_COUNT(loops)-1] = l;
+
+ }
+ lastl = l;
+ }
+ }
+
+ if (V_COUNT(loops) == 0) continue;
+
+ if (V_COUNT(loops) > 2) {
+ V_GROW(loops);
+ loops[V_COUNT(loops)-1] = loops[V_COUNT(loops)-2];
+
+ V_GROW(loops);
+ loops[V_COUNT(loops)-1] = loops[0];
+ }
+
+ BM_LegalSplits(bm, f, loops, V_COUNT(loops)/2);
+
+ for (i=0; i<V_COUNT(loops)/2; i++) {
+ if (loops[i*2]==NULL) continue;
+
+ V_GROW(verts);
+ verts[V_COUNT(verts)-1] = loops[i*2]->v;
+
+ V_GROW(verts);
+ verts[V_COUNT(verts)-1] = loops[i*2+1]->v;
+ }
+
+ for (i=0; i<V_COUNT(verts)/2; i++) {
+ nf = BM_Split_Face(bm, f, verts[i*2],
+ verts[i*2+1], &nl, NULL);
+ f = nf;
+
+ if (!nl || !nf) {
+ BMO_RaiseError(bm, op,
+ BMERR_CONNECTVERT_FAILED, NULL);
+ V_FREE(loops);
+ return;;;
+ }
+ BMO_SetFlag(bm, nf, FACE_NEW);
+ BMO_SetFlag(bm, nl->e, EDGE_OUT);
+ }
+ }
+
+ BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_OUT, BM_EDGE);
+
+ V_FREE(loops);
+ V_FREE(verts);
+}
+
+int BM_ConnectVerts(EditMesh *em, int flag)
+{
+ EditMesh *em2;
+ BMesh *bm = editmesh_to_bmesh(em);
+ BMOperator op;
+
+ BMO_Init_Op(&op, "connectverts");
+ BMO_HeaderFlag_To_Slot(bm, &op, "verts", flag, BM_VERT);
+ BMO_Exec_Op(bm, &op);
+ BMO_Finish_Op(bm, &op);
+
+ if (BMO_GetSlot(&op, "edgeout")->len > 0 &&
+ BMO_GetError(bm, NULL, NULL)==0)
+ {
+ em2 = bmesh_to_editmesh(bm);
+ set_editMesh(em, em2);
+ MEM_freeN(em2);
+
+ return 1;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/source/blender/bmesh/operators/createops.c b/source/blender/bmesh/operators/createops.c
new file mode 100644
index 00000000000..29ec08868ec
--- /dev/null
+++ b/source/blender/bmesh/operators/createops.c
@@ -0,0 +1,156 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "bmesh.h"
+#include "bmesh_operators_private.h"
+
+#define ELE_NEW 1
+#define ELE_OUT 2
+
+void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op)
+{
+ /*unimplemented, need to think on how to do this. probably are graph
+ theory stuff that could help with this problem.*/
+}
+
+/* evaluate if entire quad is a proper convex quad */
+static int convex(float *v1, float *v2, float *v3, float *v4)
+{
+ float nor[3], nor1[3], nor2[3], vec[4][2];
+
+ /* define projection, do both trias apart, quad is undefined! */
+ CalcNormFloat(v1, v2, v3, nor1);
+ CalcNormFloat(v1, v3, v4, nor2);
+ 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( IsectLL2Df(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1;
+ return 0;
+}
+
+/*this is essentially new fkey*/
+void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator op2;
+ BMOIter oiter;
+ BMIter iter, liter;
+ BMHeader *h;
+ BMVert *v, *verts[4];
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+ int totv=0, tote=0, totf=0, amount;
+
+ /*count number of each element type we were passed*/
+ BMO_ITER(h, &oiter, bm, op, "geom", BM_VERT|BM_EDGE|BM_FACE) {
+ switch (h->type) {
+ case BM_VERT: totv++; break;
+ case BM_EDGE: tote++; break;
+ case BM_FACE: totf++; break;
+ }
+
+ BMO_SetFlag(bm, h, ELE_NEW);
+ }
+
+ /*first call dissolve faces*/
+ BMO_InitOpf(bm, &op2, "dissolvefaces faces=%ff", ELE_NEW);
+ BMO_Exec_Op(bm, &op2);
+ BMO_ITER(f, &oiter, bm, &op2, "regionout", BM_FACE) {
+ BMO_SetFlag(bm, f, ELE_OUT);
+
+ /*unflag verts associated with dissolved faces*/
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BMO_ClearFlag(bm, l->v, ELE_NEW);
+ }
+ }
+ BMO_Finish_Op(bm, &op2);
+
+ /*then call edgenet create, which may still be unimplemented, heh*/
+ BMO_InitOpf(bm, &op2, "edgenet_fill edges=%fe", ELE_NEW);
+ BMO_Exec_Op(bm, &op2);
+ BMO_ITER(f, &oiter, bm, &op2, "faceout", BM_FACE) {
+ BMO_SetFlag(bm, f, ELE_OUT);
+
+ /*unflag verts associated with the output faces*/
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ BMO_ClearFlag(bm, l->v, ELE_NEW);
+ }
+ }
+ BMO_Finish_Op(bm, &op2);
+
+ /*now, count how many verts we have*/
+ amount = 0;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, v, ELE_NEW)) {
+ verts[amount] = v;
+ amount++;
+
+ if (amount > 4) break;
+ }
+ }
+
+ if (amount == 2) {
+ /*create edge*/
+ e = BM_Make_Edge(bm, verts[0], verts[1], NULL, 1);
+ BMO_SetFlag(bm, e, ELE_OUT);
+ } else if (amount == 3) {
+ /*create triangle*/
+ BM_Make_QuadTri(bm, verts[0], verts[1], verts[2], NULL, NULL, 1);
+ } else if (amount == 4) {
+ f = NULL;
+
+ /* the order of vertices can be anything, 6 cases to check */
+ if( convex(verts[0]->co, verts[1]->co, verts[2]->co, verts[3]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[2], verts[3], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[2]->co, verts[3]->co, verts[1]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[3], verts[1], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[2]->co, verts[1]->co, verts[3]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[2], verts[1], verts[3], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[1]->co, verts[3]->co, verts[2]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[1], verts[3], verts[2], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[3]->co, verts[2]->co, verts[1]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[2], verts[1], NULL, 1);
+ }
+ else if( convex(verts[0]->co, verts[3]->co, verts[1]->co, verts[2]->co) ) {
+ f= BM_Make_QuadTri(bm, verts[0], verts[3], verts[1], verts[2], NULL, 1);
+ }
+ else {
+ printf("cannot find nice quad from concave set of vertices\n");
+ }
+
+ if (f) BMO_SetFlag(bm, f, ELE_OUT);
+ }
+
+ BMO_Flag_To_Slot(bm, op, "faceout", ELE_OUT, BM_FACE);
+}
diff --git a/source/blender/bmesh/operators/dissolveops.c b/source/blender/bmesh/operators/dissolveops.c
new file mode 100644
index 00000000000..997a24d0507
--- /dev/null
+++ b/source/blender/bmesh/operators/dissolveops.c
@@ -0,0 +1,430 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "bmesh_private.h"
+#include "BLI_arithb.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define FACE_MARK 1
+#define FACE_ORIG 2
+#define FACE_NEW 4
+#define EDGE_MARK 1
+
+#define VERT_MARK 1
+
+static int check_hole_in_region(BMesh *bm, BMFace *f) {
+ BMWalker regwalker;
+ BMIter liter2;
+ BMLoop *l2, *l3;
+ BMFace *f2;
+
+ /*checks if there are any unmarked boundary edges in the face region*/
+
+ BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK);
+ f2 = BMW_Begin(&regwalker, f);
+ for (; f2; f2=BMW_Step(&regwalker)) {
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ l3 = bmesh_radial_nextloop(l2);
+ if (BMO_TestFlag(bm, l3->f, FACE_MARK)
+ != BMO_TestFlag(bm, l2->f, FACE_MARK))
+ {
+ if (!BMO_TestFlag(bm, l2->e, EDGE_MARK)) {
+ return 0;
+ }
+ }
+ }
+ }
+ BMW_End(&regwalker);
+
+ return 1;
+}
+
+void dissolvefaces_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter oiter;
+ BMIter liter, liter2, liter3;
+ BMLoop *l, *l2, *l3;
+ BMFace *f, *f2, *nf = NULL;
+ V_DECLARE(region);
+ V_DECLARE(regions);
+ BMLoop ***regions = NULL;
+ BMLoop **region = NULL;
+ BMWalker regwalker;
+ int i, j, fcopied;
+
+ BMO_Flag_Buffer(bm, op, "faces", FACE_MARK);
+
+ /*collect regions*/
+ f = BMO_IterNew(&oiter, bm, op, "faces", BM_FACE);
+ for (; f; f=BMO_IterStep(&oiter)) {
+ if (!BMO_TestFlag(bm, f, FACE_MARK)) continue;
+
+ V_RESET(region);
+ region = NULL; /*forces different allocation*/
+
+ /*yay, walk!*/
+ BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK);
+ f2 = BMW_Begin(&regwalker, f);
+ for (; f2; f2=BMW_Step(&regwalker)) {
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_FACE, f2);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ l3 = BMIter_New(&liter3, bm, BM_LOOPS_OF_LOOP, l2);
+ for (; l3; l3=BMIter_Step(&liter3)) {
+ if (!BMO_TestFlag(bm, l3->f, FACE_MARK)) {
+ V_GROW(region);
+ region[V_COUNT(region)-1] = l2;
+ break;
+ }
+ }
+ if (bmesh_radial_nextloop(l2) == l2) {
+ V_GROW(region);
+ region[V_COUNT(region)-1] = l2;
+ }
+ }
+ }
+ BMW_End(&regwalker);
+
+ BMW_Init(&regwalker, bm, BMW_ISLAND, FACE_MARK);
+ f2 = BMW_Begin(&regwalker, f);
+ for (; f2; f2=BMW_Step(&regwalker)) {
+ BMO_ClearFlag(bm, f2, FACE_MARK);
+ BMO_SetFlag(bm, f2, FACE_ORIG);
+ }
+
+ BMW_End(&regwalker);
+
+ if (BMO_HasError(bm)) {
+ BMO_ClearStack(bm);
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED, NULL);
+ goto cleanup;
+ }
+
+ V_GROW(region);
+ V_GROW(regions);
+ regions[V_COUNT(regions)-1] = region;
+ region[V_COUNT(region)-1] = NULL;
+ }
+
+ for (i=0; i<V_COUNT(regions); i++) {
+ BMEdge **edges = NULL;
+ V_DECLARE(edges);
+
+ region = regions[i];
+ for (j=0; region[j]; j++) {
+ V_GROW(edges);
+ edges[V_COUNT(edges)-1] = region[j]->e;
+ }
+
+ if (!region[0]) {
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED,
+ "Could not find boundary of dissolve region");
+ goto cleanup;
+ }
+
+ if (region[0]->e->v1 == region[0]->v)
+ f= BM_Make_Ngon(bm, region[0]->e->v1, region[0]->e->v2, edges, j, 1);
+ else
+ f= BM_Make_Ngon(bm, region[0]->e->v2, region[0]->e->v1, edges, j, 1);
+
+ V_FREE(edges);
+
+ if (!f) {
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEFACES_FAILED,
+ "Could not create merged face");
+ goto cleanup;
+ }
+
+ /*if making the new face failed (e.g. overlapping test)
+ unmark the original faces for deletion.*/
+ BMO_ClearFlag(bm, f, FACE_ORIG);
+ BMO_SetFlag(bm, f, FACE_NEW);
+
+ fcopied = 0;
+ l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&liter)) {
+ /*ensure winding is identical*/
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
+ if (l2->v != l->v)
+ bmesh_loop_reverse(bm, l2->f);
+ break;
+ }
+ }
+
+ /*copy over attributes*/
+ l2 = BMIter_New(&liter2, bm, BM_LOOPS_OF_LOOP, l);
+ for (; l2; l2=BMIter_Step(&liter2)) {
+ if (BMO_TestFlag(bm, l2->f, FACE_ORIG)) {
+ if (!fcopied) {
+ BM_Copy_Attributes(bm, bm, l2->f, f);
+ fcopied = 1;
+ }
+ BM_Copy_Attributes(bm, bm, l2, l);
+ break;
+ }
+ }
+ }
+ }
+
+ BMO_CallOpf(bm, "del geom=%ff context=%d", FACE_ORIG, DEL_FACES);
+ if (BMO_HasError(bm)) goto cleanup;
+
+ BMO_Flag_To_Slot(bm, op, "regionout", FACE_NEW, BM_FACE);
+
+cleanup:
+ /*free/cleanup*/
+ for (i=0; i<V_COUNT(regions); i++) {
+ if (regions[i]) V_FREE(regions[i]);
+ }
+
+ V_FREE(regions);
+}
+
+/*almost identical to dissolve edge, except it cleans up vertices*/
+void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator fop;
+ BMOIter oiter;
+ BMIter iter;
+ BMVert *v, **verts = NULL;
+ V_DECLARE(verts);
+ BMEdge *e;
+ BMFace *f;
+ int i;
+
+ BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) {
+ if (BM_Edge_FaceCount(e) == 2) {
+ BMO_SetFlag(bm, e->v1, VERT_MARK);
+ BMO_SetFlag(bm, e->v2, VERT_MARK);
+
+ BM_Join_Faces(bm, e->loop->f,
+ ((BMLoop*)e->loop->radial.next->data)->f,
+ e);
+ }
+ }
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, v, VERT_MARK) &&
+ BM_Vert_EdgeCount(v) == 2)
+ {
+ V_GROW(verts);
+ verts[V_COUNT(verts)-1] = v;
+ }
+ }
+
+ /*clean up extreneous 2-valence vertices*/
+ for (i=0; i<V_COUNT(verts); i++) {
+ BM_Collapse_Vert(bm, verts[i]->edge, verts[i], 1.0);
+ }
+
+ V_FREE(verts);
+
+ //BMO_InitOpf(bm, &fop, "dissolvefaces faces=%ff", FACE_MARK);
+ //BMO_Exec_Op(bm, &fop);
+
+ //BMO_CopySlot(op, &fop, "regionout", "regionout");
+
+ //BMO_Finish_Op(bm, &fop);
+}
+
+
+void dissolveedges_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator fop;
+ BMOIter oiter;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ int i;
+
+ BMO_ITER(e, &oiter, bm, op, "edges", BM_EDGE) {
+ if (BM_Edge_FaceCount(e) == 2) {
+ BMO_SetFlag(bm, e->v1, VERT_MARK);
+ BMO_SetFlag(bm, e->v2, VERT_MARK);
+
+ BM_Join_Faces(bm, e->loop->f,
+ ((BMLoop*)e->loop->radial.next->data)->f,
+ e);
+ }
+ }
+
+ //BMO_InitOpf(bm, &fop, "dissolvefaces faces=%ff", FACE_MARK);
+ //BMO_Exec_Op(bm, &fop);
+
+ //BMO_CopySlot(op, &fop, "regionout", "regionout");
+
+ //BMO_Finish_Op(bm, &fop);
+}
+
+static int test_extra_verts(BMesh *bm, BMVert *v)
+{
+ BMIter iter, liter, iter2, iter3;
+ BMFace *f, *f2;
+ BMLoop *l;
+ BMEdge *e;
+ int found;
+
+ /*test faces around verts for verts that would be wronly killed
+ by dissolve faces.*/
+ f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&iter)) {
+ l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (!BMO_TestFlag(bm, l->v, VERT_MARK)) {
+ /*if an edge around a vert is a boundary edge,
+ then dissolve faces won't destroy it.
+ also if it forms a boundary with one
+ of the face regions*/
+ found = 0;
+ e = BMIter_New(&iter2, bm, BM_EDGES_OF_VERT, l->v);
+ for (; e; e=BMIter_Step(&iter2)) {
+ if (BM_Edge_FaceCount(e)==1) found = 1;
+ f2 = BMIter_New(&iter3, bm, BM_FACES_OF_EDGE, e);
+ for (; f2; f2=BMIter_Step(&iter3)) {
+ if (!BMO_TestFlag(bm, f2, FACE_MARK)) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) break;
+ }
+ if (!found) return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+void dissolveverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMOpSlot *vinput;
+ BMIter iter, fiter;
+ BMVert *v;
+ BMFace *f;
+ int i;
+
+ vinput = BMO_GetSlot(op, "verts");
+ BMO_Flag_Buffer(bm, op, "verts", VERT_MARK);
+
+ for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) {
+ if (BMO_TestFlag(bm, v, VERT_MARK)) {
+ f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&fiter)) {
+ BMO_SetFlag(bm, f, FACE_ORIG);
+ BMO_SetFlag(bm, f, FACE_MARK);
+ }
+
+ /*check if our additions to the input to face dissolve
+ will destroy nonmarked vertices.*/
+ if (!test_extra_verts(bm, v)) {
+ f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&fiter)) {
+ if (BMO_TestFlag(bm, f, FACE_ORIG)) {
+ BMO_ClearFlag(bm, f, FACE_MARK);
+ BMO_ClearFlag(bm, f, FACE_ORIG);
+ }
+ }
+ } else {
+ f=BMIter_New(&fiter, bm, BM_FACES_OF_VERT, v);
+ for (; f; f=BMIter_Step(&fiter)) {
+ BMO_ClearFlag(bm, f, FACE_ORIG);
+ }
+ }
+ }
+ }
+
+ BMO_CallOpf(bm, "dissolvefaces faces=%ff", FACE_MARK);
+ if (BMO_HasError(bm)) {
+ char *msg;
+
+ BMO_GetError(bm, &msg, NULL);
+ BMO_ClearStack(bm);
+ BMO_RaiseError(bm, op, BMERR_DISSOLVEVERTS_FAILED,msg);
+ }
+
+ /*clean up any remaining*/
+ for (v=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); v; v=BMIter_Step(&iter)) {
+ if (BMO_TestFlag(bm, v, VERT_MARK)) {
+ if (!BM_Dissolve_Vert(bm, v)) {
+ BMO_RaiseError(bm, op,
+ BMERR_DISSOLVEVERTS_FAILED, NULL);
+ return;
+ }
+ }
+ }
+
+}
+
+/*this code is for cleaning up two-edged faces, it shall become
+ it's own function one day.*/
+#if 0
+ /*clean up two-edged faces*/
+ /*basic idea is to keep joining 2-edged faces until their
+ gone. this however relies on joining two 2-edged faces
+ together to work, which doesn't.*/
+ found3 = 1;
+ while (found3) {
+ found3 = 0;
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)){
+ if (!BM_Validate_Face(bm, f, stderr)) {
+ printf("error.\n");
+ }
+
+ if (f->len == 2) {
+ //this design relies on join faces working
+ //with two-edged faces properly.
+ //commenting this line disables the
+ //outermost loop.
+ //found3 = 1;
+ found2 = 0;
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ fe = l->e;
+ for (; l; l=BMIter_Step(&liter)) {
+ f2 = BMIter_New(&fiter, bm,
+ BM_FACES_OF_EDGE, l->e);
+ for (; f2; f2=BMIter_Step(&fiter)) {
+ if (f2 != f) {
+ BM_Join_Faces(bm, f, f2, l->e);
+ found2 = 1;
+ break;
+ }
+ }
+ if (found2) break;
+ }
+
+ if (!found2) {
+ bmesh_kf(bm, f);
+ bmesh_ke(bm, fe);
+ }
+ } /*else if (f->len == 3) {
+ BMEdge *ed[3];
+ BMVert *vt[3];
+ BMLoop *lp[3];
+ int i=0;
+
+ //check for duplicate edges
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&liter)) {
+ ed[i] = l->e;
+ lp[i] = l;
+ vt[i++] = l->v;
+ }
+ if (vt[0] == vt[1] || vt[0] == vt[2]) {
+ i += 1;
+ }
+ }*/
+ }
+ }
+ if (oldlen == len) break;
+ oldlen = len;
+
+#endif
diff --git a/source/blender/bmesh/operators/extrudeops.c b/source/blender/bmesh/operators/extrudeops.c
new file mode 100644
index 00000000000..5417d232205
--- /dev/null
+++ b/source/blender/bmesh/operators/extrudeops.c
@@ -0,0 +1,190 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "bmesh.h"
+#include "bmesh_operators_private.h"
+
+#define EXT_INPUT 1
+#define EXT_KEEP 2
+#define EXT_DEL 4
+
+void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMVert *v, *dupev;
+ BMEdge *e;
+
+ v = BMO_IterNew(&siter, bm, op, "verts", BM_VERT);
+ for (; v; v=BMO_IterStep(&siter)) {
+ dupev = BM_Make_Vert(bm, v->co, NULL);
+ VECCOPY(dupev->no, v->no);
+ BM_Copy_Attributes(bm, bm, v, dupev);
+
+ e = BM_Make_Edge(bm, v, dupev, NULL, 0);
+
+ BMO_SetFlag(bm, e, EXT_KEEP);
+ BMO_SetFlag(bm, dupev, EXT_KEEP);
+ }
+
+ BMO_Flag_To_Slot(bm, op, "vertout", EXT_KEEP, BM_VERT);
+ BMO_Flag_To_Slot(bm, op, "edgeout", EXT_KEEP, BM_EDGE);
+}
+
+void extrude_edge_context_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator dupeop, delop;
+ BMOIter siter;
+ BMIter iter, fiter, viter;
+ BMEdge *e, *newedge, *e2, *ce;
+ BMLoop *l, *l2;
+ BMVert *verts[4], *v, *v2;
+ BMFace *f;
+ int rlen, found, delorig=0, i, reverse;
+
+ /*initialize our sub-operators*/
+ BMO_Init_Op(&dupeop, "dupe");
+
+ BMO_Flag_Buffer(bm, op, "edgefacein", EXT_INPUT);
+
+ /*if one flagged face is bordered by an unflagged face, then we delete
+ original geometry.*/
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, e, EXT_INPUT)) continue;
+
+ found = 0;
+ f = BMIter_New(&fiter, bm, BM_FACES_OF_EDGE, e);
+ for (rlen=0; f; f=BMIter_Step(&fiter), rlen++) {
+ if (!BMO_TestFlag(bm, f, EXT_INPUT)) {
+ found = 1;
+ delorig = 1;
+ break;
+ }
+ }
+
+ if (!found && (rlen > 1)) BMO_SetFlag(bm, e, EXT_DEL);
+ }
+
+ /*calculate verts to delete*/
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ found = 0;
+
+ BM_ITER(e, &viter, bm, BM_EDGES_OF_VERT, v) {
+ if (!BMO_TestFlag(bm, e, EXT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+
+ BM_ITER(f, &viter, bm, BM_FACES_OF_VERT, v) {
+ if (!BMO_TestFlag(bm, f, EXT_INPUT)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ BMO_SetFlag(bm, v, EXT_DEL);
+ }
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (BMO_TestFlag(bm, f, EXT_INPUT))
+ BMO_SetFlag(bm, f, EXT_DEL);
+ }
+ if (delorig) BMO_InitOpf(bm, &delop, "del geom=%fvef context=%d",
+ EXT_DEL, DEL_ONLYTAGGED);
+
+ BMO_CopySlot(op, &dupeop, "edgefacein", "geom");
+ BMO_Exec_Op(bm, &dupeop);
+
+ if (bm->act_face && BMO_TestFlag(bm, bm->act_face, EXT_INPUT))
+ bm->act_face = BMO_Get_MapPointer(bm, &dupeop, "facemap", bm->act_face);
+
+ if (delorig) BMO_Exec_Op(bm, &delop);
+
+ /*if not delorig, reverse loops of original faces*/
+ if (!delorig) {
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)) {
+ if (BMO_TestFlag(bm, f, EXT_INPUT)) {
+ BM_flip_normal(bm, f);
+ }
+ }
+ }
+
+ BMO_CopySlot(&dupeop, op, "newout", "geomout");
+ e = BMO_IterNew(&siter, bm, &dupeop, "boundarymap", 0);
+ for (; e; e=BMO_IterStep(&siter)) {
+ if (BMO_InMap(bm, op, "exclude", e)) continue;
+
+ newedge = BMO_IterMapVal(&siter);
+ newedge = *(BMEdge**)newedge;
+ if (!newedge) continue;
+ if (!newedge->loop) ce = e;
+ else ce = newedge;
+
+ if (ce->loop && (ce->loop->v == ce->v1)) {
+ verts[0] = e->v1;
+ verts[1] = e->v2;
+ verts[2] = newedge->v2;
+ verts[3] = newedge->v1;
+ } else {
+ verts[3] = e->v1;
+ verts[2] = e->v2;
+ verts[1] = newedge->v2;
+ verts[0] = newedge->v1;
+ }
+
+ /*not sure what to do about example face, pass NULL for now.*/
+ f = BM_Make_Quadtriangle(bm, verts, NULL, 4, NULL, 0);
+
+ /*copy attributes*/
+ l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
+ for (; l; l=BMIter_Step(&iter)) {
+ if (l->e != e && l->e != newedge) continue;
+ l2 = l->radial.next->data;
+
+ if (l2 == l) {
+ l2 = newedge->loop;
+ BM_Copy_Attributes(bm, bm, l2->f, l->f);
+
+ BM_Copy_Attributes(bm, bm, l2, l);
+ l2 = (BMLoop*) l2->head.next;
+ l = (BMLoop*) l->head.next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ } else {
+ BM_Copy_Attributes(bm, bm, l2->f, l->f);
+
+ /*copy data*/
+ if (l2->v == l->v) {
+ BM_Copy_Attributes(bm, bm, l2, l);
+ l2 = (BMLoop*) l2->head.next;
+ l = (BMLoop*) l->head.next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ } else {
+ l2 = (BMLoop*) l2->head.next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ l2 = (BMLoop*) l2->head.prev;
+ l = (BMLoop*) l->head.next;
+ BM_Copy_Attributes(bm, bm, l2, l);
+ }
+ }
+ }
+ }
+
+ /*link isolated verts*/
+ v = BMO_IterNew(&siter, bm, &dupeop, "isovertmap", 0);
+ for (; v; v=BMO_IterStep(&siter)) {
+ v2 = *((void**)BMO_IterMapVal(&siter));
+ BM_Make_Edge(bm, v, v2, v->edge, 1);
+ }
+
+ /*cleanup*/
+ if (delorig) BMO_Finish_Op(bm, &delop);
+ BMO_Finish_Op(bm, &dupeop);
+}
diff --git a/source/blender/bmesh/operators/mesh_conv.c b/source/blender/bmesh/operators/mesh_conv.c
new file mode 100644
index 00000000000..3ca95ea1e32
--- /dev/null
+++ b/source/blender/bmesh/operators/mesh_conv.c
@@ -0,0 +1,308 @@
+
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+
+#include "bmesh.h"
+
+/*
+ * MESH CONV.C
+ *
+ * This file contains functions
+ * for converting a Mesh
+ * into a Bmesh. will not support non-ngon
+ * meshes at first, use the editmesh functions
+ * until it's implemented, and remove this
+ * comment if it already is. -joeedh
+ *
+*/
+
+void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op) {
+ Mesh *me = BMO_Get_Pnt(op, "mesh");
+ MVert *mvert;
+ MEdge *medge;
+ MLoop *ml;
+ MPoly *mpoly;
+ BMVert *v, **vt=NULL;
+ BMEdge *e, **fedges=NULL, **et;
+ V_DECLARE(fedges);
+ BMFace *f;
+ int i, j, allocsize[4] = {512, 512, 2048, 512};
+
+ if (!me || !me->totvert) return; /*sanity check*/
+
+ mvert = me->mvert;
+
+ vt = MEM_mallocN(sizeof(void**)*me->totvert, "mesh to bmesh vtable");
+
+ CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &me->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bm->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bm->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bm->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bm->pdata, allocsize[3]);
+
+ for (i=0; i<me->totvert; i++, mvert++) {
+ v = BM_Make_Vert(bm, mvert->co, NULL);
+ VECCOPY(v->no, mvert->no);
+
+ vt[i] = v;
+ BMINDEX_SET(v, i);
+
+ /*transfer flags*/
+ v->head.flag = (mvert->flag & ME_HIDE) ? BM_HIDDEN : 0;
+ if(mvert->flag & SELECT) BM_Select_Vert(bm, v, 1);
+ v->bweight = (float)mvert->bweight / 255.0f;
+
+ /*Copy Custom Data*/
+ CustomData_to_bmesh_block(&me->vdata, &bm->vdata, i, &v->head.data);
+
+ v->head.flag = MEFlags_To_BMFlags(mvert->flag, BM_VERT);
+ }
+
+ if (!me->totedge) return;
+
+ et = MEM_mallocN(sizeof(void**)*me->totedge, "mesh to bmesh etable");
+
+ medge = me->medge;
+ for (i=0; i<me->totedge; i++, medge++) {
+ e = BM_Make_Edge(bm, vt[medge->v1], vt[medge->v2], NULL, 0);
+ et[i] = e;
+
+ /*Copy Custom Data*/
+ CustomData_to_bmesh_block(&me->edata, &bm->edata, i, &e->head.data);
+
+ e->crease = (float)medge->crease / 255.0f;
+ e->bweight = (float)medge->bweight / 255.0f;
+
+ e->head.flag = MEFlags_To_BMFlags(medge->flag, BM_EDGE);
+ }
+
+ if (!me->totpoly) return;
+
+ mpoly = me->mpoly;
+ for (i=0; i<me->totpoly; i++, mpoly++) {
+ BMVert *v1, *v2;
+
+ V_RESET(fedges);
+ for (j=0; j<mpoly->totloop; j++) {
+ ml = &me->mloop[mpoly->loopstart+j];
+ v = vt[ml->v];
+ e = et[ml->e];
+
+ V_GROW(fedges);
+
+ fedges[j] = e;
+ }
+
+ v1 = vt[me->mloop[mpoly->loopstart].v];
+ v2 = vt[me->mloop[mpoly->loopstart+1].v];
+
+ if (v1 == fedges[0]->v1) v2 = fedges[0]->v2;
+ else {
+ v1 = fedges[0]->v2;
+ v2 = fedges[0]->v1;
+ }
+
+ f = BM_Make_Ngon(bm, v1, v2, fedges, mpoly->totloop, 0);
+
+ f->head.flag = MEFlags_To_BMFlags(mpoly->flag, BM_FACE);
+ if (i == me->act_face) bm->act_face = f;
+
+ /*Copy Custom Data*/
+ CustomData_to_bmesh_block(&me->fdata, &bm->pdata, i, &f->head.data);
+ }
+}
+
+void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op) {
+ BMesh *bmtess;
+ Object *ob = BMO_Get_Pnt(op, "object");
+ Scene *scene = BMO_Get_Pnt(op, "scene");
+ Mesh *me = ob->data;
+ MLoop *mloop;
+ MPoly *mpoly;
+ MVert *mvert, *oldverts;
+ MEdge *medge;
+ MFace *mface;
+ BMVert *v;
+ BMEdge *e;
+ BMLoop *l;
+ BMFace *f;
+ BMIter iter, liter;
+ int i, j, ototvert, totloop, numTex, numCol;
+
+ numTex = CustomData_number_of_layers(&me->pdata, CD_MLOOPUV);
+ numCol = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+
+ bmtess = BM_Copy_Mesh(bm);
+ BMO_CallOpf(bmtess, "makefgon trifan=%i", 0);
+
+ /* 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");
+
+ /* new Face block */
+ if(bmtess->totface==0) mface= NULL;
+ else mface= MEM_callocN(bmtess->totface*sizeof(MFace), "loadeditbMesh face");
+
+ /*build ngon data*/
+ /* new Ngon Face block */
+ if(bm->totface==0) mpoly = NULL;
+ else mpoly= MEM_callocN(bm->totface*sizeof(MPoly), "loadeditbMesh poly");
+
+ /*find number of loops to allocate*/
+ totloop = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ totloop += f->len;
+ }
+
+ if (totloop==0) mloop = NULL;
+ else mloop = MEM_callocN(totloop*sizeof(MLoop), "loadeditbMesh loop");
+
+ /* lets save the old verts just in case we are actually working on
+ * a key ... we now do processing of the keys at the end */
+ oldverts= me->mvert;
+
+ /* don't free this yet */
+ CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+
+ /* free custom data */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* add new custom data */
+ me->totvert= bm->totvert;
+ me->totedge= bm->totedge;
+ me->totface= bmtess->totface;
+ me->totloop= totloop;
+ me->totpoly= bm->totface;
+
+ CustomData_copy(&bm->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
+ CustomData_copy(&bm->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
+ CustomData_copy(&bm->ldata, &me->ldata, CD_MASK_MESH, CD_CALLOC, me->totloop);
+ CustomData_copy(&bm->pdata, &me->pdata, CD_MASK_MESH, CD_CALLOC, me->totpoly);
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface);
+ CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, mloop, me->totloop);
+ CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, mpoly, me->totpoly);
+
+ CustomData_from_bmeshpoly(&me->fdata, &bmtess->pdata, &bmtess->ldata, bmtess->totface);
+
+ mesh_update_customdata_pointers(me);
+
+ /*set indices*/
+ i = 0;
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ VECCOPY(mvert->co, v->co);
+
+ mvert->no[0] = (unsigned char) (v->no[0]*255.0f);
+ mvert->no[1] = (unsigned char) (v->no[1]*255.0f);
+ mvert->no[2] = (unsigned char) (v->no[2]*255.0f);
+
+ mvert->flag = BMFlags_To_MEFlags(v);
+
+ BMINDEX_SET(v, i);
+ i++;
+ mvert++;
+ }
+
+ i = 0;
+ BM_ITER(v, &iter, bmtess, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+ }
+
+ i = 0;
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ medge->v1 = BMINDEX_GET(e->v1);
+ medge->v2 = BMINDEX_GET(e->v2);
+
+ medge->flag = BMFlags_To_MEFlags(e);
+
+ BMINDEX_SET(e, i);
+ i++;
+ medge++;
+ }
+
+ i = 0;
+ BM_ITER(f, &iter, bmtess, BM_FACES_OF_MESH, NULL) {
+ mface->mat_nr = f->mat_nr;
+ mface->flag = BMFlags_To_MEFlags(f);
+
+ mface->v1 = BMINDEX_GET(f->loopbase->v);
+ mface->v2 = BMINDEX_GET(((BMLoop*)f->loopbase->head.next)->v);
+ if (f->len < 3) {
+ mface++;
+ i++;
+ continue;
+ }
+
+ mface->v3 = BMINDEX_GET(((BMLoop*)f->loopbase->head.next->next)->v);
+ if (f->len < 4) {
+ mface->v4 = 0;
+ mface++;
+ i++;
+ continue;
+ }
+
+ mface->v4 = BMINDEX_GET(((BMLoop*)f->loopbase->head.next->next->next)->v);
+ test_index_face(mface, &me->fdata, i, 1);
+
+ BM_loops_to_corners(bmtess, me, i, f, numTex, numCol);
+
+ mface++;
+ i++;
+ }
+
+ i = 0;
+ j = 0;
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ mpoly->loopstart = j;
+ mpoly->totloop = f->len;
+ mpoly->mat_nr = f->mat_nr;
+ mpoly->flag = BMFlags_To_MEFlags(f);
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
+ for ( ; l; l=BMIter_Step(&liter), j++, mloop++) {
+ mloop->e = BMINDEX_GET(l->e);
+ mloop->v = BMINDEX_GET(l->v);
+ }
+
+ if (f == bm->act_face) me->act_face = i;
+
+ i++;
+ mpoly++;
+ }
+
+ BM_Free_Mesh(bmtess);
+} \ No newline at end of file
diff --git a/source/blender/bmesh/operators/removedoubles.c b/source/blender/bmesh/operators/removedoubles.c
new file mode 100644
index 00000000000..605626d15e0
--- /dev/null
+++ b/source/blender/bmesh/operators/removedoubles.c
@@ -0,0 +1,309 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "bmesh_private.h"
+#include "BLI_arithb.h"
+#include "BLI_ghash.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BL(ptr) ((BMLoop*)(ptr))
+
+void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op)
+{
+ BMIter liter;
+ BMLoop *l;
+ BMVert *v2, *doub;
+ int split=0;
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", l->v);
+ /*ok: if v2 is NULL (e.g. not in the map) then it's
+ a target vert, otherwise it's a double*/
+ if (v2 && BM_Vert_In_Face(f, v2) && v2 != BL(l->head.prev)->v
+ && v2 != BL(l->head.next)->v)
+ {
+ doub = l->v;
+ split = 1;
+ break;
+ }
+ }
+
+ if (split && doub != v2) {
+ BMLoop *nl;
+ BMFace *f2 = BM_Split_Face(bm, f, doub, v2, &nl, NULL);
+
+ remdoubles_splitface(f, bm, op);
+ remdoubles_splitface(f2, bm, op);
+ }
+}
+
+#define ELE_DEL 1
+#define EDGE_COL 2
+#define FACE_MARK 2
+
+#if 0
+int remdoubles_face_overlaps(BMesh *bm, BMVert **varr,
+ int len, BMFace *exclude,
+ BMFace **overlapface)
+{
+ BMIter vertfaces;
+ BMFace *f;
+ int i, amount;
+
+ if (overlapface) *overlapface = NULL;
+
+ for(i=0; i < len; i++){
+ f = BMIter_New(&vertfaces, bm, BM_FACES_OF_VERT, varr[i] );
+ while(f){
+ amount = BM_Verts_In_Face(bm, f, varr, len);
+ if(amount >= len){
+ if (overlapface) *overlapface = f;
+ return 1;
+ }
+ f = BMIter_Step(&vertfaces);
+ }
+ }
+ return 0;
+}
+#endif
+
+void bmesh_weldverts_exec(BMesh *bm, BMOperator *op)
+{
+ BMIter iter, liter;
+ BMVert *v, *v2;
+ BMEdge *e, *e2, **edges = NULL;
+ V_DECLARE(edges);
+ BMLoop *l, *l2, **loops = NULL;
+ V_DECLARE(loops);
+ BMFace *f, *f2;
+ int a;
+
+ BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMO_Get_MapPointer(bm, op, "targetmap", v))
+ BMO_SetFlag(bm, v, ELE_DEL);
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ remdoubles_splitface(f, bm, op);
+ }
+
+ BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ v = BMO_Get_MapPointer(bm, op, "targetmap", e->v1);
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", e->v2);
+
+ if (!v) v = e->v1;
+ if (!v2) v2 = e->v2;
+
+ if ((e->v1 != v) || (e->v2 != v2)) {
+ if (v == v2) BMO_SetFlag(bm, e, EDGE_COL);
+ else BM_Make_Edge(bm, v, v2, e, 1);
+
+ BMO_SetFlag(bm, e, ELE_DEL);
+ }
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMINDEX_SET(f, 0);
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ if (BMO_TestFlag(bm, l->v, ELE_DEL))
+ BMO_SetFlag(bm, f, FACE_MARK);
+ if (BMO_TestFlag(bm, l->e, EDGE_COL))
+ BMINDEX_SET(f, BMINDEX_GET(f)+1);
+ }
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ if (!BMO_TestFlag(bm, f, FACE_MARK)) continue;
+ if (f->len - BMINDEX_GET(f) < 3) {
+ BMO_SetFlag(bm, f, ELE_DEL);
+ continue;
+ }
+
+ V_RESET(edges);
+ V_RESET(loops);
+ a = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
+ v = l->v;
+ v2 = BL(l->head.next)->v;
+ if (BMO_TestFlag(bm, v, ELE_DEL))
+ v = BMO_Get_MapPointer(bm, op, "targetmap", v);
+ if (BMO_TestFlag(bm, v2, ELE_DEL))
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2);
+
+ e2 = v != v2 ? BM_Edge_Exist(v, v2) : NULL;
+ if (e2) {
+ V_GROW(edges);
+ V_GROW(loops);
+
+ edges[a] = e2;
+ loops[a] = l;
+
+ a++;
+ }
+ }
+
+ v = loops[0]->v;
+ v2 = loops[1]->v;
+
+ if (BMO_TestFlag(bm, v, ELE_DEL))
+ v = BMO_Get_MapPointer(bm, op, "targetmap", v);
+ if (BMO_TestFlag(bm, v2, ELE_DEL))
+ v2 = BMO_Get_MapPointer(bm, op, "targetmap", v2);
+
+
+ f2 = BM_Make_Ngon(bm, v, v2, edges, a, 0);
+ if (f2) {
+ BM_Copy_Attributes(bm, bm, f, f2);
+ BMO_SetFlag(bm, f, ELE_DEL);
+
+ a = 0;
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f2) {
+ l2 = loops[a];
+ BM_Copy_Attributes(bm, bm, l2, l);
+
+ a++;
+ }
+ }
+
+ /*need to still copy customdata stuff here, will do later*/
+ }
+
+ BMO_CallOpf(bm, "del geom=%fvef context=%i", ELE_DEL, DEL_ONLYTAGGED);
+
+ V_FREE(edges);
+}
+
+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
+
+void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op)
+{
+ BMOperator weldop;
+ BMOIter oiter;
+ BMVert *v, *v2;
+ BMVert **verts=NULL;
+ V_DECLARE(verts);
+ float dist, distsqr;
+ int i, j, len;
+
+ dist = BMO_Get_Float(op, "dist");
+ distsqr = dist*dist;
+
+ BMO_Init_Op(&weldop, "weldverts");
+
+ i = 0;
+ BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
+ V_GROW(verts);
+ verts[i++] = v;
+ }
+
+ /*sort by vertex coordinates added together*/
+ qsort(verts, V_COUNT(verts), sizeof(void*), vergaverco);
+
+ len = V_COUNT(verts);
+ for (i=0; i<len; i++) {
+ v = verts[i];
+ if (BMO_TestFlag(bm, v, VERT_TESTED)) continue;
+
+ BMO_SetFlag(bm, v, VERT_TESTED);
+ for (j=i+1; j<len; j++) {
+ float vec[3];
+
+ v2 = verts[j];
+ if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
+ > distsqr) break;
+
+ vec[0] = v->co[0] - v2->co[0];
+ vec[1] = v->co[1] - v2->co[1];
+ vec[2] = v->co[2] - v2->co[2];
+
+ if (INPR(vec, vec) < distsqr) {
+ BMO_SetFlag(bm, v2, VERT_TESTED);
+ BMO_SetFlag(bm, v2, VERT_DOUBLE);
+ BMO_SetFlag(bm, v, VERT_TARGET);
+
+ BMO_Insert_MapPointer(bm, &weldop, "targetmap", v2, v);
+ }
+ }
+ }
+
+ V_FREE(verts);
+
+ BMO_Exec_Op(bm, &weldop);
+ BMO_Finish_Op(bm, &weldop);
+}
+
+
+void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter oiter;
+ BMVert *v, *v2;
+ BMVert **verts=NULL;
+ V_DECLARE(verts);
+ float dist, distsqr;
+ int i, j, len;
+
+ dist = BMO_Get_Float(op, "dist");
+ distsqr = dist*dist;
+
+ i = 0;
+ BMO_ITER(v, &oiter, bm, op, "verts", BM_VERT) {
+ V_GROW(verts);
+ verts[i++] = v;
+ }
+
+ /*sort by vertex coordinates added together*/
+ //qsort(verts, V_COUNT(verts), sizeof(void*), vergaverco);
+
+ BMO_Flag_Buffer(bm, op, "keepverts", VERT_KEEP);
+
+ len = V_COUNT(verts);
+ for (i=0; i<len; i++) {
+ v = verts[i];
+ if (BMO_TestFlag(bm, v, VERT_DOUBLE)) continue;
+
+ //BMO_SetFlag(bm, v, VERT_TESTED);
+ for (j=0; j<len; j++) {
+ if (j == i) continue;
+
+ //float vec[3];
+ if (BMO_TestFlag(bm, v, VERT_KEEP)) continue;
+
+ v2 = verts[j];
+ //if ((v2->co[0]+v2->co[1]+v2->co[2]) - (v->co[0]+v->co[1]+v->co[2])
+ // > distsqr) break;
+
+ //vec[0] = v->co[0] - v2->co[0];
+ //vec[1] = v->co[1] - v2->co[1];
+ //vec[2] = v->co[2] - v2->co[2];
+
+ if (VecLenCompare(v->co, v2->co, dist)) {
+ BMO_SetFlag(bm, v2, VERT_DOUBLE);
+ BMO_SetFlag(bm, v, VERT_TARGET);
+
+ BMO_Insert_MapPointer(bm, op, "targetmapout", v2, v);
+ }
+ }
+ }
+
+ V_FREE(verts);
+}
diff --git a/source/blender/bmesh/operators/subdivideop.c b/source/blender/bmesh/operators/subdivideop.c
new file mode 100644
index 00000000000..8482fecb7bb
--- /dev/null
+++ b/source/blender/bmesh/operators/subdivideop.c
@@ -0,0 +1,825 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+
+#include "DNA_object_types.h"
+
+#include "ED_mesh.h"
+
+#include "bmesh.h"
+#include "mesh_intern.h"
+#include "subdivideop.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/*flags for all elements share a common bitfield space*/
+#define SUBD_SPLIT 1
+
+#define EDGE_PERCENT 2
+
+/*I don't think new faces are flagged, currently, but
+ better safe than sorry.*/
+#define FACE_NEW 4
+#define FACE_CUSTOMFILL 8
+#define ELE_INNER 16
+#define ELE_SPLIT 32
+#define ELE_CONNECT 64
+
+/*stuff for the flag paramter. note that
+ what used to live in "beauty" and
+ in "seltype" live here. still have to
+ convert the beauty flags over, which
+ is why it starts at 128 (to avoid
+ collision).*/
+#define SELTYPE_INNER 128
+
+/*
+NOTE: beauty has been renamed to flag!
+*/
+
+/*generic subdivision rules:
+
+ * two selected edges in a face should make a link
+ between them.
+
+ * one edge should do, what? make pretty topology, or just
+ split the edge only?
+*/
+
+/*connects face with smallest len, which I think should always be correct for
+ edge subdivision*/
+BMEdge *connect_smallest_face(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) {
+ BMIter iter, iter2;
+ BMVert *v;
+ BMLoop *nl;
+ BMFace *face, *curf = NULL;
+
+ /*this isn't the best thing in the world. it doesn't handle cases where there's
+ multiple faces yet. that might require a convexity test to figure out which
+ face is "best," and who knows what for non-manifold conditions.*/
+ for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) {
+ for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) {
+ if (v == v2) {
+ if (!curf || face->len < curf->len) curf = face;
+ }
+ }
+ }
+
+ if (curf) {
+ face = BM_Split_Face(bm, curf, v1, v2, &nl, NULL);
+
+ if (nf) *nf = face;
+ return nl ? nl->e : NULL;
+ }
+
+ return NULL;
+}
+/* calculates offset for co, based on fractal, sphere or smooth settings */
+static void alter_co(float *co, BMEdge *edge, subdparams *params, float perc,
+ BMVert *vsta, BMVert *vend)
+{
+ float vec1[3], fac;
+
+ if(params->beauty & B_SMOOTH) {
+ /* we calculate an offset vector vec1[], to be added to *co */
+ float len, fac, nor[3], nor1[3], nor2[3], smooth=params->smooth;
+
+ VecSubf(nor, vsta->co, vend->co);
+ len= 0.5f*Normalize(nor);
+
+ VECCOPY(nor1, vsta->no);
+ VECCOPY(nor2, vend->no);
+
+ /* cosine angle */
+ fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
+
+ vec1[0]= fac*nor1[0];
+ vec1[1]= fac*nor1[1];
+ vec1[2]= fac*nor1[2];
+
+ /* cosine angle */
+ fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
+
+ vec1[0]+= fac*nor2[0];
+ vec1[1]+= fac*nor2[1];
+ vec1[2]+= fac*nor2[2];
+
+ /* falloff for multi subdivide */
+ smooth *= sqrt(fabs(1.0f - 2.0f*fabs(perc)));
+
+ vec1[0]*= smooth*len;
+ vec1[1]*= smooth*len;
+ vec1[2]*= smooth*len;
+
+ co[0] += vec1[0];
+ co[1] += vec1[1];
+ co[2] += vec1[2];
+ }
+ else if(params->beauty & B_SPHERE) { /* subdivide sphere */
+ Normalize(co);
+ co[0]*= params->smooth;
+ co[1]*= params->smooth;
+ co[2]*= params->smooth;
+ }
+
+ if(params->beauty & B_FRACTAL) {
+ fac= params->fractal*VecLenf(vsta->co, vend->co);
+ vec1[0]= fac*(float)(0.5-BLI_drand());
+ vec1[1]= fac*(float)(0.5-BLI_drand());
+ vec1[2]= fac*(float)(0.5-BLI_drand());
+ VecAddf(co, co, vec1);
+ }
+}
+
+/* assumes in the edge is the correct interpolated vertices already */
+/* percent defines the interpolation, rad and flag are for special options */
+/* results in new vertex with correct coordinate, vertex normal and weight group info */
+static BMVert *bm_subdivide_edge_addvert(BMesh *bm, BMEdge *edge,BMEdge *oedge,
+ subdparams *params, float percent,
+ float percent2,
+ BMEdge **out,BMVert *vsta,BMVert *vend)
+{
+ BMVert *ev;
+// float co[3];
+
+ ev = BM_Split_Edge(bm, edge->v1, edge, out, percent);
+ BM_Vert_UpdateNormal(bm, ev);
+
+ BMO_SetFlag(bm, ev, ELE_INNER);
+
+ /* offset for smooth or sphere or fractal */
+ alter_co(ev->co, oedge, params, percent2, vsta, vend);
+
+#if 0 //TODO
+ /* clip if needed by mirror modifier */
+ if (edge->v1->f2) {
+ if ( edge->v1->f2 & edge->v2->f2 & 1) {
+ co[0]= 0.0f;
+ }
+ if ( edge->v1->f2 & edge->v2->f2 & 2) {
+ co[1]= 0.0f;
+ }
+ if ( edge->v1->f2 & edge->v2->f2 & 4) {
+ co[2]= 0.0f;
+ }
+ }
+#endif
+
+ return ev;
+}
+
+static BMVert *subdivideedgenum(BMesh *bm, BMEdge *edge, BMEdge *oedge,
+ int curpoint, int totpoint, subdparams *params,
+ BMEdge **newe, BMVert *vsta, BMVert *vend)
+{
+ BMVert *ev;
+ float percent, percent2 = 0.0f;
+
+ if (BMO_TestFlag(bm, edge, EDGE_PERCENT) && totpoint == 1)
+ percent = BMO_Get_MapFloat(bm, params->op,
+ "edgepercents", edge);
+ else {
+ percent= 1.0f/(float)(totpoint+1-curpoint);
+ percent2 = (float)curpoint / (float)(totpoint + 1);
+
+ }
+
+ ev= bm_subdivide_edge_addvert(bm, edge, oedge, params, percent,
+ percent2, newe, vsta, vend);
+ return ev;
+}
+
+static void bm_subdivide_multicut(BMesh *bm, BMEdge *edge, subdparams *params,
+ BMVert *vsta, BMVert *vend) {
+ BMEdge *eed = edge, *newe, temp = *edge;
+ BMVert *v;
+ int i, numcuts = params->numcuts;
+
+ for(i=0;i<numcuts;i++) {
+ v = subdivideedgenum(bm, eed, &temp, i, params->numcuts, params,
+ &newe, vsta, vend);
+ BMO_SetFlag(bm, v, SUBD_SPLIT);
+ BMO_SetFlag(bm, eed, SUBD_SPLIT);
+
+ BMO_SetFlag(bm, v, ELE_SPLIT);
+ BMO_SetFlag(bm, eed, ELE_SPLIT);
+ }
+}
+
+/*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 q_1edge_split(BMesh *bm, BMFace *face,
+ BMVert **verts, subdparams *params) {
+ BMFace *nf;
+ int i, add, numcuts = params->numcuts;
+
+ /*if it's odd, the middle face is a quad, otherwise it's a triangle*/
+ if (numcuts % 2==0) {
+ add = 2;
+ for (i=0; i<numcuts; i++) {
+ if (i == numcuts/2) add -= 1;
+ connect_smallest_face(bm, verts[i], verts[numcuts+add],
+ &nf);
+ }
+ } else {
+ add = 2;
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts+add],
+ &nf);
+ if (i == numcuts/2) {
+ add -= 1;
+ connect_smallest_face(bm, verts[i],
+ verts[numcuts+add],
+ &nf);
+ }
+ }
+
+ }
+}
+
+subdpattern q_1edge = {
+ {1, 0, 0, 0},
+ q_1edge_split,
+ 4,
+};
+
+
+/*
+
+v4---v3---v2
+| s |
+| |
+| |
+| s |
+v5---v0---v1
+
+*/
+
+static void q_2edge_op_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i],verts[(numcuts-i-1)+numcuts+2],
+ &nf);
+ }
+}
+
+subdpattern q_2edge_op = {
+ {1, 0, 1, 0},
+ q_2edge_op_split,
+ 4,
+};
+
+/*
+v6--------v5
+| |
+| |v4s
+| |v3s
+| s s |
+v7-v0--v1-v2
+
+*/
+static void q_2edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts+(numcuts-i)],
+ &nf);
+ }
+ connect_smallest_face(bm, verts[numcuts*2+3], verts[numcuts*2+1], &nf);
+}
+
+subdpattern q_2edge = {
+ {1, 1, 0, 0},
+ q_2edge_split,
+ 4,
+};
+
+/* s s
+v8--v7--v6-v5
+| |
+| v4 s
+| |
+| v3 s
+| s s |
+v9-v0--v1-v2
+
+*/
+static void q_3edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, add=0, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ if (i == numcuts/2) {
+ if (numcuts % 2 != 0) {
+ connect_smallest_face(bm, verts[numcuts-i-1+add],
+ verts[i+numcuts+1], &nf);
+ }
+ add = numcuts*2+2;
+ }
+ connect_smallest_face(bm, verts[numcuts-i-1+add],
+ verts[i+numcuts+1], &nf);
+ }
+
+ for (i=0; i<numcuts/2+1; i++) {
+ connect_smallest_face(bm, verts[i],verts[(numcuts-i)+numcuts*2+1],
+ &nf);
+ }
+}
+
+subdpattern q_3edge = {
+ {1, 1, 1, 0},
+ q_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 q_4edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ BMVert *v, *v1, *v2;
+ BMEdge *e, *ne, temp;
+ BMVert **lines;
+ int numcuts = params->numcuts;
+ int i, j, a, b, s=numcuts+2, totv=numcuts*4+4;
+
+ lines = MEM_callocN(sizeof(BMVert*)*(numcuts+2)*(numcuts+2),
+ "q_4edge_split");
+ /*build a 2-dimensional array of verts,
+ containing every vert (and all new ones)
+ in the face.*/
+
+ /*first line*/
+ for (i=0; i<numcuts+2; i++) {
+ lines[i] = verts[numcuts*3+2+(numcuts-i+1)];
+ }
+
+ /*last line*/
+ for (i=0; i<numcuts+2; i++) {
+ lines[(s-1)*s+i] = verts[numcuts+i];
+ }
+
+ /*first and last members of middle lines*/
+ for (i=0; i<numcuts; i++) {
+ a = i;
+ b = numcuts + 1 + numcuts + 1 + (numcuts - i - 1);
+
+ e = connect_smallest_face(bm, verts[a], verts[b], &nf);
+ if (!e) continue;
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+
+
+ v1 = lines[(i+1)*s] = verts[a];
+ v2 = lines[(i+1)*s + s-1] = verts[b];
+
+ temp = *e;
+ for (a=0; a<numcuts; a++) {
+ v = subdivideedgenum(bm, e, &temp, a, numcuts, params, &ne,
+ v1, v2);
+ BMO_SetFlag(bm, ne, ELE_INNER);
+ lines[(i+1)*s+a+1] = v;
+ }
+ }
+
+ for (i=1; i<numcuts+2; i++) {
+ for (j=1; j<numcuts+1; j++) {
+ a = i*s + j;
+ b = (i-1)*s + j;
+ e = connect_smallest_face(bm, lines[a], lines[b], &nf);
+ if (!e) continue;
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+ }
+ }
+
+ MEM_freeN(lines);
+}
+
+/* v3
+ / \
+ / \
+ / \
+ / \
+ / \
+v4--v0--v1--v2
+ s s
+*/
+static void t_1edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts+1], &nf);
+ }
+}
+
+subdpattern t_1edge = {
+ {1, 0, 0},
+ t_1edge_split,
+ 3,
+};
+
+/* v5
+ / \
+ / \ v4 s
+ / \
+ / \ v3 s
+ / \
+v6--v0--v1--v2
+ s s
+*/
+static void t_2edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ int i, numcuts = params->numcuts;
+
+ for (i=0; i<numcuts; i++) {
+ connect_smallest_face(bm, verts[i], verts[numcuts+numcuts-i], &nf);
+ }
+}
+
+subdpattern t_2edge = {
+ {1, 1, 0},
+ t_2edge_split,
+ 3,
+};
+
+
+/* v5
+ / \
+ s v6/---\ v4 s
+ / \ / \
+sv7/---v---\ v3 s
+ / \/ \/ \
+ v8--v0--v1--v2
+ s s
+*/
+static void t_3edge_split(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params)
+{
+ BMFace *nf;
+ BMEdge *e, *ne, temp;
+ BMVert ***lines, *v;
+ void *stackarr[1];
+ int i, j, a, b, numcuts = params->numcuts;
+
+ /*number of verts in each line*/
+ lines = MEM_callocN(sizeof(void*)*(numcuts+2), "triangle vert table");
+
+ lines[0] = (BMVert**) stackarr;
+ lines[0][0] = verts[numcuts*2+1];
+
+ lines[1+numcuts] = MEM_callocN(sizeof(void*)*(numcuts+2),
+ "triangle vert table 2");
+ for (i=0; i<numcuts; i++) {
+ lines[1+numcuts][1+i] = verts[i];
+ }
+ lines[1+numcuts][0] = verts[numcuts*3+2];
+ lines[1+numcuts][1+numcuts] = verts[numcuts];
+
+ for (i=0; i<numcuts; i++) {
+ lines[i+1] = MEM_callocN(sizeof(void*)*(2+i),
+ "triangle vert table row");
+ a = numcuts*2 + 2 + i;
+ b = numcuts + numcuts - i;
+ e = connect_smallest_face(bm, verts[a], verts[b], &nf);
+ if (!e) goto cleanup;
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+
+ lines[i+1][0] = verts[a];
+ lines[i+1][1+i] = verts[b];
+
+ temp = *e;
+ for (j=0; j<i; j++) {
+ v = subdivideedgenum(bm, e, &temp, j, i, params, &ne,
+ verts[a], verts[b]);
+ lines[i+1][j+1] = v;
+
+ BMO_SetFlag(bm, ne, ELE_INNER);
+ }
+ }
+
+
+/* v5
+ / \
+ s v6/---\ v4 s
+ / \ / \
+sv7/---v---\ v3 s
+ / \/ \/ \
+ v8--v0--v1--v2
+ s s
+*/
+ for (i=1; i<numcuts+1; i++) {
+ for (j=0; j<i; j++) {
+ e= connect_smallest_face(bm, lines[i][j], lines[i+1][j+1],
+ &nf);
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+
+ e= connect_smallest_face(bm,lines[i][j+1],lines[i+1][j+1],
+ &nf);
+
+ BMO_SetFlag(bm, e, ELE_INNER);
+ BMO_SetFlag(bm, nf, ELE_INNER);
+ }
+ }
+
+cleanup:
+ for (i=1; i<numcuts+2; i++) {
+ if (lines[i]) MEM_freeN(lines[i]);
+ }
+
+ MEM_freeN(lines);
+}
+
+subdpattern t_3edge = {
+ {1, 1, 1},
+ t_3edge_split,
+ 3,
+};
+
+
+subdpattern q_4edge = {
+ {1, 1, 1, 1},
+ q_4edge_split,
+ 4,
+};
+
+subdpattern *patterns[] = {
+ &q_1edge,
+ &q_2edge_op,
+ &q_4edge,
+ &q_3edge,
+ &q_2edge,
+ &t_1edge,
+ &t_2edge,
+ &t_3edge,
+};
+
+#define PLEN (sizeof(patterns) / sizeof(void*))
+
+typedef struct subd_facedata {
+ BMVert *start; subdpattern *pat;
+} subd_facedata;
+
+void esubdivide_exec(BMesh *bmesh, BMOperator *op)
+{
+ BMOpSlot *einput;
+ BMEdge *edge, **edges = NULL;
+ V_DECLARE(edges);
+ BMFace *face;
+ BMLoop *nl;
+ BMVert **verts = NULL;
+ V_DECLARE(verts);
+ BMIter fiter, liter;
+ subdpattern *pat;
+ subdparams params;
+ subd_facedata *facedata = NULL;
+ V_DECLARE(facedata);
+ float smooth, fractal;
+ int beauty;
+ int i, j, matched, a, b, numcuts;
+
+ BMO_Flag_Buffer(bmesh, op, "edges", SUBD_SPLIT);
+
+ numcuts = BMO_GetSlot(op, "numcuts")->data.i;
+ smooth = BMO_GetSlot(op, "smooth")->data.f;
+ fractal = BMO_GetSlot(op, "fractal")->data.f;
+ beauty = BMO_GetSlot(op, "beauty")->data.i;
+
+ einput = BMO_GetSlot(op, "edges");
+
+ /*first go through and tag edges*/
+ BMO_Flag_To_Slot(bmesh, op, "edges",
+ SUBD_SPLIT, BM_EDGE);
+
+ params.numcuts = numcuts;
+ params.op = op;
+ params.smooth = smooth;
+ params.fractal = fractal;
+ params.beauty = beauty;
+
+ BMO_Mapping_To_Flag(bmesh, op, "custompatterns",
+ FACE_CUSTOMFILL);
+
+ BMO_Mapping_To_Flag(bmesh, op, "edgepercents",
+ EDGE_PERCENT);
+
+ for (face=BMIter_New(&fiter, bmesh, BM_FACES_OF_MESH, NULL);
+ face; face=BMIter_Step(&fiter)) {
+ /*figure out which pattern to use*/
+
+ V_RESET(edges);
+ V_RESET(verts);
+ i = 0;
+ for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
+ nl; nl=BMIter_Step(&liter)) {
+ V_GROW(edges);
+ V_GROW(verts);
+ edges[i] = nl->e;
+ verts[i] = nl->v;
+ i++;
+ }
+
+ if (BMO_TestFlag(bmesh, face, FACE_CUSTOMFILL)) {
+ pat = BMO_Get_MapData(bmesh, op,
+ "custompatterns", face);
+ for (i=0; i<pat->len; i++) {
+ matched = 1;
+ for (j=0; j<pat->len; j++) {
+ a = (j + i) % pat->len;
+ if ((!!BMO_TestFlag(bmesh, edges[a], SUBD_SPLIT))
+ != (!!pat->seledges[j])) {
+ matched = 0;
+ break;
+ }
+ }
+ if (matched) {
+ V_GROW(facedata);
+ b = V_COUNT(facedata)-1;
+ facedata[b].pat = pat;
+ facedata[b].start = verts[i];
+ BMO_SetFlag(bmesh, face, SUBD_SPLIT);
+ break;
+ }
+ }
+ if (!matched) {
+ /*if no match, append null element to array.*/
+ V_GROW(facedata);
+ }
+
+ /*obvously don't test for other patterns matching*/
+ continue;
+ }
+
+ for (i=0; i<PLEN; i++) {
+ pat = patterns[i];
+ if (pat->len == face->len) {
+ for (a=0; a<pat->len; a++) {
+ matched = 1;
+ for (b=0; b<pat->len; b++) {
+ j = (b + a) % pat->len;
+ if ((!!BMO_TestFlag(bmesh, edges[j], SUBD_SPLIT))
+ != (!!pat->seledges[b])) {
+ matched = 0;
+ break;
+ }
+ }
+ if (matched) break;
+ }
+ if (matched) {
+ V_GROW(facedata);
+ BMO_SetFlag(bmesh, face, SUBD_SPLIT);
+ j = V_COUNT(facedata) - 1;
+ facedata[j].pat = pat;
+ facedata[j].start = verts[a];
+ break;
+ }
+ }
+ }
+ }
+
+ einput = BMO_GetSlot(op, "edges");
+
+ /*go through and split edges*/
+ for (i=0; i<einput->len; i++) {
+ edge = ((BMEdge**)einput->data.p)[i];
+ bm_subdivide_multicut(bmesh, edge,&params, edge->v1, edge->v2);
+ //BM_Split_Edge_Multi(bmesh, edge, numcuts);
+ }
+
+ //if (facedata) V_FREE(facedata);
+ //return;
+
+ i = 0;
+ for (face=BMIter_New(&fiter, bmesh, BM_FACES_OF_MESH, NULL);
+ face; face=BMIter_Step(&fiter)) {
+ /*figure out which pattern to use*/
+ V_RESET(verts);
+ if (BMO_TestFlag(bmesh, face, SUBD_SPLIT) == 0) continue;
+
+ pat = facedata[i].pat;
+ if (!pat) continue;
+
+ j = a = 0;
+ for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
+ nl; nl=BMIter_Step(&liter)) {
+ if (nl->v == facedata[i].start) {
+ a = j+1;
+ break;
+ }
+ j++;
+ }
+
+ for (j=0; j<face->len; j++) {
+ V_GROW(verts);
+ }
+
+ j = 0;
+ for (nl=BMIter_New(&liter, bmesh, BM_LOOPS_OF_FACE, face);
+ nl; nl=BMIter_Step(&liter)) {
+ b = (j-a+face->len) % face->len;
+ verts[b] = nl->v;
+ j += 1;
+ }
+
+ pat->connectexec(bmesh, face, verts, &params);
+ i++;
+ }
+
+ if (facedata) V_FREE(facedata);
+ if (edges) V_FREE(edges);
+ if (verts) V_FREE(verts);
+
+ BMO_Flag_To_Slot(bmesh, op, "outinner",
+ ELE_INNER, BM_ALL);
+ BMO_Flag_To_Slot(bmesh, op, "outsplit",
+ ELE_SPLIT, BM_ALL);
+}
+
+/*editmesh-emulating function*/
+void BM_esubdivideflag(Object *obedit, BMesh *bm, int flag, float smooth,
+ float fractal, int beauty, int numcuts, int seltype) {
+ BMOperator op;
+
+ BMO_InitOpf(bm, &op, "esubd edges=%he smooth=%f fractal=%f "
+ "beauty=%d numcuts=%d", flag, smooth, fractal,
+ beauty, numcuts);
+
+ BMO_Exec_Op(bm, &op);
+
+ if (seltype == SUBDIV_SELECT_INNER) {
+ BMOIter iter;
+ BMHeader *ele;
+ int i;
+
+ ele = BMO_IterNew(&iter,bm,&op, "outinner", BM_EDGE|BM_VERT);
+ for (; ele; ele=BMO_IterStep(&iter)) {
+ BM_Select(bm, ele, 1);
+ }
+ }
+ BMO_Finish_Op(bm, &op);
+}
+
+#if 0
+void BM_esubdivideflag_conv(Object *obedit,EditMesh *em,int selflag, float rad,
+ int flag, int numcuts, int seltype) {
+ BMesh *bm = editmesh_to_bmesh(em);
+ EditMesh *em2;
+
+ BM_esubdivideflag(obedit, bm, selflag, rad, flag, numcuts, seltype);
+ em2 = bmesh_to_editmesh(bm);
+
+ free_editMesh(em);
+ *em = *em2;
+ MEM_freeN(em2);
+ BM_Free_Mesh(bm);
+}
+#endif \ No newline at end of file
diff --git a/source/blender/bmesh/operators/subdivideop.h b/source/blender/bmesh/operators/subdivideop.h
new file mode 100644
index 00000000000..7bb471117d8
--- /dev/null
+++ b/source/blender/bmesh/operators/subdivideop.h
@@ -0,0 +1,38 @@
+#ifndef _SUBDIVIDEOP_H
+#define _SUBDIVIDEOP_H
+
+typedef struct subdparams {
+ int numcuts;
+ float smooth;
+ float fractal;
+ int beauty;
+ BMOperator *op;
+} subdparams;
+
+typedef void (*subd_pattern_fill_fp)(BMesh *bm, BMFace *face, BMVert **verts,
+ subdparams *params);
+
+/*
+note: this is a pattern-based edge subdivider.
+it tries to match a pattern to edge selections on faces,
+then executes functions to cut them.
+*/
+typedef struct subdpattern {
+ int seledges[20]; //selected edges mask, for splitting
+
+ /*verts starts at the first new vert cut, not the first vert in the
+ face*/
+ subd_pattern_fill_fp connectexec;
+ int len; /*total number of verts, before any subdivision*/
+} subdpattern;
+
+/*generic subdivision rules:
+
+ * two selected edges in a face should make a link
+ between them.
+
+ * one edge should do, what? make pretty topology, or just
+ split the edge only?
+*/
+
+#endif /* _SUBDIVIDEOP_H */ \ No newline at end of file
diff --git a/source/blender/bmesh/operators/triangulateop.c b/source/blender/bmesh/operators/triangulateop.c
new file mode 100644
index 00000000000..732a3a85860
--- /dev/null
+++ b/source/blender/bmesh/operators/triangulateop.c
@@ -0,0 +1,55 @@
+#include "MEM_guardedalloc.h"
+
+#include "BKE_utildefines.h"
+
+#include "bmesh.h"
+#include "bmesh_private.h"
+#include "BLI_arithb.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EDGE_NEW 1
+#define FACE_NEW 1
+
+void triangulate_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMFace *face, **newfaces = NULL;
+ V_DECLARE(newfaces);
+ float (*projectverts)[3] = NULL;
+ V_DECLARE(projectverts);
+ int i, lastlen=0, count = 0;
+
+ face = BMO_IterNew(&siter, bm, op, "faces", BM_FACE);
+ for (; face; face=BMO_IterStep(&siter)) {
+ if (lastlen < face->len) {
+ V_RESET(projectverts);
+ V_RESET(newfaces);
+ for (lastlen=0; lastlen<face->len; lastlen++) {
+ V_GROW(projectverts);
+ V_GROW(projectverts);
+ V_GROW(projectverts);
+ V_GROW(newfaces);
+ }
+ }
+
+ BM_Triangulate_Face(bm, face, projectverts, EDGE_NEW,
+ FACE_NEW, newfaces);
+
+ BMO_Insert_MapPointer(bm, op, "facemap",
+ face, face);
+ for (i=0; newfaces[i]; i++) {
+ BMO_Insert_MapPointer(bm, op, "facemap",
+ newfaces[i], face);
+
+ }
+ }
+
+ BMO_Flag_To_Slot(bm, op, "edgeout", EDGE_NEW, BM_EDGE);
+ BMO_Flag_To_Slot(bm, op, "faceout", FACE_NEW, BM_FACE);
+
+ V_FREE(projectverts);
+ V_FREE(newfaces);
+} \ No newline at end of file
diff --git a/source/blender/bmesh/operators/utils.c b/source/blender/bmesh/operators/utils.c
new file mode 100644
index 00000000000..77e0b7083e2
--- /dev/null
+++ b/source/blender/bmesh/operators/utils.c
@@ -0,0 +1,91 @@
+
+#include "MEM_guardedalloc.h"
+#include "BKE_customdata.h"
+#include "DNA_listBase.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include <string.h>
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+#include "BKE_global.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+
+#include "BLI_editVert.h"
+#include "mesh_intern.h"
+#include "ED_mesh.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+
+#include "bmesh.h"
+
+/*
+ * UTILS.C
+ *
+ * utility bmesh operators, e.g. transform,
+ * translate, rotate, scale, etc.
+ *
+*/
+
+void bmesh_makevert_exec(BMesh *bm, BMOperator *op) {
+ float vec[3];
+
+ BMO_Get_Vec(op, "co", vec);
+
+ BMO_SetFlag(bm, BM_Make_Vert(bm, vec, NULL), 1);
+ BMO_Flag_To_Slot(bm, op, "newvertout", 1, BM_VERT);
+}
+
+void bmesh_transform_exec(BMesh *bm, BMOperator *op) {
+ BMOIter iter;
+ BMVert *v;
+ float mat[4][4];
+
+ BMO_Get_Mat4(op, "mat", mat);
+
+ BMO_ITER(v, &iter, bm, op, "verts", BM_VERT) {
+ Mat4MulVecfl(mat, v->co);
+ }
+}
+
+/*this operator calls the transform operator, which
+ is a little complex, but makes it easier to make
+ sure the transform op is working, since initially
+ only this one will be used.*/
+void bmesh_translate_exec(BMesh *bm, BMOperator *op) {
+ BMOIter iter;
+ BMVert *v;
+ float mat[4][4], vec[3];
+
+ BMO_Get_Vec(op, "vec", vec);
+
+ Mat4One(mat);
+ VECCOPY(mat[3], vec);
+
+ BMO_CallOpf(bm, "transform mat=%m4 verts=%s", mat, op, "verts");
+}
+
+void bmesh_rotate_exec(BMesh *bm, BMOperator *op) {
+ BMOIter iter;
+ BMVert *v;
+ float mat[4][4], vec[3];
+
+ BMO_Get_Vec(op, "cent", vec);
+
+ /*there has to be a proper matrix way to do this, but
+ this is how editmesh did it and I'm too tired to think
+ through the math right now.*/
+ VecMulf(vec, -1);
+ BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
+
+ BMO_CallOpf(bm, "transform mat=%s verts=%s", op, "mat", op, "verts");
+
+ VecMulf(vec, -1);
+ BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
+}
+
diff --git a/source/blender/bmesh/tools/BME_bevel.c b/source/blender/bmesh/tools/BME_bevel.c
new file mode 100644
index 00000000000..543d64b6131
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_bevel.c
@@ -0,0 +1,918 @@
+/**
+ * BME_tools.c jan 2007
+ *
+ * Functions for changing the topology of a mesh.
+ *
+ * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Geoffrey Bantle and Levi Schooley.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "MTC_matrixops.h"
+#include "MTC_vectorops.h"
+
+#include "blendef.h"
+
+/* ------- Bevel code starts here -------- */
+
+BME_TransData_Head *BME_init_transdata(int bufsize) {
+ BME_TransData_Head *td;
+
+ td = MEM_callocN(sizeof(BME_TransData_Head), "BM transdata header");
+ td->gh = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp);
+ td->ma = BLI_memarena_new(bufsize);
+ BLI_memarena_use_calloc(td->ma);
+
+ return td;
+}
+
+void BME_free_transdata(BME_TransData_Head *td) {
+ BLI_ghash_free(td->gh,NULL,NULL);
+ BLI_memarena_free(td->ma);
+ MEM_freeN(td);
+}
+
+BME_TransData *BME_assign_transdata(BME_TransData_Head *td, BMesh *bm, BMVert *v,
+ float *co, float *org, float *vec, float *loc,
+ float factor, float weight, float maxfactor, float *max) {
+ BME_TransData *vtd;
+ int is_new = 0;
+
+ if (v == NULL) return NULL;
+
+ if ((vtd = BLI_ghash_lookup(td->gh, v)) == NULL && bm != NULL) {
+ vtd = BLI_memarena_alloc(td->ma, sizeof(*vtd));
+ BLI_ghash_insert(td->gh, v, vtd);
+ td->len++;
+ is_new = 1;
+ }
+
+ vtd->bm = bm;
+ vtd->v = v;
+ if (co != NULL) VECCOPY(vtd->co,co);
+ if (org == NULL && is_new) { VECCOPY(vtd->org,v->co); } /* default */
+ else if (org != NULL) VECCOPY(vtd->org,org);
+ if (vec != NULL) {
+ VECCOPY(vtd->vec,vec);
+ Normalize(vtd->vec);
+ }
+ vtd->loc = loc;
+
+ vtd->factor = factor;
+ vtd->weight = weight;
+ vtd->maxfactor = maxfactor;
+ vtd->max = max;
+
+ return vtd;
+}
+
+BME_TransData *BME_get_transdata(BME_TransData_Head *td, BMVert *v) {
+ BME_TransData *vtd;
+ vtd = BLI_ghash_lookup(td->gh, v);
+ return vtd;
+}
+
+/* a hack (?) to use the transdata memarena to allocate floats for use with the max limits */
+float *BME_new_transdata_float(BME_TransData_Head *td) {
+ return BLI_memarena_alloc(td->ma, sizeof(float));
+}
+
+static int BME_bevel_is_split_vert(BMLoop *l) {
+ /* look for verts that have already been added to the edge when
+ * beveling other polys; this can be determined by testing the
+ * vert and the edges around it for originality
+ */
+ if ((l->v->tflag1 & BME_BEVEL_ORIG)==0
+ && (l->e->tflag1 & BME_BEVEL_ORIG)
+ && (l->prev->e->tflag1 & BME_BEVEL_ORIG))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/* get a vector, vec, that points from v1->co to wherever makes sense to
+ * the bevel operation as a whole based on the relationship between v1 and v2
+ * (won't necessarily be a vec from v1->co to v2->co, though it probably will be);
+ * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */
+static int BME_bevel_get_vec(float *vec, BMVert *v1, BMVert *v2, BME_TransData_Head *td) {
+ BME_TransData *vtd1, *vtd2;
+
+ vtd1 = BME_get_transdata(td,v1);
+ vtd2 = BME_get_transdata(td,v2);
+ if (!vtd1 || !vtd2) {
+ //printf("BME_bevel_get_vec() got called without proper BME_TransData\n");
+ return -1;
+ }
+
+ /* compare the transform origins to see if we can use the vert co's;
+ * if they belong to different origins, then we will use the origins to determine
+ * the vector */
+ if (VecCompare(vtd1->org,vtd2->org,0.000001f)) {
+ VECSUB(vec,v2->co,v1->co);
+ if (VecLength(vec) < 0.000001f) {
+ VecMulf(vec,0);
+ }
+ return 0;
+ }
+ else {
+ VECSUB(vec,vtd2->org,vtd1->org);
+ if (VecLength(vec) < 0.000001f) {
+ VecMulf(vec,0);
+ }
+ return 1;
+ }
+}
+
+/* "Projects" a vector perpendicular to vec2 against vec1, such that
+ * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2.
+ * note: the direction, is_forward, is used in conjunction with up_vec to determine
+ * whether this is a convex or concave corner. If it is a concave corner, it will
+ * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards).
+ * vec1 is the vector to project onto (expected to be normalized)
+ * vec2 is the direction of projection (pointing away from vec1)
+ * up_vec is used for orientation (expected to be normalized)
+ * returns the length of the projected vector that lies along vec1 */
+static float BME_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward, BME_TransData_Head *td) {
+ float factor, vec3[3], tmp[3],c1,c2;
+
+ Crossf(tmp,vec1,vec2);
+ Normalize(tmp);
+ factor = Inpf(up_vec,tmp);
+ if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) {
+ Crossf(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */
+ }
+ else {
+ Crossf(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */
+ }
+ Normalize(vec3);
+ c1 = Inpf(vec3,vec1);
+ c2 = Inpf(vec1,vec1);
+ if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) {
+ factor = 0.0f;
+ }
+ else {
+ factor = c2/c1;
+ }
+
+ return factor;
+}
+
+/* BME_bevel_split_edge() is the main math work-house; its responsibilities are:
+ * using the vert and the loop passed, get or make the split vert, set its coordinates
+ * and transform properties, and set the max limits.
+ * Finally, return the split vert. */
+static BMVert *BME_bevel_split_edge(BMesh *bm, BMVert *v, BMVert *v1, BMLoop *l, float *up_vec, float value, BME_TransData_Head *td) {
+ BME_TransData *vtd, *vtd1, *vtd2;
+ BMVert *sv, *v2, *v3, *ov;
+ BMLoop *lv1, *lv2;
+ BMEdge *ne, *e1, *e2;
+ float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3];
+ int is_edge, forward, is_split_vert;
+
+ if (l == NULL) {
+ /* what you call operator overloading in C :)
+ * I wanted to use the same function for both wire edges and poly loops
+ * so... here we walk around edges to find the needed verts */
+ forward = 1;
+ is_split_vert = 0;
+ if (v->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 = bmesh_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 = BM_OtherEdgeVert(e1, v);
+ v3 = BM_OtherEdgeVert(e2, v);
+ if (v1 != v2 && v1 != v3) {
+ //printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n");
+ return NULL;
+ }
+ if (v1 == v2) {
+ v2 = v3;
+ }
+ else {
+ e1 = e2;
+ }
+ ov = BM_OtherEdgeVert(e1,v);
+ sv = BM_Split_Edge(bm,v,e1,&ne,0);
+ //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
+ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
+ //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
+ BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
+ sv->tflag1 |= BME_BEVEL_BEVEL;
+ ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
+ BME_bevel_get_vec(vec1,v1,v,td);
+ BME_bevel_get_vec(vec2,v2,v,td);
+ Crossf(t_up_vec,vec1,vec2);
+ Normalize(t_up_vec);
+ up_vec = t_up_vec;
+ }
+ else {
+ /* establish loop direction */
+ if (l->v == v) {
+ forward = 1;
+ lv1 = l->next;
+ lv2 = l->prev;
+ v1 = l->next->v;
+ v2 = l->prev->v;
+ }
+ else if (l->next->v == v) {
+ forward = 0;
+ lv1 = l;
+ lv2 = l->next->next;
+ v1 = l->v;
+ v2 = l->next->next->v;
+ }
+ else {
+ //printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n");
+ return NULL;
+ }
+
+ if (BME_bevel_is_split_vert(lv1)) {
+ is_split_vert = 1;
+ sv = v1;
+ if (forward) v1 = l->next->next->v;
+ else v1 = l->prev->v;
+ }
+ else {
+ is_split_vert = 0;
+ ov = BM_OtherEdgeVert(l->e,v);
+ sv = BM_Split_Edge(bm,v,l->e,&ne,0);
+ //BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
+ //BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
+ //BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
+ BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
+ sv->tflag1 |= BME_BEVEL_BEVEL;
+ ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
+ }
+
+ if (BME_bevel_is_split_vert(lv2)) {
+ if (forward) v2 = lv2->prev->v;
+ else v2 = lv2->next->v;
+ }
+ }
+
+ is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */
+ BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */
+ len = VecLength(vec1);
+ Normalize(vec1);
+
+ vtd = BME_get_transdata(td, sv);
+ vtd1 = BME_get_transdata(td, v);
+ vtd2 = BME_get_transdata(td,v1);
+
+ if (vtd1->loc == NULL) {
+ /* this is a vert with data only for calculating initial weights */
+ if (vtd1->weight < 0) {
+ vtd1->weight = 0;
+ }
+ scale = vtd1->weight/vtd1->factor;
+ if (!vtd1->max) {
+ vtd1->max = BME_new_transdata_float(td);
+ *vtd1->max = -1;
+ }
+ }
+ else {
+ scale = vtd1->weight;
+ }
+ vtd->max = vtd1->max;
+
+ if (is_edge && vtd1->loc != NULL) {
+ maxfactor = vtd1->maxfactor;
+ }
+ else {
+ maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td);
+ if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) {
+ maxfactor = vtd->maxfactor;
+ }
+ }
+
+ dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2;
+ if (is_edge || dis > maxfactor*value) {
+ dis = maxfactor*value;
+ }
+ VECADDFAC(sv->co,v->co,vec1,dis);
+ VECSUB(vec1,sv->co,vtd1->org);
+ dis = VecLength(vec1);
+ Normalize(vec1);
+ BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max);
+
+ return sv;
+}
+
+static float BME_bevel_set_max(BMVert *v1, BMVert *v2, float value, BME_TransData_Head *td) {
+ BME_TransData *vtd1, *vtd2;
+ float max, fac1, fac2, vec1[3], vec2[3], vec3[3];
+
+ BME_bevel_get_vec(vec1,v1,v2,td);
+ vtd1 = BME_get_transdata(td,v1);
+ vtd2 = BME_get_transdata(td,v2);
+
+ if (vtd1->loc == NULL) {
+ fac1 = 0;
+ }
+ else {
+ VECCOPY(vec2,vtd1->vec);
+ VecMulf(vec2,vtd1->factor);
+ if (Inpf(vec1, vec1)) {
+ Projf(vec2,vec2,vec1);
+ fac1 = VecLength(vec2)/value;
+ }
+ else {
+ fac1 = 0;
+ }
+ }
+
+ if (vtd2->loc == NULL) {
+ fac2 = 0;
+ }
+ else {
+ VECCOPY(vec3,vtd2->vec);
+ VecMulf(vec3,vtd2->factor);
+ if (Inpf(vec1, vec1)) {
+ Projf(vec2,vec3,vec1);
+ fac2 = VecLength(vec2)/value;
+ }
+ else {
+ fac2 = 0;
+ }
+ }
+
+ if (fac1 || fac2) {
+ max = VecLength(vec1)/(fac1 + fac2);
+ if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
+ *vtd1->max = max;
+ }
+ if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
+ *vtd2->max = max;
+ }
+ }
+ else {
+ max = -1;
+ }
+
+ return max;
+}
+
+static BMVert *BME_bevel_wire(BMesh *bm, BMVert *v, float value, int res, int options, BME_TransData_Head *td) {
+ BMVert *ov1, *ov2, *v1, *v2;
+
+ ov1 = BM_OtherEdgeVert(v->edge, v);
+ ov2 = BM_OtherEdgeVert(bmesh_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) {
+ bmesh_jekv;
+
+ //void BM_Collapse_Vert(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, int calcnorm){
+ //hrm, why is there a fac here? it just removes a vert
+ BM_Collapse_Vert(bm, v->edge, v, 1.0, 0);
+ //bmesh_jekv(bm,v->edge,v);
+ }
+
+ return v1;
+}
+
+static BMLoop *BME_bevel_edge(BMesh *bm, BMLoop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
+ BMVert *v1, *v2, *kv;
+ BMLoop *kl=NULL, *nl;
+ BMEdge *e;
+ BMFace *f;
+
+ f = l->f;
+ e = l->e;
+
+ if ((l->e->tflag1 & BME_BEVEL_BEVEL) == 0
+ && ((l->v->tflag1 & BME_BEVEL_BEVEL) || (l->next->v->tflag1 & BME_BEVEL_BEVEL)))
+ { /* sanity check */
+ return l;
+ }
+
+ /* checks and operations for prev edge */
+ /* first, check to see if this edge was inset previously */
+ if ((l->prev->e->tflag1 & BME_BEVEL_ORIG) == 0
+ && (l->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
+ kl = l->prev->radial.next->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) {
+ BM_Split_Face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
+ bmesh_jfke(bm,((BMLoop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+
+ }
+ else {
+ BM_Split_Face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
+ bmesh_jfke(bm,((BMLoop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+ }
+ l = l->prev;
+ }
+
+ /* checks and operations for the next edge */
+ /* first, check to see if this edge was inset previously */
+ if ((l->next->e->tflag1 & BME_BEVEL_ORIG) == 0
+ && (l->next->v->tflag1 & BME_BEVEL_NONMAN) == 0) {
+ kl = l->next->radial.next->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) {
+ BM_Split_Face(bm,kl->f,kl->prev->v,kl->next->v,&nl,kl->prev->e);
+ bmesh_jfke(bm,((BMLoop*)kl->prev->radial.next->data)->f,kl->f,kl->prev->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+ }
+ else {
+ BM_Split_Face(bm,kl->f,kl->next->next->v,kl->v,&nl,kl->next->e);
+ bmesh_jfke(bm,((BMLoop*)kl->next->radial.next->data)->f,kl->f,kl->next->e);
+ BM_Collapse_Vert(bm, kl->e, kv, 1.0);
+ //BME_JEKV(bm,kl->e,kv);
+ }
+ }
+
+ if ((v1->tflag1 & BME_BEVEL_NONMAN)==0 || (v2->tflag1 & BME_BEVEL_NONMAN)==0) {
+ BM_Split_Face(bm,f,v2,v1,&l,e);
+ l->e->tflag1 = BME_BEVEL_BEVEL;
+ l = l->radial.next->data;
+ }
+
+ if (l->f != f){
+ //printf("Whoops! You got something out of order in BME_bevel_edge()!\n");
+ }
+
+ return l;
+}
+
+static BMLoop *BME_bevel_vert(BMesh *bm, BMLoop *l, float value, int options, float *up_vec, BME_TransData_Head *td) {
+ BMVert *v1, *v2;
+ BMFace *f;
+
+ /* get/make the first vert to be used in SFME */
+ /* may need to split the previous edge */
+ v1 = BME_bevel_split_edge(bm,l->v,NULL,l->prev,up_vec,value,td);
+
+ /* get/make the second vert to be used in SFME */
+ /* may need to split this edge (so move l) */
+ l = l->prev;
+ v2 = BME_bevel_split_edge(bm,l->next->v,NULL,l->next,up_vec,value,td);
+ l = l->next->next;
+
+ /* "cut off" this corner */
+ f = BM_Split_Face(bm,l->f,v2,v1,NULL,l->e);
+
+ return l;
+}
+
+/**
+ * BME_bevel_poly
+ *
+ * Polygon inset tool:
+ *
+ * Insets a polygon/face based on the tflag1's of its vertices
+ * and edges. Used by the bevel tool only, for now.
+ * The parameter "value" is the distance to inset (should be negative).
+ * The parameter "options" is not currently used.
+ *
+ * Returns -
+ * A BMFace pointer to the resulting inner face.
+*/
+static BMFace *BME_bevel_poly(BMesh *bm, BMFace *f, float value, int options, BME_TransData_Head *td) {
+ BMLoop *l, *ol;
+ BME_TransData *vtd1, *vtd2;
+ float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1;
+ int len, i;
+
+ up_vec[0] = 0.0f;
+ up_vec[1] = 0.0f;
+ up_vec[2] = 0.0f;
+ /* find a good normal for this face (there's better ways, I'm sure) */
+ ol = f->loopbase;
+ l = ol->next;
+ for (i=0,ol=f->loopbase,l=ol->next; l->next!=ol; l=l->next) {
+ BME_bevel_get_vec(vec1,l->next->v,ol->v,td);
+ BME_bevel_get_vec(vec2,l->v,ol->v,td);
+ Crossf(vec3,vec2,vec1);
+ VECADD(up_vec,up_vec,vec3);
+ i++;
+ }
+ VecMulf(up_vec,1.0f/i);
+ Normalize(up_vec);
+
+ for (i=0,len=f->len; i<len; i++,l=l->next) {
+ if ((l->e->tflag1 & BME_BEVEL_BEVEL) && (l->e->tflag1 & BME_BEVEL_ORIG)) {
+ max = 1.0f;
+ l = BME_bevel_edge(bm, l, value, options, up_vec, td);
+ }
+
+ else if ((l->v->tflag1 & BME_BEVEL_BEVEL) && (l->v->tflag1 & BME_BEVEL_ORIG) && (l->prev->e->tflag1 & BME_BEVEL_BEVEL) == 0) {
+ max = 1.0f;
+ l = BME_bevel_vert(bm, l, value, options, up_vec, td);
+ }
+ }
+
+ /* max pass */
+ if (value > 0.5 && max > 0) {
+ max = -1;
+ for (i=0,len=f->len; i<len; i++,l=l->next) {
+ if ((l->e->tflag1 & BME_BEVEL_BEVEL) || (l->e->tflag1 & BME_BEVEL_ORIG)) {
+ BME_bevel_get_vec(vec1,l->v,l->next->v,td);
+ vtd1 = BME_get_transdata(td,l->v);
+ vtd2 = BME_get_transdata(td,l->next->v);
+ if (vtd1->loc == NULL) {
+ fac1 = 0;
+ }
+ else {
+ VECCOPY(vec2,vtd1->vec);
+ VecMulf(vec2,vtd1->factor);
+ if (Inpf(vec1, vec1)) {
+ Projf(vec2,vec2,vec1);
+ fac1 = VecLength(vec2)/value;
+ }
+ else {
+ fac1 = 0;
+ }
+ }
+ if (vtd2->loc == NULL) {
+ fac2 = 0;
+ }
+ else {
+ VECCOPY(vec3,vtd2->vec);
+ VecMulf(vec3,vtd2->factor);
+ if (Inpf(vec1, vec1)) {
+ Projf(vec2,vec3,vec1);
+ fac2 = VecLength(vec2)/value;
+ }
+ else {
+ fac2 = 0;
+ }
+ }
+ if (fac1 || fac2) {
+ max = VecLength(vec1)/(fac1 + fac2);
+ if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
+ *vtd1->max = max;
+ }
+ if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
+ *vtd2->max = max;
+ }
+ }
+ }
+ }
+ }
+
+ return l->f;
+}
+
+static void BME_bevel_add_vweight(BME_TransData_Head *td, BMesh *bm, BMVert *v, float weight, float factor, int options) {
+ BME_TransData *vtd;
+
+ if (v->tflag1 & BME_BEVEL_NONMAN) return;
+ v->tflag1 |= BME_BEVEL_BEVEL;
+ if ( (vtd = BME_get_transdata(td, v)) ) {
+ if (options & BME_BEVEL_EMIN) {
+ vtd->factor = 1.0;
+ if (vtd->weight < 0 || weight < vtd->weight) {
+ vtd->weight = weight;
+ }
+ }
+ else if (options & BME_BEVEL_EMAX) {
+ vtd->factor = 1.0;
+ if (weight > vtd->weight) {
+ vtd->weight = weight;
+ }
+ }
+ else if (vtd->weight < 0) {
+ vtd->factor = factor;
+ vtd->weight = weight;
+ }
+ else {
+ vtd->factor += factor; /* increment number of edges with weights (will be averaged) */
+ vtd->weight += weight; /* accumulate all the weights */
+ }
+ }
+ else {
+ /* we'll use vtd->loc == NULL to mark that this vert is not moving */
+ vtd = BME_assign_transdata(td, bm, v, v->co, NULL, NULL, NULL, factor, weight, -1, NULL);
+ }
+}
+
+
+static bevel_init_verts(BMesh *bm, int options, BME_TransData_Head *td){
+ BMVert *v;
+ float weight;
+ for(v=bm->verts.first; v; v=v->next){
+ weight = 0.0;
+ if(!(v->tflag1 & BME_BEVEL_NONMAN)){
+ if(options & BME_BEVEL_SELECT){
+ if(v->flag & SELECT) weight = 1.0;
+ }
+ else if(options & BME_BEVEL_WEIGHT) weight = v->bweight;
+ else weight = 1.0;
+ if(weight > 0.0){
+ v->tflag1 |= BME_BEVEL_BEVEL;
+ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 1.0,weight, -1, NULL);
+ }
+ }
+ }
+}
+static bevel_init_edges(BMesh *bm, int options, BME_TransData_Head *td){
+ BMEdge *e;
+ int count;
+ float weight;
+ for( e = BM_first_element(bm, BME_EDGE); e; e = BM_next_element(bm, BME_EDGE, e)){
+ weight = 0.0;
+ if(!(e->tflag1 & BME_BEVEL_NONMAN)){
+ if(options & BME_BEVEL_SELECT){
+ if(e->flag & SELECT) weight = 1.0;
+ }
+ else if(options & BME_BEVEL_WEIGHT){
+ weight = e->bweight;
+ }
+ else{
+ weight = 1.0;
+ }
+ if(weight > 0.0){
+ e->tflag1 |= BME_BEVEL_BEVEL;
+ e->v1->tflag1 |= BME_BEVEL_BEVEL;
+ e->v2->tflag1 |= BME_BEVEL_BEVEL;
+ BME_bevel_add_vweight(td, bm, e->v1, weight, 1.0, options);
+ BME_bevel_add_vweight(td, bm, e->v2, weight, 1.0, options);
+ }
+ }
+ }
+
+ /*clean up edges with 2 faces that share more than one edge*/
+ for( e = BM_first_element(bm, BME_EDGE); e; e = BM_next_element(bm, BME_EDGE, e)){
+ if(e->tflag1 & BME_BEVEL_BEVEL){
+ count = BM_face_sharededges(e->loop->f, ((BMLoop*)e->loop->radial.next->data)->f);
+ if(count > 1) e->tflag1 &= ~BME_BEVEL_BEVEL;
+ }
+ }
+}
+static BMesh *BME_bevel_initialize(BMesh *bm, int options, int defgrp_index, float angle, BME_TransData_Head *td){
+
+ BMVert *v, *v2;
+ BMEdge *e, *curedge;
+ BMFace *f;
+ BMIter iter;
+ int wire, len;
+
+ for (v = BMIter_New(&iter, bm, BM_VERTS, nm); v; v = BMIter_Step(&iter)) v->tflag1 = 0;
+ for (e = BMIter_New(&iter, bm, BM_EDGES, nm); e; e = BMIter_Step(&iter)) e->tflag1 = 0;
+ for (f = BMIter_New(&iter, bm, BM_FACES, nm); f; f = BMIter_Step(&iter)) f->tflag1 = 0;
+
+ /*tag non-manifold geometry*/
+ for (v = BMIter_New(&iter, bm, BM_VERTS, nm); v; v = BMIter_Step(&iter)) {
+ v->tflag1 = BME_BEVEL_ORIG;
+ if(v->edge){
+ BME_assign_transdata(td, bm, v, v->co, v->co, NULL, NULL, 0, -1, -1, NULL);
+ if (BM_Nonmanifold_Vert(bm,v)) v->tflag1 |= BME_BEVEL_NONMAN;
+ /*test wire vert*/
+ len = bmesh_cycle_length(bmesh_disk_getpointer(v->edge,v));
+ if(len == 2 && BME_wirevert(bm, v)) v->tflag1 &= ~BME_BEVEL_NONMAN;
+ }else v->tflag1 |= BME_BEVEL_NONMAN;
+ }
+
+ for (e = BMIter_New(&iter, bm, BM_EDGES, nm); e; e = BMIter_Step(&iter)) {
+ e->tflag1 = BME_BEVEL_ORIG;
+ if (e->loop == NULL || BME_cycle_length(&(e->loop->radial)) > 2){
+ e->v1->tflag1 |= BME_BEVEL_NONMAN;
+ e->v2->tflag1 |= BME_BEVEL_NONMAN;
+ e->tflag1 |= BME_BEVEL_NONMAN;
+ }
+ if((e->v1->tflag1 & BME_BEVEL_NONMAN) || (e->v2->tflag1 & BME_BEVEL_NONMAN)) e->tflag1 |= BME_BEVEL_NONMAN;
+ }
+
+ for (f = BMIter_New(&iter, bm, BM_FACES, nm); f; f = BMIter_Step(&iter))
+ f->tflag1 = BME_BEVEL_ORIG;
+ if(options & BME_BEVEL_VERT) bevel_init_verts(bm, options, td);
+ else bevel_init_edges(bm, options, td);
+ return bm;
+
+}
+static BMesh *BME_bevel_reinitialize(BMesh *bm)
+{
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ for (v = BMIter_New(bm, BM_VERTS, NULL); v; v = BMIter_Step(bm)){
+ v->tflag1 |= BME_BEVEL_ORIG;
+ v->tflag2 = 0;
+ }
+ for (e = BMIter_New(bm, BM_EDGES, NULL); e; e = BMIter_Step(bm)){
+ e->tflag1 |= BME_BEVEL_ORIG;
+ }
+ for (f = BMIter_New(bm, BM_FACES, NULL); f; f = BMIter_Step(bm)){
+ f->tflag1 |= BME_BEVEL_ORIG;
+ }
+ return bm;
+
+}
+
+/**
+ * BME_bevel_mesh
+ *
+ * Mesh beveling tool:
+ *
+ * Bevels an entire mesh. It currently uses the tflag1's of
+ * its vertices and edges to track topological changes.
+ * The parameter "value" is the distance to inset (should be negative).
+ * The parameter "options" is not currently used.
+ *
+ * Returns -
+ * A BMesh pointer to the BM passed as a parameter.
+*/
+
+static BMMesh *BME_bevel_mesh(BMMesh *bm, float value, int res, int options, int defgrp_index, BME_TransData_Head *td) {
+ BMVert *v, *nv;
+ BMEdge *e, *curedge, *ne;
+ BMLoop *l, *l2;
+ BMFace *f, *nf;
+
+ BMeshIter verts;
+ BMeshIter edges;
+ BMeshIter loops;
+ BMeshIter faces;
+
+ unsigned int i, len;
+
+ /*bevel polys*/
+ for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f; f = BMeshIter_step(faces)){
+ if(bmesh_test_flag(f, BME_BEVEL_ORIG){
+ bevel_poly(bm,f,value,options,td);
+ }
+ }
+ /*get rid of beveled edges*/
+ for(e = BMeshIter_init(edges, BM_EDGES, bm, 0); e;){
+ ne = BMeshIter_step(edges);
+ if( bmesh_test_flag(e, BME_BEVEL_BEVEL) && bmesh_test_flag(e, BME_BEVEL_ORIG) ) bmesh_join_faces(bm, e->loop->f, ((BMLoop*)e->loop->radial.next->data)->f, e, 1);
+ e = ne;
+ }
+ /*link up corners and clip*/
+ for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v;){
+ nv = BMeshIter_step(verts)
+ if( bmesh_test_flag(v, BME_BEVEL_ORIG) && bmesh_test_flag(v, BME_BEVEL_BEVEL)){
+ curedge = v->edge;
+ do{
+ l = curedge->loop;
+ l2 = l->radial.next->data;
+ if(l->v != v) l = l->next;
+ if(l2->v != v) l2 = l2->next;
+ if(l->f->len > 3) BM_split_face(bm,l->f,l->next->v,l->prev->v,&l,l->e); /* clip this corner off */
+ if(l2->f->len > 3) BM_split_face(bm,l2->f,l2->next->v,l2->prev->v,&l,l2->e); /* clip this corner off */
+ curedge = BM_edge_of_vert(curedge, v);
+ }while(curedge != v->edge);
+ BM_dissolve_disk(bm,v);
+ }
+ v = nv;
+ }
+
+ /*Debug print, remove*/
+ for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f;){
+ if(f->len == 2){
+ printf("warning");
+ }
+ }
+
+ return bm;
+}
+
+BMesh *BME_bevel(BMMesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) {
+ BMVert *v;
+ BMEdge *e;
+ BMIter *verts;
+
+ BME_TransData_Head *td;
+ BME_TransData *vtd;
+ int i;
+ double fac=1, d;
+
+
+ td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE);
+ /* recursion math courtesy of Martin Poirier (theeth) */
+ for (i=0; i<res-1; i++) {
+ if (i==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * i * 2.0f);
+ }
+ d = 1.0f/fac;
+
+
+ for (i=0; i<res || (res==0 && i==0); i++) {
+ BME_bevel_initialize(bm, options, defgrp_index, angle, td);
+ //if (i != 0) BME_bevel_reinitialize(bm);
+ bmesh_begin_edit(bm);
+ BME_bevel_mesh(bm,(float)d,res,options,defgrp_index,td);
+ bmesh_end_edit(bm);
+ if (i==0) d /= 3; else d /= 2;
+ }
+
+ BME_model_begin(bm);
+ BME_tesselate(bm);
+ BME_model_end(bm);
+
+
+ /*interactive preview?*/
+ if (rtd) {
+ *rtd = td;
+ return bm;
+ }
+
+ /* otherwise apply transforms */
+ for( v = BMeshIter_init(verts); v; v = BMeshIter_step(verts)){
+ if ( (vtd = BME_get_transdata(td, v)) ) {
+ if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) {
+ d = *vtd->max;
+ }
+ else {
+ d = value;
+ }
+ VECADDFAC(v->co,vtd->org,vtd->vec,vtd->factor*d);
+ }
+ v->tflag1 = 0;
+ }
+
+ BME_free_transdata(td);
+ return bm;
+}
diff --git a/source/blender/bmesh/tools/BME_dupe_ops.c b/source/blender/bmesh/tools/BME_dupe_ops.c
new file mode 100644
index 00000000000..533e278ea68
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_dupe_ops.c
@@ -0,0 +1,318 @@
+/*
+ * BME_DUPLICATE.C
+ *
+ * This file contains functions for duplicating, copying, and splitting
+ * elements from a bmesh.
+ *
+ */
+
+/*
+ * COPY VERTEX
+ *
+ * Copy an existing vertex from one bmesh to another.
+ *
+*/
+
+static BMVert *copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash)
+{
+ BMVert *target_vertex = NULL;
+
+ /*create a new vertex*/
+ target_vertex = BM_Make_Vert(target, source_vertex->co, NULL);
+
+ /*insert new vertex into the vert hash*/
+ BLI_ghash_insert(vhash, source_vertex, target_vertex);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data);
+
+ /*Copy Markings*/
+ if(BM_Is_Selected((BMHeader*)source_vertex)) BM_Select_Vert(target_mesh, target_vertex, 1);
+ if(BM_Is_Hidden((BMHeader*)source_vertex)) BM_Mark_Hidden((BMHeader*)target_vertex, 1);
+
+ BMO_SetFlag(target_mesh, (BMHeader*)target_vertex, DUPE_NEW);
+
+ return target_vertex;
+}
+
+/*
+ * COPY EDGE
+ *
+ * Copy an existing edge from one bmesh to another.
+ *
+*/
+
+static BMEdge *copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash)
+{
+ BMEdge *target_edge = NULL;
+ BMVert *target_vert1, *target_vert2;
+
+ /*lookup v1 and v2*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
+ target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
+
+ /*create a new edge*/
+ target_edge = BM_Make_Edge(target_mesh, target_vert1, target_vert2, NULL, 0);
+
+ /*insert new edge into the edge hash*/
+ BLI_ghash_insert(ehash, source_edge, target_edge);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data);
+
+ /*copy flags*/
+ if(BM_Is_Selected((BMHeader*) source_edge)) BM_Select_Edge(target_mesh, target_edge, 1);
+ if(BM_Is_Hidden((BMHeader*) source_edge)) BM_Mark_Hidden(target_mesh, target_edge, 1);
+ if(BM_Is_Sharp((BMHeader*) source_edge)) BM_Mark_Sharp(target_edge, 1);
+ if(BM_Is_Seam((BMHeader*) source_edge)) BM_Mark_Seam(target_edge, 1);
+ if(BM_Is_Fgon((BMHeader*) source_edge)) BM_Mark_Fgon(target_edge, 1);
+
+ BMO_SetFlag(target_mesh, (BMHeader*)target_edge, DUPE_NEW);
+
+ return target_edge;
+}
+
+/*
+ * COPY FACE
+ *
+ * Copy an existing face from one bmesh to another.
+ *
+*/
+
+static BMFace *copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash)
+{
+ BMEdge *target_edge;
+ BMVert *target_vert1, *target_vert2;
+ BMLoop *source_loop, *target_loop;
+ BMFace *target_face = NULL;
+ int i;
+
+ /*lookup the first and second verts*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_face->loopbase->v);
+ target_vert2 = BLI_ghash_lookup(vhash, source_face->loopbase->next->v);
+
+ /*lookup edges*/
+ i = 0;
+ source_loop = source_face->loopbase;
+ do{
+ edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
+ i++;
+ source_loop = source_loop->next;
+ }while(source_loop != source_face->loopbase);
+
+ /*create new face*/
+ target_face = BM_Make_Ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0);
+
+ /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/
+ CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data);
+
+ /*copy flags*/
+ if(BM_Is_Selected((BMHeader*)source_face)) BM_Select_face(target, target_face, 1);
+ if(BM_Is_Hidden((BMHeader*)source_face)) BM_Mark_Hidden((BMHeader*)target_face, 1);
+
+ /*mark the face for output*/
+ BMO_SetFlag(target_mesh, (BMHeader*)target_face, DUPE_NEW);
+
+ /*copy per-loop custom data*/
+ source_loop = source_face->loopbase;
+ target_loop = target_face->loopbase;
+ do{
+ CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data);
+ source_loop = source_loop->next;
+ target_loop = target_loop->next;
+ }while(source_loop != source_face->loopbase);
+
+ return target_face;
+}
+
+/*
+ * COPY MESH
+ *
+ * Internal Copy function.
+*/
+
+/*local flag defines*/
+
+#define DUPE_INPUT 1 /*input from operator*/
+#define DUPE_NEW 2
+#define DUPE_DONE 3
+
+static void copy_mesh(BMMesh *source, BMMesh *target)
+{
+
+ BMVert *v = NULL;
+ BMEdge *e = NULL, **edar = NULL;
+ BMLoop *l = NULL;
+ BMFace *f = NULL;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BMIter loops;
+
+ GHash *vhash;
+ GHash *ehash;
+
+ int maxlength = 0, flag;
+
+ /*initialize pointer hashes*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp);
+
+ /*initialize edge pointer array*/
+ for(f = BMIter_New(&faces, source, BM_FACES, source, 0, NULL); f; f = BMIter_Step(&faces)){
+ if(f->len > maxlength) maxlength = f->len;
+ }
+ edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array");
+
+
+ /*first we dupe all flagged faces and their elements from source*/
+ for(f = BMIter_New(&faces, source, BM_FACES, source, 0, NULL); f; f= BMIter_Step(&faces)){
+ if(BMO_TestFlag(source, (BMHeader*)f, DUPE_INPUT)){
+ /*vertex pass*/
+ for(v = BMIter_New(&verts, source, BM_VERT_OF_FACE, f, 0, NULL); v; v = BMIter_Step(&verts)){
+ if(!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE)){
+ copy_vertex(source,v, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*edge pass*/
+ for(e = BMIter_New(&edges, source, BM_EDGE_OF_FACE, f, 0, NULL); e; e = BMeshIter_step(&edges)){
+ if(!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE)){
+ copy_edge(source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+ copy_face(source, f, target, edar, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)f, DUPE_DONE);
+ }
+ }
+
+ /*now we dupe all the edges*/
+ for(e = BMIter_New(&edges, source, BM_EDGES, source, 0, NULL); e; e = BMIter_Step(&edges)){
+ if(BMO_TestFlag(source, (BMHeader*)e, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)e, DUPE_DONE))){
+ /*make sure that verts are copied*/
+ if(!BMO_TestFlag(source, (BMHeader*)e->v1, DUPE_DONE){
+ copy_vertex(source, e->v1, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v1, DUPE_DONE);
+ }
+ if(!BMO_TestFlag(source, (BMHeader*)e->v2, DUPE_DONE){
+ copy_vertex(source, e->v2, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)e->v2, DUPE_DONE);
+ }
+ /*now copy the actual edge*/
+ copy_edge(source, e, target, vhash, ehash);
+ BMO_SetFlag(source, (BMHeader*)e, DUPE_DONE);
+ }
+ }
+
+ /*finally dupe all loose vertices*/
+ for(v = BMIter_New(&verts, source, BM_VERTS, source, 0, NULL); v; v = BMIter_Step(&verts)){
+ if(BMO_TestFlag(source, (BMHeader*)v, DUPE_INPUT) && (!BMO_TestFlag(source, (BMHeader*)v, DUPE_DONE))){
+ copy_vertex(source, v, target, vhash);
+ BMO_SetFlag(source, (BMHeader*)v, DUPE_DONE);
+ }
+ }
+
+ /*free pointer hashes*/
+ BLI_ghash_free(vhash, NULL, NULL);
+ BLI_ghash_free(ehash, NULL, NULL);
+
+ /*free edge pointer array*/
+ if(edar)
+ MEM_freeN(edar);
+}
+/*
+BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4])
+{
+ BMMesh *target = NULL;
+ target = bmesh_make_mesh(allocsize);
+
+
+ CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+
+ CustomData_bmesh_init_pool(&target->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&target->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&target->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&target->pdata, allocsize[3]);
+
+ bmesh_begin_edit(bm);
+ bmesh_begin_edit(target);
+
+ bmesh_copy_mesh(bm, target, 0);
+
+ bmesh_end_edit(bm);
+ bmesh_end_edit(target);
+
+ return target;
+
+}
+*/
+
+void dupeop_exec(BMMesh *bm, BMOperator *op)
+{
+ BMOperator *dupeop = op;
+ BMOpSlot *vinput, *einput, *finput, *vnew, *enew, *fnew;
+ int i;
+
+ vinput = BMO_Get_Slot(dupeop, BMOP_DUPE_VINPUT);
+ einput = BMO_Get_Slot(dupeop, BMOP_DUPE_EINPUT);
+ finput = BMO_Get_Slot(dupeop, BMOP_DUPE_FINPUT);
+
+ /*go through vinput, einput, and finput and flag elements with private flags*/
+ BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_VINPUT, DUPE_INPUT);
+ BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_EINPUT, DUPE_INPUT);
+ BMO_Flag_Buffer(bm, dupeop, BMOP_DUPE_FINPUT, DUPE_INPUT);
+
+ /*use the internal copy function*/
+ copy_mesh(bm, bm);
+
+ /*Output*/
+ /*First copy the input buffers to output buffers - original data*/
+ BMO_Copy_Opslot_Buffer_Alloc(dupeop, vinput, BMO_Get_Slot(dupeop, BMOP_DUPE_VORIGINAL));
+ BMO_Copy_Opslot_Buffer_Alloc(dupeop, einput, BMO_Get_Slot(dupeop, BMOP_DUPE_EORIGINAL));
+ BMO_Copy_Opslot_Buffer_Alloc(dupeop, finput, BMO_Get_Slot(dupeop, BMOP_DUPE_FORIGINAL));
+
+ /*Now alloc the new output buffers*/
+ BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_VNEW, DUPE_NEW, BMESH_VERT);
+ BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_ENEW, DUPE_NEW, BMESH_EDGE);
+ BMO_Flag_To_Slot(bm, dupeop, BMOP_DUPE_FNEW, DUPE_NEW, BMESH_FACE);
+}
+
+void splitop_exec(BMMesh *bm, BMOperator *op)
+{
+ BMOperator *splitop = op;
+ BMOperator dupeop;
+ BMOperator delop;
+
+ /*initialize our sub-operators*/
+ BMO_Init_Op(&dupeop, BMOP_DUPE);
+ BMO_Init_Op(&delop, BMOP_DEL);
+
+ BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_VINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_VINPUT));
+ BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_EINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_EINPUT));
+ BMO_Connect(BMO_Get_Slot(splitop, BMOP_SPLIT_FINPUT),BMO_Get_Slot(&dupeop, BMOP_DUPE_FINPUT));
+
+ BMO_Exec_Op(&dupeop);
+
+ /*connect outputs of dupe to delete*/
+ BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_VORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_VINPUT));
+ BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_EORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_EINPUT));
+ BMO_Connect(BMO_Get_Slot(&dupeop, BMOP_DUPE_FORIGINAL), BMO_Get_Slot(&delop, BMOP_DEL_FINPUT));
+
+ BMO_Exec_Op(&delop);
+
+ /*now we make our outputs by copying the dupe outputs*/
+ BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_VNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_VOUTPUT));
+ BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_ENEW), BMO_Get_Slot(splitop, BMOP_SPLIT_EOUTPUT));
+ BMO_Copy_Buffer_Alloc(BMO_Get_Slot(&dupeop, BMOP_DUPE_FNEW), BMO_Get_Slot(splitop, BMOP_SPLIT_FOUTPUT));
+
+ /*cleanup*/
+ BMO_Finish_Op(&dupeop);
+ BMO_Finish_Op(&delop);
+} \ No newline at end of file
diff --git a/source/blender/bmesh/tools/BME_duplicate.c b/source/blender/bmesh/tools/BME_duplicate.c
new file mode 100644
index 00000000000..7c679ff6a89
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_duplicate.c
@@ -0,0 +1,307 @@
+/*
+ * BME_DUPLICATE.C
+ *
+ * This file contains functions for duplicating, copying, and splitting
+ * elements from a bmesh.
+ *
+ */
+
+/*
+ * BMESH COPY VERTEX
+ *
+ * Copy an existing vertex from one bmesh to another.
+ *
+*/
+
+static BMVert *bmesh_copy_vertex(BMMesh *source_mesh, BMVert *source_vertex, BMMesh *target_mesh, GHash *vhash)
+{
+ BMVert *target_vertex = NULL;
+
+ /*create a new vertex*/
+ target_vertex = bmesh_make_vert(target, source_vertex->co, NULL);
+
+ /*insert new vertex into the vert hash*/
+ BLI_ghash_insert(vhash, source_vertex, target_vertex);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata, source_vertex->data, &target_vertex->data);
+
+ /*copy flags*/
+ if(bmesh_test_flag(source_vertex, BMESH_SELECT)) bmesh_set_flag(target_vertex, BMESH_SELECT);
+ if(bmesh_test_flag(source_vertex, BMESH_HIDDEN)) bmesh_set_flag(target_vertex, BMESH_HIDDEN);
+
+ return target_vertex;
+}
+
+/*
+ * BMESH COPY EDGE
+ *
+ * Copy an existing edge from one bmesh to another.
+ *
+*/
+
+static BMEdge *bmesh_copy_edge(BMMesh *source_mesh, BMEdge *source_edge, BMMesh *target_mesh, GHash *vhash, GHash *ehash)
+{
+ BMEdge *target_edge = NULL;
+ BMVert *target_vert1, *target_vert2;
+
+ /*lookup v1 and v2*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_edge->v1);
+ target_vert2 = BLI_ghash_lookup(vhash, source_edge->v2);
+
+ /*create a new edge*/
+ target_edge = bmesh_make_edge(target_mesh, target_vert1, target_vert2, NULL, 0);
+
+ /*insert new edge into the edge hash*/
+ BLI_ghash_insert(ehash, source_edge, target_edge);
+
+ /*copy custom data in this function since we cannot be assured that byte layout is same between meshes*/
+ CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata, source_edge->data, &target_edge->data);
+
+ /*copy flags*/
+ if(bmesh_test_flag(source_edge, BMESH_SELECT)) bmesh_set_flag(target_edge, BMESH_SELECT);
+ if(bmesh_test_flag(source_edge, BMESH_HIDDEN)) bmesh_set_flag(target_edge, BMESH_SELECT);
+ if(bmesh_test_flag(source_edge, BMESH_SHARP)) bmesh_set_flag(target_edge, BMESH_SHARP);
+ if(bmesh_test_flag(source_edge, BMESH_SEAM)) bmesh_set_flag(target_edge, BMESH_SEAM);
+ if(bmesh_test_flag(source_edge, BMESH_FGON)) bmesh_set_flag(target_edge, BMESH_FGON);
+
+ return target_edge;
+}
+
+/*
+ * BMESH COPY FACE
+ *
+ * Copy an existing face from one bmesh to another.
+ *
+*/
+
+static BMFace *bmesh_copy_face(BMMesh *source_mesh, BMFace *source_face, BMMesh *target_mesh, BMEdge **edar, GHash *verthash, GHash *ehash)
+{
+ BMEdge *target_edge;
+ BMVert *target_vert1, *target_vert2;
+ BMLoop *source_loop, *target_loop;
+ BMFace *target_face = NULL;
+ int i;
+
+
+ /*lookup the first and second verts*/
+ target_vert1 = BLI_ghash_lookup(vhash, source_face->loopbase->v);
+ target_vert2 = BLI_ghash_lookup(vhash, source_face->loopbase->next->v);
+
+ /*lookup edges*/
+ i = 0;
+ source_loop = source_face->loopbase;
+ do{
+ edar[i] = BLI_ghash_lookup(ehash, source_loop->e);
+ i++;
+ source_loop = source_loop->next;
+ }while(source_loop != source_face->loopbase);
+
+ /*create new face*/
+ target_face = bmesh_make_ngon(target_mesh, target_vert1, target_vert2, edar, source_face->len, 0);
+
+ /*we copy custom data by hand, we cannot assume that customdata byte layout will be exactly the same....*/
+ CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata, source_face->data, &target_face->data);
+
+ /*copy flags*/
+ if(bmesh_test_flag(source_face, BMESH_SELECT)) bmesh_set_flag(target_face, BMESH_SELECT);
+ if(bmesh_test_flag(source_face, BMESH_HIDDEN)) bmesh_set_flag(target_face, BMESH_HIDDEN);
+
+ /*mark the face as dirty for normal and tesselation calcs*/
+ bmesh_set_flag(target_face, BMESH_DIRTY);
+
+ /*copy per-loop custom data*/
+ source_loop = source_face->loopbase;
+ target_loop = target_face->loopbase;
+ do{
+ CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata, source_loop->data, &target_loop->data);
+ source_loop = source_loop->next;
+ target_loop = target_loop->next;
+ }while(source_loop != source_face->loopbase);
+
+ return target_face;
+}
+
+/*
+ * BMESH COPY MESH
+ *
+ * Internal Copy function. copies flagged elements from
+ * source to target, which may in fact be the same mesh.
+ * Note that if __flag is 0, all elements will be copied.
+ *
+*/
+
+static void bmesh_copy_mesh(BMMesh *source, BMMesh *target, int __flag)
+{
+
+ BMVert *v;
+ BMEdge *e, **edar;
+ BMLoop *l;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+ BMIter loops;
+
+ GHash *vhash;
+ GHash *ehash;
+
+ int maxlength = 0, flag;
+
+ /*initialize pointer hashes*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrrhash, BLI_ghashutil_ptrcmp);
+
+ /*initialize edge pointer array*/
+ for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)){
+ if(f->len > maxlength) maxlength = f->len;
+ }
+ edar = MEM_callocN(sizeof(BMEdge*) * maxlength, "BM copy mesh edge pointer array");
+
+ /*begin modelling loop for target*/
+ bmesh_begin_edit(target);
+
+ /*we make special exception for __flag == 0... we copy all*/
+ if(!__flag){
+ flag = BMESH_DUPE;
+ for(v = BMeshIter_init(verts, BM_VERTS, source, 0); v; v = BMeshIter_step(verts)) bmesh_set_flag(v, BMESH_DUPE);
+ for(e = BMeshIter_init(verts, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)) bmesh_set_flag(e, BMESH_DUPE);
+ for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f = BMeshIter_step(faces)) bmesh_set_flag(f, BMESH_DUPE);
+ } else{
+ flag = __flag;
+ }
+
+ /*first we dupe all flagged faces and their elements from source*/
+ for(f = BMeshIter_init(faces, BM_FACES, source, 0); f; f= BMeshIter_step(faces)){
+ if(bmesh_test_flag(f, flag)){
+ /*vertex pass*/
+ for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){
+ if(!bmesh_test_flag(l->v, BMESH_DUPED)){
+ bmesh_copy_vertex(source,l->v, target, vhash);
+ bmesh_set_flag(l->v, BMESH_DUPED);
+ }
+ }
+
+ /*edge pass*/
+ for(l = BMeshIter_init(loops, BMESH_LOOP_OF_MESH, f, 0); l; l = BMeshIter_step(loops)){
+ if(!bmesh_test_flag(l->e, BMESH_DUPED)){
+ bmesh_copy_edge(source, l->e, target, vhash, ehash);
+ bmesh_set_flag(l->e, BMESH_DUPED);
+ }
+ }
+ bmesh_copy_face(source, f, target, edar, vhash, ehash);
+ bmesh_set_flag(f, BMESH_DUPED);
+ }
+ }
+
+ /*now we dupe all the edges*/
+ for(e = BMeshIter_init(edges, BM_EDGES, source, 0); e; e = BMeshIter_step(edges)){
+ if(bmesh_test_flag(e, flag) && (!bmesh_test_flag(e, BMESH_DUPED))){
+ /*make sure that verts are copied*/
+ if(!bmesh_test_flag(e->v1, BMESH_DUPED)){
+ bmesh_copy_vertex(source, e->v1, target, vhash);
+ bmesh_set_flag(e->v1, BMESH_DUPED);
+ }
+ if(!bmesh_test_flag(e->v2, BMESH_DUPED)){
+ bmesh_copy_vertex(source, e->v2, target, vhash);
+ bmesh_set_flag(e->v2, BMESH_DUPED);
+ }
+ /*now copy the actual edge*/
+ bmesh_copy_edge(source, e, target, vhash, ehash);
+ bmesh_set_flag(e, BMESH_DUPED);
+ }
+ }
+
+ /*finally dupe all loose vertices*/
+ for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){
+ if(bmesh_test_flag(v, flag) && (!bmesh_test_flag(v, BMESH_DUPED))){
+ bmesh_copy_vertex(source, v, target, vhash);
+ bmesh_set_flag(v, BMESH_DUPED);
+ }
+ }
+
+ /*finish*/
+ bmesh_end_edit(target, BMESH_CALC_NORM | BMESH_CALC_TESS);
+
+ /*free pointer hashes*/
+ BLI_ghash_free(vhash, NULL, NULL);
+ BLI_ghash_free(ehash, NULL, NULL);
+
+ /*free edge pointer array*/
+ MEM_freeN(edar);
+}
+
+/*
+ * BMESH MAKE MESH FROM MESH
+ *
+ * Creates a new mesh by duplicating an existing one.
+ *
+*/
+
+BMMesh *bmesh_make_mesh_from_mesh(BMMesh *bm, int allocsize[4])
+{
+ BMMesh *target = NULL;
+ target = bmesh_make_mesh(allocsize);
+
+ /*copy custom data layout*/
+ CustomData_copy(&bm->vdata, &target->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->edata, &target->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->ldata, &target->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&bm->pdata, &target->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ /*initialize memory pools*/
+ CustomData_bmesh_init_pool(&target->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&target->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&target->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&target->pdata, allocsize[3]);
+
+ bmesh_begin_edit(bm);
+ bmesh_begin_edit(target);
+
+ bmesh_copy_mesh(bm, target, 0); /*copy all elements*/
+
+ bmesh_end_edit(bm);
+ bmesh_end_edit(target);
+
+ return target;
+
+}
+
+/*
+ * BMESH SPLIT MESH
+ *
+ * Copies flagged elements then deletes them.
+ *
+*/
+
+void bmesh_split_mesh(BMMesh *bm, int flag){
+
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+
+ BMIter verts;
+ BMIter edges;
+ BMIter faces;
+
+ bmesh_begin_edit(bm);
+ bmesh_copy_mesh(bm, bm, flag);
+
+ /*mark verts for deletion*/
+ for(v = BMeshIter_init(verts, BM_VERTS, bm, 0); v; v = BMeshIter_step(verts)){
+ if(bmesh_test_flag(v, flag)) bmesh_delete_vert(bm, v);
+ }
+ /*mark edges for deletion*/
+ for(e = BMeshIter_init(edges, BM_EDGES, bm, 0); e; e = BMeshIter_step(edges)){
+ if(bmesh_test_flag(e, flag)) bmesh_delete_edge(bm, e);
+
+ }
+ /*mark faces for deletion*/
+ for(f = BMeshIter_init(faces, BM_FACES, bm, 0); f; f= BMeshIter_step(faces)){
+ if(bmesh_tes t_flag(f, flag)) bmesh_delete_face(bm, f);
+
+ }
+ bmesh_end_edit(bm);
+}
+
diff --git a/source/blender/bmesh/tools/BME_extrude.c b/source/blender/bmesh/tools/BME_extrude.c
new file mode 100644
index 00000000000..b7b3a94893d
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_extrude.c
@@ -0,0 +1,216 @@
+/**
+ * BMESH EXTRUDE TOOL
+ *
+ * A rewrite of the old editmesh extrude code with the
+ * redundant parts broken into multiple functions
+ * in an effort to reduce code. This works with multiple
+ * selection modes, and is intended to build the
+ * extrusion in steps, depending on what elements are selected.
+ * Also decoupled the calculation of transform normal
+ * and put it in UI where it probably is more appropriate
+ * for the moment.
+ *
+ * TODO:
+ * -Fit this into the new 'easy' API.
+*/
+
+void BME_extrude_verts(BME_Mesh *bm, GHash *vhash){
+ BMVert *v, *nv = NULL;
+ BMEdge *ne = NULL;
+ float vec[3];
+
+ //extrude the vertices
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(BME_SELECTED(v)){
+ VECCOPY(vec,v->co);
+ nv = BME_MV(bm,vec);
+ nv->tflag2 =1; //mark for select
+ ne = BME_ME(bm,v,nv);
+ ne->tflag1 = 2; //mark as part of skirt 'ring'
+ BLI_ghash_insert(vhash,v,nv);
+ BME_VISIT(v);
+ }
+ }
+}
+
+void BME_extrude_skirt(BME_Mesh *bm, GHash *ehash){
+
+ BMFace *nf=NULL;
+ BMEdge *e, *l=NULL, *r=NULL, *edar[4], *ne;
+ BMVert *v, *v1, *v2, *lv, *rv, *nv;
+
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(BME_SELECTED(e)){
+ /*find one face incident upon e and use it for winding of new face*/
+ if(e->loop){
+ v1 = e->loop->next->v;
+ v2 = e->loop->v;
+ }
+ else{
+ v1 = e->v1;
+ v2 = e->v2;
+ }
+
+ if(v1->edge->tflag1 == 2) l = v1->edge;
+ else l = BME_disk_next_edgeflag(v1->edge, v1, 0, 2);
+ if(v2->edge->tflag1 == 2) r = v2->edge;
+ else r = BME_disk_next_edgeflag(v2->edge, v2, 0, 2);
+
+ lv = BME_edge_getothervert(l,v1);
+ rv = BME_edge_getothervert(r,v2);
+
+ ne = BME_ME(bm,lv,rv);
+ ne->tflag2 = 1; //mark for select
+ BLI_ghash_insert(ehash,e,ne);
+ BME_VISIT(e);
+
+ edar[0] = e;
+ edar[1] = l;
+ edar[2] = ne;
+ edar[3] = r;
+ BME_MF(bm,v1,v2,edar,4);
+ }
+ }
+}
+
+void BME_cap_skirt(BME_Mesh *bm, GHash *vhash, GHash *ehash){
+ BMVert *v, *nv, *v1, *v2;
+ BMEdge *e, **edar, *ne;
+ BME_Loop *l;
+ BMFace *f, *nf;
+ MemArena *edgearena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ float vec[3];
+ int i, j, del_old =0;
+
+
+ //loop through faces, then loop through their verts. If the verts havnt been visited yet, duplicate these.
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(BME_SELECTED(f)){
+ l = f->loopbase;
+ do{
+ if(!(BME_ISVISITED(l->v))){ //interior vertex
+ //dupe vert
+ VECCOPY(vec,l->v->co);
+ nv = BME_MV(bm,vec);
+ BLI_ghash_insert(vhash,l->v,nv);
+ //mark for delete
+ l->v->tflag1 = 1;
+ BME_VISIT(l->v); //we dont want to dupe it again.
+ }
+ l=l->next;
+ }while(l!=f->loopbase);
+ }
+ }
+
+ //find out if we delete old faces or not. This needs to be improved a lot.....
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(BME_SELECTED(e) && e->loop){
+ i= BME_cycle_length(&(e->loop->radial));
+ if(i > 2){
+ del_old = 1;
+ break;
+ }
+ }
+ }
+
+
+ //build a new edge net, insert the new edges into the edge hash
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(BME_SELECTED(f)){
+ l=f->loopbase;
+ do{
+ if(!(BME_ISVISITED(l->e))){ //interior edge
+ //dupe edge
+ ne = BME_ME(bm,BLI_ghash_lookup(vhash,l->e->v1),BLI_ghash_lookup(vhash,l->e->v2));
+ BLI_ghash_insert(ehash,l->e,ne);
+ //mark for delete
+ l->e->tflag1 = 1;
+ BME_VISIT(l->e); //we dont want to dupe it again.
+ }
+ l=l->next;
+ }while(l!=f->loopbase);
+ }
+ }
+
+ //build new faces. grab edges from edge hash.
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(BME_SELECTED(f)){
+ edar = MEM_callocN(sizeof(BMEdge*)*f->len,"Extrude array");
+ v1 = BLI_ghash_lookup(vhash,f->loopbase->v);
+ v2 = BLI_ghash_lookup(vhash,f->loopbase->next->v);
+ for(i=0,l=f->loopbase; i < f->len; i++,l=l->next){
+ ne = BLI_ghash_lookup(ehash,l->e);
+ edar[i] = ne;
+ }
+ nf=BME_MF(bm,v1,v2,edar,f->len);
+ nf->tflag2 = 1; // mark for select
+ if(del_old) f->tflag1 = 1; //mark for delete
+ MEM_freeN(edar);
+ }
+ }
+ BLI_memarena_free(edgearena);
+}
+
+/*unified extrude code*/
+void BME_extrude_mesh(BME_Mesh *bm, int type){
+
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BME_Loop *l;
+
+ struct GHash *vhash, *ehash;
+ /*Build a hash table of old pointers and new pointers.*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ BME_selectmode_flush(bm); //ensure consistent selection. contains hack to make sure faces get consistent select.
+ if(type & BME_EXTRUDE_FACES){ //Find selected edges with more than one incident face that is also selected. deselect them.
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ int totsel=0;
+ if(e->loop){
+ l= e->loop;
+ do{
+ if(BME_SELECTED(l->f)) totsel++;
+ l=BME_radial_nextloop(l);
+ }while(l!=e->loop);
+ }
+ if(totsel > 1) BME_select_edge(bm,e,0);
+ }
+ }
+
+ /*another hack to ensure consistent selection.....*/
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(BME_SELECTED(e)) BME_select_edge(bm,e,1);
+ }
+
+ /*now we are ready to extrude*/
+ if(type & BME_EXTRUDE_VERTS) BME_extrude_verts(bm,vhash);
+ if(type & BME_EXTRUDE_EDGES) BME_extrude_skirt(bm,ehash);
+ if(type & BME_EXTRUDE_FACES) BME_cap_skirt(bm,vhash,ehash);
+
+ /*clear all selection flags*/
+ BME_clear_flag_all(bm, SELECT|BME_VISITED);
+ /*go through and fix up selection flags. Anything with BME_NEW should be selected*/
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(f->tflag2 == 1) BME_select_poly(bm,f,1);
+ if(f->tflag1 == 1) BME_VISIT(f); //mark for delete
+ }
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ if(e->tflag2 == 1) BME_select_edge(bm,e,1);
+ if(e->tflag1 == 1) BME_VISIT(e); // mark for delete
+ }
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(v->tflag2 == 1) BME_select_vert(bm,v,1);
+ if(v->tflag1 == 1) BME_VISIT(v); //mark for delete
+ }
+ /*go through and delete all of our old faces , edges and vertices.*/
+ remove_tagged_polys(bm);
+ remove_tagged_edges(bm);
+ remove_tagged_verts(bm);
+ /*free our hash tables*/
+ BLI_ghash_free(vhash,NULL, NULL); //check usage!
+ BLI_ghash_free(ehash,NULL, NULL); //check usage!
+ BME_selectmode_flush(bm);
+}
+
diff --git a/source/blender/bmesh/tools/BME_weld.c b/source/blender/bmesh/tools/BME_weld.c
new file mode 100644
index 00000000000..a17c07addbc
--- /dev/null
+++ b/source/blender/bmesh/tools/BME_weld.c
@@ -0,0 +1,333 @@
+/*
+ * BME_WELD.C
+ *
+ * This file contains functions for welding
+ * elements in a mesh togather (remove doubles,
+ * collapse, ect).
+ *
+ * TODO:
+ * -Rewrite this to fit into the new API
+ * -Seperate out find doubles code and put it in
+ * BME_queries.c
+ *
+*/
+
+
+/********* qsort routines *********/
+
+
+typedef struct xvertsort {
+ float x;
+ BMVert *v1;
+} xvertsort;
+
+static int vergxco(const void *v1, const void *v2)
+{
+ const xvertsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+struct facesort {
+ unsigned long x;
+ struct BMFace *f;
+};
+
+
+static int vergface(const void *v1, const void *v2)
+{
+ const struct facesort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+
+
+/*break this into two functions.... 'find doubles' and 'remove doubles'?*/
+
+static void BME_remove_doubles__splitface(BME_Mesh *bm,BMFace *f,GHash *vhash){
+ BMVert *doub=NULL, *target=NULL;
+ BME_Loop *l;
+ BMFace *f2=NULL;
+ int split=0;
+
+ l=f->loopbase;
+ do{
+ if(l->v->tflag1 == 2){
+ target = BLI_ghash_lookup(vhash,l->v);
+ if((BME_vert_in_face(target,f)) && (target != l->next->v) && (target != l->prev->v)){
+ doub = l->v;
+ split = 1;
+ break;
+ }
+ }
+
+ l= l->next;
+ }while(l!= f->loopbase);
+
+ if(split){
+ f2 = BME_SFME(bm,f,doub,target,NULL);
+ BME_remove_doubles__splitface(bm,f,vhash);
+ BME_remove_doubles__splitface(bm,f2,vhash);
+ }
+}
+
+int BME_remove_doubles(BME_Mesh *bm, float limit)
+{
+
+ /* all verts with (flag & 'flag') are being evaluated */
+ BMVert *v, *v2, *target;
+ BMEdge *e, **edar, *ne;
+ BME_Loop *l;
+ BMFace *f, *nf;
+ xvertsort *sortblock, *sb, *sb1;
+ struct GHash *vhash;
+ struct facesort *fsortblock, *vsb, *vsb1;
+ int a, b, test, amount=0, found;
+ float dist;
+
+ /*Build a hash table of doubles to thier target vert/edge.*/
+ vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ /*count amount of selected vertices*/
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(BME_SELECTED(v))amount++;
+ }
+
+ /*qsort vertices based upon average of coordinate. We test this way first.*/
+ sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub");
+
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(BME_SELECTED(v)){
+ sb->x = v->co[0]+v->co[1]+v->co[2];
+ sb->v1 = v;
+ sb++;
+ }
+ }
+ qsort(sortblock, amount, sizeof(xvertsort), vergxco);
+
+ /* test for doubles */
+ sb= sortblock;
+ for(a=0; a<amount; a++) {
+ v= sb->v1;
+ if(!(v->tflag1)) { //have we tested yet?
+ sb1= sb+1;
+ for(b=a+1; b<amount; b++) {
+ /* first test: simple distance. Simple way to discard*/
+ dist= sb1->x - sb->x;
+ if(dist > limit) break;
+
+ /* second test: have we already done this vertex?
+ (eh this should be swapped, simple equality test should be cheaper than math above... small savings
+ though) */
+ v2= sb1->v1;
+ if(!(v2->tflag1)) {
+ dist= (float)fabs(v2->co[0]-v->co[0]);
+ if(dist<=limit) {
+ dist= (float)fabs(v2->co[1]-v->co[1]);
+ if(dist<=limit) {
+ dist= (float)fabs(v2->co[2]-v->co[2]);
+ if(dist<=limit) {
+ /*v2 is a double of v. We want to throw out v1 and relink everything to v*/
+ BLI_ghash_insert(vhash,v2, v);
+ v->tflag1 = 1; //mark this vertex as a target
+ v->tflag2++; //increase user count for this vert.
+ v2->tflag1 = 2; //mark this vertex as a double.
+ BME_VISIT(v2); //mark for delete
+ }
+ }
+ }
+ }
+ sb1++;
+ }
+ }
+ sb++;
+ }
+ MEM_freeN(sortblock);
+
+
+ /*todo... figure out what this is for...
+ for(eve = em->verts.first; eve; eve=eve->next)
+ if((eve->f & flag) && (eve->f & 128))
+ EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f);
+ */
+
+ /*We cannot collapse a vertex onto another vertex if they share a face and are not connected via a collapsable edge.
+ so to deal with this we simply find these offending vertices and split the faces. Note that this is not optimal, but works.
+ */
+
+
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(!(BME_NEWELEM(f))){
+ BME_remove_doubles__splitface(bm,f,vhash);
+ }
+ }
+
+ for(e=BME_first(bm,BME_EDGE);e;e=BME_next(bm,BME_EDGE,e)){
+ /*If either vertices of this edge are a double, we must mark it for removal and we create a new one.*/
+ if(e->v1->tflag1 == 2 || e->v2->tflag1 == 2){
+ v = v2 = NULL;
+ /*For each vertex in the edge, test to find out what it should equal now.*/
+ if(e->v1->tflag1 == 2) v= BLI_ghash_lookup(vhash,e->v1);
+ else v = e->v1;
+ if(e->v2->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,e->v2);
+ else v2 = e->v2;
+
+ /*small optimization, test to see if the edge needs to be rebuilt at all*/
+ if((e->v1 != v) || (e->v2 != v2)){ /*will this always be true of collapsed edges?*/
+ if(v == v2) e->tflag1 = 2; /*mark as a collapsed edge*/
+ else if(!BME_disk_existedge(v,v2)) ne = BME_ME(bm,v,v2);
+ BME_VISIT(e); /*mark for delete*/
+ }
+ }
+ }
+
+
+ /*need to remove double edges as well. To do this we decide on one edge to keep, and if its inserted into hash then we need to remove all other
+ edges incident upon and relink.*/
+ /*
+ * REBUILD FACES
+ *
+ * Loop through double faces and if they have vertices that have been flagged, they need to be rebuilt.
+ * We do this by looking up the face
+ *rebuild faces. loop through original face, for each loop, if the edge it is attached to is marked for delete and has no
+ *other edge in the hash edge, then we know to skip that loop on face recreation. Simple.
+ */
+
+ /*1st loop through, just marking elements*/
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){ //insert bit here about double edges, mark with a flag (e->tflag2) so that we can nuke it later.
+ l = f->loopbase;
+ do{
+ if(l->v->tflag1 == 2) f->tflag1 = 1; //double, mark for rebuild
+ if(l->e->tflag1 != 2) f->tflag2++; //count number of edges in the new face.
+ l=l->next;
+ }while(l!=f->loopbase);
+ }
+
+ /*now go through and create new faces*/
+ for(f=BME_first(bm,BME_POLY);f;f=BME_next(bm,BME_POLY,f)){
+ if(f->tflag1 && f->tflag2 < 3) BME_VISIT(f); //mark for delete
+ else if (f->tflag1 == 1){ /*is the face marked for rebuild*/
+ edar = MEM_callocN(sizeof(BMEdge *)*f->tflag2,"Remove doubles face creation array.");
+ a=0;
+ l = f->loopbase;
+ do{
+ v = l->v;
+ v2 = l->next->v;
+ if(l->v->tflag1 == 2) v = BLI_ghash_lookup(vhash,l->v);
+ if(l->next->v->tflag1 == 2) v2 = BLI_ghash_lookup(vhash,l->next->v);
+ ne = BME_disk_existedge(v,v2); //use BME_disk_next_edgeflag here or something to find the edge that is marked as 'target'.
+ //add in call here to edge doubles hash array... then bobs your uncle.
+ if(ne){
+ edar[a] = ne;
+ a++;
+ }
+ l=l->next;
+ }while(l!=f->loopbase);
+
+ if(BME_vert_in_edge(edar[1],edar[0]->v2)){
+ v = edar[0]->v1;
+ v2 = edar[0]->v2;
+ }
+ else{
+ v = edar[0]->v2;
+ v2 = edar[0]->v1;
+ }
+
+ nf = BME_MF(bm,v,v2,edar,f->tflag2);
+
+ /*copy per loop data here*/
+ if(nf){
+ BME_VISIT(f); //mark for delete
+ }
+ MEM_freeN(edar);
+ }
+ }
+
+ /*count amount of removed vert doubles*/
+ a = 0;
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(v->tflag1 == 2) a++;
+ }
+
+ /*free memory and return amount removed*/
+ remove_tagged_polys(bm);
+ remove_tagged_edges(bm);
+ remove_tagged_verts(bm);
+ BLI_ghash_free(vhash,NULL, NULL);
+ BME_selectmode_flush(bm);
+ return a;
+}
+
+static void BME_MeshWalk__collapsefunc(void *userData, BMEdge *applyedge){
+ int index;
+ GHash *collected = userData;
+ index = BLI_ghash_size(collected);
+ if(!BLI_ghash_lookup(collected,applyedge->v1)){
+ BLI_ghash_insert(collected,index,applyedge->v1);
+ index++;
+ }
+ if(!BLI_ghash_lookup(collected,applyedge->v2)){
+ BLI_ghash_insert(collected,index,applyedge->v2);
+ }
+}
+
+void BME_collapse_edges(BME_Mesh *bm){
+
+ BMVert *v, *cvert;
+ GHash *collected;
+ float min[3], max[3], cent[3];
+ int size, i=0, j, num=0;
+
+ for(v=BME_first(bm,BME_VERT);v;v=BME_next(bm,BME_VERT,v)){
+ if(!(BME_ISVISITED(v)) && v->edge){
+ /*initiate hash table*/
+ collected = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ /*do the walking.*/
+ BME_MeshWalk(bm,v,BME_MeshWalk__collapsefunc,collected,BME_RESTRICTSELECT);
+ /*now loop through the hash table twice, once to calculate bounding box, second time to do the actual collapse*/
+ size = BLI_ghash_size(collected);
+ /*initial values*/
+ VECCOPY(min,v->co);
+ VECCOPY(max,v->co);
+ cent[0] = cent[1] = cent[2]=0;
+ for(i=0; i<size; i++){
+ cvert = BLI_ghash_lookup(collected,i);
+ cent[0] = cent[0] + cvert->co[0];
+ cent[1] = cent[1] + cvert->co[1];
+ cent[2] = cent[2] + cvert->co[2];
+ }
+
+ cent[0] = cent[0] / size;
+ cent[1] = cent[1] / size;
+ cent[2] = cent[2] / size;
+
+ for(i=0; i<size; i++){
+ cvert = BLI_ghash_lookup(collected,i);
+ VECCOPY(cvert->co,cent);
+ num++;
+ }
+ /*free the hash table*/
+ BLI_ghash_free(collected,NULL, NULL);
+ }
+ }
+ /*if any collapsed, call remove doubles*/
+ if(num){
+ //need to change selection mode here, OR do something else? Or does tool change selection mode?
+ //selectgrep
+ //first clear flags
+ BMEdge *e;
+ BMFace *f;
+ BME_clear_flag_all(bm,BME_VISITED);
+ for(v=BME_first(bm,BME_VERT); v; v=BME_next(bm,BME_VERT,v)) v->tflag1 = v->tflag2 = 0;
+ for(e=BME_first(bm,BME_EDGE); e; e=BME_next(bm,BME_EDGE,e)) e->tflag1 = e->tflag2 = 0;
+ for(f=BME_first(bm,BME_POLY); f; f=BME_next(bm,BME_POLY,f)) f->tflag1 = f->tflag2 = 0;
+ /*now call remove doubles*/
+ BME_remove_doubles(bm,0.0000001);
+ }
+ BME_selectmode_flush(bm);
+} \ No newline at end of file
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
deleted file mode 100644
index 7a618f4d222..00000000000
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/**
- * $Id:
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation, Joshua Leung
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/* User-Interface Stuff for F-Modifiers:
- * This file defines the (C-Coded) templates + editing callbacks needed
- * by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
- * and NLA-Strips in the NLA Editor.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-#include <float.h>
-
-#include "DNA_anim_types.h"
-#include "DNA_action_types.h"
-#include "DNA_object_types.h"
-#include "DNA_space_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_userdef_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_arithb.h"
-#include "BLI_blenlib.h"
-#include "BLI_editVert.h"
-#include "BLI_rand.h"
-
-#include "BKE_animsys.h"
-#include "BKE_action.h"
-#include "BKE_context.h"
-#include "BKE_curve.h"
-#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
-#include "BKE_fcurve.h"
-#include "BKE_object.h"
-#include "BKE_global.h"
-#include "BKE_nla.h"
-#include "BKE_scene.h"
-#include "BKE_screen.h"
-#include "BKE_utildefines.h"
-
-#include "BIF_gl.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "ED_anim_api.h"
-#include "ED_keyframing.h"
-#include "ED_screen.h"
-#include "ED_types.h"
-#include "ED_util.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-#include "UI_view2d.h"
-
-// XXX! --------------------------------
-/* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
-#define UI_FLT_MAX 10000.0f
-
-/* ********************************************** */
-
-#define B_REDR 1
-#define B_FMODIFIER_REDRAW 20
-
-/* macro for use here to draw background box and set height */
-// XXX for now, roundbox has it's callback func set to NULL to not intercept events
-#define DRAW_BACKDROP(height) \
- { \
- uiDefBut(block, ROUNDBOX, B_REDR, "", -3, yco-height, width+3, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); \
- }
-
-/* callback to verify modifier data */
-static void validate_fmodifier_cb (bContext *C, void *fcm_v, void *dummy)
-{
- FModifier *fcm= (FModifier *)fcm_v;
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
-
- /* call the verify callback on the modifier if applicable */
- if (fmi && fmi->verify_data)
- fmi->verify_data(fcm);
-}
-
-/* callback to set the active modifier */
-static void activate_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
-{
- ListBase *modifiers = (ListBase *)fmods_v;
- FModifier *fcm= (FModifier *)fcm_v;
-
- /* call API function to set the active modifier for active modifier-stack */
- set_active_fmodifier(modifiers, fcm);
-}
-
-/* callback to remove the given modifier */
-static void delete_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
-{
- ListBase *modifiers = (ListBase *)fmods_v;
- FModifier *fcm= (FModifier *)fcm_v;
-
- /* remove the given F-Modifier from the active modifier-stack */
- remove_fmodifier(modifiers, fcm);
-}
-
-/* --------------- */
-
-/* draw settings for generator modifier */
-static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
-{
- FMod_Generator *data= (FMod_Generator *)fcm->data;
- uiLayout *col, *row;
- uiBlock *block;
- uiBut *but;
- PointerRNA ptr;
-
- /* init the RNA-pointer */
- RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
-
- /* basic settings (backdrop + mode selector + some padding) */
- col= uiLayoutColumn(layout, 1);
- block= uiLayoutGetBlock(layout);
- uiBlockBeginAlign(block);
- but= uiDefButR(block, MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
-
- uiDefButR(block, TOG, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "additive", -1, 0, 0, -1, -1, NULL);
- uiBlockEndAlign(block);
-
- /* now add settings for individual modes */
- switch (data->mode) {
- case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
- {
- float *cp = NULL;
- char xval[32];
- unsigned int i;
-
- /* draw polynomial order selector */
- row= uiLayoutRow(layout, 0);
- block= uiLayoutGetBlock(row);
- but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
-
-
- /* draw controls for each coefficient and a + sign at end of row */
- row= uiLayoutRow(layout, 1);
- block= uiLayoutGetBlock(row);
- uiDefBut(block, LABEL, 1, "y = ", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
-
- cp= data->coefficients;
- for (i=0; (i < data->arraysize) && (cp); i++, cp++) {
- /* coefficient */
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 150, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient for polynomial");
-
- /* 'x' param (and '+' if necessary) */
- if (i) {
- if (i == 1)
- strcpy(xval, "x");
- else
- sprintf(xval, "x^%d", i);
- uiDefBut(block, LABEL, 1, xval, 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "Power of x");
- }
-
- if ( (i != (data->arraysize - 1)) || ((i==0) && data->arraysize==2) ) {
- uiDefBut(block, LABEL, 1, "+", 0,0 , 30, 20, NULL, 0.0, 0.0, 0, 0, "");
-
- /* next coefficient on a new row */
- row= uiLayoutRow(layout, 1);
- block= uiLayoutGetBlock(row);
- }
- }
- }
- break;
-
- case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial expression */
- {
- float *cp = NULL;
- unsigned int i;
-
- /* draw polynomial order selector */
- row= uiLayoutRow(layout, 0);
- block= uiLayoutGetBlock(row);
- but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 0,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
-
-
- /* draw controls for each pair of coefficients */
- row= uiLayoutRow(layout, 1);
- block= uiLayoutGetBlock(row);
- uiDefBut(block, LABEL, 1, "y=", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
-
- cp= data->coefficients;
- for (i=0; (i < data->poly_order) && (cp); i++, cp+=2) {
- /* opening bracket */
- uiDefBut(block, LABEL, 1, "(", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
-
- /* coefficients */
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient of x");
-
- uiDefBut(block, LABEL, 1, "x+", 0, 0, 40, 20, NULL, 0.0, 0.0, 0, 0, "");
-
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Second coefficient");
-
- /* closing bracket and '+' sign */
- if ( (i != (data->poly_order - 1)) || ((i==0) && data->poly_order==2) ) {
- uiDefBut(block, LABEL, 1, ") +", 0, 0, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
-
- /* set up new row for the next pair of coefficients*/
- row= uiLayoutRow(layout, 1);
- block= uiLayoutGetBlock(row);
- }
- else
- uiDefBut(block, LABEL, 1, ")", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
- }
- }
- break;
- }
-}
-
-/* --------------- */
-
-/* draw settings for noise modifier */
-static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
-{
- uiLayout *col;
- PointerRNA ptr;
-
- /* init the RNA-pointer */
- RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
-
- /* add the settings */
- col= uiLayoutColumn(layout, 1);
- uiItemR(col, "", 0, &ptr, "type", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "additive", 0, 0, 1);
-
- col= uiLayoutColumn(layout, 0); // no grouping for now
- uiItemR(col, NULL, 0, &ptr, "amplitude", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "phase_multiplier", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "phase_offset", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "value_offset", 0, 0, 0);
-}
-
-/* --------------- */
-
-/* draw settings for cycles modifier */
-static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, short width)
-{
- uiLayout *split, *col;
- PointerRNA ptr;
-
- /* init the RNA-pointer */
- RNA_pointer_create(id, &RNA_FModifierCycles, fcm, &ptr);
-
- /* split into 2 columns
- * NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room
- */
- split= uiLayoutSplit(layout, 0.5f);
-
- /* before range */
- col= uiLayoutColumn(split, 1);
- uiItemL(col, "Before:", 0);
- uiItemR(col, "", 0, &ptr, "before_mode", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "before_cycles", 0, 0, 0);
-
- /* after range */
- col= uiLayoutColumn(split, 1);
- uiItemL(col, "After:", 0);
- uiItemR(col, "", 0, &ptr, "after_mode", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "after_cycles", 0, 0, 0);
-}
-
-/* --------------- */
-
-/* draw settings for noise modifier */
-static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short width)
-{
- uiLayout *split, *col;
- PointerRNA ptr;
-
- /* init the RNA-pointer */
- RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr);
-
- /* blending mode */
- uiItemR(layout, NULL, 0, &ptr, "modification", 0, 0, 0);
-
- /* split into 2 columns */
- split= uiLayoutSplit(layout, 0.5f);
-
- /* col 1 */
- col= uiLayoutColumn(split, 0);
- uiItemR(col, NULL, 0, &ptr, "size", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "strength", 0, 0, 0);
-
- /* col 2 */
- col= uiLayoutColumn(split, 0);
- uiItemR(col, NULL, 0, &ptr, "phase", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "depth", 0, 0, 0);
-}
-
-/* --------------- */
-
-#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001
-
-/* Binary search algorithm for finding where to insert Envelope Data Point.
- * Returns the index to insert at (data already at that index will be offset if replace is 0)
- */
-static int binarysearch_fcm_envelopedata_index (FCM_EnvelopeData array[], float frame, int arraylen, short *exists)
-{
- int start=0, end=arraylen;
- int loopbreaker= 0, maxloop= arraylen * 2;
-
- /* initialise exists-flag first */
- *exists= 0;
-
- /* sneaky optimisations (don't go through searching process if...):
- * - keyframe to be added is to be added out of current bounds
- * - keyframe to be added would replace one of the existing ones on bounds
- */
- if ((arraylen <= 0) || (array == NULL)) {
- printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array \n");
- return 0;
- }
- else {
- /* check whether to add before/after/on */
- float framenum;
-
- /* 'First' Point (when only one point, this case is used) */
- framenum= array[0].time;
- if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
- *exists = 1;
- return 0;
- }
- else if (frame < framenum)
- return 0;
-
- /* 'Last' Point */
- framenum= array[(arraylen-1)].time;
- if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
- *exists= 1;
- return (arraylen - 1);
- }
- else if (frame > framenum)
- return arraylen;
- }
-
-
- /* most of the time, this loop is just to find where to put it
- * - 'loopbreaker' is just here to prevent infinite loops
- */
- for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
- /* compute and get midpoint */
- int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */
- float midfra= array[mid].time;
-
- /* check if exactly equal to midpoint */
- if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
- *exists = 1;
- return mid;
- }
-
- /* repeat in upper/lower half */
- if (frame > midfra)
- start= mid + 1;
- else if (frame < midfra)
- end= mid - 1;
- }
-
- /* print error if loop-limit exceeded */
- if (loopbreaker == (maxloop-1)) {
- printf("Error: binarysearch_fcm_envelopedata_index() was taking too long \n");
-
- // include debug info
- printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
- }
-
- /* not found, so return where to place it */
- return start;
-}
-
-/* callback to add new envelope data point */
-// TODO: should we have a separate file for things like this?
-static void fmod_envelope_addpoint_cb (bContext *C, void *fcm_dv, void *dummy)
-{
- Scene *scene= CTX_data_scene(C);
- FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
- FCM_EnvelopeData *fedn;
- FCM_EnvelopeData fed;
-
- /* init template data */
- fed.min= -1.0f;
- fed.max= 1.0f;
- fed.time= (float)scene->r.cfra; // XXX make this int for ease of use?
- fed.f1= fed.f2= 0;
-
- /* check that no data exists for the current frame... */
- if (env->data) {
- short exists = -1;
- int i= binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
-
- /* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
- if (exists)
- return;
-
- /* add new */
- fedn= MEM_callocN((env->totvert+1)*sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
-
- /* add the points that should occur before the point to be pasted */
- if (i > 0)
- memcpy(fedn, env->data, i*sizeof(FCM_EnvelopeData));
-
- /* add point to paste at index i */
- *(fedn + i)= fed;
-
- /* add the points that occur after the point to be pasted */
- if (i < env->totvert)
- memcpy(fedn+i+1, env->data+i, (env->totvert-i)*sizeof(FCM_EnvelopeData));
-
- /* replace (+ free) old with new */
- MEM_freeN(env->data);
- env->data= fedn;
-
- env->totvert++;
- }
- else {
- env->data= MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
- *(env->data)= fed;
-
- env->totvert= 1;
- }
-}
-
-/* callback to remove envelope data point */
-// TODO: should we have a separate file for things like this?
-static void fmod_envelope_deletepoint_cb (bContext *C, void *fcm_dv, void *ind_v)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
- FCM_EnvelopeData *fedn;
- int index= GET_INT_FROM_POINTER(ind_v);
-
- /* check that no data exists for the current frame... */
- if (env->totvert > 1) {
- /* allocate a new smaller array */
- fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData");
-
- memcpy(fedn, &env->data, sizeof(FCM_EnvelopeData)*(index));
- memcpy(&fedn[index], &env->data[index+1], sizeof(FCM_EnvelopeData)*(env->totvert-index-1));
-
- /* free old array, and set the new */
- MEM_freeN(env->data);
- env->data= fedn;
- env->totvert--;
- }
- else {
- /* just free array, since the only vert was deleted */
- if (env->data)
- MEM_freeN(env->data);
- env->totvert= 0;
- }
-}
-
-/* draw settings for envelope modifier */
-static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, short width)
-{
- FMod_Envelope *env= (FMod_Envelope *)fcm->data;
- FCM_EnvelopeData *fed;
- uiLayout *col, *row;
- uiBlock *block;
- uiBut *but;
- PointerRNA ptr;
- int i;
-
- /* init the RNA-pointer */
- RNA_pointer_create(id, &RNA_FModifierEnvelope, fcm, &ptr);
-
- /* general settings */
- col= uiLayoutColumn(layout, 1);
- uiItemL(col, "Envelope:", 0);
- uiItemR(col, NULL, 0, &ptr, "reference_value", 0, 0, 0);
-
- row= uiLayoutRow(col, 1);
- uiItemR(row, "Min", 0, &ptr, "default_minimum", 0, 0, 0);
- uiItemR(row, "Max", 0, &ptr, "default_maximum", 0, 0, 0);
-
- /* control points header */
- // TODO: move this control-point control stuff to using the new special widgets for lists
- // the current way is far too cramped
- row= uiLayoutRow(layout, 0);
- block= uiLayoutGetBlock(row);
-
- uiDefBut(block, LABEL, 1, "Control Points:", 0, 0, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
-
- but= uiDefBut(block, BUT, B_FMODIFIER_REDRAW, "Add Point", 0,0,150,19, NULL, 0, 0, 0, 0, "Adds a new control-point to the envelope on the current frame");
- uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL);
-
- /* control points list */
- for (i=0, fed=env->data; i < env->totvert; i++, fed++) {
- /* get a new row to operate on */
- row= uiLayoutRow(layout, 1);
- block= uiLayoutGetBlock(row);
-
- uiBlockBeginAlign(block);
- but=uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Fra:", 0, 0, 90, 20, &fed->time, -UI_FLT_MAX, UI_FLT_MAX, 10, 1, "Frame that envelope point occurs");
- uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
-
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 0, 0, 100, 20, &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Minimum bound of envelope at this point");
- uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 0, 0, 100, 20, &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Maximum bound of envelope at this point");
-
- but= uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete envelope control point");
- uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
- uiBlockBeginAlign(block);
- }
-}
-
-/* --------------- */
-
-/* draw settings for limits modifier */
-static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, short width)
-{
- uiLayout *split, *col, *row;
- PointerRNA ptr;
-
- /* init the RNA-pointer */
- RNA_pointer_create(id, &RNA_FModifierLimits, fcm, &ptr);
-
- /* row 1: minimum */
- {
- row= uiLayoutRow(layout, 0);
-
- /* split into 2 columns */
- split= uiLayoutSplit(layout, 0.5f);
-
- /* x-minimum */
- col= uiLayoutColumn(split, 1);
- uiItemR(col, NULL, 0, &ptr, "use_minimum_x", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "minimum_x", 0, 0, 0);
-
- /* y-minimum*/
- col= uiLayoutColumn(split, 1);
- uiItemR(col, NULL, 0, &ptr, "use_minimum_y", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "minimum_y", 0, 0, 0);
- }
-
- /* row 2: minimum */
- {
- row= uiLayoutRow(layout, 0);
-
- /* split into 2 columns */
- split= uiLayoutSplit(layout, 0.5f);
-
- /* x-minimum */
- col= uiLayoutColumn(split, 1);
- uiItemR(col, NULL, 0, &ptr, "use_maximum_x", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "maximum_x", 0, 0, 0);
-
- /* y-minimum*/
- col= uiLayoutColumn(split, 1);
- uiItemR(col, NULL, 0, &ptr, "use_maximum_y", 0, 0, 0);
- uiItemR(col, NULL, 0, &ptr, "maximum_y", 0, 0, 0);
- }
-}
-
-/* --------------- */
-
-
-void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
-{
- FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
- uiLayout *box, *row, *subrow;
- uiBlock *block;
- uiBut *but;
- short width= 314;
-
- /* draw header */
- {
- /* get layout-row + UI-block for this */
- box= uiLayoutBox(layout);
-
- row= uiLayoutRow(box, 0);
- block= uiLayoutGetBlock(row); // err...
-
- uiBlockSetEmboss(block, UI_EMBOSSN);
-
- /* left-align -------------------------------------------- */
- subrow= uiLayoutRow(row, 0);
- uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
-
- /* expand */
- uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_EXPANDED, B_REDR, ICON_TRIA_RIGHT, 0, -1, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is expanded.");
-
- /* checkbox for 'active' status (for now) */
- but= uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_ACTIVE, B_REDR, ICON_RADIOBUT_OFF, 0, -1, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is active one.");
- uiButSetFunc(but, activate_fmodifier_cb, modifiers, fcm);
-
- /* name */
- if (fmi)
- uiDefBut(block, LABEL, 1, fmi->name, 0, 0, 150, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
- else
- uiDefBut(block, LABEL, 1, "<Unknown Modifier>", 0, 0, 150, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
-
- /* right-align ------------------------------------------- */
- subrow= uiLayoutRow(row, 0);
- uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
-
- /* 'mute' button */
- uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_MUTED, B_REDR, ICON_MUTE_IPO_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is temporarily muted (not evaluated).");
-
- /* delete button */
- but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier.");
- uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm);
-
- uiBlockSetEmboss(block, UI_EMBOSS);
- }
-
- /* when modifier is expanded, draw settings */
- if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
- /* set up the flexible-box layout which acts as the backdrop for the modifier settings */
- box= uiLayoutBox(layout);
-
- /* draw settings for individual modifiers */
- switch (fcm->type) {
- case FMODIFIER_TYPE_GENERATOR: /* Generator */
- draw_modifier__generator(box, id, fcm, width);
- break;
-
- case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
- draw_modifier__fn_generator(box, id, fcm, width);
- break;
-
- case FMODIFIER_TYPE_CYCLES: /* Cycles */
- draw_modifier__cycles(box, id, fcm, width);
- break;
-
- case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
- draw_modifier__envelope(box, id, fcm, width);
- break;
-
- case FMODIFIER_TYPE_LIMITS: /* Limits */
- draw_modifier__limits(box, id, fcm, width);
- break;
-
- case FMODIFIER_TYPE_NOISE: /* Noise */
- draw_modifier__noise(box, id, fcm, width);
- break;
-
- default: /* unknown type */
- break;
- }
- }
-}
-
-/* ********************************************** */
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 8807b21e653..83179dd3843 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1151,8 +1151,8 @@ static void meshdeform_ray_tree_create(MeshDeformBind *mdb)
MESHDEFORM_BIND= mdb;
- mface= mdb->cagedm->getFaceArray(mdb->cagedm);
- totface= mdb->cagedm->getNumFaces(mdb->cagedm);
+ mface= mdb->cagedm->getTessFaceArray(mdb->cagedm);
+ totface= mdb->cagedm->getNumTessFaces(mdb->cagedm);
mdb->raytree= RE_ray_tree_create(64, totface, min, max,
meshdeform_ray_coords_func, meshdeform_ray_check_func);
@@ -1178,8 +1178,8 @@ static int meshdeform_intersect(MeshDeformBind *mdb, Isect *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);
for(f=0; f<totface; f++, mface++) {
VECCOPY(face[0], mdb->cagecos[mface->v1]);
diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c
index 132d9edf8d0..2a012437b42 100644
--- a/source/blender/editors/armature/reeb.c
+++ b/source/blender/editors/armature/reeb.c
@@ -64,6 +64,7 @@
#include "BKE_global.h"
#include "BKE_utildefines.h"
#include "BKE_customdata.h"
+#include "BKE_mesh.h"
//#include "blendef.h"
@@ -3387,7 +3388,7 @@ ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C)
{
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;
@@ -3483,6 +3484,12 @@ 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;
}
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 0face00f82b..dd29f270680 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -36,7 +36,6 @@ struct EditVert;
struct EditEdge;
struct EditFace;
struct bContext;
-struct wmOperator;
struct wmWindowManager;
struct EditSelection;
struct ViewContext;
@@ -49,35 +48,68 @@ struct MCol;
struct UvVertMap;
struct UvMapVert;
struct CustomData;
+struct BMEditSelection;
+struct BMesh;
+struct BMVert;
+struct BMEdge;
+struct BMFace;
-#define EM_FGON_DRAW 1 // face flag
-#define EM_FGON 2 // edge and face flag both
+// edge and face flag both
+#define EM_FGON 2
+// face flag
+#define EM_FGON_DRAW 1
/* editbutflag */
-#define B_CLOCKWISE 1
-#define B_KEEPORIG 2
-#define B_BEAUTY 4
-#define B_SMOOTH 8
-#define B_BEAUTY_SHORT 0x10
-#define B_AUTOFGON 0x20
-#define B_KNIFE 0x80
+#define B_CLOCKWISE 1
+#define B_KEEPORIG 2
+#define B_BEAUTY 4
+#define B_SMOOTH 8
+#define B_BEAUTY_SHORT 16
+#define B_AUTOFGON 32
+#define B_KNIFE 0x80
#define B_PERCENTSUBD 0x40
#define B_MESH_X_MIRROR 0x100
#define B_JOINTRIA_UV 0x200
#define B_JOINTRIA_VCOL 0X400
#define B_JOINTRIA_SHARP 0X800
#define B_JOINTRIA_MAT 0X1000
-#define B_FRACTAL 0x2000
-#define B_SPHERE 0x4000
+#define B_FRACTAL 0x2000
+#define B_SPHERE 0x4000
+
+/* bmeshutils.c */
+
+/*this function is currently defunct, dead*/
+void EDBM_Tesselate(struct EditMesh *em);
+void EDBM_RecalcNormals(struct BMEditMesh *em);
+void EDBM_MakeEditBMesh(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 *tm, int forvert, int foredge, int forface);
+void EDBM_free_index_arrays(struct BMEditMesh *tm);
+struct BMVert *EDBM_get_vert_for_index(struct BMEditMesh *tm, int index);
+struct BMEdge *EDBM_get_edge_for_index(struct BMEditMesh *tm, int index);
+struct BMFace *EDBM_get_face_for_index(struct BMEditMesh *tm, int index);
+struct BMFace *EDBM_get_actFace(struct BMEditMesh *em, int sloppy);
+void EDBM_selectmode_flush(struct BMEditMesh *em);
+int EDBM_get_actSelection(struct BMEditMesh *em, struct BMEditSelection *ese);
+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);
+void EDBM_selectmode_set(struct BMEditMesh *em);
+void EDBM_convertsel(struct BMEditMesh *em, short oldmode, short selectmode);
+
+int EDBM_check_backbuf(unsigned int index);
+int EDBM_mask_init_backbuf_border(struct ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax);
+void EDBM_free_backbuf(void);
+int EDBM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
+int EDBM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads);
/* meshtools.c */
-intptr_t mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode);
-struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, struct EditMesh *em, float *co);
+intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode);
+struct BMVert *editmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, float *co);
int mesh_get_x_mirror_vert(struct Object *ob, int index);
-int *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em);
-
-int join_mesh_exec(struct bContext *C, struct wmOperator *op);
+int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em);
/* mesh_ops.c */
void ED_operatortypes_mesh(void);
@@ -89,8 +121,8 @@ void ED_keymap_mesh(struct wmWindowManager *wm);
void ED_spacetypes_init(void);
void ED_keymap_mesh(struct wmWindowManager *wm);
-void make_editMesh(struct Scene *scene, Object *ob);
-void load_editMesh(struct Scene *scene, Object *ob);
+struct EditMesh *make_editMesh(struct Scene *scene, Object *ob);
+void load_editMesh(struct Scene *scene, Object *ob, struct EditMesh *em);
void remake_editMesh(struct Scene *scene, Object *ob);
void free_editMesh(struct EditMesh *em);
@@ -112,6 +144,7 @@ void undo_push_mesh(struct bContext *C, char *name);
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 EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type);
void EM_select_edge(struct EditEdge *eed, int sel);
void EM_select_face(struct EditFace *efa, int sel);
@@ -135,11 +168,8 @@ struct UvVertMap *EM_make_uv_vert_map(struct EditMesh *em, int selected, int do_
struct UvMapVert *EM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v);
void EM_free_uv_vert_map(struct UvVertMap *vmap);
-void EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type);
-void EM_free_data_layer(struct EditMesh *em, struct CustomData *data, int type);
-
/* editmesh_mods.c */
-extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs;
+extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs;
void mouse_mesh(struct bContext *C, short mval[2], short extend);
int EM_check_backbuf(unsigned int index);
@@ -151,9 +181,6 @@ int EM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short r
void EM_hide_mesh(struct EditMesh *em, int swap);
void EM_reveal_mesh(struct EditMesh *em);
-void EM_select_by_material(struct EditMesh *em, int index);
-void EM_deselect_by_material(struct EditMesh *em, int index);
-
/* editface.c */
struct MTFace *EM_get_active_mtface(struct EditMesh *em, struct EditFace **act_efa, struct MCol **mcol, int sloppy);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index b576299c1d0..6360bf49f1a 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -37,9 +37,9 @@ struct bglMats;
struct BPoint;
struct Nurb;
struct BezTriple;
-struct EditVert;
-struct EditEdge;
-struct EditFace;
+struct BMVert;
+struct BMEdge;
+struct BMFace;
struct ImBuf;
struct Scene;
struct bContext;
@@ -52,7 +52,7 @@ typedef struct ViewContext {
struct ARegion *ar;
struct View3D *v3d;
struct RegionView3D *rv3d;
- struct EditMesh *em;
+ struct BMEditMesh *em;
short mval[2];
} ViewContext;
@@ -96,9 +96,9 @@ void view3d_get_object_project_mat(struct RegionView3D *v3d, struct Object *ob,
void view3d_project_float(struct ARegion *a, float *vec, float *adr, float mat[4][4]);
/* drawobject.c itterators */
-void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, int clipVerts);
-void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts);
-void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData);
+void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, int x, int y, int index), void *userData, int clipVerts);
+void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts);
+void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, int x, int y, int index), void *userData);
void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData);
void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData);
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
index df1f297698d..80536b5e431 100644
--- a/source/blender/editors/mesh/SConscript
+++ b/source/blender/editors/mesh/SConscript
@@ -7,5 +7,6 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' #/intern/guardedalloc ../../gpu'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
+incs += ' ../../bmesh '
env.BlenderLib ( 'bf_editors_mesh', sources, Split(incs), [], libtype=['core'], priority=[45] )
diff --git a/source/blender/editors/mesh/bmesh_select.c b/source/blender/editors/mesh/bmesh_select.c
new file mode 100644
index 00000000000..c4f2a294d0b
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_select.c
@@ -0,0 +1,1424 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+
+BMEditMesh_mods.c, UI level access, no geometry changes
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "MTC_matrixops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "BKE_context.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "mesh_intern.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/* XXX */
+static void waitcursor() {}
+static int pupmenu() {return 0;}
+
+/* ****************************** MIRROR **************** */
+
+void EDBM_select_mirrored(Object *obedit, BMEditMesh *em)
+{
+#if 0 //BMESH_TODO
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *eve, *v1;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) {
+ v1= BMEditMesh_get_x_mirror_vert(obedit, em, eve->co);
+ if(v1) {
+ eve->f &= ~SELECT;
+ v1->f |= SELECT;
+ }
+ }
+ }
+ }
+#endif
+}
+
+void EDBM_automerge(int update)
+{
+// XXX int len;
+
+// if ((scene->automerge) &&
+// (obedit && obedit->type==OB_MESH) &&
+// (((Mesh*)obedit->data)->mr==NULL)
+// ) {
+// len = removedoublesflag(1, 1, scene->toolsettings->doublimit);
+// if (len) {
+// em->totvert -= len; /* saves doing a countall */
+// if (update) {
+// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+// }
+// }
+// }
+}
+
+/* ****************************** SELECTION ROUTINES **************** */
+
+unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0; /* set in drawobject.c ... for colorindices */
+
+/* facilities for border select and circle select */
+static char *selbuf= NULL;
+
+/* opengl doesn't support concave... */
+static void draw_triangulated(short mcords[][2], short tot)
+{
+ ListBase lb={NULL, NULL};
+ DispList *dl;
+ float *fp;
+ int a;
+
+ /* make displist */
+ dl= MEM_callocN(sizeof(DispList), "poly disp");
+ dl->type= DL_POLY;
+ dl->parts= 1;
+ dl->nr= tot;
+ dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
+ BLI_addtail(&lb, dl);
+
+ for(a=0; a<tot; a++, fp+=3) {
+ fp[0]= (float)mcords[a][0];
+ fp[1]= (float)mcords[a][1];
+ }
+
+ /* do the fill */
+ filldisplist(&lb, &lb);
+
+ /* do the draw */
+ dl= lb.first; /* filldisplist adds in head of list */
+ if(dl->type==DL_INDEX3) {
+ int *index;
+
+ a= dl->parts;
+ fp= dl->verts;
+ index= dl->index;
+ glBegin(GL_TRIANGLES);
+ while(a--) {
+ glVertex3fv(fp+3*index[0]);
+ glVertex3fv(fp+3*index[1]);
+ glVertex3fv(fp+3*index[2]);
+ index+= 3;
+ }
+ glEnd();
+ }
+
+ freedisplist(&lb);
+}
+
+
+/* reads rect, and builds selection array for quick lookup */
+/* returns if all is OK */
+int EDBM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax)
+{
+ struct ImBuf *buf;
+ unsigned int *dr;
+ int a;
+
+ if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+ if(bm_vertoffs==0) return 0;
+
+ dr = buf->rect;
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+
+ a= (xmax-xmin+1)*(ymax-ymin+1);
+ while(a--) {
+ if(*dr>0 && *dr<=bm_vertoffs)
+ selbuf[*dr]= 1;
+ dr++;
+ }
+ IMB_freeImBuf(buf);
+ return 1;
+}
+
+int EDBM_check_backbuf(unsigned int index)
+{
+ if(selbuf==NULL) return 1;
+ if(index>0 && index<=bm_vertoffs)
+ return selbuf[index];
+ return 0;
+}
+
+void EDBM_free_backbuf(void)
+{
+ if(selbuf) MEM_freeN(selbuf);
+ selbuf= NULL;
+}
+
+/* mcords is a polygon mask
+ - grab backbuffer,
+ - draw with black in backbuffer,
+ - grab again and compare
+ returns 'OK'
+*/
+int EDBM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
+{
+ unsigned int *dr, *drm;
+ struct ImBuf *buf, *bufmask;
+ int a;
+
+ /* method in use for face selecting too */
+ if(vc->obedit==NULL) {
+ if(FACESEL_PAINT_TEST);
+ else return 0;
+ }
+ else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+ if(bm_vertoffs==0) return 0;
+
+ dr = buf->rect;
+
+ /* draw the mask */
+ glDisable(GL_DEPTH_TEST);
+
+ glColor3ub(0, 0, 0);
+
+ /* yah, opengl doesn't do concave... tsk! */
+ ED_region_pixelspace(vc->ar);
+ draw_triangulated(mcords, tot);
+
+ glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
+ for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
+ glEnd();
+
+ glFinish(); /* to be sure readpixels sees mask */
+
+ /* grab mask */
+ bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ drm = bufmask->rect;
+ if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+
+ a= (xmax-xmin+1)*(ymax-ymin+1);
+ while(a--) {
+ if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1;
+ dr++; drm++;
+ }
+ IMB_freeImBuf(buf);
+ IMB_freeImBuf(bufmask);
+ return 1;
+
+}
+
+/* circle shaped sample area */
+int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
+{
+ struct ImBuf *buf;
+ unsigned int *dr;
+ short xmin, ymin, xmax, ymax, xc, yc;
+ int radsq;
+
+ /* method in use for face selecting too */
+ if(vc->obedit==NULL) {
+ if(FACESEL_PAINT_TEST);
+ else return 0;
+ }
+ else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ xmin= xs-rads; xmax= xs+rads;
+ ymin= ys-rads; ymax= ys+rads;
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(bm_vertoffs==0) return 0;
+ if(buf==NULL) return 0;
+
+ dr = buf->rect;
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+ radsq= rads*rads;
+ for(yc= -rads; yc<=rads; yc++) {
+ for(xc= -rads; xc<=rads; xc++, dr++) {
+ if(xc*xc + yc*yc < radsq) {
+ if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1;
+ }
+ }
+ }
+
+ IMB_freeImBuf(buf);
+ return 1;
+
+}
+
+static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index)
+{
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
+ if (BM_TestHFlag(eve, BM_SELECT) == data->select) {
+ if (data->strict == 1)
+ return;
+ else
+ temp += 5;
+ }
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = eve;
+ data->closestIndex = index;
+ }
+ }
+}
+
+
+
+
+static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
+{
+ BMEditMesh *em= (BMEditMesh *)handle;
+ BMIter iter;
+ BMVert *eve = BMIter_AtIndex(em->bm, BM_VERTS_OF_MESH, NULL, index-1);
+
+ if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0;
+ return 1;
+}
+/**
+ * findnearestvert
+ *
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ * if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ */
+BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
+{
+ if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
+ int distance;
+ unsigned int index;
+ BMVert *eve;
+
+ if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
+ else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
+
+ eve = BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, index-1);
+
+ if(eve && distance < *dist) {
+ *dist = distance;
+ return eve;
+ } else {
+ return NULL;
+ }
+
+ }
+ else {
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data;
+ static int lastSelectedIndex=0;
+ static BMVert *lastSelected=NULL;
+
+ if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.select = sel;
+ data.dist = *dist;
+ data.strict = strict;
+ data.closest = NULL;
+ data.closestIndex = 0;
+
+ data.pass = 0;
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
+
+ if (data.dist>3) {
+ data.pass = 1;
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
+ }
+
+ *dist = data.dist;
+ lastSelected = data.closest;
+ lastSelectedIndex = data.closestIndex;
+
+ return data.closest;
+ }
+}
+
+/* returns labda for closest distance v1 to line-piece v2-v3 */
+static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
+{
+ float rc[2], len;
+
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
+ len= rc[0]*rc[0]+ rc[1]*rc[1];
+ if(len==0.0f)
+ return 0.0f;
+
+ return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
+}
+
+/* note; uses v3d, so needs active 3d window */
+static void findnearestedge__doClosest(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
+{
+ struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData;
+ float v1[2], v2[2];
+ int distance;
+
+ v1[0] = x0;
+ v1[1] = y0;
+ v2[0] = x1;
+ v2[1] = y1;
+
+ distance= PdistVL2Dfl(data->mval, v1, v2);
+
+ if(BM_TestHFlag(eed, BM_SELECT)) distance+=5;
+ if(distance < data->dist) {
+ if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
+ float vec[3];
+
+ vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
+ vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
+ vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
+ Mat4MulVecfl(data->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(data->vc.rv3d, vec)==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 = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL);
+ BMEdge *eed = BMIter_AtIndex(vc->em->bm, BM_EDGES_OF_MESH, NULL, index-1);
+
+ if (eed && distance<*dist) {
+ *dist = distance;
+ return eed;
+ } else {
+ return NULL;
+ }
+ }
+ else {
+ struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data;
+
+ data.vc= *vc;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+
+ mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
+
+ *dist = data.dist;
+ return data.closest;
+ }
+}
+
+static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int index)
+{
+ struct { short mval[2]; int dist; BMFace *toFace; } *data = userData;
+
+ if (efa==data->toFace) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist)
+ data->dist = temp;
+ }
+}
+static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index)
+{
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = efa;
+ data->closestIndex = index;
+ }
+ }
+}
+static BMFace *EDBM_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]);
+ BMFace *efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1);
+
+ if (efa) {
+ struct { short mval[2]; int dist; BMFace *toFace; } data;
+
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = 0x7FFF; /* largest short */
+ data.toFace = efa;
+
+ mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
+
+ if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
+ *dist= data.dist;
+ return efa;
+ }
+ }
+
+ return NULL;
+ }
+ else {
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data;
+ static int lastSelectedIndex=0;
+ static BMFace *lastSelected=NULL;
+
+ if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+ data.closestIndex = 0;
+
+ data.pass = 0;
+ 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, BMVert **eve, BMEdge **eed, BMFace **efa)
+{
+ BMEditMesh *em= vc->em;
+ int dist= 75;
+
+ *eve= NULL;
+ *eed= NULL;
+ *efa= NULL;
+
+ /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
+ view3d_validate_backbuf(vc);
+
+ if(em->selectmode & SCE_SELECT_VERTEX)
+ *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0);
+ if(em->selectmode & SCE_SELECT_FACE)
+ *efa= EDBM_findnearestface(vc, &dist);
+
+ dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
+ if(em->selectmode & SCE_SELECT_EDGE)
+ *eed= EDBM_findnearestedge(vc, &dist);
+
+ /* return only one of 3 pointers, for frontbuffer redraws */
+ if(*eed) {
+ *efa= NULL; *eve= NULL;
+ }
+ else if(*efa) {
+ *eve= NULL;
+ }
+
+ return (*eve || *eed || *efa);
+}
+
+
+/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
+
+/* selects new faces/edges/verts based on the
+ existing selection
+
+FACES GROUP
+ mode 1: same material
+ mode 2: same image
+ mode 3: same area
+ mode 4: same perimeter
+ mode 5: same normal
+ mode 6: same co-planer
+*/
+
+static EnumPropertyItem prop_simface_types[] = {
+ {1, "MATERIAL", 0, "Material", ""},
+ {2, "IMAGE", 0, "Image", ""},
+ {3, "AREA", 0, "Area", ""},
+ {4, "PERIMETER", 0, "Perimeter", ""},
+ {5, "NORMAL", 0, "Normal", ""},
+ {6, "COPLANAR", 0, "Co-planar", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
+/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
+*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
+#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
+
+static int similar_face_select__internal(Scene *scene, BMEditMesh *em, int mode)
+{
+#if 0 //BMESH_TODO
+ BMFace *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;
+ float thresh= scene->toolsettings->select_thresh;
+ 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 is 3 then record face areas, 4 record perimeter */
+ if (mode==3) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->tmp.fp= EM_face_area(efa);
+ }
+ } else if (mode==4) {
+ 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==1) { /* 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==2) { /* 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==3 || mode==4) { /* 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==5) { /* same normal */
+ float angle;
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (!(efa->f & SELECT) && !efa->h) {
+ angle= VecAngle2(base_efa->n, efa->n);
+ if (angle/180.0<=thresh) {
+ EM_select_face(efa, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ } else if (mode==6) { /* same planer */
+ float angle, base_dot, dot;
+ base_dot= Inpf(base_efa->cent, base_efa->n);
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (!(efa->f & SELECT) && !efa->h) {
+ angle= VecAngle2(base_efa->n, efa->n);
+ if (angle/180.0<=thresh) {
+ dot=Inpf(efa->cent, base_efa->n);
+ if (fabs(base_dot-dot) <= thresh) {
+ EM_select_face(efa, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ }
+ }
+ }
+ } /* end base_efa loop */
+ return selcount;
+#endif
+}
+
+/* ***************************************************** */
+
+/* **************** 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, 0);
+ h = BMW_Begin(&walker, start);
+ for (; h; h=BMW_Step(&walker)) {
+ BM_Select(bm, h, select);
+ }
+ BMW_End(&walker);
+}
+
+#if 0
+/* 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);
+ }
+ }
+}
+#endif
+
+
+/* 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
+*/
+
+/*
+ Almostly exactly the same code as faceloop select
+*/
+static void edgering_select(BMEditMesh *em, BMEdge *startedge, int select)
+{
+#if 0 //BMESH_TODO
+ BMEdge *eed;
+ BMFace *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);
+ }
+#endif
+}
+
+static int loop_multiselect(bContext *C, wmOperator *op)
+{
+#if 0 //BMESH_TODO
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= EM_GetBMEditMesh(((Mesh *)obedit->data));
+ BMEdge *eed;
+ BMEdge **edarray;
+ int edindex, edfirstcount;
+ int looptype= RNA_boolean_get(op->ptr, "ring");
+
+ /* sets em->totedgesel */
+ EM_nedges_selected(em);
+
+ edarray = MEM_mallocN(sizeof(BMEdge*)*em->totedgesel,"edge array");
+ edindex = 0;
+ edfirstcount = em->totedgesel;
+
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(eed->f&SELECT){
+ edarray[edindex] = eed;
+ edindex += 1;
+ }
+ }
+
+ if(looptype){
+ for(edindex = 0; edindex < edfirstcount; edindex +=1){
+ eed = edarray[edindex];
+ edgering_select(em, eed,SELECT);
+ }
+ EM_selectmode_flush(em);
+ }
+ else{
+ for(edindex = 0; edindex < edfirstcount; edindex +=1){
+ eed = edarray[edindex];
+ edgeloop_select(em, eed,SELECT);
+ }
+ EM_selectmode_flush(em);
+ }
+ MEM_freeN(edarray);
+// if (EM_texFaceCheck())
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ EM_EndBMEditMesh(obedit->data, em);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_multi_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Multi Select Loops";
+ ot->idname= "MESH_OT_loop_multi_select";
+
+ /* api callbacks */
+ ot->exec= loop_multiselect;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
+}
+
+
+/* ***************** MAIN MOUSE SELECTION ************** */
+
+
+/* ***************** loop select (non modal) ************** */
+
+static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
+{
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *eed;
+ int select= 1;
+ int dist= 50;
+
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+ em= vc.em;
+
+ eed= EDBM_findnearestedge(&vc, &dist);
+ if(eed) {
+ if(extend==0) EDBM_clear_flag_all(em, BM_SELECT);
+
+ if(BM_TestHFlag(em, BM_SELECT)==0) select=1;
+ else if(extend) select=0;
+
+ if(em->selectmode & SCE_SELECT_FACE) {
+ walker_select(em, BMW_FACELOOP, eed, select);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ if(ring)
+ edgering_select(em, eed, select);
+ else
+ walker_select(em, BMW_LOOP, eed, select);
+ }
+ else if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(ring)
+ edgering_select(em, eed, select);
+ else
+ walker_select(em, BMW_LOOP, eed, select);
+ }
+
+ EDBM_selectmode_flush(em);
+// if (EM_texFaceCheck())
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
+ }
+}
+
+static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+
+ view3d_operator_needs_opengl(C);
+
+ mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "ring"));
+
+ /* cannot do tweaks for as long this keymap is after transform map */
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Loop Select";
+ ot->idname= "MESH_OT_loop_select";
+
+ /* api callbacks */
+ ot->invoke= mesh_select_loop_invoke;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+ RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
+}
+
+/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
+
+/* since you want to create paths with multiple selects, it doesn't have extend option */
+static void mouse_mesh_shortest_path(bContext *C, short mval[2])
+{
+#if 0 //BMESH_TODO
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *eed;
+ int dist= 50;
+
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+ em= vc.em;
+
+ eed= findnearestedge(&vc, &dist);
+ if(eed) {
+ Mesh *me= vc.obedit->data;
+ int path = 0;
+
+ if (em->selected.last) {
+ EditSelection *ese = em->selected.last;
+
+ if(ese && ese->type == BMEdge) {
+ BMEdge *eed_act;
+ eed_act = (BMEdge*)ese->data;
+ if (eed_act != eed) {
+ if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
+ EM_remove_selection(em, eed_act, BMEdge);
+ path = 1;
+ }
+ }
+ }
+ }
+ if (path==0) {
+ int act = (edgetag_context_check(vc.scene, eed)==0);
+ edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
+ }
+
+ EM_selectmode_flush(em);
+
+ /* even if this is selected it may not be in the selection list */
+ if(edgetag_context_check(vc.scene, eed)==0)
+ EDBM_remove_selection(em, eed);
+ else
+ EDBM_store_selection(em, eed);
+
+ /* force drawmode for mesh */
+ switch (vc.scene->toolsettings->edge_mode) {
+
+ case EDGE_MODE_TAG_SEAM:
+ me->drawflag |= ME_DRAWSEAMS;
+ break;
+ case EDGE_MODE_TAG_SHARP:
+ me->drawflag |= ME_DRAWSHARP;
+ break;
+ case EDGE_MODE_TAG_CREASE:
+ me->drawflag |= ME_DRAWCREASES;
+ break;
+ case EDGE_MODE_TAG_BEVEL:
+ me->drawflag |= ME_DRAWBWEIGHTS;
+ break;
+ }
+
+ DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
+ }
+#endif
+}
+
+
+static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+
+ view3d_operator_needs_opengl(C);
+
+ mouse_mesh_shortest_path(C, event->mval);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_shortest_path(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shortest Path Select";
+ ot->idname= "MESH_OT_select_shortest_path";
+
+ /* api callbacks */
+ ot->invoke= mesh_shortest_path_select_invoke;
+ ot->poll= ED_operator_editmesh;
+
+ /* 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 */
+void mouse_mesh(bContext *C, short mval[2], short extend)
+{
+ ViewContext vc;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
+ /* setup view context for argument to callbacks */
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+
+ if(unified_findnearest(&vc, &eve, &eed, &efa)) {
+
+ if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT);
+
+ if(efa) {
+ /* set the last selected face */
+ EDBM_set_actFace(vc.em, efa);
+
+ if(!BM_TestHFlag(efa, BM_SELECT)) {
+ EDBM_store_selection(vc.em, efa);
+ BM_Select(vc.em->bm, efa, 1);
+ }
+ else if(extend) {
+ EDBM_remove_selection(vc.em, efa);
+ BM_Select(vc.em->bm, efa, 1);
+ }
+ }
+ else if(eed) {
+ if(!BM_TestHFlag(eed, BM_SELECT)) {
+ EDBM_store_selection(vc.em, eed);
+ BM_Select(vc.em->bm, eed, 1);
+ }
+ else if(extend) {
+ EDBM_remove_selection(vc.em, eed);
+ BM_Select(vc.em->bm, eed, 0);
+ }
+ }
+ else if(eve) {
+ if(!BM_TestHFlag(eve, BM_SELECT)) {
+ EDBM_store_selection(vc.em, eve);
+ BM_Select(vc.em->bm, eve, 1);
+ }
+ else if(extend){
+ EDBM_remove_selection(vc.em, eve);
+ BM_Select(vc.em->bm, eve, 0);
+ }
+ }
+
+ EDBM_selectmode_flush(vc.em);
+
+// if (EM_texFaceCheck()) {
+
+ if (efa && efa->mat_nr != vc.obedit->actcol-1) {
+ vc.obedit->actcol= efa->mat_nr+1;
+ vc.em->mat_nr= efa->mat_nr;
+// BIF_preview_changed(ID_MA);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
+}
+
+static void EDBM_strip_selections(BMEditMesh *em)
+{
+ BMEditSelection *ese, *nextese;
+
+ if(!(em->selectmode & SCE_SELECT_VERTEX)){
+ ese = em->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == BM_VERT) 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 == BM_EDGE) 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 == BM_FACE) BLI_freelinkN(&(em->selected), ese);
+ ese = nextese;
+ }
+ }
+}
+
+/* when switching select mode, makes sure selection is consistant for editing */
+/* also for paranoia checks to make sure edge or face mode works */
+void EDBM_selectmode_set(BMEditMesh *em)
+{
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+
+ em->bm->selectmode = em->selectmode;
+
+ EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ BMIter iter;
+
+ /*eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
+
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, 0);*/
+
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ /* deselect vertices, and select again based on edge select */
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, 0);
+
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(eed, BM_SELECT))
+ BM_Select(em->bm, eed, 1);
+ }
+
+ /* selects faces based on edge status */
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_FACE) {
+ /* deselect eges, and select again based on face select */
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
+
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(efa, BM_SELECT))
+ BM_Select(em->bm, efa, 1);
+ }
+ }
+}
+
+void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode)
+{
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+
+ /*have to find out what the selectionmode was previously*/
+ if(oldmode == SCE_SELECT_VERTEX) {
+ if(selectmode == SCE_SELECT_EDGE) {
+ /*select all edges associated with every selected vertex*/
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if(BM_TestHFlag(eed->v1, BM_SELECT)) BM_Select(em->bm, eed, 1);
+ else if(BM_TestHFlag(eed->v2, BM_SELECT)) BM_Select(em->bm, eed, 1);
+ }
+ }
+ else if(selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /*select all faces associated with every selected vertex*/
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ BM_Select(em->bm, efa, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(oldmode == SCE_SELECT_EDGE){
+ if(selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /*select all faces associated with every selected vertex*/
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ BM_Select(em->bm, efa, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/editors/mesh/bmesh_selecthistory.c b/source/blender/editors/mesh/bmesh_selecthistory.c
new file mode 100644
index 00000000000..9421a98a11c
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_selecthistory.c
@@ -0,0 +1,270 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* ********* Selection History ************ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "MTC_matrixops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "BKE_context.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "mesh_intern.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/* XXX */
+static void waitcursor() {}
+static int pupmenu() {return 0;}
+
+/* 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 EDBM_editselection_center(BMEditMesh *em, float *center, BMEditSelection *ese)
+{
+ if (ese->type==BM_VERT) {
+ BMVert *eve= ese->data;
+ VecCopyf(center, eve->co);
+ } else if (ese->type==BM_EDGE) {
+ BMEdge *eed= ese->data;
+ VecAddf(center, eed->v1->co, eed->v2->co);
+ VecMulf(center, 0.5);
+ } else if (ese->type==BM_FACE) {
+ BMFace *efa= ese->data;
+ BM_Compute_Face_Center(em->bm, efa, center);
+ }
+}
+
+void EDBM_editselection_normal(float *normal, BMEditSelection *ese)
+{
+ if (ese->type==BM_VERT) {
+ BMVert *eve= ese->data;
+ VecCopyf(normal, eve->no);
+ } else if (ese->type==BM_EDGE) {
+ BMEdge *eed= ese->data;
+ float plane[3]; /* need a plane to correct the normal */
+ float vec[3]; /* temp vec storage */
+
+ VecAddf(normal, eed->v1->no, eed->v2->no);
+ VecSubf(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 */
+ Crossf(vec, normal, plane);
+ Crossf(normal, plane, vec);
+ Normalize(normal);
+
+ } else if (ese->type==BM_FACE) {
+ BMFace *efa= ese->data;
+ VecCopyf(normal, efa->no);
+ }
+}
+
+/* Calculate a plane that is rightangles to the edge/vert/faces normal
+also make the plane run allong an axis that is related to the geometry,
+because this is used for the manipulators Y axis.*/
+void EDBM_editselection_plane(BMEditMesh *em, float *plane, BMEditSelection *ese)
+{
+ if (ese->type==BM_VERT) {
+ BMVert *eve= ese->data;
+ float vec[3]={0,0,0};
+
+ if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
+ EDBM_editselection_center(em, vec, ese->prev);
+ VecSubf(plane, vec, eve->co);
+ } else {
+ /* make a fake plane thats at rightangles to the normal
+ we cant make a crossvec from a vec thats the same as the vec
+ unlikely but possible, so make sure if the normal is (0,0,1)
+ that vec isnt the same or in the same direction even.*/
+ if (eve->no[0]<0.5) vec[0]=1;
+ else if (eve->no[1]<0.5) vec[1]=1;
+ else vec[2]=1;
+ Crossf(plane, eve->no, vec);
+ }
+ } else if (ese->type==BM_EDGE) {
+ BMEdge *eed= ese->data;
+
+ /*the plane is simple, it runs allong the edge
+ however selecting different edges can swap the direction of the y axis.
+ this makes it less likely for the y axis of the manipulator
+ (running along the edge).. to flip less often.
+ at least its more pradictable */
+ if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */
+ VecSubf(plane, eed->v2->co, eed->v1->co);
+ else
+ VecSubf(plane, eed->v1->co, eed->v2->co);
+
+ } else if (ese->type==BM_FACE) {
+ BMFace *efa= ese->data;
+ float vec[3] = {0.0f, 0.0f, 0.0f};
+
+ /*for now, use face normal*/
+
+ /* make a fake plane thats at rightangles to the normal
+ we cant make a crossvec from a vec thats the same as the vec
+ unlikely but possible, so make sure if the normal is (0,0,1)
+ that vec isnt the same or in the same direction even.*/
+ if (efa->no[0]<0.5) vec[0]=1.0f;
+ else if (efa->no[1]<0.5) vec[1]=1.0f;
+ else vec[2]=1.0f;
+ Crossf(plane, efa->no, vec);
+#if 0
+
+ if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
+ float vecA[3], vecB[3];
+ VecSubf(vecA, efa->v4->co, efa->v3->co);
+ VecSubf(vecB, efa->v1->co, efa->v2->co);
+ VecAddf(plane, vecA, vecB);
+
+ VecSubf(vecA, efa->v1->co, efa->v4->co);
+ VecSubf(vecB, efa->v2->co, efa->v3->co);
+ VecAddf(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])
+ VecCopyf(plane, vec);
+ } else {
+ /*start with v1-2 */
+ VecSubf(plane, efa->v1->co, efa->v2->co);
+
+ /*test the edge between v2-3, use if longer */
+ VecSubf(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])
+ VecCopyf(plane, vec);
+
+ /*test the edge between v1-3, use if longer */
+ VecSubf(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])
+ VecCopyf(plane, vec);
+ }
+#endif
+ }
+ Normalize(plane);
+}
+
+static int EDBM_check_selection(BMEditMesh *em, void *data)
+{
+ BMEditSelection *ese;
+
+ for(ese = em->selected.first; ese; ese = ese->next){
+ if(ese->data == data) return 1;
+ }
+
+ return 0;
+}
+
+void EDBM_remove_selection(BMEditMesh *em, void *data)
+{
+ BMEditSelection *ese;
+ for(ese=em->selected.first; ese; ese = ese->next){
+ if(ese->data == data){
+ BLI_freelinkN(&(em->selected),ese);
+ break;
+ }
+ }
+}
+
+void EDBM_store_selection(BMEditMesh *em, void *data)
+{
+ BMEditSelection *ese;
+ if(!EDBM_check_selection(em, data)){
+ ese = (BMEditSelection*) MEM_callocN( sizeof(BMEditSelection), "BMEdit Selection");
+ ese->type = ((BMHeader*)data)->type;
+ ese->data = data;
+ BLI_addtail(&(em->selected),ese);
+ }
+}
+
+void EDBM_validate_selections(BMEditMesh *em)
+{
+ BMEditSelection *ese, *nextese;
+
+ ese = em->selected.first;
+
+ while(ese){
+ nextese = ese->next;
+ if (!BM_TestHFlag(ese->data, BM_SELECT)) BLI_freelinkN(&(em->selected), ese);
+ ese = nextese;
+ }
+}
diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c
new file mode 100644
index 00000000000..103bcbcebce
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_tools.c
@@ -0,0 +1,1321 @@
+ /* $Id: bmesh_tools.c
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+
+#include "UI_interface.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+static void add_normal_aligned(float *nor, float *add)
+{
+ if( INPR(nor, add) < -0.9999f)
+ VecSubf(nor, nor, add);
+ else
+ VecAddf(nor, nor, add);
+}
+
+
+static int subdivide_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;
+ int cuts= RNA_int_get(op->ptr,"number_cuts");
+ float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
+ float fractal= RNA_float_get(op->ptr, "fractal")/100;
+ int flag= 0;
+
+ if(smooth != 0.0f)
+ flag |= B_SMOOTH;
+ if(fractal != 0.0f)
+ flag |= B_FRACTAL;
+
+ BM_esubdivideflag(obedit, em->bm, BM_SELECT, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_subdivide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Subdivide";
+ 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, 10, "Number of Cuts", "", 1, INT_MAX);
+ RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
+}
+
+#if 0
+static int subdivide_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, 1, 0);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_subdivide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Subdivide";
+ ot->idname= "MESH_OT_subdivide";
+
+ /* api callbacks */
+ ot->exec= subdivide_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int subdivide_multi_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, RNA_int_get(op->ptr,"number_cuts"), 0);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_subdivide_multi(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Subdivide Multi";
+ ot->idname= "MESH_OT_subdivide_multi";
+
+ /* api callbacks */
+ ot->exec= subdivide_multi_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
+}
+
+static int subdivide_multi_fractal_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ BM_esubdivideflag(obedit, em->bm, 1, -(RNA_float_get(op->ptr, "random_factor")/100), scene->toolsettings->editbutflag, RNA_int_get(op->ptr, "number_cuts"), 0);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_subdivide_multi_fractal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Subdivide Multi Fractal";
+ ot->idname= "MESH_OT_subdivide_multi_fractal";
+
+ /* api callbacks */
+ ot->exec= subdivide_multi_fractal_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
+ RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
+}
+
+static int subdivide_smooth_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ BM_esubdivideflag(obedit, em->bm, 1, 0.292f*RNA_float_get(op->ptr, "smoothness"), scene->toolsettings->editbutflag | B_SMOOTH, 1, 0);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_subdivide_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Subdivide Smooth";
+ ot->idname= "MESH_OT_subdivide_smooth";
+
+ /* api callbacks */
+ ot->exec= subdivide_smooth_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);
+}
+
+static int subdivs_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ uiPopupMenu *pup;
+ uiLayout *layout;
+
+ pup= uiPupMenuBegin(C, "Subdivision Type", 0);
+ layout= uiPupMenuLayout(pup);
+ uiItemsEnumO(layout, "MESH_OT_subdivs", "type");
+ uiPupMenuEnd(C, pup);
+
+ return OPERATOR_CANCELLED;
+}
+
+static int subdivs_exec(bContext *C, wmOperator *op)
+{
+ switch(RNA_int_get(op->ptr, "type"))
+ {
+ case 0: // simple
+ subdivide_exec(C,op);
+ break;
+ case 1: // multi
+ subdivide_multi_exec(C,op);
+ break;
+ case 2: // fractal;
+ subdivide_multi_fractal_exec(C,op);
+ break;
+ case 3: //smooth
+ subdivide_smooth_exec(C,op);
+ break;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_subdivs(wmOperatorType *ot)
+{
+ static EnumPropertyItem type_items[]= {
+ {0, "SIMPLE", 0, "Simple", ""},
+ {1, "MULTI", 0, "Multi", ""},
+ {2, "FRACTAL", 0, "Fractal", ""},
+ {3, "SMOOTH", 0, "Smooth", ""},
+ {0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "subdivs";
+ ot->idname= "MESH_OT_subdivs";
+
+ /* api callbacks */
+ ot->invoke= subdivs_invoke;
+ ot->exec= subdivs_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /*props */
+ RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
+
+ /* this is temp, the ops are different, but they are called from subdivs, so all the possible props should be here as well*/
+ RNA_def_int(ot->srna, "number_cuts", 4, 1, 10, "Number of Cuts", "", 1, INT_MAX);
+ RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
+ RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);
+}
+#endif
+
+/* individual face extrude */
+/* will use vertex normals for extrusion directions, so *nor is unaffected */
+short EDBM_Extrude_face_indiv(BMEditMesh *em, short flag, float *nor)
+{
+#if 0
+ EditVert *eve, *v1, *v2, *v3, *v4;
+ EditEdge *eed;
+ EditFace *efa, *nextfa;
+
+ if(em==NULL) return 0;
+
+ /* selected edges with 1 or more selected face become faces */
+ /* selected faces each makes new faces */
+ /* always remove old faces, keeps volumes manifold */
+ /* select the new extrusion, deselect old */
+
+ /* step 1; init, count faces in edges */
+ recalc_editnormals(em);
+
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f2= 0; // amount of unselected faces
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT);
+ else {
+ efa->e1->f2++;
+ efa->e2->f2++;
+ efa->e3->f2++;
+ if(efa->e4) efa->e4->f2++;
+ }
+ }
+
+ /* step 2: make new faces from faces */
+ for(efa= em->faces.last; efa; efa= efa->prev) {
+ if(efa->f & SELECT) {
+ v1= addvertlist(em, efa->v1->co, efa->v1);
+ v2= addvertlist(em, efa->v2->co, efa->v2);
+ v3= addvertlist(em, efa->v3->co, efa->v3);
+
+ v1->f1= v2->f1= v3->f1= 1;
+ VECCOPY(v1->no, efa->n);
+ VECCOPY(v2->no, efa->n);
+ VECCOPY(v3->no, efa->n);
+ if(efa->v4) {
+ v4= addvertlist(em, efa->v4->co, efa->v4);
+ v4->f1= 1;
+ VECCOPY(v4->no, efa->n);
+ }
+ else v4= NULL;
+
+ /* side faces, clockwise */
+ addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
+ addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
+ if(efa->v4) {
+ addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
+ addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
+ }
+ else {
+ addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
+ }
+ /* top face */
+ addfacelist(em, v1, v2, v3, v4, efa, NULL);
+ }
+ }
+
+ /* step 3: remove old faces */
+ efa= em->faces.first;
+ while(efa) {
+ nextfa= efa->next;
+ if(efa->f & SELECT) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(em, efa);
+ }
+ efa= nextfa;
+ }
+
+ /* step 4: redo selection */
+ EM_clear_flag_all(em, SELECT);
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1) eve->f |= SELECT;
+ }
+
+ EM_select_flush(em);
+
+ return 'n';
+#endif
+}
+
+
+/* extrudes individual edges */
+/* nor is filled with constraint vector */
+short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor)
+{
+#if 0
+ 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(nor);
+
+ /* set correct selection */
+ EM_clear_flag_all(em, SELECT);
+ for(eve= em->verts.last; eve; eve= eve->prev) {
+ if(eve->tmp.v) {
+ eve->tmp.v->f |= flag;
+ }
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
+ }
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
+#endif
+ return 'n'; // n is for normal constraint
+}
+
+/* extrudes individual vertices */
+short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor)
+{
+ BMOperator bmop;
+ BMOIter siter;
+ BMVert *v;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
+
+ /*deselect original verts*/
+ v = BMO_IterNew(&siter, em->bm, &bmop, "verts", BM_VERT);
+ for (; v; v=BMO_IterStep(&siter)) {
+ BM_Select(em->bm, v, 0);
+ }
+
+ BMO_Exec_Op(em->bm, &bmop);
+
+ v = BMO_IterNew(&siter, em->bm, &bmop, "vertout", BM_VERT);
+ for (; v; v=BMO_IterStep(&siter)) {
+ BM_Select(em->bm, v, 1);
+ }
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
+
+ return 'g'; // g is grab
+}
+
+short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
+{
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMOIter siter;
+ BMOperator extop;
+ BMVert *vert;
+ BMEdge *edge;
+ BMFace *f;
+ ModifierData *md;
+ BMHeader *el;
+
+ BMO_Init_Op(&extop, "extrudefaceregion");
+ BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
+ flag, BM_VERT|BM_EDGE|BM_FACE);
+
+ BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BM_Select(bm, vert, 0);
+ }
+
+ BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BM_Select(bm, edge, 0);
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_Select(bm, f, 0);
+ }
+
+ /* If a mirror modifier with clipping is on, we need to adjust some
+ * of the cases above to handle edges on the line of symmetry.
+ */
+ md = obedit->modifiers.first;
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ float mtx[4][4];
+ if (mmd->mirror_ob) {
+ float imtx[4][4];
+ Mat4Invert(imtx, mmd->mirror_ob->obmat);
+ Mat4MulMat4(mtx, obedit->obmat, imtx);
+ }
+
+ for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
+ edge; edge=BMIter_Step(&iter))
+ {
+ if(edge->head.flag & flag) {
+ float co1[3], co2[3];
+
+ VecCopyf(co1, edge->v1->co);
+ VecCopyf(co2, edge->v2->co);
+
+ if (mmd->mirror_ob) {
+ VecMat4MulVecfl(co1, mtx, co1);
+ VecMat4MulVecfl(co2, mtx, co2);
+ }
+
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ if ( (fabs(co1[0]) < mmd->tolerance) &&
+ (fabs(co2[0]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ if ( (fabs(co1[1]) < mmd->tolerance) &&
+ (fabs(co2[1]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ if ( (fabs(co1[2]) < mmd->tolerance) &&
+ (fabs(co2[2]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ BMO_Exec_Op(bm, &extop);
+
+ nor[0] = nor[1] = nor[2] = 0.0f;
+
+ BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
+ BM_Select(bm, el, 1);
+
+ if (el->type == BM_FACE) {
+ f = (BMFace*)el;
+ add_normal_aligned(nor, f->no);
+ };
+ }
+
+ Normalize(nor);
+
+ BMO_Finish_Op(bm, &extop);
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
+ return 'n'; // normal constraint
+
+}
+short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
+{
+ BMIter iter;
+ BMEdge *eed;
+
+ /*ensure vert flags are consistent for edge selections*/
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(eed, flag)) {
+ if (flag != BM_SELECT) {
+ BM_SetHFlag(eed->v1, flag);
+ BM_SetHFlag(eed->v2, flag);
+ } else {
+ BM_Select(em->bm, eed->v1, 1);
+ BM_Select(em->bm, eed->v2, 1);
+ }
+ } else {
+ if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
+ if (flag != BM_SELECT)
+ BM_SetHFlag(eed, flag);
+ else BM_Select(em->bm, eed, 1);
+ }
+ }
+ }
+
+ return EDBM_Extrude_edge(obedit, em, flag, nor);
+
+}
+
+static int extrude_repeat_mesh(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ int steps = RNA_int_get(op->ptr,"steps");
+
+ float offs = RNA_float_get(op->ptr,"offset");
+
+ float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
+ short a;
+
+ /* dvec */
+ dvec[0]= rv3d->persinv[2][0];
+ dvec[1]= rv3d->persinv[2][1];
+ dvec[2]= rv3d->persinv[2][2];
+ Normalize(dvec);
+ dvec[0]*= offs;
+ dvec[1]*= offs;
+ dvec[2]*= offs;
+
+ /* base correction */
+ Mat3CpyMat4(bmat, obedit->obmat);
+ Mat3Inv(tmat, bmat);
+ Mat3MulVecfl(tmat, dvec);
+
+ for(a=0; a<steps; a++) {
+ EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
+ //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
+ BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
+ //extrudeflag(obedit, em, SELECT, nor);
+ //translateflag(em, SELECT, dvec);
+ }
+
+ EDBM_RecalcNormals(em);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_repeat(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Repeat Mesh";
+ ot->idname= "MESH_OT_extrude_repeat";
+
+ /* api callbacks */
+ ot->exec= extrude_repeat_mesh;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
+ RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
+}
+
+/* generic extern called extruder */
+int EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
+{
+ Scene *scene= NULL; // XXX CTX!
+ short nr, transmode= 0;
+ float stacknor[3] = {0.0f, 0.0f, 0.0f};
+ float *nor = norin ? norin : stacknor;
+
+ nor[0] = nor[1] = nor[2] = 0.0f;
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(em->bm->totvertsel==0) nr= 0;
+ else if(em->bm->totvertsel==1) nr= 4;
+ else if(em->bm->totedgesel==0) nr= 4;
+ else if(em->bm->totfacesel==0)
+ nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
+ else if(em->bm->totfacesel==1)
+ nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ if (em->bm->totedgesel==0) nr = 0;
+
+ nr = 1;
+ /*else if (em->totedgesel==1) nr = 3;
+ else if(em->totfacesel==0) nr = 3;
+ else if(em->totfacesel==1)
+ nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
+ */
+ }
+ else {
+ if (em->bm->totfacesel == 0) nr = 0;
+ else if (em->bm->totfacesel == 1) nr = 1;
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
+ }
+
+ if(nr<1) return 'g';
+
+ if(nr==1 && em->selectmode & SCE_SELECT_VERTEX)
+ transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
+ else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
+ else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
+ else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, SELECT, nor);
+ else transmode= EDBM_Extrude_face_indiv(em, 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') {
+ Mat4MulVecfl(obedit->obmat, nor);
+ VecSubf(nor, nor, obedit->obmat[3]);
+// BIF_setSingleAxisConstraint(nor, "along normal");
+ }
+// Transform();
+ }
+ }
+
+ return transmode;
+}
+
+static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ int constraint_axis[3] = {0, 0, 1};
+ int tmode;
+
+ tmode = EDBM_Extrude_Mesh(obedit, em, op, NULL);
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ RNA_enum_set(op->ptr, "proportional", 0);
+ RNA_boolean_set(op->ptr, "mirror", 0);
+
+ if (tmode == 'n') {
+ RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
+ RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
+ }
+ WM_operator_name_call(C, "TFM_OT_translation", WM_OP_INVOKE_REGION_WIN, op->ptr);
+
+ return OPERATOR_FINISHED;
+}
+
+/* extrude without transform */
+static int mesh_extrude_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+
+ EDBM_Extrude_Mesh(obedit, em, op, NULL);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MESH_OT_extrude(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude";
+ 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;
+
+ /* to give to transform */
+ Properties_Proportional(ot);
+ Properties_Constraints(ot);
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+/* ******************** (de)select all operator **************** */
+
+void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
+{
+ if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
+ EDBM_clear_flag_all(em, SELECT);
+ else
+ EDBM_set_flag_all(em, SELECT);
+}
+
+static int toggle_select_all_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ EDBM_toggle_select_all(em);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_all_toggle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select/Deselect All";
+ ot->idname= "MESH_OT_select_all_toggle";
+
+ /* api callbacks */
+ ot->exec= toggle_select_all_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/* *************** add-click-mesh (extrude) operator ************** */
+
+static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
+{
+ ViewContext vc;
+ BMVert *eve, *v1;
+ BMIter iter;
+ float min[3], max[3];
+ int done= 0;
+
+ em_setup_viewcontext(C, &vc);
+
+ INIT_MINMAX(min, max);
+
+ BM_ITER(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(v1, BM_SELECT)) {
+ DO_MINMAX(v1->co, min, max);
+ done= 1;
+ }
+ }
+
+ /* call extrude? */
+ if(done) {
+ BMEdge *eed;
+ float vec[3], cent[3], mat[3][3];
+ float nor[3]= {0.0, 0.0, 0.0};
+
+ /* check for edges that are half selected, use for rotation */
+ done= 0;
+ BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
+ if(BM_TestHFlag(eed->v1, BM_SELECT))
+ VecSubf(vec, eed->v1->co, eed->v2->co);
+ else
+ VecSubf(vec, eed->v2->co, eed->v1->co);
+ VecAddf(nor, nor, vec);
+ done= 1;
+ }
+ }
+ if(done) Normalize(nor);
+
+ /* center */
+ VecAddf(cent, min, max);
+ VecMulf(cent, 0.5f);
+ VECCOPY(min, cent);
+
+ Mat4MulVecfl(vc.obedit->obmat, min); // view space
+ view3d_get_view_aligned_coordinate(&vc, min, event->mval);
+ Mat4Invert(vc.obedit->imat, vc.obedit->obmat);
+ Mat4MulVecfl(vc.obedit->imat, min); // back in object space
+
+ VecSubf(min, min, cent);
+
+ /* calculate rotation */
+ Mat3One(mat);
+ if(done) {
+ float dot;
+
+ VECCOPY(vec, min);
+ Normalize(vec);
+ dot= INPR(vec, nor);
+
+ if( fabs(dot)<0.999) {
+ float cross[3], si, q1[4];
+
+ Crossf(cross, nor, vec);
+ Normalize(cross);
+ dot= 0.5f*saacos(dot);
+ si= (float)sin(dot);
+ q1[0]= (float)cos(dot);
+ q1[1]= cross[0]*si;
+ q1[2]= cross[1]*si;
+ q1[3]= cross[2]*si;
+
+ QuatToMat3(q1, mat);
+ }
+ }
+
+
+ EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
+ EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
+ BM_SELECT, cent, mat);
+ EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
+ BM_SELECT, min);
+ }
+ else {
+ float *curs= give_cursor(vc.scene, vc.v3d);
+ BMOperator bmop;
+ BMOIter oiter;
+
+ VECCOPY(min, curs);
+
+ view3d_get_view_aligned_coordinate(&vc, min, event->mval);
+ Mat4Invert(vc.obedit->imat, vc.obedit->obmat);
+ Mat4MulVecfl(vc.obedit->imat, min); // back in object space
+
+ EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
+ BMO_Exec_Op(vc.em->bm, &bmop);
+
+ BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
+ BM_Select(vc.em->bm, v1, 1);
+ }
+
+ if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+ }
+
+ //retopo_do_all();
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
+ DAG_object_flush_update(vc.scene, vc.obedit, 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->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int delete_mesh(Object *obedit, wmOperator *op, int event, Scene *scene)
+{
+ BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
+
+ if(event<1) return OPERATOR_CANCELLED;
+
+ if(event==10 ) {
+ //"Erase Vertices";
+
+ if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==11) {
+ //"Edge Loop"
+ if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==7) {
+ //"Dissolve"
+ if (bem->selectmode & SCE_SELECT_FACE) {
+ if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ } else if (bem->selectmode & SCE_SELECT_EDGE) {
+ if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ } else if (bem->selectmode & SCE_SELECT_VERTEX) {
+ if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if(event==4) {
+ //Edges and Faces
+ if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==1) {
+ //"Erase Edges"
+ if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==2) {
+ //"Erase Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==5) {
+ //"Erase Only Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
+ BM_SELECT, DEL_ONLYFACES))
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Note, these values must match delete_mesh() event values */
+static EnumPropertyItem prop_mesh_delete_types[] = {
+ {7, "DISSOLVE", 0, "Dissolve", ""},
+ {10,"VERT", 0, "Vertices", ""},
+ {1, "EDGE", 0, "Edges", ""},
+ {2, "FACE", 0, "Faces", ""},
+ {11, "EDGE_LOOP", 0, "Edge Loop", ""},
+ {4, "EDGE_FACE", 0, "Edges & Faces", ""},
+ {5, "ONLY_FACE", 0, "Only Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int delete_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Scene *scene = CTX_data_scene(C);
+
+ delete_mesh(obedit, op, RNA_enum_get(op->ptr, "type"), scene);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Delete";
+ 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 */
+ RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
+}
+
+
+static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
+{
+ BMOperator bmop;
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+ DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edge_face_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Make Edge/Face";
+ ot->idname= "MESH_OT_edge_face_add";
+
+ /* api callbacks */
+ ot->exec= addedgeface_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+}
+
+static EnumPropertyItem prop_mesh_edit_types[] = {
+ {1, "VERT", 0, "Vertices", ""},
+ {2, "EDGE", 0, "Edges", ""},
+ {3, "FACE", 0, "Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int mesh_selection_type_exec(bContext *C, wmOperator *op)
+{
+
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int type = RNA_enum_get(op->ptr,"type");
+
+ switch (type) {
+ case 1:
+ em->selectmode = SCE_SELECT_VERTEX;
+ break;
+ case 2:
+ em->selectmode = SCE_SELECT_EDGE;
+ break;
+ case 3:
+ em->selectmode = SCE_SELECT_FACE;
+ break;
+ }
+
+ EDBM_selectmode_set(em);
+ CTX_data_scene(C)->toolsettings->selectmode = em->selectmode;
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_selection_type(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Selection Mode";
+ ot->idname= "MESH_OT_selection_type";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= mesh_selection_type_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
+ RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");
+}
+
+/* ************************* SEAMS AND EDGES **************** */
+
+static int editbmesh_mark_seam(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ 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_TestHFlag(eed, BM_HIDDEN) == 0 &&
+ BM_TestHFlag(eed, BM_SELECT) != 0)
+ {
+ BM_ClearHFlag(eed, BM_SEAM);
+ }
+ }
+ }
+ else {
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
+ BM_TestHFlag(eed, BM_SELECT) != 0)
+ {
+ BM_SetHFlag(eed, BM_SEAM);
+ }
+ }
+ }
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_seam(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Seam";
+ ot->idname= "MESH_OT_mark_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)
+{
+ Scene *scene = CTX_data_scene(C);
+ 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_TestHFlag(eed, BM_HIDDEN) == 0 &&
+ BM_TestHFlag(eed, BM_SELECT) != 0)
+ {
+ BM_SetHFlag(eed, BM_SHARP);
+ }
+ }
+ } else {
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
+ BM_TestHFlag(eed, BM_SELECT) != 0)
+ {
+ BM_ClearHFlag(eed, BM_SHARP);
+ }
+ }
+ }
+
+
+ DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_sharp(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Sharp";
+ ot->idname= "MESH_OT_mark_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", "");
+}
diff --git a/source/blender/editors/mesh/bmeshutils.c b/source/blender/editors/mesh/bmeshutils.c
new file mode 100644
index 00000000000..e3ec1c16ce3
--- /dev/null
+++ b/source/blender/editors/mesh/bmeshutils.c
@@ -0,0 +1,523 @@
+ /* $Id: bmeshutils.c
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+void EDBM_RecalcNormals(BMEditMesh *em)
+{
+ BM_Compute_Normals(em->bm);
+}
+
+void EDBM_stats_update(BMEditMesh *em)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+ int *tots[3];
+ int i;
+
+ tots[0] = &em->bm->totvertsel;
+ tots[1] = &em->bm->totedgesel;
+ tots[2] = &em->bm->totfacesel;
+
+ em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
+
+ for (i=0; i<3; i++) {
+ ele = BMIter_New(&iter, em->bm, types[i], NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(ele, BM_SELECT)) {
+ *tots[i]++;
+ }
+ }
+ }
+}
+
+/*this function is defunct, dead*/
+void EDBM_Tesselate(EditMesh *em)
+{
+ EditMesh *em2;
+ EditFace *efa;
+ BMesh *bm;
+ int found=0;
+
+ for (efa=em->faces.first; efa; efa=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)))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ bm = editmesh_to_bmesh(em);
+ em2 = bmesh_to_editmesh(bm);
+ set_editMesh(em, em2);
+
+ MEM_freeN(em2);
+ BM_Free_Mesh(bm);
+ }
+}
+
+int EDBM_InitOpf(BMEditMesh *em, BMOperator *bmop, wmOperator *op, char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ em->emcopy = BMEdit_Copy(em);
+
+ va_end(list);
+}
+
+
+/*returns 0 on error, 1 on success. executes and finishes a bmesh operator*/
+int EDBM_FinishOp(BMEditMesh *em, BMOperator *bmop, wmOperator *op, int report) {
+ char *errmsg;
+
+ BMO_Finish_Op(em->bm, bmop);
+
+ if (BMO_GetError(em->bm, &errmsg, NULL)) {
+ BMEditMesh *emcopy = em->emcopy;
+
+ if (report) BKE_report(op->reports, RPT_ERROR, errmsg);
+
+ BMEdit_Free(em);
+ *em = *emcopy;
+
+ MEM_freeN(emcopy);
+ return 0;
+ } else {
+ BMEdit_Free(em->emcopy);
+ MEM_freeN(em->emcopy);
+ em->emcopy = NULL;
+ }
+
+ return 1;
+}
+
+int EDBM_CallOpf(BMEditMesh *em, wmOperator *op, char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ em->emcopy = BMEdit_Copy(em);
+
+ BMO_Exec_Op(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, op, 1);
+}
+
+int EDBM_CallOpfSilent(BMEditMesh *em, char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ va_end(list);
+ return 0;
+ }
+
+ em->emcopy = BMEdit_Copy(em);
+
+ BMO_Exec_Op(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, NULL, 0);
+}
+
+void EDBM_MakeEditBMesh(Scene *scene, Object *ob)
+{
+ Mesh *me = ob->data;
+ EditMesh *em;
+ BMesh *bm;
+
+ if (!me->mpoly && me->totface) {
+ em = make_editMesh(scene, ob);
+ bm = editmesh_to_bmesh(em);
+
+ free_editMesh(em);
+ } else {
+ bm = BKE_mesh_to_bmesh(me);
+ }
+
+ me->edit_btmesh = BMEdit_Create(bm);
+ me->edit_btmesh->selectmode = scene->toolsettings->selectmode;
+}
+
+void EDBM_LoadEditBMesh(Scene *scene, Object *ob)
+{
+ Mesh *me = ob->data;
+ BMesh *bm = me->edit_btmesh->bm;
+
+ BMO_CallOpf(bm, "object_load_bmesh scene=%p object=%p", scene, ob);
+
+#if 0
+ EditMesh *em = bmesh_to_editmesh(me->edit_btmesh->bm);
+
+ load_editMesh(scene, ob, em);
+ free_editMesh(em);
+ MEM_freeN(em);
+#endif
+}
+
+void EDBM_FreeEditBMesh(BMEditMesh *tm)
+{
+ BMEdit_Free(tm);
+}
+
+void EDBM_init_index_arrays(BMEditMesh *tm, int forvert, int foredge, int forface)
+{
+ EDBM_free_index_arrays(tm);
+
+ if (forvert) {
+ BMIter iter;
+ BMVert *ele;
+ int i=0;
+
+ tm->vert_index = MEM_mallocN(sizeof(void**)*tm->bm->totvert, "tm->vert_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->vert_index[i++] = ele;
+ }
+ }
+
+ if (foredge) {
+ BMIter iter;
+ BMEdge *ele;
+ int i=0;
+
+ tm->edge_index = MEM_mallocN(sizeof(void**)*tm->bm->totedge, "tm->edge_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->edge_index[i++] = ele;
+ }
+ }
+
+ if (forface) {
+ BMIter iter;
+ BMFace *ele;
+ int i=0;
+
+ tm->face_index = MEM_mallocN(sizeof(void**)*tm->bm->totface, "tm->face_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->face_index[i++] = ele;
+ }
+ }
+}
+
+void EDBM_free_index_arrays(BMEditMesh *tm)
+{
+ if (tm->vert_index) {
+ MEM_freeN(tm->vert_index);
+ tm->vert_index = NULL;
+ }
+
+ if (tm->edge_index) {
+ MEM_freeN(tm->edge_index);
+ tm->edge_index = NULL;
+ }
+
+ if (tm->face_index) {
+ MEM_freeN(tm->face_index);
+ tm->face_index = NULL;
+ }
+}
+
+BMVert *EDBM_get_vert_for_index(BMEditMesh *tm, int index)
+{
+ return tm->vert_index?tm->vert_index[index]:NULL;
+}
+
+BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index)
+{
+ return tm->edge_index?tm->edge_index[index]:NULL;
+}
+
+BMFace *EDBM_get_face_for_index(BMEditMesh *tm, int index)
+{
+ return tm->face_index?tm->face_index[index]:NULL;
+}
+
+/* this replaces the active flag used in uv/face mode */
+void EDBM_set_actFace(BMEditMesh *em, BMFace *efa)
+{
+ em->bm->act_face = efa;
+}
+
+BMFace *EDBM_get_actFace(BMEditMesh *em, int sloppy)
+{
+ if (em->bm->act_face) {
+ return em->bm->act_face;
+ } else if (sloppy) {
+ BMFace *efa= NULL;
+ BMEditSelection *ese;
+
+ ese = em->selected.last;
+ for (; ese; ese=ese->prev){
+ if(ese->type == BM_FACE) {
+ efa = (BMFace *)ese->data;
+
+ if (BM_TestHFlag(efa, BM_HIDDEN)) efa= NULL;
+ else break;
+ }
+ }
+ if (efa==NULL) {
+ BMIter iter;
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(efa, BM_SELECT))
+ break;
+ }
+ }
+ return efa; /* can still be null */
+ }
+ return NULL;
+
+}
+
+void EDBM_selectmode_flush(BMEditMesh *em)
+{
+ em->bm->selectmode = em->selectmode;
+ BM_SelectMode_Flush(em->bm);
+}
+
+
+int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese)
+{
+ BMEditSelection *ese_last = em->selected.last;
+ BMFace *efa = EDBM_get_actFace(em, 0);
+
+ ese->next = ese->prev = NULL;
+
+ if (ese_last) {
+ if (ese_last->type == BM_FACE) { /* if there is an active face, use it over the last selected face */
+ if (efa) {
+ ese->data = (void *)efa;
+ } else {
+ ese->data = ese_last->data;
+ }
+ ese->type = BM_FACE;
+ } else {
+ ese->data = ese_last->data;
+ ese->type = ese_last->type;
+ }
+ } else if (efa) { /* no */
+ ese->data = (void *)efa;
+ ese->type = BM_FACE;
+ } else {
+ ese->data = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+void EDBM_clear_flag_all(BMEditMesh *em, int flag)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, type;
+
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ type = BM_VERTS_OF_MESH;
+ break;
+ case 1:
+ type = BM_EDGES_OF_MESH;
+ break;
+ case 2:
+ type = BM_FACES_OF_MESH;
+ break;
+ }
+ ele = BMIter_New(&iter, em->bm, type, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (flag & BM_SELECT) BM_Select(em->bm, ele, 0);
+ BM_ClearHFlag(ele, flag);
+ }
+ }
+}
+
+
+void EDBM_set_flag_all(BMEditMesh *em, int flag)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, type;
+
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ type = BM_VERTS_OF_MESH;
+ break;
+ case 1:
+ type = BM_EDGES_OF_MESH;
+ break;
+ case 2:
+ type = BM_FACES_OF_MESH;
+ break;
+ }
+ ele = BMIter_New(&iter, em->bm, type, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (flag & BM_SELECT) BM_Select(em->bm, ele, 1);
+ BM_SetHFlag(ele, flag);
+ }
+ }
+}
+
+/**************-------------- Undo ------------*****************/
+
+/* for callbacks */
+
+static void *getEditMesh(bContext *C)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ if(obedit && obedit->type==OB_MESH) {
+ Mesh *me= obedit->data;
+ return me->edit_btmesh;
+ }
+ return NULL;
+}
+
+/*undo simply makes copies of a bmesh*/
+static void *editbtMesh_to_undoMesh(void *emv)
+{
+ /*we recalc the tesselation here, to avoid seeding calls to
+ BMEdit_RecalcTesselation throughout the code.*/
+ BMEdit_RecalcTesselation(emv);
+
+ return BMEdit_Copy(emv);
+}
+
+static void undoMesh_to_editbtMesh(void *umv, void *emv)
+{
+ BMEditMesh *bm1 = umv, *bm2 = emv;
+
+ BMEdit_Free(bm2);
+
+ *bm2 = *BMEdit_Copy(bm1);
+}
+
+
+static void free_undo(void *umv)
+{
+ BMEditMesh *em = umv;
+
+ BMEdit_Free(em);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(bContext *C, char *name)
+{
+ undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+}
diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c
index 6c66ae468fa..49872eae897 100644
--- a/source/blender/editors/mesh/editmesh.c
+++ b/source/blender/editors/mesh/editmesh.c
@@ -53,6 +53,7 @@
#include "BLI_editVert.h"
#include "BLI_dynstr.h"
#include "BLI_rand.h"
+#include "BLI_mempool.h"
#include "BKE_cloth.h"
#include "BKE_context.h"
@@ -71,6 +72,7 @@
#include "BKE_softbody.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "LBM_fluidsim.h"
@@ -91,6 +93,8 @@
/* own include */
#include "mesh_intern.h"
+#include "bmesh.h"
+
/*
editmesh.c:
- add/alloc/free data
@@ -112,22 +116,21 @@ static void error() {}
/* ************ ADD / REMOVE / FIND ****************** */
-static void *calloc_em(EditMesh *em, size_t size, size_t nr)
-{
- return calloc(size, nr);
+static void init_editMesh(EditMesh *em) {
+ if (!em->vertpool) em->vertpool = BLI_mempool_create(sizeof(EditVert), 1, 512);
+ if (!em->edgepool) em->edgepool = BLI_mempool_create(sizeof(EditEdge), 1, 512);
+ if (!em->facepool) em->facepool = BLI_mempool_create(sizeof(EditFace), 1, 512);
}
-/* 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;
+
+ if (!em->vertpool) init_editMesh(em);
+
+ eve= BLI_mempool_calloc(em->vertpool);
- eve= callocvert(em, sizeof(EditVert), 1);
BLI_addtail(&em->verts, eve);
em->totvert++;
@@ -157,8 +160,7 @@ 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);
+ BLI_mempool_free(em->vertpool, eve);
em->totvert--;
}
@@ -256,11 +258,12 @@ EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *exampl
}
/* find in hashlist */
+ if (!em->edgepool) init_editMesh(em);
eed= findedgelist(em, v1, v2);
if(eed==NULL) {
- eed= (EditEdge *)callocedge(em, sizeof(EditEdge), 1);
+ eed= (EditEdge *)BLI_mempool_calloc(em->edgepool);
eed->v1= v1;
eed->v2= v2;
BLI_addtail(&em->edges, eed);
@@ -293,9 +296,8 @@ void remedge(EditMesh *em, EditEdge *eed)
void free_editedge(EditMesh *em, EditEdge *eed)
{
EM_remove_selection(em, eed, EDITEDGE);
- if(eed->fast==0){
- free(eed);
- }
+
+ BLI_mempool_free(em->edgepool, eed);
}
void free_editface(EditMesh *em, EditFace *efa)
@@ -307,8 +309,7 @@ void free_editface(EditMesh *em, EditFace *efa)
}
CustomData_em_free_block(&em->fdata, &efa->data);
- if(efa->fast==0)
- free(efa);
+ BLI_mempool_free(em->facepool, efa);
em->totface--;
}
@@ -384,7 +385,9 @@ EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, Ed
if(v1==v2 || v2==v3 || v1==v3) return NULL;
if(e2==0) return NULL;
- efa= (EditFace *)callocface(em, sizeof(EditFace), 1);
+ if (!em->facepool) init_editMesh(em);
+ efa= (EditFace *)BLI_mempool_calloc(em->facepool);
+
efa->v1= v1;
efa->v2= v2;
efa->v3= v3;
@@ -467,55 +470,10 @@ int editface_containsEdge(EditFace *efa, EditEdge *eed)
/* ************************ stuct EditMesh manipulation ***************************** */
-/* fake callocs for fastmalloc below */
-static void *calloc_fastvert(EditMesh *em, size_t size, size_t nr)
-{
- EditVert *eve= em->curvert++;
- eve->fast= 1;
- return eve;
-}
-static void *calloc_fastedge(EditMesh *em, size_t size, size_t nr)
-{
- EditEdge *eed= em->curedge++;
- eed->fast= 1;
- return eed;
-}
-static void *calloc_fastface(EditMesh *em, size_t size, size_t 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)
+void set_editMesh(EditMesh *dst, EditMesh *src)
{
- callocvert= calloc_em;
- callocedge= calloc_em;
- callocface= calloc_em;
+ free_editMesh(dst);
+ *dst = *src;
}
/* do not free editmesh itself here */
@@ -527,7 +485,12 @@ void free_editMesh(EditMesh *em)
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));
-
+
+ if (em->vertpool) BLI_mempool_destroy(em->vertpool);
+ if (em->edgepool) BLI_mempool_destroy(em->edgepool);
+ if (em->facepool) BLI_mempool_destroy(em->facepool);
+ em->vertpool = em->edgepool = em->facepool = NULL;
+
CustomData_free(&em->vdata, 0);
CustomData_free(&em->fdata, 0);
@@ -815,7 +778,7 @@ static int editmesh_pointcache_edit(Scene *scene, Object *ob, int totvert, PTCac
}
/* turns Mesh into editmesh */
-void make_editMesh(Scene *scene, Object *ob)
+EditMesh *make_editMesh(Scene *scene, Object *ob)
{
Mesh *me= ob->data;
MFace *mface;
@@ -833,13 +796,7 @@ void make_editMesh(Scene *scene, Object *ob)
float cacheco[3], cachemat[4][4], *co;
int tot, a, cacheedit= 0, eekadoodle= 0;
- 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= MEM_callocN(sizeof(EditMesh), "editmesh");
em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced
em->act_face = NULL;
@@ -847,18 +804,9 @@ void make_editMesh(Scene *scene, Object *ob)
em->totedge= me->totedge;
em->totface= me->totface;
- if(tot==0) {
- return;
- }
-
- /* initialize fastmalloc for editmesh */
- init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface);
-
actkey = ob_get_keyblock(ob);
if(actkey) {
tot= actkey->totelem;
- /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */
- undo_editmode_clear();
}
@@ -979,8 +927,6 @@ void make_editMesh(Scene *scene, Object *ob)
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
@@ -1014,18 +960,18 @@ void make_editMesh(Scene *scene, Object *ob)
/* vertex coordinates change with cache edit, need to recalc */
if(cacheedit)
recalc_editnormals(em);
-
+
+ return em;
}
/* makes Mesh out of editmesh */
-void load_editMesh(Scene *scene, Object *ob)
+void load_editMesh(Scene *scene, Object *ob, EditMesh *em)
{
Mesh *me= ob->data;
MVert *mvert, *oldverts;
MEdge *medge;
MFace *mface;
MSelect *mselect;
- EditMesh *em= me->edit_mesh;
EditVert *eve;
EditFace *efa, *efa_act;
EditEdge *eed;
@@ -1489,8 +1435,8 @@ static int mesh_separate_selected(Scene *scene, Base *editbase)
/* 2 */
basenew->object->data= menew= add_mesh(me->id.name); /* empty */
me->id.us--;
- make_editMesh(scene, basenew->object);
- emnew= menew->edit_mesh;
+ emnew = make_editMesh(scene, basenew->object);
+ //emnew= menew->edit_mesh;
/* 3 */
/* SPLIT: first make duplicate */
@@ -1531,7 +1477,7 @@ static int mesh_separate_selected(Scene *scene, Base *editbase)
}
/* 5 */
- load_editMesh(scene, basenew->object);
+ load_editMesh(scene, basenew->object, emnew);
free_editMesh(emnew);
/* hashedges are invalid now, make new! */
@@ -1682,6 +1628,7 @@ typedef struct UndoMesh {
EditVertC *verts;
EditEdgeC *edges;
EditFaceC *faces;
+ EditFaceC *act_face;
EditSelectionC *selected;
int totvert, totedge, totface, totsel;
short selectmode;
@@ -1690,247 +1637,6 @@ typedef struct UndoMesh {
CustomData vdata, edata, fdata;
} UndoMesh;
-/* for callbacks */
-
-static void free_undoMesh(void *umv)
-{
- UndoMesh *um= umv;
-
- if(um->verts) MEM_freeN(um->verts);
- if(um->edges) MEM_freeN(um->edges);
- if(um->faces) MEM_freeN(um->faces);
- if(um->selected) MEM_freeN(um->selected);
-// XXX if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
- CustomData_free(&um->vdata, um->totvert);
- CustomData_free(&um->edata, um->totedge);
- CustomData_free(&um->fdata, um->totface);
- MEM_freeN(um);
-}
-
-static void *editMesh_to_undoMesh(void *emv)
-{
- EditMesh *em= (EditMesh *)emv;
- UndoMesh *um;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- EditSelection *ese;
- EditVertC *evec=NULL;
- EditEdgeC *eedc=NULL;
- EditFaceC *efac=NULL;
- EditSelectionC *esec=NULL;
- int a;
-
- um= MEM_callocN(sizeof(UndoMesh), "undomesh");
-
- um->selectmode = em->selectmode;
-
- for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
- for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
- for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
- for(ese=em->selected.first; ese; ese=ese->next) um->totsel++;
- /* malloc blocks */
-
- if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC");
- if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC");
- if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC");
- if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections");
-
- if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert);
- if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge);
- if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface);
-
- /* now copy vertices */
- a = 0;
- for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) {
- VECCOPY(evec->co, eve->co);
- VECCOPY(evec->no, eve->no);
-
- evec->f= eve->f;
- evec->h= eve->h;
- evec->keyindex= eve->keyindex;
- eve->tmp.l = a; /*store index*/
- evec->bweight= (short)(eve->bweight*255.0);
-
- CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
- }
-
- /* copy edges */
- a = 0;
- for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) {
- eedc->v1= (int)eed->v1->tmp.l;
- eedc->v2= (int)eed->v2->tmp.l;
- eedc->f= eed->f;
- eedc->h= eed->h;
- eedc->seam= eed->seam;
- eedc->sharp= eed->sharp;
- eedc->crease= (short)(eed->crease*255.0);
- eedc->bweight= (short)(eed->bweight*255.0);
- eedc->fgoni= eed->fgoni;
- eed->tmp.l = a; /*store index*/
- CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
-
- }
-
- /* copy faces */
- a = 0;
- for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) {
- efac->v1= (int)efa->v1->tmp.l;
- efac->v2= (int)efa->v2->tmp.l;
- efac->v3= (int)efa->v3->tmp.l;
- if(efa->v4) efac->v4= (int)efa->v4->tmp.l;
- else efac->v4= -1;
-
- efac->mat_nr= efa->mat_nr;
- efac->flag= efa->flag;
- efac->f= efa->f;
- efac->h= efa->h;
- efac->fgonf= efa->fgonf;
-
- efa->tmp.l = a; /*store index*/
-
- CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a);
- }
-
- a = 0;
- for(ese=em->selected.first; ese; ese=ese->next, esec++){
- esec->type = ese->type;
- if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l;
- else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l;
- else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l;
- }
-
-// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
-// um->retopo_mode= scene->toolsettings->retopo_mode;
-
- return um;
-}
-
-static void undoMesh_to_editMesh(void *umv, void *emv)
-{
- EditMesh *em= (EditMesh *)emv;
- UndoMesh *um= (UndoMesh *)umv;
- EditVert *eve, **evar=NULL;
- EditEdge *eed;
- EditFace *efa;
- EditSelection *ese;
- EditVertC *evec;
- EditEdgeC *eedc;
- EditFaceC *efac;
- EditSelectionC *esec;
- int a=0;
-
- free_editMesh(em);
-
- /* malloc blocks */
- memset(em, 0, sizeof(EditMesh));
-
- em->selectmode = um->selectmode;
-
- init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
-
- CustomData_free(&em->vdata, 0);
- CustomData_free(&em->edata, 0);
- CustomData_free(&em->fdata, 0);
-
- CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
-
- /* now copy vertices */
-
- if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar");
- for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
- eve= addvertlist(em, evec->co, NULL);
- evar[a]= eve;
-
- VECCOPY(eve->no, evec->no);
- eve->f= evec->f;
- eve->h= evec->h;
- eve->keyindex= evec->keyindex;
- eve->bweight= ((float)evec->bweight)/255.0f;
-
- CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data);
- }
-
- /* copy edges */
- for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) {
- eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL);
-
- eed->f= eedc->f;
- eed->h= eedc->h;
- eed->seam= eedc->seam;
- eed->sharp= eedc->sharp;
- eed->fgoni= eedc->fgoni;
- eed->crease= ((float)eedc->crease)/255.0f;
- eed->bweight= ((float)eedc->bweight)/255.0f;
- CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
- }
-
- /* copy faces */
- for(a=0, efac= um->faces; a<um->totface; a++, efac++) {
- if(efac->v4 != -1)
- efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL);
- else
- efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL);
-
- efa->mat_nr= efac->mat_nr;
- efa->flag= efac->flag;
- efa->f= efac->f;
- efa->h= efac->h;
- efa->fgonf= efac->fgonf;
-
- CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data);
- }
-
- end_editmesh_fastmalloc();
- if(evar) MEM_freeN(evar);
-
- em->totvert = um->totvert;
- em->totedge = um->totedge;
- em->totface = um->totface;
- /*restore stored editselections*/
- if(um->totsel){
- EM_init_index_arrays(em, 1,1,1);
- for(a=0, esec= um->selected; a<um->totsel; a++, esec++){
- ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
- ese->type = esec->type;
- if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else
- if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else
- if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index);
- BLI_addtail(&(em->selected),ese);
- }
- EM_free_index_arrays();
- }
-
-// XXX retopo_free_paint();
-// em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
-// scene->toolsettings->retopo_mode= um->retopo_mode;
-// if(scene->toolsettings->retopo_mode) {
-// XXX if(G.vd->depths) G.vd->depths->damaged= 1;
-// retopo_queue_updates(G.vd);
-// retopo_paint_view_update(G.vd);
-// }
-
-}
-
-static void *getEditMesh(bContext *C)
-{
- Object *obedit= CTX_data_edit_object(C);
- if(obedit && obedit->type==OB_MESH) {
- Mesh *me= obedit->data;
- return me->edit_mesh;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, char *name)
-{
- undo_editmode_push(C, name, getEditMesh, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL);
-}
-
-
/* *************** END UNDO *************/
@@ -2033,6 +1739,6 @@ void em_setup_viewcontext(bContext *C, ViewContext *vc)
if(vc->obedit) {
Mesh *me= vc->obedit->data;
- vc->em= me->edit_mesh;
+ vc->em= me->edit_btmesh;
}
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index c24670aa856..4b891843f5e 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -60,6 +60,7 @@
#include "BKE_object.h"
#include "BKE_utildefines.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -71,6 +72,8 @@
#include "ED_util.h"
#include "ED_view3d.h"
+#include "bmesh.h"
+
#include "mesh_intern.h"
/* bpymenu removed XXX */
@@ -116,127 +119,6 @@ static short icoface[20][3] = {
{10,9,11}
};
-/* *************** add-click-mesh (extrude) operator ************** */
-
-static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
-{
- ViewContext vc;
- EditVert *eve, *v1;
- float min[3], max[3];
- int done= 0;
-
- em_setup_viewcontext(C, &vc);
-
- INIT_MINMAX(min, max);
-
- for(v1= vc.em->verts.first;v1; v1=v1->next) {
- if(v1->f & SELECT) {
- DO_MINMAX(v1->co, min, max);
- done= 1;
- }
- }
-
- /* call extrude? */
- if(done) {
- EditEdge *eed;
- float vec[3], cent[3], mat[3][3];
- float nor[3]= {0.0, 0.0, 0.0};
-
- /* check for edges that are half selected, use for rotation */
- done= 0;
- for(eed= vc.em->edges.first; eed; eed= eed->next) {
- if( (eed->v1->f & SELECT)+(eed->v2->f & SELECT) == SELECT ) {
- if(eed->v1->f & SELECT) VecSubf(vec, eed->v1->co, eed->v2->co);
- else VecSubf(vec, eed->v2->co, eed->v1->co);
- VecAddf(nor, nor, vec);
- done= 1;
- }
- }
- if(done) Normalize(nor);
-
- /* center */
- VecAddf(cent, min, max);
- VecMulf(cent, 0.5f);
- VECCOPY(min, cent);
-
- Mat4MulVecfl(vc.obedit->obmat, min); // view space
- view3d_get_view_aligned_coordinate(&vc, min, event->mval);
- Mat4Invert(vc.obedit->imat, vc.obedit->obmat);
- Mat4MulVecfl(vc.obedit->imat, min); // back in object space
-
- VecSubf(min, min, cent);
-
- /* calculate rotation */
- Mat3One(mat);
- if(done) {
- float dot;
-
- VECCOPY(vec, min);
- Normalize(vec);
- dot= INPR(vec, nor);
-
- if( fabs(dot)<0.999) {
- float cross[3], si, q1[4];
-
- Crossf(cross, nor, vec);
- Normalize(cross);
- dot= 0.5f*saacos(dot);
- si= (float)sin(dot);
- q1[0]= (float)cos(dot);
- q1[1]= cross[0]*si;
- q1[2]= cross[1]*si;
- q1[3]= cross[2]*si;
-
- QuatToMat3(q1, mat);
- }
- }
-
- extrudeflag(vc.obedit, vc.em, SELECT, nor);
- rotateflag(vc.em, SELECT, cent, mat);
- translateflag(vc.em, SELECT, min);
-
- recalc_editnormals(vc.em);
- }
- else {
- float mat[3][3],imat[3][3];
- float *curs= give_cursor(vc.scene, vc.v3d);
-
- VECCOPY(min, curs);
- view3d_get_view_aligned_coordinate(&vc, min, event->mval);
-
- eve= addvertlist(vc.em, 0, NULL);
-
- Mat3CpyMat4(mat, vc.obedit->obmat);
- Mat3Inv(imat, mat);
-
- VECCOPY(eve->co, min);
- Mat3MulVecfl(imat, eve->co);
- VecSubf(eve->co, eve->co, vc.obedit->obmat[3]);
-
- eve->f= SELECT;
- }
-
- //retopo_do_all();
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
- DAG_object_flush_update(vc.scene, vc.obedit, 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->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
/* ********************** */
@@ -666,12 +548,53 @@ void addfaces_from_edgenet(EditMesh *em)
// XXX DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
}
-static void addedgeface_mesh(EditMesh *em, wmOperator *op)
+static void addedgeface_mesh(Mesh *me, BMEditMesh *bem, wmOperator *op)
{
+ EditMesh *em;
EditVert *eve, *neweve[4];
EditEdge *eed;
EditFace *efa;
short amount=0;
+
+ /*return if bmesh vert connect does anything.*/
+ if (bem->selectmode & SCE_SELECT_VERTEX) {
+ BMesh *bm = bem->bm;
+ BMOperator bmop;
+ int len, ok;
+
+ EDBM_InitOpf(bem, &bmop, op, "connectverts verts=%hv", BM_SELECT);
+ BMO_Exec_Op(bem->bm, &bmop);
+
+ len = BMO_GetSlot(&bmop, "edgeout")->len;
+
+ ok = EDBM_FinishOp(bem, &bmop, op, 1);
+ if (!ok) return OPERATOR_CANCELLED;
+
+ if (len) return;
+ }
+
+ /*return if bmesh face dissolve finds stuff to
+ dissolve. this entire tool should be
+ bmeshafied eventually, but until then
+ hacks like this to integrate with it
+ are necassary.*/
+ if (bem->selectmode & SCE_SELECT_VERTEX) {
+ BMesh *bm = bem->bm;
+ BMOperator bmop;
+ int len, ok;
+
+ EDBM_InitOpf(bem, &bmop, op, "dissolvefaces faces=%hf", BM_SELECT);
+ BMO_Exec_Op(bem->bm, &bmop);
+
+ len = BMO_GetSlot(&bmop, "regionout")->len;
+
+ ok = EDBM_FinishOp(bem, &bmop, op, 1);
+ if (!ok) return OPERATOR_CANCELLED;
+
+ if (len) return;
+ }
+
+ em = BKE_mesh_get_editmesh(me);
/* how many selected ? */
if(em->selectmode & SCE_SELECT_EDGE) {
@@ -691,16 +614,19 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op)
if(amount==2) {
eed= addedgelist(em, neweve[0], neweve[1], NULL);
EM_select_edge(eed, 1);
-
+
+ BKE_mesh_end_editmesh(me, em);
// XXX DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return;
}
else if(amount > 4) {
addfaces_from_edgenet(em);
+ BKE_mesh_end_editmesh(me, em);
return;
}
else if(amount<2) {
BKE_report(op->reports, RPT_ERROR, "More vertices are needed to make an edge/face");
+ BKE_mesh_end_editmesh(me, em);
return;
}
@@ -739,6 +665,7 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op)
if(count++ > 4){
addfaces_from_edgenet(em);
+ BKE_mesh_end_editmesh(me, em);
return;
} else {
/* if 4 edges exist, we just create the face, convex or not */
@@ -780,40 +707,10 @@ static void addedgeface_mesh(EditMesh *em, wmOperator *op)
recalc_editnormals(em);
}
- }
-static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- addedgeface_mesh(em, op);
-
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
- DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_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->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;
-
+ BKE_mesh_end_editmesh(me, em);
}
-
-
/* ************************ primitives ******************* */
// HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker
@@ -1104,7 +1001,9 @@ static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int se
}
dia*=200;
- for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1,0);
+
+ for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0.0, 0, 1, 0);
+
/* and now do imat */
eve= em->verts.first;
while(eve) {
diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c
index e1b63022dd4..d9e0cc0f339 100644
--- a/source/blender/editors/mesh/editmesh_lib.c
+++ b/source/blender/editors/mesh/editmesh_lib.c
@@ -61,6 +61,7 @@ editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data
#include "ED_view3d.h"
#include "mesh_intern.h"
+#include "bmesh.h"
/* ****************** stats *************** */
@@ -1139,10 +1140,128 @@ short extrudeflag_verts_indiv(EditMesh *em, short flag, float *nor)
return 'g'; // g is grab
}
+short BM_extrude_edgeflag(Object *obedit, BMesh *bm, int eflag, float *nor)
+{
+ BMIter iter;
+ BMOIter siter;
+ BMOperator extop;
+ BMEdge *edge;
+ BMFace *f;
+ void *el;
+ ModifierData *md;
+ int flag;
+
+ switch (eflag) {
+ case SELECT:
+ flag = BM_SELECT;
+ break;
+ default:
+ flag = BM_SELECT;
+ break;
+ }
+
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);f;f=BMIter_Step(&iter)) {
+ add_normal_aligned(nor, f->no);
+ }
+ Normalize(nor);
+
+ BMO_Init_Op(&extop, "extrudefaceregion");
+ BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
+ flag, BM_VERT|BM_EDGE|BM_FACE);
+
+ for (edge=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); edge; edge=BMIter_Step(&iter)) {
+ BM_Select_Edge(bm, edge, 0);
+ }
+
+ for (f=BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); f; f=BMIter_Step(&iter)) {
+ BM_Select_Face(bm, f, 0);
+ }
+
+ /* If a mirror modifier with clipping is on, we need to adjust some
+ * of the cases above to handle edges on the line of symmetry.
+ */
+ md = obedit->modifiers.first;
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ float mtx[4][4];
+ if (mmd->mirror_ob) {
+ float imtx[4][4];
+ Mat4Invert(imtx, mmd->mirror_ob->obmat);
+ Mat4MulMat4(mtx, obedit->obmat, imtx);
+ }
+
+ for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
+ edge; edge=BMIter_Step(&iter))
+ {
+ if(edge->head.flag & flag) {
+ float co1[3], co2[3];
+
+ VecCopyf(co1, edge->v1->co);
+ VecCopyf(co2, edge->v2->co);
+
+ if (mmd->mirror_ob) {
+ VecMat4MulVecfl(co1, mtx, co1);
+ VecMat4MulVecfl(co2, mtx, co2);
+ }
+
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ if ( (fabs(co1[0]) < mmd->tolerance) &&
+ (fabs(co2[0]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ if ( (fabs(co1[1]) < mmd->tolerance) &&
+ (fabs(co2[1]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ if ( (fabs(co1[2]) < mmd->tolerance) &&
+ (fabs(co2[2]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+ }
+ }
+ }
+ }
+ }
+
+
+ BMO_Exec_Op(bm, &extop);
+
+ el = BMO_IterNew(&siter, bm, &extop, "geomout", BM_ALL);
+ for (; el; el=BMO_IterStep(&siter)) {
+ BM_Select(bm, el, 1);
+ }
+
+ BMO_Finish_Op(bm, &extop);
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
+ return 'n'; // normal constraint
+
+}
+
+
+static short extrudeflag_edge(Object *obedit, EditMesh *em, short flag, float *nor) {
+ short ret;
+ EditMesh *em2;
+ BMesh *bm = editmesh_to_bmesh(em);
+
+ ret = BM_extrude_edgeflag(obedit, bm, flag, nor);
+ em2 = bmesh_to_editmesh(bm);
+
+ set_editMesh(em, em2);
+ MEM_freeN(em2);
+
+ EM_select_flush(em);
+
+ return ret;
+}
/* 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 flag, float *nor)
+static short extrudeflag_edge_old(Object *obedit, EditMesh *em, short flag, float *nor)
{
/* all select edges/faces: extrude */
/* old select is cleared, in new ones it is set */
@@ -1686,9 +1805,22 @@ short extrudeflag_vert(Object *obedit, EditMesh *em, short flag, float *nor)
/* generic extrude */
short extrudeflag(Object *obedit, EditMesh *em, short flag, float *nor)
{
- if(em->selectmode & SCE_SELECT_VERTEX)
- return extrudeflag_vert(obedit, em, flag, nor);
- else
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ EditEdge *eed;
+
+ /*ensure vert flags are consistent for edge selections*/
+ for (eed=em->edges.first; eed; eed=eed->next) {
+ if (eed->f & flag) {
+ eed->v1->f |= flag;
+ eed->v2->f |= flag;
+ } else {
+ if ((eed->v1->f & flag) && (eed->v2->f & flag))
+ eed->f |= flag;
+ }
+ }
+
+ return extrudeflag_edge(obedit, em, flag, nor);
+ } else
return extrudeflag_edge(obedit, em, flag, nor);
}
@@ -1912,6 +2044,9 @@ void recalc_editnormals(EditMesh *em)
}
for(efa= em->faces.first; efa; efa=efa->next) {
+ if (efa->e1->fgoni||efa->e2->fgoni||efa->e3->fgoni) continue;
+ if (efa->e4 && efa->e4->fgoni) continue;
+
if(efa->v4) {
CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
CalcCent4f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
diff --git a/source/blender/editors/mesh/editmesh_loop.c b/source/blender/editors/mesh/editmesh_loop.c
index 7fc3753eefb..9b5de48a644 100644
--- a/source/blender/editors/mesh/editmesh_loop.c
+++ b/source/blender/editors/mesh/editmesh_loop.c
@@ -61,6 +61,7 @@ editmesh_loop: tools with own drawing subloops, select, knife, subdiv
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "PIL_time.h"
@@ -77,6 +78,7 @@ editmesh_loop: tools with own drawing subloops, select, knife, subdiv
#include "ED_view3d.h"
#include "mesh_intern.h"
+#include "bmesh.h"
/* **** XXX ******** */
static void BIF_undo_push() {}
@@ -201,6 +203,7 @@ static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int prev
}
void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts)
{
+#if 0
ViewContext vc; // XXX
EditEdge *nearest=NULL, *eed;
float fac;
@@ -391,6 +394,7 @@ void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts)
// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
return;
+#endif
}
@@ -474,7 +478,7 @@ static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct
float m1, b1, m2, b2, x21, x22, y21, y22, xi;
float yi, x1min, x1max, y1max, y1min, perc=0;
float *scr;
- float threshold;
+ float threshold = 0.0;
int i;
threshold = 0.000001; /*tolerance for vertex intersection*/
@@ -620,26 +624,184 @@ static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct
}
+static float bm_seg_intersect(BMEdge *e, CutCurve *c, int len, char mode,
+ struct GHash *gh, int *isected)
+{
+#define MAXSLOPE 100000
+ float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
+ float y2min, dist, lastdist=0, xdiff2, xdiff1;
+ float m1, b1, m2, b2, x21, x22, y21, y22, xi;
+ float yi, x1min, x1max, y1max, y1min, perc=0;
+ float *scr;
+ float threshold = 0.0;
+ int i;
+
+ //threshold = 0.000001; /*tolerance for vertex intersection*/
+ // XXX threshold = scene->toolsettings->select_thresh / 100;
+
+ /* Get screen coords of verts */
+ scr = BLI_ghash_lookup(gh, e->v1);
+ x21=scr[0];
+ y21=scr[1];
+
+ scr = BLI_ghash_lookup(gh, e->v2);
+ x22=scr[0];
+ y22=scr[1];
+
+ xdiff2=(x22-x21);
+ if (xdiff2) {
+ m2=(y22-y21)/xdiff2;
+ b2= ((x22*y21)-(x21*y22))/xdiff2;
+ }
+ else {
+ m2=MAXSLOPE; /* Verticle slope */
+ b2=x22;
+ }
+
+ *isected = 0;
+
+ /*check for *exact* vertex intersection first*/
+ if(mode!=KNIFE_MULTICUT){
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /*test e->v1*/
+ if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
+ perc = 0;
+ *isected = 1;
+ return(perc);
+ }
+ /*test e->v2*/
+ else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
+ perc = 0;
+ *isected = 2;
+ return(perc);
+ }
+ }
+ }
+
+ /*now check for edge interesect (may produce vertex intersection as well)*/
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /* Perp. Distance from point to line */
+ if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
+ /* change in sign. Skip extra math */
+ else dist=x22-x12;
+
+ if (i==0) lastdist=dist;
+
+ /* if dist changes sign, and intersect point in edge's Bound Box*/
+ if ((lastdist*dist)<=0){
+ xdiff1=(x12-x11); /* Equation of line between last 2 points */
+ if (xdiff1){
+ m1=(y12-y11)/xdiff1;
+ b1= ((x12*y11)-(x11*y12))/xdiff1;
+ }
+ else{
+ m1=MAXSLOPE;
+ b1=x12;
+ }
+ x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
+ x2min=MIN2(x21,x22)-0.001; /* due to round off error */
+ y2max=MAX2(y21,y22)+0.001;
+ y2min=MIN2(y21,y22)-0.001;
+
+ /* Found an intersect, calc intersect point */
+ if (m1==m2){ /* co-incident lines */
+ /* cut at 50% of overlap area*/
+ x1max=MAX2(x11, x12);
+ x1min=MIN2(x11, x12);
+ xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
+
+ y1max=MAX2(y11, y12);
+ y1min=MIN2(y11, y12);
+ yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
+ }
+ else if (m2==MAXSLOPE){
+ xi=x22;
+ yi=m1*x22+b1;
+ }
+ else if (m1==MAXSLOPE){
+ xi=x12;
+ yi=m2*x12+b2;
+ }
+ else {
+ xi=(b1-b2)/(m2-m1);
+ yi=(b1*m2-m1*b2)/(m2-m1);
+ }
+
+ /* Intersect inside bounding box of edge?*/
+ if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
+ /*test for vertex intersect that may be 'close enough'*/
+ if(mode!=KNIFE_MULTICUT){
+ if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
+ if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
+ *isected = 1;
+ perc = 0;
+ break;
+ }
+ }
+ if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
+ if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
+ *isected = 2;
+ perc = 0;
+ break;
+ }
+ }
+ }
+ if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
+ else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
+ //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
+
+ break;
+ }
+ }
+ lastdist=dist;
+ }
+ return(perc);
+}
+
#define MAX_CUTS 256
static int knife_cut_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;
+ BMesh *bm = em->bm;
ARegion *ar= CTX_wm_region(C);
- EditEdge *eed;
- EditVert *eve;
+ BMVert *bv;
+ BMIter iter;
+ BMEdge **edges = NULL, *be;
+ BMOperator bmop;
CutCurve curve[MAX_CUTS];
struct GHash *gh;
float isect=0.0;
- float *scr, co[4];
- int len=0;
+ float *scr, co[4], *percents = NULL;
+ int len=0, isected, flag, i;
short numcuts=1, mode= RNA_int_get(op->ptr, "type");
- if (EM_nvertices_selected(em) < 2) {
+ if (bm->totvertsel < 2) {
error("No edges are selected to operate on");
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;;
}
@@ -653,57 +815,60 @@ static int knife_cut_exec(bContext *C, wmOperator *op)
RNA_END;
if(len<2) {
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
- /*store percentage of edge cut for KNIFE_EXACT here.*/
- for(eed=em->edges.first; eed; eed= eed->next)
- eed->tmp.fp = 0.0;
-
/*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
- for(eve=em->verts.first; eve; eve=eve->next){
+ for(bv=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);bv;bv=BMIter_Step(&iter)){
scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
- VECCOPY(co, eve->co);
+ VECCOPY(co, bv->co);
co[3]= 1.0;
Mat4MulVec4fl(obedit->obmat, co);
project_float(ar, co, scr);
- BLI_ghash_insert(gh, eve, scr);
- eve->f1 = 0; /*store vertex intersection flag here*/
-
+ BLI_ghash_insert(gh, bv, scr);
}
- 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;
- //printf("isect=%i\n", isect);
- }
- else {
- eed->f2=0;
- eed->f1=0;
+ BMO_Init_Op(&bmop, "esubd");
+
+ i = 0;
+ /*store percentage of edge cut for KNIFE_EXACT here.*/
+ for (be=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be=BMIter_Step(&iter)) {
+ if( BM_Is_Selected(bm, be) ) {
+ isect= bm_seg_intersect(be, curve, len, mode, gh, &isected);
+
+ if (isect != 0.0f) {
+ if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
+ BMO_Insert_MapFloat(bm, &bmop,
+ "edgepercents",
+ be, isect);
+
+ }
+ BMO_SetFlag(bm, be, 1);
+ }
}
- eed= eed->next;
}
- if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_SELECT_ORIG);
- else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_SELECT_ORIG);
- else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_SELECT_ORIG);
+ BMO_Flag_To_Slot(bm, &bmop, "edges", 1, BM_EDGE);
- eed=em->edges.first;
- while(eed){
- eed->f2=0;
- eed->f1=0;
- eed=eed->next;
- }
+ BMO_Set_Int(&bmop, "numcuts", numcuts);
+ flag = B_KNIFE;
+ if (mode == KNIFE_MIDPOINT) numcuts = 1;
+ BMO_Set_Int(&bmop, "flag", flag);
+ BMO_Set_Float(&bmop, "radius", 0);
- BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Finish_Op(bm, &bmop);
- BKE_mesh_end_editmesh(obedit->data, em);
+ V_FREE(edges);
+ V_FREE(percents);
+
+ //if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, B_KNIFE, 1, SUBDIV_SELECT_ORIG);
+ //else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, B_KNIFE, numcuts, SUBDIV_SELECT_ORIG);
+ //else esubdivideflag(obedit, em, SELECT, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_SELECT_ORIG);
+
+ BLI_ghash_free(gh, NULL, (GHashValFreeFP)WMEM_freeN);
+
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c
index 5fc2ce46792..aa7a5e6b292 100644
--- a/source/blender/editors/mesh/editmesh_mods.c
+++ b/source/blender/editors/mesh/editmesh_mods.c
@@ -83,6 +83,7 @@ editmesh_mods.c, UI level access, no geometry changes
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "bmesh.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -99,6 +100,7 @@ static int pupmenu() {return 0;}
void EM_select_mirrored(Object *obedit, EditMesh *em)
{
+#if 0
if(em->selectmode & SCE_SELECT_VERTEX) {
EditVert *eve, *v1;
@@ -112,6 +114,7 @@ void EM_select_mirrored(Object *obedit, EditMesh *em)
}
}
}
+#endif
}
void EM_automerge(int update)
@@ -326,320 +329,6 @@ int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
}
-static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
-{
- struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
-
- if (data->pass==0) {
- if (index<=data->lastIndex)
- return;
- } else {
- if (index>data->lastIndex)
- return;
- }
-
- if (data->dist>3) {
- int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
- if ((eve->f&1) == data->select) {
- if (data->strict == 1)
- return;
- else
- temp += 5;
- }
-
- if (temp<data->dist) {
- data->dist = temp;
- data->closest = eve;
- data->closestIndex = index;
- }
- }
-}
-
-
-
-
-static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
-{
- EditMesh *em= (EditMesh *)handle;
- EditVert *eve = BLI_findlink(&em->verts, index-1);
-
- if(eve && (eve->f & SELECT)) return 0;
- return 1;
-}
-/**
- * findnearestvert
- *
- * dist (in/out): minimal distance to the nearest and at the end, actual distance
- * sel: selection bias
- * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
- * if 0, unselected vertice are given the bias
- * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
- */
-EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
-{
- if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
- int distance;
- unsigned int index;
- EditVert *eve;
-
- if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
- else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
-
- eve = BLI_findlink(&vc->em->verts, index-1);
-
- if(eve && distance < *dist) {
- *dist = distance;
- return eve;
- } else {
- return NULL;
- }
-
- }
- else {
- struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
- static int lastSelectedIndex=0;
- static EditVert *lastSelected=NULL;
-
- if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
- }
-
- data.lastIndex = lastSelectedIndex;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.select = sel;
- data.dist = *dist;
- data.strict = strict;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
-
- if (data.dist>3) {
- data.pass = 1;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
- }
-
- *dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
-
- return data.closest;
- }
-}
-
-/* returns labda for closest distance v1 to line-piece v2-v3 */
-static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
-{
- float rc[2], len;
-
- rc[0]= v3[0]-v2[0];
- rc[1]= v3[1]-v2[1];
- len= rc[0]*rc[0]+ rc[1]*rc[1];
- if(len==0.0f)
- return 0.0f;
-
- return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
-}
-
-/* note; uses v3d, so needs active 3d window */
-static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
-{
- struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
- float v1[2], v2[2];
- int distance;
-
- v1[0] = x0;
- v1[1] = y0;
- v2[0] = x1;
- v2[1] = y1;
-
- distance= PdistVL2Dfl(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]);
- Mat4MulVecfl(data->vc.obedit->obmat, vec);
-
- if(view3d_test_clipping(data->vc.rv3d, vec)==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;
-
- mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
-
- *dist = data.dist;
- return data.closest;
- }
-}
-
-static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index)
-{
- struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
-
- if (efa==data->toFace) {
- int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
-
- if (temp<data->dist)
- data->dist = temp;
- }
-}
-static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
-{
- struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
-
- if (data->pass==0) {
- if (index<=data->lastIndex)
- return;
- } else {
- if (index>data->lastIndex)
- return;
- }
-
- if (data->dist>3) {
- int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
-
- if (temp<data->dist) {
- data->dist = temp;
- data->closest = efa;
- data->closestIndex = index;
- }
- }
-}
-static EditFace *findnearestface(ViewContext *vc, int *dist)
-{
-
- if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
- EditFace *efa = BLI_findlink(&vc->em->faces, index-1);
-
- if (efa) {
- struct { short mval[2]; int dist; EditFace *toFace; } data;
-
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.dist = 0x7FFF; /* largest short */
- data.toFace = efa;
-
- mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
-
- if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
- *dist= data.dist;
- return efa;
- }
- }
-
- return NULL;
- }
- else {
- struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
- static int lastSelectedIndex=0;
- static EditFace *lastSelected=NULL;
-
- if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
- }
-
- data.lastIndex = lastSelectedIndex;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.dist = *dist;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
- 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 */
@@ -1715,9 +1404,9 @@ void mesh_copy_menu(EditMesh *em, wmOperator *op)
}
}
-
/* **************** LOOP SELECTS *************** */
+#if 0
/* selects quads in loop direction of indicated edge */
/* only flush over edges with valence <= 2 */
void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
@@ -1787,6 +1476,7 @@ void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
}
}
}
+#endif
/* helper for edgeloop_select, checks for eed->f2 tag in faces */
@@ -1819,6 +1509,34 @@ static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
*/
static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
{
+ BMesh *bm;
+ BMEdge *e;
+ EditMesh *em2;
+ BMOperator op;
+ BMWalker walker;
+
+ bm = init_editmesh_to_bmesh(em, &op);
+ BMO_Exec_Op(bm, &op);
+
+ e = BMO_Get_MapPointer(bm, &op, "map", starteed);
+
+ BMW_Init(&walker, bm, BMW_LOOP, 0);
+ e = BMW_Begin(&walker, e);
+ for (; e; e=BMW_Step(&walker)) {
+ BM_Select(bm, e, 1);
+ }
+ BMW_End(&walker);
+
+ BMO_Finish_Op(bm, &op);
+
+ em2 = bmesh_to_editmesh(bm);
+ BM_Free_Mesh(bm);
+ set_editMesh(em, em2);
+ MEM_freeN(em2);
+}
+
+static void edgeloop_select_old(EditMesh *em, EditEdge *starteed, int select)
+{
EditVert *eve;
EditEdge *eed;
EditFace *efa;
@@ -1995,6 +1713,7 @@ static int loop_multiselect(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+#if 0 //moved to bmeshutils_mods.c
void MESH_OT_loop_multi_select(wmOperatorType *ot)
{
/* identifiers */
@@ -2011,255 +1730,15 @@ void MESH_OT_loop_multi_select(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
}
-
+#endif
/* ***************** MAIN MOUSE SELECTION ************** */
-/* ***************** loop select (non modal) ************** */
-
-static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
-{
- ViewContext vc;
- EditMesh *em;
- EditEdge *eed;
- int select= 1;
- int dist= 50;
-
- em_setup_viewcontext(C, &vc);
- vc.mval[0]= mval[0];
- vc.mval[1]= mval[1];
- em= vc.em;
-
- 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())
-
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
- }
-}
-
-static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
-
- view3d_operator_needs_opengl(C);
-
- mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
- RNA_boolean_get(op->ptr, "ring"));
-
- /* cannot do tweaks for as long this keymap is after transform map */
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_loop_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Loop Select";
- ot->idname= "MESH_OT_loop_select";
-
- /* api callbacks */
- ot->invoke= mesh_select_loop_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
- RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
-}
-
/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
-/* since you want to create paths with multiple selects, it doesn't have extend option */
-static void mouse_mesh_shortest_path(bContext *C, short mval[2])
-{
- ViewContext vc;
- EditMesh *em;
- EditEdge *eed;
- int dist= 50;
-
- em_setup_viewcontext(C, &vc);
- vc.mval[0]= mval[0];
- vc.mval[1]= mval[1];
- em= vc.em;
-
- eed= findnearestedge(&vc, &dist);
- if(eed) {
- Mesh *me= vc.obedit->data;
- int path = 0;
-
- if (em->selected.last) {
- EditSelection *ese = em->selected.last;
-
- if(ese && ese->type == EDITEDGE) {
- EditEdge *eed_act;
- eed_act = (EditEdge*)ese->data;
- if (eed_act != eed) {
- if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
- 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 */
- }
-
- EM_selectmode_flush(em);
-
- /* even if this is selected it may not be in the selection list */
- if(edgetag_context_check(vc.scene, eed)==0)
- EM_remove_selection(em, eed, EDITEDGE);
- else
- EM_store_selection(em, eed, EDITEDGE);
-
- /* force drawmode for mesh */
- switch (vc.scene->toolsettings->edge_mode) {
-
- case EDGE_MODE_TAG_SEAM:
- me->drawflag |= ME_DRAWSEAMS;
- break;
- case EDGE_MODE_TAG_SHARP:
- me->drawflag |= ME_DRAWSHARP;
- break;
- case EDGE_MODE_TAG_CREASE:
- me->drawflag |= ME_DRAWCREASES;
- break;
- case EDGE_MODE_TAG_BEVEL:
- me->drawflag |= ME_DRAWBWEIGHTS;
- break;
- }
-
- DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
-
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
- }
-}
-
-
-static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
-
- view3d_operator_needs_opengl(C);
-
- mouse_mesh_shortest_path(C, event->mval);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_shortest_path(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shortest Path Select";
- ot->idname= "MESH_OT_select_shortest_path";
-
- /* api callbacks */
- ot->invoke= mesh_shortest_path_select_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* 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 */
-void mouse_mesh(bContext *C, short mval[2], short extend)
-{
- ViewContext vc;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- /* setup view context for argument to callbacks */
- em_setup_viewcontext(C, &vc);
- vc.mval[0]= mval[0];
- vc.mval[1]= mval[1];
-
- if(unified_findnearest(&vc, &eve, &eed, &efa)) {
-
- if(extend==0) EM_clear_flag_all(vc.em, SELECT);
-
- if(efa) {
- /* set the last selected face */
- EM_set_actFace(vc.em, efa);
-
- if( (efa->f & SELECT)==0 ) {
- EM_store_selection(vc.em, efa, EDITFACE);
- EM_select_face_fgon(vc.em, efa, 1);
- }
- else if(extend) {
- EM_remove_selection(vc.em, efa, EDITFACE);
- EM_select_face_fgon(vc.em, efa, 0);
- }
- }
- else if(eed) {
- if((eed->f & SELECT)==0) {
- EM_store_selection(vc.em, eed, EDITEDGE);
- EM_select_edge(eed, 1);
- }
- else if(extend) {
- EM_remove_selection(vc.em, eed, EDITEDGE);
- EM_select_edge(eed, 0);
- }
- }
- else if(eve) {
- if((eve->f & SELECT)==0) {
- eve->f |= SELECT;
- EM_store_selection(vc.em, eve, EDITVERT);
- }
- else if(extend){
- EM_remove_selection(vc.em, eve, EDITVERT);
- eve->f &= ~SELECT;
- }
- }
-
- EM_selectmode_flush(vc.em);
-
-// if (EM_texFaceCheck()) {
-
- if (efa && efa->mat_nr != vc.obedit->actcol-1) {
- vc.obedit->actcol= efa->mat_nr+1;
- vc.em->mat_nr= efa->mat_nr;
-// BIF_preview_changed(ID_MA);
- }
- }
-
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
-
-}
-
/* *********** select linked ************* */
/* for use with selectconnected_delimit_mesh only! */
@@ -2277,6 +1756,7 @@ else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
/* legacy warning, this function combines too much :) */
static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
{
+#if 0 //BMESH_TODO
EditMesh *em= vc->em;
EditFace *efa;
EditEdge *eed;
@@ -2367,7 +1847,7 @@ static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
EM_select_face(efa, 1);
// if (EM_texFaceCheck())
-
+#endif
return OPERATOR_FINISHED;
}
@@ -2377,6 +1857,7 @@ static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
+#if 0 //BMESH_TODO
Object *obedit= CTX_data_edit_object(C);
ViewContext vc;
EditVert *eve, *v1, *v2;
@@ -2461,6 +1942,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
return OPERATOR_FINISHED;
+#endif
}
void MESH_OT_select_linked_pick(wmOperatorType *ot)
@@ -3264,40 +2746,21 @@ void MESH_OT_select_inverse(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-/* ******************** (de)select all operator **************** */
-
-void EM_toggle_select_all(EditMesh *em) /* exported for UV */
+static int bmesh_test_exec(bContext *C, wmOperator *op)
{
- if(EM_nvertices_selected(em))
- EM_clear_flag_all(em, SELECT);
- else
- EM_set_flag_all(em, SELECT);
-}
-
-static int toggle_select_all_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_toggle_select_all(em);
-
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
- BKE_mesh_end_editmesh(obedit->data, em);
-
return OPERATOR_FINISHED;
}
-void MESH_OT_select_all_toggle(wmOperatorType *ot)
+void MESH_OT_bmesh_test(wmOperatorType *ot)
{
/* identifiers */
- ot->name= "Select/Deselect All";
- ot->idname= "MESH_OT_select_all_toggle";
+ ot->name= "bmesh test op";
+ ot->idname= "MESH_OT_bmesh_test";
/* api callbacks */
- ot->exec= toggle_select_all_exec;
+ ot->exec= bmesh_test_exec;
ot->poll= ED_operator_editmesh;
-
- /* flags */
+
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
@@ -3585,157 +3048,6 @@ static void mesh_selection_type(Scene *scene, EditMesh *em, int val)
}
}
-static EnumPropertyItem prop_mesh_edit_types[] = {
- {1, "VERT", 0, "Vertices", ""},
- {2, "EDGE", 0, "Edges", ""},
- {3, "FACE", 0, "Faces", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static int mesh_selection_type_exec(bContext *C, wmOperator *op)
-{
-
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- mesh_selection_type(CTX_data_scene(C), em, RNA_enum_get(op->ptr,"type"));
-
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_selection_type(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Selection Mode";
- ot->idname= "MESH_OT_selection_type";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= mesh_selection_type_exec;
-
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
-
-}
-/* ************************* 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;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_mark_seam(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark 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)
-{
- 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);
- 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_object_flush_update(scene, obedit, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_mark_sharp(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark Sharp";
- ot->idname= "MESH_OT_mark_sharp";
-
- /* api callbacks */
- ot->exec= editmesh_mark_sharp;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
-}
-
/* **************** NORMALS ************** */
/* XXX value of select is messed up, it means two things */
@@ -3954,6 +3266,7 @@ static int righthandfaces_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));
/* 'standard' behaviour - check if selected, then apply relevant selection */
@@ -4163,6 +3476,7 @@ void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, wmOperator *o
static int smooth_vertex(bContext *C, wmOperator *op)
{
+#if 0 //BMESH_TODO
Scene *scene= CTX_data_scene(C);
Object *obedit= CTX_data_edit_object(C);
EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
@@ -4173,12 +3487,18 @@ static int smooth_vertex(bContext *C, wmOperator *op)
int teller=0;
ModifierData *md;
+ if(em==NULL) {
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+
/* 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;
@@ -4296,6 +3616,7 @@ static int smooth_vertex(bContext *C, wmOperator *op)
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+#endif
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index efb68f69dac..50ac7894120 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -75,6 +75,8 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
#include "BKE_utildefines.h"
#include "BKE_bmesh.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -91,6 +93,7 @@ editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise
#include "UI_interface.h"
#include "mesh_intern.h"
+#include "bmesh.h"
/* XXX */
static int extern_qread() {return 0;}
@@ -529,6 +532,7 @@ static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y,
/* all verts with (flag & 'flag') are sorted */
void xsortvert_flag(bContext *C, int flag)
{
+#if 0 //BMESH_TODO
ViewContext vc;
EditVert *eve;
xvertsort *sortblock;
@@ -560,7 +564,7 @@ void xsortvert_flag(bContext *C, int flag)
addlisttolist(&vc.em->verts, &tbase);
MEM_freeN(sortblock);
-
+#endif
}
/* called from buttons */
@@ -641,12 +645,15 @@ void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op)
}
else if(em->selectmode & SCE_SELECT_EDGE) {
if (em->totedgesel==0) nr = 0;
- else if (em->totedgesel==1) nr = 3;
+
+ 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->totfacesel == 0) nr = 0;
@@ -696,6 +703,8 @@ void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op)
}
+#if 0
+//need to see if this really had new stuff I should merge over
// XXX should be a menu item
static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
@@ -752,6 +761,7 @@ void MESH_OT_extrude(wmOperatorType *ot)
Properties_Proportional(ot);
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
}
+#endif
static int split_mesh(bContext *C, wmOperator *op)
{
@@ -790,7 +800,9 @@ void MESH_OT_split(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-
+#if 0
+//this also showed up in a merge, need to check if it
+//needs changes ported over to new extrude code too
static int extrude_repeat_mesh(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
@@ -853,7 +865,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
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);
}
-
+#endif
/* ************************** spin operator ******************** */
@@ -1146,190 +1158,6 @@ static void erase_vertices(EditMesh *em, ListBase *l)
}
}
-void delete_mesh(Object *obedit, EditMesh *em, wmOperator *op, int event)
-{
- EditFace *efa, *nextvl;
- EditVert *eve,*nextve;
- EditEdge *eed,*nexted;
- int count;
- 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;
- }
- }
-
- 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)
-{
- Scene *scene= CTX_data_scene(C);
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- delete_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
-
- DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_delete(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Delete";
- 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 */
- RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
-}
-
-
/*GB*/
/*-------------------------------------------------------------------------------*/
/*--------------------------- Edge Based Subdivide ------------------------------*/
@@ -1382,7 +1210,7 @@ static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int
co[1] += vec1[1];
co[2] += vec1[2];
}
- else if(beauty & B_SPHERE) { /* subdivide sphere */
+ /*else if(beauty & B_SPHERE) { // subdivide sphere
Normalize(co);
co[0]*= smooth;
co[1]*= smooth;
@@ -1395,7 +1223,7 @@ static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int
vec1[1]= fac*(float)(0.5-BLI_drand());
vec1[2]= fac*(float)(0.5-BLI_drand());
VecAddf(co, co, vec1);
- }
+ }*/
}
/* assumes in the edge is the correct interpolated vertices already */
@@ -2243,7 +2071,7 @@ static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, 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.v2 = innerverts[i][0] = verts[1][i];
temp.v1 = innerverts[i][numcuts+1] = verts[3][i];
for(j=1;j<=numcuts;j++) {
@@ -2382,7 +2210,7 @@ static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int n
MEM_freeN(innerverts);
}
-//Next two fill types are for knife exact only and are provided to allow for knifing through vertices
+//Next two fill types are for 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)
{
@@ -4780,6 +4608,7 @@ static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
/* based on mouse cursor position, it defines how is being ripped */
static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
+#if 0 //BMESH_TODO
Scene *scene= CTX_data_scene(C);
ARegion *ar= CTX_wm_region(C);
RegionView3D *rv3d= ar->regiondata;
@@ -4984,6 +4813,7 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
RNA_enum_set(op->ptr, "proportional", 0);
RNA_boolean_set(op->ptr, "mirror", 0);
WM_operator_name_call(C, "TFM_OT_translation", WM_OP_INVOKE_REGION_WIN, op->ptr);
+#endif
return OPERATOR_FINISHED;
}
@@ -5053,6 +4883,7 @@ void shape_propagate(Scene *scene, Object *obedit, EditMesh *em, wmOperator *op)
void shape_copy_from_lerp(EditMesh *em, KeyBlock* thisBlock, KeyBlock* fromBlock)
{
+#if 0 //BMESH_TODO
EditVert *ev = NULL;
short mval[2], curval[2], event = 0, finished = 0, canceled = 0, fullcopy=0 ;
float perc = 0;
@@ -5129,6 +4960,7 @@ void shape_copy_from_lerp(EditMesh *em, KeyBlock* thisBlock, KeyBlock* fromBlock
}
}
return;
+#endif
}
@@ -6645,52 +6477,6 @@ void MESH_OT_colors_mirror(wmOperatorType *ot)
RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
}
-/********************** Subdivide Operator *************************/
-
-static int subdivide_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);
- int cuts= RNA_int_get(op->ptr,"number_cuts");
- float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
- float fractal= RNA_float_get(op->ptr, "fractal")/100;
- int flag= 0;
-
- if(smooth != 0.0f)
- flag |= B_SMOOTH;
- if(fractal != 0.0f)
- flag |= B_FRACTAL;
-
- esubdivideflag(obedit, em, 1, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0);
-
- DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_subdivide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Subdivide";
- 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, 10, "Number of Cuts", "", 1, INT_MAX);
- RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
- RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
-}
-
-/********************** 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 beauty_fill(EditMesh *em)
@@ -7002,14 +6788,15 @@ static int quads_convert_to_tris_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;
- convert_to_triface(em,0);
+ //convert_to_triface(em,0);
+ if (!EDBM_CallOpf(em, op, "triangulate faces=%hf", BM_SELECT))
+ return OPERATOR_CANCELLED;
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
- BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 6e098e04a14..7f974a532d8 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -32,11 +32,54 @@
#ifndef MESH_INTERN_H
#define MESH_INTERN_H
+#include "BLI_editVert.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
struct bContext;
struct wmOperatorType;
+struct ViewContext;
+struct BMEditMesh;
+struct BMesh;
+struct BMEdge;
+struct BMFace;
#define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float));
+/* ******************** 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, doing conversions,
+ etc.*/
+int EDBM_CallOpf(struct BMEditMesh *em, struct wmOperator *op, char *fmt, ...);
+
+/*same as above, but doesn't report errors.*/
+int EDBM_CallOpfSilent(struct BMEditMesh *em, 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, char *fmt, ...);
+/*cleans up after a bmesh operator*/
+int EDBM_FinishOp(struct BMEditMesh *em, struct BMOperator *bmop,
+ struct wmOperator *op, int report);
+
+void EDBM_clear_flag_all(struct BMEditMesh *em, int flag);
+void EDBM_set_actFace(struct BMEditMesh *em, struct BMFace *efa);
+void EDBM_store_selection(struct BMEditMesh *em, void *data);
+void EDBM_validate_selections(struct BMEditMesh *em);
+void EDBM_remove_selection(struct BMEditMesh *em, void *data);
+void EDBM_stats_update(struct BMEditMesh *em);
+
/* ******************** editface.c */
int edgetag_context_check(Scene *scene, EditEdge *eed);
@@ -45,11 +88,18 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge
/* ******************* editmesh.c */
+void EM_beginEditMesh(struct Object *ob);
+void EM_endEditMesh(struct Object *ob, EditMesh *em);
+
extern void free_editvert(EditMesh *em, EditVert *eve);
extern void free_editedge(EditMesh *em, EditEdge *eed);
extern void free_editface(EditMesh *em, EditFace *efa);
void free_editMesh(EditMesh *em);
+/*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);
@@ -67,7 +117,7 @@ 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);
-void em_setup_viewcontext(struct bContext *C, ViewContext *vc);
+void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc);
void MESH_OT_separate(struct wmOperatorType *ot);
@@ -149,6 +199,7 @@ void MESH_OT_knife_cut(struct wmOperatorType *ot);
/* ******************* editmesh_mods.c */
void MESH_OT_loop_select(struct wmOperatorType *ot);
void MESH_OT_select_all_toggle(struct wmOperatorType *ot);
+void MESH_OT_bmesh_test(struct wmOperatorType *ot);
void MESH_OT_select_more(struct wmOperatorType *ot);
void MESH_OT_select_less(struct wmOperatorType *ot);
void MESH_OT_select_inverse(struct wmOperatorType *ot);
@@ -172,13 +223,13 @@ void MESH_OT_mark_sharp(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth(struct wmOperatorType *ot);
void MESH_OT_flip_normals(struct wmOperatorType *ot);
-extern EditEdge *findnearestedge(ViewContext *vc, int *dist);
+extern EditEdge *findnearestedge(struct ViewContext *vc, int *dist);
extern void EM_automerge(int update);
void editmesh_select_by_material(EditMesh *em, int index);
void righthandfaces(EditMesh *em, 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);
+void faceloop_select(struct BMEditMesh *em, struct BMEdge *startedge, int select);
/**
* findnearestvert
@@ -189,7 +240,7 @@ void faceloop_select(EditMesh *em, EditEdge *startedge, int select);
* if 0, unselected vertice are given the bias
* strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
*/
-extern EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict);
+extern EditVert *findnearestvert(struct ViewContext *vc, int *dist, short sel, short strict);
/* ******************* editmesh_tools.c */
@@ -202,7 +253,7 @@ extern EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short st
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 beauty, int numcuts, int seltype);
-int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc);
+int EdgeSlide(EditMesh *em, struct wmOperator *op, short immediate, float imperc);
void MESH_OT_merge(struct wmOperatorType *ot);
void MESH_OT_subdivide(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_layers.c b/source/blender/editors/mesh/mesh_layers.c
index 99d50d1a9b0..bad2fa99434 100644
--- a/source/blender/editors/mesh/mesh_layers.c
+++ b/source/blender/editors/mesh/mesh_layers.c
@@ -44,6 +44,7 @@
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BLI_editVert.h"
@@ -57,10 +58,11 @@
#include "ED_view3d.h"
#include "mesh_intern.h"
+#include "bmesh.h"
static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer)
{
- CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
+ CustomData *data= (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata;
void *actlayerdata, *rndlayerdata, *clonelayerdata, *masklayerdata, *layerdata=layer->data;
int type= layer->type;
int index= CustomData_get_layer_index(data, type);
@@ -79,8 +81,8 @@ static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer)
masklayerdata = data->layers[CustomData_get_mask_layer_index(data, type)].data;
CustomData_set_layer_active(data, type, layer - &data->layers[index]);
- if(me->edit_mesh) {
- EM_free_data_layer(me->edit_mesh, data, type);
+ if(me->edit_btmesh) {
+ BM_free_data_layer(me->edit_btmesh->bm, data, type);
}
else {
CustomData_free_layer_active(data, type, me->totface);
@@ -88,7 +90,7 @@ static void delete_customdata_layer(Mesh *me, CustomDataLayer *layer)
}
if(!CustomData_has_layer(data, type))
- if(type == CD_MCOL && (G.f & G_VERTEXPAINT))
+ if(type == CD_MLOOPCOL && (G.f & G_VERTEXPAINT))
G.f &= ~G_VERTEXPAINT; /* get out of vertexpaint mode */
/* reconstruct active layer */
@@ -156,7 +158,7 @@ static int uv_texture_add_exec(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
Mesh *me;
- EditMesh *em;
+ BMEditMesh *em;
int layernum;
if(!ob || ob->type!=OB_MESH)
@@ -165,26 +167,30 @@ static int uv_texture_add_exec(bContext *C, wmOperator *op)
me= (Mesh*)ob->data;
if(scene->obedit == ob) {
- em= me->edit_mesh;
+ em= me->edit_btmesh;
- layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
+ layernum= CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
if(layernum >= MAX_MTFACE)
return OPERATOR_CANCELLED;
- EM_add_data_layer(em, &em->fdata, CD_MTFACE);
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum);
+ BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
+ CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
}
else if(ob) {
- layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ layernum= CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
if(layernum >= MAX_MTFACE)
return OPERATOR_CANCELLED;
- if(me->mtface)
- CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface);
- else
- CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface);
-
- CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum);
+ if (me->mtpoly) {
+ CustomData_add_layer(&me->pdata, CD_MTEXPOLY, CD_DUPLICATE, me->mtpoly, me->totpoly);
+ CustomData_add_layer(&me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop);
+ } else {
+ CustomData_add_layer(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly);
+ CustomData_add_layer(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop);
+ }
+
+ CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum);
mesh_update_customdata_pointers(me);
}
@@ -212,20 +218,24 @@ static int uv_texture_remove_exec(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
Mesh *me;
- CustomDataLayer *cdl;
+ CustomDataLayer *cdl, *cdl2;
int index;
if(!ob || ob->type!=OB_MESH)
return OPERATOR_CANCELLED;
me= (Mesh*)ob->data;
- index= CustomData_get_active_layer_index(&me->fdata, CD_MTFACE);
- cdl= (index == -1)? NULL: &me->fdata.layers[index];
+ index= CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+ cdl= (index == -1)? NULL: &me->pdata.layers[index];
+
+ index= CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV);
+ cdl2= (index == -1)? NULL: &me->ldata.layers[index];
if(!cdl)
return OPERATOR_CANCELLED;
delete_customdata_layer(me, cdl);
+ delete_customdata_layer(me, cdl2);
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
@@ -253,8 +263,8 @@ static int vertex_color_add_exec(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
Mesh *me;
- EditMesh *em;
- MCol *mcol;
+ BMEditMesh *em;
+ MLoopCol *mcol;
int layernum;
if(!ob || ob->type!=OB_MESH)
@@ -263,28 +273,28 @@ static int vertex_color_add_exec(bContext *C, wmOperator *op)
me= (Mesh*)ob->data;
if(scene->obedit == ob) {
- em= me->edit_mesh;
+ em= me->edit_btmesh;
- layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL);
+ layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
if(layernum >= MAX_MCOL)
return OPERATOR_CANCELLED;
- EM_add_data_layer(em, &em->fdata, CD_MCOL);
- CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
+ BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPCOL);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
}
else {
- layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL);
+ layernum= CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
if(layernum >= MAX_MCOL)
return OPERATOR_CANCELLED;
- mcol= me->mcol;
+ mcol= me->mloopcol;
- if(me->mcol)
- CustomData_add_layer(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface);
+ if(me->mloopcol)
+ CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop);
else
- CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface);
+ CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop);
- CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum);
mesh_update_customdata_pointers(me);
if(!mcol)
@@ -322,8 +332,8 @@ static int vertex_color_remove_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
me= (Mesh*)ob->data;
- index= CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
- cdl= (index == -1)? NULL: &me->fdata.layers[index];
+ index= CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL);
+ cdl= (index == -1)? NULL: &me->ldata.layers[index];
if(!cdl)
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index c10fdbcfd8f..5f406cb4db8 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -72,6 +72,7 @@
#include "BKE_object.h"
#include "BKE_utildefines.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "RE_pipeline.h"
#include "RE_shader_ext.h"
@@ -118,15 +119,17 @@ int join_mesh_exec(bContext *C, wmOperator *op)
MVert *mvert, *mv, *mvertmain;
MEdge *medge = NULL, *medgemain;
MFace *mface = NULL, *mfacemain;
+ MPoly *mpoly = NULL, *mpolymain;
+ MLoop *mloop = NULL, *mloopmain;
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;
- int i, j, index, haskey=0, edgeofs, faceofs;
+ int totloop=0, totpoly=0, vertofs, *matmap;
+ int i, j, index, haskey=0, edgeofs, faceofs, loopofs, polyofs;
bDeformGroup *dg, *odg;
MDeformVert *dvert;
- CustomData vdata, edata, fdata;
+ CustomData vdata, edata, fdata, ldata, pdata;
if(scene->obedit)
return OPERATOR_CANCELLED;
@@ -143,6 +146,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)
@@ -290,18 +295,26 @@ 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);
mvertmain= mvert;
medgemain= medge;
mfacemain= mface;
+ mloopmain = mloop;
+ mpolymain = mpoly;
vertofs= 0;
edgeofs= 0;
faceofs= 0;
+ loopofs= 0;
+ polyofs= 0;
/* inverse transform for all selected meshes in this object */
Mat4Invert(imat, ob->obmat);
@@ -451,7 +464,43 @@ int join_mesh_exec(bContext *C, wmOperator *op)
edgeofs += me->totedge;
}
+
+ if (me->totloop) {
+ 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;
+ }
+
+ loopofs += me->totloop;
+ }
+ if(me->totpoly) {
+ /* make mapping for materials */
+ for(a=1; a<=base->object->totcol; a++) {
+ ma= give_current_material(base->object, a);
+
+ for(b=0; b<totcol; b++) {
+ if(ma == matar[b]) {
+ matmap[a-1]= b;
+ break;
+ }
+ }
+ }
+
+ CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+ CustomData_copy_data(&me->pdata, &pdata, 0, polyofs, me->totpoly);
+
+ for(a=0; a<me->totpoly; a++, mpoly++) {
+ mpoly->loopstart += loopofs;
+ mpoly->mat_nr= matmap[(int)mpoly->mat_nr];
+ }
+
+ polyofs += me->totface;
+ }
+
/* vertofs is used to help newly added verts be reattached to their edge/face
* (cannot be set earlier, or else reattaching goes wrong)
*/
@@ -470,14 +519,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);
@@ -838,7 +893,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;
@@ -864,10 +919,12 @@ 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)
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter))
DO_MINMAX(eve->co, min, max)
}
else {
@@ -905,10 +962,12 @@ 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) {
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter)) {
mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve));
}
}
@@ -964,7 +1023,7 @@ int mesh_get_x_mirror_vert(Object *ob, int index)
return mesh_octree_table(ob, NULL, vec, 'u');
}
-EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co)
+BMVert *editmesh_get_x_mirror_vert(Object *ob, BMEditMesh *em, float *co)
{
float vec[3];
intptr_t poinval;
@@ -982,7 +1041,7 @@ EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co)
poinval= mesh_octree_table(ob, em, vec, 'u');
if(poinval != -1)
- return (EditVert *)(poinval);
+ return (BMVert *)(poinval);
return NULL;
}
@@ -1032,7 +1091,7 @@ static int mirror_facecmp(void *a, void *b)
return (mirror_facerotation((MFace*)a, (MFace*)b) == -1);
}
-int *mesh_get_x_mirror_faces(Object *ob, EditMesh *em)
+int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em)
{
Mesh *me= ob->data;
MVert *mv, *mvert= me->mvert;
diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript
index 3371e172a82..0b7a4e41192 100644
--- a/source/blender/editors/object/SConscript
+++ b/source/blender/editors/object/SConscript
@@ -6,7 +6,7 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc'
incs += ' #/intern/guardedalloc'
-incs += ' ../../makesrna ../../python'
+incs += ' ../../makesrna ../../python ../../bmesh'
defs = []
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 0746fbaefb6..a938018d97b 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -96,6 +96,7 @@
#include "BKE_material.h"
#include "BKE_mball.h"
#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -845,13 +846,14 @@ static void copy_object_set_idnew(Scene *scene, View3D *v3d, int dupflag)
}
-static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent)
+static int return_editmesh_indexar(BMEditMesh *em, int *tot, int **indexar, float *cent)
{
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
int *index, nr, totvert=0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) totvert++;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) totvert++;
}
if(totvert==0) return 0;
@@ -860,8 +862,8 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float
nr= 0;
cent[0]= cent[1]= cent[2]= 0.0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) {
*index= nr; index++;
VecAddf(cent, cent, eve->co);
}
@@ -873,19 +875,19 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float
return totvert;
}
-static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent)
+static int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent)
{
MDeformVert *dvert;
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
int i, totvert=0;
cent[0]= cent[1]= cent[2]= 0.0;
if(obedit->actdef) {
-
/* find the vertices */
- for(eve= em->verts.first; eve; eve= eve->next) {
- dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ dvert= CustomData_em_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT);
if(dvert) {
for(i=0; i<dvert->totweight; i++){
@@ -910,19 +912,18 @@ static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, floa
static void select_editmesh_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;
- for(eve= em->verts.first; eve; eve= eve->next, nr++) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
if(nr==hmd->indexar[index]) {
- eve->f |= SELECT;
+ BM_Select(em->bm, eve, 1);
if(index < hmd->totindex-1) index++;
}
+ nr++;
}
- EM_select_flush(em);
-
- BKE_mesh_end_editmesh(me, em);
}
static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent)
@@ -1095,16 +1096,13 @@ int hook_getIndexArray(Object *obedit, int *tot, int **indexar, char *name, floa
case OB_MESH:
{
Mesh *me= obedit->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
/* check selected vertices first */
if( return_editmesh_indexar(em, tot, indexar, cent_r)) {
- BKE_mesh_end_editmesh(me, em);
return 1;
} else {
- int ret = return_editmesh_vgroup(obedit, em, name, cent_r);
- BKE_mesh_end_editmesh(me, em);
- return ret;
+ return return_editmesh_vgroup(obedit, em, name, cent_r);
}
}
case OB_CURVE:
@@ -2541,10 +2539,10 @@ void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d)
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
- eve= em->verts.first;
- while(eve) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
if(eve->f & 1) {
if(v1==0) v1= nr;
else if(v2==0) v2= nr;
@@ -2553,10 +2551,7 @@ void make_vertex_parent(Scene *scene, Object *obedit, View3D *v3d)
else break;
}
nr++;
- eve= eve->next;
}
-
- BKE_mesh_end_editmesh(me, em);
}
else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) {
ListBase *editnurb= curve_get_editcurve(obedit);
@@ -3179,9 +3174,10 @@ static int object_center_set_exec(bContext *C, wmOperator *op)
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
+ BMEditMesh *em = me->edit_btmesh;
+ BMIter iter;
- for(eve= em->verts.first; eve; eve= eve->next) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
if(v3d->around==V3D_CENTROID) {
total++;
VECADD(cent, cent, eve->co);
@@ -3200,14 +3196,13 @@ static int object_center_set_exec(bContext *C, wmOperator *op)
cent[2]= (min[2]+max[2])/2.0f;
}
- for(eve= em->verts.first; eve; eve= eve->next) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
VecSubf(eve->co, eve->co, cent);
}
- recalc_editnormals(em);
+ EDBM_RecalcNormals(em);
tot_change++;
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
- BKE_mesh_end_editmesh(me, em);
}
}
@@ -3504,16 +3499,17 @@ void ED_object_exit_editmode(bContext *C, int flag)
// if(retopo_mesh_paint_check())
// retopo_end_okee();
- if(me->edit_mesh->totvert>MESH_MAX_VERTS) {
+ if(me->edit_btmesh->bm->totvert>MESH_MAX_VERTS) {
error("Too many vertices");
return;
}
- load_editMesh(scene, obedit);
+
+ EDBM_LoadEditBMesh(scene, obedit);
if(freedata) {
- free_editMesh(me->edit_mesh);
- MEM_freeN(me->edit_mesh);
- me->edit_mesh= NULL;
+ EDBM_FreeEditBMesh(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh= NULL;
}
if(G.f & G_WEIGHTPAINT)
@@ -3597,7 +3593,7 @@ void ED_object_enter_editmode(bContext *C, int flag)
ok= 1;
scene->obedit= ob; // context sees this
- make_editMesh(scene, ob);
+ EDBM_MakeEditBMesh(scene, ob);
WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene);
}
diff --git a/source/blender/editors/physics/editparticle.c b/source/blender/editors/physics/editparticle.c
index 3f7880b7fef..da8bcaab0b5 100644
--- a/source/blender/editors/physics/editparticle.c
+++ b/source/blender/editors/physics/editparticle.c
@@ -1015,7 +1015,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
mvert=dm->getVertDataArray(dm,CD_MVERT);
for(i=0; i<totface; i++, vec+=6, nor+=6) {
- mface=dm->getFaceData(dm,i,CD_MFACE);
+ mface=dm->getTessFaceData(dm,i,CD_MFACE);
mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
VECCOPY(vec,mvert->co);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 113e7249e65..19cbf93a83c 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -201,7 +201,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;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 720e64d260f..08a1c014a10 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -2966,11 +2966,11 @@ static void project_paint_begin(ProjPaintState *ps)
return;
}
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? */
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 85ea55331dc..46d41c043bd 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -80,9 +80,9 @@ static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, fl
void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceindex, int *xy, float *uv)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
- MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
- int numfaces = dm->getNumFaces(dm), a;
+ int *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ MTFace *tface = dm->getTessFaceDataArray(dm, CD_MTFACE), *tf;
+ int numfaces = dm->getNumTessFaces(dm), a;
float p[2], w[3], absw, minabsw;
MFace mf;
MVert mv[4];
@@ -93,7 +93,7 @@ void imapaint_pick_uv(Scene *scene, Object *ob, Mesh *mesh, unsigned int faceind
/* test all faces in the derivedmesh with the original index of the picked face */
for(a = 0; a < numfaces; a++) {
if(index[a] == 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/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 7245218c688..f3108e02159 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -1001,8 +1001,8 @@ static void sculpt_update_mesh_elements(bContext *C)
ss->totvert = dm->getNumVerts(dm);
ss->totface = dm->getNumFaces(dm);
ss->mvert = dm->getVertDataArray(dm, CD_MVERT);
- ss->mface = dm->getFaceDataArray(dm, CD_MFACE);
- ss->face_normals = dm->getFaceDataArray(dm, CD_NORMAL);
+ ss->mface = dm->getTessFaceDataArray(dm, CD_MFACE);
+ ss->face_normals = dm->getTessFaceDataArray(dm, CD_NORMAL);
}
else {
Mesh *me = get_mesh(ob);
diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript
index a0a7dad4077..71530d6f92d 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 ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
-incs += ' ../../makesrna ../../render/extern/include'
+incs += ' ../../makesrna ../../render/extern/include ../../bmesh'
defs = []
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index fb1e9d1214d..0c3bda5b9b8 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -50,6 +50,7 @@
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_world.h"
+#include "BKE_tessmesh.h"
#include "BLI_editVert.h"
#include "BLI_listbase.h"
@@ -128,12 +129,13 @@ static int material_slot_assign_exec(bContext *C, wmOperator *op)
if(ob && ob->actcol>0) {
if(ob->type == OB_MESH) {
- EditMesh *em= ((Mesh*)ob->data)->edit_mesh;
- EditFace *efa;
+ BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
if(em) {
- for(efa= em->faces.first; efa; efa=efa->next)
- if(efa->f & SELECT)
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL)
+ if(BM_TestHFlag(efa, BM_SELECT))
efa->mat_nr= ob->actcol-1;
}
}
@@ -185,7 +187,7 @@ 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;
+ EditMesh *em= BKE_mesh_get_editmesh(((Mesh*)ob->data));
if(em) {
if(select)
@@ -193,6 +195,8 @@ static int material_slot_de_select(bContext *C, int select)
else
EM_deselect_by_material(em, ob->actcol-1);
}
+
+ BKE_mesh_end_editmesh(ob->data, em);
}
else if ELEM(ob->type, OB_CURVE, OB_SURF) {
ListBase *editnurb= ((Curve*)ob->data)->editnurb;
diff --git a/source/blender/editors/space_image/image_header.c b/source/blender/editors/space_image/image_header.c
index 35088f0e4d1..e4cd5c77703 100644
--- a/source/blender/editors/space_image/image_header.c
+++ b/source/blender/editors/space_image/image_header.c
@@ -48,6 +48,7 @@
#include "BKE_mesh.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index 7d51d237ef0..b90ac30cd41 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -7,7 +7,7 @@ defs = []
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include #/intern/guardedalloc'
-incs += ' ../../gpu ../../makesrna ../../blenfont'
+incs += ' ../../gpu ../../makesrna ../../blenfont ../../bmesh '
if env['WITH_BF_GAMEENGINE']:
defs.append('GAMEBLENDER=1')
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 1807de9efbb..a04d6d07d24 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -550,6 +550,7 @@ void draw_mesh_text(Scene *scene, Object *ob, int glsl)
void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int faceselect)
{
+#if 0
Mesh *me= ob->data;
/* correct for negative scale */
@@ -586,5 +587,6 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o
/* in editmode, the blend mode needs to be set incase it was ADD */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+#endif
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 93c6c535a31..0c521512c12 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -88,6 +88,7 @@
#include "BKE_particle.h"
#include "BKE_property.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -227,7 +228,7 @@ static int check_material_alpha(Base *base, Mesh *me, int glsl)
if(G.f & G_PICKSEL)
return 0;
- if(me->edit_mesh)
+ if(me->edit_btmesh)
return 0;
return (glsl || (base->object->dtx & OB_DRAWTRANSP));
@@ -1278,10 +1279,10 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
{
- struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
+ BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index);
- if (eve->h==0) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
short s[2]= {IS_CLIPPED, 0};
if (data->clipVerts) {
@@ -1295,30 +1296,30 @@ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co
}
}
-void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts)
+void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BMVert *eve, int x, int y, int index), void *userData, int clipVerts)
{
- struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
data.userData = userData;
data.clipVerts = clipVerts;
- 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);
}
static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
{
- struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
- EditEdge *eed = EM_get_edge_for_index(index);
+ struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
+ BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index);
short s[2][2];
- if (eed->h==0) {
+ if (!BM_TestHFlag(eed, BM_HIDDEN)) {
if (data->clipVerts==1) {
view3d_project_short_clip(data->vc.ar, v0co, s[0]);
view3d_project_short_clip(data->vc.ar, v1co, s[1]);
@@ -1337,48 +1338,48 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0
}
}
-void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
+void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
{
- struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
data.userData = userData;
data.clipVerts = clipVerts;
- 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);
}
static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *no)
{
- struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData;
- EditFace *efa = EM_get_face_for_index(index);
+ struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } *data = userData;
+ BMFace *efa = EDBM_get_face_for_index(data->vc.em, index);
short s[2];
- if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
+ if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) {
view3d_project_short_clip(data->vc.ar, cent, s);
data->func(data->userData, efa, s[0], s[1], index);
}
}
-void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData)
+void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, BMFace *efa, int x, int y, int index), void *userData)
{
- struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data;
- DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
+ struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
data.vc= *vc;
data.func = func;
data.userData = userData;
- 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);
}
@@ -1441,46 +1442,54 @@ void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb
static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
{
+ Scene *scene= ((void **)userData)[0];
+ BMEditMesh *em = ((void **)userData)[1];
+ BMFace *efa = EDBM_get_face_for_index(em, index);
ToolSettings *ts= ((Scene *)userData)->toolsettings;
- EditFace *efa = EM_get_face_for_index(index);
- if (efa->h==0 && efa->fgonf!=EM_FGON) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN)) {
glVertex3fv(cent);
glVertex3f( cent[0] + no[0]*ts->normalsize,
cent[1] + no[1]*ts->normalsize,
cent[2] + no[2]*ts->normalsize);
}
}
-static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm)
+static void draw_dm_face_normals(BMEditMesh *tm, Scene *scene, DerivedMesh *dm)
{
+ void *ptrs[2] = {scene, tm};
+
glBegin(GL_LINES);
- dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene);
+ dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, ptrs);
glEnd();
}
static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *no)
{
- EditFace *efa = EM_get_face_for_index(index);
- int sel = *((int*) userData);
+ BMFace *efa = EDBM_get_face_for_index(((void **)userData)[0], index);
+ BMEditMesh *em = ((void **)userData)[0];
+ int sel = *(((int **)userData)[1]);
- if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)==sel) {
bglVertex3fv(cent);
}
}
-static void draw_dm_face_centers(DerivedMesh *dm, int sel)
+static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
{
+ void *ptrs[2] = {em, &sel};
+
bglBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel);
+ dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
bglEnd();
}
static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
{
- Scene *scene= (Scene *)userData;
+ Scene *scene= ((void **)userData)[0];
ToolSettings *ts= scene->toolsettings;
- EditVert *eve = EM_get_vert_for_index(index);
+ BMEditMesh *em = ((void **)userData)[1];
+ BMVert *eve = EDBM_get_vert_for_index(em, index);
- if (eve->h==0) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
glVertex3fv(co);
if (no_f) {
@@ -1494,20 +1503,22 @@ static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co,
}
}
}
-static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm)
+static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
{
+ void *ptrs[2] = {scene, em};
+
glBegin(GL_LINES);
- dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene);
+ dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, ptrs);
glEnd();
}
/* Draw verts with color set based on selection */
static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
{
- struct { int sel; EditVert *eve_act; } * data = userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ struct { BMEditMesh *em; int sel; BMVert *eve_act; } *data = userData;
+ BMVert *eve = EDBM_get_vert_for_index(data->em, index);
- if (eve->h==0 && (eve->f&SELECT)==data->sel) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)==data->sel) {
/* draw active larger - need to stop/start point drawing for this :/ */
if (eve==data->eve_act) {
float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
@@ -1528,11 +1539,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)
{
- struct { int sel; EditVert *eve_act; } data;
+ struct { BMEditMesh *em; int sel; BMVert *eve_act; } data;
data.sel = sel;
data.eve_act = eve_act;
+ data.em = em;
bglBegin(GL_POINTS);
dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
@@ -1542,16 +1554,18 @@ static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
/* Draw edges with color set based on selection */
static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed;
//unsigned char **cols = userData, *col;
- struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData;
+ struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } * data = userData;
unsigned char *col;
- if (eed->h==0) {
+ eed = EDBM_get_edge_for_index(data->em, index);
+
+ if (!BM_TestHFlag(eed, BM_HIDDEN)) {
if (eed==data->eed_act) {
glColor4ubv(data->actCol);
} else {
- if (eed->f&SELECT) {
+ if (BM_TestHFlag(eed, BM_SELECT)) {
col = data->selCol;
} else {
col = data->baseCol;
@@ -1566,13 +1580,15 @@ static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
return 0;
}
}
-static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act)
+static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
+ unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act)
{
- struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data;
+ struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } data;
data.baseCol = baseCol;
data.selCol = selCol;
data.actCol = actCol;
+ data.em = em;
data.eed_act = eed_act;
dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
}
@@ -1580,60 +1596,65 @@ static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned
/* Draw edges */
static int draw_dm_edges__setDrawOptions(void *userData, int index)
{
- return EM_get_edge_for_index(index)->h==0;
+ return !BM_TestHFlag(EDBM_get_edge_for_index(userData, index), BM_HIDDEN);
}
-static void draw_dm_edges(DerivedMesh *dm)
+static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
{
- dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
}
/* Draw edges with color interpolated based on selection */
static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
{
- return EM_get_edge_for_index(index)->h==0;
+ return !BM_TestHFlag(EDBM_get_edge_for_index(((void**)userData)[1], index), BM_HIDDEN);
}
static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
{
- EditEdge *eed = EM_get_edge_for_index(index);
- unsigned char **cols = userData;
- unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
- unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
+ BMEdge *eed = EDBM_get_edge_for_index(((void**)userData)[1], index);
+ unsigned char **cols = ((void**)userData)[0];
+ unsigned char *col0 = cols[(BM_TestHFlag(eed->v1, BM_SELECT))?1:0];
+ unsigned char *col1 = cols[(BM_TestHFlag(eed->v2, BM_SELECT))?1:0];
glColor4ub( col0[0] + (col1[0]-col0[0])*t,
col0[1] + (col1[1]-col0[1])*t,
col0[2] + (col1[2]-col0[2])*t,
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];
+ void *ptrs[2] = {cols, em};
+
cols[0] = baseCol;
cols[1] = selCol;
- dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
+ dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions,
+ draw_dm_edges_sel_interp__setDrawInterpOptions, ptrs);
}
/* Draw only seam edges */
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_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_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 *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
- return (eed->h==0 && eed->sharp);
+ return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SHARP);
}
-static void draw_dm_edges_sharp(DerivedMesh *dm)
+static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
{
- dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
+ dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
}
@@ -1641,16 +1662,16 @@ static void draw_dm_edges_sharp(DerivedMesh *dm)
* return 2 for the active face so it renders with stipple enabled */
static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *drawSmooth_r)
{
- struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
- EditFace *efa = EM_get_face_for_index(index);
+ struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; } *data = userData;
+ BMFace *efa = EDBM_get_face_for_index(data->em, index);
unsigned char *col;
- if (efa->h==0) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN)) {
if (efa == data->efa_act) {
glColor4ubv(data->cols[2]);
return 2; /* stipple */
} else {
- col = data->cols[(efa->f&SELECT)?1:0];
+ col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0];
if (col[3]==0) return 0;
glColor4ubv(col);
return 1;
@@ -1660,10 +1681,13 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *dra
}
/* also draws the active face */
-static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act)
+static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
+ unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
{
- struct { unsigned char *cols[3]; EditFace *efa_act; } data;
+ struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; } data;
+
data.cols[0] = baseCol;
+ data.em = em;
data.cols[1] = selCol;
data.cols[2] = actCol;
data.efa_act = efa_act;
@@ -1673,27 +1697,27 @@ static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned
static int draw_dm_creases__setDrawOptions(void *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
- if (eed->h==0 && eed->crease!=0.0) {
+ if (!BM_TestHFlag(eed, BM_HIDDEN) && eed->crease!=0.0) {
UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->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 *userData, int index)
{
- EditEdge *eed = EM_get_edge_for_index(index);
+ BMEdge *eed = EDBM_get_edge_for_index(userData, index);
- if (eed->h==0 && eed->bweight!=0.0) {
+ if (!BM_TestHFlag(eed, BM_HIDDEN) && eed->bweight!=0.0) {
UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
return 1;
} else {
@@ -1702,26 +1726,26 @@ static int draw_dm_bweights__setDrawOptions(void *userData, int index)
}
static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
{
- EditVert *eve = EM_get_vert_for_index(index);
+ BMVert *eve = EDBM_get_vert_for_index(userData, index);
- if (eve->h==0 && eve->bweight!=0.0) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN) && eve->bweight!=0.0) {
UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->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);
}
}
@@ -1735,7 +1759,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, EditMesh *em, 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;
@@ -1772,13 +1797,13 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, EditM
if(ts->selectmode & SCE_SELECT_VERTEX) {
glPointSize(size);
glColor4ubv((GLubyte *)col);
- draw_dm_verts(cageDM, sel, eve_act);
+ draw_dm_verts(em, cageDM, sel, eve_act);
}
if( CHECK_OB_DRAWFACEDOT(scene, v3d, obedit->dt) ) {
glPointSize(fsize);
glColor4ubv((GLubyte *)fcol);
- draw_dm_face_centers(cageDM, sel);
+ draw_dm_face_centers(em, cageDM, sel);
}
if (pass==0) {
@@ -1792,7 +1817,9 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, EditM
glPointSize(1.0);
}
-static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act)
+static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
+ Mesh *me, DerivedMesh *cageDM, short sel_only,
+ BMEdge *eed_act)
{
ToolSettings *ts= scene->toolsettings;
int pass;
@@ -1825,21 +1852,21 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh
}
if(ts->selectmode == SCE_SELECT_FACE) {
- draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
+ draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {
if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
glShadeModel(GL_SMOOTH);
- draw_dm_edges_sel_interp(cageDM, wireCol, selCol);
+ draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
glShadeModel(GL_FLAT);
} else {
- draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
+ draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
}
else {
if (!sel_only) {
glColor4ubv(wireCol);
- draw_dm_edges(cageDM);
+ draw_dm_edges(em, cageDM);
}
}
@@ -1850,8 +1877,10 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh
}
}
-static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em)
+static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d,
+ Object *ob, BMEditMesh *em)
{
+#if 0
Mesh *me= ob->data;
EditEdge *eed;
EditFace *efa;
@@ -2014,13 +2043,14 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
glEnable(GL_DEPTH_TEST);
bglPolygonOffset(rv3d->dist, 0.0);
}
+#endif
}
static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth_r)
{
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(userData, index);
- if (efa->h==0) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN)) {
GPU_enable_material(efa->mat_nr+1, NULL);
return 1;
}
@@ -2030,31 +2060,33 @@ static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth
static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
{
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(userData, index);
- return (efa->h==0);
+ return !BM_TestHFlag(efa, BM_HIDDEN);
}
-static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
+static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob,
+ BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
+
{
Mesh *me = ob->data;
- EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */
- EditEdge *eed_act = NULL;
- EditVert *eve_act = NULL;
+ BMFace *efa_act = EDBM_get_actFace(em, 0); /* annoying but active faces is stored differently */
+ BMEdge *eed_act = NULL;
+ BMVert *eve_act = NULL;
if (em->selected.last) {
- EditSelection *ese = em->selected.last;
+ BMEditSelection *ese = em->selected.last;
/* face is handeled above */
/*if (ese->type == EDITFACE ) {
efa_act = (EditFace *)ese->data;
} else */ if ( ese->type == EDITEDGE ) {
- eed_act = (EditEdge *)ese->data;
+ eed_act = (BMEdge *)ese->data;
} else if ( ese->type == EDITVERT ) {
- eve_act = (EditVert *)ese->data;
+ eve_act = (BMVert *)ese->data;
}
}
- EM_init_index_arrays(em, 1, 1, 1);
+ EDBM_init_index_arrays(em, 1, 1, 1);
if(dt>OB_WIRE) {
if(CHECK_OB_DRAWTEXTURE(v3d, dt)) {
@@ -2062,7 +2094,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
- draw_em_fancy__setGLSLFaceOpts, NULL);
+ draw_em_fancy__setGLSLFaceOpts, em);
GPU_disable_material();
glFrontFace(GL_CCW);
@@ -2077,7 +2109,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
- finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0);
+ finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, em, 0);
glFrontFace(GL_CCW);
glDisable(GL_LIGHTING);
@@ -2111,7 +2143,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
if CHECK_OB_DRAWTEXTURE(v3d, dt)
col1[3] = 0;
- draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -2126,7 +2158,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glEnable(GL_BLEND);
glDepthMask(0); // disable write in zbuffer, needed for nice transp
- draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
glDisable(GL_BLEND);
glDepthMask(1); // restore write in zbuffer
@@ -2138,14 +2170,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
/* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */
/* only draw selected edges otherwise there is no way of telling if a face is selected */
- draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act);
+ draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act);
} else {
if(me->drawflag & ME_DRAWSEAMS) {
UI_ThemeColor(TH_EDGE_SEAM);
glLineWidth(2);
- draw_dm_edges_seams(cageDM);
+ draw_dm_edges_seams(em, cageDM);
glColor3ub(0,0,0);
glLineWidth(1);
@@ -2155,20 +2187,20 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
UI_ThemeColor(TH_EDGE_SHARP);
glLineWidth(2);
- draw_dm_edges_sharp(cageDM);
+ draw_dm_edges_sharp(em, cageDM);
glColor3ub(0,0,0);
glLineWidth(1);
}
if(me->drawflag & ME_DRAWCREASES) {
- draw_dm_creases(cageDM);
+ 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) {
// XXX retopo_matrix_update(v3d);
@@ -2177,11 +2209,11 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
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_NORMAL);
- draw_dm_vert_normals(scene, cageDM);
+ draw_dm_vert_normals(em, scene, cageDM);
}
if(me->drawflag & (ME_DRAW_EDGELEN|ME_DRAW_FACEAREA|ME_DRAW_EDGEANG))
@@ -2249,7 +2281,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
- totface = dm->getNumFaces(dm);
+ totface = dm->getNumTessFaces(dm);
/* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
if(dt!=OB_SHADED)
@@ -2443,7 +2475,7 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
Object *ob= base->object;
Object *obedit= scene->obedit;
Mesh *me= ob->data;
- EditMesh *em= me->edit_mesh;
+ BMEditMesh *em= me->edit_btmesh;
int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha;
if(obedit && ob!=obedit && ob->data==obedit->data) {
@@ -2455,9 +2487,9 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
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,
v3d->customdata_mask);
if(dt>OB_WIRE) {
@@ -5432,44 +5464,49 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
{
- int offset = (intptr_t) userData;
- EditVert *eve = EM_get_vert_for_index(index);
+ void **ptrs = userData;
+ int offset = (intptr_t) ptrs[0];
+ BMVert *eve = EDBM_get_vert_for_index(ptrs[1], index);
- if (eve->h==0) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN)) {
WM_set_framebuffer_index_color(offset+index);
bglVertex3fv(co);
}
}
-static void bbs_mesh_verts(DerivedMesh *dm, int offset)
+static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset)
{
+ void *ptrs[2] = {(void*)(intptr_t) offset, em};
+
glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) );
bglBegin(GL_POINTS);
- dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(intptr_t) offset);
+ dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, ptrs);
bglEnd();
glPointSize(1.0);
}
static int bbs_mesh_wire__setDrawOptions(void *userData, int index)
{
- int offset = (intptr_t) userData;
- EditEdge *eed = EM_get_edge_for_index(index);
+ void **ptrs = userData;
+ int offset = (intptr_t) ptrs[0];
+ BMEdge *eed = EDBM_get_edge_for_index(ptrs[1], index);
- if (eed->h==0) {
+ if (!BM_TestHFlag(eed, BM_HIDDEN)) {
WM_set_framebuffer_index_color(offset+index);
return 1;
} else {
return 0;
}
}
-static void bbs_mesh_wire(DerivedMesh *dm, int offset)
+static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
{
- dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset);
+ void *ptrs[2] = {(void*)(intptr_t) offset, em};
+ dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, ptrs);
}
static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
{
- if (EM_get_face_for_index(index)->h==0) {
- if (userData) {
+ if (!BM_TestHFlag(EDBM_get_face_for_index(((void**)userData)[0], index), BM_HIDDEN)) {
+ if (((void**)userData)[1]) {
WM_set_framebuffer_index_color(index+1);
}
return 1;
@@ -5480,9 +5517,9 @@ static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *d
static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, float *no)
{
- EditFace *efa = EM_get_face_for_index(index);
+ BMFace *efa = EDBM_get_face_for_index(((void**)userData)[0], index);
- if (efa->h==0 && efa->fgonf!=EM_FGON) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN)) {
WM_set_framebuffer_index_color(index+1);
bglVertex3fv(cent);
@@ -5490,23 +5527,26 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, f
}
/* two options, facecolors or black */
-static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh *dm, int facecol)
+static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
+ Object *ob, DerivedMesh *dm, int facecol)
{
+ void *ptrs[2] = {em, NULL}; //second one being null means to draw black
cpack(0);
if (facecol) {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0);
+ ptrs[1] = (void*)(intptr_t) 1;
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0);
if( CHECK_OB_DRAWFACEDOT(scene, v3d, ob->dt) ) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
bglBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL);
+ dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, ptrs);
bglEnd();
}
} else {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0);
}
}
@@ -5548,36 +5588,36 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
{
if(ob == scene->obedit) {
Mesh *me= ob->data;
- EditMesh *em= me->edit_mesh;
+ BMEditMesh *em= me->edit_btmesh;
- DerivedMesh *dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
+ DerivedMesh *dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
- EM_init_index_arrays(em, 1, 1, 1);
+ EDBM_init_index_arrays(em, 1, 1, 1);
- bbs_mesh_solid_EM(scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE);
+ bbs_mesh_solid_EM(em, scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE);
if(ts->selectmode & SCE_SELECT_FACE)
- em_solidoffs = 1+em->totface;
+ bm_solidoffs = 1+em->bm->totface;
else
- em_solidoffs= 1;
+ bm_solidoffs= 1;
bglPolygonOffset(rv3d->dist, 1.0);
// we draw edges always, for loop (select) tools
- bbs_mesh_wire(dm, em_solidoffs);
- em_wireoffs= em_solidoffs + em->totedge;
+ bbs_mesh_wire(em, dm, bm_solidoffs);
+ bm_wireoffs= bm_solidoffs + em->bm->totedge;
// we draw verts if vert select mode or if in transform (for snap).
if(ts->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT) {
- bbs_mesh_verts(dm, em_wireoffs);
- em_vertoffs= em_wireoffs + em->totvert;
+ bbs_mesh_verts(em, dm, bm_wireoffs);
+ bm_vertoffs= bm_wireoffs + em->bm->totvert;
}
- else em_vertoffs= em_wireoffs;
+ else bm_vertoffs= bm_wireoffs;
bglPolygonOffset(rv3d->dist, 0.0);
dm->release(dm);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
else bbs_mesh_solid(scene, v3d, ob);
}
@@ -5603,7 +5643,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
int glsl;
if(ob == scene->obedit)
- 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/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 7db577bf139..fcfc48eff84 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -69,6 +69,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
@@ -164,31 +165,30 @@ static void v3d_editvertex_buts(const bContext *C, uiBlock *block, View3D *v3d,
if(ob->type==OB_MESH) {
Mesh *me= ob->data;
- EditMesh *em = BKE_mesh_get_editmesh(me);
- EditVert *eve, *evedef=NULL;
- EditEdge *eed;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMVert *eve, *evedef=NULL;
+ BMEdge *eed;
+ BMIter iter;
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) {
evedef= eve;
tot++;
VecAddf(median, median, eve->co);
}
- eve= eve->next;
}
- eed= em->edges.first;
- while(eed) {
- if((eed->f & SELECT)) {
+
+ BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
totedge++;
median[3]+= eed->crease;
}
- eed= eed->next;
}
/* check for defgroups */
if(evedef)
- dvert= CustomData_em_get(&em->vdata, evedef->data, CD_MDEFORMVERT);
+ dvert= CustomData_bmesh_get(&em->bm->vdata, evedef->head.data, CD_MDEFORMVERT);
if(tot==1 && dvert && dvert->totweight) {
bDeformGroup *dg;
int i, max=1, init=1;
@@ -212,8 +212,6 @@ static void v3d_editvertex_buts(const bContext *C, uiBlock *block, View3D *v3d,
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;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index e68a1c8a10a..51ba58b3020 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -64,6 +64,7 @@
#include "BKE_particle.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h" /* for VECCOPY */
+#include "BKE_tessmesh.h"
#include "ED_armature.h"
#include "ED_particle.h"
@@ -4012,11 +4013,11 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
Base *basact= CTX_data_active_base(C);
Object *ob= CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
- EditMesh *em= NULL;
+ BMEditMesh *em= NULL;
int bit, ctrl= win->eventstate->ctrl, shift= win->eventstate->shift;
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 */
@@ -4142,7 +4143,7 @@ static void do_view3d_header_buttons(bContext *C, void *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_OBJECT|ND_GEOM_SELECT, obedit);
ED_undo_push(C, "Selectmode Set: Vertex");
}
@@ -4151,12 +4152,12 @@ static void do_view3d_header_buttons(bContext *C, void *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_OBJECT|ND_GEOM_SELECT, obedit);
ED_undo_push(C, "Selectmode Set: Edge");
}
@@ -4165,12 +4166,12 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
if(em) {
if( shift==0 || em->selectmode==0){
if( ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){
- if(ctrl) EM_convertsel(em, (ts->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE);
+ 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_OBJECT|ND_GEOM_SELECT, obedit);
ED_undo_push(C, "Selectmode Set: Face");
}
@@ -4253,9 +4254,6 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
}
break;
}
-
- if(obedit && obedit->type==OB_MESH)
- BKE_mesh_end_editmesh(obedit->data, em);
}
static void view3d_header_pulldowns(const bContext *C, uiBlock *block, Object *ob, int *xcoord, int yco)
@@ -4622,7 +4620,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
/* selection modus */
if(obedit && (obedit->type == OB_MESH)) {
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
uiBlockBeginAlign(block);
uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, xco,yco,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode (Ctrl Tab 1)");
@@ -4638,8 +4636,6 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
}
uiBlockEndAlign(block);
header_xco_step(ar, &xco, &yco, &maxco, XIC);
-
- BKE_mesh_end_editmesh(obedit->data, em);
}
else if(G.f & G_PARTICLEEDIT) {
uiBlockBeginAlign(block);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 112847272e5..32305b5c76b 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -203,7 +203,7 @@ void view3d_keymap(wmWindowManager *wm)
/* selection*/
WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
- RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "type", 1);
WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT|KM_CTRL, 0)->ptr, "deselect", 1);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 2537982210a..31ea1070b32 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -62,6 +62,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "RE_pipeline.h" // make_stars
@@ -78,10 +79,10 @@
#include "ED_particle.h"
#include "ED_mesh.h"
#include "ED_object.h"
-#include "ED_retopo.h"
#include "ED_screen.h"
#include "ED_types.h"
#include "ED_util.h"
+#include "ED_retopo.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -149,43 +150,49 @@ static void BIF_undo_push() {}
/* local prototypes */
-void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
+void EM_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) {
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; eve; eve=BMIter_Step(&iter), index++) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
if(EM_check_backbuf(index)) {
- eve->f = select?(eve->f|1):(eve->f&~1);
+ BM_Select_Vert(em->bm, eve, select);
}
}
}
}
-void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
+void EM_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) {
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter), index++) {
+ if(!BM_TestHFlag(eed, BM_HIDDEN)) {
if(EM_check_backbuf(index)) {
- EM_select_edge(eed, select);
+ BM_Select_Edge(em->bm, eed, select);
}
}
}
}
-void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
+void EM_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) {
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter), index++) {
+ if(!BM_TestHFlag(efa, BM_HIDDEN)) {
if(EM_check_backbuf(index)) {
- EM_select_face_fgon(em, efa, select);
+ BM_Select_Face(em->bm, efa, select);
}
}
}
@@ -399,53 +406,52 @@ void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
}
}
-static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
+static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, int x, int y, int index)
{
struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
- eve->f = data->select?(eve->f|1):(eve->f&~1);
+ BM_Select_Vert(data->vc.em->bm, eve, data->select);
}
}
-static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
{
struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
- if (EM_check_backbuf(em_solidoffs+index)) {
+ if (EM_check_backbuf(bm_solidoffs+index)) {
if (data->pass==0) {
if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) &&
lasso_inside(data->mcords, data->moves, x0, y0) &&
lasso_inside(data->mcords, data->moves, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select_Edge(data->vc.em->bm, eed, data->select);
data->done = 1;
}
} else {
if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select_Edge(data->vc.em->bm, eed, data->select);
}
}
}
}
-static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
+static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, int x, int y, int index)
{
struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
- EM_select_face_fgon(data->vc.em, efa, data->select);
+ BM_Select_Face(data->vc.em->bm, efa, data->select);
}
}
static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves, short select)
{
struct { ViewContext vc; rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
- ToolSettings *ts= vc->scene->toolsettings;
rcti rect;
int bbsel;
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;
@@ -457,14 +463,14 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves
bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
- if(ts->selectmode & SCE_SELECT_VERTEX) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) {
EM_backbuf_checkAndSelectVerts(vc->em, select);
} else {
mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
}
}
- if(ts->selectmode & SCE_SELECT_EDGE) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_EDGE) {
/* Does both bbsel and non-bbsel versions (need screen cos for both) */
data.pass = 0;
@@ -476,7 +482,7 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves
}
}
- if(ts->selectmode & SCE_SELECT_FACE) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_FACE) {
if (bbsel) {
EM_backbuf_checkAndSelectFaces(vc->em, select);
} else {
@@ -485,7 +491,7 @@ static void do_lasso_select_mesh(ViewContext *vc, short mcords[][2], short moves
}
EM_free_backbuf();
- EM_selectmode_flush(vc->em);
+ EDBM_selectmode_flush(vc->em);
}
#if 0
@@ -647,7 +653,7 @@ static void do_lasso_select_facemode(ViewContext *vc, short mcords[][2], short m
if(me==NULL || me->mtface==NULL) return;
if(me->totface==0) return;
- em_vertoffs= me->totface+1; /* max index array */
+ bm_vertoffs= me->totface+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);
@@ -715,6 +721,12 @@ void view3d_lasso_select(bContext *C, ViewContext *vc, short mcords[][2], short
}
+static EnumPropertyItem lasso_select_types[] = {
+ {0, "SELECT", 0, "Select", ""},
+ {1, "DESELECT", 0, "Deselect", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
/* lasso operator gives properties, but since old code works
with short array we convert */
@@ -741,7 +753,7 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
/* setup view context for argument to callbacks */
view3d_set_viewcontext(C, &vc);
- select= !RNA_boolean_get(op->ptr, "deselect");
+ select= RNA_enum_is_equal(C, op->ptr, "type", "SELECT");
view3d_lasso_select(C, &vc, mcords, i, select);
return OPERATOR_FINISHED;
@@ -763,7 +775,7 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
ot->flag= OPTYPE_UNDO;
RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items.");
+ RNA_def_enum(ot->srna, "type", lasso_select_types, 0, "Type", "");
}
@@ -1236,43 +1248,47 @@ static void do_lattice_box_select(ViewContext *vc, rcti *rect, int select)
lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data);
}
-static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
+static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, int x, int y, int index)
{
struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y)) {
- eve->f = data->select?(eve->f|1):(eve->f&~1);
+ BM_Select_Vert(data->vc.em->bm, eve, data->select);
}
}
-static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
{
struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
- if(EM_check_backbuf(em_solidoffs+index)) {
+ if(EM_check_backbuf(bm_solidoffs+index)) {
if (data->pass==0) {
if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select_Edge(data->vc.em->bm, eed, data->select);
data->done = 1;
}
} else {
if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select_Edge(data->vc.em->bm, eed, data->select);
}
}
}
}
-static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
+
+static void
+do_mesh_box_select__doSelectFace(void *userData, BMFace
+ *efa, int x, int y,
+ int index)
+
{
struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData;
if (BLI_in_rcti(data->rect, x, y)) {
- EM_select_face_fgon(data->vc.em, efa, data->select);
+ BM_Select_Face(data->vc.em->bm, efa, data->select);
}
}
static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
{
struct { ViewContext vc; rcti *rect; short select, pass, done; } data;
- ToolSettings *ts= vc->scene->toolsettings;
int bbsel;
data.vc= *vc;
@@ -1281,16 +1297,16 @@ static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
data.pass = 0;
data.done = 0;
- 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(vc->scene->toolsettings->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) {
EM_backbuf_checkAndSelectVerts(vc->em, select);
} else {
mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
}
}
- if(ts->selectmode & SCE_SELECT_EDGE) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_EDGE) {
/* Does both bbsel and non-bbsel versions (need screen cos for both) */
data.pass = 0;
@@ -1302,7 +1318,7 @@ static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
}
}
- if(ts->selectmode & SCE_SELECT_FACE) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_FACE) {
if(bbsel) {
EM_backbuf_checkAndSelectFaces(vc->em, select);
} else {
@@ -1312,7 +1328,7 @@ static void do_mesh_box_select(ViewContext *vc, rcti *rect, int select)
EM_free_backbuf();
- EM_selectmode_flush(vc->em);
+ EDBM_selectmode_flush(vc->em);
}
static int view3d_borderselect_exec(bContext *C, wmOperator *op)
@@ -1351,7 +1367,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
if(obedit) {
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- vc.em= me->edit_mesh;
+ vc.em= me->edit_btmesh;
do_mesh_box_select(&vc, &rect, (val==LEFTMOUSE));
// if (EM_texFaceCheck())
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
@@ -1436,7 +1452,6 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
}
}
- ED_armature_sync_selection(arm->edbo);
}
else if(obedit->type==OB_LATTICE) {
do_lattice_box_select(&vc, &rect, val==LEFTMOUSE);
@@ -1522,6 +1537,11 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
/* *****************Selection Operators******************* */
+static EnumPropertyItem prop_select_types[] = {
+ {0, "EXCLUSIVE", 0, "Exclusive", ""},
+ {1, "EXTEND", 0, "Extend", ""},
+ {0, NULL, 0, NULL, NULL}
+};
/* ****** Border Select ****** */
void VIEW3D_OT_select_border(wmOperatorType *ot)
@@ -1547,7 +1567,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
- RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
+ RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
}
/* ****** Mouse Select ****** */
@@ -1556,7 +1576,7 @@ void VIEW3D_OT_select_border(wmOperatorType *ot)
static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
Object *obedit= CTX_data_edit_object(C);
- short extend= RNA_boolean_get(op->ptr, "extend");
+ short extend= RNA_enum_is_equal(C, op->ptr, "type", "EXTEND");
view3d_operator_needs_opengl(C);
@@ -1594,44 +1614,43 @@ void VIEW3D_OT_select(wmOperatorType *ot)
ot->flag= OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everyting first.");
+ RNA_def_enum(ot->srna, "type", prop_select_types, 0, "Type", "");
}
/* -------------------- circle select --------------------------------------------- */
-static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
+static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int index)
{
struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
int mx = x - data->mval[0], my = y - data->mval[1];
float r = sqrt(mx*mx + my*my);
if (r<=data->radius) {
- eve->f = data->select?(eve->f|1):(eve->f&~1);
+ BM_Select_Vert(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 index)
+static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index)
{
struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
- EM_select_edge(eed, data->select);
+ BM_Select_Edge(data->vc->em->bm, eed, data->select);
}
}
-static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
+static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int index)
{
struct {ViewContext *vc; short select, mval[2]; float radius; } *data = userData;
int mx = x - data->mval[0], my = y - data->mval[1];
float r = sqrt(mx*mx + my*my);
if (r<=data->radius) {
- EM_select_face_fgon(data->vc->em, efa, data->select);
+ BM_Select_Face(data->vc->em->bm, efa, data->select);
}
}
static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
{
- ToolSettings *ts= vc->scene->toolsettings;
int bbsel;
if(vc->obedit==NULL && (FACESEL_PAINT_TEST)) {
@@ -1639,9 +1658,9 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa
Mesh *me = ob?ob->data:NULL;
if (me) {
- em_vertoffs= me->totface+1; /* max index array */
+ bm_vertoffs= me->totface+1; /* max index array */
- bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
+ bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
EM_free_backbuf();
@@ -1651,15 +1670,15 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa
else {
struct {ViewContext *vc; short select, mval[2]; float radius; } data;
- bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
- vc->em= ((Mesh *)vc->obedit->data)->edit_mesh;
+ bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0));
+ vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh;
data.select = selecting;
data.mval[0] = mval[0];
data.mval[1] = mval[1];
data.radius = rad;
- if(ts->selectmode & SCE_SELECT_VERTEX) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_VERTEX) {
if(bbsel) {
EM_backbuf_checkAndSelectVerts(vc->em, selecting==LEFTMOUSE);
} else {
@@ -1667,7 +1686,7 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa
}
}
- if(ts->selectmode & SCE_SELECT_EDGE) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_EDGE) {
if (bbsel) {
EM_backbuf_checkAndSelectEdges(vc->em, selecting==LEFTMOUSE);
} else {
@@ -1675,7 +1694,7 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa
}
}
- if(ts->selectmode & SCE_SELECT_FACE) {
+ if(vc->scene->toolsettings->selectmode & SCE_SELECT_FACE) {
if(bbsel) {
EM_backbuf_checkAndSelectFaces(vc->em, selecting==LEFTMOUSE);
} else {
@@ -1684,7 +1703,7 @@ static void mesh_circle_select(ViewContext *vc, int selecting, short *mval, floa
}
EM_free_backbuf();
- EM_selectmode_flush(vc->em);
+ EDBM_selectmode_flush(vc->em);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c
index fba8d13c6a5..98980548b86 100644
--- a/source/blender/editors/space_view3d/view3d_snap.c
+++ b/source/blender/editors/space_view3d/view3d_snap.c
@@ -1,5 +1,5 @@
/**
- * $Id$
+ * $Id: view3d_snap.c 18967 2009-02-14 13:07:09Z ton $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -66,6 +66,7 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -110,7 +111,7 @@ static void special_transvert_update(Scene *scene, Object *obedit)
if(obedit->type==OB_MESH) {
Mesh *me= obedit->data;
- recalc_editnormals(me->edit_mesh); // does face centers too
+ BM_Compute_Normals(me->edit_btmesh->bm); // does face centers too
}
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
Curve *cu= obedit->data;
@@ -178,7 +179,8 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode)
BPoint *bp;
TransVert *tv=NULL;
MetaElem *ml;
- EditVert *eve;
+ BMVert *eve;
+ BMIter iter;
EditBone *ebo;
float total, center[3], centroid[3];
int a;
@@ -190,45 +192,70 @@ 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;
int proptrans= 0;
// transform now requires awareness for select mode, so we tag the f1 flags in verts
tottrans= 0;
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0 && (eve->f & SELECT)) {
- eve->f1= SELECT;
+ if(em->bm->selectmode & SCE_SELECT_VERTEX) {
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) {
+ BMINDEX_SET(eve, 1);
tottrans++;
}
- else eve->f1= 0;
+ else BMINDEX_SET(eve, 0);
}
}
- else if(em->selectmode & SCE_SELECT_EDGE) {
- EditEdge *eed;
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
+ else if(em->bm->selectmode & SCE_SELECT_EDGE) {
+ BMEdge *eed;
+
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter))
+ BMINDEX_SET(eve, 0);
+
+ eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for (; eed; eed=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT))
+ BMINDEX_SET(eed->v1, 0), BMINDEX_SET(eed->v2, 0);
}
- for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter))
+ if(BMINDEX_GET(eve)) tottrans++;
}
else {
- EditFace *efa;
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0 && (efa->f & SELECT)) {
- efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
- if(efa->v4) efa->v4->f1= SELECT;
+ BMFace *efa;
+
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter))
+ BMINDEX_SET(eve, 0);
+
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for (; efa; efa=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) {
+ BMIter liter;
+ BMLoop *l;
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&iter)) {
+ BMINDEX_SET(l->v, 1);
+ }
}
}
- for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter))
+ if(BMINDEX_GET(eve)) tottrans++;
}
/* proportional edit exception... */
if((mode & 1) && tottrans) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- eve->f1 |= 2;
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter)) {
+ if(BMINDEX_GET(eve)) tottrans++;
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
+ BMINDEX_SET(eve, BMINDEX_GET(eve)|2);
proptrans++;
}
}
@@ -239,13 +266,14 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode)
if(tottrans) {
tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1) {
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for (; eve; eve=BMIter_Step(&iter)) {
+ if(BMINDEX_GET(eve)) {
VECCOPY(tv->oldloc, eve->co);
tv->loc= eve->co;
if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0)
tv->nor= eve->no; // note this is a hackish signal (ton)
- tv->flag= eve->f1 & SELECT;
+ tv->flag= BMINDEX_GET(eve) & SELECT;
tv++;
}
}
@@ -846,10 +874,10 @@ static int snap_curs_to_active(bContext *C, wmOperator *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);
}
Mat4MulVecfl(obedit->obmat, curs);
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index b2dee8c3358..8501a95b981 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -6,6 +6,6 @@ sources = env.Glob('*.c')
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include #/intern/guardedalloc'
-incs += ' ../../gpu ../../makesrna'
+incs += ' ../../gpu ../../makesrna ../../bmesh'
env.BlenderLib ( 'bf_editors_transform', sources, Split(incs), [], libtype=['core'], priority=[40] ) \ No newline at end of file
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index d45a6f42232..c62ea07e398 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -1170,7 +1170,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
if (RNA_struct_find_property(op->ptr, "constraint_axis"))
{
- RNA_int_set(op->ptr, "constraint_orientation", t->current_orientation);
+ RNA_enum_set(op->ptr, "constraint_orientation", t->current_orientation);
if (t->con.mode & CON_APPLY)
{
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 3d643a2dec1..aeccaee070e 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -100,6 +100,7 @@
#include "BKE_bmesh.h"
#include "BKE_context.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
//#include "BIF_editview.h"
//#include "BIF_editlattice.h"
@@ -149,6 +150,7 @@
extern ListBase editelems;
#include "transform.h"
+#include "bmesh.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -1883,22 +1885,31 @@ static void editmesh_set_connectivity_distance(EditMesh *em, int total, float *v
}
/* loop-in-a-loop I know, but we need it! (ton) */
-static void get_face_center(float *cent, EditMesh *em, EditVert *eve)
+ static void get_face_center(float *centout, BMesh *bm, BMVert *eve)
+
{
- EditFace *efa;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter;
+ float cent[3] = {0.0, 0.0, 0.0};
- for(efa= em->faces.first; efa; efa= efa->next)
- if(efa->f & SELECT)
- if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve)
- break;
- if(efa) {
- VECCOPY(cent, efa->cent);
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_VERT, eve);
+ if (efa) {
+ l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
+ for ( ; l; l=BMIter_Step(&iter)) {
+ VECADD(cent, cent, l->v->co);
+ }
+
+ VECMUL(cent, 1.0f / (float)efa->len);
}
+
+ if (cent[0] == 0.0f && cent[1] == 0.0f && cent[2] == 0.0f) cent[2] = 1.0f;
+ VECCOPY(centout, cent);
}
//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, BMesh *em, BMVert *eve)
{
td->flag = 0;
//if(key)
@@ -1965,13 +1976,13 @@ static float *get_crazy_mapped_editverts(TransInfo *t)
/* disable subsurf temporal, get mapped cos, and enable it */
if(modifiers_disable_subsurf_temporary(t->obedit)) {
/* need to make new derivemesh */
- makeDerivedMesh(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
+ makeDerivedMesh(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH);
}
/* now get the cage */
- dm= editmesh_get_derived_cage(t->scene, t->obedit, me->edit_mesh, CD_MASK_BAREMESH);
+ dm= editbmesh_get_derived_cage(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH);
- vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_mesh->totvert, "vertexcos map");
+ vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_btmesh->bm->totvert, "vertexcos map");
dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
dm->release(dm);
@@ -2000,17 +2011,18 @@ static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3,
}
#undef TAN_MAKE_VEC
-static void set_crazyspace_quats(EditMesh *em, float *origcos, float *mappedcos, float *quats)
+static void set_crazyspace_quats(BMEditMesh *em, float *origcos, float *mappedcos, float *quats)
{
- EditVert *eve, *prev;
- EditFace *efa;
+#if 0
+ BMVert *eve, *prev;
+ BMFace *efa;
float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
intptr_t index= 0;
/* two abused locations in vertices */
for(eve= em->verts.first; eve; eve= eve->next, index++) {
eve->tmp.p = NULL;
- eve->prev= (EditVert *)index;
+ eve->prev= (BMVert *)index;
}
/* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
@@ -2068,7 +2080,7 @@ static void set_crazyspace_quats(EditMesh *em, float *origcos, float *mappedcos,
/* restore abused prev pointer */
for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
eve->prev= prev;
-
+#endif
}
void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) {
@@ -2100,10 +2112,12 @@ 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 **nears = NULL;
- EditVert *eve_act = NULL;
+ BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMVert **nears = NULL;
+ BMIter iter;
+ BMVert *eve_act = NULL;
float *vectors = NULL, *mappedcos = NULL, *quats= NULL;
float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
int count=0, countsel=0, a, totleft;
@@ -2117,36 +2131,49 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
// transform now requires awareness for select mode, so we tag the f1 flags in verts
if(ts->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0 && (eve->f & SELECT))
- eve->f1= SELECT;
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT))
+ BMINDEX_SET(eve, SELECT);
else
- eve->f1= 0;
+ BMINDEX_SET(eve, 0);
}
}
else if(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))
- eed->v1->f1= eed->v2->f1= SELECT;
+ BMEdge *eed;
+
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BMIter_Step(&iter)) BMINDEX_SET(eve, 0);
+
+ eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+ for( ; eed; eed=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SELECT))
+ BMINDEX_SET(eed->v1, SELECT), BMINDEX_SET(eed->v2, SELECT);
}
}
else {
- EditFace *efa;
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0 && (efa->f & SELECT)) {
- efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
- if(efa->v4) efa->v4->f1= SELECT;
+ BMFace *efa;
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BMIter_Step(&iter)) BMINDEX_SET(eve, 0);
+
+ efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+ for( ; efa; efa=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) {
+ BMIter liter;
+ BMLoop *l;
+
+ l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ BMINDEX_SET(l->v, SELECT);
+ }
}
}
}
/* now we can count */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- if(eve->f1) countsel++;
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
+ if(BMINDEX_GET(eve)) countsel++;
if(propmode) count++;
}
}
@@ -2156,9 +2183,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
/* check active */
if (em->selected.last) {
- EditSelection *ese = em->selected.last;
+ BMEditSelection *ese = em->selected.last;
if ( ese->type == EDITVERT ) {
- eve_act = (EditVert *)ese->data;
+ eve_act = (BMVert *)ese->data;
}
}
@@ -2168,7 +2195,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
/* allocating scratch arrays */
vectors = (float *)MEM_mallocN(t->total * 3 * sizeof(float), "scratch vectors");
- nears = (EditVert**)MEM_mallocN(t->total * sizeof(EditVert*), "scratch nears");
+ nears = (BMVert**)MEM_mallocN(t->total * sizeof(BMVert*), "scratch nears");
}
else t->total = countsel;
tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)");
@@ -2176,7 +2203,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
Mat3CpyMat4(mtx, t->obedit->obmat);
Mat3Inv(smtx, mtx);
- if(propmode) editmesh_set_connectivity_distance(em, t->total, vectors, nears);
+ //BMESH_TODO if(propmode) editmesh_set_connectivity_distance(em, t->total, vectors, nears);
/* detect CrazySpace [tm] */
if(propmode==0) {
@@ -2184,7 +2211,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
if(modifiers_isDeformed(t->scene, 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->obedit, em, &defmats, &defcos);
+ totleft= editbmesh_get_first_deform_matrices(t->obedit, em, &defmats, &defcos);
/* if we still have more modifiers, also do crazyspace
correction with quats, relative to the coordinates after
@@ -2205,8 +2232,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
/* find out which half we do */
if(mirror) {
- for (eve=em->verts.first; eve; eve=eve->next) {
- if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) {
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for( ; eve; eve=BMIter_Step(&iter)) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN) && BMINDEX_GET(eve) && eve->co[0]!=0.0f) {
if(eve->co[0]<0.0f)
mirror = -1;
break;
@@ -2214,36 +2242,41 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
}
}
- for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
- if(eve->h==0) {
- if(propmode || eve->f1) {
- VertsToTransData(t, tob, em, eve);
+ eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+ for(a=0; eve; eve=BMIter_Step(&iter), a++) {
+ if(!BM_TestHFlag(eve, BM_HIDDEN)) {
+ if(propmode || BMINDEX_GET(eve)) {
+ VertsToTransData(t, tob, bm, eve);
/* selected */
- if(eve->f1) tob->flag |= TD_SELECTED;
+ if(BMINDEX_GET(eve)) tob->flag |= TD_SELECTED;
/* active */
if(eve == eve_act) tob->flag |= TD_ACTIVE;
if(propmode) {
+ /*BMESH_TODO
+ this has to do with edge connectivity
+ PEP mode, I think. -joeedh
if (eve->f2) {
float vec[3];
VECCOPY(vec, E_VEC(eve));
Mat3MulVecfl(mtx, vec);
tob->dist= VecLength(vec);
}
- else {
+ else {*/
tob->flag |= TD_NOTCONNECTED;
tob->dist = MAXFLOAT;
- }
+ //}
}
/* CrazySpace */
- if(defmats || (quats && eve->tmp.p)) {
+ if(defmats) { // || (quats && eve->tmp.p)) {
float mat[3][3], imat[3][3], qmat[3][3];
/* use both or either quat and defmat correction */
- if(quats && eve->tmp.f) {
+ //BMESH_TODO, need to restore this quats thing
+ /*if(quats && eve->tmp.f) {
QuatToMat3(eve->tmp.p, qmat);
if(defmats)
@@ -2252,7 +2285,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t)
else
Mat3MulMat3(mat, mtx, qmat);
}
- else
+ else*/
Mat3MulMat3(mat, mtx, defmats[a]);
Mat3Inv(imat, mat);
@@ -2266,10 +2299,12 @@ 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, tob->iloc); /* initializes octree on first call */
- if(vmir != eve) tob->extra = vmir;
- }
+
+ //BMESH_TODO
+ //if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
+ // EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, tob->iloc); /* initializes octree on first call */
+ // if(vmir != eve) tob->extra = vmir;
+ //}
tob++;
}
}
@@ -2416,6 +2451,7 @@ static void UVsToTransData(SpaceImage *sima, TransData *td, TransData2D *td2d, f
static void createTransUVs(bContext *C, TransInfo *t)
{
+#if 0
SpaceImage *sima = (SpaceImage*)CTX_wm_space_data(C);
Image *ima = CTX_data_edit_image(C);
Scene *scene = CTX_data_scene(C);
@@ -2482,6 +2518,7 @@ static void createTransUVs(bContext *C, TransInfo *t)
if (sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_begin(t->scene, t->obedit);
+#endif
}
void flushTransUVs(TransInfo *t)
@@ -4856,7 +4893,7 @@ void special_aftertrans_update(TransInfo *t)
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 560b37caf0a..3fc9fe73a5b 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -83,6 +83,7 @@
#include "BKE_object.h"
#include "BKE_utildefines.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@@ -241,10 +242,11 @@ 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;
+ BMIter iter;
int i;
for(i = 0 ; i < t->total; i++, td++) {
@@ -607,7 +609,7 @@ void recalcData(TransInfo *t)
DAG_object_flush_update(scene, t->obedit, OB_RECALC_DATA);
} else {
- EditMesh *em = ((Mesh*)t->obedit->data)->edit_mesh;
+ BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh;
/* mirror modifier clipping? */
if(t->state != TRANS_CANCEL) {
/* TRANSFORM_FIX_ME */
@@ -618,11 +620,12 @@ void recalcData(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_object_flush_update(scene, t->obedit, OB_RECALC_DATA); /* sets recalc flags */
- recalc_editnormals(em);
+ EDBM_RecalcNormals(em);
+ BMEdit_RecalcTesselation(em);
}
}
else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */
@@ -886,7 +889,7 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
if (op && RNA_struct_find_property(op->ptr, "constraint_axis") && RNA_property_is_set(op->ptr, "constraint_orientation"))
{
- t->current_orientation = RNA_int_get(op->ptr, "constraint_orientation");
+ t->current_orientation = RNA_enum_get(op->ptr, "constraint_orientation");
if (t->current_orientation >= V3D_MANIP_CUSTOM + BIF_countTransformOrientation(C) - 1)
{
@@ -1018,8 +1021,7 @@ void postTrans (TransInfo *t)
else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
if (t->customData)
MEM_freeN(t->customData);
- }
-}
+ }}
void applyTransObjects(TransInfo *t)
{
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index c656b097cb9..bf87319d05c 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -63,6 +63,7 @@
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"
@@ -204,20 +205,22 @@ int calc_manipulator_stats(const bContext *C)
if((ob->lay & v3d->lay)==0) return 0;
if(obedit->type==OB_MESH) {
- EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
- EditVert *eve;
- EditSelection ese;
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMVert *eve;
+ BMEditSelection ese;
+ BMIter iter;
float vec[3]= {0,0,0};
/* USE LAST SELECTE WITH ACTIVE */
- if (v3d->around==V3D_ACTIVE && EM_get_actSelection(em, &ese)) {
- EM_editselection_center(vec, &ese);
+ if (v3d->around==V3D_ACTIVE && EDBM_get_actSelection(em, &ese)) {
+ EDBM_editselection_center(em, vec, &ese);
calc_tw_center(scene, vec);
totsel= 1;
} else {
/* do vertices for center, and if still no normal found, use vertex normals */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
+ BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT)) {
totsel++;
calc_tw_center(scene, eve->co);
}
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index f2630f40c9c..2fc3d2f1e53 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -81,6 +81,13 @@ EnumPropertyItem proportional_falloff_types[] = {
{0, NULL, 0, NULL, NULL}
};
+EnumPropertyItem orientation_items[]= {
+ {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""},
+ {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""},
+ {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""},
+ {V3D_MANIP_VIEW, "VIEW", 0, "View", ""},
+ {0, NULL, 0, NULL, NULL}};
+
char OP_TRANSLATION[] = "TFM_OT_translation";
char OP_ROTATION[] = "TFM_OT_rotation";
char OP_TOSPHERE[] = "TFM_OT_tosphere";
@@ -137,12 +144,6 @@ static EnumPropertyItem *select_orientation_itemf(bContext *C, PointerRNA *ptr,
void TFM_OT_select_orientation(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- static EnumPropertyItem orientation_items[]= {
- {V3D_MANIP_GLOBAL, "GLOBAL", 0, "Global", ""},
- {V3D_MANIP_NORMAL, "NORMAL", 0, "Normal", ""},
- {V3D_MANIP_LOCAL, "LOCAL", 0, "Local", ""},
- {V3D_MANIP_VIEW, "VIEW", 0, "View", ""},
- {0, NULL, 0, NULL, NULL}};
/* identifiers */
ot->name = "Select Orientation";
@@ -293,8 +294,11 @@ void Properties_Snapping(struct wmOperatorType *ot, short align)
void Properties_Constraints(struct wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
- RNA_def_int(ot->srna, "constraint_orientation", 0, 0, INT_MAX, "Constraint Orientation", "", 0, INT_MAX);
+ prop= RNA_def_enum(ot->srna, "constraint_orientation", orientation_items, V3D_MANIP_GLOBAL, "Orientation", "DOC_BROKEN");
+ RNA_def_enum_funcs(prop, select_orientation_itemf);
}
void TFM_OT_translation(struct wmOperatorType *ot)
@@ -557,9 +561,8 @@ void TFM_OT_transform(struct wmOperatorType *ot)
Properties_Proportional(ot);
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
-
- RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
- RNA_def_int(ot->srna, "constraint_orientation", 0, 0, INT_MAX, "Constraint Orientation", "", 0, INT_MAX);
+
+ Properties_Constraints(ot);
}
void transform_operatortypes(void)
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 6d60c7602f4..6cda535516e 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -43,6 +43,7 @@
#include "BKE_utildefines.h"
#include "BKE_armature.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
@@ -590,16 +591,16 @@ 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)
{
@@ -616,30 +617,30 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
else
{
- if (em->totfacesel >= 1)
+ if (em->bm->totfacesel >= 1)
{
- EditFace *efa;
-
- for(efa= em->faces.first; efa; efa= efa->next)
- {
- if(efa->f & SELECT)
- {
- VECADD(normal, normal, efa->n);
- VecSubf(vec, efa->v2->co, efa->v1->co);
+ BMFace *efa;
+ BMIter iter;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(BM_TestHFlag(efa, BM_SELECT)) {
+ VECADD(normal, normal, efa->no);
+ VecSubf(vec, efa->loopbase->v->co,
+ ((BMLoop*)efa->loopbase->head.next)->v->co);
VECADD(plane, plane, vec);
}
}
result = ORIENTATION_FACE;
}
- else if (em->totvertsel == 3)
+ else if (em->bm->totvertsel == 3)
{
- EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
+ BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
+ BMIter iter;
float cotangent[3];
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
if (v1 == NULL) {
v1 = eve;
}
@@ -658,12 +659,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
/* if there's an edge available, use that for the tangent */
- if (em->totedgesel >= 1)
+ if (em->bm->totedgesel >= 1)
{
- EditEdge *eed = NULL;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
+ BMEdge *eed = NULL;
+ BMIter iter;
+
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
VecSubf(plane, eed->v2->co, eed->v1->co);
break;
}
@@ -672,12 +674,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
result = ORIENTATION_FACE;
}
- else if (em->totedgesel == 1)
+ else if (em->bm->totedgesel == 1)
{
- EditEdge *eed;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
+ BMEdge *eed = NULL;
+ BMIter iter;
+
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if(BM_TestHFlag(eed, BM_SELECT)) {
/* use average vert normals as plane and edge vector as normal */
VECCOPY(plane, eed->v1->no);
VECADD(plane, plane, eed->v2->no);
@@ -687,13 +690,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
result = ORIENTATION_EDGE;
}
- else if (em->totvertsel == 2)
+ else if (em->bm->totvertsel == 2)
{
- EditVert *v1 = NULL, *v2 = NULL;
-
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+ BMVert *v1 = NULL, *v2 = NULL;
+ BMIter iter;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
if (v1 == NULL) {
v1 = eve;
}
@@ -709,24 +712,25 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
}
result = ORIENTATION_EDGE;
}
- else if (em->totvertsel == 1)
+ else if (em->bm->totvertsel == 1)
{
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+ BMIter iter;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
VECCOPY(normal, eve->no);
break;
}
}
result = ORIENTATION_VERT;
}
- else if (em->totvertsel > 3)
+ else if (em->bm->totvertsel > 3)
{
+ BMIter iter;
normal[0] = normal[1] = normal[2] = 0;
-
- for (eve = em->verts.first; eve; eve = eve->next)
- {
- if ( eve->f & SELECT ) {
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT)) {
VecAddf(normal, normal, eve->no);
}
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 9438581409b..575e8f2150a 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -69,6 +69,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"
@@ -1109,11 +1111,11 @@ int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float
return retval;
}
-int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, EditMesh *em, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth)
+int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[][4], float ray_start[3], float ray_normal[3], short mval[2], float *loc, float *no, int *dist, float *depth)
{
int retval = 0;
int totvert = dm->getNumVerts(dm);
- int totface = dm->getNumFaces(dm);
+ int totface = dm->getNumTessFaces(dm);
if (totvert > 0) {
float imat[4][4];
@@ -1148,19 +1150,19 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
case SCE_SNAP_MODE_FACE:
{
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 */
@@ -1182,11 +1184,22 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
}
else
{
- efa = EM_get_face_for_index(index);
+ efa = EDBM_get_face_for_index(em, index);
- if (efa && (efa->h || (efa->v1->f & SELECT) || (efa->v2->f & SELECT) || (efa->v3->f & SELECT) || (efa->v4 && efa->v4->f & SELECT)))
+ if (efa && BM_TestHFlag(efa, BM_HIDDEN))
{
test = 0;
+ } else if (efa) {
+ BMIter iter;
+ BMLoop *l;
+
+ l = BMIter_New(&iter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for ( ; l; l=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ test = 0;
+ break;
+ }
+ }
}
}
}
@@ -1214,7 +1227,7 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
if (em != NULL)
{
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
break;
}
@@ -1228,11 +1241,11 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
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 */
@@ -1254,9 +1267,9 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
}
else
{
- eve = EM_get_vert_for_index(index);
+ eve = EDBM_get_vert_for_index(em, index);
- if (eve && (eve->h || (eve->f & SELECT)))
+ if (eve && (BM_TestHFlag(eve, BM_HIDDEN) || BM_TestHFlag(eve, BM_SELECT)))
{
test = 0;
}
@@ -1272,7 +1285,7 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
if (em != NULL)
{
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
break;
}
@@ -1288,11 +1301,11 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
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 */
@@ -1314,9 +1327,11 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
}
else
{
- eed = EM_get_edge_for_index(index);
+ eed = EDBM_get_edge_for_index(em, index);
- if (eed && (eed->h || (eed->v1->f & SELECT) || (eed->v2->f & SELECT)))
+ if (eed && (BM_TestHFlag(eed, BM_HIDDEN) ||
+ BM_TestHFlag(eed->v1, BM_SELECT) ||
+ BM_TestHFlag(eed->v2, BM_SELECT)))
{
test = 0;
}
@@ -1332,7 +1347,7 @@ int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, E
if (em != NULL)
{
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
break;
}
@@ -1349,13 +1364,13 @@ int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obma
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);
+ em = ((Mesh *)ob->data)->edit_btmesh;
+ dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
}
else
{
@@ -1491,7 +1506,7 @@ int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta
{
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];
@@ -1521,7 +1536,7 @@ int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_sta
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++) {
@@ -1617,6 +1632,7 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase
Object *ob = dupli_ob->ob;
if (ob->type == OB_MESH) {
+#if 0 //BMESH_TODO
EditMesh *em;
DerivedMesh *dm = NULL;
int val;
@@ -1638,6 +1654,7 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase
retval = retval || val;
dm->release(dm);
+#endif
}
}
@@ -1645,7 +1662,7 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase
}
if (ob->type == OB_MESH) {
- EditMesh *em;
+ BMEditMesh *em;
DerivedMesh *dm = NULL;
int val;
@@ -1657,8 +1674,8 @@ int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase
}
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/ed_util.c b/source/blender/editors/util/ed_util.c
index ae1e932bb81..93760ab77e3 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -72,10 +72,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/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index a58ee9772e9..0a747c951f5 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -41,6 +41,7 @@
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
#include "BLI_arithb.h"
#include "BLI_editVert.h"
@@ -452,7 +453,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 */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 801da08e611..6f8d710ed3e 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -1374,7 +1374,7 @@ static int de_select_all_exec(bContext *C, wmOperator *op)
ima= CTX_data_edit_image(C);
if(ts->uv_flag & UV_SYNC_SELECTION) {
- EM_toggle_select_all(em);
+ EDBM_toggle_select_all(((Mesh*)obedit->data)->edit_btmesh);
}
else {
sel= 0;
@@ -2172,7 +2172,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
-
+
BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_CANCELLED;
}
@@ -2706,6 +2706,7 @@ static int hide_exec(bContext *C, wmOperator *op)
EM_hide_mesh(em, swap);
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
BKE_mesh_end_editmesh(obedit->data, em);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 18c18d9e9dd..98cf7379df9 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -76,7 +76,9 @@ typedef struct CustomData {
#define CD_TANGENT 18
#define CD_MDISPS 19
#define CD_WEIGHT_MCOL 20 /* for displaying weightpaint colors */
-#define CD_NUMTYPES 21
+#define CD_MPOLY 21
+#define CD_MLOOP 22
+#define CD_NUMTYPES 23
/* Bits for CustomDataMask */
#define CD_MASK_MVERT (1 << CD_MVERT)
@@ -100,6 +102,8 @@ typedef struct CustomData {
#define CD_MASK_TANGENT (1 << CD_TANGENT)
#define CD_MASK_MDISPS (1 << CD_MDISPS)
#define CD_MASK_WEIGHT_MCOL (1 << CD_WEIGHT_MCOL)
+#define CD_MASK_MPOLY (1 << CD_MPOLY)
+#define CD_MASK_MLOOP (1 << CD_MLOOP)
/* derivedmesh wants CustomDataMask for weightpaint too, is not customdata though */
#define CD_MASK_WEIGHTPAINT (1 << CD_WEIGHTPAINT)
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index 3ecfe416c79..01c009a7971 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -44,6 +44,11 @@ struct MCol;
struct MSticky;
struct Mesh;
struct OcInfo;
+struct MPoly;
+struct MTexPoly;
+struct MLoop;
+struct MLoopUV;
+struct MLoopCol;
struct Multires;
struct PartialVisibility;
struct EditMesh;
@@ -58,23 +63,35 @@ typedef struct Mesh {
struct Ipo *ipo;
struct Key *key;
struct Material **mat;
-
- struct MFace *mface; /* array of mesh object mode faces */
- struct MTFace *mtface; /* store face UV's and texture here */
+
+ /*new face structures*/
+ struct MPoly *mpoly;
+ struct MTexPoly *mtpoly;
+ struct MLoop *mloop;
+ struct MLoopUV *mloopuv;
+ struct MLoopCol *mloopcol;
+
+ /*mface stores the tesselation (triangulation) of the mesh,
+ real faces are now stored in nface.*/
+ struct MFace *mface; /* array of mesh object mode faces for tesselation */
+ struct MTFace *mtface; /* store tesselation face UV's and texture here */
struct TFace *tface; /* depecrated, use mtface */
struct MVert *mvert; /* array of verts */
struct MEdge *medge; /* array of edges */
struct MDeformVert *dvert; /* deformgroup vertices */
- struct MCol *mcol; /* array of colors, this must be the number of faces * 4 */
+
+ /* array of colors for the tesselated faces, must be number of tesselated
+ faces * 4 in length */
+ struct MCol *mcol;
struct MSticky *msticky;
struct Mesh *texcomesh;
struct MSelect *mselect;
- struct EditMesh *edit_mesh; /* not saved in file! */
+ struct BMEditMesh *edit_btmesh; /* not saved in file! */
- struct CustomData vdata, edata, fdata;
+ struct CustomData vdata, edata, fdata, pdata, ldata;
- int totvert, totedge, totface, totselect;
+ int totvert, totedge, totface, totpoly, totloop, totselect;
/* the last selected vertex/edge/face are used for the active face however
* this means the active face must always be selected, this is to keep track
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index d53a7833d0e..94713cf0d76 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -71,7 +71,22 @@ typedef struct MCol {
char a, r, g, b;
} MCol;
-/*bmesh custom data stuff*/
+/*new face structure, replaces MFace, which is now
+ only used for storing tesselations.*/
+typedef struct MPoly {
+ /*offset into loop array and number of loops in the face*/
+ int loopstart, totloop;
+ short mat_nr;
+ short flag;
+} MPoly;
+
+/*the e here is because we want to move away from
+ relying on edge hashes.*/
+typedef struct MLoop {
+ int v; /*vertex index*/
+ int e; /*edge index*/
+} MLoop;
+
typedef struct MTexPoly{
struct Image *tpage;
char flag, transp;
@@ -217,7 +232,9 @@ typedef struct PartialVisibility {
/* flag (mface) */
#define ME_SMOOTH 1
#define ME_FACE_SEL 2
- /* flag ME_HIDE==16 is used here too */
+/* flag ME_HIDE==16 is used here too */
+#define ME_DRAW_ACT 4
+
/* mselect->type */
#define ME_VSEl 0
#define ME_ESEl 1
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 2b0ede846af..93980e58f8c 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -116,7 +116,7 @@ typedef struct Object {
/* materials */
struct Material **mat; /* material slots */
- char *matbits; /* 1 if material linked to object */
+ char *matbits; /* a bitfield, with each bit 1 if corrusponding material linked to object */
int totcol; /* copy of mesh or curve or meta */
int actcol; /* currently selected material in the UI */
diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript
index 1c716019e80..29d57f095e7 100644
--- a/source/blender/makesdna/intern/SConscript
+++ b/source/blender/makesdna/intern/SConscript
@@ -46,21 +46,25 @@ targetdir = normpath(root_build_dir + '/makesdna')
if not (root_build_dir[0]==os.sep or root_build_dir[1]==':'):
targetdir = '#' + targetdir
+ #root_build_dir = "#"
makesdna = makesdna_tool.Program (target = targetdir, source = source_files, LIBS=['bf_guardedalloc'])
dna_dict = dna.Dictionary()
dna.Depends ('dna.c', makesdna)
dna.Depends ('dna.c', header_files)
+
+ap = os.path.abspath
+
if env['OURPLATFORM'] != 'linuxcross':
if USE_WINE:
- dna.Command ('dna.c', '', 'wine ' + root_build_dir+os.sep+"makesdna $TARGET")
+ dna.Command ('dna.c', '', 'wine ' + ap(root_build_dir+os.sep+"makesdna $TARGET"))
else:
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc', 'win32-mingw'):
dna.Command ('dna.c', '', "\"" + root_build_dir+os.sep+"makesdna\" $TARGET")
else:
dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna $TARGET")
else:
- dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna.exe $TARGET")
+ dna.Command ('dna.c', '', ap(root_build_dir+os.sep+"makesdna.exe $TARGET"))
obj = ['intern/dna.c', 'intern/dna_genfile.c']
Return ('obj')
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index 89118850b20..2a1ae7be543 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -7,7 +7,7 @@ o = SConscript('intern/SConscript')
objs += o
incs = '#/intern/guardedalloc ../blenkernel ../blenlib ../makesdna intern .'
-incs += ' ../windowmanager ../editors/include ../imbuf'
+incs += ' ../windowmanager ../editors/include ../imbuf ../bmesh'
defs = []
diff --git a/source/blender/makesrna/intern/Makefile b/source/blender/makesrna/intern/Makefile
index 7f9bfbfea67..4a3715fb9a9 100644
--- a/source/blender/makesrna/intern/Makefile
+++ b/source/blender/makesrna/intern/Makefile
@@ -52,6 +52,7 @@ CPPFLAGS += -I../../imbuf
CPPFLAGS += -I../../makesdna
CPPFLAGS += -I../../windowmanager
CPPFLAGS += -I../../editors/include
+CPPFLAGS += -I../../bmesh
CPPFLAGS += -I..
CPPFLAGS += -I.
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 7cd3fde21be..53243fd97a0 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -29,7 +29,7 @@ makesrna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesrna/\\"" '
defs = []
-incs = '#/intern/guardedalloc ../../blenlib ../../blenkernel'
+incs = '#/intern/guardedalloc ../../bmesh ../../blenlib ../../blenkernel'
incs += ' ../../imbuf ../../makesdna ../../makesrna'
incs += ' ../../windowmanager ../../editors/include'
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
deleted file mode 100644
index 6d56b2b00f9..00000000000
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "RNA_define.h"
-#include "RNA_types.h"
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_main.h"
-#include "BKE_mesh.h"
-#include "BKE_library.h"
-
-#include "DNA_mesh_types.h"
-
-Mesh *rna_Main_add_mesh(Main *main, char *name)
-{
- Mesh *me= add_mesh(name);
- me->id.us--;
- return me;
-}
-
-void rna_Main_remove_mesh(Main *main, ReportList *reports, Mesh *me)
-{
- if(me->id.us == 0)
- free_libblock(&main->mesh, me);
- else
- BKE_report(reports, RPT_ERROR, "Mesh must have zero users to be removed.");
-
- /* XXX python now has invalid pointer? */
-}
-
-#else
-
-void RNA_api_main(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *prop;
-
- func= RNA_def_function(srna, "add_mesh", "rna_Main_add_mesh");
- RNA_def_function_ui_description(func, "Add a new mesh.");
- prop= RNA_def_string(func, "name", "Mesh", 0, "", "New name for the datablock.");
- prop= RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh.");
- RNA_def_function_return(func, prop);
-
- func= RNA_def_function(srna, "remove_mesh", "rna_Main_remove_mesh");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
- RNA_def_function_ui_description(func, "Remove a mesh if it has zero users.");
- prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove.");
- RNA_def_property_flag(prop, PROP_REQUIRED);
-}
-
-#endif
-
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 3a7015b65be..0a0d70fa9eb 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -45,6 +45,7 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -212,7 +213,7 @@ static void rna_MeshFace_material_index_range(PointerRNA *ptr, int *min, int *ma
static CustomData *rna_mesh_fdata(Mesh *me)
{
- return (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
+ return (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata;
}
static int rna_CustomDataLayer_length(PointerRNA *ptr, int type)
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
deleted file mode 100644
index c98b3fb7b09..00000000000
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "RNA_define.h"
-#include "RNA_types.h"
-
-#ifdef RNA_RUNTIME
-
-#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-
-#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_main.h"
-#include "BKE_mesh.h"
-
-#include "BLI_edgehash.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-static void rna_Mesh_calc_edges(Mesh *mesh)
-{
- CustomData edata;
- EdgeHashIterator *ehi;
- MFace *mf = mesh->mface;
- MEdge *med;
- EdgeHash *eh = BLI_edgehash_new();
- int i, *index, totedge, totface = mesh->totface;
-
- 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);
- }
- }
-
- totedge = BLI_edgehash_size(eh);
-
- /* write new edges into a temporary CustomData */
- memset(&edata, 0, sizeof(edata));
- CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
-
- ehi = BLI_edgehashIterator_new(eh);
- med = CustomData_get_layer(&edata, CD_MEDGE);
- for(i = 0; !BLI_edgehashIterator_isDone(ehi);
- BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
- BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
-
- med->flag = ME_EDGEDRAW|ME_EDGERENDER;
- }
- BLI_edgehashIterator_free(ehi);
-
- /* free old CustomData and assign new one */
- CustomData_free(&mesh->edata, mesh->totedge);
- mesh->edata = edata;
- mesh->totedge = totedge;
-
- mesh->medge = CustomData_get_layer(&mesh->edata, CD_MEDGE);
-
- BLI_edgehash_free(eh, NULL);
-}
-
-static void rna_Mesh_update(Mesh *mesh, bContext *C)
-{
- Main *bmain= CTX_data_main(C);
- Object *ob;
-
- if(mesh->totface && mesh->totedge == 0)
- rna_Mesh_calc_edges(mesh);
-
- mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
-
- for(ob=bmain->object.first; ob; ob=ob->id.next) {
- if(ob->data == mesh) {
- ob->recalc |= OB_RECALC_DATA;
- WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
- }
- }
-}
-
-static void rna_Mesh_add_verts(Mesh *mesh, int len)
-{
- CustomData vdata;
- MVert *mvert;
- int i, totvert;
-
- if(len == 0)
- return;
-
- totvert= mesh->totvert + len;
- CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
- CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
-
- if(!CustomData_has_layer(&vdata, CD_MVERT))
- CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
-
- CustomData_free(&mesh->vdata, mesh->totvert);
- mesh->vdata= vdata;
- mesh_update_customdata_pointers(mesh);
-
- /* scan the input list and insert the new vertices */
-
- mvert= &mesh->mvert[mesh->totvert];
- for(i=0; i<len; i++, mvert++)
- mvert->flag |= SELECT;
-
- /* set final vertex list size */
- mesh->totvert= totvert;
-}
-
-static void rna_Mesh_add_edges(Mesh *mesh, int len)
-{
- CustomData edata;
- MEdge *medge;
- int i, totedge;
-
- if(len == 0)
- return;
-
- totedge= mesh->totedge+len;
-
- /* update customdata */
- CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
- CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
-
- if(!CustomData_has_layer(&edata, CD_MEDGE))
- CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
-
- CustomData_free(&mesh->edata, mesh->totedge);
- mesh->edata= edata;
- mesh_update_customdata_pointers(mesh);
-
- /* set default flags */
- medge= &mesh->medge[mesh->totedge];
- for(i=0; i<len; i++, medge++)
- medge->flag= ME_EDGEDRAW|ME_EDGERENDER|SELECT;
-
- mesh->totedge= totedge;
-}
-
-static void rna_Mesh_add_faces(Mesh *mesh, int len)
-{
- CustomData fdata;
- MFace *mface;
- int i, totface;
-
- if(len == 0)
- return;
-
- totface= mesh->totface + len; /* new face count */
-
- /* update customdata */
- CustomData_copy(&mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
- CustomData_copy_data(&mesh->fdata, &fdata, 0, 0, mesh->totface);
-
- if(!CustomData_has_layer(&fdata, CD_MFACE))
- CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
-
- CustomData_free(&mesh->fdata, mesh->totface);
- mesh->fdata= fdata;
- mesh_update_customdata_pointers(mesh);
-
- /* set default flags */
- mface= &mesh->mface[mesh->totface];
- for(i=0; i<len; i++, mface++)
- mface->flag= SELECT;
-
- mesh->totface= totface;
-}
-
-static void rna_Mesh_add_geometry(Mesh *mesh, int verts, int edges, int faces)
-{
- if(verts)
- rna_Mesh_add_verts(mesh, verts);
- if(edges)
- rna_Mesh_add_edges(mesh, edges);
- if(faces)
- rna_Mesh_add_faces(mesh, faces);
-}
-
-#else
-
-void RNA_api_mesh(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *parm;
-
- func= RNA_def_function(srna, "add_geometry", "rna_Mesh_add_geometry");
- parm= RNA_def_int(func, "verts", 0, 0, INT_MAX, "Number", "Number of vertices to add.", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_int(func, "edges", 0, 0, INT_MAX, "Number", "Number of edges to add.", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_int(func, "faces", 0, 0, INT_MAX, "Number", "Number of faces to add.", 0, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "update", "rna_Mesh_update");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-}
-
-#endif
-
diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c
deleted file mode 100644
index bc636af6849..00000000000
--- a/source/blender/makesrna/intern/rna_nla.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Contributor(s): Blender Foundation (2009), Joshua Leung
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <stdlib.h>
-
-#include "RNA_define.h"
-#include "RNA_types.h"
-
-#include "rna_internal.h"
-
-#include "DNA_anim_types.h"
-#include "DNA_action_types.h"
-#include "DNA_scene_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#ifdef RNA_RUNTIME
-
-#include <stdio.h>
-#include <math.h>
-
-/* needed for some of the validation stuff... */
-#include "BKE_animsys.h"
-#include "BKE_nla.h"
-
-/* temp constant defined for these funcs only... */
-#define NLASTRIP_MIN_LEN_THRESH 0.1f
-
-void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value)
-{
- NlaStrip *data= (NlaStrip *)ptr->data;
-
- /* copy the name first */
- BLI_strncpy(data->name, value, sizeof(data->name));
-
- /* validate if there's enough info to do so */
- if (ptr->id.data) {
- AnimData *adt= BKE_animdata_from_id(ptr->id.data);
- BKE_nlastrip_validate_name(adt, data);
- }
-}
-
-
-static void rna_NlaStrip_start_frame_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
-
- /* clamp value to lie within valid limits
- * - cannot start past the end of the strip + some flexibility threshold
- * - cannot start before the previous strip (if present) ends
- * -> but if it was a transition, we could go up to the start of the strip + some flexibility threshold
- * as long as we re-adjust the transition afterwards
- * - minimum frame is -MAXFRAME so that we don't get clipping on frame 0
- */
- if (data->prev) {
- if (data->prev->type == NLASTRIP_TYPE_TRANSITION) {
- CLAMP(value, data->prev->start+NLASTRIP_MIN_LEN_THRESH, data->end-NLASTRIP_MIN_LEN_THRESH);
-
- /* readjust the transition to stick to the endpoints of the action-clips */
- data->prev->end= value;
- }
- else {
- CLAMP(value, data->prev->end, data->end-NLASTRIP_MIN_LEN_THRESH);
- }
- }
- else {
- CLAMP(value, MINAFRAME, data->end);
- }
- data->start= value;
-}
-
-static void rna_NlaStrip_end_frame_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
-
- /* clamp value to lie within valid limits
- * - must not have zero or negative length strip, so cannot start before the first frame
- * + some minimum-strip-length threshold
- * - cannot end later than the start of the next strip (if present)
- * -> but if it was a transition, we could go up to the start of the end - some flexibility threshold
- * as long as we re-adjust the transition afterwards
- */
- if (data->next) {
- if (data->next->type == NLASTRIP_TYPE_TRANSITION) {
- CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->end-NLASTRIP_MIN_LEN_THRESH);
-
- /* readjust the transition to stick to the endpoints of the action-clips */
- data->next->start= value;
- }
- else {
- CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->start);
- }
- }
- else {
- CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, MAXFRAME);
- }
- data->end= value;
-
-
- /* calculate the lengths the strip and its action (if applicable) */
- if (data->type == NLASTRIP_TYPE_CLIP) {
- float len, actlen;
-
- len= data->end - data->start;
- actlen= data->actend - data->actstart;
- if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
-
- /* now, adjust the 'scale' setting to reflect this (so that this change can be valid) */
- data->scale= len / ((actlen) * data->repeat);
- }
-}
-
-static void rna_NlaStrip_scale_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
- float actlen, mapping;
-
- /* set scale value */
- CLAMP(value, 0.0001f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
- data->scale= value;
-
- /* calculate existing factors */
- actlen= data->actend - data->actstart;
- if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
- mapping= data->scale * data->repeat;
-
- /* adjust endpoint of strip in response to this */
- if (IS_EQ(mapping, 0.0f) == 0)
- data->end = (actlen * mapping) + data->start;
- else
- printf("NlaStrip Set Scale Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat);
-}
-
-static void rna_NlaStrip_repeat_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
- float actlen, mapping;
-
- /* set scale value */
- CLAMP(value, 0.01f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
- data->repeat= value;
-
- /* calculate existing factors */
- actlen= data->actend - data->actstart;
- if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
- mapping= data->scale * data->repeat;
-
- /* adjust endpoint of strip in response to this */
- if (IS_EQ(mapping, 0.0f) == 0)
- data->end = (actlen * mapping) + data->start;
- else
- printf("NlaStrip Set Repeat Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat);
-}
-
-static void rna_NlaStrip_blend_in_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
- float len;
-
- /* blend-in is limited to the length of the strip, and also cannot overlap with blendout */
- len= (data->end - data->start) - data->blendout;
- CLAMP(value, 0, len);
-
- data->blendin= value;
-}
-
-static void rna_NlaStrip_blend_out_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
- float len;
-
- /* blend-out is limited to the length of the strip */
- len= (data->end - data->start);
- CLAMP(value, 0, len);
-
- /* it also cannot overlap with blendin */
- if ((len - value) < data->blendin)
- value= len - data->blendin;
-
- data->blendout= value;
-}
-
-static void rna_NlaStrip_action_start_frame_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
- CLAMP(value, MINAFRAME, data->actend);
- data->actstart= value;
-}
-
-static void rna_NlaStrip_action_end_frame_set(PointerRNA *ptr, float value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
- CLAMP(value, data->actstart, MAXFRAME);
- data->actend= value;
-}
-
-static void rna_NlaStrip_animated_influence_set(PointerRNA *ptr, int value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
-
- if (value) {
- /* set the flag, then make sure a curve for this exists */
- data->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
- BKE_nlastrip_validate_fcurves(data);
- }
- else
- data->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
-}
-
-static void rna_NlaStrip_animated_time_set(PointerRNA *ptr, int value)
-{
- NlaStrip *data= (NlaStrip*)ptr->data;
-
- if (value) {
- /* set the flag, then make sure a curve for this exists */
- data->flag |= NLASTRIP_FLAG_USR_TIME;
- BKE_nlastrip_validate_fcurves(data);
- }
- else
- data->flag &= ~NLASTRIP_FLAG_USR_TIME;
-}
-
-#else
-
-void rna_def_nlastrip(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- /* enum defs */
- static EnumPropertyItem prop_type_items[] = {
- {NLASTRIP_TYPE_CLIP, "CLIP", 0, "Action Clip", "NLA Strip references some Action."},
- {NLASTRIP_TYPE_TRANSITION, "TRANSITION", 0, "Transition", "NLA Strip 'transitions' between adjacent strips."},
- {NLASTRIP_TYPE_META, "META", 0, "Meta", "NLA Strip acts as a container for adjacent strips."},
- {0, NULL, 0, NULL, NULL}};
- static EnumPropertyItem prop_mode_blend_items[] = {
- {NLASTRIP_MODE_REPLACE, "REPLACE", 0, "Replace", "Result strip replaces the accumulated results by amount specified by influence."},
- {NLASTRIP_MODE_ADD, "ADD", 0, "Add", "Weighted result of strip is added to the accumlated results."},
- {NLASTRIP_MODE_SUBTRACT, "SUBTRACT", 0, "Subtract", "Weighted result of strip is removed from the accumlated results."},
- {NLASTRIP_MODE_MULTIPLY, "MULITPLY", 0, "Multiply", "Weighted result of strip is multiplied with the accumlated results."},
- {0, NULL, 0, NULL, NULL}};
- static EnumPropertyItem prop_mode_extend_items[] = {
- {NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents."},
- {NLASTRIP_EXTEND_HOLD, "HOLD", 0, "Hold", "Hold the first frame if no previous strips in track, and always hold last frame."},
- {NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame."},
- {0, NULL, 0, NULL, NULL}};
-
- /* struct definition */
- srna= RNA_def_struct(brna, "NlaStrip", NULL);
- RNA_def_struct_ui_text(srna, "NLA Strip", "A container referencing an existing Action.");
- RNA_def_struct_ui_icon(srna, ICON_NLA); // XXX
-
- /* name property */
- prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Name", "");
- RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NlaStrip_name_set");
- RNA_def_struct_name_property(srna, prop);
-
- /* Enums */
- prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_clear_flag(prop, PROP_EDITABLE); // XXX for now, not editable, since this is dangerous
- RNA_def_property_enum_items(prop, prop_type_items);
- RNA_def_property_ui_text(prop, "Type", "Type of NLA Strip.");
-
- prop= RNA_def_property(srna, "extrapolation", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "extendmode");
- RNA_def_property_enum_items(prop, prop_mode_extend_items);
- RNA_def_property_ui_text(prop, "Extrapolation", "Action to take for gaps past the strip extents.");
-
- prop= RNA_def_property(srna, "blending", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "blendmode");
- RNA_def_property_enum_items(prop, prop_mode_blend_items);
- RNA_def_property_ui_text(prop, "Blending", "Method used for combining strip's result with accumulated result.");
-
- /* Strip extents */
- prop= RNA_def_property(srna, "start_frame", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "start");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_start_frame_set", NULL);
- RNA_def_property_ui_text(prop, "Start Frame", "");
-
- prop= RNA_def_property(srna, "end_frame", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "end");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_end_frame_set", NULL);
- RNA_def_property_ui_text(prop, "End Frame", "");
-
- /* Blending */
- prop= RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "blendin");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_in_set", NULL);
- RNA_def_property_ui_text(prop, "Blend In", "Number of frames at start of strip to fade in influence.");
-
- prop= RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "blendout");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_out_set", NULL);
- RNA_def_property_ui_text(prop, "Blend Out", "");
-
- prop= RNA_def_property(srna, "auto_blending", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_AUTO_BLENDS);
- RNA_def_property_ui_text(prop, "Auto Blend In/Out", "Number of frames for Blending In/Out is automatically determined from overlapping strips.");
-
- /* Action */
- prop= RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
- RNA_def_property_pointer_sdna(prop, NULL, "act");
- RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip.");
-
- /* Action extents */
- prop= RNA_def_property(srna, "action_start_frame", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "actstart");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_start_frame_set", NULL);
- RNA_def_property_ui_text(prop, "Action Start Frame", "");
-
- prop= RNA_def_property(srna, "action_end_frame", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "actend");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_end_frame_set", NULL);
- RNA_def_property_ui_text(prop, "Action End Frame", "");
-
- /* Action Reuse */
- prop= RNA_def_property(srna, "repeat", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "repeat");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_repeat_set", NULL);
- RNA_def_property_range(prop, 0.1f, 1000.0f); /* these limits have currently be chosen arbitarily, but could be extended (minimum should still be > 0 though) if needed... */
- RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range.");
-
- prop= RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "scale");
- RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_scale_set", NULL);
- RNA_def_property_range(prop, 0.0001f, 1000.0f); /* these limits can be extended, but beyond this, we can get some crazy+annoying bugs due to numeric errors */
- RNA_def_property_ui_text(prop, "Scale", "Scaling factor for action.");
-
- /* Strip's F-Curves */
- prop= RNA_def_property(srna, "fcurves", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "FCurve");
- RNA_def_property_ui_text(prop, "F-Curves", "F-Curves for controlling the strip's influence and timing.");
-
- /* Strip's F-Modifiers */
- prop= RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "FModifier");
- RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting all the F-Curves in the referenced Action.");
-
- /* Strip's Sub-Strips (for Meta-Strips) */
- prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "NlaStrip");
- RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips that this strip acts as a container for (if it is of type Meta).");
-
- /* Settings - Values necessary for evaluation */
- prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result.");
-
- prop= RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_NONE);
- RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate.");
-
- // TODO: should the animated_influence/time settings be animatable themselves?
- prop= RNA_def_property(srna, "animated_influence", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_INFLUENCE);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_influence_set");
- RNA_def_property_ui_text(prop, "Animated Influence", "Influence setting is controlled by an F-Curve rather than automatically determined.");
-
- prop= RNA_def_property(srna, "animated_time", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME);
- RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_time_set");
- RNA_def_property_ui_text(prop, "Animated Strip Time", "Strip time is controlled by an F-Curve rather than automatically determined.");
-
- /* settings */
- prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_ACTIVE);
- RNA_def_property_ui_text(prop, "Active", "NLA Strip is active.");
-
- prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SELECT);
- RNA_def_property_ui_text(prop, "Selected", "NLA Strip is selected.");
-
- prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED);
- RNA_def_property_ui_text(prop, "Muted", "NLA Strip is not evaluated.");
-
- prop= RNA_def_property(srna, "reversed", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_REVERSE);
- RNA_def_property_ui_text(prop, "Reversed", "NLA Strip is played back in reverse order (only when timing is automatically determined).");
-
- // TODO:
- // - sync length
-}
-
-void rna_def_nlatrack(BlenderRNA *brna)
-{
- StructRNA *srna;
- PropertyRNA *prop;
-
- srna= RNA_def_struct(brna, "NlaTrack", NULL);
- RNA_def_struct_ui_text(srna, "NLA Track", "A animation layer containing Actions referenced as NLA strips.");
- RNA_def_struct_ui_icon(srna, ICON_NLA);
-
- /* strips collection */
- prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_type(prop, "NlaStrip");
- RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track.");
-
- /* name property */
- prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Name", "");
- RNA_def_struct_name_property(srna, prop);
-
- /* settings */
- prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_ACTIVE);
- RNA_def_property_ui_text(prop, "Active", "NLA Track is active.");
-
- prop= RNA_def_property(srna, "solo", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SOLO);
- RNA_def_property_ui_text(prop, "Solo", "NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the same AnimData block are disabled).");
-
- prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SELECTED);
- RNA_def_property_ui_text(prop, "Selected", "NLA Track is selected.");
-
- prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_MUTED);
- RNA_def_property_ui_text(prop, "Muted", "NLA Track is not evaluated.");
-
- prop= RNA_def_property(srna, "locked", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED);
- RNA_def_property_ui_text(prop, "Locked", "NLA Track is locked.");
-}
-
-/* --------- */
-
-void RNA_def_nla(BlenderRNA *brna)
-{
- rna_def_nlatrack(brna);
- rna_def_nlastrip(brna);
-}
-
-
-#endif
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
deleted file mode 100644
index 053ab115b3b..00000000000
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "RNA_define.h"
-#include "RNA_types.h"
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_customdata.h"
-#include "BKE_DerivedMesh.h"
-
-#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-
-/* copied from init_render_mesh (render code) */
-Mesh *rna_Object_create_render_mesh(Object *ob, Scene *scene)
-{
- CustomDataMask mask = CD_MASK_BAREMESH|CD_MASK_MTFACE|CD_MASK_MCOL;
- DerivedMesh *dm;
- Mesh *me;
-
- /* TODO: other types */
- if(ob->type != OB_MESH)
- return NULL;
-
- dm= mesh_create_derived_render(scene, ob, mask);
-
- if(!dm)
- return NULL;
-
- me= add_mesh("tmp_render_mesh");
- me->id.us--; /* we don't assign it to anything */
- DM_to_mesh(dm, me);
- dm->release(dm);
-
- return me;
-}
-
-#else
-
-void RNA_api_object(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *prop;
-
- func= RNA_def_function(srna, "create_render_mesh", "rna_Object_create_render_mesh");
- RNA_def_function_ui_description(func, "Create a Mesh datablock with all modifiers applied.");
- prop= RNA_def_pointer(func, "scene", "Scene", "", "");
- RNA_def_property_flag(prop, PROP_REQUIRED);
- prop= RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object, remove it if it is only used for export.");
- RNA_def_function_return(func, prop);
-}
-
-#endif
-
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
deleted file mode 100644
index 404befc9bb2..00000000000
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/**
- * $Id:
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "RNA_define.h"
-#include "RNA_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#ifdef RNA_RUNTIME
-
-#else
-
-#define DEF_ICON(name) {name, #name, 0, #name, ""},
-static EnumPropertyItem icon_items[] = {
-#include "UI_icons.h"
- {0, NULL, 0, NULL, NULL}};
-#undef DEF_ICON
-
-static void api_ui_item_common(FunctionRNA *func)
-{
- PropertyRNA *prop;
-
- RNA_def_string(func, "text", "", 0, "", "Override automatic text of the item.");
-
- prop= RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, icon_items);
- RNA_def_property_ui_text(prop, "Icon", "Override automatic icon of the item.");
-
-}
-
-static void api_ui_item_op_common(FunctionRNA *func)
-{
- PropertyRNA *parm;
-
- api_ui_item_common(func);
- parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-}
-
-static void api_ui_item_rna_common(FunctionRNA *func)
-{
- PropertyRNA *parm;
-
- parm= RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property.");
- RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in data.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-}
-
-void RNA_api_ui_layout(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *parm;
-
- static EnumPropertyItem curve_type_items[] = {
- {0, "NONE", 0, "None", ""},
- {'v', "VECTOR", 0, "Vector", ""},
- {'c', "COLOR", 0, "Color", ""},
- {0, NULL, 0, NULL, NULL}};
-
- /* simple layout specifiers */
- func= RNA_def_function(srna, "row", "uiLayoutRow");
- parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in.");
- RNA_def_function_return(func, parm);
- RNA_def_boolean(func, "align", 0, "", "Align buttons to each other.");
-
- func= RNA_def_function(srna, "column", "uiLayoutColumn");
- parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in.");
- RNA_def_function_return(func, parm);
- RNA_def_boolean(func, "align", 0, "", "Align buttons to each other.");
-
- func= RNA_def_function(srna, "column_flow", "uiLayoutColumnFlow");
- parm= RNA_def_int(func, "columns", 0, 0, INT_MAX, "", "Number of columns, 0 is automatic.", 0, INT_MAX);
- parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in.");
- RNA_def_function_return(func, parm);
- RNA_def_boolean(func, "align", 0, "", "Align buttons to each other.");
-
- /* box layout */
- func= RNA_def_function(srna, "box", "uiLayoutBox");
- parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in.");
- RNA_def_function_return(func, parm);
-
- /* split layout */
- func= RNA_def_function(srna, "split", "uiLayoutSplit");
- parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in.");
- RNA_def_function_return(func, parm);
- RNA_def_float(func, "percentage", 0.5f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at.", 0.0f, 1.0f);
-
- /* items */
- func= RNA_def_function(srna, "itemR", "uiItemR");
- api_ui_item_common(func);
- api_ui_item_rna_common(func);
- RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail.");
- RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values.");
- RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values.");
-
- func= RNA_def_function(srna, "items_enumR", "uiItemsEnumR");
- api_ui_item_rna_common(func);
-
- func= RNA_def_function(srna, "item_menu_enumR", "uiItemMenuEnumR");
- api_ui_item_common(func);
- api_ui_item_rna_common(func);
-
- func= RNA_def_function(srna, "item_enumR", "uiItemEnumR_string");
- api_ui_item_common(func);
- api_ui_item_rna_common(func);
- parm= RNA_def_string(func, "value", "", 0, "", "Enum property value.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "item_pointerR", "uiItemPointerR");
- api_ui_item_common(func);
- api_ui_item_rna_common(func);
- parm= RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in.");
- RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR);
- parm= RNA_def_string(func, "search_property", "", 0, "", "Identifier of search collection property.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "itemO", "uiItemO");
- api_ui_item_op_common(func);
-
- func= RNA_def_function(srna, "item_enumO", "uiItemEnumO_string");
- api_ui_item_op_common(func);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_string(func, "value", "", 0, "", "Enum property value.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "items_enumO", "uiItemsEnumO");
- parm= RNA_def_string(func, "operator", "", 0, "", "Identifier of the operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "item_menu_enumO", "uiItemMenuEnumO");
- api_ui_item_op_common(func);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "item_booleanO", "uiItemBooleanO");
- api_ui_item_op_common(func);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_boolean(func, "value", 0, "", "Value of the property to call the operator with.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "item_intO", "uiItemIntO");
- api_ui_item_op_common(func);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_int(func, "value", 0, INT_MIN, INT_MAX, "", "Value of the property to call the operator with.", INT_MIN, INT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "item_floatO", "uiItemFloatO");
- api_ui_item_op_common(func);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "", "Value of the property to call the operator with.", -FLT_MAX, FLT_MAX);
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "item_stringO", "uiItemStringO");
- api_ui_item_op_common(func);
- parm= RNA_def_string(func, "property", "", 0, "", "Identifier of property in operator.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_string(func, "value", "", 0, "", "Value of the property to call the operator with.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "itemL", "uiItemL");
- api_ui_item_common(func);
-
- func= RNA_def_function(srna, "itemM", "uiItemM");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
- api_ui_item_common(func);
- parm= RNA_def_string(func, "menu", "", 0, "", "Identifier of the menu.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "itemS", "uiItemS");
-
- /* context */
- func= RNA_def_function(srna, "set_context_pointer", "uiLayoutSetContextPointer");
- parm= RNA_def_string(func, "name", "", 0, "Name", "Name of entry in the context.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context.");
- RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR);
-
- /* templates */
- func= RNA_def_function(srna, "template_header", "uiTemplateHeader");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-
- func= RNA_def_function(srna, "template_ID", "uiTemplateID");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
- api_ui_item_rna_common(func);
- RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block.");
- RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
-
- func= RNA_def_function(srna, "template_modifier", "uiTemplateModifier");
- parm= RNA_def_pointer(func, "data", "Modifier", "", "Modifier data.");
- RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR);
- parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in.");
- RNA_def_function_return(func, parm);
-
- func= RNA_def_function(srna, "template_constraint", "uiTemplateConstraint");
- parm= RNA_def_pointer(func, "data", "Constraint", "", "Constraint data.");
- RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR);
- parm= RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in.");
- RNA_def_function_return(func, parm);
-
- func= RNA_def_function(srna, "template_preview", "uiTemplatePreview");
- parm= RNA_def_pointer(func, "id", "ID", "", "ID datablock.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "template_curve_mapping", "uiTemplateCurveMapping");
- parm= RNA_def_pointer(func, "curvemap", "CurveMapping", "", "Curve mapping pointer.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display.");
-
- func= RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp");
- parm= RNA_def_pointer(func, "ramp", "ColorRamp", "", "Color ramp pointer.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_boolean(func, "expand", 0, "", "Expand button to show more detail.");
-
- func= RNA_def_function(srna, "template_layers", "uiTemplateLayers");
- api_ui_item_rna_common(func);
-
- func= RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
- parm= RNA_def_pointer(func, "image", "Image", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_pointer(func, "image_user", "ImageUser", "", "");
- RNA_def_property_flag(parm, PROP_REQUIRED);
-
- func= RNA_def_function(srna, "template_list", "uiTemplateList");
- api_ui_item_rna_common(func);
- parm= RNA_def_pointer(func, "active_data", "AnyType", "", "Data from which to take property for the active element.");
- RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR);
- parm= RNA_def_string(func, "active_property", "", 0, "", "Identifier of property in data, for the active element.");
- RNA_def_property_flag(parm, PROP_REQUIRED);
- parm= RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display.", 0, INT_MAX);
- parm= RNA_def_int(func, "columns", 5, 0, INT_MAX, "", "Number of columns to display.", 0, INT_MAX);
- parm= RNA_def_boolean(func, "compact", 0, "", "Use compact, single row list template.");
- parm= RNA_def_collection(func, "items", 0, "", "Items visible in the list.");
- RNA_def_function_return(func, parm);
-
- func= RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-
- func= RNA_def_function(srna, "template_operator_search", "uiTemplateOperatorSearch");
-
- func= RNA_def_function(srna, "template_header_3D", "uiTemplateHeader3D");
- RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-}
-
-#endif
-
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
deleted file mode 100644
index fd34d7c4d70..00000000000
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- *
- *
- * Contributor(s): Blender Foundation
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "RNA_define.h"
-#include "RNA_types.h"
-
-#ifdef RNA_RUNTIME
-
-#include "BKE_context.h"
-
-#include "WM_api.h"
-
-#else
-
-void RNA_api_wm(StructRNA *srna)
-{
- FunctionRNA *func;
- PropertyRNA *prop;
-
- func= RNA_def_function(srna, "add_fileselect", "WM_event_add_fileselect");
- RNA_def_function_flag(func, FUNC_NO_SELF|FUNC_USE_CONTEXT);
- RNA_def_function_ui_description(func, "Show up the file selector.");
- prop= RNA_def_pointer(func, "operator", "Operator", "", "Operator to call.");
- RNA_def_property_flag(prop, PROP_REQUIRED);
-}
-
-#endif
-
diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_at.c b/source/blender/nodes/intern/TEX_nodes/TEX_at.c
deleted file mode 100644
index 80f232ccd0c..00000000000
--- a/source/blender/nodes/intern/TEX_nodes/TEX_at.c
+++ /dev/null
@@ -1,70 +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): R Allen
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "../TEX_util.h"
-
-static bNodeSocketType inputs[]= {
- { SOCK_RGBA, 1, "Texture", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f },
- { SOCK_VECTOR, 1, "Coordinates", 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f },
- { -1, 0, "" }
-};
-static bNodeSocketType outputs[]= {
- { SOCK_RGBA, 0, "Texture", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f },
- { -1, 0, "" }
-};
-
-static void colorfn(float *out, float *coord, bNode *node, bNodeStack **in, short thread)
-{
- float new_coord[3];
-
- tex_input_vec(new_coord, in[1], coord, thread);
- tex_input_rgba(out, in[0], new_coord, thread);
-}
-
-static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
-{
- tex_output(node, in, out[0], &colorfn);
-}
-
-bNodeType tex_node_at = {
- /* *next,*prev */ NULL, NULL,
- /* type code */ TEX_NODE_AT,
- /* name */ "At",
- /* width+range */ 100, 60, 150,
- /* class+opts */ NODE_CLASS_DISTORT, 0,
- /* input sock */ inputs,
- /* output sock */ outputs,
- /* storage */ "",
- /* execfunc */ exec,
- /* butfunc */ NULL,
- /* initfunc */ NULL,
- /* freestoragefunc */ NULL,
- /* copystoragefunc */ NULL,
- /* id */ NULL
-
-};
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index c6972793372..ff3e89a6e25 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -1,5 +1,5 @@
/*
- * $Id$
+ * $Id: BPY_extern.h 12334 2007-10-21 23:00:29Z aligorith $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
@@ -50,8 +50,6 @@ struct bConstraintTarget; /* DNA_constraint_types.h*/
struct Script; /* DNA_screen_types.h */
struct BPyMenu;
struct bContext;
-struct ReportList;
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -99,8 +97,8 @@ extern "C" {
int BPY_menu_invoke( struct BPyMenu *pym, short menutype );
/* 2.5 UI Scripts */
- int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text, struct ReportList *reports ); // 2.5 working
- int BPY_run_script_space_draw(const struct bContext *C, struct SpaceScript * sc); // 2.5 working
+ int BPY_run_python_script( struct bContext *C, const char *filename, struct Text *text ); // 2.5 working
+ int BPY_run_script_space_draw(struct bContext *C, struct SpaceScript * sc); // 2.5 working
void BPY_run_ui_scripts(struct bContext *C, int reload);
// int BPY_run_script_space_listener(struct bContext *C, struct SpaceScript * sc, struct ARegion *ar, struct wmNotifier *wmn); // 2.5 working
void BPY_update_modules( void ); // XXX - annoying, need this for pointers that get out of date
diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c
new file mode 100644
index 00000000000..b67f1e717da
--- /dev/null
+++ b/source/blender/python/BPY_menus.c
@@ -0,0 +1,1118 @@
+/*
+ * $Id: BPY_menus.c 12932 2007-12-17 20:21:06Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Michael Reimpell
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/*
+ *This is the main file responsible for having bpython scripts accessible
+ * from Blender menus. To know more, please start with its header file.
+ */
+
+#include "BPY_menus.h"
+
+#include <Python.h>
+#ifndef WIN32
+ #include <dirent.h>
+#else
+ #include "BLI_winstuff.h"
+#endif
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+#include "DNA_userdef_types.h" /* for U.pythondir */
+#include "api2_2x/EXPP_interface.h" /* for bpy_gethome() */
+
+#define BPYMENU_DATAFILE "Bpymenus"
+#define MAX_DIR_DEPTH 4 /* max depth for traversing scripts dirs */
+#define MAX_DIR_NUMBER 30 /* max number of dirs in scripts dirs trees */
+
+static int DEBUG;
+static int Dir_Depth;
+static int Dirs_Number;
+
+/* BPyMenuTable holds all registered pymenus, as linked lists for each menu
+ * where they can appear (see PYMENUHOOKS enum in BPY_menus.h).
+*/
+BPyMenu *BPyMenuTable[PYMENU_TOTAL];
+
+static int bpymenu_group_atoi( char *str )
+{
+ if( !strcmp( str, "Export" ) )
+ return PYMENU_EXPORT;
+ else if( !strcmp( str, "Import" ) )
+ return PYMENU_IMPORT;
+ else if( !strcmp( str, "Help" ) )
+ return PYMENU_HELP;
+ else if( !strcmp( str, "HelpWebsites" ) )
+ return PYMENU_HELPWEBSITES;
+ else if( !strcmp( str, "HelpSystem" ) )
+ return PYMENU_HELPSYSTEM;
+ else if( !strcmp( str, "Render" ) )
+ return PYMENU_RENDER;
+ else if( !strcmp( str, "System" ) )
+ return PYMENU_SYSTEM;
+ else if( !strcmp( str, "Object" ) )
+ return PYMENU_OBJECT;
+ else if( !strcmp( str, "Mesh" ) )
+ return PYMENU_MESH;
+ else if( !strncmp( str, "Theme", 5 ) )
+ return PYMENU_THEMES;
+ else if( !strcmp( str, "Add" ) )
+ return PYMENU_ADD;
+ else if( !strcmp( str, "Wizards" ) )
+ return PYMENU_WIZARDS;
+ else if( !strcmp( str, "Animation" ) )
+ return PYMENU_ANIMATION;
+ else if( !strcmp( str, "Materials" ) )
+ return PYMENU_MATERIALS;
+ else if( !strcmp( str, "UV" ) )
+ return PYMENU_UV;
+ else if( !strcmp( str, "Image" ) )
+ return PYMENU_IMAGE;
+ else if( !strcmp( str, "FaceSelect" ) )
+ return PYMENU_FACESELECT;
+ else if( !strcmp( str, "WeightPaint" ) )
+ return PYMENU_WEIGHTPAINT;
+ else if( !strcmp( str, "VertexPaint" ) )
+ return PYMENU_VERTEXPAINT;
+ else if( !strcmp( str, "UVCalculation" ) )
+ return PYMENU_UVCALCULATION;
+ else if( !strcmp( str, "Armature" ) )
+ return PYMENU_ARMATURE;
+ else if( !strcmp( str, "ScriptTemplate" ) )
+ return PYMENU_SCRIPTTEMPLATE;
+ else if( !strcmp( str, "MeshFaceKey" ) )
+ return PYMENU_MESHFACEKEY;
+ else if( !strcmp( str, "AddMesh" ) )
+ return PYMENU_ADDMESH;
+ /* "Misc" or an inexistent group name: use misc */
+ else
+ return PYMENU_MISC;
+}
+
+char *BPyMenu_group_itoa( short menugroup )
+{
+ switch ( menugroup ) {
+ case PYMENU_EXPORT:
+ return "Export";
+ break;
+ case PYMENU_IMPORT:
+ return "Import";
+ break;
+ case PYMENU_ADD:
+ return "Add";
+ break;
+ case PYMENU_HELP:
+ return "Help";
+ break;
+ case PYMENU_HELPWEBSITES:
+ return "HelpWebsites";
+ break;
+ case PYMENU_HELPSYSTEM:
+ return "HelpSystem";
+ break;
+ case PYMENU_RENDER:
+ return "Render";
+ break;
+ case PYMENU_SYSTEM:
+ return "System";
+ break;
+ case PYMENU_OBJECT:
+ return "Object";
+ break;
+ case PYMENU_MESH:
+ return "Mesh";
+ break;
+ case PYMENU_THEMES:
+ return "Themes";
+ break;
+ case PYMENU_WIZARDS:
+ return "Wizards";
+ break;
+ case PYMENU_ANIMATION:
+ return "Animation";
+ break;
+ case PYMENU_MATERIALS:
+ return "Materials";
+ break;
+ case PYMENU_UV:
+ return "UV";
+ break;
+ case PYMENU_IMAGE:
+ return "Image";
+ break;
+ case PYMENU_FACESELECT:
+ return "FaceSelect";
+ break;
+ case PYMENU_WEIGHTPAINT:
+ return "WeightPaint";
+ break;
+ case PYMENU_VERTEXPAINT:
+ return "VertexPaint";
+ break;
+ case PYMENU_UVCALCULATION:
+ return "UVCalculation";
+ break;
+ case PYMENU_ARMATURE:
+ return "Armature";
+ break;
+ case PYMENU_SCRIPTTEMPLATE:
+ return "ScriptTemplate";
+ break;
+ case PYMENU_MESHFACEKEY:
+ return "MeshFaceKey";
+ break;
+ case PYMENU_ADDMESH:
+ return "AddMesh";
+ break;
+ case PYMENU_MISC:
+ return "Misc";
+ break;
+ }
+ return NULL;
+}
+
+/* BPyMenu_CreatePupmenuStr:
+ * build and return a meaninful string to be used by pupmenu(). The
+ * string is made of a bpymenu name as title and its submenus as possible
+ * choices for the user.
+*/
+char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short menugroup )
+{
+ BPySubMenu *pysm = pym->submenus;
+ char str[1024], str2[100];
+ int i = 0, rlen;
+
+ if( !pym || !pysm )
+ return NULL;
+
+ str[0] = '\0';
+
+ PyOS_snprintf( str2, sizeof( str2 ), "%s: %s%%t",
+ BPyMenu_group_itoa( menugroup ), pym->name );
+ strcat( str, str2 );
+
+ while( pysm ) {
+ PyOS_snprintf( str2, sizeof( str2 ), "|%s%%x%d", pysm->name,
+ i );
+ rlen = sizeof( str ) - strlen( str );
+ strncat( str, str2, rlen );
+ i++;
+ pysm = pysm->next;
+ }
+
+ return BLI_strdup( str );
+}
+
+static void bpymenu_RemoveAllSubEntries( BPySubMenu * smenu )
+{
+ BPySubMenu *tmp;
+
+ while( smenu ) {
+ tmp = smenu->next;
+ if( smenu->name )
+ MEM_freeN( smenu->name );
+ if( smenu->arg )
+ MEM_freeN( smenu->arg );
+ MEM_freeN( smenu );
+ smenu = tmp;
+ }
+ return;
+}
+
+void BPyMenu_RemoveAllEntries( void )
+{
+ BPyMenu *tmp, *pymenu;
+ int i;
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ while( pymenu ) {
+ tmp = pymenu->next;
+ if( pymenu->name )
+ MEM_freeN( pymenu->name );
+ if( pymenu->filename )
+ MEM_freeN( pymenu->filename );
+ if( pymenu->tooltip )
+ MEM_freeN( pymenu->tooltip );
+ if( pymenu->submenus )
+ bpymenu_RemoveAllSubEntries( pymenu->
+ submenus );
+ MEM_freeN( pymenu );
+ pymenu = tmp;
+ }
+ BPyMenuTable[i] = NULL;
+ }
+
+ Dirs_Number = 0;
+ Dir_Depth = 0;
+
+ return;
+}
+
+static BPyMenu *bpymenu_FindEntry( short group, char *name )
+{
+ BPyMenu *pymenu;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+
+ pymenu = BPyMenuTable[group];
+
+ while( pymenu ) {
+ if( !strcmp( pymenu->name, name ) )
+ return pymenu;
+ pymenu = pymenu->next;
+ }
+
+ return NULL;
+}
+
+/* BPyMenu_GetEntry:
+ * given a group and a position, return the entry in that position from
+ * that group.
+*/
+BPyMenu *BPyMenu_GetEntry( short group, short pos )
+{
+ BPyMenu *pym = NULL;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+
+ pym = BPyMenuTable[group];
+
+ while( pos-- ) {
+ if( pym )
+ pym = pym->next;
+ else
+ break;
+ }
+
+ return pym; /* found entry or NULL */
+}
+
+static void bpymenu_set_tooltip( BPyMenu * pymenu, char *tip )
+{
+ if( !pymenu )
+ return;
+
+ if( pymenu->tooltip )
+ MEM_freeN( pymenu->tooltip );
+ pymenu->tooltip = BLI_strdup( tip );
+
+ return;
+}
+
+/* bpymenu_AddEntry:
+ * try to find an existing pymenu entry with the given type and name;
+ * if found, update it with new info, otherwise create a new one and fill it.
+ */
+static BPyMenu *bpymenu_AddEntry( short group, short version, char *name,
+ char *fname, int is_userdir, char *tooltip )
+{
+ BPyMenu *menu, *next = NULL, **iter;
+ int nameclash = 0;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+ if( !name || !fname )
+ return NULL;
+
+ menu = bpymenu_FindEntry( group, name ); /* already exists? */
+
+ /* if a menu with this name already exists in the same group:
+ * - if one script is in the default dir and the other in U.pythondir,
+ * accept and let the new one override the other.
+ * - otherwise, report the error and return NULL. */
+ if( menu ) {
+ if( menu->dir < is_userdir ) { /* new one is in U.pythondir */
+ nameclash = 1;
+ if( menu->name )
+ MEM_freeN( menu->name );
+ if( menu->filename )
+ MEM_freeN( menu->filename );
+ if( menu->tooltip )
+ MEM_freeN( menu->tooltip );
+ if( menu->submenus )
+ bpymenu_RemoveAllSubEntries( menu->submenus );
+ next = menu->next;
+ } else { /* they are in the same dir */
+ if (DEBUG) {
+ fprintf(stderr, "\n\
+Warning: script %s's menu name is already in use.\n\
+Edit the script and change its \n\
+Name: '%s'\n\
+field, please.\n\
+Note: if you really want to have two scripts for the same menu with\n\
+the same name, keep one in the default dir and the other in\n\
+the user defined dir (only the later will be registered).\n", fname, name);
+ }
+ return NULL;
+ }
+ } else
+ menu = MEM_mallocN( sizeof( BPyMenu ), "pymenu" );
+
+ if( !menu )
+ return NULL;
+
+ menu->name = BLI_strdup( name );
+ menu->version = version;
+ menu->filename = BLI_strdup( fname );
+ menu->tooltip = NULL;
+ if( tooltip )
+ menu->tooltip = BLI_strdup( tooltip );
+ menu->dir = is_userdir;
+ menu->submenus = NULL;
+ menu->next = next; /* non-NULL if menu already existed */
+
+ if( nameclash )
+ return menu; /* no need to place it, it's already at the list */
+ else { /* insert the new entry in its correct position at the table */
+ BPyMenu *prev = NULL;
+ char *s = NULL;
+
+ iter = &BPyMenuTable[group];
+ while( *iter ) {
+ s = ( *iter )->name;
+ if( s )
+ if( strcmp( menu->name, s ) < 0 )
+ break; /* sort by names */
+ prev = *iter;
+ iter = &( ( *iter )->next );
+ }
+
+ if( *iter ) { /* prepend */
+ menu->next = *iter;
+ if( prev )
+ prev->next = menu;
+ else
+ BPyMenuTable[group] = menu; /* is first entry */
+ } else
+ *iter = menu; /* append */
+ }
+
+ return menu;
+}
+
+/* bpymenu_AddSubEntry:
+ * add a submenu to an existing python menu.
+ */
+static int bpymenu_AddSubEntry( BPyMenu * mentry, char *name, char *arg )
+{
+ BPySubMenu *smenu, **iter;
+
+ smenu = MEM_mallocN( sizeof( BPySubMenu ), "pysubmenu" );
+ if( !smenu )
+ return -1;
+
+ smenu->name = BLI_strdup( name );
+ smenu->arg = BLI_strdup( arg );
+ smenu->next = NULL;
+
+ if( !smenu->name || !smenu->arg )
+ return -1;
+
+ iter = &( mentry->submenus );
+ while( *iter )
+ iter = &( ( *iter )->next );
+
+ *iter = smenu;
+
+ return 0;
+}
+
+/* bpymenu_CreateFromFile:
+ * parse the bpymenus data file where Python menu data is stored;
+ * based on this data, create and fill the pymenu structs.
+ */
+static int bpymenu_CreateFromFile( void )
+{
+ FILE *fp;
+ char line[255], w1[255], w2[255], tooltip[255], *tip;
+ char *homedir = NULL;
+ int parsing, version, is_userdir;
+ short group;
+ BPyMenu *pymenu = NULL;
+
+ /* init global bpymenu table (it is a list of pointers to struct BPyMenus
+ * for each available cathegory: import, export, etc.) */
+ for( group = 0; group < PYMENU_TOTAL; group++ )
+ BPyMenuTable[group] = NULL;
+
+ /* let's try to open the file with bpymenu data */
+ homedir = bpy_gethome(0);
+ if (!homedir) {
+ if( DEBUG )
+ fprintf(stderr,
+ "BPyMenus error: couldn't open config file Bpymenus: no home dir.\n");
+ return -1;
+ }
+
+ BLI_make_file_string( "/", line, homedir, BPYMENU_DATAFILE );
+
+ fp = fopen( line, "rb" );
+
+ if( !fp ) {
+ if( DEBUG )
+ fprintf(stderr, "BPyMenus error: couldn't open config file %s.\n", line );
+ return -1;
+ }
+
+ fgets( line, 255, fp ); /* header */
+
+ /* check if the U.pythondir we saved at the file is different from the
+ * current one. If so, return to force updating from dirs */
+ w1[0] = '\0';
+ fscanf( fp, "# User defined scripts dir: %[^\n]\n", w1 );
+ if( w1 ) {
+ char upythondir[FILE_MAXDIR];
+
+ BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ if( strcmp( w1, upythondir ) != 0 )
+ return -1;
+ w1[0] = '\0';
+ }
+
+ while( fgets( line, 255, fp ) ) { /* parsing file lines */
+
+ switch ( line[0] ) { /* check first char */
+ case '#': /* comment */
+ continue;
+ break;
+ case '\n':
+ continue;
+ break;
+ default:
+ parsing = sscanf( line, "%s {\n", w1 ); /* menu group */
+ break;
+ }
+
+ if( parsing == 1 ) { /* got menu group string */
+ group = (short)bpymenu_group_atoi( w1 );
+ if( group < 0 && DEBUG ) { /* invalid type */
+ fprintf(stderr,
+ "BPyMenus error parsing config file: wrong group: %s,\n\
+will use 'Misc'.\n", w1 );
+ }
+ } else
+ continue;
+
+ for(;;) {
+ tip = NULL; /* optional tooltip */
+ fgets( line, 255, fp );
+ if( line[0] == '}' )
+ break;
+ else if( line[0] == '\n' )
+ continue;
+ else if( line[0] == '\'' ) { /* menu entry */
+ parsing =
+ sscanf( line,
+ "'%[^']' %d %s %d '%[^']'\n",
+ w1, &version, w2, &is_userdir,
+ tooltip );
+
+ if( parsing <= 0 ) { /* invalid line, get rid of it */
+ fgets( line, 255, fp );
+ } else if( parsing == 5 )
+ tip = tooltip; /* has tooltip */
+
+ pymenu = bpymenu_AddEntry( group,
+ ( short ) version,
+ w1, w2, is_userdir,
+ tip );
+ if( !pymenu ) {
+ puts( "BPyMenus error: couldn't create bpymenu entry.\n" );
+ fclose( fp );
+ return -1;
+ }
+ } else if( line[0] == '|' && line[1] == '_' ) { /* menu sub-entry */
+ if( !pymenu )
+ continue; /* no menu yet, skip this line */
+ sscanf( line, "|_%[^:]: %s\n", w1, w2 );
+ bpymenu_AddSubEntry( pymenu, w1, w2 );
+ }
+ }
+ }
+
+ fclose( fp );
+ return 0;
+}
+
+/* bpymenu_WriteDataFile:
+ * writes the registered scripts info to the user's home dir, for faster
+ * access when the scripts dir hasn't changed.
+*/
+static void bpymenu_WriteDataFile( void )
+{
+ BPyMenu *pymenu;
+ BPySubMenu *smenu;
+ FILE *fp;
+ char fname[FILE_MAXDIR], *homedir;
+ int i;
+
+ homedir = bpy_gethome(0);
+
+ if (!homedir) {
+ if( DEBUG )
+ fprintf(stderr,
+ "BPyMenus error: couldn't write Bpymenus file: no home dir.\n\n");
+ return;
+ }
+
+ BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE );
+
+ fp = fopen( fname, "w" );
+ if( !fp ) {
+ if( DEBUG )
+ fprintf(stderr, "BPyMenus error: couldn't write %s file.\n\n",
+ fname );
+ return;
+ }
+
+ fprintf( fp,
+ "# Blender: registered menu entries for bpython scripts\n" );
+
+ if (U.pythondir[0] != '\0' &&
+ strcmp(U.pythondir, "/") != 0 && strcmp(U.pythondir, "//") != 0)
+ {
+ char upythondir[FILE_MAXDIR];
+
+ BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ fprintf( fp, "# User defined scripts dir: %s\n", upythondir );
+ }
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ if( !pymenu )
+ continue;
+ fprintf( fp, "\n%s {\n", BPyMenu_group_itoa( (short)i ) );
+ while( pymenu ) {
+ fprintf( fp, "'%s' %d %s %d", pymenu->name,
+ pymenu->version, pymenu->filename,
+ pymenu->dir );
+ if( pymenu->tooltip )
+ fprintf( fp, " '%s'\n", pymenu->tooltip );
+ else
+ fprintf( fp, "\n" );
+ smenu = pymenu->submenus;
+ while( smenu ) {
+ fprintf( fp, "|_%s: %s\n", smenu->name,
+ smenu->arg );
+ smenu = smenu->next;
+ }
+ pymenu = pymenu->next;
+ }
+ fprintf( fp, "}\n" );
+ }
+
+ fclose( fp );
+ return;
+}
+
+/* BPyMenu_PrintAllEntries:
+ * useful for debugging.
+ */
+void BPyMenu_PrintAllEntries( void )
+{
+ BPyMenu *pymenu;
+ BPySubMenu *smenu;
+ int i;
+
+ printf( "# Blender: registered menu entries for bpython scripts\n" );
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ printf( "\n%s {\n", BPyMenu_group_itoa( (short)i ) );
+ while( pymenu ) {
+ printf( "'%s' %d %s %d", pymenu->name, pymenu->version,
+ pymenu->filename, pymenu->dir );
+ if( pymenu->tooltip )
+ printf( " '%s'\n", pymenu->tooltip );
+ else
+ printf( "\n" );
+ smenu = pymenu->submenus;
+ while( smenu ) {
+ printf( "|_%s: %s\n", smenu->name,
+ smenu->arg );
+ smenu = smenu->next;
+ }
+ pymenu = pymenu->next;
+ }
+ printf( "}\n" );
+ }
+}
+
+/* bpymenu_ParseFile:
+ * recursively scans folders looking for scripts to register.
+ *
+ * This function scans the scripts directory looking for .py files with the
+ * right header and menu info, using that to fill the bpymenu structs.
+ * is_userdir defines if the script is in the default scripts dir or the
+ * user defined one (U.pythondir: is_userdir == 1).
+ * Speed is important.
+ *
+ * The first line of the script must be '#!BPY'.
+ * The header registration lines must appear between the first pair of
+ * '\"\"\"' and follow this order (the single-quotes are part of
+ * the format):
+ *
+ * # \"\"\"<br>
+ * # Name: 'script name for the menu'
+ * # Blender: <code>short int</code> (minimal Blender version)
+ * # Group: 'group name' (defines menu)
+ * # Submenu: 'submenu name' related_1word_arg
+ * # Tooltip: 'tooltip for the menu'
+ * # \"\"\"
+ *
+ * Notes:
+ *
+ * - Commenting out header lines with "#" is optional, but recommended.
+ * - There may be more than one submenu line, or none:
+ * submenus and the tooltip are optional;
+ * - The Blender version is the same number reported by
+ * Blender.Get('version') in BPython or G.version in C;
+ * - Line length must be less than 99.
+ */
+static int bpymenu_ParseFile(FILE *file, char *fname, int is_userdir)
+{
+ char line[100];
+ char head[100];
+ char middle[100];
+ char tail[100];
+ int matches;
+ int parser_state;
+
+ char script_name[100];
+ int script_version = 1;
+ int script_group;
+
+ BPyMenu *scriptMenu = NULL;
+
+ if (file != NULL) {
+ parser_state = 1; /* state of parser, 0 to terminate */
+
+ while ((parser_state != 0) && (fgets(line, 100, file) != NULL)) {
+
+ switch (parser_state) {
+
+ case 1: /* !BPY */
+ if (strncmp(line, "#!BPY", 5) == 0) {
+ parser_state++;
+ } else {
+ parser_state = 0;
+ }
+ break;
+
+ case 2: /* \"\"\" */
+ if ((strstr(line, "\"\"\""))) {
+ parser_state++;
+ }
+ break;
+
+ case 3: /* Name: 'script name for the menu' */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, script_name, tail);
+ if ((matches == 3) && (strstr(head, "Name:") != NULL)) {
+ parser_state++;
+ } else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Wrong 'Name' line: %s\n", fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 4: /* Blender: <short int> */
+ matches = sscanf(line, "%[^1234567890]%i%c", head, &script_version,
+ tail);
+ if (matches == 3) {
+ parser_state++;
+ } else {
+ if (DEBUG)
+ fprintf(stderr,"BPyMenus error: Wrong 'Blender' line: %s\n",fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 5: /* Group: 'group name' */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
+ if ((matches == 3) && (strstr(head, "Group:") != NULL)) {
+ script_group = bpymenu_group_atoi(middle);
+ if (script_group < 0) {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Unknown group \"%s\": %s\n",
+ middle, fname);
+ parser_state = 0;
+ }
+
+ else { /* register script */
+ scriptMenu = bpymenu_AddEntry((short)script_group,
+ (short int)script_version, script_name, fname, is_userdir,NULL);
+ if (scriptMenu == NULL) {
+ if (DEBUG)
+ fprintf(stderr,
+ "BPyMenus error: Couldn't create entry for: %s\n", fname);
+ parser_state = 0;
+ } else {
+ parser_state++;
+ }
+ }
+
+ } else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Wrong 'Group' line: %s\n",fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 6: /* optional elements */
+ /* Submenu: 'submenu name' related_1word_arg */
+ matches = sscanf(line, "%[^']'%[^']'%s\n", head, middle, tail);
+ if ((matches == 3) && (strstr(head, "Submenu:") != NULL)) {
+ bpymenu_AddSubEntry(scriptMenu, middle, tail);
+ } else {
+ /* Tooltip: 'tooltip for the menu */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
+ if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) ||
+ (strstr(head, "Tip:") != NULL))) {
+ bpymenu_set_tooltip(scriptMenu, middle);
+ }
+ parser_state = 0;
+ }
+ break;
+
+ default:
+ parser_state = 0;
+ break;
+ }
+ }
+ }
+
+ else { /* shouldn't happen, it's checked in bpymenus_ParseDir */
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", fname);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* bpymenu_ParseDir:
+ * recursively scans folders looking for scripts to register.
+ *
+ * This function scans the scripts directory looking for .py files with the
+ * right header and menu info.
+ * - is_userdir defines if the script is in the default scripts dir or the
+ * user defined one (U.pythondir: is_userdir == 1);
+ * - parentdir is the parent dir name to store as part of the script filename,
+ * if we're down a subdir.
+ * Speed is important.
+ */
+static int bpymenu_ParseDir(char *dirname, char *parentdir, int is_userdir )
+{
+ DIR *dir;
+ FILE *file = NULL;
+ struct dirent *de;
+ struct stat status;
+ char *file_extension;
+ char path[FILE_MAX];
+ char subdir[FILE_MAX];
+ char *s = NULL;
+
+ dir = opendir(dirname);
+
+ if (dir != NULL) {
+ while ((de = readdir(dir)) != NULL) {
+
+ /* skip files and dirs starting with '.' or 'bpy' */
+ if ((de->d_name[0] == '.') || !strncmp(de->d_name, "bpy", 3)) {
+ continue;
+ }
+
+ BLI_make_file_string("/", path, dirname, de->d_name);
+
+ if (stat(path, &status) != 0) {
+ if (DEBUG)
+ fprintf(stderr, "stat %s failed: %s\n", path, strerror(errno));
+ }
+
+ if (S_ISREG(status.st_mode)) { /* is file */
+
+ file_extension = strstr(de->d_name, ".py");
+
+ if (file_extension && *(file_extension + 3) == '\0') {
+ file = fopen(path, "rb");
+
+ if (file) {
+ s = de->d_name;
+ if (parentdir) {
+ /* Join parentdir and de->d_name */
+ BLI_join_dirfile(subdir, parentdir, de->d_name);
+
+ s = subdir;
+ }
+ bpymenu_ParseFile(file, s, is_userdir);
+ fclose(file);
+ }
+
+ else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", path);
+ }
+ }
+ }
+
+ else if (S_ISDIR(status.st_mode)) { /* is subdir */
+ Dirs_Number++;
+ Dir_Depth++;
+ if (Dirs_Number > MAX_DIR_NUMBER) {
+ if (DEBUG) {
+ fprintf(stderr, "BPyMenus error: too many subdirs.\n");
+ }
+ closedir(dir);
+ return -1;
+ }
+ else if (Dir_Depth > MAX_DIR_DEPTH) {
+ if (DEBUG)
+ fprintf(stderr,
+ "BPyMenus error: max depth reached traversing dir tree.\n");
+ closedir(dir);
+ return -1;
+ }
+ s = de->d_name;
+ if (parentdir) {
+ /* Join parentdir and de->d_name */
+ BLI_join_dirfile(subdir, parentdir, de->d_name);
+ s = subdir;
+ }
+ if (bpymenu_ParseDir(path, s, is_userdir) == -1) {
+ closedir(dir);
+ return -1;
+ }
+ Dir_Depth--;
+ }
+
+ }
+ closedir(dir);
+ }
+
+ else { /* open directory stream failed */
+ if (DEBUG)
+ fprintf(stderr, "opendir %s failed: %s\n", dirname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bpymenu_GetStatMTime( char *name, int is_file, time_t * mtime )
+{
+ struct stat st;
+ int result;
+
+ result = stat( name, &st );
+
+ if( result == -1 )
+ return -1;
+
+ if( is_file ) {
+ if( !S_ISREG( st.st_mode ) )
+ return -2;
+ } else if( !S_ISDIR( st.st_mode ) )
+ return -2;
+
+ *mtime = st.st_mtime;
+
+ return 0;
+}
+
+/* BPyMenu_Init:
+ * import the bpython menus data to Blender, either from:
+ * - the BPYMENU_DATAFILE file (?/.blender/Bpymenus) or
+ * - the scripts dir(s), case newer than the datafile (then update the file).
+ * then fill the bpymenu table with this data.
+ * if param usedir != 0, then the data is recreated from the dir(s) anyway.
+*/
+int BPyMenu_Init( int usedir )
+{
+ char fname[FILE_MAXDIR];
+ char dirname[FILE_MAXDIR];
+ char upythondir[FILE_MAXDIR];
+ char *upydir = U.pythondir, *sdir = NULL;
+ time_t time_dir1 = 0, time_dir2 = 0, time_file = 0;
+ int stat_dir1 = 0, stat_dir2 = 0, stat_file = 0;
+ int i;
+
+ DEBUG = G.f & G_DEBUG; /* is Blender in debug mode (started with -d) ? */
+
+ /* init global bpymenu table (it is a list of pointers to struct BPyMenus
+ * for each available group: import, export, etc.) */
+ for( i = 0; i < PYMENU_TOTAL; i++ )
+ BPyMenuTable[i] = NULL;
+
+ if( DEBUG )
+ fprintf(stdout, "\nRegistering scripts in Blender menus ...\n\n" );
+
+ if( U.pythondir[0] == '\0') {
+ upydir = NULL;
+ }
+ else if (strcmp(U.pythondir, "/") == 0 || strcmp(U.pythondir, "//") == 0) {
+ /* these are not accepted to prevent possible slight slowdowns on startup;
+ * they should not be used as user defined scripts dir, anyway, also from
+ * speed considerations, since they'd not be dedicated scripts dirs */
+ if (DEBUG) fprintf(stderr,
+ "BPyMenus: invalid user defined Python scripts dir: \"/\" or \"//\".\n");
+ upydir = NULL;
+ }
+ else {
+ BLI_strncpy(upythondir, upydir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ }
+
+ sdir = bpy_gethome(1);
+
+ if (sdir) {
+ BLI_strncpy(dirname, sdir, FILE_MAXDIR);
+ stat_dir1 = bpymenu_GetStatMTime( dirname, 0, &time_dir1 );
+
+ if( stat_dir1 < 0 ) {
+ time_dir1 = 0;
+ if( DEBUG ) {
+ fprintf(stderr,
+ "\nDefault scripts dir: %s:\n%s\n", dirname, strerror(errno));
+ if( upydir )
+ fprintf(stdout,
+ "Getting scripts menu data from user defined dir: %s.\n",
+ upythondir );
+ }
+ }
+ }
+ else stat_dir1 = -1;
+
+ if( upydir ) {
+ stat_dir2 = bpymenu_GetStatMTime( upythondir, 0, &time_dir2 );
+
+ if( stat_dir2 < 0 ) {
+ time_dir2 = 0;
+ upydir = NULL;
+ if( DEBUG )
+ fprintf(stderr, "\nUser defined scripts dir: %s:\n%s.\n",
+ upythondir, strerror( errno ) );
+ if( stat_dir1 < 0 ) {
+ if( DEBUG )
+ fprintf(stderr, "\
+To have scripts in menus, please add them to the default scripts dir:\n\
+%s\n\
+and / or go to 'Info window -> File Paths tab' and set a valid path for\n\
+the user defined Python scripts dir.\n", dirname );
+ return -1;
+ }
+ }
+ }
+ else stat_dir2 = -1;
+
+ if( ( stat_dir1 < 0 ) && ( stat_dir2 < 0 ) ) {
+ if( DEBUG ) {
+ fprintf(stderr, "\nCannot register scripts in menus, no scripts dir"
+ " available.\nExpected default dir at: %s \n", dirname );
+ }
+ return -1;
+ }
+
+ if (usedir) stat_file = -1;
+ else { /* if we're not forced to use the dir */
+ char *homedir = bpy_gethome(0);
+
+ if (homedir) {
+ BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE );
+ stat_file = bpymenu_GetStatMTime( fname, 1, &time_file );
+ if( stat_file < 0 )
+ time_file = 0;
+
+ /* comparing dates */
+
+ if((stat_file == 0)
+ && (time_file > time_dir1) && (time_file > time_dir2))
+ { /* file is newer */
+ stat_file = bpymenu_CreateFromFile( ); /* -1 if an error occurred */
+ if( !stat_file && DEBUG )
+ fprintf(stdout,
+ "Getting menu data for scripts from file:\n%s\n\n", fname );
+ }
+ else stat_file = -1;
+ }
+ else stat_file = -1; /* -1 to use dirs: didn't use file or it was corrupted */
+ }
+
+ if( stat_file == -1 ) { /* use dirs */
+ if( DEBUG ) {
+ fprintf(stdout,
+ "Getting menu data for scripts from dir(s):\ndefault: %s\n", dirname );
+ if( upydir )
+ fprintf(stdout, "user defined: %s\n", upythondir );
+ fprintf(stdout, "\n");
+ }
+ if( stat_dir1 == 0 ) {
+ i = bpymenu_ParseDir( dirname, NULL, 0 );
+ if (i == -1 && DEBUG)
+ fprintf(stderr, "Default scripts dir does not seem valid.\n\n");
+ }
+ if( stat_dir2 == 0 ) {
+ BLI_strncpy(dirname, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(dirname, G.sce, 0);
+ i = bpymenu_ParseDir( dirname, NULL, 1 );
+ if (i == -1 && DEBUG)
+ fprintf(stderr, "User defined scripts dir does not seem valid.\n\n");
+ }
+
+ /* check if we got any data */
+ for( i = 0; i < PYMENU_TOTAL; i++ )
+ if( BPyMenuTable[i] )
+ break;
+
+ /* if we got, recreate the file */
+ if( i < PYMENU_TOTAL )
+ bpymenu_WriteDataFile( );
+ else if( DEBUG ) {
+ fprintf(stderr, "\n\
+Warning: Registering scripts in menus -- no info found.\n\
+Either your scripts dirs have no .py scripts or the scripts\n\
+don't have a header with registration data.\n\
+Default scripts dir is:\n\
+%s\n", dirname );
+ if( upydir )
+ fprintf(stderr, "User defined scripts dir is: %s\n",
+ upythondir );
+ }
+ }
+
+ return 0;
+}
diff --git a/source/blender/python/BPY_menus.h b/source/blender/python/BPY_menus.h
new file mode 100644
index 00000000000..6cdea608b10
--- /dev/null
+++ b/source/blender/python/BPY_menus.h
@@ -0,0 +1,128 @@
+/*
+ * $Id: BPY_menus.h 12931 2007-12-17 18:20:48Z theeth $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Matt Ebb
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef BPY_MENUS_H
+#define BPY_MENUS_H
+
+/* This header exposes BPyMenu related public declarations. The implementation
+ * adds 'dynamic' menus to Blender, letting scripts register themselves in any
+ * of a few pre-defined (trivial to upgrade) places in menus. These places or
+ * slots are called groups here (Import, Export, etc). This is how it works:
+ * - scripts at dirs user pref U.pythondir and .blender/scripts/ are scanned
+ * for registration info.
+ * - this data is also saved to a Bpymenus file at the user's .blender/ dir and
+ * only re-created when the scripts folder gets modified.
+ * - on start-up Blender uses this info to fill a table, which is used to
+ * create the menu entries when they are needed (see header_info.c or
+ * header_script.c, under source/blender/src/, for examples).
+*/
+
+/* These two structs hold py menu/submenu info.
+ * BPyMenu holds a script's name (as should appear in the menu) and filename,
+ * plus an optional list of submenus. Each submenu is related to a string
+ * (arg) that the script can get from the __script__ pydict, to know which
+ * submenu was chosen. */
+
+typedef struct BPySubMenu {
+ char *name;
+ char *arg;
+ struct BPySubMenu *next;
+} BPySubMenu;
+
+typedef struct BPyMenu {
+ char *name;
+ char *filename;
+ char *tooltip;
+ short version; /* Blender version */
+ int dir; /* 0: default, 1: U.pythondir */
+ struct BPySubMenu *submenus;
+ struct BPyMenu *next;
+} BPyMenu;
+
+/* Scripts can be added to only a few pre-defined places in menus, like
+ * File->Import, File->Export, etc. (for speed and better control).
+ * To make a new menu 'slot' available for scripts:
+ * - add an entry to the enum below, before PYMENU_TOTAL, of course;
+ * - update the bpymenu_group_atoi() and BPyMenu_group_itoa() functions in
+ * BPY_menus.c;
+ * - add the necessary code to the header_***.c file in
+ * source/blender/src/, like done in header_info.c for import/export;
+*/
+typedef enum {
+ PYMENU_ADD,/* creates new objects */
+ PYMENU_ANIMATION,
+ PYMENU_EXPORT,
+ PYMENU_IMPORT,
+ PYMENU_MATERIALS,
+ PYMENU_MESH,
+ PYMENU_MISC,
+ PYMENU_OBJECT,
+ PYMENU_RENDER,/* exporters to external renderers */
+ PYMENU_SYSTEM,
+ PYMENU_THEMES,
+ PYMENU_UV,/* UV editing tools, to go in UV/Image editor space, 'UV' menu */
+ PYMENU_IMAGE,/* Image editing tools, to go in UV/Image editor space, 'Image' menu */
+ PYMENU_WIZARDS,/* complex 'app' scripts */
+
+ /* entries put after Wizards don't appear at the Scripts win->Scripts menu;
+ * see define right below */
+
+ PYMENU_FACESELECT,
+ PYMENU_WEIGHTPAINT,
+ PYMENU_VERTEXPAINT,
+ PYMENU_UVCALCULATION,
+ PYMENU_ARMATURE,
+ PYMENU_SCRIPTTEMPLATE,
+ PYMENU_HELP,/*Main Help menu items - prob best to leave for 'official' ones*/
+ PYMENU_HELPSYSTEM,/* Resources, troubleshooting, system tools */
+ PYMENU_HELPWEBSITES,/* Help -> Websites submenu */
+ PYMENU_MESHFACEKEY, /* face key in mesh editmode */
+ PYMENU_ADDMESH, /* adds mesh */
+ PYMENU_TOTAL
+} PYMENUHOOKS;
+
+#define PYMENU_SCRIPTS_MENU_TOTAL (PYMENU_WIZARDS + 1)
+
+/* BPyMenuTable holds all registered pymenus, as linked lists for each menu
+ * where they can appear (see PYMENUHOOKS enum above).
+*/
+extern BPyMenu *BPyMenuTable[]; /* defined in BPY_menus.c */
+
+/* public functions: */
+int BPyMenu_Init( int usedir );
+void BPyMenu_RemoveAllEntries( void );
+void BPyMenu_PrintAllEntries( void );
+char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short group );
+char *BPyMenu_group_itoa( short group );
+struct BPyMenu *BPyMenu_GetEntry( short group, short pos );
+
+#endif /* BPY_MENUS_H */
diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt
index 7700e6bc2aa..d15970e1df4 100644
--- a/source/blender/python/CMakeLists.txt
+++ b/source/blender/python/CMakeLists.txt
@@ -24,12 +24,10 @@
# ***** END GPL LICENSE BLOCK *****
FILE(GLOB SRC intern/*.c)
-FILE(GLOB GENSRC generic/*.c)
SET(INC
. ../../../intern/guardedalloc ../blenlib ../makesdna ../makesrna
../blenkernel ../editors/include ../windowmanager ${PYTHON_INC}
- ../../../extern/glew/include
)
IF(WITH_OPENEXR)
@@ -49,5 +47,3 @@ ENDIF(WITH_FFMPEG)
ADD_DEFINITIONS(-DWITH_CCGSUBSURF)
BLENDERLIB(bf_python "${SRC}" "${INC}")
-BLENDERLIB(bf_gen_python "${GENSRC}" "${INC}")
-
diff --git a/source/blender/python/Makefile b/source/blender/python/Makefile
index 8e2a04b8449..c830fbb3ccf 100644
--- a/source/blender/python/Makefile
+++ b/source/blender/python/Makefile
@@ -1,5 +1,5 @@
#
-# $Id$
+# $Id: Makefile 14444 2008-04-16 22:40:48Z hos $
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -29,6 +29,6 @@
# Bounces make to subdirectories.
SOURCEDIR = source/blender/python
-DIRS = intern generic
+DIRS = intern
include nan_subdirs.mk
diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript
index 73dc171fc3e..9d7fcf6a9cf 100644
--- a/source/blender/python/SConscript
+++ b/source/blender/python/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('intern/*.c')
incs = '. ../editors/include ../makesdna ../makesrna ../blenlib ../blenkernel ../nodes'
incs += ' ../imbuf ../blenloader ../render/extern/include ../windowmanager'
-incs += ' #intern/guardedalloc #intern/memutil #extern/glew/include'
+incs += ' #intern/guardedalloc #intern/memutil'
incs += ' ' + env['BF_PYTHON_INC']
defs = []
@@ -15,7 +15,3 @@ if env['OURPLATFORM'] in ('win32-mingw', 'win32-vc') and env['BF_DEBUG']:
env.BlenderLib( libname = 'bf_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core'], priority = [140])
-
-# generic
-sources = env.Glob('generic/*.c')
-env.BlenderLib( libname = 'bf_gen_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core'], priority = [361]) # ketsji is 360
diff --git a/source/blender/python/generic/BGL.c b/source/blender/python/generic/BGL.c
deleted file mode 100644
index de82781cf3a..00000000000
--- a/source/blender/python/generic/BGL.c
+++ /dev/null
@@ -1,1610 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Willian P. Germano
- *
- * ***** END GPL LICENSE BLOCK *****
-*/
-
-/* This file is the Blender.BGL part of opy_draw.c, from the old
- * bpython/intern dir, with minor changes to adapt it to the new Python
- * implementation. The BGL submodule "wraps" OpenGL functions and constants,
- * allowing script writers to make OpenGL calls in their Python scripts. */
-
-#include "BGL.h" /*This must come first */
-
-#include "MEM_guardedalloc.h"
-
-static int type_size( int type );
-static Buffer *make_buffer( int type, int ndimensions, int *dimensions );
-
-static char Method_Buffer_doc[] =
- "(type, dimensions, [template]) - Create a new Buffer object\n\n\
-(type) - The format to store data in\n\
-(dimensions) - An int or sequence specifying the dimensions of the buffer\n\
-[template] - A sequence of matching dimensions to the buffer to be created\n\
- which will be used to initialize the Buffer.\n\n\
-If a template is not passed in all fields will be initialized to 0.\n\n\
-The type should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, or GL_DOUBLE.\n\
-If the dimensions are specified as an int a linear buffer will be\n\
-created. If a sequence is passed for the dimensions the buffer\n\
-will have len(sequence) dimensions, where the size for each dimension\n\
-is determined by the value in the sequence at that index.\n\n\
-For example, passing [100, 100] will create a 2 dimensional\n\
-square buffer. Passing [16, 16, 32] will create a 3 dimensional\n\
-buffer which is twice as deep as it is wide or high.";
-
-static PyObject *Method_Buffer( PyObject * self, PyObject * args );
-
-/* Buffer sequence methods */
-
-static int Buffer_len( PyObject * self );
-static PyObject *Buffer_item( PyObject * self, int i );
-static PyObject *Buffer_slice( PyObject * self, int begin, int end );
-static int Buffer_ass_item( PyObject * self, int i, PyObject * v );
-static int Buffer_ass_slice( PyObject * self, int begin, int end,
- PyObject * seq );
-
-static PySequenceMethods Buffer_SeqMethods = {
- ( inquiry ) Buffer_len, /*sq_length */
- ( binaryfunc ) 0, /*sq_concat */
- ( ssizeargfunc ) 0, /*sq_repeat */
- ( ssizeargfunc ) Buffer_item, /*sq_item */
- ( ssizessizeargfunc ) Buffer_slice, /*sq_slice */
- ( ssizeobjargproc ) Buffer_ass_item, /*sq_ass_item */
- ( ssizessizeobjargproc ) Buffer_ass_slice, /*sq_ass_slice */
-};
-
-static void Buffer_dealloc( PyObject * self );
-static PyObject *Buffer_tolist( PyObject * self );
-static PyObject *Buffer_dimensions( PyObject * self );
-static PyObject *Buffer_getattr( PyObject * self, char *name );
-static PyObject *Buffer_repr( PyObject * self );
-
-PyTypeObject buffer_Type = {
-#if (PY_VERSION_HEX >= 0x02060000)
- PyVarObject_HEAD_INIT(NULL, 0)
-#else
- /* python 2.5 and below */
- PyObject_HEAD_INIT( NULL ) /* required py macro */
- 0, /* ob_size */
-#endif
- "buffer", /*tp_name */
- sizeof( Buffer ), /*tp_basicsize */
- 0, /*tp_itemsize */
- ( destructor ) Buffer_dealloc, /*tp_dealloc */
- ( printfunc ) 0, /*tp_print */
- ( getattrfunc ) Buffer_getattr, /*tp_getattr */
- ( setattrfunc ) 0, /*tp_setattr */
- 0, /*tp_compare */
- ( reprfunc ) Buffer_repr, /*tp_repr */
- 0, /*tp_as_number */
- &Buffer_SeqMethods, /*tp_as_sequence */
-};
-
-/* #ifndef __APPLE__ */
-
-#define BGL_Wrap(nargs, funcname, ret, arg_list) \
-static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
- arg_def##nargs arg_list; \
- ret_def_##ret; \
- if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\
- ret_set_##ret gl##funcname (arg_var##nargs arg_list);\
- ret_ret_##ret; \
-}
-
-#define BGLU_Wrap(nargs, funcname, ret, arg_list) \
-static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
- arg_def##nargs arg_list; \
- ret_def_##ret; \
- if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\
- ret_set_##ret glu##funcname (arg_var##nargs arg_list);\
- ret_ret_##ret; \
-}
-
-/* #endif */
-
-/********/
-static int type_size(int type)
-{
- switch (type) {
- case GL_BYTE:
- return sizeof(char);
- case GL_SHORT:
- return sizeof(short);
- case GL_INT:
- return sizeof(int);
- case GL_FLOAT:
- return sizeof(float);
- case GL_DOUBLE:
- return sizeof(double);
- }
- return -1;
-}
-
-static Buffer *make_buffer(int type, int ndimensions, int *dimensions)
-{
- Buffer *buffer;
- void *buf= NULL;
- int i, size, length;
-
- length= 1;
- for (i=0; i<ndimensions; i++)
- length*= dimensions[i];
-
- size= type_size(type);
-
- buf= MEM_mallocN(length*size, "Buffer buffer");
-
- buffer= (Buffer *) PyObject_NEW(Buffer, &buffer_Type);
- buffer->parent= NULL;
- buffer->ndimensions= ndimensions;
- buffer->dimensions= dimensions;
- buffer->type= type;
- buffer->buf.asvoid= buf;
-
- for (i= 0; i<length; i++) {
- if (type==GL_BYTE)
- buffer->buf.asbyte[i]= 0;
- else if (type==GL_SHORT)
- buffer->buf.asshort[i]= 0;
- else if (type==GL_INT)
- buffer->buf.asint[i]= 0;
- else if (type==GL_FLOAT)
- buffer->buf.asfloat[i]= 0.0f;
- else if (type==GL_DOUBLE)
- buffer->buf.asdouble[i]= 0.0;
- }
- return buffer;
-}
-
-static PyObject *Method_Buffer (PyObject *self, PyObject *args)
-{
- PyObject *length_ob= NULL, *template= NULL;
- Buffer *buffer;
-
- int i, type;
- int *dimensions = 0, ndimensions = 0;
-
- if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &template)) {
- PyErr_SetString(PyExc_AttributeError, "expected an int and one or two PyObjects");
- return NULL;
- }
- if (type!=GL_BYTE && type!=GL_SHORT && type!=GL_INT && type!=GL_FLOAT && type!=GL_DOUBLE) {
- PyErr_SetString(PyExc_AttributeError, "invalid first argument type, should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT or GL_DOUBLE");
- return NULL;
- }
-
- if (PyNumber_Check(length_ob)) {
- ndimensions= 1;
- dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions");
- dimensions[0]= PyLong_AsLong(length_ob);
- } else if (PySequence_Check(length_ob)) {
- ndimensions= PySequence_Length(length_ob);
- dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions");
- for (i=0; i<ndimensions; i++) {
- PyObject *ob= PySequence_GetItem(length_ob, i);
-
- if (!PyNumber_Check(ob)) dimensions[i]= 1;
- else dimensions[i]= PyLong_AsLong(ob);
- Py_DECREF(ob);
- }
- }
-
- buffer= make_buffer(type, ndimensions, dimensions);
- if (template && ndimensions) {
- if (Buffer_ass_slice((PyObject *) buffer, 0, dimensions[0], template)) {
- Py_DECREF(buffer);
- return NULL;
- }
- }
-
- return (PyObject *) buffer;
-}
-
-/*@ Buffer sequence methods */
-
-static int Buffer_len(PyObject *self)
-{
- Buffer *buf= (Buffer *) self;
- return buf->dimensions[0];
-}
-
-static PyObject *Buffer_item(PyObject *self, int i)
-{
- Buffer *buf= (Buffer *) self;
-
- if (i >= buf->dimensions[0]) {
- PyErr_SetString(PyExc_IndexError, "array index out of range");
- return NULL;
- }
-
- if (buf->ndimensions==1) {
- switch (buf->type) {
- case GL_BYTE: return Py_BuildValue("b", buf->buf.asbyte[i]);
- case GL_SHORT: return Py_BuildValue("h", buf->buf.asshort[i]);
- case GL_INT: return Py_BuildValue("i", buf->buf.asint[i]);
- case GL_FLOAT: return PyFloat_FromDouble(buf->buf.asfloat[i]);
- case GL_DOUBLE: return Py_BuildValue("d", buf->buf.asdouble[i]);
- }
- } else {
- Buffer *newbuf;
- int j, length, size;
-
- length= 1;
- for (j=1; j<buf->ndimensions; j++) {
- length*= buf->dimensions[j];
- }
- size= type_size(buf->type);
-
- newbuf= (Buffer *) PyObject_NEW(Buffer, &buffer_Type);
-
- Py_INCREF(self);
- newbuf->parent= self;
-
- newbuf->ndimensions= buf->ndimensions-1;
- newbuf->type= buf->type;
- newbuf->buf.asvoid= buf->buf.asbyte + i*length*size;
- newbuf->dimensions= MEM_mallocN(newbuf->ndimensions*sizeof(int),
- "Buffer dimensions");
- memcpy(newbuf->dimensions, buf->dimensions+1,
- newbuf->ndimensions*sizeof(int));
-
- return (PyObject *) newbuf;
- }
-
- return NULL;
-}
-
-static PyObject *Buffer_slice(PyObject *self, int begin, int end)
-{
- Buffer *buf= (Buffer *) self;
- PyObject *list;
- int count;
-
- if (begin<0) begin= 0;
- if (end>buf->dimensions[0])
- end= buf->dimensions[0];
- if (begin>end) begin= end;
-
- list= PyList_New(end-begin);
-
- for (count= begin; count<end; count++)
- PyList_SetItem(list, count-begin, Buffer_item(self, count));
-
- return list;
-}
-
-static int Buffer_ass_item(PyObject *self, int i, PyObject *v)
-{
- Buffer *buf= (Buffer *) self;
-
- if (i >= buf->dimensions[0]) {
- PyErr_SetString(PyExc_IndexError, "array assignment index out of range");
- return -1;
- }
-
- if (buf->ndimensions!=1) {
- PyObject *row= Buffer_item(self, i);
- int ret;
-
- if (!row) return -1;
- ret= Buffer_ass_slice(row, 0, buf->dimensions[1], v);
- Py_DECREF(row);
- return ret;
- }
-
- if (buf->type==GL_BYTE) {
- if (!PyArg_Parse(v, "b;Coordinates must be ints", &buf->buf.asbyte[i]))
- return -1;
- } else if (buf->type==GL_SHORT) {
- if (!PyArg_Parse(v, "h;Coordinates must be ints", &buf->buf.asshort[i]))
- return -1;
-
- } else if (buf->type==GL_INT) {
- if (!PyArg_Parse(v, "i;Coordinates must be ints", &buf->buf.asint[i]))
- return -1;
- } else if (buf->type==GL_FLOAT) {
- if (!PyArg_Parse(v, "f;Coordinates must be floats", &buf->buf.asfloat[i]))
- return -1;
- } else if (buf->type==GL_DOUBLE) {
- if (!PyArg_Parse(v, "d;Coordinates must be floats", &buf->buf.asdouble[i]))
- return -1;
- }
- return 0;
-}
-
-static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq)
-{
- Buffer *buf= (Buffer *) self;
- PyObject *item;
- int count, err=0;
-
- if (begin<0) begin= 0;
- if (end>buf->dimensions[0]) end= buf->dimensions[0];
- if (begin>end) begin= end;
-
- if (!PySequence_Check(seq)) {
- PyErr_SetString(PyExc_TypeError,
- "illegal argument type for built-in operation");
- return -1;
- }
-
- if (PySequence_Length(seq)!=(end-begin)) {
- PyErr_SetString(PyExc_TypeError, "size mismatch in assignment");
- return -1;
- }
-
- for (count= begin; count<end; count++) {
- item= PySequence_GetItem(seq, count-begin);
- err= Buffer_ass_item(self, count, item);
- Py_DECREF(item);
- if (err) break;
- }
- return err;
-}
-
-static void Buffer_dealloc(PyObject *self)
-{
- Buffer *buf = (Buffer *)self;
-
- if (buf->parent) Py_DECREF (buf->parent);
- else MEM_freeN (buf->buf.asvoid);
-
- MEM_freeN (buf->dimensions);
-
- PyObject_DEL (self);
-}
-
-static PyObject *Buffer_tolist(PyObject *self)
-{
- int i, len= ((Buffer *)self)->dimensions[0];
- PyObject *list= PyList_New(len);
-
- for (i=0; i<len; i++) {
- PyList_SetItem(list, i, Buffer_item(self, i));
- }
-
- return list;
-}
-
-static PyObject *Buffer_dimensions(PyObject *self)
-{
- Buffer *buffer= (Buffer *) self;
- PyObject *list= PyList_New(buffer->ndimensions);
- int i;
-
- for (i= 0; i<buffer->ndimensions; i++) {
- PyList_SetItem(list, i, PyLong_FromLong(buffer->dimensions[i]));
- }
-
- return list;
-}
-
-static PyObject *Buffer_getattr(PyObject *self, char *name)
-{
- if (strcmp(name, "list")==0) return Buffer_tolist(self);
- else if (strcmp(name, "dimensions")==0) return Buffer_dimensions(self);
-
- PyErr_SetString(PyExc_AttributeError, name);
- return NULL;
-}
-
-static PyObject *Buffer_repr(PyObject *self)
-{
- PyObject *list= Buffer_tolist(self);
- PyObject *repr= PyObject_Repr(list);
- Py_DECREF(list);
-
- return repr;
-}
-
-
-BGL_Wrap(2, Accum, void, (GLenum, GLfloat))
-BGL_Wrap(2, AlphaFunc, void, (GLenum, GLclampf))
-BGL_Wrap(3, AreTexturesResident, GLboolean, (GLsizei, GLuintP, GLbooleanP))
-BGL_Wrap(1, Begin, void, (GLenum))
-BGL_Wrap(2, BindTexture, void, (GLenum, GLuint))
-BGL_Wrap(7, Bitmap, void, (GLsizei, GLsizei, GLfloat,
- GLfloat, GLfloat, GLfloat, GLubyteP))
-BGL_Wrap(2, BlendFunc, void, (GLenum, GLenum))
-BGL_Wrap(1, CallList, void, (GLuint))
-BGL_Wrap(3, CallLists, void, (GLsizei, GLenum, GLvoidP))
-BGL_Wrap(1, Clear, void, (GLbitfield))
-BGL_Wrap(4, ClearAccum, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(4, ClearColor, void, (GLclampf, GLclampf, GLclampf, GLclampf))
-BGL_Wrap(1, ClearDepth, void, (GLclampd))
-BGL_Wrap(1, ClearIndex, void, (GLfloat))
-BGL_Wrap(1, ClearStencil, void, (GLint))
-BGL_Wrap(2, ClipPlane, void, (GLenum, GLdoubleP))
-BGL_Wrap(3, Color3b, void, (GLbyte, GLbyte, GLbyte))
-BGL_Wrap(1, Color3bv, void, (GLbyteP))
-BGL_Wrap(3, Color3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, Color3dv, void, (GLdoubleP))
-BGL_Wrap(3, Color3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, Color3fv, void, (GLfloatP))
-BGL_Wrap(3, Color3i, void, (GLint, GLint, GLint))
-BGL_Wrap(1, Color3iv, void, (GLintP))
-BGL_Wrap(3, Color3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(1, Color3sv, void, (GLshortP))
-BGL_Wrap(3, Color3ub, void, (GLubyte, GLubyte, GLubyte))
-BGL_Wrap(1, Color3ubv, void, (GLubyteP))
-BGL_Wrap(3, Color3ui, void, (GLuint, GLuint, GLuint))
-BGL_Wrap(1, Color3uiv, void, (GLuintP))
-BGL_Wrap(3, Color3us, void, (GLushort, GLushort, GLushort))
-BGL_Wrap(1, Color3usv, void, (GLushortP))
-BGL_Wrap(4, Color4b, void, (GLbyte, GLbyte, GLbyte, GLbyte))
-BGL_Wrap(1, Color4bv, void, (GLbyteP))
-BGL_Wrap(4, Color4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, Color4dv, void, (GLdoubleP))
-BGL_Wrap(4, Color4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, Color4fv, void, (GLfloatP))
-BGL_Wrap(4, Color4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(1, Color4iv, void, (GLintP))
-BGL_Wrap(4, Color4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(1, Color4sv, void, (GLshortP))
-BGL_Wrap(4, Color4ub, void, (GLubyte, GLubyte, GLubyte, GLubyte))
-BGL_Wrap(1, Color4ubv, void, (GLubyteP))
-BGL_Wrap(4, Color4ui, void, (GLuint, GLuint, GLuint, GLuint))
-BGL_Wrap(1, Color4uiv, void, (GLuintP))
-BGL_Wrap(4, Color4us, void, (GLushort, GLushort, GLushort, GLushort))
-BGL_Wrap(1, Color4usv, void, (GLushortP))
-BGL_Wrap(4, ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean))
-BGL_Wrap(2, ColorMaterial, void, (GLenum, GLenum))
-BGL_Wrap(5, CopyPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum))
-BGL_Wrap(1, CullFace, void, (GLenum))
-BGL_Wrap(2, DeleteLists, void, (GLuint, GLsizei))
-BGL_Wrap(2, DeleteTextures, void, (GLsizei, GLuintP))
-BGL_Wrap(1, DepthFunc, void, (GLenum))
-BGL_Wrap(1, DepthMask, void, (GLboolean))
-BGL_Wrap(2, DepthRange, void, (GLclampd, GLclampd))
-BGL_Wrap(1, Disable, void, (GLenum))
-BGL_Wrap(1, DrawBuffer, void, (GLenum))
-BGL_Wrap(5, DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP))
-BGL_Wrap(1, EdgeFlag, void, (GLboolean))
-BGL_Wrap(1, EdgeFlagv, void, (GLbooleanP))
-BGL_Wrap(1, Enable, void, (GLenum))
-BGL_Wrap(1, End, void, (void))
-BGL_Wrap(1, EndList, void, (void))
-BGL_Wrap(1, EvalCoord1d, void, (GLdouble))
-BGL_Wrap(1, EvalCoord1dv, void, (GLdoubleP))
-BGL_Wrap(1, EvalCoord1f, void, (GLfloat))
-BGL_Wrap(1, EvalCoord1fv, void, (GLfloatP))
-BGL_Wrap(2, EvalCoord2d, void, (GLdouble, GLdouble))
-BGL_Wrap(1, EvalCoord2dv, void, (GLdoubleP))
-BGL_Wrap(2, EvalCoord2f, void, (GLfloat, GLfloat))
-BGL_Wrap(1, EvalCoord2fv, void, (GLfloatP))
-BGL_Wrap(3, EvalMesh1, void, (GLenum, GLint, GLint))
-BGL_Wrap(5, EvalMesh2, void, (GLenum, GLint, GLint, GLint, GLint))
-BGL_Wrap(1, EvalPoint1, void, (GLint))
-BGL_Wrap(2, EvalPoint2, void, (GLint, GLint))
-BGL_Wrap(3, FeedbackBuffer, void, (GLsizei, GLenum, GLfloatP))
-BGL_Wrap(1, Finish, void, (void))
-BGL_Wrap(1, Flush, void, (void))
-BGL_Wrap(2, Fogf, void, (GLenum, GLfloat))
-BGL_Wrap(2, Fogfv, void, (GLenum, GLfloatP))
-BGL_Wrap(2, Fogi, void, (GLenum, GLint))
-BGL_Wrap(2, Fogiv, void, (GLenum, GLintP))
-BGL_Wrap(1, FrontFace, void, (GLenum))
-BGL_Wrap(6, Frustum, void, (GLdouble, GLdouble,
- GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, GenLists, GLuint, (GLsizei))
-BGL_Wrap(2, GenTextures, void, (GLsizei, GLuintP))
-BGL_Wrap(2, GetBooleanv, void, (GLenum, GLbooleanP))
-BGL_Wrap(2, GetClipPlane, void, (GLenum, GLdoubleP))
-BGL_Wrap(2, GetDoublev, void, (GLenum, GLdoubleP))
-BGL_Wrap(1, GetError, GLenum, (void))
-BGL_Wrap(2, GetFloatv, void, (GLenum, GLfloatP))
-BGL_Wrap(2, GetIntegerv, void, (GLenum, GLintP))
-BGL_Wrap(3, GetLightfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, GetLightiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(3, GetMapdv, void, (GLenum, GLenum, GLdoubleP))
-BGL_Wrap(3, GetMapfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, GetMapiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(3, GetMaterialfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, GetMaterialiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(2, GetPixelMapfv, void, (GLenum, GLfloatP))
-BGL_Wrap(2, GetPixelMapuiv, void, (GLenum, GLuintP))
-BGL_Wrap(2, GetPixelMapusv, void, (GLenum, GLushortP))
-BGL_Wrap(1, GetPolygonStipple,void, (GLubyteP))
-BGL_Wrap(1, GetString, GLstring, (GLenum))
-BGL_Wrap(3, GetTexEnvfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, GetTexEnviv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(3, GetTexGendv, void, (GLenum, GLenum, GLdoubleP))
-BGL_Wrap(3, GetTexGenfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, GetTexGeniv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(5, GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP))
-BGL_Wrap(4, GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP))
-BGL_Wrap(4, GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP))
-BGL_Wrap(3, GetTexParameterfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, GetTexParameteriv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(2, Hint, void, (GLenum, GLenum))
-BGL_Wrap(1, IndexMask, void, (GLuint))
-BGL_Wrap(1, Indexd, void, (GLdouble))
-BGL_Wrap(1, Indexdv, void, (GLdoubleP))
-BGL_Wrap(1, Indexf, void, (GLfloat))
-BGL_Wrap(1, Indexfv, void, (GLfloatP))
-BGL_Wrap(1, Indexi, void, (GLint))
-BGL_Wrap(1, Indexiv, void, (GLintP))
-BGL_Wrap(1, Indexs, void, (GLshort))
-BGL_Wrap(1, Indexsv, void, (GLshortP))
-BGL_Wrap(1, InitNames, void, (void))
-BGL_Wrap(1, IsEnabled, GLboolean, (GLenum))
-BGL_Wrap(1, IsList, GLboolean, (GLuint))
-BGL_Wrap(1, IsTexture, GLboolean, (GLuint))
-BGL_Wrap(2, LightModelf, void, (GLenum, GLfloat))
-BGL_Wrap(2, LightModelfv, void, (GLenum, GLfloatP))
-BGL_Wrap(2, LightModeli, void, (GLenum, GLint))
-BGL_Wrap(2, LightModeliv, void, (GLenum, GLintP))
-BGL_Wrap(3, Lightf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(3, Lightfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, Lighti, void, (GLenum, GLenum, GLint))
-BGL_Wrap(3, Lightiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(2, LineStipple, void, (GLint, GLushort))
-BGL_Wrap(1, LineWidth, void, (GLfloat))
-BGL_Wrap(1, ListBase, void, (GLuint))
-BGL_Wrap(1, LoadIdentity, void, (void))
-BGL_Wrap(1, LoadMatrixd, void, (GLdoubleP))
-BGL_Wrap(1, LoadMatrixf, void, (GLfloatP))
-BGL_Wrap(1, LoadName, void, (GLuint))
-BGL_Wrap(1, LogicOp, void, (GLenum))
-BGL_Wrap(6, Map1d, void, (GLenum, GLdouble, GLdouble,
- GLint, GLint, GLdoubleP))
-BGL_Wrap(6, Map1f, void, (GLenum, GLfloat, GLfloat,
- GLint, GLint, GLfloatP))
-BGL_Wrap(10, Map2d, void, (GLenum, GLdouble, GLdouble,
- GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdoubleP))
-BGL_Wrap(10, Map2f, void, (GLenum, GLfloat, GLfloat,
- GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloatP))
-BGL_Wrap(3, MapGrid1d, void, (GLint, GLdouble, GLdouble))
-BGL_Wrap(3, MapGrid1f, void, (GLint, GLfloat, GLfloat))
-BGL_Wrap(6, MapGrid2d, void, (GLint, GLdouble, GLdouble,
- GLint, GLdouble, GLdouble))
-BGL_Wrap(6, MapGrid2f, void, (GLint, GLfloat, GLfloat,
- GLint, GLfloat, GLfloat))
-BGL_Wrap(3, Materialf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(3, Materialfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, Materiali, void, (GLenum, GLenum, GLint))
-BGL_Wrap(3, Materialiv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(1, MatrixMode, void, (GLenum))
-BGL_Wrap(1, MultMatrixd, void, (GLdoubleP))
-BGL_Wrap(1, MultMatrixf, void, (GLfloatP))
-BGL_Wrap(2, NewList, void, (GLuint, GLenum))
-BGL_Wrap(3, Normal3b, void, (GLbyte, GLbyte, GLbyte))
-BGL_Wrap(1, Normal3bv, void, (GLbyteP))
-BGL_Wrap(3, Normal3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, Normal3dv, void, (GLdoubleP))
-BGL_Wrap(3, Normal3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, Normal3fv, void, (GLfloatP))
-BGL_Wrap(3, Normal3i, void, (GLint, GLint, GLint))
-BGL_Wrap(1, Normal3iv, void, (GLintP))
-BGL_Wrap(3, Normal3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(1, Normal3sv, void, (GLshortP))
-BGL_Wrap(6, Ortho, void, (GLdouble, GLdouble,
- GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, PassThrough, void, (GLfloat))
-BGL_Wrap(3, PixelMapfv, void, (GLenum, GLint, GLfloatP))
-BGL_Wrap(3, PixelMapuiv, void, (GLenum, GLint, GLuintP))
-BGL_Wrap(3, PixelMapusv, void, (GLenum, GLint, GLushortP))
-BGL_Wrap(2, PixelStoref, void, (GLenum, GLfloat))
-BGL_Wrap(2, PixelStorei, void, (GLenum, GLint))
-BGL_Wrap(2, PixelTransferf, void, (GLenum, GLfloat))
-BGL_Wrap(2, PixelTransferi, void, (GLenum, GLint))
-BGL_Wrap(2, PixelZoom, void, (GLfloat, GLfloat))
-BGL_Wrap(1, PointSize, void, (GLfloat))
-BGL_Wrap(2, PolygonMode, void, (GLenum, GLenum))
-BGL_Wrap(2, PolygonOffset, void, (GLfloat, GLfloat))
-BGL_Wrap(1, PolygonStipple, void, (GLubyteP))
-BGL_Wrap(1, PopAttrib, void, (void))
-BGL_Wrap(1, PopClientAttrib, void, (void))
-BGL_Wrap(1, PopMatrix, void, (void))
-BGL_Wrap(1, PopName, void, (void))
-BGL_Wrap(3, PrioritizeTextures, void, (GLsizei, GLuintP, GLclampfP))
-BGL_Wrap(1, PushAttrib, void, (GLbitfield))
-BGL_Wrap(1, PushClientAttrib, void, (GLbitfield))
-BGL_Wrap(1, PushMatrix, void, (void))
-BGL_Wrap(1, PushName, void, (GLuint))
-BGL_Wrap(2, RasterPos2d, void, (GLdouble, GLdouble))
-BGL_Wrap(1, RasterPos2dv, void, (GLdoubleP))
-BGL_Wrap(2, RasterPos2f, void, (GLfloat, GLfloat))
-BGL_Wrap(1, RasterPos2fv, void, (GLfloatP))
-BGL_Wrap(2, RasterPos2i, void, (GLint, GLint))
-BGL_Wrap(1, RasterPos2iv, void, (GLintP))
-BGL_Wrap(2, RasterPos2s, void, (GLshort, GLshort))
-BGL_Wrap(1, RasterPos2sv, void, (GLshortP))
-BGL_Wrap(3, RasterPos3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, RasterPos3dv, void, (GLdoubleP))
-BGL_Wrap(3, RasterPos3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, RasterPos3fv, void, (GLfloatP))
-BGL_Wrap(3, RasterPos3i, void, (GLint, GLint, GLint))
-BGL_Wrap(1, RasterPos3iv, void, (GLintP))
-BGL_Wrap(3, RasterPos3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(1, RasterPos3sv, void, (GLshortP))
-BGL_Wrap(4, RasterPos4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, RasterPos4dv, void, (GLdoubleP))
-BGL_Wrap(4, RasterPos4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, RasterPos4fv, void, (GLfloatP))
-BGL_Wrap(4, RasterPos4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(1, RasterPos4iv, void, (GLintP))
-BGL_Wrap(4, RasterPos4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(1, RasterPos4sv, void, (GLshortP))
-BGL_Wrap(1, ReadBuffer, void, (GLenum))
-BGL_Wrap(7, ReadPixels, void, (GLint, GLint, GLsizei,
- GLsizei, GLenum, GLenum, GLvoidP))
-BGL_Wrap(4, Rectd, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(2, Rectdv, void, (GLdoubleP, GLdoubleP))
-BGL_Wrap(4, Rectf, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(2, Rectfv, void, (GLfloatP, GLfloatP))
-BGL_Wrap(4, Recti, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(2, Rectiv, void, (GLintP, GLintP))
-BGL_Wrap(4, Rects, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(2, Rectsv, void, (GLshortP, GLshortP))
-BGL_Wrap(1, RenderMode, GLint, (GLenum))
-BGL_Wrap(4, Rotated, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(4, Rotatef, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(3, Scaled, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(3, Scalef, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(4, Scissor, void, (GLint, GLint, GLsizei, GLsizei))
-BGL_Wrap(2, SelectBuffer, void, (GLsizei, GLuintP))
-BGL_Wrap(1, ShadeModel, void, (GLenum))
-BGL_Wrap(3, StencilFunc, void, (GLenum, GLint, GLuint))
-BGL_Wrap(1, StencilMask, void, (GLuint))
-BGL_Wrap(3, StencilOp, void, (GLenum, GLenum, GLenum))
-BGL_Wrap(1, TexCoord1d, void, (GLdouble))
-BGL_Wrap(1, TexCoord1dv, void, (GLdoubleP))
-BGL_Wrap(1, TexCoord1f, void, (GLfloat))
-BGL_Wrap(1, TexCoord1fv, void, (GLfloatP))
-BGL_Wrap(1, TexCoord1i, void, (GLint))
-BGL_Wrap(1, TexCoord1iv, void, (GLintP))
-BGL_Wrap(1, TexCoord1s, void, (GLshort))
-BGL_Wrap(1, TexCoord1sv, void, (GLshortP))
-BGL_Wrap(2, TexCoord2d, void, (GLdouble, GLdouble))
-BGL_Wrap(1, TexCoord2dv, void, (GLdoubleP))
-BGL_Wrap(2, TexCoord2f, void, (GLfloat, GLfloat))
-BGL_Wrap(1, TexCoord2fv, void, (GLfloatP))
-BGL_Wrap(2, TexCoord2i, void, (GLint, GLint))
-BGL_Wrap(1, TexCoord2iv, void, (GLintP))
-BGL_Wrap(2, TexCoord2s, void, (GLshort, GLshort))
-BGL_Wrap(1, TexCoord2sv, void, (GLshortP))
-BGL_Wrap(3, TexCoord3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, TexCoord3dv, void, (GLdoubleP))
-BGL_Wrap(3, TexCoord3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, TexCoord3fv, void, (GLfloatP))
-BGL_Wrap(3, TexCoord3i, void, (GLint, GLint, GLint))
-BGL_Wrap(1, TexCoord3iv, void, (GLintP))
-BGL_Wrap(3, TexCoord3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(1, TexCoord3sv, void, (GLshortP))
-BGL_Wrap(4, TexCoord4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, TexCoord4dv, void, (GLdoubleP))
-BGL_Wrap(4, TexCoord4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, TexCoord4fv, void, (GLfloatP))
-BGL_Wrap(4, TexCoord4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(1, TexCoord4iv, void, (GLintP))
-BGL_Wrap(4, TexCoord4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(1, TexCoord4sv, void, (GLshortP))
-BGL_Wrap(3, TexEnvf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(3, TexEnvfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, TexEnvi, void, (GLenum, GLenum, GLint))
-BGL_Wrap(3, TexEnviv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(3, TexGend, void, (GLenum, GLenum, GLdouble))
-BGL_Wrap(3, TexGendv, void, (GLenum, GLenum, GLdoubleP))
-BGL_Wrap(3, TexGenf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(3, TexGenfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, TexGeni, void, (GLenum, GLenum, GLint))
-BGL_Wrap(3, TexGeniv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(8, TexImage1D, void, (GLenum, GLint, GLint,
- GLsizei, GLint, GLenum, GLenum, GLvoidP))
-BGL_Wrap(9, TexImage2D, void, (GLenum, GLint, GLint,
- GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP))
-BGL_Wrap(3, TexParameterf, void, (GLenum, GLenum, GLfloat))
-BGL_Wrap(3, TexParameterfv, void, (GLenum, GLenum, GLfloatP))
-BGL_Wrap(3, TexParameteri, void, (GLenum, GLenum, GLint))
-BGL_Wrap(3, TexParameteriv, void, (GLenum, GLenum, GLintP))
-BGL_Wrap(3, Translated, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(3, Translatef, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(2, Vertex2d, void, (GLdouble, GLdouble))
-BGL_Wrap(1, Vertex2dv, void, (GLdoubleP))
-BGL_Wrap(2, Vertex2f, void, (GLfloat, GLfloat))
-BGL_Wrap(1, Vertex2fv, void, (GLfloatP))
-BGL_Wrap(2, Vertex2i, void, (GLint, GLint))
-BGL_Wrap(1, Vertex2iv, void, (GLintP))
-BGL_Wrap(2, Vertex2s, void, (GLshort, GLshort))
-BGL_Wrap(1, Vertex2sv, void, (GLshortP))
-BGL_Wrap(3, Vertex3d, void, (GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, Vertex3dv, void, (GLdoubleP))
-BGL_Wrap(3, Vertex3f, void, (GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, Vertex3fv, void, (GLfloatP))
-BGL_Wrap(3, Vertex3i, void, (GLint, GLint, GLint))
-BGL_Wrap(1, Vertex3iv, void, (GLintP))
-BGL_Wrap(3, Vertex3s, void, (GLshort, GLshort, GLshort))
-BGL_Wrap(1, Vertex3sv, void, (GLshortP))
-BGL_Wrap(4, Vertex4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGL_Wrap(1, Vertex4dv, void, (GLdoubleP))
-BGL_Wrap(4, Vertex4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
-BGL_Wrap(1, Vertex4fv, void, (GLfloatP))
-BGL_Wrap(4, Vertex4i, void, (GLint, GLint, GLint, GLint))
-BGL_Wrap(1, Vertex4iv, void, (GLintP))
-BGL_Wrap(4, Vertex4s, void, (GLshort, GLshort, GLshort, GLshort))
-BGL_Wrap(1, Vertex4sv, void, (GLshortP))
-BGL_Wrap(4, Viewport, void, (GLint, GLint, GLsizei, GLsizei))
-BGLU_Wrap(4, Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGLU_Wrap(9, LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
-BGLU_Wrap(4, Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble))
-BGLU_Wrap(5, PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP))
-BGLU_Wrap(9, Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
-BGLU_Wrap(9, UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
-
-#undef MethodDef
-#define MethodDef(func) {"gl"#func, Method_##func, METH_VARARGS, "no string"}
-#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, "no string"}
-/* So that MethodDef(Accum) becomes:
- * {"glAccum", Method_Accumfunc, METH_VARARGS} */
-
-static struct PyMethodDef BGL_methods[] = {
- {"Buffer", Method_Buffer, METH_VARARGS, Method_Buffer_doc},
-
-/* #ifndef __APPLE__ */
- MethodDef(Accum),
- MethodDef(AlphaFunc),
- MethodDef(AreTexturesResident),
- MethodDef(Begin),
- MethodDef(BindTexture),
- MethodDef(Bitmap),
- MethodDef(BlendFunc),
- MethodDef(CallList),
- MethodDef(CallLists),
- MethodDef(Clear),
- MethodDef(ClearAccum),
- MethodDef(ClearColor),
- MethodDef(ClearDepth),
- MethodDef(ClearIndex),
- MethodDef(ClearStencil),
- MethodDef(ClipPlane),
- MethodDef(Color3b),
- MethodDef(Color3bv),
- MethodDef(Color3d),
- MethodDef(Color3dv),
- MethodDef(Color3f),
- MethodDef(Color3fv),
- MethodDef(Color3i),
- MethodDef(Color3iv),
- MethodDef(Color3s),
- MethodDef(Color3sv),
- MethodDef(Color3ub),
- MethodDef(Color3ubv),
- MethodDef(Color3ui),
- MethodDef(Color3uiv),
- MethodDef(Color3us),
- MethodDef(Color3usv),
- MethodDef(Color4b),
- MethodDef(Color4bv),
- MethodDef(Color4d),
- MethodDef(Color4dv),
- MethodDef(Color4f),
- MethodDef(Color4fv),
- MethodDef(Color4i),
- MethodDef(Color4iv),
- MethodDef(Color4s),
- MethodDef(Color4sv),
- MethodDef(Color4ub),
- MethodDef(Color4ubv),
- MethodDef(Color4ui),
- MethodDef(Color4uiv),
- MethodDef(Color4us),
- MethodDef(Color4usv),
- MethodDef(ColorMask),
- MethodDef(ColorMaterial),
- MethodDef(CopyPixels),
- MethodDef(CullFace),
- MethodDef(DeleteLists),
- MethodDef(DeleteTextures),
- MethodDef(DepthFunc),
- MethodDef(DepthMask),
- MethodDef(DepthRange),
- MethodDef(Disable),
- MethodDef(DrawBuffer),
- MethodDef(DrawPixels),
- MethodDef(EdgeFlag),
- MethodDef(EdgeFlagv),
- MethodDef(Enable),
- MethodDef(End),
- MethodDef(EndList),
- MethodDef(EvalCoord1d),
- MethodDef(EvalCoord1dv),
- MethodDef(EvalCoord1f),
- MethodDef(EvalCoord1fv),
- MethodDef(EvalCoord2d),
- MethodDef(EvalCoord2dv),
- MethodDef(EvalCoord2f),
- MethodDef(EvalCoord2fv),
- MethodDef(EvalMesh1),
- MethodDef(EvalMesh2),
- MethodDef(EvalPoint1),
- MethodDef(EvalPoint2),
- MethodDef(FeedbackBuffer),
- MethodDef(Finish),
- MethodDef(Flush),
- MethodDef(Fogf),
- MethodDef(Fogfv),
- MethodDef(Fogi),
- MethodDef(Fogiv),
- MethodDef(FrontFace),
- MethodDef(Frustum),
- MethodDef(GenLists),
- MethodDef(GenTextures),
- MethodDef(GetBooleanv),
- MethodDef(GetClipPlane),
- MethodDef(GetDoublev),
- MethodDef(GetError),
- MethodDef(GetFloatv),
- MethodDef(GetIntegerv),
- MethodDef(GetLightfv),
- MethodDef(GetLightiv),
- MethodDef(GetMapdv),
- MethodDef(GetMapfv),
- MethodDef(GetMapiv),
- MethodDef(GetMaterialfv),
- MethodDef(GetMaterialiv),
- MethodDef(GetPixelMapfv),
- MethodDef(GetPixelMapuiv),
- MethodDef(GetPixelMapusv),
- MethodDef(GetPolygonStipple),
- MethodDef(GetString),
- MethodDef(GetTexEnvfv),
- MethodDef(GetTexEnviv),
- MethodDef(GetTexGendv),
- MethodDef(GetTexGenfv),
- MethodDef(GetTexGeniv),
- MethodDef(GetTexImage),
- MethodDef(GetTexLevelParameterfv),
- MethodDef(GetTexLevelParameteriv),
- MethodDef(GetTexParameterfv),
- MethodDef(GetTexParameteriv),
- MethodDef(Hint),
- MethodDef(IndexMask),
- MethodDef(Indexd),
- MethodDef(Indexdv),
- MethodDef(Indexf),
- MethodDef(Indexfv),
- MethodDef(Indexi),
- MethodDef(Indexiv),
- MethodDef(Indexs),
- MethodDef(Indexsv),
- MethodDef(InitNames),
- MethodDef(IsEnabled),
- MethodDef(IsList),
- MethodDef(IsTexture),
- MethodDef(LightModelf),
- MethodDef(LightModelfv),
- MethodDef(LightModeli),
- MethodDef(LightModeliv),
- MethodDef(Lightf),
- MethodDef(Lightfv),
- MethodDef(Lighti),
- MethodDef(Lightiv),
- MethodDef(LineStipple),
- MethodDef(LineWidth),
- MethodDef(ListBase),
- MethodDef(LoadIdentity),
- MethodDef(LoadMatrixd),
- MethodDef(LoadMatrixf),
- MethodDef(LoadName),
- MethodDef(LogicOp),
- MethodDef(Map1d),
- MethodDef(Map1f),
- MethodDef(Map2d),
- MethodDef(Map2f),
- MethodDef(MapGrid1d),
- MethodDef(MapGrid1f),
- MethodDef(MapGrid2d),
- MethodDef(MapGrid2f),
- MethodDef(Materialf),
- MethodDef(Materialfv),
- MethodDef(Materiali),
- MethodDef(Materialiv),
- MethodDef(MatrixMode),
- MethodDef(MultMatrixd),
- MethodDef(MultMatrixf),
- MethodDef(NewList),
- MethodDef(Normal3b),
- MethodDef(Normal3bv),
- MethodDef(Normal3d),
- MethodDef(Normal3dv),
- MethodDef(Normal3f),
- MethodDef(Normal3fv),
- MethodDef(Normal3i),
- MethodDef(Normal3iv),
- MethodDef(Normal3s),
- MethodDef(Normal3sv),
- MethodDef(Ortho),
- MethodDef(PassThrough),
- MethodDef(PixelMapfv),
- MethodDef(PixelMapuiv),
- MethodDef(PixelMapusv),
- MethodDef(PixelStoref),
- MethodDef(PixelStorei),
- MethodDef(PixelTransferf),
- MethodDef(PixelTransferi),
- MethodDef(PixelZoom),
- MethodDef(PointSize),
- MethodDef(PolygonMode),
- MethodDef(PolygonOffset),
- MethodDef(PolygonStipple),
- MethodDef(PopAttrib),
- MethodDef(PopClientAttrib),
- MethodDef(PopMatrix),
- MethodDef(PopName),
- MethodDef(PrioritizeTextures),
- MethodDef(PushAttrib),
- MethodDef(PushClientAttrib),
- MethodDef(PushMatrix),
- MethodDef(PushName),
- MethodDef(RasterPos2d),
- MethodDef(RasterPos2dv),
- MethodDef(RasterPos2f),
- MethodDef(RasterPos2fv),
- MethodDef(RasterPos2i),
- MethodDef(RasterPos2iv),
- MethodDef(RasterPos2s),
- MethodDef(RasterPos2sv),
- MethodDef(RasterPos3d),
- MethodDef(RasterPos3dv),
- MethodDef(RasterPos3f),
- MethodDef(RasterPos3fv),
- MethodDef(RasterPos3i),
- MethodDef(RasterPos3iv),
- MethodDef(RasterPos3s),
- MethodDef(RasterPos3sv),
- MethodDef(RasterPos4d),
- MethodDef(RasterPos4dv),
- MethodDef(RasterPos4f),
- MethodDef(RasterPos4fv),
- MethodDef(RasterPos4i),
- MethodDef(RasterPos4iv),
- MethodDef(RasterPos4s),
- MethodDef(RasterPos4sv),
- MethodDef(ReadBuffer),
- MethodDef(ReadPixels),
- MethodDef(Rectd),
- MethodDef(Rectdv),
- MethodDef(Rectf),
- MethodDef(Rectfv),
- MethodDef(Recti),
- MethodDef(Rectiv),
- MethodDef(Rects),
- MethodDef(Rectsv),
- MethodDef(RenderMode),
- MethodDef(Rotated),
- MethodDef(Rotatef),
- MethodDef(Scaled),
- MethodDef(Scalef),
- MethodDef(Scissor),
- MethodDef(SelectBuffer),
- MethodDef(ShadeModel),
- MethodDef(StencilFunc),
- MethodDef(StencilMask),
- MethodDef(StencilOp),
- MethodDef(TexCoord1d),
- MethodDef(TexCoord1dv),
- MethodDef(TexCoord1f),
- MethodDef(TexCoord1fv),
- MethodDef(TexCoord1i),
- MethodDef(TexCoord1iv),
- MethodDef(TexCoord1s),
- MethodDef(TexCoord1sv),
- MethodDef(TexCoord2d),
- MethodDef(TexCoord2dv),
- MethodDef(TexCoord2f),
- MethodDef(TexCoord2fv),
- MethodDef(TexCoord2i),
- MethodDef(TexCoord2iv),
- MethodDef(TexCoord2s),
- MethodDef(TexCoord2sv),
- MethodDef(TexCoord3d),
- MethodDef(TexCoord3dv),
- MethodDef(TexCoord3f),
- MethodDef(TexCoord3fv),
- MethodDef(TexCoord3i),
- MethodDef(TexCoord3iv),
- MethodDef(TexCoord3s),
- MethodDef(TexCoord3sv),
- MethodDef(TexCoord4d),
- MethodDef(TexCoord4dv),
- MethodDef(TexCoord4f),
- MethodDef(TexCoord4fv),
- MethodDef(TexCoord4i),
- MethodDef(TexCoord4iv),
- MethodDef(TexCoord4s),
- MethodDef(TexCoord4sv),
- MethodDef(TexEnvf),
- MethodDef(TexEnvfv),
- MethodDef(TexEnvi),
- MethodDef(TexEnviv),
- MethodDef(TexGend),
- MethodDef(TexGendv),
- MethodDef(TexGenf),
- MethodDef(TexGenfv),
- MethodDef(TexGeni),
- MethodDef(TexGeniv),
- MethodDef(TexImage1D),
- MethodDef(TexImage2D),
- MethodDef(TexParameterf),
- MethodDef(TexParameterfv),
- MethodDef(TexParameteri),
- MethodDef(TexParameteriv),
- MethodDef(Translated),
- MethodDef(Translatef),
- MethodDef(Vertex2d),
- MethodDef(Vertex2dv),
- MethodDef(Vertex2f),
- MethodDef(Vertex2fv),
- MethodDef(Vertex2i),
- MethodDef(Vertex2iv),
- MethodDef(Vertex2s),
- MethodDef(Vertex2sv),
- MethodDef(Vertex3d),
- MethodDef(Vertex3dv),
- MethodDef(Vertex3f),
- MethodDef(Vertex3fv),
- MethodDef(Vertex3i),
- MethodDef(Vertex3iv),
- MethodDef(Vertex3s),
- MethodDef(Vertex3sv),
- MethodDef(Vertex4d),
- MethodDef(Vertex4dv),
- MethodDef(Vertex4f),
- MethodDef(Vertex4fv),
- MethodDef(Vertex4i),
- MethodDef(Vertex4iv),
- MethodDef(Vertex4s),
- MethodDef(Vertex4sv),
- MethodDef(Viewport),
- MethodDefu(Perspective),
- MethodDefu(LookAt),
- MethodDefu(Ortho2D),
- MethodDefu(PickMatrix),
- MethodDefu(Project),
- MethodDefu(UnProject),
-/* #endif */
- {NULL, NULL, 0, NULL}
-};
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static struct PyModuleDef BGL_module_def = {
- PyModuleDef_HEAD_INIT,
- "BGL", /* m_name */
- 0, /* m_doc */
- 0, /* m_size */
- BGL_methods, /* m_methods */
- 0, /* m_reload */
- 0, /* m_traverse */
- 0, /* m_clear */
- 0, /* m_free */
-};
-#endif
-
-PyObject *BGL_Init(const char *from)
-{
- PyObject *mod, *dict, *item;
-#if (PY_VERSION_HEX >= 0x03000000)
- mod = PyModule_Create(&BGL_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), BGL_module_def.m_name, mod);
-#else
- mod= Py_InitModule(from, BGL_methods);
-#endif
- dict= PyModule_GetDict(mod);
-
- if( PyType_Ready( &buffer_Type) < 0)
- return NULL; /* should never happen */
-
-#define EXPP_ADDCONST(x) PyDict_SetItemString(dict, #x, item=PyLong_FromLong((int)x)); Py_DECREF(item)
-
-/* So, for example:
- * EXPP_ADDCONST(GL_CURRENT_BIT) becomes
- * PyDict_SetItemString(dict, "GL_CURRENT_BIT", item=PyLong_FromLong(GL_CURRENT_BIT)); Py_DECREF(item) */
-
- EXPP_ADDCONST(GL_CURRENT_BIT);
- EXPP_ADDCONST(GL_POINT_BIT);
- EXPP_ADDCONST(GL_LINE_BIT);
- EXPP_ADDCONST(GL_POLYGON_BIT);
- EXPP_ADDCONST(GL_POLYGON_STIPPLE_BIT);
- EXPP_ADDCONST(GL_PIXEL_MODE_BIT);
- EXPP_ADDCONST(GL_LIGHTING_BIT);
- EXPP_ADDCONST(GL_FOG_BIT);
- EXPP_ADDCONST(GL_DEPTH_BUFFER_BIT);
- EXPP_ADDCONST(GL_ACCUM_BUFFER_BIT);
- EXPP_ADDCONST(GL_STENCIL_BUFFER_BIT);
- EXPP_ADDCONST(GL_VIEWPORT_BIT);
- EXPP_ADDCONST(GL_TRANSFORM_BIT);
- EXPP_ADDCONST(GL_ENABLE_BIT);
- EXPP_ADDCONST(GL_COLOR_BUFFER_BIT);
- EXPP_ADDCONST(GL_HINT_BIT);
- EXPP_ADDCONST(GL_EVAL_BIT);
- EXPP_ADDCONST(GL_LIST_BIT);
- EXPP_ADDCONST(GL_TEXTURE_BIT);
- EXPP_ADDCONST(GL_SCISSOR_BIT);
- EXPP_ADDCONST(GL_ALL_ATTRIB_BITS);
- EXPP_ADDCONST(GL_CLIENT_ALL_ATTRIB_BITS);
-
- EXPP_ADDCONST(GL_FALSE);
- EXPP_ADDCONST(GL_TRUE);
-
- EXPP_ADDCONST(GL_POINTS);
- EXPP_ADDCONST(GL_LINES);
- EXPP_ADDCONST(GL_LINE_LOOP);
- EXPP_ADDCONST(GL_LINE_STRIP);
- EXPP_ADDCONST(GL_TRIANGLES);
- EXPP_ADDCONST(GL_TRIANGLE_STRIP);
- EXPP_ADDCONST(GL_TRIANGLE_FAN);
- EXPP_ADDCONST(GL_QUADS);
- EXPP_ADDCONST(GL_QUAD_STRIP);
- EXPP_ADDCONST(GL_POLYGON);
-
- EXPP_ADDCONST(GL_ACCUM);
- EXPP_ADDCONST(GL_LOAD);
- EXPP_ADDCONST(GL_RETURN);
- EXPP_ADDCONST(GL_MULT);
- EXPP_ADDCONST(GL_ADD);
-
- EXPP_ADDCONST(GL_NEVER);
- EXPP_ADDCONST(GL_LESS);
- EXPP_ADDCONST(GL_EQUAL);
- EXPP_ADDCONST(GL_LEQUAL);
- EXPP_ADDCONST(GL_GREATER);
- EXPP_ADDCONST(GL_NOTEQUAL);
- EXPP_ADDCONST(GL_GEQUAL);
- EXPP_ADDCONST(GL_ALWAYS);
-
- EXPP_ADDCONST(GL_ZERO);
- EXPP_ADDCONST(GL_ONE);
- EXPP_ADDCONST(GL_SRC_COLOR);
- EXPP_ADDCONST(GL_ONE_MINUS_SRC_COLOR);
- EXPP_ADDCONST(GL_SRC_ALPHA);
- EXPP_ADDCONST(GL_ONE_MINUS_SRC_ALPHA);
- EXPP_ADDCONST(GL_DST_ALPHA);
- EXPP_ADDCONST(GL_ONE_MINUS_DST_ALPHA);
-
- EXPP_ADDCONST(GL_DST_COLOR);
- EXPP_ADDCONST(GL_ONE_MINUS_DST_COLOR);
- EXPP_ADDCONST(GL_SRC_ALPHA_SATURATE);
-
- EXPP_ADDCONST(GL_NONE);
- EXPP_ADDCONST(GL_FRONT_LEFT);
- EXPP_ADDCONST(GL_FRONT_RIGHT);
- EXPP_ADDCONST(GL_BACK_LEFT);
- EXPP_ADDCONST(GL_BACK_RIGHT);
- EXPP_ADDCONST(GL_FRONT);
- EXPP_ADDCONST(GL_BACK);
- EXPP_ADDCONST(GL_LEFT);
- EXPP_ADDCONST(GL_RIGHT);
- EXPP_ADDCONST(GL_FRONT_AND_BACK);
- EXPP_ADDCONST(GL_AUX0);
- EXPP_ADDCONST(GL_AUX1);
- EXPP_ADDCONST(GL_AUX2);
- EXPP_ADDCONST(GL_AUX3);
-
- EXPP_ADDCONST(GL_NO_ERROR);
- EXPP_ADDCONST(GL_INVALID_ENUM);
- EXPP_ADDCONST(GL_INVALID_VALUE);
- EXPP_ADDCONST(GL_INVALID_OPERATION);
- EXPP_ADDCONST(GL_STACK_OVERFLOW);
- EXPP_ADDCONST(GL_STACK_UNDERFLOW);
- EXPP_ADDCONST(GL_OUT_OF_MEMORY);
-
- EXPP_ADDCONST(GL_2D);
- EXPP_ADDCONST(GL_3D);
- EXPP_ADDCONST(GL_3D_COLOR);
- EXPP_ADDCONST(GL_3D_COLOR_TEXTURE);
- EXPP_ADDCONST(GL_4D_COLOR_TEXTURE);
-
- EXPP_ADDCONST(GL_PASS_THROUGH_TOKEN);
- EXPP_ADDCONST(GL_POINT_TOKEN);
- EXPP_ADDCONST(GL_LINE_TOKEN);
- EXPP_ADDCONST(GL_POLYGON_TOKEN);
- EXPP_ADDCONST(GL_BITMAP_TOKEN);
- EXPP_ADDCONST(GL_DRAW_PIXEL_TOKEN);
- EXPP_ADDCONST(GL_COPY_PIXEL_TOKEN);
- EXPP_ADDCONST(GL_LINE_RESET_TOKEN);
-
- EXPP_ADDCONST(GL_EXP);
- EXPP_ADDCONST(GL_EXP2);
-
- EXPP_ADDCONST(GL_CW);
- EXPP_ADDCONST(GL_CCW);
-
- EXPP_ADDCONST(GL_COEFF);
- EXPP_ADDCONST(GL_ORDER);
- EXPP_ADDCONST(GL_DOMAIN);
-
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I);
- EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A);
- EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R);
- EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G);
- EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B);
- EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A);
-
- EXPP_ADDCONST(GL_CURRENT_COLOR);
- EXPP_ADDCONST(GL_CURRENT_INDEX);
- EXPP_ADDCONST(GL_CURRENT_NORMAL);
- EXPP_ADDCONST(GL_CURRENT_TEXTURE_COORDS);
- EXPP_ADDCONST(GL_CURRENT_RASTER_COLOR);
- EXPP_ADDCONST(GL_CURRENT_RASTER_INDEX);
- EXPP_ADDCONST(GL_CURRENT_RASTER_TEXTURE_COORDS);
- EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION);
- EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION_VALID);
- EXPP_ADDCONST(GL_CURRENT_RASTER_DISTANCE);
- EXPP_ADDCONST(GL_POINT_SMOOTH);
- EXPP_ADDCONST(GL_POINT_SIZE);
- EXPP_ADDCONST(GL_POINT_SIZE_RANGE);
- EXPP_ADDCONST(GL_POINT_SIZE_GRANULARITY);
- EXPP_ADDCONST(GL_LINE_SMOOTH);
- EXPP_ADDCONST(GL_LINE_WIDTH);
- EXPP_ADDCONST(GL_LINE_WIDTH_RANGE);
- EXPP_ADDCONST(GL_LINE_WIDTH_GRANULARITY);
- EXPP_ADDCONST(GL_LINE_STIPPLE);
- EXPP_ADDCONST(GL_LINE_STIPPLE_PATTERN);
- EXPP_ADDCONST(GL_LINE_STIPPLE_REPEAT);
- EXPP_ADDCONST(GL_LIST_MODE);
- EXPP_ADDCONST(GL_MAX_LIST_NESTING);
- EXPP_ADDCONST(GL_LIST_BASE);
- EXPP_ADDCONST(GL_LIST_INDEX);
- EXPP_ADDCONST(GL_POLYGON_MODE);
- EXPP_ADDCONST(GL_POLYGON_SMOOTH);
- EXPP_ADDCONST(GL_POLYGON_STIPPLE);
- EXPP_ADDCONST(GL_EDGE_FLAG);
- EXPP_ADDCONST(GL_CULL_FACE);
- EXPP_ADDCONST(GL_CULL_FACE_MODE);
- EXPP_ADDCONST(GL_FRONT_FACE);
- EXPP_ADDCONST(GL_LIGHTING);
- EXPP_ADDCONST(GL_LIGHT_MODEL_LOCAL_VIEWER);
- EXPP_ADDCONST(GL_LIGHT_MODEL_TWO_SIDE);
- EXPP_ADDCONST(GL_LIGHT_MODEL_AMBIENT);
- EXPP_ADDCONST(GL_SHADE_MODEL);
- EXPP_ADDCONST(GL_COLOR_MATERIAL_FACE);
- EXPP_ADDCONST(GL_COLOR_MATERIAL_PARAMETER);
- EXPP_ADDCONST(GL_COLOR_MATERIAL);
- EXPP_ADDCONST(GL_FOG);
- EXPP_ADDCONST(GL_FOG_INDEX);
- EXPP_ADDCONST(GL_FOG_DENSITY);
- EXPP_ADDCONST(GL_FOG_START);
- EXPP_ADDCONST(GL_FOG_END);
- EXPP_ADDCONST(GL_FOG_MODE);
- EXPP_ADDCONST(GL_FOG_COLOR);
- EXPP_ADDCONST(GL_DEPTH_RANGE);
- EXPP_ADDCONST(GL_DEPTH_TEST);
- EXPP_ADDCONST(GL_DEPTH_WRITEMASK);
- EXPP_ADDCONST(GL_DEPTH_CLEAR_VALUE);
- EXPP_ADDCONST(GL_DEPTH_FUNC);
- EXPP_ADDCONST(GL_ACCUM_CLEAR_VALUE);
- EXPP_ADDCONST(GL_STENCIL_TEST);
- EXPP_ADDCONST(GL_STENCIL_CLEAR_VALUE);
- EXPP_ADDCONST(GL_STENCIL_FUNC);
- EXPP_ADDCONST(GL_STENCIL_VALUE_MASK);
- EXPP_ADDCONST(GL_STENCIL_FAIL);
- EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_FAIL);
- EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_PASS);
- EXPP_ADDCONST(GL_STENCIL_REF);
- EXPP_ADDCONST(GL_STENCIL_WRITEMASK);
- EXPP_ADDCONST(GL_MATRIX_MODE);
- EXPP_ADDCONST(GL_NORMALIZE);
- EXPP_ADDCONST(GL_VIEWPORT);
- EXPP_ADDCONST(GL_MODELVIEW_STACK_DEPTH);
- EXPP_ADDCONST(GL_PROJECTION_STACK_DEPTH);
- EXPP_ADDCONST(GL_TEXTURE_STACK_DEPTH);
- EXPP_ADDCONST(GL_MODELVIEW_MATRIX);
- EXPP_ADDCONST(GL_PROJECTION_MATRIX);
- EXPP_ADDCONST(GL_TEXTURE_MATRIX);
- EXPP_ADDCONST(GL_ATTRIB_STACK_DEPTH);
- EXPP_ADDCONST(GL_ALPHA_TEST);
- EXPP_ADDCONST(GL_ALPHA_TEST_FUNC);
- EXPP_ADDCONST(GL_ALPHA_TEST_REF);
- EXPP_ADDCONST(GL_DITHER);
- EXPP_ADDCONST(GL_BLEND_DST);
- EXPP_ADDCONST(GL_BLEND_SRC);
- EXPP_ADDCONST(GL_BLEND);
- EXPP_ADDCONST(GL_LOGIC_OP_MODE);
- EXPP_ADDCONST(GL_LOGIC_OP);
- EXPP_ADDCONST(GL_AUX_BUFFERS);
- EXPP_ADDCONST(GL_DRAW_BUFFER);
- EXPP_ADDCONST(GL_READ_BUFFER);
- EXPP_ADDCONST(GL_SCISSOR_BOX);
- EXPP_ADDCONST(GL_SCISSOR_TEST);
- EXPP_ADDCONST(GL_INDEX_CLEAR_VALUE);
- EXPP_ADDCONST(GL_INDEX_WRITEMASK);
- EXPP_ADDCONST(GL_COLOR_CLEAR_VALUE);
- EXPP_ADDCONST(GL_COLOR_WRITEMASK);
- EXPP_ADDCONST(GL_INDEX_MODE);
- EXPP_ADDCONST(GL_RGBA_MODE);
- EXPP_ADDCONST(GL_DOUBLEBUFFER);
- EXPP_ADDCONST(GL_STEREO);
- EXPP_ADDCONST(GL_RENDER_MODE);
- EXPP_ADDCONST(GL_PERSPECTIVE_CORRECTION_HINT);
- EXPP_ADDCONST(GL_POINT_SMOOTH_HINT);
- EXPP_ADDCONST(GL_LINE_SMOOTH_HINT);
- EXPP_ADDCONST(GL_POLYGON_SMOOTH_HINT);
- EXPP_ADDCONST(GL_FOG_HINT);
- EXPP_ADDCONST(GL_TEXTURE_GEN_S);
- EXPP_ADDCONST(GL_TEXTURE_GEN_T);
- EXPP_ADDCONST(GL_TEXTURE_GEN_R);
- EXPP_ADDCONST(GL_TEXTURE_GEN_Q);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B_SIZE);
- EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A_SIZE);
- EXPP_ADDCONST(GL_UNPACK_SWAP_BYTES);
- EXPP_ADDCONST(GL_UNPACK_LSB_FIRST);
- EXPP_ADDCONST(GL_UNPACK_ROW_LENGTH);
- EXPP_ADDCONST(GL_UNPACK_SKIP_ROWS);
- EXPP_ADDCONST(GL_UNPACK_SKIP_PIXELS);
- EXPP_ADDCONST(GL_UNPACK_ALIGNMENT);
- EXPP_ADDCONST(GL_PACK_SWAP_BYTES);
- EXPP_ADDCONST(GL_PACK_LSB_FIRST);
- EXPP_ADDCONST(GL_PACK_ROW_LENGTH);
- EXPP_ADDCONST(GL_PACK_SKIP_ROWS);
- EXPP_ADDCONST(GL_PACK_SKIP_PIXELS);
- EXPP_ADDCONST(GL_PACK_ALIGNMENT);
- EXPP_ADDCONST(GL_MAP_COLOR);
- EXPP_ADDCONST(GL_MAP_STENCIL);
- EXPP_ADDCONST(GL_INDEX_SHIFT);
- EXPP_ADDCONST(GL_INDEX_OFFSET);
- EXPP_ADDCONST(GL_RED_SCALE);
- EXPP_ADDCONST(GL_RED_BIAS);
- EXPP_ADDCONST(GL_ZOOM_X);
- EXPP_ADDCONST(GL_ZOOM_Y);
- EXPP_ADDCONST(GL_GREEN_SCALE);
- EXPP_ADDCONST(GL_GREEN_BIAS);
- EXPP_ADDCONST(GL_BLUE_SCALE);
- EXPP_ADDCONST(GL_BLUE_BIAS);
- EXPP_ADDCONST(GL_ALPHA_SCALE);
- EXPP_ADDCONST(GL_ALPHA_BIAS);
- EXPP_ADDCONST(GL_DEPTH_SCALE);
- EXPP_ADDCONST(GL_DEPTH_BIAS);
- EXPP_ADDCONST(GL_MAX_EVAL_ORDER);
- EXPP_ADDCONST(GL_MAX_LIGHTS);
- EXPP_ADDCONST(GL_MAX_CLIP_PLANES);
- EXPP_ADDCONST(GL_MAX_TEXTURE_SIZE);
- EXPP_ADDCONST(GL_MAX_PIXEL_MAP_TABLE);
- EXPP_ADDCONST(GL_MAX_ATTRIB_STACK_DEPTH);
- EXPP_ADDCONST(GL_MAX_MODELVIEW_STACK_DEPTH);
- EXPP_ADDCONST(GL_MAX_NAME_STACK_DEPTH);
- EXPP_ADDCONST(GL_MAX_PROJECTION_STACK_DEPTH);
- EXPP_ADDCONST(GL_MAX_TEXTURE_STACK_DEPTH);
- EXPP_ADDCONST(GL_MAX_VIEWPORT_DIMS);
- EXPP_ADDCONST(GL_SUBPIXEL_BITS);
- EXPP_ADDCONST(GL_INDEX_BITS);
- EXPP_ADDCONST(GL_RED_BITS);
- EXPP_ADDCONST(GL_GREEN_BITS);
- EXPP_ADDCONST(GL_BLUE_BITS);
- EXPP_ADDCONST(GL_ALPHA_BITS);
- EXPP_ADDCONST(GL_DEPTH_BITS);
- EXPP_ADDCONST(GL_STENCIL_BITS);
- EXPP_ADDCONST(GL_ACCUM_RED_BITS);
- EXPP_ADDCONST(GL_ACCUM_GREEN_BITS);
- EXPP_ADDCONST(GL_ACCUM_BLUE_BITS);
- EXPP_ADDCONST(GL_ACCUM_ALPHA_BITS);
- EXPP_ADDCONST(GL_NAME_STACK_DEPTH);
- EXPP_ADDCONST(GL_AUTO_NORMAL);
- EXPP_ADDCONST(GL_MAP1_COLOR_4);
- EXPP_ADDCONST(GL_MAP1_INDEX);
- EXPP_ADDCONST(GL_MAP1_NORMAL);
- EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_1);
- EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_2);
- EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_3);
- EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_4);
- EXPP_ADDCONST(GL_MAP1_VERTEX_3);
- EXPP_ADDCONST(GL_MAP1_VERTEX_4);
- EXPP_ADDCONST(GL_MAP2_COLOR_4);
- EXPP_ADDCONST(GL_MAP2_INDEX);
- EXPP_ADDCONST(GL_MAP2_NORMAL);
- EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_1);
- EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_2);
- EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_3);
- EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_4);
- EXPP_ADDCONST(GL_MAP2_VERTEX_3);
- EXPP_ADDCONST(GL_MAP2_VERTEX_4);
- EXPP_ADDCONST(GL_MAP1_GRID_DOMAIN);
- EXPP_ADDCONST(GL_MAP1_GRID_SEGMENTS);
- EXPP_ADDCONST(GL_MAP2_GRID_DOMAIN);
- EXPP_ADDCONST(GL_MAP2_GRID_SEGMENTS);
- EXPP_ADDCONST(GL_TEXTURE_1D);
- EXPP_ADDCONST(GL_TEXTURE_2D);
-
- EXPP_ADDCONST(GL_TEXTURE_WIDTH);
- EXPP_ADDCONST(GL_TEXTURE_HEIGHT);
- EXPP_ADDCONST(GL_TEXTURE_COMPONENTS);
- EXPP_ADDCONST(GL_TEXTURE_BORDER_COLOR);
- EXPP_ADDCONST(GL_TEXTURE_BORDER);
-
- EXPP_ADDCONST(GL_DONT_CARE);
- EXPP_ADDCONST(GL_FASTEST);
- EXPP_ADDCONST(GL_NICEST);
-
- EXPP_ADDCONST(GL_AMBIENT);
- EXPP_ADDCONST(GL_DIFFUSE);
- EXPP_ADDCONST(GL_SPECULAR);
- EXPP_ADDCONST(GL_POSITION);
- EXPP_ADDCONST(GL_SPOT_DIRECTION);
- EXPP_ADDCONST(GL_SPOT_EXPONENT);
- EXPP_ADDCONST(GL_SPOT_CUTOFF);
- EXPP_ADDCONST(GL_CONSTANT_ATTENUATION);
- EXPP_ADDCONST(GL_LINEAR_ATTENUATION);
- EXPP_ADDCONST(GL_QUADRATIC_ATTENUATION);
-
- EXPP_ADDCONST(GL_COMPILE);
- EXPP_ADDCONST(GL_COMPILE_AND_EXECUTE);
-
- EXPP_ADDCONST(GL_BYTE);
- EXPP_ADDCONST(GL_UNSIGNED_BYTE);
- EXPP_ADDCONST(GL_SHORT);
- EXPP_ADDCONST(GL_UNSIGNED_SHORT);
- EXPP_ADDCONST(GL_INT);
- EXPP_ADDCONST(GL_UNSIGNED_INT);
- EXPP_ADDCONST(GL_FLOAT);
- EXPP_ADDCONST(GL_DOUBLE);
- EXPP_ADDCONST(GL_2_BYTES);
- EXPP_ADDCONST(GL_3_BYTES);
- EXPP_ADDCONST(GL_4_BYTES);
-
- EXPP_ADDCONST(GL_CLEAR);
- EXPP_ADDCONST(GL_AND);
- EXPP_ADDCONST(GL_AND_REVERSE);
- EXPP_ADDCONST(GL_COPY);
- EXPP_ADDCONST(GL_AND_INVERTED);
- EXPP_ADDCONST(GL_NOOP);
- EXPP_ADDCONST(GL_XOR);
- EXPP_ADDCONST(GL_OR);
- EXPP_ADDCONST(GL_NOR);
- EXPP_ADDCONST(GL_EQUIV);
- EXPP_ADDCONST(GL_INVERT);
- EXPP_ADDCONST(GL_OR_REVERSE);
- EXPP_ADDCONST(GL_COPY_INVERTED);
- EXPP_ADDCONST(GL_OR_INVERTED);
- EXPP_ADDCONST(GL_NAND);
- EXPP_ADDCONST(GL_SET);
-
- EXPP_ADDCONST(GL_EMISSION);
- EXPP_ADDCONST(GL_SHININESS);
- EXPP_ADDCONST(GL_AMBIENT_AND_DIFFUSE);
- EXPP_ADDCONST(GL_COLOR_INDEXES);
-
- EXPP_ADDCONST(GL_MODELVIEW);
- EXPP_ADDCONST(GL_PROJECTION);
- EXPP_ADDCONST(GL_TEXTURE);
-
- EXPP_ADDCONST(GL_COLOR);
- EXPP_ADDCONST(GL_DEPTH);
- EXPP_ADDCONST(GL_STENCIL);
-
- EXPP_ADDCONST(GL_COLOR_INDEX);
- EXPP_ADDCONST(GL_STENCIL_INDEX);
- EXPP_ADDCONST(GL_DEPTH_COMPONENT);
- EXPP_ADDCONST(GL_RED);
- EXPP_ADDCONST(GL_GREEN);
- EXPP_ADDCONST(GL_BLUE);
- EXPP_ADDCONST(GL_ALPHA);
- EXPP_ADDCONST(GL_RGB);
- EXPP_ADDCONST(GL_RGBA);
- EXPP_ADDCONST(GL_LUMINANCE);
- EXPP_ADDCONST(GL_LUMINANCE_ALPHA);
-
- EXPP_ADDCONST(GL_BITMAP);
-
- EXPP_ADDCONST(GL_POINT);
- EXPP_ADDCONST(GL_LINE);
- EXPP_ADDCONST(GL_FILL);
-
- EXPP_ADDCONST(GL_RENDER);
- EXPP_ADDCONST(GL_FEEDBACK);
- EXPP_ADDCONST(GL_SELECT);
-
- EXPP_ADDCONST(GL_FLAT);
- EXPP_ADDCONST(GL_SMOOTH);
-
- EXPP_ADDCONST(GL_KEEP);
- EXPP_ADDCONST(GL_REPLACE);
- EXPP_ADDCONST(GL_INCR);
- EXPP_ADDCONST(GL_DECR);
-
- EXPP_ADDCONST(GL_VENDOR);
- EXPP_ADDCONST(GL_RENDERER);
- EXPP_ADDCONST(GL_VERSION);
- EXPP_ADDCONST(GL_EXTENSIONS);
-
- EXPP_ADDCONST(GL_S);
- EXPP_ADDCONST(GL_T);
- EXPP_ADDCONST(GL_R);
- EXPP_ADDCONST(GL_Q);
-
- EXPP_ADDCONST(GL_MODULATE);
- EXPP_ADDCONST(GL_DECAL);
-
- EXPP_ADDCONST(GL_TEXTURE_ENV_MODE);
- EXPP_ADDCONST(GL_TEXTURE_ENV_COLOR);
-
- EXPP_ADDCONST(GL_TEXTURE_ENV);
-
- EXPP_ADDCONST(GL_EYE_LINEAR);
- EXPP_ADDCONST(GL_OBJECT_LINEAR);
- EXPP_ADDCONST(GL_SPHERE_MAP);
-
- EXPP_ADDCONST(GL_TEXTURE_GEN_MODE);
- EXPP_ADDCONST(GL_OBJECT_PLANE);
- EXPP_ADDCONST(GL_EYE_PLANE);
-
- EXPP_ADDCONST(GL_NEAREST);
- EXPP_ADDCONST(GL_LINEAR);
-
- EXPP_ADDCONST(GL_NEAREST_MIPMAP_NEAREST);
- EXPP_ADDCONST(GL_LINEAR_MIPMAP_NEAREST);
- EXPP_ADDCONST(GL_NEAREST_MIPMAP_LINEAR);
- EXPP_ADDCONST(GL_LINEAR_MIPMAP_LINEAR);
-
- EXPP_ADDCONST(GL_TEXTURE_MAG_FILTER);
- EXPP_ADDCONST(GL_TEXTURE_MIN_FILTER);
- EXPP_ADDCONST(GL_TEXTURE_WRAP_S);
- EXPP_ADDCONST(GL_TEXTURE_WRAP_T);
-
- EXPP_ADDCONST(GL_CLAMP);
- EXPP_ADDCONST(GL_REPEAT);
-
- EXPP_ADDCONST(GL_CLIP_PLANE0);
- EXPP_ADDCONST(GL_CLIP_PLANE1);
- EXPP_ADDCONST(GL_CLIP_PLANE2);
- EXPP_ADDCONST(GL_CLIP_PLANE3);
- EXPP_ADDCONST(GL_CLIP_PLANE4);
- EXPP_ADDCONST(GL_CLIP_PLANE5);
-
- EXPP_ADDCONST(GL_LIGHT0);
- EXPP_ADDCONST(GL_LIGHT1);
- EXPP_ADDCONST(GL_LIGHT2);
- EXPP_ADDCONST(GL_LIGHT3);
- EXPP_ADDCONST(GL_LIGHT4);
- EXPP_ADDCONST(GL_LIGHT5);
- EXPP_ADDCONST(GL_LIGHT6);
- EXPP_ADDCONST(GL_LIGHT7);
-
- EXPP_ADDCONST(GL_POLYGON_OFFSET_UNITS);
- EXPP_ADDCONST(GL_POLYGON_OFFSET_POINT);
- EXPP_ADDCONST(GL_POLYGON_OFFSET_LINE);
- EXPP_ADDCONST(GL_POLYGON_OFFSET_FILL);
- EXPP_ADDCONST(GL_POLYGON_OFFSET_FACTOR);
-
- EXPP_ADDCONST(GL_TEXTURE_PRIORITY);
- EXPP_ADDCONST(GL_TEXTURE_RESIDENT);
- EXPP_ADDCONST(GL_TEXTURE_BINDING_1D);
- EXPP_ADDCONST(GL_TEXTURE_BINDING_2D);
-
- return mod;
-}
-
diff --git a/source/blender/python/generic/BGL.h b/source/blender/python/generic/BGL.h
deleted file mode 100755
index 938c916bcea..00000000000
--- a/source/blender/python/generic/BGL.h
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Willian P. Germano
- *
- * ***** END GPL LICENSE BLOCK *****
-*/
-
-/* This is the Blender.BGL part of opy_draw.c, from the old bpython/intern
- * dir, with minor changes to adapt it to the new Python implementation.
- * The BGL submodule "wraps" OpenGL functions and constants, allowing script
- * writers to make OpenGL calls in their Python scripts for Blender. The
- * more important original comments are marked with an @ symbol. */
-
-#ifndef EXPP_BGL_H
-#define EXPP_BGL_H
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <Python.h>
-#include <GL/glew.h>
-#include "../intern/bpy_compat.h"
-
-PyObject *BGL_Init( const char *from );
-
-/*@ Buffer Object */
-/*@ For Python access to OpenGL functions requiring a pointer. */
-
-typedef struct _Buffer {
- PyObject_VAR_HEAD
- PyObject * parent;
-
- int type; /* GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT */
- int ndimensions;
- int *dimensions;
-
- union {
- char *asbyte;
- short *asshort;
- int *asint;
- float *asfloat;
- double *asdouble;
-
- void *asvoid;
- } buf;
-} Buffer;
-
-
-/*@ By golly George! It looks like fancy pants macro time!!! */
-
-/*
-#define int_str "i"
-#define int_var(number) bgl_int##number
-#define int_ref(number) &bgl_int##number
-#define int_def(number) int int_var(number)
-
-#define float_str "f"
-#define float_var(number) bgl_float##number
-#define float_ref(number) &bgl_float##number
-#define float_def(number) float float_var(number)
-*/
-
-/* TYPE_str is the string to pass to Py_ArgParse (for the format) */
-/* TYPE_var is the name to pass to the GL function */
-/* TYPE_ref is the pointer to pass to Py_ArgParse (to store in) */
-/* TYPE_def is the C initialization of the variable */
-
-#define void_str ""
-#define void_var(num)
-#define void_ref(num) &bgl_var##num
-#define void_def(num) char bgl_var##num
-
-#define buffer_str "O!"
-#define buffer_var(number) (bgl_buffer##number)->buf.asvoid
-#define buffer_ref(number) &buffer_Type, &bgl_buffer##number
-#define buffer_def(number) Buffer *bgl_buffer##number
-
-/* GL Pointer fields, handled by buffer type */
-/* GLdoubleP, GLfloatP, GLintP, GLuintP, GLshortP */
-
-#define GLbooleanP_str "O!"
-#define GLbooleanP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLbooleanP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLbooleanP_def(number) Buffer *bgl_buffer##number
-
-#define GLbyteP_str "O!"
-#define GLbyteP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLbyteP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLbyteP_def(number) Buffer *bgl_buffer##number
-
-#define GLubyteP_str "O!"
-#define GLubyteP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLubyteP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLubyteP_def(number) Buffer *bgl_buffer##number
-
-#define GLintP_str "O!"
-#define GLintP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLintP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLintP_def(number) Buffer *bgl_buffer##number
-
-#define GLuintP_str "O!"
-#define GLuintP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLuintP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLuintP_def(number) Buffer *bgl_buffer##number
-
-#define GLshortP_str "O!"
-#define GLshortP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLshortP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLshortP_def(number) Buffer *bgl_buffer##number
-
-#define GLushortP_str "O!"
-#define GLushortP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLushortP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLushortP_def(number) Buffer *bgl_buffer##number
-
-#define GLfloatP_str "O!"
-#define GLfloatP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLfloatP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLfloatP_def(number) Buffer *bgl_buffer##number
-
-#define GLdoubleP_str "O!"
-#define GLdoubleP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLdoubleP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLdoubleP_def(number) Buffer *bgl_buffer##number
-
-#define GLclampfP_str "O!"
-#define GLclampfP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLclampfP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLclampfP_def(number) Buffer *bgl_buffer##number
-
-#define GLvoidP_str "O!"
-#define GLvoidP_var(number) (bgl_buffer##number)->buf.asvoid
-#define GLvoidP_ref(number) &buffer_Type, &bgl_buffer##number
-#define GLvoidP_def(number) Buffer *bgl_buffer##number
-
-#define buffer_str "O!"
-#define buffer_var(number) (bgl_buffer##number)->buf.asvoid
-#define buffer_ref(number) &buffer_Type, &bgl_buffer##number
-#define buffer_def(number) Buffer *bgl_buffer##number
-
-/*@The standard GL typedefs are used as prototypes, we can't
- * use the GL type directly because Py_ArgParse expects normal
- * C types.
- *
- * Py_ArgParse doesn't grok writing into unsigned variables,
- * so we use signed everything (even stuff that should be unsigned.
- */
-
-/* typedef unsigned int GLenum; */
-#define GLenum_str "i"
-#define GLenum_var(num) bgl_var##num
-#define GLenum_ref(num) &bgl_var##num
-#define GLenum_def(num) /* unsigned */ int GLenum_var(num)
-
-/* typedef unsigned int GLboolean; */
-#define GLboolean_str "b"
-#define GLboolean_var(num) bgl_var##num
-#define GLboolean_ref(num) &bgl_var##num
-#define GLboolean_def(num) /* unsigned */ char GLboolean_var(num)
-
-/* typedef unsigned int GLbitfield; */
-#define GLbitfield_str "i"
-#define GLbitfield_var(num) bgl_var##num
-#define GLbitfield_ref(num) &bgl_var##num
-#define GLbitfield_def(num) /* unsigned */ int GLbitfield_var(num)
-
-/* typedef signed char GLbyte; */
-#define GLbyte_str "b"
-#define GLbyte_var(num) bgl_var##num
-#define GLbyte_ref(num) &bgl_var##num
-#define GLbyte_def(num) signed char GLbyte_var(num)
-
-/* typedef short GLshort; */
-#define GLshort_str "h"
-#define GLshort_var(num) bgl_var##num
-#define GLshort_ref(num) &bgl_var##num
-#define GLshort_def(num) short GLshort_var(num)
-
-/* typedef int GLint; */
-#define GLint_str "i"
-#define GLint_var(num) bgl_var##num
-#define GLint_ref(num) &bgl_var##num
-#define GLint_def(num) int GLint_var(num)
-
-/* typedef int GLsizei; */
-#define GLsizei_str "i"
-#define GLsizei_var(num) bgl_var##num
-#define GLsizei_ref(num) &bgl_var##num
-#define GLsizei_def(num) int GLsizei_var(num)
-
-/* typedef unsigned char GLubyte; */
-#define GLubyte_str "b"
-#define GLubyte_var(num) bgl_var##num
-#define GLubyte_ref(num) &bgl_var##num
-#define GLubyte_def(num) /* unsigned */ char GLubyte_var(num)
-
-/* typedef unsigned short GLushort; */
-#define GLushort_str "h"
-#define GLushort_var(num) bgl_var##num
-#define GLushort_ref(num) &bgl_var##num
-#define GLushort_def(num) /* unsigned */ short GLushort_var(num)
-
-/* typedef unsigned int GLuint; */
-#define GLuint_str "i"
-#define GLuint_var(num) bgl_var##num
-#define GLuint_ref(num) &bgl_var##num
-#define GLuint_def(num) /* unsigned */ int GLuint_var(num)
-
-/* typedef float GLfloat; */
-#define GLfloat_str "f"
-#define GLfloat_var(num) bgl_var##num
-#define GLfloat_ref(num) &bgl_var##num
-#define GLfloat_def(num) float GLfloat_var(num)
-
-/* typedef float GLclampf; */
-#define GLclampf_str "f"
-#define GLclampf_var(num) bgl_var##num
-#define GLclampf_ref(num) &bgl_var##num
-#define GLclampf_def(num) float GLclampf_var(num)
-
-/* typedef double GLdouble; */
-#define GLdouble_str "d"
-#define GLdouble_var(num) bgl_var##num
-#define GLdouble_ref(num) &bgl_var##num
-#define GLdouble_def(num) double GLdouble_var(num)
-
-/* typedef double GLclampd; */
-#define GLclampd_str "d"
-#define GLclampd_var(num) bgl_var##num
-#define GLclampd_ref(num) &bgl_var##num
-#define GLclampd_def(num) double GLclampd_var(num)
-
-/* typedef void GLvoid; */
-/* #define GLvoid_str "" */
-/* #define GLvoid_var(num) bgl_var##num */
-/* #define GLvoid_ref(num) &bgl_var##num */
-/* #define GLvoid_def(num) char bgl_var##num */
-
-#define arg_def1(a1) a1##_def(1)
-#define arg_def2(a1, a2) arg_def1(a1); a2##_def(2)
-#define arg_def3(a1, a2, a3) arg_def2(a1, a2); a3##_def(3)
-#define arg_def4(a1, a2, a3, a4) arg_def3(a1, a2, a3); a4##_def(4)
-#define arg_def5(a1, a2, a3, a4, a5) arg_def4(a1, a2, a3, a4); a5##_def(5)
-#define arg_def6(a1, a2, a3, a4, a5, a6)arg_def5(a1, a2, a3, a4, a5); a6##_def(6)
-#define arg_def7(a1, a2, a3, a4, a5, a6, a7)arg_def6(a1, a2, a3, a4, a5, a6); a7##_def(7)
-#define arg_def8(a1, a2, a3, a4, a5, a6, a7, a8)arg_def7(a1, a2, a3, a4, a5, a6, a7); a8##_def(8)
-#define arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_def8(a1, a2, a3, a4, a5, a6, a7, a8); a9##_def(9)
-#define arg_def10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9); a10##_def(10)
-
-#define arg_var1(a1) a1##_var(1)
-#define arg_var2(a1, a2) arg_var1(a1), a2##_var(2)
-#define arg_var3(a1, a2, a3) arg_var2(a1, a2), a3##_var(3)
-#define arg_var4(a1, a2, a3, a4) arg_var3(a1, a2, a3), a4##_var(4)
-#define arg_var5(a1, a2, a3, a4, a5) arg_var4(a1, a2, a3, a4), a5##_var(5)
-#define arg_var6(a1, a2, a3, a4, a5, a6)arg_var5(a1, a2, a3, a4, a5), a6##_var(6)
-#define arg_var7(a1, a2, a3, a4, a5, a6, a7)arg_var6(a1, a2, a3, a4, a5, a6), a7##_var(7)
-#define arg_var8(a1, a2, a3, a4, a5, a6, a7, a8)arg_var7(a1, a2, a3, a4, a5, a6, a7), a8##_var(8)
-#define arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_var8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_var(9)
-#define arg_var10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_var(10)
-
-#define arg_ref1(a1) a1##_ref(1)
-#define arg_ref2(a1, a2) arg_ref1(a1), a2##_ref(2)
-#define arg_ref3(a1, a2, a3) arg_ref2(a1, a2), a3##_ref(3)
-#define arg_ref4(a1, a2, a3, a4) arg_ref3(a1, a2, a3), a4##_ref(4)
-#define arg_ref5(a1, a2, a3, a4, a5) arg_ref4(a1, a2, a3, a4), a5##_ref(5)
-#define arg_ref6(a1, a2, a3, a4, a5, a6)arg_ref5(a1, a2, a3, a4, a5), a6##_ref(6)
-#define arg_ref7(a1, a2, a3, a4, a5, a6, a7)arg_ref6(a1, a2, a3, a4, a5, a6), a7##_ref(7)
-#define arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8)arg_ref7(a1, a2, a3, a4, a5, a6, a7), a8##_ref(8)
-#define arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_ref(9)
-#define arg_ref10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_ref(10)
-
-#define arg_str1(a1) a1##_str
-#define arg_str2(a1, a2) arg_str1(a1) a2##_str
-#define arg_str3(a1, a2, a3) arg_str2(a1, a2) a3##_str
-#define arg_str4(a1, a2, a3, a4) arg_str3(a1, a2, a3) a4##_str
-#define arg_str5(a1, a2, a3, a4, a5) arg_str4(a1, a2, a3, a4) a5##_str
-#define arg_str6(a1, a2, a3, a4, a5, a6)arg_str5(a1, a2, a3, a4, a5) a6##_str
-#define arg_str7(a1, a2, a3, a4, a5, a6, a7)arg_str6(a1, a2, a3, a4, a5, a6) a7##_str
-#define arg_str8(a1, a2, a3, a4, a5, a6, a7, a8)arg_str7(a1, a2, a3, a4, a5, a6, a7) a8##_str
-#define arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_str8(a1, a2, a3, a4, a5, a6, a7, a8) a9##_str
-#define arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9) a10##_str
-
-#define ret_def_void
-#define ret_set_void
-/* would use Py_RETURN_NONE - except for py 2.3 doesnt have it */
-#define ret_ret_void { Py_INCREF(Py_None); return Py_None; }
-
-#define ret_def_GLint int ret_int
-#define ret_set_GLint ret_int=
-#define ret_ret_GLint return PyLong_FromLong(ret_int);
-
-#define ret_def_GLuint unsigned int ret_uint
-#define ret_set_GLuint ret_uint=
-#define ret_ret_GLuint return PyLong_FromLong((long) ret_uint);
-
-#define ret_def_GLenum unsigned int ret_uint
-#define ret_set_GLenum ret_uint=
-#define ret_ret_GLenum return PyLong_FromLong((long) ret_uint);
-
-#define ret_def_GLboolean unsigned char ret_bool
-#define ret_set_GLboolean ret_bool=
-#define ret_ret_GLboolean return PyLong_FromLong((long) ret_bool);
-
-#define ret_def_GLstring const unsigned char *ret_str;
-#define ret_set_GLstring ret_str=
-
-#define ret_ret_GLstring \
- if (ret_str) {\
- return PyUnicode_FromString(ret_str);\
- } else {\
- PyErr_SetString(PyExc_AttributeError, "could not get opengl string");\
- return NULL;\
- }
-
-#endif /* EXPP_BGL_H */
diff --git a/source/blender/python/generic/Geometry.c b/source/blender/python/generic/Geometry.c
deleted file mode 100644
index b4a34d30051..00000000000
--- a/source/blender/python/generic/Geometry.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Joseph Gilbert, Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "Geometry.h"
-
-/* - Not needed for now though other geometry functions will probably need them
-#include "BLI_arithb.h"
-#include "BKE_utildefines.h"
-*/
-
-/* Used for PolyFill */
-#include "BKE_displist.h"
-#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
-
-#include "BKE_utildefines.h"
-#include "BKE_curve.h"
-#include "BLI_boxpack2d.h"
-#include "BLI_arithb.h"
-
-#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp
-#define eul 0.000001
-
-/*-- forward declarations -- */
-static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq );
-static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args );
-static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args );
-static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args );
-static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args );
-static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args );
-static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args );
-
-
-/*-------------------------DOC STRINGS ---------------------------*/
-static char M_Geometry_doc[] = "The Blender Geometry module\n\n";
-static char M_Geometry_PolyFill_doc[] = "(veclist_list) - takes a list of polylines (each point a vector) and returns the point indicies for a polyline filled with triangles";
-static char M_Geometry_LineIntersect2D_doc[] = "(lineA_p1, lineA_p2, lineB_p1, lineB_p2) - takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None";
-static char M_Geometry_ClosestPointOnLine_doc[] = "(pt, line_p1, line_p2) - takes a point and a line and returns a (Vector, float) for the point on the line, and the bool so you can know if the point was between the 2 points";
-static char M_Geometry_PointInTriangle2D_doc[] = "(pt, tri_p1, tri_p2, tri_p3) - takes 4 vectors, one is the point and the next 3 define the triangle, only the x and y are used from the vectors";
-static char M_Geometry_PointInQuad2D_doc[] = "(pt, quad_p1, quad_p2, quad_p3, quad_p4) - takes 5 vectors, one is the point and the next 4 define the quad, only the x and y are used from the vectors";
-static char M_Geometry_BoxPack2D_doc[] = "";
-static char M_Geometry_BezierInterp_doc[] = "";
-/*-----------------------METHOD DEFINITIONS ----------------------*/
-struct PyMethodDef M_Geometry_methods[] = {
- {"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc},
- {"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc},
- {"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc},
- {"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc},
- {"PointInQuad2D", ( PyCFunction ) M_Geometry_PointInQuad2D, METH_VARARGS, M_Geometry_PointInQuad2D_doc},
- {"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc},
- {"BezierInterp", ( PyCFunction ) M_Geometry_BezierInterp, METH_VARARGS, M_Geometry_BezierInterp_doc},
- {NULL, NULL, 0, NULL}
-};
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static struct PyModuleDef M_Geometry_module_def = {
- PyModuleDef_HEAD_INIT,
- "Geometry", /* m_name */
- M_Geometry_doc, /* m_doc */
- 0, /* m_size */
- M_Geometry_methods, /* m_methods */
- 0, /* m_reload */
- 0, /* m_traverse */
- 0, /* m_clear */
- 0, /* m_free */
-};
-#endif
-
-/*----------------------------MODULE INIT-------------------------*/
-PyObject *Geometry_Init(const char *from)
-{
- PyObject *submodule;
-
-#if (PY_VERSION_HEX >= 0x03000000)
- submodule = PyModule_Create(&M_Geometry_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), M_Geometry_module_def.m_name, submodule);
-#else
- submodule = Py_InitModule3(from, M_Geometry_methods, M_Geometry_doc);
-#endif
-
- return (submodule);
-}
-
-/*----------------------------------Geometry.PolyFill() -------------------*/
-/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */
-static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq )
-{
- PyObject *tri_list; /*return this list of tri's */
- PyObject *polyLine, *polyVec;
- int i, len_polylines, len_polypoints, ls_error = 0;
-
- /* display listbase */
- ListBase dispbase={NULL, NULL};
- DispList *dl;
- float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
- int index, *dl_face, totpoints=0;
-
-
- dispbase.first= dispbase.last= NULL;
-
-
- if(!PySequence_Check(polyLineSeq)) {
- PyErr_SetString( PyExc_TypeError, "expected a sequence of poly lines" );
- return NULL;
- }
-
- len_polylines = PySequence_Size( polyLineSeq );
-
- for( i = 0; i < len_polylines; ++i ) {
- polyLine= PySequence_GetItem( polyLineSeq, i );
- if (!PySequence_Check(polyLine)) {
- freedisplist(&dispbase);
- Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
- PyErr_SetString( PyExc_TypeError, "One or more of the polylines is not a sequence of Mathutils.Vector's" );
- return NULL;
- }
-
- len_polypoints= PySequence_Size( polyLine );
- if (len_polypoints>0) { /* dont bother adding edges as polylines */
-#if 0
- if (EXPP_check_sequence_consistency( polyLine, &vector_Type ) != 1) {
- freedisplist(&dispbase);
- Py_DECREF(polyLine);
- PyErr_SetString( PyExc_TypeError, "A point in one of the polylines is not a Mathutils.Vector type" );
- return NULL;
- }
-#endif
- dl= MEM_callocN(sizeof(DispList), "poly disp");
- BLI_addtail(&dispbase, dl);
- dl->type= DL_INDEX3;
- dl->nr= len_polypoints;
- dl->type= DL_POLY;
- dl->parts= 1; /* no faces, 1 edge loop */
- dl->col= 0; /* no material */
- dl->verts= fp= MEM_callocN( sizeof(float)*3*len_polypoints, "dl verts");
- dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index");
-
- for( index = 0; index<len_polypoints; ++index, fp+=3) {
- polyVec= PySequence_GetItem( polyLine, index );
- if(VectorObject_Check(polyVec)) {
-
- if(!BaseMath_ReadCallback((VectorObject *)polyVec))
- ls_error= 1;
-
- fp[0] = ((VectorObject *)polyVec)->vec[0];
- fp[1] = ((VectorObject *)polyVec)->vec[1];
- if( ((VectorObject *)polyVec)->size > 2 )
- fp[2] = ((VectorObject *)polyVec)->vec[2];
- else
- fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */
- }
- else {
- ls_error= 1;
- }
-
- totpoints++;
- Py_DECREF(polyVec);
- }
- }
- Py_DECREF(polyLine);
- }
-
- if(ls_error) {
- freedisplist(&dispbase); /* possible some dl was allocated */
- PyErr_SetString( PyExc_TypeError, "A point in one of the polylines is not a Mathutils.Vector type" );
- return NULL;
- }
- else if (totpoints) {
- /* now make the list to return */
- filldisplist(&dispbase, &dispbase);
-
- /* The faces are stored in a new DisplayList
- thats added to the head of the listbase */
- dl= dispbase.first;
-
- tri_list= PyList_New(dl->parts);
- if( !tri_list ) {
- freedisplist(&dispbase);
- PyErr_SetString( PyExc_RuntimeError, "Geometry.PolyFill failed to make a new list" );
- return NULL;
- }
-
- index= 0;
- dl_face= dl->index;
- while(index < dl->parts) {
- PyList_SetItem(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]) );
- dl_face+= 3;
- index++;
- }
- freedisplist(&dispbase);
- } else {
- /* no points, do this so scripts dont barf */
- freedisplist(&dispbase); /* possible some dl was allocated */
- tri_list= PyList_New(0);
- }
-
- return tri_list;
-}
-
-
-static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args )
-{
- VectorObject *line_a1, *line_a2, *line_b1, *line_b2;
- float a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, xi, yi, a1,a2,b1,b2, newvec[2];
- if( !PyArg_ParseTuple ( args, "O!O!O!O!",
- &vector_Type, &line_a1,
- &vector_Type, &line_a2,
- &vector_Type, &line_b1,
- &vector_Type, &line_b2)
- ) {
- PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(line_a1) || !BaseMath_ReadCallback(line_a2) || !BaseMath_ReadCallback(line_b1) || !BaseMath_ReadCallback(line_b2))
- return NULL;
-
- a1x= line_a1->vec[0];
- a1y= line_a1->vec[1];
- a2x= line_a2->vec[0];
- a2y= line_a2->vec[1];
-
- b1x= line_b1->vec[0];
- b1y= line_b1->vec[1];
- b2x= line_b2->vec[0];
- b2y= line_b2->vec[1];
-
- if((MIN2(a1x, a2x) > MAX2(b1x, b2x)) ||
- (MAX2(a1x, a2x) < MIN2(b1x, b2x)) ||
- (MIN2(a1y, a2y) > MAX2(b1y, b2y)) ||
- (MAX2(a1y, a2y) < MIN2(b1y, b2y)) ) {
- Py_RETURN_NONE;
- }
- /* Make sure the hoz/vert line comes first. */
- if (fabs(b1x - b2x) < eul || fabs(b1y - b2y) < eul) {
- SWAP_FLOAT(a1x, b1x, xi); /*abuse xi*/
- SWAP_FLOAT(a1y, b1y, xi);
- SWAP_FLOAT(a2x, b2x, xi);
- SWAP_FLOAT(a2y, b2y, xi);
- }
-
- if (fabs(a1x-a2x) < eul) { /* verticle line */
- if (fabs(b1x-b2x) < eul){ /*verticle second line */
- Py_RETURN_NONE; /* 2 verticle lines dont intersect. */
- }
- else if (fabs(b1y-b2y) < eul) {
- /*X of vert, Y of hoz. no calculation needed */
- newvec[0]= a1x;
- newvec[1]= b1y;
- return newVectorObject(newvec, 2, Py_NEW, NULL);
- }
-
- yi = (float)(((b1y / fabs(b1x - b2x)) * fabs(b2x - a1x)) + ((b2y / fabs(b1x - b2x)) * fabs(b1x - a1x)));
-
- if (yi > MAX2(a1y, a2y)) {/* New point above seg1's vert line */
- Py_RETURN_NONE;
- } else if (yi < MIN2(a1y, a2y)) { /* New point below seg1's vert line */
- Py_RETURN_NONE;
- }
- newvec[0]= a1x;
- newvec[1]= yi;
- return newVectorObject(newvec, 2, Py_NEW, NULL);
- } else if (fabs(a2y-a1y) < eul) { /* hoz line1 */
- if (fabs(b2y-b1y) < eul) { /*hoz line2*/
- Py_RETURN_NONE; /*2 hoz lines dont intersect*/
- }
-
- /* Can skip vert line check for seg 2 since its covered above. */
- xi = (float)(((b1x / fabs(b1y - b2y)) * fabs(b2y - a1y)) + ((b2x / fabs(b1y - b2y)) * fabs(b1y - a1y)));
- if (xi > MAX2(a1x, a2x)) { /* New point right of hoz line1's */
- Py_RETURN_NONE;
- } else if (xi < MIN2(a1x, a2x)) { /*New point left of seg1's hoz line */
- Py_RETURN_NONE;
- }
- newvec[0]= xi;
- newvec[1]= a1y;
- return newVectorObject(newvec, 2, Py_NEW, NULL);
- }
-
- b1 = (a2y-a1y)/(a2x-a1x);
- b2 = (b2y-b1y)/(b2x-b1x);
- a1 = a1y-b1*a1x;
- a2 = b1y-b2*b1x;
-
- if (b1 - b2 == 0.0) {
- Py_RETURN_NONE;
- }
-
- xi = - (a1-a2)/(b1-b2);
- yi = a1+b1*xi;
- if ((a1x-xi)*(xi-a2x) >= 0 && (b1x-xi)*(xi-b2x) >= 0 && (a1y-yi)*(yi-a2y) >= 0 && (b1y-yi)*(yi-b2y)>=0) {
- newvec[0]= xi;
- newvec[1]= yi;
- return newVectorObject(newvec, 2, Py_NEW, NULL);
- }
- Py_RETURN_NONE;
-}
-
-static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args )
-{
- VectorObject *pt, *line_1, *line_2;
- float pt_in[3], pt_out[3], l1[3], l2[3];
- float lambda;
- PyObject *ret;
-
- if( !PyArg_ParseTuple ( args, "O!O!O!",
- &vector_Type, &pt,
- &vector_Type, &line_1,
- &vector_Type, &line_2)
- ) {
- PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(pt) || !BaseMath_ReadCallback(line_1) || !BaseMath_ReadCallback(line_2))
- return NULL;
-
- /* accept 2d verts */
- if (pt->size==3) { VECCOPY(pt_in, pt->vec);}
- else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) }
-
- if (line_1->size==3) { VECCOPY(l1, line_1->vec);}
- else { l1[2]=0.0; VECCOPY2D(l1, line_1->vec) }
-
- if (line_2->size==3) { VECCOPY(l2, line_2->vec);}
- else { l2[2]=0.0; VECCOPY2D(l2, line_2->vec) }
-
- /* do the calculation */
- lambda = lambda_cp_line_ex(pt_in, l1, l2, pt_out);
-
- ret = PyTuple_New(2);
- PyTuple_SET_ITEM( ret, 0, newVectorObject(pt_out, 3, Py_NEW, NULL) );
- PyTuple_SET_ITEM( ret, 1, PyFloat_FromDouble(lambda) );
- return ret;
-}
-
-static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args )
-{
- VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
-
- if( !PyArg_ParseTuple ( args, "O!O!O!O!",
- &vector_Type, &pt_vec,
- &vector_Type, &tri_p1,
- &vector_Type, &tri_p2,
- &vector_Type, &tri_p3)
- ) {
- PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(tri_p1) || !BaseMath_ReadCallback(tri_p2) || !BaseMath_ReadCallback(tri_p3))
- return NULL;
-
- return PyLong_FromLong(IsectPT2Df(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec));
-}
-
-static PyObject *M_Geometry_PointInQuad2D( PyObject * self, PyObject * args )
-{
- VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4;
-
- if( !PyArg_ParseTuple ( args, "O!O!O!O!O!",
- &vector_Type, &pt_vec,
- &vector_Type, &quad_p1,
- &vector_Type, &quad_p2,
- &vector_Type, &quad_p3,
- &vector_Type, &quad_p4)
- ) {
- PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(pt_vec) || !BaseMath_ReadCallback(quad_p1) || !BaseMath_ReadCallback(quad_p2) || !BaseMath_ReadCallback(quad_p3) || !BaseMath_ReadCallback(quad_p4))
- return NULL;
-
- return PyLong_FromLong(IsectPQ2Df(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec));
-}
-
-static int boxPack_FromPyObject(PyObject * value, boxPack **boxarray )
-{
- int len, i;
- PyObject *list_item, *item_1, *item_2;
- boxPack *box;
-
-
- /* Error checking must alredy be done */
- if( !PyList_Check( value ) ) {
- PyErr_SetString( PyExc_TypeError, "can only back a list of [x,y,x,w]" );
- return -1;
- }
-
- len = PyList_Size( value );
-
- (*boxarray) = MEM_mallocN( len*sizeof(boxPack), "boxPack box");
-
-
- for( i = 0; i < len; i++ ) {
- list_item = PyList_GET_ITEM( value, i );
- if( !PyList_Check( list_item ) || PyList_Size( list_item ) < 4 ) {
- MEM_freeN(*boxarray);
- PyErr_SetString( PyExc_TypeError, "can only back a list of [x,y,x,w]" );
- return -1;
- }
-
- box = (*boxarray)+i;
-
- item_1 = PyList_GET_ITEM(list_item, 2);
- item_2 = PyList_GET_ITEM(list_item, 3);
-
- if (!PyNumber_Check(item_1) || !PyNumber_Check(item_2)) {
- MEM_freeN(*boxarray);
- PyErr_SetString( PyExc_TypeError, "can only back a list of 2d boxes [x,y,x,w]" );
- return -1;
- }
-
- box->w = (float)PyFloat_AsDouble( item_1 );
- box->h = (float)PyFloat_AsDouble( item_2 );
- box->index = i;
- /* verts will be added later */
- }
- return 0;
-}
-
-static void boxPack_ToPyObject(PyObject * value, boxPack **boxarray)
-{
- int len, i;
- PyObject *list_item;
- boxPack *box;
-
- len = PyList_Size( value );
-
- for( i = 0; i < len; i++ ) {
- box = (*boxarray)+i;
- list_item = PyList_GET_ITEM( value, box->index );
- PyList_SET_ITEM( list_item, 0, PyFloat_FromDouble( box->x ));
- PyList_SET_ITEM( list_item, 1, PyFloat_FromDouble( box->y ));
- }
- MEM_freeN(*boxarray);
-}
-
-
-static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * boxlist )
-{
- boxPack *boxarray = NULL;
- float tot_width, tot_height;
- int len;
- int error;
-
- if(!PyList_Check(boxlist)) {
- PyErr_SetString( PyExc_TypeError, "expected a sequence of boxes [[x,y,w,h], ... ]" );
- return NULL;
- }
-
- len = PyList_Size( boxlist );
-
- if (!len)
- return Py_BuildValue( "ff", 0.0, 0.0);
-
- error = boxPack_FromPyObject(boxlist, &boxarray);
- if (error!=0) return NULL;
-
- /* Non Python function */
- boxPack2D(boxarray, len, &tot_width, &tot_height);
-
- boxPack_ToPyObject(boxlist, &boxarray);
-
- return Py_BuildValue( "ff", tot_width, tot_height);
-}
-
-static PyObject *M_Geometry_BezierInterp( PyObject * self, PyObject * args )
-{
- VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2;
- int resolu;
- int dims;
- int i;
- float *coord_array, *fp;
- PyObject *list;
-
- float k1[4] = {0.0, 0.0, 0.0, 0.0};
- float h1[4] = {0.0, 0.0, 0.0, 0.0};
- float k2[4] = {0.0, 0.0, 0.0, 0.0};
- float h2[4] = {0.0, 0.0, 0.0, 0.0};
-
-
- if( !PyArg_ParseTuple ( args, "O!O!O!O!i",
- &vector_Type, &vec_k1,
- &vector_Type, &vec_h1,
- &vector_Type, &vec_h2,
- &vector_Type, &vec_k2, &resolu) || (resolu<=1)
- ) {
- PyErr_SetString( PyExc_TypeError, "expected 4 vector types and an int greater then 1\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec_k1) || !BaseMath_ReadCallback(vec_h1) || !BaseMath_ReadCallback(vec_k2) || !BaseMath_ReadCallback(vec_h2))
- return NULL;
-
- dims= MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size);
-
- for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i];
- for(i=0; i < vec_h1->size; i++) h1[i]= vec_h1->vec[i];
- for(i=0; i < vec_k2->size; i++) k2[i]= vec_k2->vec[i];
- for(i=0; i < vec_h2->size; i++) h2[i]= vec_h2->vec[i];
-
- coord_array = MEM_callocN(dims * (resolu) * sizeof(float), "BezierInterp");
- for(i=0; i<dims; i++) {
- forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array+i, resolu-1, dims);
- }
-
- list= PyList_New(resolu);
- fp= coord_array;
- for(i=0; i<resolu; i++, fp= fp+dims) {
- PyList_SET_ITEM(list, i, newVectorObject(fp, dims, Py_NEW, NULL));
- }
- MEM_freeN(coord_array);
- return list;
-}
diff --git a/source/blender/python/generic/Geometry.h b/source/blender/python/generic/Geometry.h
deleted file mode 100644
index ebfb054c54a..00000000000
--- a/source/blender/python/generic/Geometry.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
-*/
-/*Include this file for access to vector, quat, matrix, euler, etc...*/
-
-#ifndef EXPP_Geometry_H
-#define EXPP_Geometry_H
-
-#include <Python.h>
-#include "Mathutils.h"
-
-PyObject *Geometry_Init( const char *from );
-
-#endif /* EXPP_Geometry_H */
diff --git a/source/blender/python/generic/Makefile b/source/blender/python/generic/Makefile
deleted file mode 100644
index 0dbfbd1d102..00000000000
--- a/source/blender/python/generic/Makefile
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# $Id$
-#
-# ***** BEGIN GPL LICENSE BLOCK *****
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): none yet.
-#
-# ***** END GPL LICENSE BLOCK *****
-#
-#
-
-LIBNAME = gen_python
-DIR = $(OCGDIR)/blender/$(LIBNAME)
-
-include nan_compile.mk
-
-CFLAGS += $(LEVEL_1_C_WARNINGS)
-
-# OpenGL and Python
-CPPFLAGS += -I$(NAN_GLEW)/include
-CPPFLAGS += $(OGL_CPPFLAGS)
-CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
-
-# PreProcessor stuff
-
-CPPFLAGS += -I$(NAN_GHOST)/include
-CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include $(NAN_SDLCFLAGS)
-
-# modules
-CPPFLAGS += -I../../editors/include
-CPPFLAGS += -I../../python
-CPPFLAGS += -I../../makesdna
-CPPFLAGS += -I../../makesrna
-CPPFLAGS += -I../../blenlib
-CPPFLAGS += -I../../blenkernel
-CPPFLAGS += -I../../nodes
-CPPFLAGS += -I../../imbuf
-CPPFLAGS += -I../../blenloader
-CPPFLAGS += -I../../windowmanager
-CPPFLAGS += -I../../render/extern/include
-
-# path to the guarded memory allocator
-CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
-CPPFLAGS += -I$(NAN_MEMUTIL)/include
-
-# path to our own headerfiles
-CPPFLAGS += -I..
diff --git a/source/blender/python/generic/Mathutils.c b/source/blender/python/generic/Mathutils.c
deleted file mode 100644
index 53077659655..00000000000
--- a/source/blender/python/generic/Mathutils.c
+++ /dev/null
@@ -1,1266 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Joseph Gilbert, Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "Mathutils.h"
-
-#include "BLI_arithb.h"
-#include "PIL_time.h"
-#include "BLI_rand.h"
-#include "BKE_utildefines.h"
-
-//-------------------------DOC STRINGS ---------------------------
-static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n";
-static char M_Mathutils_Rand_doc[] = "() - return a random number";
-static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees";
-static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors";
-static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB";
-static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation";
-static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor";
-static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane";
-static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor";
-static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector";
-static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions";
-static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats";
-static char M_Mathutils_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise";
-static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined";
-static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined";
-static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined";
-static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other";
-//-----------------------METHOD DEFINITIONS ----------------------
-
-static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value);
-static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args);
-static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args );
-static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args );
-static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args );
-static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args );
-static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args );
-
-struct PyMethodDef M_Mathutils_methods[] = {
- {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc},
- {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc},
- {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc},
- {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc},
- {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc},
- {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc},
- {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc},
- {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc},
- {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc},
- {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc},
- {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc},
- {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc},
- {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc},
- {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc},
- {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc},
- {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc},
- {NULL, NULL, 0, NULL}
-};
-
-/*----------------------------MODULE INIT-------------------------*/
-/* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static struct PyModuleDef M_Mathutils_module_def = {
- PyModuleDef_HEAD_INIT,
- "Mathutils", /* m_name */
- M_Mathutils_doc, /* m_doc */
- 0, /* m_size */
- M_Mathutils_methods, /* m_methods */
- 0, /* m_reload */
- 0, /* m_traverse */
- 0, /* m_clear */
- 0, /* m_free */
-};
-#endif
-
-PyObject *Mathutils_Init(const char *from)
-{
- PyObject *submodule;
-
- //seed the generator for the rand function
- BLI_srand((unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF));
-
-#if (PY_VERSION_HEX < 0x03000000)
- vector_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
- matrix_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
- euler_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
- quaternion_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
-#endif
-
- if( PyType_Ready( &vector_Type ) < 0 )
- return NULL;
- if( PyType_Ready( &matrix_Type ) < 0 )
- return NULL;
- if( PyType_Ready( &euler_Type ) < 0 )
- return NULL;
- if( PyType_Ready( &quaternion_Type ) < 0 )
- return NULL;
-
-#if (PY_VERSION_HEX >= 0x03000000)
- submodule = PyModule_Create(&M_Mathutils_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), M_Mathutils_module_def.m_name, submodule);
-#else
- submodule = Py_InitModule3(from, M_Mathutils_methods, M_Mathutils_doc);
-#endif
-
- /* each type has its own new() function */
- PyModule_AddObject( submodule, "Vector", (PyObject *)&vector_Type );
- PyModule_AddObject( submodule, "Matrix", (PyObject *)&matrix_Type );
- PyModule_AddObject( submodule, "Euler", (PyObject *)&euler_Type );
- PyModule_AddObject( submodule, "Quaternion", (PyObject *)&quaternion_Type );
-
- mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb);
-
- return (submodule);
-}
-
-//-----------------------------METHODS----------------------------
-//-----------------quat_rotation (internal)-----------
-//This function multiplies a vector/point * quat or vice versa
-//to rotate the point/vector by the quaternion
-//arguments should all be 3D
-PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
-{
- float rot[3];
- QuaternionObject *quat = NULL;
- VectorObject *vec = NULL;
-
- if(QuaternionObject_Check(arg1)){
- quat = (QuaternionObject*)arg1;
- if(!BaseMath_ReadCallback(quat))
- return NULL;
-
- if(VectorObject_Check(arg2)){
- vec = (VectorObject*)arg2;
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
- 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
- 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
- quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
- rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
- 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
- quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
- 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
- rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
- quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
- quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
- quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
- return newVectorObject(rot, 3, Py_NEW, NULL);
- }
- }else if(VectorObject_Check(arg1)){
- vec = (VectorObject*)arg1;
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- if(QuaternionObject_Check(arg2)){
- quat = (QuaternionObject*)arg2;
- if(!BaseMath_ReadCallback(quat))
- return NULL;
-
- rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
- 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
- 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
- quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
- rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
- 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
- quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
- 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
- rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
- quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
- quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
- quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
- return newVectorObject(rot, 3, Py_NEW, NULL);
- }
- }
-
- PyErr_SetString(PyExc_RuntimeError, "quat_rotation(internal): internal problem rotating vector/point\n");
- return NULL;
-
-}
-
-//----------------------------------Mathutils.Rand() --------------------
-//returns a random number between a high and low value
-static PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args)
-{
- float high, low, range;
- double drand;
- //initializers
- high = 1.0;
- low = 0.0;
-
- if(!PyArg_ParseTuple(args, "|ff", &low, &high)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.Rand(): expected nothing or optional (float, float)\n");
- return NULL;
- }
-
- if((high < low) || (high < 0 && low > 0)) {
- PyErr_SetString(PyExc_ValueError, "Mathutils.Rand(): high value should be larger than low value\n");
- return NULL;
- }
- //get the random number 0 - 1
- drand = BLI_drand();
-
- //set it to range
- range = high - low;
- drand = drand * range;
- drand = drand + low;
-
- return PyFloat_FromDouble(drand);
-}
-//----------------------------------VECTOR FUNCTIONS---------------------
-//----------------------------------Mathutils.AngleBetweenVecs() ---------
-//calculates the angle between 2 vectors
-static PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
-{
- VectorObject *vec1 = NULL, *vec2 = NULL;
- double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f;
- int x, size;
-
- if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
- goto AttributeError1; //not vectors
- if(vec1->size != vec2->size)
- goto AttributeError1; //bad sizes
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
- return NULL;
-
- //since size is the same....
- size = vec1->size;
-
- for(x = 0; x < size; x++) {
- test_v1 += vec1->vec[x] * vec1->vec[x];
- test_v2 += vec2->vec[x] * vec2->vec[x];
- }
- if (!test_v1 || !test_v2){
- goto AttributeError2; //zero-length vector
- }
-
- //dot product
- for(x = 0; x < size; x++) {
- dot += vec1->vec[x] * vec2->vec[x];
- }
- dot /= (sqrt(test_v1) * sqrt(test_v2));
-
- angleRads = (double)saacos(dot);
-
-#ifdef USE_MATHUTILS_DEG
- return PyFloat_FromDouble(angleRads * (180/ Py_PI));
-#else
- return PyFloat_FromDouble(angleRads);
-#endif
-AttributeError1:
- PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n");
- return NULL;
-
-AttributeError2:
- PyErr_SetString(PyExc_AttributeError, "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n");
- return NULL;
-}
-//----------------------------------Mathutils.MidpointVecs() -------------
-//calculates the midpoint between 2 vectors
-static PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args)
-{
- VectorObject *vec1 = NULL, *vec2 = NULL;
- float vec[4];
- int x;
-
- if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
- return NULL;
- }
- if(vec1->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
- return NULL;
-
- for(x = 0; x < vec1->size; x++) {
- vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]);
- }
- return newVectorObject(vec, vec1->size, Py_NEW, NULL);
-}
-//----------------------------------Mathutils.ProjectVecs() -------------
-//projects vector 1 onto vector 2
-static PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args)
-{
- VectorObject *vec1 = NULL, *vec2 = NULL;
- float vec[4];
- double dot = 0.0f, dot2 = 0.0f;
- int x, size;
-
- if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
- return NULL;
- }
- if(vec1->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
- return NULL;
-
-
- //since they are the same size...
- size = vec1->size;
-
- //get dot products
- for(x = 0; x < size; x++) {
- dot += vec1->vec[x] * vec2->vec[x];
- dot2 += vec2->vec[x] * vec2->vec[x];
- }
- //projection
- dot /= dot2;
- for(x = 0; x < size; x++) {
- vec[x] = (float)(dot * vec2->vec[x]);
- }
- return newVectorObject(vec, size, Py_NEW, NULL);
-}
-//----------------------------------MATRIX FUNCTIONS--------------------
-//----------------------------------Mathutils.RotationMatrix() ----------
-//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
-//creates a rotation matrix
-static PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
-{
- VectorObject *vec = NULL;
- char *axis = NULL;
- int matSize;
- float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!PyArg_ParseTuple(args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.RotationMatrix(): expected float int and optional string and vector\n");
- return NULL;
- }
-
-#ifdef USE_MATHUTILS_DEG
- /* Clamp to -360:360 */
- while (angle<-360.0f)
- angle+=360.0;
- while (angle>360.0f)
- angle-=360.0;
-#else
- while (angle<-(Py_PI*2))
- angle+=(Py_PI*2);
- while (angle>(Py_PI*2))
- angle-=(Py_PI*2);
-#endif
-
- if(matSize != 2 && matSize != 3 && matSize != 4) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
- return NULL;
- }
- if(matSize == 2 && (axis != NULL || vec != NULL)) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n");
- return NULL;
- }
- if((matSize == 3 || matSize == 4) && axis == NULL) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n");
- return NULL;
- }
- if(axis) {
- if(((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) && vec == NULL) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n");
- return NULL;
- }
- }
- if(vec) {
- if(vec->size != 3) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- }
-#ifdef USE_MATHUTILS_DEG
- //convert to radians
- angle = angle * (float) (Py_PI / 180);
-#endif
-
- if(axis == NULL && matSize == 2) {
- //2D rotation matrix
- mat[0] = (float) cos (angle);
- mat[1] = (float) sin (angle);
- mat[2] = -((float) sin(angle));
- mat[3] = (float) cos(angle);
- } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) {
- //rotation around X
- mat[0] = 1.0f;
- mat[4] = (float) cos(angle);
- mat[5] = (float) sin(angle);
- mat[7] = -((float) sin(angle));
- mat[8] = (float) cos(angle);
- } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) {
- //rotation around Y
- mat[0] = (float) cos(angle);
- mat[2] = -((float) sin(angle));
- mat[4] = 1.0f;
- mat[6] = (float) sin(angle);
- mat[8] = (float) cos(angle);
- } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) {
- //rotation around Z
- mat[0] = (float) cos(angle);
- mat[1] = (float) sin(angle);
- mat[3] = -((float) sin(angle));
- mat[4] = (float) cos(angle);
- mat[8] = 1.0f;
- } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) {
- //arbitrary rotation
- //normalize arbitrary axis
- norm = (float) sqrt(vec->vec[0] * vec->vec[0] +
- vec->vec[1] * vec->vec[1] +
- vec->vec[2] * vec->vec[2]);
- vec->vec[0] /= norm;
- vec->vec[1] /= norm;
- vec->vec[2] /= norm;
-
- if (isnan(vec->vec[0]) || isnan(vec->vec[1]) || isnan(vec->vec[2])) {
- /* zero length vector, return an identity matrix, could also return an error */
- mat[0]= mat[4] = mat[8] = 1.0f;
- } else {
- /* create matrix */
- cosAngle = (float) cos(angle);
- sinAngle = (float) sin(angle);
- mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) +
- cosAngle;
- mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) +
- (vec->vec[2] * sinAngle);
- mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) -
- (vec->vec[1] * sinAngle);
- mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) -
- (vec->vec[2] * sinAngle);
- mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) +
- cosAngle;
- mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) +
- (vec->vec[0] * sinAngle);
- mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) +
- (vec->vec[1] * sinAngle);
- mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) -
- (vec->vec[0] * sinAngle);
- mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) +
- cosAngle;
- }
- } else {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n");
- return NULL;
- }
- if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
- }
- //pass to matrix creation
- return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL);
-}
-//----------------------------------Mathutils.TranslationMatrix() -------
-//creates a translation matrix
-static PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec)
-{
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!VectorObject_Check(vec)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): expected vector\n");
- return NULL;
- }
- if(vec->size != 3 && vec->size != 4) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- //create a identity matrix and add translation
- Mat4One((float(*)[4]) mat);
- mat[12] = vec->vec[0];
- mat[13] = vec->vec[1];
- mat[14] = vec->vec[2];
-
- return newMatrixObject(mat, 4, 4, Py_NEW, NULL);
-}
-//----------------------------------Mathutils.ScaleMatrix() -------------
-//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
-//creates a scaling matrix
-static PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args)
-{
- VectorObject *vec = NULL;
- float norm = 0.0f, factor;
- int matSize, x;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!PyArg_ParseTuple(args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.ScaleMatrix(): expected float int and optional vector\n");
- return NULL;
- }
- if(matSize != 2 && matSize != 3 && matSize != 4) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
- return NULL;
- }
- if(vec) {
- if(vec->size > 2 && matSize == 2) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- }
- if(vec == NULL) { //scaling along axis
- if(matSize == 2) {
- mat[0] = factor;
- mat[3] = factor;
- } else {
- mat[0] = factor;
- mat[4] = factor;
- mat[8] = factor;
- }
- } else { //scaling in arbitrary direction
- //normalize arbitrary axis
- for(x = 0; x < vec->size; x++) {
- norm += vec->vec[x] * vec->vec[x];
- }
- norm = (float) sqrt(norm);
- for(x = 0; x < vec->size; x++) {
- vec->vec[x] /= norm;
- }
- if(matSize == 2) {
- mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0]));
- mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
- } else {
- mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0]));
- mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
- mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
- mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
- mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
- mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
- mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2]));
- }
- }
- if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
- }
- //pass to matrix creation
- return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL);
-}
-//----------------------------------Mathutils.OrthoProjectionMatrix() ---
-//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
-//creates an ortho projection matrix
-static PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args)
-{
- VectorObject *vec = NULL;
- char *plane;
- int matSize, x;
- float norm = 0.0f;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!PyArg_ParseTuple(args, "si|O!", &plane, &matSize, &vector_Type, &vec)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n");
- return NULL;
- }
- if(matSize != 2 && matSize != 3 && matSize != 4) {
- PyErr_SetString(PyExc_AttributeError,"Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
- return NULL;
- }
- if(vec) {
- if(vec->size > 2 && matSize == 2) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- }
- if(vec == NULL) { //ortho projection onto cardinal plane
- if(((strcmp(plane, "x") == 0)
- || (strcmp(plane, "X") == 0)) && matSize == 2) {
- mat[0] = 1.0f;
- } else if(((strcmp(plane, "y") == 0)
- || (strcmp(plane, "Y") == 0))
- && matSize == 2) {
- mat[3] = 1.0f;
- } else if(((strcmp(plane, "xy") == 0)
- || (strcmp(plane, "XY") == 0))
- && matSize > 2) {
- mat[0] = 1.0f;
- mat[4] = 1.0f;
- } else if(((strcmp(plane, "xz") == 0)
- || (strcmp(plane, "XZ") == 0))
- && matSize > 2) {
- mat[0] = 1.0f;
- mat[8] = 1.0f;
- } else if(((strcmp(plane, "yz") == 0)
- || (strcmp(plane, "YZ") == 0))
- && matSize > 2) {
- mat[4] = 1.0f;
- mat[8] = 1.0f;
- } else {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n");
- return NULL;
- }
- } else { //arbitrary plane
- //normalize arbitrary axis
- for(x = 0; x < vec->size; x++) {
- norm += vec->vec[x] * vec->vec[x];
- }
- norm = (float) sqrt(norm);
- for(x = 0; x < vec->size; x++) {
- vec->vec[x] /= norm;
- }
- if(((strcmp(plane, "r") == 0)
- || (strcmp(plane, "R") == 0)) && matSize == 2) {
- mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
- mat[1] = -(vec->vec[0] * vec->vec[1]);
- mat[2] = -(vec->vec[0] * vec->vec[1]);
- mat[3] = 1 - (vec->vec[1] * vec->vec[1]);
- } else if(((strcmp(plane, "r") == 0)
- || (strcmp(plane, "R") == 0))
- && matSize > 2) {
- mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
- mat[1] = -(vec->vec[0] * vec->vec[1]);
- mat[2] = -(vec->vec[0] * vec->vec[2]);
- mat[3] = -(vec->vec[0] * vec->vec[1]);
- mat[4] = 1 - (vec->vec[1] * vec->vec[1]);
- mat[5] = -(vec->vec[1] * vec->vec[2]);
- mat[6] = -(vec->vec[0] * vec->vec[2]);
- mat[7] = -(vec->vec[1] * vec->vec[2]);
- mat[8] = 1 - (vec->vec[2] * vec->vec[2]);
- } else {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n");
- return NULL;
- }
- }
- if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
- }
- //pass to matrix creation
- return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL);
-}
-//----------------------------------Mathutils.ShearMatrix() -------------
-//creates a shear matrix
-static PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args)
-{
- int matSize;
- char *plane;
- float factor;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) {
- PyErr_SetString(PyExc_TypeError,"Mathutils.ShearMatrix(): expected string float and int\n");
- return NULL;
- }
- if(matSize != 2 && matSize != 3 && matSize != 4) {
- PyErr_SetString(PyExc_AttributeError,"Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
- return NULL;
- }
-
- if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0))
- && matSize == 2) {
- mat[0] = 1.0f;
- mat[2] = factor;
- mat[3] = 1.0f;
- } else if(((strcmp(plane, "y") == 0)
- || (strcmp(plane, "Y") == 0)) && matSize == 2) {
- mat[0] = 1.0f;
- mat[1] = factor;
- mat[3] = 1.0f;
- } else if(((strcmp(plane, "xy") == 0)
- || (strcmp(plane, "XY") == 0)) && matSize > 2) {
- mat[0] = 1.0f;
- mat[4] = 1.0f;
- mat[6] = factor;
- mat[7] = factor;
- } else if(((strcmp(plane, "xz") == 0)
- || (strcmp(plane, "XZ") == 0)) && matSize > 2) {
- mat[0] = 1.0f;
- mat[3] = factor;
- mat[4] = 1.0f;
- mat[5] = factor;
- mat[8] = 1.0f;
- } else if(((strcmp(plane, "yz") == 0)
- || (strcmp(plane, "YZ") == 0)) && matSize > 2) {
- mat[0] = 1.0f;
- mat[1] = factor;
- mat[2] = factor;
- mat[4] = 1.0f;
- mat[8] = 1.0f;
- } else {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n");
- return NULL;
- }
- if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
- }
- //pass to matrix creation
- return newMatrixObject(mat, matSize, matSize, Py_NEW, NULL);
-}
-//----------------------------------QUATERNION FUNCTIONS-----------------
-
-//----------------------------------Mathutils.DifferenceQuats() ---------
-//returns the difference between 2 quaternions
-static PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args)
-{
- QuaternionObject *quatU = NULL, *quatV = NULL;
- float quat[4], tempQuat[4];
- double dot = 0.0f;
- int x;
-
- if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU, &quaternion_Type, &quatV)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV))
- return NULL;
-
- tempQuat[0] = quatU->quat[0];
- tempQuat[1] = -quatU->quat[1];
- tempQuat[2] = -quatU->quat[2];
- tempQuat[3] = -quatU->quat[3];
-
- dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] +
- tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]);
-
- for(x = 0; x < 4; x++) {
- tempQuat[x] /= (float)(dot * dot);
- }
- QuatMul(quat, tempQuat, quatV->quat);
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-//----------------------------------Mathutils.Slerp() ------------------
-//attemps to interpolate 2 quaternions and return the result
-static PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args)
-{
- QuaternionObject *quatU = NULL, *quatV = NULL;
- float quat[4], quat_u[4], quat_v[4], param;
- double x, y, dot, sinT, angle, IsinT;
- int z;
-
- if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type, &quatU, &quaternion_Type, &quatV, &param)) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.Slerp(): expected Quaternion types and float");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(quatU) || !BaseMath_ReadCallback(quatV))
- return NULL;
-
- if(param > 1.0f || param < 0.0f) {
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0");
- return NULL;
- }
-
- //copy quats
- for(z = 0; z < 4; z++){
- quat_u[z] = quatU->quat[z];
- quat_v[z] = quatV->quat[z];
- }
-
- //dot product
- dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] +
- quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3];
-
- //if negative negate a quat (shortest arc)
- if(dot < 0.0f) {
- quat_v[0] = -quat_v[0];
- quat_v[1] = -quat_v[1];
- quat_v[2] = -quat_v[2];
- quat_v[3] = -quat_v[3];
- dot = -dot;
- }
- if(dot > .99999f) { //very close
- x = 1.0f - param;
- y = param;
- } else {
- //calculate sin of angle
- sinT = sqrt(1.0f - (dot * dot));
- //calculate angle
- angle = atan2(sinT, dot);
- //caluculate inverse of sin(theta)
- IsinT = 1.0f / sinT;
- x = sin((1.0f - param) * angle) * IsinT;
- y = sin(param * angle) * IsinT;
- }
- //interpolate
- quat[0] = (float)(quat_u[0] * x + quat_v[0] * y);
- quat[1] = (float)(quat_u[1] * x + quat_v[1] * y);
- quat[2] = (float)(quat_u[2] * x + quat_v[2] * y);
- quat[3] = (float)(quat_u[3] * x + quat_v[3] * y);
-
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-//----------------------------------EULER FUNCTIONS----------------------
-//---------------------------------INTERSECTION FUNCTIONS--------------------
-//----------------------------------Mathutils.Intersect() -------------------
-static PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args )
-{
- VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
- float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
- float det, inv_det, u, v, t;
- int clip = 1;
-
- if(!PyArg_ParseTuple(args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) {
- PyErr_SetString( PyExc_TypeError, "expected 5 vector types\n" );
- return NULL;
- }
- if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) {
- PyErr_SetString( PyExc_TypeError, "only 3D vectors for all parameters\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(ray) || !BaseMath_ReadCallback(ray_off))
- return NULL;
-
- VECCOPY(v1, vec1->vec);
- VECCOPY(v2, vec2->vec);
- VECCOPY(v3, vec3->vec);
-
- VECCOPY(dir, ray->vec);
- Normalize(dir);
-
- VECCOPY(orig, ray_off->vec);
-
- /* find vectors for two edges sharing v1 */
- VecSubf(e1, v2, v1);
- VecSubf(e2, v3, v1);
-
- /* begin calculating determinant - also used to calculated U parameter */
- Crossf(pvec, dir, e2);
-
- /* if determinant is near zero, ray lies in plane of triangle */
- det = Inpf(e1, pvec);
-
- if (det > -0.000001 && det < 0.000001) {
- Py_RETURN_NONE;
- }
-
- inv_det = 1.0f / det;
-
- /* calculate distance from v1 to ray origin */
- VecSubf(tvec, orig, v1);
-
- /* calculate U parameter and test bounds */
- u = Inpf(tvec, pvec) * inv_det;
- if (clip && (u < 0.0f || u > 1.0f)) {
- Py_RETURN_NONE;
- }
-
- /* prepare to test the V parameter */
- Crossf(qvec, tvec, e1);
-
- /* calculate V parameter and test bounds */
- v = Inpf(dir, qvec) * inv_det;
-
- if (clip && (v < 0.0f || u + v > 1.0f)) {
- Py_RETURN_NONE;
- }
-
- /* calculate t, ray intersects triangle */
- t = Inpf(e2, qvec) * inv_det;
-
- VecMulf(dir, t);
- VecAddf(pvec, orig, dir);
-
- return newVectorObject(pvec, 3, Py_NEW, NULL);
-}
-//----------------------------------Mathutils.LineIntersect() -------------------
-/* Line-Line intersection using algorithm from mathworld.wolfram.com */
-static PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args )
-{
- PyObject * tuple;
- VectorObject *vec1, *vec2, *vec3, *vec4;
- float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
-
- if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
- PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
- return NULL;
- }
- if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec2->size) {
- PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
- return NULL;
-
- if( vec1->size == 3 || vec1->size == 2) {
- int result;
-
- if (vec1->size == 3) {
- VECCOPY(v1, vec1->vec);
- VECCOPY(v2, vec2->vec);
- VECCOPY(v3, vec3->vec);
- VECCOPY(v4, vec4->vec);
- }
- else {
- v1[0] = vec1->vec[0];
- v1[1] = vec1->vec[1];
- v1[2] = 0.0f;
-
- v2[0] = vec2->vec[0];
- v2[1] = vec2->vec[1];
- v2[2] = 0.0f;
-
- v3[0] = vec3->vec[0];
- v3[1] = vec3->vec[1];
- v3[2] = 0.0f;
-
- v4[0] = vec4->vec[0];
- v4[1] = vec4->vec[1];
- v4[2] = 0.0f;
- }
-
- result = LineIntersectLine(v1, v2, v3, v4, i1, i2);
-
- if (result == 0) {
- /* colinear */
- Py_RETURN_NONE;
- }
- else {
- tuple = PyTuple_New( 2 );
- PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL) );
- PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL) );
- return tuple;
- }
- }
- else {
- PyErr_SetString( PyExc_TypeError, "2D/3D vectors only\n" );
- return NULL;
- }
-}
-
-
-
-//---------------------------------NORMALS FUNCTIONS--------------------
-//----------------------------------Mathutils.QuadNormal() -------------------
-static PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args )
-{
- VectorObject *vec1;
- VectorObject *vec2;
- VectorObject *vec3;
- VectorObject *vec4;
- float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3];
-
- if( !PyArg_ParseTuple( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4 ) ) {
- PyErr_SetString( PyExc_TypeError, "expected 4 vector types\n" );
- return NULL;
- }
- if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) {
- PyErr_SetString( PyExc_TypeError,"vectors must be of the same size\n" );
- return NULL;
- }
- if( vec1->size != 3 ) {
- PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3) || !BaseMath_ReadCallback(vec4))
- return NULL;
-
- VECCOPY(v1, vec1->vec);
- VECCOPY(v2, vec2->vec);
- VECCOPY(v3, vec3->vec);
- VECCOPY(v4, vec4->vec);
-
- /* find vectors for two edges sharing v2 */
- VecSubf(e1, v1, v2);
- VecSubf(e2, v3, v2);
-
- Crossf(n1, e2, e1);
- Normalize(n1);
-
- /* find vectors for two edges sharing v4 */
- VecSubf(e1, v3, v4);
- VecSubf(e2, v1, v4);
-
- Crossf(n2, e2, e1);
- Normalize(n2);
-
- /* adding and averaging the normals of both triangles */
- VecAddf(n1, n2, n1);
- Normalize(n1);
-
- return newVectorObject(n1, 3, Py_NEW, NULL);
-}
-
-//----------------------------Mathutils.TriangleNormal() -------------------
-static PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args )
-{
- VectorObject *vec1, *vec2, *vec3;
- float v1[3], v2[3], v3[3], e1[3], e2[3], n[3];
-
- if( !PyArg_ParseTuple( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3 ) ) {
- PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n" );
- return NULL;
- }
- if( vec1->size != vec2->size || vec1->size != vec3->size ) {
- PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
- return NULL;
- }
- if( vec1->size != 3 ) {
- PyErr_SetString( PyExc_TypeError, "only 3D vectors\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
- return NULL;
-
- VECCOPY(v1, vec1->vec);
- VECCOPY(v2, vec2->vec);
- VECCOPY(v3, vec3->vec);
-
- /* find vectors for two edges sharing v2 */
- VecSubf(e1, v1, v2);
- VecSubf(e2, v3, v2);
-
- Crossf(n, e2, e1);
- Normalize(n);
-
- return newVectorObject(n, 3, Py_NEW, NULL);
-}
-
-//--------------------------------- AREA FUNCTIONS--------------------
-//----------------------------------Mathutils.TriangleArea() -------------------
-static PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args )
-{
- VectorObject *vec1, *vec2, *vec3;
- float v1[3], v2[3], v3[3];
-
- if( !PyArg_ParseTuple
- ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
- , &vector_Type, &vec3 ) ) {
- PyErr_SetString( PyExc_TypeError, "expected 3 vector types\n");
- return NULL;
- }
- if( vec1->size != vec2->size || vec1->size != vec3->size ) {
- PyErr_SetString( PyExc_TypeError, "vectors must be of the same size\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2) || !BaseMath_ReadCallback(vec3))
- return NULL;
-
- if (vec1->size == 3) {
- VECCOPY(v1, vec1->vec);
- VECCOPY(v2, vec2->vec);
- VECCOPY(v3, vec3->vec);
-
- return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3) );
- }
- else if (vec1->size == 2) {
- v1[0] = vec1->vec[0];
- v1[1] = vec1->vec[1];
-
- v2[0] = vec2->vec[0];
- v2[1] = vec2->vec[1];
-
- v3[0] = vec3->vec[0];
- v3[1] = vec3->vec[1];
-
- return PyFloat_FromDouble( AreaF2Dfl(v1, v2, v3) );
- }
- else {
- PyErr_SetString( PyExc_TypeError, "only 2D,3D vectors are supported\n" );
- return NULL;
- }
-}
-
-/* Utility functions */
-
-/*---------------------- EXPP_FloatsAreEqual -------------------------
- Floating point comparisons
- floatStep = number of representable floats allowable in between
- float A and float B to be considered equal. */
-int EXPP_FloatsAreEqual(float A, float B, int floatSteps)
-{
- int a, b, delta;
- assert(floatSteps > 0 && floatSteps < (4 * 1024 * 1024));
- a = *(int*)&A;
- if (a < 0)
- a = 0x80000000 - a;
- b = *(int*)&B;
- if (b < 0)
- b = 0x80000000 - b;
- delta = abs(a - b);
- if (delta <= floatSteps)
- return 1;
- return 0;
-}
-/*---------------------- EXPP_VectorsAreEqual -------------------------
- Builds on EXPP_FloatsAreEqual to test vectors */
-int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps)
-{
- int x;
- for (x=0; x< size; x++){
- if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
- return 0;
- }
- return 1;
-}
-
-
-/* Mathutils Callbacks */
-
-/* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */
-Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
-
-int Mathutils_RegisterCallback(Mathutils_Callback *cb)
-{
- int i;
-
- /* find the first free slot */
- for(i= 0; mathutils_callbacks[i]; i++) {
- if(mathutils_callbacks[i]==cb) /* alredy registered? */
- return i;
- }
-
- mathutils_callbacks[i] = cb;
- return i;
-}
-
-/* use macros to check for NULL */
-int _BaseMathObject_ReadCallback(BaseMathObject *self)
-{
- Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
- if(cb->get(self->cb_user, self->cb_subtype, self->data))
- return 1;
-
- PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
- return 0;
-}
-
-int _BaseMathObject_WriteCallback(BaseMathObject *self)
-{
- Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
- if(cb->set(self->cb_user, self->cb_subtype, self->data))
- return 1;
-
- PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
- return 0;
-}
-
-int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index)
-{
- Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
- if(cb->get_index(self->cb_user, self->cb_subtype, self->data, index))
- return 1;
-
- PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
- return 0;
-}
-
-int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index)
-{
- Mathutils_Callback *cb= mathutils_callbacks[self->cb_type];
- if(cb->set_index(self->cb_user, self->cb_subtype, self->data, index))
- return 1;
-
- PyErr_Format(PyExc_SystemError, "%s user has become invalid", Py_TYPE(self)->tp_name);
- return 0;
-}
-
-/* BaseMathObject generic functions for all mathutils types */
-PyObject *BaseMathObject_getOwner( BaseMathObject * self, void *type )
-{
- PyObject *ret= self->cb_user ? self->cb_user : Py_None;
- Py_INCREF(ret);
- return ret;
-}
-
-PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void *type )
-{
- return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0);
-}
-
-void BaseMathObject_dealloc(BaseMathObject * self)
-{
- /* only free non wrapped */
- if(self->wrapped != Py_WRAP)
- PyMem_Free(self->data);
-
- Py_XDECREF(self->cb_user);
- Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes
-}
-
diff --git a/source/blender/python/generic/Mathutils.h b/source/blender/python/generic/Mathutils.h
deleted file mode 100644
index 5bdd9d9cfe0..00000000000
--- a/source/blender/python/generic/Mathutils.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
-*/
-//Include this file for access to vector, quat, matrix, euler, etc...
-
-#ifndef EXPP_Mathutils_H
-#define EXPP_Mathutils_H
-
-#include <Python.h>
-#include "../intern/bpy_compat.h"
-#include "vector.h"
-#include "matrix.h"
-#include "quat.h"
-#include "euler.h"
-
-/* #define USE_MATHUTILS_DEG - for backwards compat */
-
-/* Can cast different mathutils types to this, use for generic funcs */
-
-typedef struct {
- PyObject_VAR_HEAD
- float *data; /*array of data (alias), wrapped status depends on wrapped status */
- PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */
- unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */
- unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */
- unsigned char wrapped; /* wrapped data type? */
-} BaseMathObject;
-
-PyObject *BaseMathObject_getOwner( BaseMathObject * self, void * );
-PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void * );
-void BaseMathObject_dealloc(BaseMathObject * self);
-
-
-
-
-PyObject *Mathutils_Init( const char * from );
-
-PyObject *quat_rotation(PyObject *arg1, PyObject *arg2);
-
-int EXPP_FloatsAreEqual(float A, float B, int floatSteps);
-int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps);
-
-
-#define Py_PI 3.14159265358979323846
-
-#define Py_NEW 1
-#define Py_WRAP 2
-
-
-/* Mathutils is used by the BGE and Blender so have to define
- * some things here for luddite mac users of py2.3 */
-#ifndef Py_RETURN_NONE
-#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
-#endif
-#ifndef Py_RETURN_FALSE
-#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
-#endif
-#ifndef Py_RETURN_TRUE
-#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
-#endif
-
-typedef struct Mathutils_Callback Mathutils_Callback;
-
-typedef int (*BaseMathCheckFunc)(PyObject *);
-typedef int (*BaseMathGetFunc)(PyObject *, int, float *);
-typedef int (*BaseMathSetFunc)(PyObject *, int, float *);
-typedef int (*BaseMathGetIndexFunc)(PyObject *, int, float *, int);
-typedef int (*BaseMathSetIndexFunc)(PyObject *, int, float *, int);
-
-struct Mathutils_Callback {
- int (*check)(PyObject *user); /* checks the user is still valid */
- int (*get)(PyObject *user, int subtype, float *from); /* gets the vector from the user */
- int (*set)(PyObject *user, int subtype, float *to); /* sets the users vector values once the vector is modified */
- int (*get_index)(PyObject *user, int subtype, float *from,int index); /* same as above but only for an index */
- int (*set_index)(PyObject *user, int subtype, float *to, int index); /* same as above but only for an index */
-};
-
-int Mathutils_RegisterCallback(Mathutils_Callback *cb);
-
-int _BaseMathObject_ReadCallback(BaseMathObject *self);
-int _BaseMathObject_WriteCallback(BaseMathObject *self);
-int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index);
-int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
-
-/* since this is called so often avoid where possible */
-#define BaseMath_ReadCallback(_self) (((_self)->cb_user ? _BaseMathObject_ReadCallback((BaseMathObject *)_self):1))
-#define BaseMath_WriteCallback(_self) (((_self)->cb_user ?_BaseMathObject_WriteCallback((BaseMathObject *)_self):1))
-#define BaseMath_ReadIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_ReadIndexCallback((BaseMathObject *)_self, _index):1))
-#define BaseMath_WriteIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_WriteIndexCallback((BaseMathObject *)_self, _index):1))
-
-#endif /* EXPP_Mathutils_H */
diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c
deleted file mode 100644
index c41ea386c0e..00000000000
--- a/source/blender/python/generic/bpy_internal_import.c
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * $Id$
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Willian P. Germano
- *
- * ***** END GPL LICENSE BLOCK *****
-*/
-
-#include "bpy_internal_import.h"
-#include "DNA_text_types.h"
-#include "DNA_ID.h"
-
-#include "MEM_guardedalloc.h"
-#include "BKE_text.h" /* txt_to_buf */
-#include "BKE_main.h"
-
-static Main *bpy_import_main= NULL;
-
-static void free_compiled_text(Text *text)
-{
- if(text->compiled) {
- Py_DECREF(( PyObject * )text->compiled);
- }
- text->compiled= NULL;
-}
-
-struct Main *bpy_import_main_get(void)
-{
- return bpy_import_main;
-}
-
-void bpy_import_main_set(struct Main *maggie)
-{
- bpy_import_main= maggie;
-}
-
-
-PyObject *bpy_text_import( char *name, int *found )
-{
- Text *text;
- char txtname[22]; /* 21+NULL */
- char *buf = NULL;
- int namelen = strlen( name );
-//XXX Main *maggie= bpy_import_main ? bpy_import_main:G.main;
- Main *maggie= bpy_import_main;
-
- *found= 0;
-
- if (namelen>21-3) return NULL; /* we know this cant be importable, the name is too long for blender! */
-
- memcpy( txtname, name, namelen );
- memcpy( &txtname[namelen], ".py", 4 );
-
- for(text = maggie->text.first; text; text = text->id.next) {
- if( !strcmp( txtname, text->id.name+2 ) )
- break;
- }
-
- if( !text )
- return NULL;
- else
- *found = 1;
-
- if( !text->compiled ) {
- buf = txt_to_buf( text );
- text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input );
- MEM_freeN( buf );
-
- if( PyErr_Occurred( ) ) {
- PyErr_Print( );
- PyErr_Clear( );
- PySys_SetObject("last_traceback", NULL);
- free_compiled_text( text );
- return NULL;
- }
- }
-
- return PyImport_ExecCodeModule( name, text->compiled );
-}
-
-
-/*
- * find in-memory module and recompile
- */
-
-PyObject *bpy_text_reimport( PyObject *module, int *found )
-{
- Text *text;
- char *txtname;
- char *name;
- char *buf = NULL;
-//XXX Main *maggie= bpy_import_main ? bpy_import_main:G.main;
- Main *maggie= bpy_import_main;
-
- *found= 0;
-
- /* get name, filename from the module itself */
-
- txtname = PyModule_GetFilename( module );
- name = PyModule_GetName( module );
- if( !txtname || !name)
- return NULL;
-
- /* look up the text object */
- text = ( Text * ) & ( maggie->text.first );
- while( text ) {
- if( !strcmp( txtname, text->id.name+2 ) )
- break;
- text = text->id.next;
- }
-
- /* uh-oh.... didn't find it */
- if( !text )
- return NULL;
- else
- *found = 1;
-
- /* if previously compiled, free the object */
- /* (can't see how could be NULL, but check just in case) */
- if( text->compiled ){
- Py_DECREF( (PyObject *)text->compiled );
- }
-
- /* compile the buffer */
- buf = txt_to_buf( text );
- text->compiled = Py_CompileString( buf, text->id.name+2, Py_file_input );
- MEM_freeN( buf );
-
- /* if compile failed.... return this error */
- if( PyErr_Occurred( ) ) {
- PyErr_Print( );
- PyErr_Clear( );
- PySys_SetObject("last_traceback", NULL);
- free_compiled_text( text );
- return NULL;
- }
-
- /* make into a module */
- return PyImport_ExecCodeModule( name, text->compiled );
-}
-
-
-static PyObject *blender_import( PyObject * self, PyObject * args, PyObject * kw)
-{
- PyObject *exception, *err, *tb;
- char *name;
- int found= 0;
- PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
- PyObject *newmodule;
-
- //PyObject_Print(args, stderr, 0);
-#if (PY_VERSION_HEX >= 0x02060000)
- int dummy_val; /* what does this do?*/
- static char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", 0};
-
- if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOOi:bpy_import_meth", kwlist,
- &name, &globals, &locals, &fromlist, &dummy_val) )
- return NULL;
-#else
- static char *kwlist[] = {"name", "globals", "locals", "fromlist", 0};
-
- if( !PyArg_ParseTupleAndKeywords( args, kw, "s|OOO:bpy_import_meth", kwlist,
- &name, &globals, &locals, &fromlist ) )
- return NULL;
-#endif
-
- /* import existing builtin modules or modules that have been imported alredy */
- newmodule = PyImport_ImportModuleEx( name, globals, locals, fromlist );
-
- if(newmodule)
- return newmodule;
-
- PyErr_Fetch( &exception, &err, &tb ); /* get the python error incase we cant import as blender text either */
-
- /* importing from existing modules failed, see if we have this module as blender text */
- newmodule = bpy_text_import( name, &found );
-
- if( newmodule ) {/* found module as blender text, ignore above exception */
- PyErr_Clear( );
- Py_XDECREF( exception );
- Py_XDECREF( err );
- Py_XDECREF( tb );
- /* printf( "imported from text buffer...\n" ); */
- }
- else if (found==1) { /* blender text module failed to execute but was found, use its error message */
- Py_XDECREF( exception );
- Py_XDECREF( err );
- Py_XDECREF( tb );
- return NULL;
- }
- else {
- /* no blender text was found that could import the module
- * rause the original error from PyImport_ImportModuleEx */
- PyErr_Restore( exception, err, tb );
- }
- return newmodule;
-}
-
-
-/*
- * our reload() module, to handle reloading in-memory scripts
- */
-
-static PyObject *blender_reload( PyObject * self, PyObject * args )
-{
- PyObject *exception, *err, *tb;
- PyObject *module = NULL;
- PyObject *newmodule = NULL;
- int found= 0;
-
- /* check for a module arg */
- if( !PyArg_ParseTuple( args, "O:bpy_reload_meth", &module ) )
- return NULL;
-
- /* try reimporting from file */
- newmodule = PyImport_ReloadModule( module );
- if( newmodule )
- return newmodule;
-
- /* no file, try importing from memory */
- PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */
-
- newmodule = bpy_text_reimport( module, &found );
- if( newmodule ) {/* found module as blender text, ignore above exception */
- PyErr_Clear( );
- Py_XDECREF( exception );
- Py_XDECREF( err );
- Py_XDECREF( tb );
- /* printf( "imported from text buffer...\n" ); */
- }
- else if (found==1) { /* blender text module failed to execute but was found, use its error message */
- Py_XDECREF( exception );
- Py_XDECREF( err );
- Py_XDECREF( tb );
- return NULL;
- }
- else {
- /* no blender text was found that could import the module
- * rause the original error from PyImport_ImportModuleEx */
- PyErr_Restore( exception, err, tb );
- }
-
- return newmodule;
-}
-
-PyMethodDef bpy_import_meth[] = { {"bpy_import_meth", blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"} };
-PyMethodDef bpy_reload_meth[] = { {"bpy_reload_meth", blender_reload, METH_VARARGS, "blenders reload"} };
-
-
-/* Clear user modules.
- * This is to clear any modules that could be defined from running scripts in blender.
- *
- * Its also needed for the BGE Python api so imported scripts are not used between levels
- *
- * This clears every modules that has a __file__ attribute (is not a builtin)
- *
- * Note that clearing external python modules is important for the BGE otherwise
- * it wont reload scripts between loading different blend files or while making the game.
- * - use 'clear_all' arg in this case.
- *
- * Since pythons bultins include a full path even for win32.
- * even if we remove a python module a reimport will bring it back again.
- */
-
-#if 0 // not used anymore but may still come in handy later
-
-#if defined(WIN32) || defined(WIN64)
-#define SEPSTR "\\"
-#else
-#define SEPSTR "/"
-#endif
-
-
-void bpy_text_clear_modules(int clear_all)
-{
- PyObject *modules= PySys_GetObject("modules");
-
- char *fname;
- char *file_extension;
-
- /* looping over the dict */
- PyObject *key, *value;
- int pos = 0;
-
- /* new list */
- PyObject *list;
-
- if (modules==NULL)
- return; /* should never happen but just incase */
-
- list= PyList_New(0);
-
- /* go over sys.modules and remove anything with a
- * sys.modukes[x].__file__ thats ends with a .py and has no path
- */
- while (PyDict_Next(modules, &pos, &key, &value)) {
- fname= PyModule_GetFilename(value);
- if(fname) {
- if (clear_all || ((strstr(fname, SEPSTR))==0)) { /* no path ? */
- file_extension = strstr(fname, ".py");
- if(file_extension && (*(file_extension + 3) == '\0' || *(file_extension + 4) == '\0')) { /* .py or pyc extension? */
- /* now we can be fairly sure its a python import from the blendfile */
- PyList_Append(list, key); /* free'd with the list */
- }
- }
- }
- else {
- PyErr_Clear();
- }
- }
-
- /* remove all our modules */
- for(pos=0; pos < PyList_Size(list); pos++) {
- /* PyObject_Print(key, stderr, 0); */
- key= PyList_GET_ITEM(list, pos);
- PyDict_DelItem(modules, key);
- }
-
- Py_DECREF(list); /* removes all references from append */
-}
-#endif
diff --git a/source/blender/python/generic/bpy_internal_import.h b/source/blender/python/generic/bpy_internal_import.h
deleted file mode 100644
index aeeafb7c1c4..00000000000
--- a/source/blender/python/generic/bpy_internal_import.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * $Id$
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * This is a new part of Blender.
- *
- * Contributor(s): Willian P. Germano, Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
-*/
-
-/* Note, the BGE needs to use this too, keep it minimal */
-
-#ifndef EXPP_bpy_import_h
-#define EXPP_bpy_import_h
-
-#include <Python.h>
-#include "../intern/bpy_compat.h"
-#include "compile.h" /* for the PyCodeObject */
-#include "eval.h" /* for PyEval_EvalCode */
-
-PyObject* bpy_text_import( char *name, int *found );
-PyObject* bpy_text_reimport( PyObject *module, int *found );
-/* void bpy_text_clear_modules( int clear_all );*/ /* Clear user modules */
-extern PyMethodDef bpy_import_meth[];
-extern PyMethodDef bpy_reload_meth[];
-
-/* The game engine has its own Main struct, if this is set search this rather then G.main */
-struct Main *bpy_import_main_get(void);
-void bpy_import_main_set(struct Main *maggie);
-
-
-#endif /* EXPP_bpy_import_h */
diff --git a/source/blender/python/generic/euler.c b/source/blender/python/generic/euler.c
deleted file mode 100644
index 69373b1aa36..00000000000
--- a/source/blender/python/generic/euler.c
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- *
- * Contributor(s): Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "Mathutils.h"
-
-#include "BLI_arithb.h"
-#include "BKE_utildefines.h"
-#include "BLI_blenlib.h"
-
-
-//-------------------------DOC STRINGS ---------------------------
-
-static PyObject *Euler_Zero( EulerObject * self );
-static PyObject *Euler_Unique( EulerObject * self );
-static PyObject *Euler_ToMatrix( EulerObject * self );
-static PyObject *Euler_ToQuat( EulerObject * self );
-static PyObject *Euler_Rotate( EulerObject * self, PyObject *args );
-static PyObject *Euler_MakeCompatible( EulerObject * self, EulerObject *value );
-static PyObject *Euler_copy( EulerObject * self, PyObject *args );
-
-//-----------------------METHOD DEFINITIONS ----------------------
-static struct PyMethodDef Euler_methods[] = {
- {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, NULL},
- {"unique", (PyCFunction) Euler_Unique, METH_NOARGS, NULL},
- {"toMatrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, NULL},
- {"toQuat", (PyCFunction) Euler_ToQuat, METH_NOARGS, NULL},
- {"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, NULL},
- {"makeCompatible", (PyCFunction) Euler_MakeCompatible, METH_O, NULL},
- {"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, NULL},
- {"copy", (PyCFunction) Euler_copy, METH_VARARGS, NULL},
- {NULL, NULL, 0, NULL}
-};
-
-//----------------------------------Mathutils.Euler() -------------------
-//makes a new euler for you to play with
-static PyObject *Euler_new(PyTypeObject * type, PyObject * args, PyObject * kwargs)
-{
- PyObject *listObject = NULL;
- int size, i;
- float eul[3];
- PyObject *e;
-
- size = PyTuple_GET_SIZE(args);
- if (size == 1) {
- listObject = PyTuple_GET_ITEM(args, 0);
- if (PySequence_Check(listObject)) {
- size = PySequence_Length(listObject);
- } else { // Single argument was not a sequence
- PyErr_SetString(PyExc_TypeError, "Mathutils.Euler(): 3d numeric sequence expected\n");
- return NULL;
- }
- } else if (size == 0) {
- //returns a new empty 3d euler
- return newEulerObject(NULL, Py_NEW, NULL);
- } else {
- listObject = args;
- }
-
- if (size != 3) { // Invalid euler size
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Euler(): 3d numeric sequence expected\n");
- return NULL;
- }
-
- for (i=0; i<size; i++) {
- e = PySequence_GetItem(listObject, i);
- if (e == NULL) { // Failed to read sequence
- Py_DECREF(listObject);
- PyErr_SetString(PyExc_RuntimeError, "Mathutils.Euler(): 3d numeric sequence expected\n");
- return NULL;
- }
-
- eul[i]= (float)PyFloat_AsDouble(e);
- Py_DECREF(e);
-
- if(eul[i]==-1 && PyErr_Occurred()) { // parsed item is not a number
- PyErr_SetString(PyExc_TypeError, "Mathutils.Euler(): 3d numeric sequence expected\n");
- return NULL;
- }
- }
- return newEulerObject(eul, Py_NEW, NULL);
-}
-
-//-----------------------------METHODS----------------------------
-//----------------------------Euler.toQuat()----------------------
-//return a quaternion representation of the euler
-static PyObject *Euler_ToQuat(EulerObject * self)
-{
- float quat[4];
-#ifdef USE_MATHUTILS_DEG
- float eul[3];
- int x;
-#endif
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
-#ifdef USE_MATHUTILS_DEG
- for(x = 0; x < 3; x++) {
- eul[x] = self->eul[x] * ((float)Py_PI / 180);
- }
- EulToQuat(eul, quat);
-#else
- EulToQuat(self->eul, quat);
-#endif
-
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-//----------------------------Euler.toMatrix()---------------------
-//return a matrix representation of the euler
-static PyObject *Euler_ToMatrix(EulerObject * self)
-{
- float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
-#ifdef USE_MATHUTILS_DEG
- {
- float eul[3];
- int x;
-
- for(x = 0; x < 3; x++) {
- eul[x] = self->eul[x] * ((float)Py_PI / 180);
- }
- EulToMat3(eul, (float (*)[3]) mat);
- }
-#else
- EulToMat3(self->eul, (float (*)[3]) mat);
-#endif
- return newMatrixObject(mat, 3, 3 , Py_NEW, NULL);
-}
-//----------------------------Euler.unique()-----------------------
-//sets the x,y,z values to a unique euler rotation
-static PyObject *Euler_Unique(EulerObject * self)
-{
-#define PI_2 (Py_PI * 2.0)
-#define PI_HALF (Py_PI / 2.0)
-#define PI_INV (1.0 / Py_PI)
-
- double heading, pitch, bank;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
-#ifdef USE_MATHUTILS_DEG
- //radians
- heading = self->eul[0] * (float)Py_PI / 180;
- pitch = self->eul[1] * (float)Py_PI / 180;
- bank = self->eul[2] * (float)Py_PI / 180;
-#else
- heading = self->eul[0];
- pitch = self->eul[1];
- bank = self->eul[2];
-#endif
-
- //wrap heading in +180 / -180
- pitch += Py_PI;
- pitch -= floor(pitch * PI_INV) * PI_2;
- pitch -= Py_PI;
-
-
- if(pitch < -PI_HALF) {
- pitch = -Py_PI - pitch;
- heading += Py_PI;
- bank += Py_PI;
- } else if(pitch > PI_HALF) {
- pitch = Py_PI - pitch;
- heading += Py_PI;
- bank += Py_PI;
- }
- //gimbal lock test
- if(fabs(pitch) > PI_HALF - 1e-4) {
- heading += bank;
- bank = 0.0f;
- } else {
- bank += Py_PI;
- bank -= (floor(bank * PI_INV)) * PI_2;
- bank -= Py_PI;
- }
-
- heading += Py_PI;
- heading -= (floor(heading * PI_INV)) * PI_2;
- heading -= Py_PI;
-
-#ifdef USE_MATHUTILS_DEG
- //back to degrees
- self->eul[0] = (float)(heading * 180 / (float)Py_PI);
- self->eul[1] = (float)(pitch * 180 / (float)Py_PI);
- self->eul[2] = (float)(bank * 180 / (float)Py_PI);
-#endif
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
-}
-//----------------------------Euler.zero()-------------------------
-//sets the euler to 0,0,0
-static PyObject *Euler_Zero(EulerObject * self)
-{
- self->eul[0] = 0.0;
- self->eul[1] = 0.0;
- self->eul[2] = 0.0;
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
-}
-//----------------------------Euler.rotate()-----------------------
-//rotates a euler a certain amount and returns the result
-//should return a unique euler rotation (i.e. no 720 degree pitches :)
-static PyObject *Euler_Rotate(EulerObject * self, PyObject *args)
-{
- float angle = 0.0f;
- char *axis;
-
- if(!PyArg_ParseTuple(args, "fs", &angle, &axis)){
- PyErr_SetString(PyExc_TypeError, "euler.rotate():expected angle (float) and axis (x,y,z)");
- return NULL;
- }
- if(!STREQ3(axis,"x","y","z")){
- PyErr_SetString(PyExc_TypeError, "euler.rotate(): expected axis to be 'x', 'y' or 'z'");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
-#ifdef USE_MATHUTILS_DEG
- {
- int x;
-
- //covert to radians
- angle *= ((float)Py_PI / 180);
- for(x = 0; x < 3; x++) {
- self->eul[x] *= ((float)Py_PI / 180);
- }
- }
-#endif
- euler_rot(self->eul, angle, *axis);
-
-#ifdef USE_MATHUTILS_DEG
- {
- int x;
- //convert back from radians
- for(x = 0; x < 3; x++) {
- self->eul[x] *= (180 / (float)Py_PI);
- }
- }
-#endif
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
-}
-
-static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
-{
-#ifdef USE_MATHUTILS_DEG
- float eul_from_rad[3];
- int x;
-#endif
-
- if(!EulerObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "euler.makeCompatible(euler):expected a single euler argument.");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
- return NULL;
-
-#ifdef USE_MATHUTILS_DEG
- //covert to radians
- for(x = 0; x < 3; x++) {
- self->eul[x] = self->eul[x] * ((float)Py_PI / 180);
- eul_from_rad[x] = value->eul[x] * ((float)Py_PI / 180);
- }
- compatible_eul(self->eul, eul_from_rad);
-#else
- compatible_eul(self->eul, value->eul);
-#endif
-
-#ifdef USE_MATHUTILS_DEG
- //convert back from radians
- for(x = 0; x < 3; x++) {
- self->eul[x] *= (180 / (float)Py_PI);
- }
-#endif
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
-}
-
-//----------------------------Euler.rotate()-----------------------
-// return a copy of the euler
-static PyObject *Euler_copy(EulerObject * self, PyObject *args)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- return newEulerObject(self->eul, Py_NEW, Py_TYPE(self));
-}
-
-//----------------------------print object (internal)--------------
-//print the object to screen
-static PyObject *Euler_repr(EulerObject * self)
-{
- char str[64];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- sprintf(str, "[%.6f, %.6f, %.6f](euler)", self->eul[0], self->eul[1], self->eul[2]);
- return PyUnicode_FromString(str);
-}
-//------------------------tp_richcmpr
-//returns -1 execption, 0 false, 1 true
-static PyObject* Euler_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
-{
- EulerObject *eulA = NULL, *eulB = NULL;
- int result = 0;
-
- if(EulerObject_Check(objectA)) {
- eulA = (EulerObject*)objectA;
- if(!BaseMath_ReadCallback(eulA))
- return NULL;
- }
- if(EulerObject_Check(objectB)) {
- eulB = (EulerObject*)objectB;
- if(!BaseMath_ReadCallback(eulB))
- return NULL;
- }
-
- if (!eulA || !eulB){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
- }
- eulA = (EulerObject*)objectA;
- eulB = (EulerObject*)objectB;
-
- switch (comparison_type){
- case Py_EQ:
- result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
- break;
- case Py_NE:
- result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
- if (result == 0){
- result = 1;
- }else{
- result = 0;
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
-}
-
-//---------------------SEQUENCE PROTOCOLS------------------------
-//----------------------------len(object)------------------------
-//sequence length
-static int Euler_len(EulerObject * self)
-{
- return 3;
-}
-//----------------------------object[]---------------------------
-//sequence accessor (get)
-static PyObject *Euler_item(EulerObject * self, int i)
-{
- if(i<0) i= 3-i;
-
- if(i < 0 || i >= 3) {
- PyErr_SetString(PyExc_IndexError, "euler[attribute]: array index out of range");
- return NULL;
- }
-
- if(!BaseMath_ReadIndexCallback(self, i))
- return NULL;
-
- return PyFloat_FromDouble(self->eul[i]);
-
-}
-//----------------------------object[]-------------------------
-//sequence accessor (set)
-static int Euler_ass_item(EulerObject * self, int i, PyObject * value)
-{
- float f = PyFloat_AsDouble(value);
-
- if(f == -1 && PyErr_Occurred()) { // parsed item not a number
- PyErr_SetString(PyExc_TypeError, "euler[attribute] = x: argument not a number");
- return -1;
- }
-
- if(i<0) i= 3-i;
-
- if(i < 0 || i >= 3){
- PyErr_SetString(PyExc_IndexError, "euler[attribute] = x: array assignment index out of range\n");
- return -1;
- }
-
- self->eul[i] = f;
-
- if(!BaseMath_WriteIndexCallback(self, i))
- return -1;
-
- return 0;
-}
-//----------------------------object[z:y]------------------------
-//sequence slice (get)
-static PyObject *Euler_slice(EulerObject * self, int begin, int end)
-{
- PyObject *list = NULL;
- int count;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- CLAMP(begin, 0, 3);
- if (end<0) end= 4+end;
- CLAMP(end, 0, 3);
- begin = MIN2(begin,end);
-
- list = PyList_New(end - begin);
- for(count = begin; count < end; count++) {
- PyList_SetItem(list, count - begin,
- PyFloat_FromDouble(self->eul[count]));
- }
-
- return list;
-}
-//----------------------------object[z:y]------------------------
-//sequence slice (set)
-static int Euler_ass_slice(EulerObject * self, int begin, int end,
- PyObject * seq)
-{
- int i, y, size = 0;
- float eul[3];
- PyObject *e;
-
- if(!BaseMath_ReadCallback(self))
- return -1;
-
- CLAMP(begin, 0, 3);
- if (end<0) end= 4+end;
- CLAMP(end, 0, 3);
- begin = MIN2(begin,end);
-
- size = PySequence_Length(seq);
- if(size != (end - begin)){
- PyErr_SetString(PyExc_TypeError, "euler[begin:end] = []: size mismatch in slice assignment");
- return -1;
- }
-
- for (i = 0; i < size; i++) {
- e = PySequence_GetItem(seq, i);
- if (e == NULL) { // Failed to read sequence
- PyErr_SetString(PyExc_RuntimeError, "euler[begin:end] = []: unable to read sequence");
- return -1;
- }
-
- eul[i] = (float)PyFloat_AsDouble(e);
- Py_DECREF(e);
-
- if(eul[i]==-1 && PyErr_Occurred()) { // parsed item not a number
- PyErr_SetString(PyExc_TypeError, "euler[begin:end] = []: sequence argument not a number");
- return -1;
- }
- }
- //parsed well - now set in vector
- for(y = 0; y < 3; y++){
- self->eul[begin + y] = eul[y];
- }
-
- BaseMath_WriteCallback(self);
- return 0;
-}
-//-----------------PROTCOL DECLARATIONS--------------------------
-static PySequenceMethods Euler_SeqMethods = {
- (inquiry) Euler_len, /* sq_length */
- (binaryfunc) 0, /* sq_concat */
- (ssizeargfunc) 0, /* sq_repeat */
- (ssizeargfunc) Euler_item, /* sq_item */
- (ssizessizeargfunc) Euler_slice, /* sq_slice */
- (ssizeobjargproc) Euler_ass_item, /* sq_ass_item */
- (ssizessizeobjargproc) Euler_ass_slice, /* sq_ass_slice */
-};
-
-
-/*
- * vector axis, vector.x/y/z/w
- */
-
-static PyObject *Euler_getAxis( EulerObject * self, void *type )
-{
- return Euler_item(self, GET_INT_FROM_POINTER(type));
-}
-
-static int Euler_setAxis( EulerObject * self, PyObject * value, void * type )
-{
- return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value);
-}
-
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
-static PyGetSetDef Euler_getseters[] = {
- {"x", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler X axis", (void *)0},
- {"y", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Y axis", (void *)1},
- {"z", (getter)Euler_getAxis, (setter)Euler_setAxis, "Euler Z axis", (void *)2},
-
- {"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "True when this wraps blenders internal data", NULL},
- {"__owner__", (getter)BaseMathObject_getOwner, (setter)NULL, "Read only owner for vectors that depend on another object", NULL},
- {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
-};
-
-//------------------PY_OBECT DEFINITION--------------------------
-PyTypeObject euler_Type = {
-#if (PY_VERSION_HEX >= 0x02060000)
- PyVarObject_HEAD_INIT(NULL, 0)
-#else
- /* python 2.5 and below */
- PyObject_HEAD_INIT( NULL ) /* required py macro */
- 0, /* ob_size */
-#endif
- "euler", //tp_name
- sizeof(EulerObject), //tp_basicsize
- 0, //tp_itemsize
- (destructor)BaseMathObject_dealloc, //tp_dealloc
- 0, //tp_print
- 0, //tp_getattr
- 0, //tp_setattr
- 0, //tp_compare
- (reprfunc) Euler_repr, //tp_repr
- 0, //tp_as_number
- &Euler_SeqMethods, //tp_as_sequence
- 0, //tp_as_mapping
- 0, //tp_hash
- 0, //tp_call
- 0, //tp_str
- 0, //tp_getattro
- 0, //tp_setattro
- 0, //tp_as_buffer
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
- 0, //tp_doc
- 0, //tp_traverse
- 0, //tp_clear
- (richcmpfunc)Euler_richcmpr, //tp_richcompare
- 0, //tp_weaklistoffset
- 0, //tp_iter
- 0, //tp_iternext
- Euler_methods, //tp_methods
- 0, //tp_members
- Euler_getseters, //tp_getset
- 0, //tp_base
- 0, //tp_dict
- 0, //tp_descr_get
- 0, //tp_descr_set
- 0, //tp_dictoffset
- 0, //tp_init
- 0, //tp_alloc
- Euler_new, //tp_new
- 0, //tp_free
- 0, //tp_is_gc
- 0, //tp_bases
- 0, //tp_mro
- 0, //tp_cache
- 0, //tp_subclasses
- 0, //tp_weaklist
- 0 //tp_del
-};
-//------------------------newEulerObject (internal)-------------
-//creates a new euler object
-/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- (i.e. it was allocated elsewhere by MEM_mallocN())
- pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *newEulerObject(float *eul, int type, PyTypeObject *base_type)
-{
- EulerObject *self;
- int x;
-
- if(base_type) self = (EulerObject *)base_type->tp_alloc(base_type, 0);
- else self = PyObject_NEW(EulerObject, &euler_Type);
-
- /* init callbacks as NULL */
- self->cb_user= NULL;
- self->cb_type= self->cb_subtype= 0;
-
- if(type == Py_WRAP){
- self->eul = eul;
- self->wrapped = Py_WRAP;
- }else if (type == Py_NEW){
- self->eul = PyMem_Malloc(3 * sizeof(float));
- if(!eul) { //new empty
- for(x = 0; x < 3; x++) {
- self->eul[x] = 0.0f;
- }
- }else{
- VECCOPY(self->eul, eul);
- }
- self->wrapped = Py_NEW;
- }else{ //bad type
- return NULL;
- }
- return (PyObject *)self;
-}
-
-PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype)
-{
- EulerObject *self= (EulerObject *)newEulerObject(NULL, Py_NEW, NULL);
- if(self) {
- Py_INCREF(cb_user);
- self->cb_user= cb_user;
- self->cb_type= (unsigned char)cb_type;
- self->cb_subtype= (unsigned char)cb_subtype;
- }
-
- return (PyObject *)self;
-}
diff --git a/source/blender/python/generic/euler.h b/source/blender/python/generic/euler.h
deleted file mode 100644
index a3706d53756..00000000000
--- a/source/blender/python/generic/euler.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-#ifndef EXPP_euler_h
-#define EXPP_euler_h
-
-#include <Python.h>
-#include "../intern/bpy_compat.h"
-
-extern PyTypeObject euler_Type;
-#define EulerObject_Check(_v) PyObject_TypeCheck((_v), &euler_Type)
-
-typedef struct {
- PyObject_VAR_HEAD
- float *eul; /*1D array of data */
- PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */
- unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */
- unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */
- unsigned char wrapped; /* wrapped data type? */
- /* end BaseMathObject */
-
-} EulerObject;
-
-/*struct data contains a pointer to the actual data that the
-object uses. It can use either PyMem allocated data (which will
-be stored in py_data) or be a wrapper for data allocated through
-blender (stored in blend_data). This is an either/or struct not both*/
-
-//prototypes
-PyObject *newEulerObject( float *eul, int type, PyTypeObject *base_type);
-PyObject *newEulerObject_cb(PyObject *cb_user, int cb_type, int cb_subtype);
-
-#endif /* EXPP_euler_h */
diff --git a/source/blender/python/generic/matrix.c b/source/blender/python/generic/matrix.c
deleted file mode 100644
index 5bdbf804618..00000000000
--- a/source/blender/python/generic/matrix.c
+++ /dev/null
@@ -1,1358 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Michel Selten & Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "Mathutils.h"
-
-#include "BKE_utildefines.h"
-#include "BLI_arithb.h"
-#include "BLI_blenlib.h"
-
-static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec); /* utility func */
-
-
-/* matrix vector callbacks */
-int mathutils_matrix_vector_cb_index= -1;
-
-static int mathutils_matrix_vector_check(MatrixObject *self)
-{
- return BaseMath_ReadCallback(self);
-}
-
-static int mathutils_matrix_vector_get(MatrixObject *self, int subtype, float *vec_from)
-{
- int i;
- if(!BaseMath_ReadCallback(self))
- return 0;
-
- for(i=0; i<self->colSize; i++)
- vec_from[i]= self->matrix[subtype][i];
-
- return 1;
-}
-
-static int mathutils_matrix_vector_set(MatrixObject *self, int subtype, float *vec_to)
-{
- int i;
- if(!BaseMath_ReadCallback(self))
- return 0;
-
- for(i=0; i<self->colSize; i++)
- self->matrix[subtype][i]= vec_to[i];
-
- BaseMath_WriteCallback(self);
- return 1;
-}
-
-static int mathutils_matrix_vector_get_index(MatrixObject *self, int subtype, float *vec_from, int index)
-{
- if(!BaseMath_ReadCallback(self))
- return 0;
-
- vec_from[index]= self->matrix[subtype][index];
- return 1;
-}
-
-static int mathutils_matrix_vector_set_index(MatrixObject *self, int subtype, float *vec_to, int index)
-{
- if(!BaseMath_ReadCallback(self))
- return 0;
-
- self->matrix[subtype][index]= vec_to[index];
-
- BaseMath_WriteCallback(self);
- return 1;
-}
-
-Mathutils_Callback mathutils_matrix_vector_cb = {
- mathutils_matrix_vector_check,
- mathutils_matrix_vector_get,
- mathutils_matrix_vector_set,
- mathutils_matrix_vector_get_index,
- mathutils_matrix_vector_set_index
-};
-/* matrix vector callbacks, this is so you can do matrix[i][j] = val */
-
-/*-------------------------DOC STRINGS ---------------------------*/
-
-static PyObject *Matrix_Zero( MatrixObject * self );
-static PyObject *Matrix_Identity( MatrixObject * self );
-static PyObject *Matrix_Transpose( MatrixObject * self );
-static PyObject *Matrix_Determinant( MatrixObject * self );
-static PyObject *Matrix_Invert( MatrixObject * self );
-static PyObject *Matrix_TranslationPart( MatrixObject * self );
-static PyObject *Matrix_RotationPart( MatrixObject * self );
-static PyObject *Matrix_scalePart( MatrixObject * self );
-static PyObject *Matrix_Resize4x4( MatrixObject * self );
-static PyObject *Matrix_toEuler( MatrixObject * self, PyObject *args );
-static PyObject *Matrix_toQuat( MatrixObject * self );
-static PyObject *Matrix_copy( MatrixObject * self );
-
-/*-----------------------METHOD DEFINITIONS ----------------------*/
-static struct PyMethodDef Matrix_methods[] = {
- {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, NULL},
- {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, NULL},
- {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, NULL},
- {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, NULL},
- {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, NULL},
- {"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, NULL},
- {"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, NULL},
- {"scalePart", (PyCFunction) Matrix_scalePart, METH_NOARGS, NULL},
- {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, NULL},
- {"toEuler", (PyCFunction) Matrix_toEuler, METH_VARARGS, NULL},
- {"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, NULL},
- {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, NULL},
- {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, NULL},
- {NULL, NULL, 0, NULL}
-};
-
-//----------------------------------Mathutils.Matrix() -----------------
-//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
-//create a new matrix type
-static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *argObject, *m, *s;
- MatrixObject *mat;
- int argSize, seqSize = 0, i, j;
- float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
- float scalar;
-
- argSize = PyTuple_GET_SIZE(args);
- if(argSize > 4){ //bad arg nums
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
- return NULL;
- } else if (argSize == 0) { //return empty 4D matrix
- return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW, NULL);
- }else if (argSize == 1){
- //copy constructor for matrix objects
- argObject = PyTuple_GET_ITEM(args, 0);
- if(MatrixObject_Check(argObject)){
- mat = (MatrixObject*)argObject;
- if(!BaseMath_ReadCallback(mat))
- return NULL;
-
- memcpy(matrix, mat->contigPtr, sizeof(float) * mat->rowSize * mat->colSize);
- }
- }else{ //2-4 arguments (all seqs? all same size?)
- for(i =0; i < argSize; i++){
- argObject = PyTuple_GET_ITEM(args, i);
- if (PySequence_Check(argObject)) { //seq?
- if(seqSize){ //0 at first
- if(PySequence_Length(argObject) != seqSize){ //seq size not same
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
- return NULL;
- }
- }
- seqSize = PySequence_Length(argObject);
- }else{ //arg not a sequence
- PyErr_SetString(PyExc_TypeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
- return NULL;
- }
- }
- //all is well... let's continue parsing
- for (i = 0; i < argSize; i++){
- m = PyTuple_GET_ITEM(args, i);
- if (m == NULL) { // Failed to read sequence
- PyErr_SetString(PyExc_RuntimeError, "Mathutils.Matrix(): failed to parse arguments...\n");
- return NULL;
- }
-
- for (j = 0; j < seqSize; j++) {
- s = PySequence_GetItem(m, j);
- if (s == NULL) { // Failed to read sequence
- PyErr_SetString(PyExc_RuntimeError, "Mathutils.Matrix(): failed to parse arguments...\n");
- return NULL;
- }
-
- scalar= (float)PyFloat_AsDouble(s);
- Py_DECREF(s);
-
- if(scalar==-1 && PyErr_Occurred()) { // parsed item is not a number
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
- return NULL;
- }
-
- matrix[(seqSize*i)+j]= scalar;
- }
- }
- }
- return newMatrixObject(matrix, argSize, seqSize, Py_NEW, NULL);
-}
-
-/*-----------------------------METHODS----------------------------*/
-/*---------------------------Matrix.toQuat() ---------------------*/
-static PyObject *Matrix_toQuat(MatrixObject * self)
-{
- float quat[4];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- /*must be 3-4 cols, 3-4 rows, square matrix*/
- if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) {
- PyErr_SetString(PyExc_AttributeError, "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix");
- return NULL;
- }
- if(self->colSize == 3){
- Mat3ToQuat((float (*)[3])*self->matrix, quat);
- }else{
- Mat4ToQuat((float (*)[4])*self->matrix, quat);
- }
-
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-/*---------------------------Matrix.toEuler() --------------------*/
-PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
-{
- float eul[3], eul_compatf[3];
- EulerObject *eul_compat = NULL;
-#ifdef USE_MATHUTILS_DEG
- int x;
-#endif
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat))
- return NULL;
-
- if(eul_compat) {
- if(!BaseMath_ReadCallback(eul_compat))
- return NULL;
-
-#ifdef USE_MATHUTILS_DEG
- for(x = 0; x < 3; x++) {
- eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180);
- }
-#else
- VECCOPY(eul_compatf, eul_compat->eul);
-#endif
- }
-
- /*must be 3-4 cols, 3-4 rows, square matrix*/
- if(self->colSize ==3 && self->rowSize ==3) {
- if(eul_compat) Mat3ToCompatibleEul((float (*)[3])*self->matrix, eul, eul_compatf);
- else Mat3ToEul((float (*)[3])*self->matrix, eul);
- }else if (self->colSize ==4 && self->rowSize ==4) {
- float tempmat3[3][3];
- Mat3CpyMat4(tempmat3, (float (*)[4])*self->matrix);
- Mat3ToEul(tempmat3, eul);
- if(eul_compat) Mat3ToCompatibleEul(tempmat3, eul, eul_compatf);
- else Mat3ToEul(tempmat3, eul);
-
- }else {
- PyErr_SetString(PyExc_AttributeError, "Matrix.toEuler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
- return NULL;
- }
-#ifdef USE_MATHUTILS_DEG
- /*have to convert to degrees*/
- for(x = 0; x < 3; x++) {
- eul[x] *= (float) (180 / Py_PI);
- }
-#endif
- return newEulerObject(eul, Py_NEW, NULL);
-}
-/*---------------------------Matrix.resize4x4() ------------------*/
-PyObject *Matrix_Resize4x4(MatrixObject * self)
-{
- int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
-
- if(self->wrapped==Py_WRAP){
- PyErr_SetString(PyExc_TypeError, "cannot resize wrapped data - make a copy and resize that");
- return NULL;
- }
- if(self->cb_user){
- PyErr_SetString(PyExc_TypeError, "cannot resize owned data - make a copy and resize that");
- return NULL;
- }
-
- self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16));
- if(self->contigPtr == NULL) {
- PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space");
- return NULL;
- }
- self->matrix = PyMem_Realloc(self->matrix, (sizeof(float *) * 4));
- if(self->matrix == NULL) {
- PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space");
- return NULL;
- }
- /*set row pointers*/
- for(x = 0; x < 4; x++) {
- self->matrix[x] = self->contigPtr + (x * 4);
- }
- /*move data to new spot in array + clean*/
- for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){
- for(x = 0; x < 4; x++){
- index = (4 * (self->rowSize + (blank_rows - 1))) + x;
- if (index == 10 || index == 15){
- self->contigPtr[index] = 1.0f;
- }else{
- self->contigPtr[index] = 0.0f;
- }
- }
- }
- for(x = 1; x <= self->rowSize; x++){
- first_row_elem = (self->colSize * (self->rowSize - x));
- curr_pos = (first_row_elem + (self->colSize -1));
- new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem);
- for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){
- self->contigPtr[new_pos + blank_columns] = 0.0f;
- }
- for(curr_pos = curr_pos; curr_pos >= first_row_elem; curr_pos--){
- self->contigPtr[new_pos] = self->contigPtr[curr_pos];
- new_pos--;
- }
- }
- self->rowSize = 4;
- self->colSize = 4;
-
- Py_INCREF(self);
- return (PyObject *)self;
-}
-/*---------------------------Matrix.translationPart() ------------*/
-PyObject *Matrix_TranslationPart(MatrixObject * self)
-{
- float vec[4];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(self->colSize < 3 || self->rowSize < 4){
- PyErr_SetString(PyExc_AttributeError, "Matrix.translationPart: inappropriate matrix size");
- return NULL;
- }
-
- vec[0] = self->matrix[3][0];
- vec[1] = self->matrix[3][1];
- vec[2] = self->matrix[3][2];
-
- return newVectorObject(vec, 3, Py_NEW, NULL);
-}
-/*---------------------------Matrix.rotationPart() ---------------*/
-PyObject *Matrix_RotationPart(MatrixObject * self)
-{
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(self->colSize < 3 || self->rowSize < 3){
- PyErr_SetString(PyExc_AttributeError, "Matrix.rotationPart: inappropriate matrix size\n");
- return NULL;
- }
-
- mat[0] = self->matrix[0][0];
- mat[1] = self->matrix[0][1];
- mat[2] = self->matrix[0][2];
- mat[3] = self->matrix[1][0];
- mat[4] = self->matrix[1][1];
- mat[5] = self->matrix[1][2];
- mat[6] = self->matrix[2][0];
- mat[7] = self->matrix[2][1];
- mat[8] = self->matrix[2][2];
-
- return newMatrixObject(mat, 3, 3, Py_NEW, Py_TYPE(self));
-}
-/*---------------------------Matrix.scalePart() --------------------*/
-PyObject *Matrix_scalePart(MatrixObject * self)
-{
- float scale[3], rot[3];
- float mat[3][3], imat[3][3], tmat[3][3];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- /*must be 3-4 cols, 3-4 rows, square matrix*/
- if(self->colSize == 4 && self->rowSize == 4)
- Mat3CpyMat4(mat, (float (*)[4])*self->matrix);
- else if(self->colSize == 3 && self->rowSize == 3)
- Mat3CpyMat3(mat, (float (*)[3])*self->matrix);
- else {
- PyErr_SetString(PyExc_AttributeError, "Matrix.scalePart(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
- return NULL;
- }
- /* functionality copied from editobject.c apply_obmat */
- Mat3ToEul(mat, rot);
- EulToMat3(rot, tmat);
- Mat3Inv(imat, tmat);
- Mat3MulMat3(tmat, imat, mat);
-
- scale[0]= tmat[0][0];
- scale[1]= tmat[1][1];
- scale[2]= tmat[2][2];
- return newVectorObject(scale, 3, Py_NEW, NULL);
-}
-/*---------------------------Matrix.invert() ---------------------*/
-PyObject *Matrix_Invert(MatrixObject * self)
-{
-
- int x, y, z = 0;
- float det = 0.0f;
- PyObject *f = NULL;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(self->rowSize != self->colSize){
- PyErr_SetString(PyExc_AttributeError, "Matrix.invert(ed): only square matrices are supported");
- return NULL;
- }
-
- /*calculate the determinant*/
- f = Matrix_Determinant(self);
- det = (float)PyFloat_AS_DOUBLE(f); /*Increfs, so we need to decref*/
- Py_DECREF(f);
-
- if(det != 0) {
- /*calculate the classical adjoint*/
- if(self->rowSize == 2) {
- mat[0] = self->matrix[1][1];
- mat[1] = -self->matrix[0][1];
- mat[2] = -self->matrix[1][0];
- mat[3] = self->matrix[0][0];
- } else if(self->rowSize == 3) {
- Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix);
- } else if(self->rowSize == 4) {
- Mat4Adj((float (*)[4]) mat, (float (*)[4]) *self->matrix);
- }
- /*divide by determinate*/
- for(x = 0; x < (self->rowSize * self->colSize); x++) {
- mat[x] /= det;
- }
- /*set values*/
- for(x = 0; x < self->rowSize; x++) {
- for(y = 0; y < self->colSize; y++) {
- self->matrix[x][y] = mat[z];
- z++;
- }
- }
- /*transpose
- Matrix_Transpose(self);*/
- } else {
- PyErr_SetString(PyExc_ValueError, "matrix does not have an inverse");
- return NULL;
- }
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
-}
-
-
-/*---------------------------Matrix.determinant() ----------------*/
-PyObject *Matrix_Determinant(MatrixObject * self)
-{
- float det = 0.0f;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(self->rowSize != self->colSize){
- PyErr_SetString(PyExc_AttributeError, "Matrix.determinant: only square matrices are supported");
- return NULL;
- }
-
- if(self->rowSize == 2) {
- det = Det2x2(self->matrix[0][0], self->matrix[0][1],
- self->matrix[1][0], self->matrix[1][1]);
- } else if(self->rowSize == 3) {
- det = Det3x3(self->matrix[0][0], self->matrix[0][1],
- self->matrix[0][2], self->matrix[1][0],
- self->matrix[1][1], self->matrix[1][2],
- self->matrix[2][0], self->matrix[2][1],
- self->matrix[2][2]);
- } else {
- det = Det4x4((float (*)[4]) *self->matrix);
- }
-
- return PyFloat_FromDouble( (double) det );
-}
-/*---------------------------Matrix.transpose() ------------------*/
-PyObject *Matrix_Transpose(MatrixObject * self)
-{
- float t = 0.0f;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(self->rowSize != self->colSize){
- PyErr_SetString(PyExc_AttributeError, "Matrix.transpose(d): only square matrices are supported");
- return NULL;
- }
-
- if(self->rowSize == 2) {
- t = self->matrix[1][0];
- self->matrix[1][0] = self->matrix[0][1];
- self->matrix[0][1] = t;
- } else if(self->rowSize == 3) {
- Mat3Transp((float (*)[3])*self->matrix);
- } else {
- Mat4Transp((float (*)[4])*self->matrix);
- }
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
-}
-
-
-/*---------------------------Matrix.zero() -----------------------*/
-PyObject *Matrix_Zero(MatrixObject * self)
-{
- int row, col;
-
- for(row = 0; row < self->rowSize; row++) {
- for(col = 0; col < self->colSize; col++) {
- self->matrix[row][col] = 0.0f;
- }
- }
-
- if(!BaseMath_WriteCallback(self))
- return NULL;
-
- Py_INCREF(self);
- return (PyObject *)self;
-}
-/*---------------------------Matrix.identity(() ------------------*/
-PyObject *Matrix_Identity(MatrixObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(self->rowSize != self->colSize){
- PyErr_SetString(PyExc_AttributeError, "Matrix.identity: only square matrices are supported\n");
- return NULL;
- }
-
- if(self->rowSize == 2) {
- self->matrix[0][0] = 1.0f;
- self->matrix[0][1] = 0.0f;
- self->matrix[1][0] = 0.0f;
- self->matrix[1][1] = 1.0f;
- } else if(self->rowSize == 3) {
- Mat3One((float (*)[3]) *self->matrix);
- } else {
- Mat4One((float (*)[4]) *self->matrix);
- }
-
- if(!BaseMath_WriteCallback(self))
- return NULL;
-
- Py_INCREF(self);
- return (PyObject *)self;
-}
-
-/*---------------------------Matrix.inverted() ------------------*/
-PyObject *Matrix_copy(MatrixObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- return (PyObject*)newMatrixObject((float (*))*self->matrix, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self));
-}
-
-/*----------------------------print object (internal)-------------*/
-/*print the object to screen*/
-static PyObject *Matrix_repr(MatrixObject * self)
-{
- int x, y;
- char buffer[48], str[1024];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- BLI_strncpy(str,"",1024);
- for(x = 0; x < self->rowSize; x++){
- sprintf(buffer, "[");
- strcat(str,buffer);
- for(y = 0; y < (self->colSize - 1); y++) {
- sprintf(buffer, "%.6f, ", self->matrix[x][y]);
- strcat(str,buffer);
- }
- if(x < (self->rowSize-1)){
- sprintf(buffer, "%.6f](matrix [row %d])\n", self->matrix[x][y], x);
- strcat(str,buffer);
- }else{
- sprintf(buffer, "%.6f](matrix [row %d])", self->matrix[x][y], x);
- strcat(str,buffer);
- }
- }
-
- return PyUnicode_FromString(str);
-}
-/*------------------------tp_richcmpr*/
-/*returns -1 execption, 0 false, 1 true*/
-static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
-{
- MatrixObject *matA = NULL, *matB = NULL;
- int result = 0;
-
- if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
- }
- matA = (MatrixObject*)objectA;
- matB = (MatrixObject*)objectB;
-
- if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB))
- return NULL;
-
- if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
- }
-
- switch (comparison_type){
- case Py_EQ:
- /*contigPtr is basically a really long vector*/
- result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
- (matA->rowSize * matA->colSize), 1);
- break;
- case Py_NE:
- result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
- (matA->rowSize * matA->colSize), 1);
- if (result == 0){
- result = 1;
- }else{
- result = 0;
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
-}
-
-/*---------------------SEQUENCE PROTOCOLS------------------------
- ----------------------------len(object)------------------------
- sequence length*/
-static int Matrix_len(MatrixObject * self)
-{
- return (self->rowSize);
-}
-/*----------------------------object[]---------------------------
- sequence accessor (get)
- the wrapped vector gives direct access to the matrix data*/
-static PyObject *Matrix_item(MatrixObject * self, int i)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(i < 0 || i >= self->rowSize) {
- PyErr_SetString(PyExc_IndexError, "matrix[attribute]: array index out of range");
- return NULL;
- }
- return newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, i);
-}
-/*----------------------------object[]-------------------------
- sequence accessor (set)*/
-static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob)
-{
- int y, x, size = 0;
- float vec[4];
- PyObject *m, *f;
-
- if(!BaseMath_ReadCallback(self))
- return -1;
-
- if(i >= self->rowSize || i < 0){
- PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad row\n");
- return -1;
- }
-
- if(PySequence_Check(ob)){
- size = PySequence_Length(ob);
- if(size != self->colSize){
- PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: bad sequence size\n");
- return -1;
- }
- for (x = 0; x < size; x++) {
- m = PySequence_GetItem(ob, x);
- if (m == NULL) { /*Failed to read sequence*/
- PyErr_SetString(PyExc_RuntimeError, "matrix[attribute] = x: unable to read sequence\n");
- return -1;
- }
-
- f = PyNumber_Float(m);
- if(f == NULL) { /*parsed item not a number*/
- Py_DECREF(m);
- PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: sequence argument not a number\n");
- return -1;
- }
-
- vec[x] = (float)PyFloat_AS_DOUBLE(f);
- Py_DECREF(m);
- Py_DECREF(f);
- }
- /*parsed well - now set in matrix*/
- for(y = 0; y < size; y++){
- self->matrix[i][y] = vec[y];
- }
-
- BaseMath_WriteCallback(self);
- return 0;
- }else{
- PyErr_SetString(PyExc_TypeError, "matrix[attribute] = x: expects a sequence of column size\n");
- return -1;
- }
-}
-/*----------------------------object[z:y]------------------------
- sequence slice (get)*/
-static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
-{
-
- PyObject *list = NULL;
- int count;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- CLAMP(begin, 0, self->rowSize);
- CLAMP(end, 0, self->rowSize);
- begin = MIN2(begin,end);
-
- list = PyList_New(end - begin);
- for(count = begin; count < end; count++) {
- PyList_SetItem(list, count - begin,
- newVectorObject_cb((PyObject *)self, self->colSize, mathutils_matrix_vector_cb_index, count));
-
- }
-
- return list;
-}
-/*----------------------------object[z:y]------------------------
- sequence slice (set)*/
-static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject * seq)
-{
- int i, x, y, size, sub_size = 0;
- float mat[16], f;
- PyObject *subseq;
- PyObject *m;
-
- if(!BaseMath_ReadCallback(self))
- return -1;
-
- CLAMP(begin, 0, self->rowSize);
- CLAMP(end, 0, self->rowSize);
- begin = MIN2(begin,end);
-
- if(PySequence_Check(seq)){
- size = PySequence_Length(seq);
- if(size != (end - begin)){
- PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n");
- return -1;
- }
- /*parse sub items*/
- for (i = 0; i < size; i++) {
- /*parse each sub sequence*/
- subseq = PySequence_GetItem(seq, i);
- if (subseq == NULL) { /*Failed to read sequence*/
- PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence");
- return -1;
- }
-
- if(PySequence_Check(subseq)){
- /*subsequence is also a sequence*/
- sub_size = PySequence_Length(subseq);
- if(sub_size != self->colSize){
- Py_DECREF(subseq);
- PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: size mismatch in slice assignment\n");
- return -1;
- }
- for (y = 0; y < sub_size; y++) {
- m = PySequence_GetItem(subseq, y);
- if (m == NULL) { /*Failed to read sequence*/
- Py_DECREF(subseq);
- PyErr_SetString(PyExc_RuntimeError, "matrix[begin:end] = []: unable to read sequence\n");
- return -1;
- }
-
- f = PyFloat_AsDouble(m); /* faster to assume a float and raise an error after */
- if(f == -1 && PyErr_Occurred()) { /*parsed item not a number*/
- Py_DECREF(m);
- Py_DECREF(subseq);
- PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: sequence argument not a number\n");
- return -1;
- }
-
- mat[(i * self->colSize) + y] = f;
- Py_DECREF(m);
- }
- }else{
- Py_DECREF(subseq);
- PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n");
- return -1;
- }
- Py_DECREF(subseq);
- }
- /*parsed well - now set in matrix*/
- for(x = 0; x < (size * sub_size); x++){
- self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x];
- }
-
- BaseMath_WriteCallback(self);
- return 0;
- }else{
- PyErr_SetString(PyExc_TypeError, "matrix[begin:end] = []: illegal argument type for built-in operation\n");
- return -1;
- }
-}
-/*------------------------NUMERIC PROTOCOLS----------------------
- ------------------------obj + obj------------------------------*/
-static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
-{
- int x, y;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
- MatrixObject *mat1 = NULL, *mat2 = NULL;
-
- mat1 = (MatrixObject*)m1;
- mat2 = (MatrixObject*)m2;
-
- if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
- PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation....");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
- return NULL;
-
- if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
- PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
- return NULL;
- }
-
- for(x = 0; x < mat1->rowSize; x++) {
- for(y = 0; y < mat1->colSize; y++) {
- mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y];
- }
- }
-
- return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
-}
-/*------------------------obj - obj------------------------------
- subtraction*/
-static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
-{
- int x, y;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
- MatrixObject *mat1 = NULL, *mat2 = NULL;
-
- mat1 = (MatrixObject*)m1;
- mat2 = (MatrixObject*)m2;
-
- if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) {
- PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation....");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
- return NULL;
-
- if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
- PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
- return NULL;
- }
-
- for(x = 0; x < mat1->rowSize; x++) {
- for(y = 0; y < mat1->colSize; y++) {
- mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y];
- }
- }
-
- return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
-}
-/*------------------------obj * obj------------------------------
- mulplication*/
-static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
-{
- int x, y, z;
- float scalar;
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
- double dot = 0.0f;
- MatrixObject *mat1 = NULL, *mat2 = NULL;
-
- if(MatrixObject_Check(m1)) {
- mat1 = (MatrixObject*)m1;
- if(!BaseMath_ReadCallback(mat1))
- return NULL;
- }
- if(MatrixObject_Check(m2)) {
- mat2 = (MatrixObject*)m2;
- if(!BaseMath_ReadCallback(mat2))
- return NULL;
- }
-
- if(mat1 && mat2) { /*MATRIX * MATRIX*/
- if(mat1->colSize != mat2->rowSize){
- PyErr_SetString(PyExc_AttributeError,"Matrix multiplication: matrix A rowsize must equal matrix B colsize");
- return NULL;
- }
- for(x = 0; x < mat1->rowSize; x++) {
- for(y = 0; y < mat2->colSize; y++) {
- for(z = 0; z < mat1->colSize; z++) {
- dot += (mat1->matrix[x][z] * mat2->matrix[z][y]);
- }
- mat[((x * mat1->rowSize) + y)] = (float)dot;
- dot = 0.0f;
- }
- }
-
- return newMatrixObject(mat, mat1->rowSize, mat2->colSize, Py_NEW, NULL);
- }
-
- if(mat1==NULL){
- scalar=PyFloat_AsDouble(m1); // may not be a float...
- if ((scalar == -1.0 && PyErr_Occurred())==0) { /*FLOAT/INT * MATRIX, this line annoys theeth, lets see if he finds it */
- for(x = 0; x < mat2->rowSize; x++) {
- for(y = 0; y < mat2->colSize; y++) {
- mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y];
- }
- }
- return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW, NULL);
- }
-
- PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
- return NULL;
- }
- else /* if(mat1) { */ {
-
- if(VectorObject_Check(m2)) { /* MATRIX*VECTOR */
- return column_vector_multiplication(mat1, (VectorObject *)m2); /* vector update done inside the function */
- }
- else {
- scalar= PyFloat_AsDouble(m2);
- if ((scalar == -1.0 && PyErr_Occurred())==0) { /* MATRIX*FLOAT/INT */
- for(x = 0; x < mat1->rowSize; x++) {
- for(y = 0; y < mat1->colSize; y++) {
- mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y];
- }
- }
- return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW, NULL);
- }
- }
- PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation");
- return NULL;
- }
-
- PyErr_SetString(PyExc_TypeError, "Matrix multiplication: arguments not acceptable for this operation\n");
- return NULL;
-}
-static PyObject* Matrix_inv(MatrixObject *self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- return Matrix_Invert(self);
-}
-
-/*-----------------PROTOCOL DECLARATIONS--------------------------*/
-static PySequenceMethods Matrix_SeqMethods = {
- (inquiry) Matrix_len, /* sq_length */
- (binaryfunc) 0, /* sq_concat */
- (ssizeargfunc) 0, /* sq_repeat */
- (ssizeargfunc) Matrix_item, /* sq_item */
- (ssizessizeargfunc) Matrix_slice, /* sq_slice */
- (ssizeobjargproc) Matrix_ass_item, /* sq_ass_item */
- (ssizessizeobjargproc) Matrix_ass_slice, /* sq_ass_slice */
-};
-
-
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i;
- i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return NULL;
- if (i < 0)
- i += self->rowSize;
- return Matrix_item(self, i);
- } else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
- return NULL;
-
- if (slicelength <= 0) {
- return PyList_New(0);
- }
- else if (step == 1) {
- return Matrix_slice(self, start, stop);
- }
- else {
- PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
- return NULL;
- }
- }
- else {
- PyErr_Format(PyExc_TypeError,
- "vector indices must be integers, not %.200s",
- item->ob_type->tp_name);
- return NULL;
- }
-}
-
-static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return -1;
- if (i < 0)
- i += self->rowSize;
- return Matrix_ass_item(self, i, value);
- }
- else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx((PySliceObject*)item, self->rowSize, &start, &stop, &step, &slicelength) < 0)
- return -1;
-
- if (step == 1)
- return Matrix_ass_slice(self, start, stop, value);
- else {
- PyErr_SetString(PyExc_TypeError, "slice steps not supported with matricies");
- return -1;
- }
- }
- else {
- PyErr_Format(PyExc_TypeError,
- "matrix indices must be integers, not %.200s",
- item->ob_type->tp_name);
- return -1;
- }
-}
-
-static PyMappingMethods Matrix_AsMapping = {
- (lenfunc)Matrix_len,
- (binaryfunc)Matrix_subscript,
- (objobjargproc)Matrix_ass_subscript
-};
-#endif /* (PY_VERSION_HEX >= 0x03000000) */
-
-
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static PyNumberMethods Matrix_NumMethods = {
- (binaryfunc) Matrix_add, /*nb_add*/
- (binaryfunc) Matrix_sub, /*nb_subtract*/
- (binaryfunc) Matrix_mul, /*nb_multiply*/
- 0, /*nb_remainder*/
- 0, /*nb_divmod*/
- 0, /*nb_power*/
- (unaryfunc) 0, /*nb_negative*/
- (unaryfunc) 0, /*tp_positive*/
- (unaryfunc) 0, /*tp_absolute*/
- (inquiry) 0, /*tp_bool*/
- (unaryfunc) Matrix_inv, /*nb_invert*/
- 0, /*nb_lshift*/
- (binaryfunc)0, /*nb_rshift*/
- 0, /*nb_and*/
- 0, /*nb_xor*/
- 0, /*nb_or*/
- 0, /*nb_int*/
- 0, /*nb_reserved*/
- 0, /*nb_float*/
- 0, /* nb_inplace_add */
- 0, /* nb_inplace_subtract */
- 0, /* nb_inplace_multiply */
- 0, /* nb_inplace_remainder */
- 0, /* nb_inplace_power */
- 0, /* nb_inplace_lshift */
- 0, /* nb_inplace_rshift */
- 0, /* nb_inplace_and */
- 0, /* nb_inplace_xor */
- 0, /* nb_inplace_or */
- 0, /* nb_floor_divide */
- 0, /* nb_true_divide */
- 0, /* nb_inplace_floor_divide */
- 0, /* nb_inplace_true_divide */
- 0, /* nb_index */
-};
-#else
-static PyNumberMethods Matrix_NumMethods = {
- (binaryfunc) Matrix_add, /* __add__ */
- (binaryfunc) Matrix_sub, /* __sub__ */
- (binaryfunc) Matrix_mul, /* __mul__ */
- (binaryfunc) 0, /* __div__ */
- (binaryfunc) 0, /* __mod__ */
- (binaryfunc) 0, /* __divmod__ */
- (ternaryfunc) 0, /* __pow__ */
- (unaryfunc) 0, /* __neg__ */
- (unaryfunc) 0, /* __pos__ */
- (unaryfunc) 0, /* __abs__ */
- (inquiry) 0, /* __nonzero__ */
- (unaryfunc) Matrix_inv, /* __invert__ */
- (binaryfunc) 0, /* __lshift__ */
- (binaryfunc) 0, /* __rshift__ */
- (binaryfunc) 0, /* __and__ */
- (binaryfunc) 0, /* __xor__ */
- (binaryfunc) 0, /* __or__ */
- /*(coercion)*/ 0, /* __coerce__ */
- (unaryfunc) 0, /* __int__ */
- (unaryfunc) 0, /* __long__ */
- (unaryfunc) 0, /* __float__ */
- (unaryfunc) 0, /* __oct__ */
- (unaryfunc) 0, /* __hex__ */
-};
-#endif
-
-static PyObject *Matrix_getRowSize( MatrixObject * self, void *type )
-{
- return PyLong_FromLong((long) self->rowSize);
-}
-
-static PyObject *Matrix_getColSize( MatrixObject * self, void *type )
-{
- return PyLong_FromLong((long) self->colSize);
-}
-
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
-static PyGetSetDef Matrix_getseters[] = {
- {"rowSize", (getter)Matrix_getRowSize, (setter)NULL, "", NULL},
- {"colSize", (getter)Matrix_getColSize, (setter)NULL, "", NULL},
- {"wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, "", NULL},
- {"__owner__",(getter)BaseMathObject_getOwner, (setter)NULL, "",
- NULL},
- {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
-};
-
-/*------------------PY_OBECT DEFINITION--------------------------*/
-PyTypeObject matrix_Type = {
-#if (PY_VERSION_HEX >= 0x02060000)
- PyVarObject_HEAD_INIT(NULL, 0)
-#else
- /* python 2.5 and below */
- PyObject_HEAD_INIT( NULL ) /* required py macro */
- 0, /* ob_size */
-#endif
- "matrix", /*tp_name*/
- sizeof(MatrixObject), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- (destructor)BaseMathObject_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- (reprfunc) Matrix_repr, /*tp_repr*/
- &Matrix_NumMethods, /*tp_as_number*/
- &Matrix_SeqMethods, /*tp_as_sequence*/
-#if (PY_VERSION_HEX >= 0x03000000)
- &Matrix_AsMapping, /*tp_as_mapping*/
-#else
- 0,
-#endif
- 0, /*tp_hash*/
- 0, /*tp_call*/
- 0, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- (richcmpfunc)Matrix_richcmpr, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- Matrix_methods, /*tp_methods*/
- 0, /*tp_members*/
- Matrix_getseters, /*tp_getset*/
- 0, /*tp_base*/
- 0, /*tp_dict*/
- 0, /*tp_descr_get*/
- 0, /*tp_descr_set*/
- 0, /*tp_dictoffset*/
- 0, /*tp_init*/
- 0, /*tp_alloc*/
- Matrix_new, /*tp_new*/
- 0, /*tp_free*/
- 0, /*tp_is_gc*/
- 0, /*tp_bases*/
- 0, /*tp_mro*/
- 0, /*tp_cache*/
- 0, /*tp_subclasses*/
- 0, /*tp_weaklist*/
- 0 /*tp_del*/
-};
-
-/*------------------------newMatrixObject (internal)-------------
-creates a new matrix object
-self->matrix self->contiguous_ptr (reference to data.xxx)
- [0]------------->[0]
- [1]
- [2]
- [1]------------->[3]
- [4]
- [5]
- ....
-self->matrix[1][1] = self->contigPtr[4] */
-
-/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- (i.e. it was allocated elsewhere by MEM_mallocN())
- pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type)
-{
- MatrixObject *self;
- int x, row, col;
-
- /*matrix objects can be any 2-4row x 2-4col matrix*/
- if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){
- PyErr_SetString(PyExc_RuntimeError, "matrix(): row and column sizes must be between 2 and 4");
- return NULL;
- }
-
- if(base_type) self = (MatrixObject *)base_type->tp_alloc(base_type, 0);
- else self = PyObject_NEW(MatrixObject, &matrix_Type);
-
- self->rowSize = rowSize;
- self->colSize = colSize;
-
- /* init callbacks as NULL */
- self->cb_user= NULL;
- self->cb_type= self->cb_subtype= 0;
-
- if(type == Py_WRAP){
- self->contigPtr = mat;
- /*create pointer array*/
- self->matrix = PyMem_Malloc(rowSize * sizeof(float *));
- if(self->matrix == NULL) { /*allocation failure*/
- PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space");
- return NULL;
- }
- /*pointer array points to contigous memory*/
- for(x = 0; x < rowSize; x++) {
- self->matrix[x] = self->contigPtr + (x * colSize);
- }
- self->wrapped = Py_WRAP;
- }else if (type == Py_NEW){
- self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float));
- if(self->contigPtr == NULL) { /*allocation failure*/
- PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space\n");
- return NULL;
- }
- /*create pointer array*/
- self->matrix = PyMem_Malloc(rowSize * sizeof(float *));
- if(self->matrix == NULL) { /*allocation failure*/
- PyMem_Free(self->contigPtr);
- PyErr_SetString( PyExc_MemoryError, "matrix(): problem allocating pointer space");
- return NULL;
- }
- /*pointer array points to contigous memory*/
- for(x = 0; x < rowSize; x++) {
- self->matrix[x] = self->contigPtr + (x * colSize);
- }
- /*parse*/
- if(mat) { /*if a float array passed*/
- for(row = 0; row < rowSize; row++) {
- for(col = 0; col < colSize; col++) {
- self->matrix[row][col] = mat[(row * colSize) + col];
- }
- }
- } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
- Matrix_Identity(self);
- Py_DECREF(self);
- }
- self->wrapped = Py_NEW;
- }else{ /*bad type*/
- return NULL;
- }
- return (PyObject *) self;
-}
-
-PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype)
-{
- MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL);
- if(self) {
- Py_INCREF(cb_user);
- self->cb_user= cb_user;
- self->cb_type= (unsigned char)cb_type;
- self->cb_subtype= (unsigned char)cb_subtype;
- }
- return (PyObject *) self;
-}
-
-//----------------column_vector_multiplication (internal)---------
-//COLUMN VECTOR Multiplication (Matrix X Vector)
-// [1][2][3] [a]
-// [4][5][6] * [b]
-// [7][8][9] [c]
-//vector/matrix multiplication IS NOT COMMUTATIVE!!!!
-static PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec)
-{
- float vecNew[4], vecCopy[4];
- double dot = 0.0f;
- int x, y, z = 0;
-
- if(!BaseMath_ReadCallback(mat) || !BaseMath_ReadCallback(vec))
- return NULL;
-
- if(mat->rowSize != vec->size){
- if(mat->rowSize == 4 && vec->size != 3){
- PyErr_SetString(PyExc_AttributeError, "matrix * vector: matrix row size and vector size must be the same");
- return NULL;
- }else{
- vecCopy[3] = 1.0f;
- }
- }
-
- for(x = 0; x < vec->size; x++){
- vecCopy[x] = vec->vec[x];
- }
-
- for(x = 0; x < mat->rowSize; x++) {
- for(y = 0; y < mat->colSize; y++) {
- dot += mat->matrix[x][y] * vecCopy[y];
- }
- vecNew[z++] = (float)dot;
- dot = 0.0f;
- }
- return newVectorObject(vecNew, vec->size, Py_NEW, NULL);
-}
diff --git a/source/blender/python/generic/matrix.h b/source/blender/python/generic/matrix.h
deleted file mode 100644
index 856c711c4ef..00000000000
--- a/source/blender/python/generic/matrix.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * $Id$
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-#ifndef EXPP_matrix_h
-#define EXPP_matrix_h
-
-#include <Python.h>
-
-extern PyTypeObject matrix_Type;
-#define MatrixObject_Check(_v) PyObject_TypeCheck((_v), &matrix_Type)
-
-typedef float **ptRow;
-typedef struct _Matrix { /* keep aligned with BaseMathObject in Mathutils.h */
- PyObject_VAR_HEAD
- float *contigPtr; /*1D array of data (alias)*/
- PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */
- unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */
- unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */
- unsigned char wrapped; /*is wrapped data?*/
- /* end BaseMathObject */
-
- unsigned char rowSize;
- unsigned int colSize;
- ptRow matrix; /*ptr to the contigPtr (accessor)*/
-
-} MatrixObject;
-
-/*struct data contains a pointer to the actual data that the
-object uses. It can use either PyMem allocated data (which will
-be stored in py_data) or be a wrapper for data allocated through
-blender (stored in blend_data). This is an either/or struct not both*/
-
-/*prototypes*/
-PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type, PyTypeObject *base_type);
-PyObject *newMatrixObject_cb(PyObject *user, int rowSize, int colSize, int cb_type, int cb_subtype);
-
-extern int mathutils_matrix_vector_cb_index;
-extern struct Mathutils_Callback mathutils_matrix_vector_cb;
-
-#endif /* EXPP_matrix_H */
diff --git a/source/blender/python/generic/quat.c b/source/blender/python/generic/quat.c
deleted file mode 100644
index a353f73c854..00000000000
--- a/source/blender/python/generic/quat.c
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- *
- * Contributor(s): Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "Mathutils.h"
-
-#include "BLI_arithb.h"
-#include "BKE_utildefines.h"
-#include "BLI_blenlib.h"
-
-
-//-------------------------DOC STRINGS ---------------------------
-
-static PyObject *Quaternion_Identity( QuaternionObject * self );
-static PyObject *Quaternion_Negate( QuaternionObject * self );
-static PyObject *Quaternion_Conjugate( QuaternionObject * self );
-static PyObject *Quaternion_Inverse( QuaternionObject * self );
-static PyObject *Quaternion_Normalize( QuaternionObject * self );
-static PyObject *Quaternion_ToEuler( QuaternionObject * self, PyObject *args );
-static PyObject *Quaternion_ToMatrix( QuaternionObject * self );
-static PyObject *Quaternion_Cross( QuaternionObject * self, QuaternionObject * value );
-static PyObject *Quaternion_Dot( QuaternionObject * self, QuaternionObject * value );
-static PyObject *Quaternion_copy( QuaternionObject * self );
-
-//-----------------------METHOD DEFINITIONS ----------------------
-static struct PyMethodDef Quaternion_methods[] = {
- {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, NULL},
- {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, NULL},
- {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, NULL},
- {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, NULL},
- {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, NULL},
- {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, NULL},
- {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, NULL},
- {"cross", (PyCFunction) Quaternion_Cross, METH_O, NULL},
- {"dot", (PyCFunction) Quaternion_Dot, METH_O, NULL},
- {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL},
- {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, NULL},
- {NULL, NULL, 0, NULL}
-};
-
-//----------------------------------Mathutils.Quaternion() --------------
-static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *listObject = NULL, *n, *q;
- int size, i;
- float quat[4];
- double angle = 0.0f;
-
- size = PyTuple_GET_SIZE(args);
- if (size == 1 || size == 2) { //seq?
- listObject = PyTuple_GET_ITEM(args, 0);
- if (PySequence_Check(listObject)) {
- size = PySequence_Length(listObject);
- if ((size == 4 && PySequence_Length(args) !=1) ||
- (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) {
- // invalid args/size
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- if(size == 3){ //get angle in axis/angle
- n = PySequence_GetItem(args, 1);
- if(n == NULL) { // parsed item not a number or getItem fail
- PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
-
- angle = PyFloat_AsDouble(n);
- Py_DECREF(n);
-
- if (angle==-1 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- }
- }else{
- listObject = PyTuple_GET_ITEM(args, 1);
- if (size>1 && PySequence_Check(listObject)) {
- size = PySequence_Length(listObject);
- if (size != 3) {
- // invalid args/size
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- angle = PyFloat_AsDouble(PyTuple_GET_ITEM(args, 0));
-
- if (angle==-1 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- } else { // argument was not a sequence
- PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- }
- } else if (size == 0) { //returns a new empty quat
- return newQuaternionObject(NULL, Py_NEW, NULL);
- } else {
- listObject = args;
- }
-
- if (size == 3) { // invalid quat size
- if(PySequence_Length(args) != 2){
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- }else{
- if(size != 4){
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- }
-
- for (i=0; i<size; i++) { //parse
- q = PySequence_GetItem(listObject, i);
- if (q == NULL) { // Failed to read sequence
- PyErr_SetString(PyExc_RuntimeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
-
- quat[i] = PyFloat_AsDouble(q);
- Py_DECREF(q);
-
- if (quat[i]==-1 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
- return NULL;
- }
- }
-
- if(size == 3) //calculate the quat based on axis/angle
-#ifdef USE_MATHUTILS_DEG
- AxisAngleToQuat(quat, quat, angle * (Py_PI / 180));
-#else
- AxisAngleToQuat(quat, quat, angle);
-#endif
-
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-
-//-----------------------------METHODS------------------------------
-//----------------------------Quaternion.toEuler()------------------
-//return the quat as a euler
-static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
-{
- float eul[3];
- EulerObject *eul_compat = NULL;
-
- if(!PyArg_ParseTuple(args, "|O!:toEuler", &euler_Type, &eul_compat))
- return NULL;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if(eul_compat) {
- float mat[3][3];
-
- if(!BaseMath_ReadCallback(eul_compat))
- return NULL;
-
- QuatToMat3(self->quat, mat);
-
-#ifdef USE_MATHUTILS_DEG
- {
- float eul_compatf[3];
- int x;
-
- for(x = 0; x < 3; x++) {
- eul_compatf[x] = eul_compat->eul[x] * ((float)Py_PI / 180);
- }
- Mat3ToCompatibleEul(mat, eul, eul_compatf);
- }
-#else
- Mat3ToCompatibleEul(mat, eul, eul_compat->eul);
-#endif
- }
- else {
- QuatToEul(self->quat, eul);
- }
-
-#ifdef USE_MATHUTILS_DEG
- {
- int x;
-
- for(x = 0; x < 3; x++) {
- eul[x] *= (180 / (float)Py_PI);
- }
- }
-#endif
- return newEulerObject(eul, Py_NEW, NULL);
-}
-//----------------------------Quaternion.toMatrix()------------------
-//return the quat as a matrix
-static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
-{
- float mat[9]; /* all values are set */
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- QuatToMat3(self->quat, (float (*)[3]) mat);
- return newMatrixObject(mat, 3, 3, Py_NEW, NULL);
-}
-
-//----------------------------Quaternion.cross(other)------------------
-//return the cross quat
-static PyObject *Quaternion_Cross(QuaternionObject * self, QuaternionObject * value)
-{
- float quat[4];
-
- if (!QuaternionObject_Check(value)) {
- PyErr_SetString( PyExc_TypeError, "quat.cross(value): expected a quaternion argument" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
- return NULL;
-
- QuatMul(quat, self->quat, value->quat);
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-
-//----------------------------Quaternion.dot(other)------------------
-//return the dot quat
-static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value)
-{
- if (!QuaternionObject_Check(value)) {
- PyErr_SetString( PyExc_TypeError, "quat.dot(value): expected a quaternion argument" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
- return NULL;
-
- return PyFloat_FromDouble(QuatDot(self->quat, value->quat));
-}
-
-//----------------------------Quaternion.normalize()----------------
-//normalize the axis of rotation of [theta,vector]
-static PyObject *Quaternion_Normalize(QuaternionObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- NormalQuat(self->quat);
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
-}
-//----------------------------Quaternion.inverse()------------------
-//invert the quat
-static PyObject *Quaternion_Inverse(QuaternionObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- QuatInv(self->quat);
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
-}
-//----------------------------Quaternion.identity()-----------------
-//generate the identity quaternion
-static PyObject *Quaternion_Identity(QuaternionObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- QuatOne(self->quat);
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
-}
-//----------------------------Quaternion.negate()-------------------
-//negate the quat
-static PyObject *Quaternion_Negate(QuaternionObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- QuatMulf(self->quat, -1.0f);
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
-}
-//----------------------------Quaternion.conjugate()----------------
-//negate the vector part
-static PyObject *Quaternion_Conjugate(QuaternionObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- QuatConj(self->quat);
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
-}
-//----------------------------Quaternion.copy()----------------
-//return a copy of the quat
-static PyObject *Quaternion_copy(QuaternionObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- return newQuaternionObject(self->quat, Py_NEW, Py_TYPE(self));
-}
-
-//----------------------------print object (internal)--------------
-//print the object to screen
-static PyObject *Quaternion_repr(QuaternionObject * self)
-{
- char str[64];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- sprintf(str, "[%.6f, %.6f, %.6f, %.6f](quaternion)", self->quat[0], self->quat[1], self->quat[2], self->quat[3]);
- return PyUnicode_FromString(str);
-}
-//------------------------tp_richcmpr
-//returns -1 execption, 0 false, 1 true
-static PyObject* Quaternion_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
-{
- QuaternionObject *quatA = NULL, *quatB = NULL;
- int result = 0;
-
- if(QuaternionObject_Check(objectA)) {
- quatA = (QuaternionObject*)objectA;
- if(!BaseMath_ReadCallback(quatA))
- return NULL;
- }
- if(QuaternionObject_Check(objectB)) {
- quatB = (QuaternionObject*)objectB;
- if(!BaseMath_ReadCallback(quatB))
- return NULL;
- }
-
- if (!quatA || !quatB){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
- }
-
- switch (comparison_type){
- case Py_EQ:
- result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1);
- break;
- case Py_NE:
- result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1);
- if (result == 0){
- result = 1;
- }else{
- result = 0;
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
-}
-
-//---------------------SEQUENCE PROTOCOLS------------------------
-//----------------------------len(object)------------------------
-//sequence length
-static int Quaternion_len(QuaternionObject * self)
-{
- return 4;
-}
-//----------------------------object[]---------------------------
-//sequence accessor (get)
-static PyObject *Quaternion_item(QuaternionObject * self, int i)
-{
- if(i<0) i= 4-i;
-
- if(i < 0 || i >= 4) {
- PyErr_SetString(PyExc_IndexError, "quaternion[attribute]: array index out of range\n");
- return NULL;
- }
-
- if(!BaseMath_ReadIndexCallback(self, i))
- return NULL;
-
- return PyFloat_FromDouble(self->quat[i]);
-
-}
-//----------------------------object[]-------------------------
-//sequence accessor (set)
-static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob)
-{
- float scalar= (float)PyFloat_AsDouble(ob);
- if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
- PyErr_SetString(PyExc_TypeError, "quaternion[index] = x: index argument not a number\n");
- return -1;
- }
-
- if(i<0) i= 4-i;
-
- if(i < 0 || i >= 4){
- PyErr_SetString(PyExc_IndexError, "quaternion[attribute] = x: array assignment index out of range\n");
- return -1;
- }
- self->quat[i] = scalar;
-
- if(!BaseMath_WriteIndexCallback(self, i))
- return -1;
-
- return 0;
-}
-//----------------------------object[z:y]------------------------
-//sequence slice (get)
-static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end)
-{
- PyObject *list = NULL;
- int count;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- CLAMP(begin, 0, 4);
- if (end<0) end= 5+end;
- CLAMP(end, 0, 4);
- begin = MIN2(begin,end);
-
- list = PyList_New(end - begin);
- for(count = begin; count < end; count++) {
- PyList_SetItem(list, count - begin,
- PyFloat_FromDouble(self->quat[count]));
- }
-
- return list;
-}
-//----------------------------object[z:y]------------------------
-//sequence slice (set)
-static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, PyObject * seq)
-{
- int i, y, size = 0;
- float quat[4];
- PyObject *q;
-
- if(!BaseMath_ReadCallback(self))
- return -1;
-
- CLAMP(begin, 0, 4);
- if (end<0) end= 5+end;
- CLAMP(end, 0, 4);
- begin = MIN2(begin,end);
-
- size = PySequence_Length(seq);
- if(size != (end - begin)){
- PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: size mismatch in slice assignment\n");
- return -1;
- }
-
- for (i = 0; i < size; i++) {
- q = PySequence_GetItem(seq, i);
- if (q == NULL) { // Failed to read sequence
- PyErr_SetString(PyExc_RuntimeError, "quaternion[begin:end] = []: unable to read sequence\n");
- return -1;
- }
-
- quat[i]= (float)PyFloat_AsDouble(q);
- Py_DECREF(q);
-
- if(quat[i]==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
- PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: sequence argument not a number\n");
- return -1;
- }
- }
- //parsed well - now set in vector
- for(y = 0; y < size; y++)
- self->quat[begin + y] = quat[y];
-
- BaseMath_WriteCallback(self);
- return 0;
-}
-//------------------------NUMERIC PROTOCOLS----------------------
-//------------------------obj + obj------------------------------
-//addition
-static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
-{
- float quat[4];
- QuaternionObject *quat1 = NULL, *quat2 = NULL;
-
- if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
- PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n");
- return NULL;
- }
- quat1 = (QuaternionObject*)q1;
- quat2 = (QuaternionObject*)q2;
-
- if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
- return NULL;
-
- QuatAdd(quat, quat1->quat, quat2->quat, 1.0f);
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-//------------------------obj - obj------------------------------
-//subtraction
-static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
-{
- int x;
- float quat[4];
- QuaternionObject *quat1 = NULL, *quat2 = NULL;
-
- if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) {
- PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation....\n");
- return NULL;
- }
-
- quat1 = (QuaternionObject*)q1;
- quat2 = (QuaternionObject*)q2;
-
- if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
- return NULL;
-
- for(x = 0; x < 4; x++) {
- quat[x] = quat1->quat[x] - quat2->quat[x];
- }
-
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-//------------------------obj * obj------------------------------
-//mulplication
-static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
-{
- float quat[4], scalar;
- QuaternionObject *quat1 = NULL, *quat2 = NULL;
- VectorObject *vec = NULL;
-
- if(QuaternionObject_Check(q1)) {
- quat1 = (QuaternionObject*)q1;
- if(!BaseMath_ReadCallback(quat1))
- return NULL;
- }
- if(QuaternionObject_Check(q2)) {
- quat2 = (QuaternionObject*)q2;
- if(!BaseMath_ReadCallback(quat2))
- return NULL;
- }
-
- if(quat1 && quat2) { /* QUAT*QUAT (dot product) */
- return PyFloat_FromDouble(QuatDot(quat1->quat, quat2->quat));
- }
-
- /* the only case this can happen (for a supported type is "FLOAT*QUAT" ) */
- if(!QuaternionObject_Check(q1)) {
- scalar= PyFloat_AsDouble(q1);
- if ((scalar == -1.0 && PyErr_Occurred())==0) { /* FLOAT*QUAT */
- QUATCOPY(quat, quat2->quat);
- QuatMulf(quat, scalar);
- return newQuaternionObject(quat, Py_NEW, NULL);
- }
- PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: val * quat, val is not an acceptable type");
- return NULL;
- }
- else { /* QUAT*SOMETHING */
- if(VectorObject_Check(q2)){ /* QUAT*VEC */
- vec = (VectorObject*)q2;
- if(vec->size != 3){
- PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: only 3D vector rotations currently supported\n");
- return NULL;
- }
- return quat_rotation((PyObject*)quat1, (PyObject*)vec); /* vector updating done inside the func */
- }
-
- scalar= PyFloat_AsDouble(q2);
- if ((scalar == -1.0 && PyErr_Occurred())==0) { /* QUAT*FLOAT */
- QUATCOPY(quat, quat1->quat);
- QuatMulf(quat, scalar);
- return newQuaternionObject(quat, Py_NEW, NULL);
- }
- }
-
- PyErr_SetString(PyExc_TypeError, "Quaternion multiplication: arguments not acceptable for this operation\n");
- return NULL;
-}
-
-//-----------------PROTOCOL DECLARATIONS--------------------------
-static PySequenceMethods Quaternion_SeqMethods = {
- (inquiry) Quaternion_len, /* sq_length */
- (binaryfunc) 0, /* sq_concat */
- (ssizeargfunc) 0, /* sq_repeat */
- (ssizeargfunc) Quaternion_item, /* sq_item */
- (ssizessizeargfunc) Quaternion_slice, /* sq_slice */
- (ssizeobjargproc) Quaternion_ass_item, /* sq_ass_item */
- (ssizessizeobjargproc) Quaternion_ass_slice, /* sq_ass_slice */
-};
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static PyNumberMethods Quaternion_NumMethods = {
- (binaryfunc) Quaternion_add, /*nb_add*/
- (binaryfunc) Quaternion_sub, /*nb_subtract*/
- (binaryfunc) Quaternion_mul, /*nb_multiply*/
- 0, /*nb_remainder*/
- 0, /*nb_divmod*/
- 0, /*nb_power*/
- (unaryfunc) 0, /*nb_negative*/
- (unaryfunc) 0, /*tp_positive*/
- (unaryfunc) 0, /*tp_absolute*/
- (inquiry) 0, /*tp_bool*/
- (unaryfunc) 0, /*nb_invert*/
- 0, /*nb_lshift*/
- (binaryfunc)0, /*nb_rshift*/
- 0, /*nb_and*/
- 0, /*nb_xor*/
- 0, /*nb_or*/
- 0, /*nb_int*/
- 0, /*nb_reserved*/
- 0, /*nb_float*/
- 0, /* nb_inplace_add */
- 0, /* nb_inplace_subtract */
- 0, /* nb_inplace_multiply */
- 0, /* nb_inplace_remainder */
- 0, /* nb_inplace_power */
- 0, /* nb_inplace_lshift */
- 0, /* nb_inplace_rshift */
- 0, /* nb_inplace_and */
- 0, /* nb_inplace_xor */
- 0, /* nb_inplace_or */
- 0, /* nb_floor_divide */
- 0, /* nb_true_divide */
- 0, /* nb_inplace_floor_divide */
- 0, /* nb_inplace_true_divide */
- 0, /* nb_index */
-};
-#else
-static PyNumberMethods Quaternion_NumMethods = {
- (binaryfunc) Quaternion_add, /* __add__ */
- (binaryfunc) Quaternion_sub, /* __sub__ */
- (binaryfunc) Quaternion_mul, /* __mul__ */
- (binaryfunc) 0, /* __div__ */
- (binaryfunc) 0, /* __mod__ */
- (binaryfunc) 0, /* __divmod__ */
- (ternaryfunc) 0, /* __pow__ */
- (unaryfunc) 0, /* __neg__ */
- (unaryfunc) 0, /* __pos__ */
- (unaryfunc) 0, /* __abs__ */
- (inquiry) 0, /* __nonzero__ */
- (unaryfunc) 0, /* __invert__ */
- (binaryfunc) 0, /* __lshift__ */
- (binaryfunc) 0, /* __rshift__ */
- (binaryfunc) 0, /* __and__ */
- (binaryfunc) 0, /* __xor__ */
- (binaryfunc) 0, /* __or__ */
- /*(coercion)*/ 0, /* __coerce__ */
- (unaryfunc) 0, /* __int__ */
- (unaryfunc) 0, /* __long__ */
- (unaryfunc) 0, /* __float__ */
- (unaryfunc) 0, /* __oct__ */
- (unaryfunc) 0, /* __hex__ */
-};
-#endif
-
-static PyObject *Quaternion_getAxis( QuaternionObject * self, void *type )
-{
- return Quaternion_item(self, GET_INT_FROM_POINTER(type));
-}
-
-static int Quaternion_setAxis( QuaternionObject * self, PyObject * value, void * type )
-{
- return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value);
-}
-
-static PyObject *Quaternion_getMagnitude( QuaternionObject * self, void *type )
-{
- return PyFloat_FromDouble(sqrt(QuatDot(self->quat, self->quat)));
-}
-
-static PyObject *Quaternion_getAngle( QuaternionObject * self, void *type )
-{
- double ang = self->quat[0];
- ang = 2 * (saacos(ang));
-#ifdef USE_MATHUTILS_DEG
- ang *= (180 / Py_PI);
-#endif
- return PyFloat_FromDouble(ang);
-}
-
-static PyObject *Quaternion_getAxisVec( QuaternionObject * self, void *type )
-{
- int i;
- float vec[3];
- double mag = self->quat[0] * (Py_PI / 180);
- mag = 2 * (saacos(mag));
- mag = sin(mag / 2);
- for(i = 0; i < 3; i++)
- vec[i] = (float)(self->quat[i + 1] / mag);
-
- Normalize(vec);
- //If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations
- if( EXPP_FloatsAreEqual(vec[0], 0.0f, 10) &&
- EXPP_FloatsAreEqual(vec[1], 0.0f, 10) &&
- EXPP_FloatsAreEqual(vec[2], 0.0f, 10) ){
- vec[0] = 1.0f;
- }
- return (PyObject *) newVectorObject(vec, 3, Py_NEW, NULL);
-}
-
-
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
-static PyGetSetDef Quaternion_getseters[] = {
- {"w",
- (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
- "Quaternion W value",
- (void *)0},
- {"x",
- (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
- "Quaternion X axis",
- (void *)1},
- {"y",
- (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
- "Quaternion Y axis",
- (void *)2},
- {"z",
- (getter)Quaternion_getAxis, (setter)Quaternion_setAxis,
- "Quaternion Z axis",
- (void *)3},
- {"magnitude",
- (getter)Quaternion_getMagnitude, (setter)NULL,
- "Size of the quaternion",
- NULL},
- {"angle",
- (getter)Quaternion_getAngle, (setter)NULL,
- "angle of the quaternion",
- NULL},
- {"axis",
- (getter)Quaternion_getAxisVec, (setter)NULL,
- "quaternion axis as a vector",
- NULL},
- {"wrapped",
- (getter)BaseMathObject_getWrapped, (setter)NULL,
- "True when this wraps blenders internal data",
- NULL},
- {"__owner__",
- (getter)BaseMathObject_getOwner, (setter)NULL,
- "Read only owner for vectors that depend on another object",
- NULL},
-
- {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
-};
-
-
-//------------------PY_OBECT DEFINITION--------------------------
-PyTypeObject quaternion_Type = {
-#if (PY_VERSION_HEX >= 0x02060000)
- PyVarObject_HEAD_INIT(NULL, 0)
-#else
- /* python 2.5 and below */
- PyObject_HEAD_INIT( NULL ) /* required py macro */
- 0, /* ob_size */
-#endif
- "quaternion", //tp_name
- sizeof(QuaternionObject), //tp_basicsize
- 0, //tp_itemsize
- (destructor)BaseMathObject_dealloc, //tp_dealloc
- 0, //tp_print
- 0, //tp_getattr
- 0, //tp_setattr
- 0, //tp_compare
- (reprfunc) Quaternion_repr, //tp_repr
- &Quaternion_NumMethods, //tp_as_number
- &Quaternion_SeqMethods, //tp_as_sequence
- 0, //tp_as_mapping
- 0, //tp_hash
- 0, //tp_call
- 0, //tp_str
- 0, //tp_getattro
- 0, //tp_setattro
- 0, //tp_as_buffer
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //tp_flags
- 0, //tp_doc
- 0, //tp_traverse
- 0, //tp_clear
- (richcmpfunc)Quaternion_richcmpr, //tp_richcompare
- 0, //tp_weaklistoffset
- 0, //tp_iter
- 0, //tp_iternext
- Quaternion_methods, //tp_methods
- 0, //tp_members
- Quaternion_getseters, //tp_getset
- 0, //tp_base
- 0, //tp_dict
- 0, //tp_descr_get
- 0, //tp_descr_set
- 0, //tp_dictoffset
- 0, //tp_init
- 0, //tp_alloc
- Quaternion_new, //tp_new
- 0, //tp_free
- 0, //tp_is_gc
- 0, //tp_bases
- 0, //tp_mro
- 0, //tp_cache
- 0, //tp_subclasses
- 0, //tp_weaklist
- 0 //tp_del
-};
-//------------------------newQuaternionObject (internal)-------------
-//creates a new quaternion object
-/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- (i.e. it was allocated elsewhere by MEM_mallocN())
- pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type)
-{
- QuaternionObject *self;
-
- if(base_type) self = (QuaternionObject *)base_type->tp_alloc(base_type, 0);
- else self = PyObject_NEW(QuaternionObject, &quaternion_Type);
-
- /* init callbacks as NULL */
- self->cb_user= NULL;
- self->cb_type= self->cb_subtype= 0;
-
- if(type == Py_WRAP){
- self->quat = quat;
- self->wrapped = Py_WRAP;
- }else if (type == Py_NEW){
- self->quat = PyMem_Malloc(4 * sizeof(float));
- if(!quat) { //new empty
- QuatOne(self->quat);
- }else{
- QUATCOPY(self->quat, quat);
- }
- self->wrapped = Py_NEW;
- }else{ //bad type
- return NULL;
- }
- return (PyObject *) self;
-}
-
-PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype)
-{
- QuaternionObject *self= (QuaternionObject *)newQuaternionObject(NULL, Py_NEW, NULL);
- if(self) {
- Py_INCREF(cb_user);
- self->cb_user= cb_user;
- self->cb_type= (unsigned char)cb_type;
- self->cb_subtype= (unsigned char)cb_subtype;
- }
-
- return (PyObject *)self;
-}
diff --git a/source/blender/python/generic/quat.h b/source/blender/python/generic/quat.h
deleted file mode 100644
index a7cfb7898b1..00000000000
--- a/source/blender/python/generic/quat.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-#ifndef EXPP_quat_h
-#define EXPP_quat_h
-
-#include <Python.h>
-#include "../intern/bpy_compat.h"
-
-extern PyTypeObject quaternion_Type;
-#define QuaternionObject_Check(_v) PyObject_TypeCheck((_v), &quaternion_Type)
-
-typedef struct { /* keep aligned with BaseMathObject in Mathutils.h */
- PyObject_VAR_HEAD
- float *quat; /* 1D array of data (alias) */
- PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */
- unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */
- unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */
- unsigned char wrapped; /* wrapped data type? */
- /* end BaseMathObject */
-
-} QuaternionObject;
-
-/*struct data contains a pointer to the actual data that the
-object uses. It can use either PyMem allocated data (which will
-be stored in py_data) or be a wrapper for data allocated through
-blender (stored in blend_data). This is an either/or struct not both*/
-
-//prototypes
-PyObject *newQuaternionObject( float *quat, int type, PyTypeObject *base_type);
-PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype);
-
-#endif /* EXPP_quat_h */
diff --git a/source/blender/python/generic/vector.c b/source/blender/python/generic/vector.c
deleted file mode 100644
index cf2396b30d4..00000000000
--- a/source/blender/python/generic/vector.c
+++ /dev/null
@@ -1,2078 +0,0 @@
-/*
- * $Id$
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- *
- * Contributor(s): Willian P. Germano, Joseph Gilbert, Ken Hughes, Alex Fraser, Campbell Barton
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#include "Mathutils.h"
-
-#include "BLI_blenlib.h"
-#include "BKE_utildefines.h"
-#include "BLI_arithb.h"
-
-#define MAX_DIMENSIONS 4
-/* Swizzle axes get packed into a single value that is used as a closure. Each
- axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is
- used as a sentinel: if it is unset, the axis is not valid. */
-#define SWIZZLE_BITS_PER_AXIS 3
-#define SWIZZLE_VALID_AXIS 0x4
-#define SWIZZLE_AXIS 0x3
-
-static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat); /* utility func */
-
-/*-----------------------METHOD DEFINITIONS ----------------------*/
-static PyObject *Vector_Zero( VectorObject * self );
-static PyObject *Vector_Normalize( VectorObject * self );
-static PyObject *Vector_Negate( VectorObject * self );
-static PyObject *Vector_Resize2D( VectorObject * self );
-static PyObject *Vector_Resize3D( VectorObject * self );
-static PyObject *Vector_Resize4D( VectorObject * self );
-static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args );
-static PyObject *Vector_Reflect( VectorObject *self, VectorObject *value );
-static PyObject *Vector_Cross( VectorObject * self, VectorObject * value );
-static PyObject *Vector_Dot( VectorObject * self, VectorObject * value );
-static PyObject *Vector_copy( VectorObject * self );
-
-static struct PyMethodDef Vector_methods[] = {
- {"zero", (PyCFunction) Vector_Zero, METH_NOARGS, NULL},
- {"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, NULL},
- {"negate", (PyCFunction) Vector_Negate, METH_NOARGS, NULL},
- {"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, NULL},
- {"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, NULL},
- {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, NULL},
- {"toTrackQuat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, NULL},
- {"reflect", ( PyCFunction ) Vector_Reflect, METH_O, NULL},
- {"cross", ( PyCFunction ) Vector_Cross, METH_O, NULL},
- {"dot", ( PyCFunction ) Vector_Dot, METH_O, NULL},
- {"copy", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
- {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
- {NULL, NULL, 0, NULL}
-};
-
-//----------------------------------Mathutils.Vector() ------------------
-// Supports 2D, 3D, and 4D vector objects both int and float values
-// accepted. Mixed float and int values accepted. Ints are parsed to float
-static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyObject *listObject = NULL;
- int size, i;
- float vec[4], f;
- PyObject *v;
-
- size = PyTuple_GET_SIZE(args); /* we know its a tuple because its an arg */
- if (size == 1) {
- listObject = PyTuple_GET_ITEM(args, 0);
- if (PySequence_Check(listObject)) {
- size = PySequence_Length(listObject);
- } else { // Single argument was not a sequence
- PyErr_SetString(PyExc_TypeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
- return NULL;
- }
- } else if (size == 0) {
- //returns a new empty 3d vector
- return newVectorObject(NULL, 3, Py_NEW, type);
- } else {
- listObject = args;
- }
-
- if (size<2 || size>4) { // Invalid vector size
- PyErr_SetString(PyExc_AttributeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
- return NULL;
- }
-
- for (i=0; i<size; i++) {
- v=PySequence_GetItem(listObject, i);
- if (v==NULL) { // Failed to read sequence
- PyErr_SetString(PyExc_RuntimeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
- return NULL;
- }
-
- f= PyFloat_AsDouble(v);
- if(f==-1 && PyErr_Occurred()) { // parsed item not a number
- Py_DECREF(v);
- PyErr_SetString(PyExc_TypeError, "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
- return NULL;
- }
-
- vec[i]= f;
- Py_DECREF(v);
- }
- return newVectorObject(vec, size, Py_NEW, type);
-}
-
-/*-----------------------------METHODS---------------------------- */
-/*----------------------------Vector.zero() ----------------------
- set the vector data to 0,0,0 */
-static PyObject *Vector_Zero(VectorObject * self)
-{
- int i;
- for(i = 0; i < self->size; i++) {
- self->vec[i] = 0.0f;
- }
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
-}
-/*----------------------------Vector.normalize() -----------------
- normalize the vector data to a unit vector */
-static PyObject *Vector_Normalize(VectorObject * self)
-{
- int i;
- float norm = 0.0f;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- for(i = 0; i < self->size; i++) {
- norm += self->vec[i] * self->vec[i];
- }
- norm = (float) sqrt(norm);
- for(i = 0; i < self->size; i++) {
- self->vec[i] /= norm;
- }
-
- BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
-}
-
-
-/*----------------------------Vector.resize2D() ------------------
- resize the vector to x,y */
-static PyObject *Vector_Resize2D(VectorObject * self)
-{
- if(self->wrapped==Py_WRAP) {
- PyErr_SetString(PyExc_TypeError, "vector.resize2d(): cannot resize wrapped data - only python vectors\n");
- return NULL;
- }
- if(self->cb_user) {
- PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner");
- return NULL;
- }
-
- self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2));
- if(self->vec == NULL) {
- PyErr_SetString(PyExc_MemoryError, "vector.resize2d(): problem allocating pointer space\n\n");
- return NULL;
- }
-
- self->size = 2;
- Py_INCREF(self);
- return (PyObject*)self;
-}
-/*----------------------------Vector.resize3D() ------------------
- resize the vector to x,y,z */
-static PyObject *Vector_Resize3D(VectorObject * self)
-{
- if (self->wrapped==Py_WRAP) {
- PyErr_SetString(PyExc_TypeError, "vector.resize3d(): cannot resize wrapped data - only python vectors\n");
- return NULL;
- }
- if(self->cb_user) {
- PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner");
- return NULL;
- }
-
- self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3));
- if(self->vec == NULL) {
- PyErr_SetString(PyExc_MemoryError, "vector.resize3d(): problem allocating pointer space\n\n");
- return NULL;
- }
-
- if(self->size == 2)
- self->vec[2] = 0.0f;
-
- self->size = 3;
- Py_INCREF(self);
- return (PyObject*)self;
-}
-/*----------------------------Vector.resize4D() ------------------
- resize the vector to x,y,z,w */
-static PyObject *Vector_Resize4D(VectorObject * self)
-{
- if(self->wrapped==Py_WRAP) {
- PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize wrapped data - only python vectors");
- return NULL;
- }
- if(self->cb_user) {
- PyErr_SetString(PyExc_TypeError, "vector.resize4d(): cannot resize a vector that has an owner");
- return NULL;
- }
-
- self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4));
- if(self->vec == NULL) {
- PyErr_SetString(PyExc_MemoryError, "vector.resize4d(): problem allocating pointer space\n\n");
- return NULL;
- }
- if(self->size == 2){
- self->vec[2] = 0.0f;
- self->vec[3] = 1.0f;
- }else if(self->size == 3){
- self->vec[3] = 1.0f;
- }
- self->size = 4;
- Py_INCREF(self);
- return (PyObject*)self;
-}
-/*----------------------------Vector.toTrackQuat(track, up) ----------------------
- extract a quaternion from the vector and the track and up axis */
-static PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
-{
- float vec[3], quat[4];
- char *strack, *sup;
- short track = 2, up = 1;
-
- if( !PyArg_ParseTuple ( args, "|ss", &strack, &sup ) ) {
- PyErr_SetString( PyExc_TypeError, "expected optional two strings\n" );
- return NULL;
- }
- if (self->size != 3) {
- PyErr_SetString( PyExc_TypeError, "only for 3D vectors\n" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if (strack) {
- if (strlen(strack) == 2) {
- if (strack[0] == '-') {
- switch(strack[1]) {
- case 'X':
- case 'x':
- track = 3;
- break;
- case 'Y':
- case 'y':
- track = 4;
- break;
- case 'z':
- case 'Z':
- track = 5;
- break;
- default:
- PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" );
- return NULL;
- }
- }
- else {
- PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" );
- return NULL;
- }
- }
- else if (strlen(strack) == 1) {
- switch(strack[0]) {
- case '-':
- case 'X':
- case 'x':
- track = 0;
- break;
- case 'Y':
- case 'y':
- track = 1;
- break;
- case 'z':
- case 'Z':
- track = 2;
- break;
- default:
- PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" );
- return NULL;
- }
- }
- else {
- PyErr_SetString( PyExc_ValueError, "only X, -X, Y, -Y, Z or -Z for track axis\n" );
- return NULL;
- }
- }
-
- if (sup) {
- if (strlen(sup) == 1) {
- switch(*sup) {
- case 'X':
- case 'x':
- up = 0;
- break;
- case 'Y':
- case 'y':
- up = 1;
- break;
- case 'z':
- case 'Z':
- up = 2;
- break;
- default:
- PyErr_SetString( PyExc_ValueError, "only X, Y or Z for up axis\n" );
- return NULL;
- }
- }
- else {
- PyErr_SetString( PyExc_ValueError, "only X, Y or Z for up axis\n" );
- return NULL;
- }
- }
-
- if (track == up) {
- PyErr_SetString( PyExc_ValueError, "Can't have the same axis for track and up\n" );
- return NULL;
- }
-
- /*
- flip vector around, since vectoquat expect a vector from target to tracking object
- and the python function expects the inverse (a vector to the target).
- */
- vec[0] = -self->vec[0];
- vec[1] = -self->vec[1];
- vec[2] = -self->vec[2];
-
- vectoquat(vec, track, up, quat);
-
- return newQuaternionObject(quat, Py_NEW, NULL);
-}
-
-/*----------------------------Vector.reflect(mirror) ----------------------
- return a reflected vector on the mirror normal
- ((2 * DotVecs(vec, mirror)) * mirror) - vec
- using arithb.c would be nice here */
-static PyObject *Vector_Reflect( VectorObject * self, VectorObject * value )
-{
- float mirror[3];
- float vec[3];
- float reflect[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- float dot2;
-
- /* for normalizing */
- int i;
- float norm = 0.0f;
-
- if (!VectorObject_Check(value)) {
- PyErr_SetString( PyExc_TypeError, "vec.reflect(value): expected a vector argument" );
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
- return NULL;
-
- mirror[0] = value->vec[0];
- mirror[1] = value->vec[1];
- if (value->size > 2) mirror[2] = value->vec[2];
- else mirror[2] = 0.0;
-
- /* normalize, whos idea was it not to use arithb.c? :-/ */
- for(i = 0; i < 3; i++) {
- norm += mirror[i] * mirror[i];
- }
- norm = (float) sqrt(norm);
- for(i = 0; i < 3; i++) {
- mirror[i] /= norm;
- }
- /* done */
-
- vec[0] = self->vec[0];
- vec[1] = self->vec[1];
- if (self->size > 2) vec[2] = self->vec[2];
- else vec[2] = 0.0;
-
- dot2 = 2 * vec[0]*mirror[0]+vec[1]*mirror[1]+vec[2]*mirror[2];
-
- reflect[0] = (dot2 * mirror[0]) - vec[0];
- reflect[1] = (dot2 * mirror[1]) - vec[1];
- reflect[2] = (dot2 * mirror[2]) - vec[2];
-
- return newVectorObject(reflect, self->size, Py_NEW, NULL);
-}
-
-static PyObject *Vector_Cross( VectorObject * self, VectorObject * value )
-{
- VectorObject *vecCross = NULL;
-
- if (!VectorObject_Check(value)) {
- PyErr_SetString( PyExc_TypeError, "vec.cross(value): expected a vector argument" );
- return NULL;
- }
-
- if(self->size != 3 || value->size != 3) {
- PyErr_SetString(PyExc_AttributeError, "vec.cross(value): expects both vectors to be 3D\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
- return NULL;
-
- vecCross = (VectorObject *)newVectorObject(NULL, 3, Py_NEW, NULL);
- Crossf(vecCross->vec, self->vec, value->vec);
- return (PyObject *)vecCross;
-}
-
-static PyObject *Vector_Dot( VectorObject * self, VectorObject * value )
-{
- double dot = 0.0;
- int x;
-
- if (!VectorObject_Check(value)) {
- PyErr_SetString( PyExc_TypeError, "vec.cross(value): expected a vector argument" );
- return NULL;
- }
-
- if(self->size != value->size) {
- PyErr_SetString(PyExc_AttributeError, "vec.dot(value): expects both vectors to have the same size\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
- return NULL;
-
- for(x = 0; x < self->size; x++) {
- dot += self->vec[x] * value->vec[x];
- }
- return PyFloat_FromDouble(dot);
-}
-
-/*----------------------------Vector.copy() --------------------------------------
- return a copy of the vector */
-static PyObject *Vector_copy(VectorObject * self)
-{
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- return newVectorObject(self->vec, self->size, Py_NEW, Py_TYPE(self));
-}
-
-/*----------------------------print object (internal)-------------
- print the object to screen */
-static PyObject *Vector_repr(VectorObject * self)
-{
- int i;
- char buffer[48], str[1024];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- BLI_strncpy(str,"[",1024);
- for(i = 0; i < self->size; i++){
- if(i < (self->size - 1)){
- sprintf(buffer, "%.6f, ", self->vec[i]);
- strcat(str,buffer);
- }else{
- sprintf(buffer, "%.6f", self->vec[i]);
- strcat(str,buffer);
- }
- }
- strcat(str, "](vector)");
-
- return PyUnicode_FromString(str);
-}
-/*---------------------SEQUENCE PROTOCOLS------------------------
- ----------------------------len(object)------------------------
- sequence length*/
-static int Vector_len(VectorObject * self)
-{
- return self->size;
-}
-/*----------------------------object[]---------------------------
- sequence accessor (get)*/
-static PyObject *Vector_item(VectorObject * self, int i)
-{
- if(i<0) i= self->size-i;
-
- if(i < 0 || i >= self->size) {
- PyErr_SetString(PyExc_IndexError,"vector[index]: out of range\n");
- return NULL;
- }
-
- if(!BaseMath_ReadIndexCallback(self, i))
- return NULL;
-
- return PyFloat_FromDouble(self->vec[i]);
-
-}
-/*----------------------------object[]-------------------------
- sequence accessor (set)*/
-static int Vector_ass_item(VectorObject * self, int i, PyObject * ob)
-{
- float scalar= (float)PyFloat_AsDouble(ob);
- if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
- PyErr_SetString(PyExc_TypeError, "vector[index] = x: index argument not a number\n");
- return -1;
- }
-
- if(i<0) i= self->size-i;
-
- if(i < 0 || i >= self->size){
- PyErr_SetString(PyExc_IndexError, "vector[index] = x: assignment index out of range\n");
- return -1;
- }
- self->vec[i] = scalar;
-
- if(!BaseMath_WriteIndexCallback(self, i))
- return -1;
- return 0;
-}
-
-/*----------------------------object[z:y]------------------------
- sequence slice (get) */
-static PyObject *Vector_slice(VectorObject * self, int begin, int end)
-{
- PyObject *list = NULL;
- int count;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- CLAMP(begin, 0, self->size);
- if (end<0) end= self->size+end+1;
- CLAMP(end, 0, self->size);
- begin = MIN2(begin,end);
-
- list = PyList_New(end - begin);
- for(count = begin; count < end; count++) {
- PyList_SetItem(list, count - begin,
- PyFloat_FromDouble(self->vec[count]));
- }
-
- return list;
-}
-/*----------------------------object[z:y]------------------------
- sequence slice (set) */
-static int Vector_ass_slice(VectorObject * self, int begin, int end,
- PyObject * seq)
-{
- int i, y, size = 0;
- float vec[4], scalar;
- PyObject *v;
-
- if(!BaseMath_ReadCallback(self))
- return -1;
-
- CLAMP(begin, 0, self->size);
- if (end<0) end= self->size+end+1;
- CLAMP(end, 0, self->size);
- begin = MIN2(begin,end);
-
- size = PySequence_Length(seq);
- if(size != (end - begin)){
- PyErr_SetString(PyExc_TypeError, "vector[begin:end] = []: size mismatch in slice assignment\n");
- return -1;
- }
-
- for (i = 0; i < size; i++) {
- v = PySequence_GetItem(seq, i);
- if (v == NULL) { /* Failed to read sequence */
- PyErr_SetString(PyExc_RuntimeError, "vector[begin:end] = []: unable to read sequence\n");
- return -1;
- }
-
- scalar= (float)PyFloat_AsDouble(v);
- if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
- Py_DECREF(v);
- PyErr_SetString(PyExc_TypeError, "vector[begin:end] = []: sequence argument not a number\n");
- return -1;
- }
-
- vec[i] = scalar;
- Py_DECREF(v);
- }
- /*parsed well - now set in vector*/
- for(y = 0; y < size; y++){
- self->vec[begin + y] = vec[y];
- }
-
- if(!BaseMath_WriteCallback(self))
- return -1;
-
- return 0;
-}
-/*------------------------NUMERIC PROTOCOLS----------------------
- ------------------------obj + obj------------------------------
- addition*/
-static PyObject *Vector_add(PyObject * v1, PyObject * v2)
-{
- int i;
- float vec[4];
-
- VectorObject *vec1 = NULL, *vec2 = NULL;
-
- if VectorObject_Check(v1)
- vec1= (VectorObject *)v1;
-
- if VectorObject_Check(v2)
- vec2= (VectorObject *)v2;
-
- /* make sure v1 is always the vector */
- if (vec1 && vec2 ) {
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
- return NULL;
-
- /*VECTOR + VECTOR*/
- if(vec1->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n");
- return NULL;
- }
- for(i = 0; i < vec1->size; i++) {
- vec[i] = vec1->vec[i] + vec2->vec[i];
- }
- return newVectorObject(vec, vec1->size, Py_NEW, NULL);
- }
-
- PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n");
- return NULL;
-}
-
-/* ------------------------obj += obj------------------------------
- addition in place */
-static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
-{
- int i;
-
- VectorObject *vec1 = NULL, *vec2 = NULL;
-
- if VectorObject_Check(v1)
- vec1= (VectorObject *)v1;
-
- if VectorObject_Check(v2)
- vec2= (VectorObject *)v2;
-
- /* make sure v1 is always the vector */
- if (vec1 && vec2 ) {
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
- return NULL;
-
- /*VECTOR + VECTOR*/
- if(vec1->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "Vector addition: vectors must have the same dimensions for this operation\n");
- return NULL;
- }
- for(i = 0; i < vec1->size; i++) {
- vec1->vec[i] += vec2->vec[i];
- }
- Py_INCREF( v1 );
- return v1;
- }
-
- BaseMath_WriteCallback(vec1);
- PyErr_SetString(PyExc_AttributeError, "Vector addition: arguments not valid for this operation....\n");
- return NULL;
-}
-
-/*------------------------obj - obj------------------------------
- subtraction*/
-static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
-{
- int i;
- float vec[4];
- VectorObject *vec1 = NULL, *vec2 = NULL;
-
- if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
- PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation....\n");
- return NULL;
- }
- vec1 = (VectorObject*)v1;
- vec2 = (VectorObject*)v2;
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
- return NULL;
-
- if(vec1->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n");
- return NULL;
- }
- for(i = 0; i < vec1->size; i++) {
- vec[i] = vec1->vec[i] - vec2->vec[i];
- }
-
- return newVectorObject(vec, vec1->size, Py_NEW, NULL);
-}
-
-/*------------------------obj -= obj------------------------------
- subtraction*/
-static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
-{
- int i;
- VectorObject *vec1 = NULL, *vec2 = NULL;
-
- if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) {
- PyErr_SetString(PyExc_AttributeError, "Vector subtraction: arguments not valid for this operation....\n");
- return NULL;
- }
- vec1 = (VectorObject*)v1;
- vec2 = (VectorObject*)v2;
-
- if(vec1->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "Vector subtraction: vectors must have the same dimensions for this operation\n");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec1) || !BaseMath_ReadCallback(vec2))
- return NULL;
-
- for(i = 0; i < vec1->size; i++) {
- vec1->vec[i] = vec1->vec[i] - vec2->vec[i];
- }
-
- BaseMath_WriteCallback(vec1);
- Py_INCREF( v1 );
- return v1;
-}
-
-/*------------------------obj * obj------------------------------
- mulplication*/
-static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
-{
- VectorObject *vec1 = NULL, *vec2 = NULL;
- float scalar;
-
- if VectorObject_Check(v1) {
- vec1= (VectorObject *)v1;
- if(!BaseMath_ReadCallback(vec1))
- return NULL;
- }
- if VectorObject_Check(v2) {
- vec2= (VectorObject *)v2;
- if(!BaseMath_ReadCallback(vec2))
- return NULL;
- }
-
-
- /* make sure v1 is always the vector */
- if (vec1 && vec2 ) {
- int i;
- double dot = 0.0f;
-
- if(vec1->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "Vector multiplication: vectors must have the same dimensions for this operation\n");
- return NULL;
- }
-
- /*dot product*/
- for(i = 0; i < vec1->size; i++) {
- dot += vec1->vec[i] * vec2->vec[i];
- }
- return PyFloat_FromDouble(dot);
- }
-
- /*swap so vec1 is always the vector */
- if (vec2) {
- vec1= vec2;
- v2= v1;
- }
-
- if (MatrixObject_Check(v2)) {
- /* VEC * MATRIX */
- return row_vector_multiplication(vec1, (MatrixObject*)v2);
- } else if (QuaternionObject_Check(v2)) {
- QuaternionObject *quat = (QuaternionObject*)v2; /* quat_rotation validates */
-
- if(vec1->size != 3) {
- PyErr_SetString(PyExc_TypeError, "Vector multiplication: only 3D vector rotations (with quats) currently supported\n");
- return NULL;
- }
- return quat_rotation((PyObject*)vec1, (PyObject*)quat);
- }
- else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*FLOAT */
- int i;
- float vec[4];
-
- for(i = 0; i < vec1->size; i++) {
- vec[i] = vec1->vec[i] * scalar;
- }
- return newVectorObject(vec, vec1->size, Py_NEW, NULL);
-
- }
-
- PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n");
- return NULL;
-}
-
-/*------------------------obj *= obj------------------------------
- in place mulplication */
-static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
-{
- VectorObject *vec = (VectorObject *)v1;
- int i;
- float scalar;
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- /* only support vec*=float and vec*=mat
- vec*=vec result is a float so that wont work */
- if (MatrixObject_Check(v2)) {
- float vecCopy[4];
- int x,y, size = vec->size;
- MatrixObject *mat= (MatrixObject*)v2;
-
- if(!BaseMath_ReadCallback(mat))
- return NULL;
-
- if(mat->colSize != size){
- if(mat->rowSize == 4 && vec->size != 3){
- PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same");
- return NULL;
- } else {
- vecCopy[3] = 1.0f;
- }
- }
-
- for(i = 0; i < size; i++){
- vecCopy[i] = vec->vec[i];
- }
-
- size = MIN2(size, mat->colSize);
-
- /*muliplication*/
- for(x = 0, i = 0; x < size; x++, i++) {
- double dot = 0.0f;
- for(y = 0; y < mat->rowSize; y++) {
- dot += mat->matrix[y][x] * vecCopy[y];
- }
- vec->vec[i] = (float)dot;
- }
- }
- else if (((scalar= PyFloat_AsDouble(v2)) == -1.0 && PyErr_Occurred())==0) { /* VEC*=FLOAT */
-
- for(i = 0; i < vec->size; i++) {
- vec->vec[i] *= scalar;
- }
- }
- else {
- PyErr_SetString(PyExc_TypeError, "Vector multiplication: arguments not acceptable for this operation\n");
- return NULL;
- }
-
- BaseMath_WriteCallback(vec);
- Py_INCREF( v1 );
- return v1;
-}
-
-/*------------------------obj / obj------------------------------
- divide*/
-static PyObject *Vector_div(PyObject * v1, PyObject * v2)
-{
- int i;
- float vec[4], scalar;
- VectorObject *vec1 = NULL;
-
- if(!VectorObject_Check(v1)) { /* not a vector */
- PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n");
- return NULL;
- }
- vec1 = (VectorObject*)v1; /* vector */
-
- if(!BaseMath_ReadCallback(vec1))
- return NULL;
-
- scalar = (float)PyFloat_AsDouble(v2);
- if(scalar== -1.0f && PyErr_Occurred()) { /* parsed item not a number */
- PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n");
- return NULL;
- }
-
- if(scalar==0.0) { /* not a vector */
- PyErr_SetString(PyExc_ZeroDivisionError, "Vector division: divide by zero error.\n");
- return NULL;
- }
-
- for(i = 0; i < vec1->size; i++) {
- vec[i] = vec1->vec[i] / scalar;
- }
- return newVectorObject(vec, vec1->size, Py_NEW, NULL);
-}
-
-/*------------------------obj /= obj------------------------------
- divide*/
-static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
-{
- int i;
- float scalar;
- VectorObject *vec1 = (VectorObject*)v1;
-
- if(!BaseMath_ReadCallback(vec1))
- return NULL;
-
- scalar = (float)PyFloat_AsDouble(v2);
- if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
- PyErr_SetString(PyExc_TypeError, "Vector division: Vector must be divided by a float\n");
- return NULL;
- }
-
- if(scalar==0.0) { /* not a vector */
- PyErr_SetString(PyExc_ZeroDivisionError, "Vector division: divide by zero error.\n");
- return NULL;
- }
- for(i = 0; i < vec1->size; i++) {
- vec1->vec[i] /= scalar;
- }
-
- BaseMath_WriteCallback(vec1);
-
- Py_INCREF( v1 );
- return v1;
-}
-
-/*-------------------------- -obj -------------------------------
- returns the negative of this object*/
-static PyObject *Vector_neg(VectorObject *self)
-{
- int i;
- float vec[4];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- for(i = 0; i < self->size; i++){
- vec[i] = -self->vec[i];
- }
-
- return newVectorObject(vec, self->size, Py_NEW, Py_TYPE(self));
-}
-
-/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */
-static double vec_magnitude_nosqrt(float *data, int size)
-{
- double dot = 0.0f;
- int i;
-
- for(i=0; i<size; i++){
- dot += data[i];
- }
- /*return (double)sqrt(dot);*/
- /* warning, line above removed because we are not using the length,
- rather the comparing the sizes and for this we do not need the sqrt
- for the actual length, the dot must be sqrt'd */
- return (double)dot;
-}
-
-
-/*------------------------tp_richcmpr
- returns -1 execption, 0 false, 1 true */
-static PyObject* Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
-{
- VectorObject *vecA = NULL, *vecB = NULL;
- int result = 0;
- float epsilon = .000001f;
- double lenA,lenB;
-
- if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
- }
- vecA = (VectorObject*)objectA;
- vecB = (VectorObject*)objectB;
-
- if(!BaseMath_ReadCallback(vecA) || !BaseMath_ReadCallback(vecB))
- return NULL;
-
- if (vecA->size != vecB->size){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
- }
-
- switch (comparison_type){
- case Py_LT:
- lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
- lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
- if( lenA < lenB ){
- result = 1;
- }
- break;
- case Py_LE:
- lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
- lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
- if( lenA < lenB ){
- result = 1;
- }else{
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- case Py_EQ:
- result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1);
- break;
- case Py_NE:
- result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1);
- if (result == 0){
- result = 1;
- }else{
- result = 0;
- }
- break;
- case Py_GT:
- lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
- lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
- if( lenA > lenB ){
- result = 1;
- }
- break;
- case Py_GE:
- lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
- lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
- if( lenA > lenB ){
- result = 1;
- }else{
- result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
-}
-
-/*-----------------PROTCOL DECLARATIONS--------------------------*/
-static PySequenceMethods Vector_SeqMethods = {
- (inquiry) Vector_len, /* sq_length */
- (binaryfunc) 0, /* sq_concat */
- (ssizeargfunc) 0, /* sq_repeat */
- (ssizeargfunc) Vector_item, /* sq_item */
-#if (PY_VERSION_HEX < 0x03000000)
- (ssizessizeargfunc) Vector_slice, /* sq_slice */ /* PY2 ONLY */
-#else
- NULL,
-#endif
- (ssizeobjargproc) Vector_ass_item, /* sq_ass_item */
-#if (PY_VERSION_HEX < 0x03000000)
- (ssizessizeobjargproc) Vector_ass_slice, /* sq_ass_slice */ /* PY2 ONLY */
-#else
- NULL,
-#endif
-};
-
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static PyObject *Vector_subscript(VectorObject* self, PyObject* item)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i;
- i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return NULL;
- if (i < 0)
- i += self->size;
- return Vector_item(self, i);
- } else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx((PySliceObject*)item, self->size, &start, &stop, &step, &slicelength) < 0)
- return NULL;
-
- if (slicelength <= 0) {
- return PyList_New(0);
- }
- else if (step == 1) {
- return Vector_slice(self, start, stop);
- }
- else {
- PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
- return NULL;
- }
- }
- else {
- PyErr_Format(PyExc_TypeError,
- "vector indices must be integers, not %.200s",
- item->ob_type->tp_name);
- return NULL;
- }
-}
-
-static int Vector_ass_subscript(VectorObject* self, PyObject* item, PyObject* value)
-{
- if (PyIndex_Check(item)) {
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return -1;
- if (i < 0)
- i += self->size;
- return Vector_ass_item(self, i, value);
- }
- else if (PySlice_Check(item)) {
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx((PySliceObject*)item, self->size, &start, &stop, &step, &slicelength) < 0)
- return -1;
-
- if (step == 1)
- return Vector_ass_slice(self, start, stop, value);
- else {
- PyErr_SetString(PyExc_TypeError, "slice steps not supported with vectors");
- return -1;
- }
- }
- else {
- PyErr_Format(PyExc_TypeError,
- "vector indices must be integers, not %.200s",
- item->ob_type->tp_name);
- return -1;
- }
-}
-
-static PyMappingMethods Vector_AsMapping = {
- (lenfunc)Vector_len,
- (binaryfunc)Vector_subscript,
- (objobjargproc)Vector_ass_subscript
-};
-#endif /* (PY_VERSION_HEX >= 0x03000000) */
-
-#if (PY_VERSION_HEX >= 0x03000000)
-static PyNumberMethods Vector_NumMethods = {
- (binaryfunc) Vector_add, /*nb_add*/
- (binaryfunc) Vector_sub, /*nb_subtract*/
- (binaryfunc) Vector_mul, /*nb_multiply*/
- 0, /*nb_remainder*/
- 0, /*nb_divmod*/
- 0, /*nb_power*/
- (unaryfunc) Vector_neg, /*nb_negative*/
- (unaryfunc) 0, /*tp_positive*/
- (unaryfunc) 0, /*tp_absolute*/
- (inquiry) 0, /*tp_bool*/
- (unaryfunc) 0, /*nb_invert*/
- 0, /*nb_lshift*/
- (binaryfunc)0, /*nb_rshift*/
- 0, /*nb_and*/
- 0, /*nb_xor*/
- 0, /*nb_or*/
- 0, /*nb_int*/
- 0, /*nb_reserved*/
- 0, /*nb_float*/
- Vector_iadd, /* nb_inplace_add */
- Vector_isub, /* nb_inplace_subtract */
- Vector_imul, /* nb_inplace_multiply */
- 0, /* nb_inplace_remainder */
- 0, /* nb_inplace_power */
- 0, /* nb_inplace_lshift */
- 0, /* nb_inplace_rshift */
- 0, /* nb_inplace_and */
- 0, /* nb_inplace_xor */
- 0, /* nb_inplace_or */
- 0, /* nb_floor_divide */
- Vector_div, /* nb_true_divide */
- 0, /* nb_inplace_floor_divide */
- Vector_idiv, /* nb_inplace_true_divide */
- 0, /* nb_index */
-};
-#else
-static PyNumberMethods Vector_NumMethods = {
- (binaryfunc) Vector_add, /* __add__ */
- (binaryfunc) Vector_sub, /* __sub__ */
- (binaryfunc) Vector_mul, /* __mul__ */
- (binaryfunc) Vector_div, /* __div__ */
- (binaryfunc) NULL, /* __mod__ */
- (binaryfunc) NULL, /* __divmod__ */
- (ternaryfunc) NULL, /* __pow__ */
- (unaryfunc) Vector_neg, /* __neg__ */
- (unaryfunc) NULL, /* __pos__ */
- (unaryfunc) NULL, /* __abs__ */
- (inquiry) NULL, /* __nonzero__ */
- (unaryfunc) NULL, /* __invert__ */
- (binaryfunc) NULL, /* __lshift__ */
- (binaryfunc) NULL, /* __rshift__ */
- (binaryfunc) NULL, /* __and__ */
- (binaryfunc) NULL, /* __xor__ */
- (binaryfunc) NULL, /* __or__ */
- /*(coercion)*/ NULL, /* __coerce__ */
- (unaryfunc) NULL, /* __int__ */
- (unaryfunc) NULL, /* __long__ */
- (unaryfunc) NULL, /* __float__ */
- (unaryfunc) NULL, /* __oct__ */
- (unaryfunc) NULL, /* __hex__ */
-
- /* Added in release 2.0 */
- (binaryfunc) Vector_iadd, /*__iadd__*/
- (binaryfunc) Vector_isub, /*__isub__*/
- (binaryfunc) Vector_imul, /*__imul__*/
- (binaryfunc) Vector_idiv, /*__idiv__*/
- (binaryfunc) NULL, /*__imod__*/
- (ternaryfunc) NULL, /*__ipow__*/
- (binaryfunc) NULL, /*__ilshift__*/
- (binaryfunc) NULL, /*__irshift__*/
- (binaryfunc) NULL, /*__iand__*/
- (binaryfunc) NULL, /*__ixor__*/
- (binaryfunc) NULL, /*__ior__*/
-
- /* Added in release 2.2 */
- /* The following require the Py_TPFLAGS_HAVE_CLASS flag */
- (binaryfunc) NULL, /*__floordiv__ __rfloordiv__*/
- (binaryfunc) NULL, /*__truediv__ __rfloordiv__*/
- (binaryfunc) NULL, /*__ifloordiv__*/
- (binaryfunc) NULL, /*__itruediv__*/
-};
-#endif
-
-/*------------------PY_OBECT DEFINITION--------------------------*/
-
-/*
- * vector axis, vector.x/y/z/w
- */
-
-static PyObject *Vector_getAxis( VectorObject * self, void *type )
-{
- return Vector_item(self, GET_INT_FROM_POINTER(type));
-}
-
-static int Vector_setAxis( VectorObject * self, PyObject * value, void * type )
-{
- return Vector_ass_item(self, GET_INT_FROM_POINTER(type), value);
-}
-
-/* vector.length */
-static PyObject *Vector_getLength( VectorObject * self, void *type )
-{
- double dot = 0.0f;
- int i;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- for(i = 0; i < self->size; i++){
- dot += (self->vec[i] * self->vec[i]);
- }
- return PyFloat_FromDouble(sqrt(dot));
-}
-
-static int Vector_setLength( VectorObject * self, PyObject * value )
-{
- double dot = 0.0f, param;
- int i;
-
- if(!BaseMath_ReadCallback(self))
- return -1;
-
- param= PyFloat_AsDouble( value );
- if(param==-1.0 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_TypeError, "length must be set to a number");
- return -1;
- }
-
- if (param < 0) {
- PyErr_SetString( PyExc_TypeError, "cannot set a vectors length to a negative value" );
- return -1;
- }
- if (param==0) {
- for(i = 0; i < self->size; i++){
- self->vec[i]= 0;
- }
- return 0;
- }
-
- for(i = 0; i < self->size; i++){
- dot += (self->vec[i] * self->vec[i]);
- }
-
- if (!dot) /* cant sqrt zero */
- return 0;
-
- dot = sqrt(dot);
-
- if (dot==param)
- return 0;
-
- dot= dot/param;
-
- for(i = 0; i < self->size; i++){
- self->vec[i]= self->vec[i] / (float)dot;
- }
-
- BaseMath_WriteCallback(self); /* checked alredy */
-
- return 0;
-}
-
-/* Get a new Vector according to the provided swizzle. This function has little
- error checking, as we are in control of the inputs: the closure is set by us
- in Vector_createSwizzleGetSeter. */
-static PyObject *Vector_getSwizzle(VectorObject * self, void *closure)
-{
- size_t axisA;
- size_t axisB;
- float vec[MAX_DIMENSIONS];
- unsigned int swizzleClosure;
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- /* Unpack the axes from the closure into an array. */
- axisA = 0;
- swizzleClosure = (unsigned int) closure;
- while (swizzleClosure & SWIZZLE_VALID_AXIS)
- {
- axisB = swizzleClosure & SWIZZLE_AXIS;
- vec[axisA] = self->vec[axisB];
- swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
- axisA++;
- }
-
- return newVectorObject(vec, axisA, Py_NEW, Py_TYPE(self));
-}
-
-/* Set the items of this vector using a swizzle.
- - If value is a vector or list this operates like an array copy, except that
- the destination is effectively re-ordered as defined by the swizzle. At
- most min(len(source), len(dest)) values will be copied.
- - If the value is scalar, it is copied to all axes listed in the swizzle.
- - If an axis appears more than once in the swizzle, the final occurrance is
- the one that determines its value.
-
- Returns 0 on success and -1 on failure. On failure, the vector will be
- unchanged. */
-static int Vector_setSwizzle(VectorObject * self, PyObject * value, void *closure)
-{
- VectorObject *vecVal;
- PyObject *item;
- size_t listLen;
- float scalarVal;
-
- size_t axisB;
- size_t axisA;
- unsigned int swizzleClosure;
-
- float vecTemp[MAX_DIMENSIONS];
-
- if(!BaseMath_ReadCallback(self))
- return -1;
-
- /* Check that the closure can be used with this vector: even 2D vectors have
- swizzles defined for axes z and w, but they would be invalid. */
- swizzleClosure = (unsigned int) closure;
- while (swizzleClosure & SWIZZLE_VALID_AXIS)
- {
- axisA = swizzleClosure & SWIZZLE_AXIS;
- if (axisA >= self->size)
- {
- PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n");
- return -1;
- }
- swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
- }
-
- if (VectorObject_Check(value))
- {
- /* Copy vector contents onto swizzled axes. */
- vecVal = (VectorObject*) value;
- axisB = 0;
- swizzleClosure = (unsigned int) closure;
- while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < vecVal->size)
- {
- axisA = swizzleClosure & SWIZZLE_AXIS;
- vecTemp[axisA] = vecVal->vec[axisB];
-
- swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
- axisB++;
- }
- memcpy(self->vec, vecTemp, axisB * sizeof(float));
- /* continue with BaseMathObject_WriteCallback at the end */
- }
- else if (PyList_Check(value))
- {
- /* Copy list contents onto swizzled axes. */
- listLen = PyList_Size(value);
- swizzleClosure = (unsigned int) closure;
- axisB = 0;
- while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < listLen)
- {
- item = PyList_GetItem(value, axisB);
- scalarVal = (float)PyFloat_AsDouble(item);
-
- if (scalarVal==-1.0 && PyErr_Occurred()) {
- PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n");
- return -1;
- }
-
-
- axisA = swizzleClosure & SWIZZLE_AXIS;
- vecTemp[axisA] = scalarVal;
-
- swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
- axisB++;
- }
- memcpy(self->vec, vecTemp, axisB * sizeof(float));
- /* continue with BaseMathObject_WriteCallback at the end */
- }
- else if (((scalarVal = (float)PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred())==0)
- {
- /* Assign the same value to each axis. */
- swizzleClosure = (unsigned int) closure;
- while (swizzleClosure & SWIZZLE_VALID_AXIS)
- {
- axisA = swizzleClosure & SWIZZLE_AXIS;
- self->vec[axisA] = scalarVal;
-
- swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
- }
- /* continue with BaseMathObject_WriteCallback at the end */
- }
- else {
- PyErr_SetString( PyExc_TypeError, "Expected a Vector, list or scalar value." );
- return -1;
- }
-
- if(!BaseMath_WriteCallback(vecVal))
- return -1;
- else
- return 0;
-}
-
-/*****************************************************************************/
-/* Python attributes get/set structure: */
-/*****************************************************************************/
-static PyGetSetDef Vector_getseters[] = {
- {"x",
- (getter)Vector_getAxis, (setter)Vector_setAxis,
- "Vector X axis",
- (void *)0},
- {"y",
- (getter)Vector_getAxis, (setter)Vector_setAxis,
- "Vector Y axis",
- (void *)1},
- {"z",
- (getter)Vector_getAxis, (setter)Vector_setAxis,
- "Vector Z axis",
- (void *)2},
- {"w",
- (getter)Vector_getAxis, (setter)Vector_setAxis,
- "Vector Z axis",
- (void *)3},
- {"length",
- (getter)Vector_getLength, (setter)Vector_setLength,
- "Vector Length",
- NULL},
- {"magnitude",
- (getter)Vector_getLength, (setter)Vector_setLength,
- "Vector Length",
- NULL},
- {"wrapped",
- (getter)BaseMathObject_getWrapped, (setter)NULL,
- "True when this wraps blenders internal data",
- NULL},
- {"__owner__",
- (getter)BaseMathObject_getOwner, (setter)NULL,
- "Read only owner for vectors that depend on another object",
- NULL},
-
- /* autogenerated swizzle attrs, see python script below */
- {"xx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 36 */
- {"xxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 292 */
- {"xxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2340 */
- {"xxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2852 */
- {"xxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3364 */
- {"xxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3876 */
- {"xxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 356 */
- {"xxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2404 */
- {"xxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2916 */
- {"xxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3428 */
- {"xxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3940 */
- {"xxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 420 */
- {"xxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2468 */
- {"xxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2980 */
- {"xxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3492 */
- {"xxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4004 */
- {"xxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 484 */
- {"xxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2532 */
- {"xxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3044 */
- {"xxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3556 */
- {"xxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4068 */
- {"xy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 44 */
- {"xyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 300 */
- {"xyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2348 */
- {"xyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2860 */
- {"xyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3372 */
- {"xyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3884 */
- {"xyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 364 */
- {"xyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2412 */
- {"xyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2924 */
- {"xyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3436 */
- {"xyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3948 */
- {"xyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 428 */
- {"xyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2476 */
- {"xyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2988 */
- {"xyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3500 */
- {"xyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4012 */
- {"xyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 492 */
- {"xywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2540 */
- {"xywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3052 */
- {"xywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3564 */
- {"xyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4076 */
- {"xz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 52 */
- {"xzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 308 */
- {"xzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2356 */
- {"xzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2868 */
- {"xzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3380 */
- {"xzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3892 */
- {"xzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 372 */
- {"xzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2420 */
- {"xzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2932 */
- {"xzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3444 */
- {"xzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3956 */
- {"xzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 436 */
- {"xzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2484 */
- {"xzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2996 */
- {"xzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3508 */
- {"xzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4020 */
- {"xzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 500 */
- {"xzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2548 */
- {"xzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3060 */
- {"xzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3572 */
- {"xzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4084 */
- {"xw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 60 */
- {"xwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 316 */
- {"xwxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2364 */
- {"xwxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2876 */
- {"xwxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3388 */
- {"xwxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3900 */
- {"xwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 380 */
- {"xwyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2428 */
- {"xwyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2940 */
- {"xwyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3452 */
- {"xwyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3964 */
- {"xwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 444 */
- {"xwzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2492 */
- {"xwzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3004 */
- {"xwzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3516 */
- {"xwzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4028 */
- {"xww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 508 */
- {"xwwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2556 */
- {"xwwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3068 */
- {"xwwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3580 */
- {"xwww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4092 */
- {"yx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 37 */
- {"yxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 293 */
- {"yxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2341 */
- {"yxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2853 */
- {"yxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3365 */
- {"yxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3877 */
- {"yxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 357 */
- {"yxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2405 */
- {"yxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2917 */
- {"yxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3429 */
- {"yxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3941 */
- {"yxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 421 */
- {"yxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2469 */
- {"yxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2981 */
- {"yxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3493 */
- {"yxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4005 */
- {"yxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 485 */
- {"yxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2533 */
- {"yxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3045 */
- {"yxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3557 */
- {"yxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4069 */
- {"yy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 45 */
- {"yyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 301 */
- {"yyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2349 */
- {"yyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2861 */
- {"yyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3373 */
- {"yyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3885 */
- {"yyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 365 */
- {"yyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2413 */
- {"yyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2925 */
- {"yyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3437 */
- {"yyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3949 */
- {"yyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 429 */
- {"yyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2477 */
- {"yyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2989 */
- {"yyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3501 */
- {"yyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4013 */
- {"yyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 493 */
- {"yywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2541 */
- {"yywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3053 */
- {"yywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3565 */
- {"yyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4077 */
- {"yz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 53 */
- {"yzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 309 */
- {"yzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2357 */
- {"yzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2869 */
- {"yzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3381 */
- {"yzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3893 */
- {"yzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 373 */
- {"yzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2421 */
- {"yzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2933 */
- {"yzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3445 */
- {"yzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3957 */
- {"yzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 437 */
- {"yzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2485 */
- {"yzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2997 */
- {"yzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3509 */
- {"yzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4021 */
- {"yzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 501 */
- {"yzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2549 */
- {"yzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3061 */
- {"yzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3573 */
- {"yzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4085 */
- {"yw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 61 */
- {"ywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 317 */
- {"ywxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2365 */
- {"ywxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2877 */
- {"ywxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3389 */
- {"ywxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3901 */
- {"ywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 381 */
- {"ywyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2429 */
- {"ywyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2941 */
- {"ywyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3453 */
- {"ywyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3965 */
- {"ywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 445 */
- {"ywzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2493 */
- {"ywzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3005 */
- {"ywzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3517 */
- {"ywzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4029 */
- {"yww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 509 */
- {"ywwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2557 */
- {"ywwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3069 */
- {"ywwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3581 */
- {"ywww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4093 */
- {"zx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 38 */
- {"zxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 294 */
- {"zxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2342 */
- {"zxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2854 */
- {"zxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3366 */
- {"zxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3878 */
- {"zxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 358 */
- {"zxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2406 */
- {"zxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2918 */
- {"zxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3430 */
- {"zxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3942 */
- {"zxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 422 */
- {"zxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2470 */
- {"zxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2982 */
- {"zxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3494 */
- {"zxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4006 */
- {"zxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 486 */
- {"zxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2534 */
- {"zxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3046 */
- {"zxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3558 */
- {"zxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4070 */
- {"zy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 46 */
- {"zyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 302 */
- {"zyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2350 */
- {"zyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2862 */
- {"zyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3374 */
- {"zyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3886 */
- {"zyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 366 */
- {"zyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2414 */
- {"zyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2926 */
- {"zyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3438 */
- {"zyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3950 */
- {"zyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 430 */
- {"zyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2478 */
- {"zyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2990 */
- {"zyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3502 */
- {"zyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4014 */
- {"zyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 494 */
- {"zywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2542 */
- {"zywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3054 */
- {"zywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3566 */
- {"zyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4078 */
- {"zz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 54 */
- {"zzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 310 */
- {"zzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2358 */
- {"zzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2870 */
- {"zzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3382 */
- {"zzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3894 */
- {"zzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 374 */
- {"zzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2422 */
- {"zzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2934 */
- {"zzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3446 */
- {"zzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3958 */
- {"zzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 438 */
- {"zzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2486 */
- {"zzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2998 */
- {"zzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3510 */
- {"zzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4022 */
- {"zzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 502 */
- {"zzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2550 */
- {"zzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3062 */
- {"zzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3574 */
- {"zzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4086 */
- {"zw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 62 */
- {"zwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 318 */
- {"zwxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2366 */
- {"zwxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2878 */
- {"zwxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3390 */
- {"zwxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3902 */
- {"zwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 382 */
- {"zwyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2430 */
- {"zwyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2942 */
- {"zwyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3454 */
- {"zwyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3966 */
- {"zwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 446 */
- {"zwzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2494 */
- {"zwzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3006 */
- {"zwzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3518 */
- {"zwzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4030 */
- {"zww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 510 */
- {"zwwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2558 */
- {"zwwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3070 */
- {"zwwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3582 */
- {"zwww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4094 */
- {"wx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 39 */
- {"wxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 295 */
- {"wxxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2343 */
- {"wxxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2855 */
- {"wxxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3367 */
- {"wxxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3879 */
- {"wxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 359 */
- {"wxyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2407 */
- {"wxyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2919 */
- {"wxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3431 */
- {"wxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3943 */
- {"wxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 423 */
- {"wxzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2471 */
- {"wxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2983 */
- {"wxzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3495 */
- {"wxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4007 */
- {"wxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 487 */
- {"wxwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2535 */
- {"wxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3047 */
- {"wxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3559 */
- {"wxww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4071 */
- {"wy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 47 */
- {"wyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 303 */
- {"wyxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2351 */
- {"wyxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2863 */
- {"wyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3375 */
- {"wyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3887 */
- {"wyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 367 */
- {"wyyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2415 */
- {"wyyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2927 */
- {"wyyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3439 */
- {"wyyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3951 */
- {"wyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 431 */
- {"wyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2479 */
- {"wyzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2991 */
- {"wyzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3503 */
- {"wyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4015 */
- {"wyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 495 */
- {"wywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2543 */
- {"wywy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3055 */
- {"wywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3567 */
- {"wyww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4079 */
- {"wz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 55 */
- {"wzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 311 */
- {"wzxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2359 */
- {"wzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2871 */
- {"wzxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3383 */
- {"wzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3895 */
- {"wzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 375 */
- {"wzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2423 */
- {"wzyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2935 */
- {"wzyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3447 */
- {"wzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3959 */
- {"wzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 439 */
- {"wzzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2487 */
- {"wzzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2999 */
- {"wzzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3511 */
- {"wzzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4023 */
- {"wzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 503 */
- {"wzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2551 */
- {"wzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3063 */
- {"wzwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3575 */
- {"wzww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4087 */
- {"ww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, /* 63 */
- {"wwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 319 */
- {"wwxx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2367 */
- {"wwxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2879 */
- {"wwxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3391 */
- {"wwxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3903 */
- {"wwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 383 */
- {"wwyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2431 */
- {"wwyy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2943 */
- {"wwyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3455 */
- {"wwyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3967 */
- {"wwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 447 */
- {"wwzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2495 */
- {"wwzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3007 */
- {"wwzz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3519 */
- {"wwzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4031 */
- {"www", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, /* 511 */
- {"wwwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 2559 */
- {"wwwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3071 */
- {"wwwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 3583 */
- {"wwww", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, /* 4095 */
- {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
-};
-
-/* Python script used to make swizzle array */
-/*
-SWIZZLE_BITS_PER_AXIS = 3
-SWIZZLE_VALID_AXIS = 0x4
-
-axis_dict = {}
-axis_pos = {'x':0, 'y':1, 'z':2, 'w':3}
-axises = 'xyzw'
-while len(axises) >= 2:
-
- for axis_0 in axises:
- axis_0_pos = axis_pos[axis_0]
- for axis_1 in axises:
- axis_1_pos = axis_pos[axis_1]
- axis_dict[axis_0+axis_1] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS))' % (axis_0_pos, axis_1_pos)
- if len(axises)>2:
- for axis_2 in axises:
- axis_2_pos = axis_pos[axis_2]
- axis_dict[axis_0+axis_1+axis_2] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)))' % (axis_0_pos, axis_1_pos, axis_2_pos)
- if len(axises)>3:
- for axis_3 in axises:
- axis_3_pos = axis_pos[axis_3]
- axis_dict[axis_0+axis_1+axis_2+axis_3] = '((%s|SWIZZLE_VALID_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((%s|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) ' % (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)
-
- axises = axises[:-1]
-
-
-items = axis_dict.items()
-items.sort(key = lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3'))
-
-unique = set()
-for key, val in items:
- num = eval(val)
- print '\t{"%s", %s(getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, (void *)((unsigned int)%s)}, // %s' % (key, (' '*(4-len(key))), axis_dict[key], num)
- unique.add(num)
-
-if len(unique) != len(items):
- print "ERROR"
-
-*/
-
-
-
-
-/* Note
- Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
- but this means for eg that
- vec*mat and mat*vec both get sent to Vector_mul and it neesd to sort out the order
-*/
-
-PyTypeObject vector_Type = {
-#if (PY_VERSION_HEX >= 0x02060000)
- PyVarObject_HEAD_INIT(NULL, 0)
-#else
- /* python 2.5 and below */
- PyObject_HEAD_INIT( NULL ) /* required py macro */
- 0, /* ob_size */
-#endif
- /* For printing, in format "<module>.<name>" */
- "vector", /* char *tp_name; */
- sizeof( VectorObject ), /* int tp_basicsize; */
- 0, /* tp_itemsize; For allocation */
-
- /* Methods to implement standard operations */
-
- ( destructor ) BaseMathObject_dealloc,/* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
- NULL, /* cmpfunc tp_compare; */
- ( reprfunc ) Vector_repr, /* reprfunc tp_repr; */
-
- /* Method suites for standard classes */
-
- &Vector_NumMethods, /* PyNumberMethods *tp_as_number; */
- &Vector_SeqMethods, /* PySequenceMethods *tp_as_sequence; */
-#if (PY_VERSION_HEX >= 0x03000000)
- &Vector_AsMapping, /* PyMappingMethods *tp_as_mapping; */
-#else
- NULL,
-#endif
-
- /* More standard operations (here for binary compatibility) */
-
- NULL, /* hashfunc tp_hash; */
- NULL, /* ternaryfunc tp_call; */
- NULL, /* reprfunc tp_str; */
- NULL, /* getattrofunc tp_getattro; */
- NULL, /* setattrofunc tp_setattro; */
-
- /* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
-
- /*** Flags to define presence of optional/expanded features ***/
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
- NULL, /* char *tp_doc; Documentation string */
- /*** Assigned meaning in release 2.0 ***/
- /* call function for all accessible objects */
- NULL, /* traverseproc tp_traverse; */
-
- /* delete references to contained objects */
- NULL, /* inquiry tp_clear; */
-
- /*** Assigned meaning in release 2.1 ***/
- /*** rich comparisons ***/
- (richcmpfunc)Vector_richcmpr, /* richcmpfunc tp_richcompare; */
-
- /*** weak reference enabler ***/
- 0, /* long tp_weaklistoffset; */
-
- /*** Added in release 2.2 ***/
- /* Iterators */
- NULL, /* getiterfunc tp_iter; */
- NULL, /* iternextfunc tp_iternext; */
-
- /*** Attribute descriptor and subclassing stuff ***/
- Vector_methods, /* struct PyMethodDef *tp_methods; */
- NULL, /* struct PyMemberDef *tp_members; */
- Vector_getseters, /* struct PyGetSetDef *tp_getset; */
- NULL, /* struct _typeobject *tp_base; */
- NULL, /* PyObject *tp_dict; */
- NULL, /* descrgetfunc tp_descr_get; */
- NULL, /* descrsetfunc tp_descr_set; */
- 0, /* long tp_dictoffset; */
- NULL, /* initproc tp_init; */
- NULL, /* allocfunc tp_alloc; */
- Vector_new, /* newfunc tp_new; */
- /* Low-level free-memory routine */
- NULL, /* freefunc tp_free; */
- /* For PyObject_IS_GC */
- NULL, /* inquiry tp_is_gc; */
- NULL, /* PyObject *tp_bases; */
- /* method resolution order */
- NULL, /* PyObject *tp_mro; */
- NULL, /* PyObject *tp_cache; */
- NULL, /* PyObject *tp_subclasses; */
- NULL, /* PyObject *tp_weaklist; */
- NULL
-};
-
-
-/*------------------------newVectorObject (internal)-------------
- creates a new vector object
- pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
- (i.e. it was allocated elsewhere by MEM_mallocN())
- pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
- (i.e. it must be created here with PyMEM_malloc())*/
-PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type)
-{
- int i;
- VectorObject *self;
-
- if(base_type) self = (VectorObject *)base_type->tp_alloc(base_type, 0);
- else self = PyObject_NEW(VectorObject, &vector_Type);
-
- if(size > 4 || size < 2)
- return NULL;
- self->size = size;
-
- /* init callbacks as NULL */
- self->cb_user= NULL;
- self->cb_type= self->cb_subtype= 0;
-
- if(type == Py_WRAP) {
- self->vec = vec;
- self->wrapped = Py_WRAP;
- } else if (type == Py_NEW) {
- self->vec = PyMem_Malloc(size * sizeof(float));
- if(!vec) { /*new empty*/
- for(i = 0; i < size; i++){
- self->vec[i] = 0.0f;
- }
- if(size == 4) /* do the homogenous thing */
- self->vec[3] = 1.0f;
- }else{
- for(i = 0; i < size; i++){
- self->vec[i] = vec[i];
- }
- }
- self->wrapped = Py_NEW;
- }else{ /*bad type*/
- return NULL;
- }
- return (PyObject *) self;
-}
-
-PyObject *newVectorObject_cb(PyObject *cb_user, int size, int cb_type, int cb_subtype)
-{
- float dummy[4] = {0.0, 0.0, 0.0, 0.0}; /* dummy init vector, callbacks will be used on access */
- VectorObject *self= (VectorObject *)newVectorObject(dummy, size, Py_NEW, NULL);
- if(self) {
- Py_INCREF(cb_user);
- self->cb_user= cb_user;
- self->cb_type= (unsigned char)cb_type;
- self->cb_subtype= (unsigned char)cb_subtype;
- }
-
- return (PyObject *)self;
-}
-
-//-----------------row_vector_multiplication (internal)-----------
-//ROW VECTOR Multiplication - Vector X Matrix
-//[x][y][z] * [1][2][3]
-// [4][5][6]
-// [7][8][9]
-//vector/matrix multiplication IS NOT COMMUTATIVE!!!!
-static PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat)
-{
- float vecNew[4], vecCopy[4];
- double dot = 0.0f;
- int x, y, z = 0, vec_size = vec->size;
-
- if(mat->colSize != vec_size){
- if(mat->rowSize == 4 && vec_size != 3){
- PyErr_SetString(PyExc_AttributeError, "vector * matrix: matrix column size and the vector size must be the same");
- return NULL;
- }else{
- vecCopy[3] = 1.0f;
- }
- }
-
- if(!BaseMath_ReadCallback(vec) || !BaseMath_ReadCallback(mat))
- return NULL;
-
- for(x = 0; x < vec_size; x++){
- vecCopy[x] = vec->vec[x];
- }
-
- //muliplication
- for(x = 0; x < mat->colSize; x++) {
- for(y = 0; y < mat->rowSize; y++) {
- dot += mat->matrix[y][x] * vecCopy[y];
- }
- vecNew[z++] = (float)dot;
- dot = 0.0f;
- }
- return newVectorObject(vecNew, vec_size, Py_NEW, NULL);
-}
-
-/*----------------------------Vector.negate() --------------------
- set the vector to it's negative -x, -y, -z */
-static PyObject *Vector_Negate(VectorObject * self)
-{
- int i;
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- for(i = 0; i < self->size; i++)
- self->vec[i] = -(self->vec[i]);
-
- BaseMath_WriteCallback(self); // alredy checked for error
-
- Py_INCREF(self);
- return (PyObject*)self;
-}
diff --git a/source/blender/python/generic/vector.h b/source/blender/python/generic/vector.h
deleted file mode 100644
index f6babac7ed9..00000000000
--- a/source/blender/python/generic/vector.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Willian P. Germano & Joseph Gilbert
- *
- * ***** END GPL LICENSE BLOCK *****
- *
- */
-
-#ifndef EXPP_vector_h
-#define EXPP_vector_h
-
-#include <Python.h>
-#include "../intern/bpy_compat.h"
-
-extern PyTypeObject vector_Type;
-#define VectorObject_Check(_v) PyObject_TypeCheck((_v), &vector_Type)
-
-typedef struct { /* keep aligned with BaseMathObject in Mathutils.h */
- PyObject_VAR_HEAD
- float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */
- PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */
- unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */
- unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */
- unsigned char wrapped; /* wrapped data type? */
- /* end BaseMathObject */
-
- unsigned char size; /* vec size 2,3 or 4 */
-} VectorObject;
-
-/*prototypes*/
-PyObject *newVectorObject(float *vec, int size, int type, PyTypeObject *base_type);
-PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype);
-
-#endif /* EXPP_vector_h */
diff --git a/source/blender/python/intern/Makefile b/source/blender/python/intern/Makefile
index d210cfaf973..3e28f5aac31 100644
--- a/source/blender/python/intern/Makefile
+++ b/source/blender/python/intern/Makefile
@@ -1,5 +1,5 @@
#
-# $Id$
+# $Id: Makefile 11904 2007-08-31 16:16:33Z sirdude $
#
# ***** BEGIN GPL LICENSE BLOCK *****
#
@@ -37,7 +37,6 @@ CFLAGS += $(LEVEL_1_C_WARNINGS)
# OpenGL and Python
CPPFLAGS += $(OGL_CPPFLAGS)
-CPPFLAGS += -I$(NAN_GLEW)/include
CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
# PreProcessor stuff
diff --git a/source/blender/python/intern/bpy_compat.h b/source/blender/python/intern/bpy_compat.h
index e999f57c733..ad6b7a5e85c 100644
--- a/source/blender/python/intern/bpy_compat.h
+++ b/source/blender/python/intern/bpy_compat.h
@@ -85,34 +85,8 @@ typedef Py_ssize_t (*lenfunc)(PyObject *);
#ifndef Py_RETURN_TRUE
#define Py_RETURN_TRUE return PyBool_FromLong(1)
#endif
-
-#define PyInt_FromSsize_t PyInt_FromLong
-#define PyNumber_AsSsize_t(ob, exc) PyInt_AsLong(ob)
-#define PyIndex_Check(ob) PyInt_Check(ob)
-
-
-#endif
-
-
-#if PY_VERSION_HEX < 0x03000000
-#ifndef ssizeargfunc
-#define ssizeargfunc intargfunc
#endif
-#ifndef ssizessizeargfunc
-#define ssizessizeargfunc intintargfunc
-#endif
-
-#ifndef ssizeobjargproc
-#define ssizeobjargproc intobjargproc
-#endif
-
-#ifndef ssizessizeobjargproc
-#define ssizessizeobjargproc intintobjargproc
-#endif
-#endif
-
-
/* defined in bpy_util.c */
#if PY_VERSION_HEX < 0x03000000
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index a07c447c718..7b3a67ebff5 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -36,14 +36,6 @@
#include "BPY_extern.h"
-#include "../generic/bpy_internal_import.h" // our own imports
-/* external util modules */
-
-#include "../generic/Mathutils.h"
-#include "../generic/Geometry.h"
-#include "../generic/BGL.h"
-
-
void BPY_free_compiled_text( struct Text *text )
{
if( text->compiled ) {
@@ -64,19 +56,12 @@ static void bpy_init_modules( void )
PyModule_AddObject( mod, "data", BPY_rna_module() );
/* PyModule_AddObject( mod, "doc", BPY_rna_doc() ); */
PyModule_AddObject( mod, "types", BPY_rna_types() );
- PyModule_AddObject( mod, "props", BPY_rna_props() );
PyModule_AddObject( mod, "ops", BPY_operator_module() );
- PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experimental, consider this a test, especially PyCObject is not meant to be permanent
+ PyModule_AddObject( mod, "ui", BPY_ui_module() ); // XXX very experemental, consider this a test, especially PyCObject is not meant to be perminant
/* add the module so we can import it */
PyDict_SetItemString(PySys_GetObject("modules"), "bpy", mod);
Py_DECREF(mod);
-
-
- /* stand alone utility modules not related to blender directly */
- Geometry_Init("Geometry");
- Mathutils_Init("Mathutils");
- BGL_Init("BGL");
}
#if (PY_VERSION_HEX < 0x02050000)
@@ -115,7 +100,6 @@ static PyObject *CreateGlobalDictionary( bContext *C )
{"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
{"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
- {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
{NULL, NULL, 0, NULL}
};
@@ -132,81 +116,13 @@ static PyObject *CreateGlobalDictionary( bContext *C )
return dict;
}
-/* Use this so we can include our own python bundle */
-#if 0
-wchar_t* Py_GetPath(void)
-{
- int i;
- static wchar_t py_path[FILE_MAXDIR] = L"";
- char *dirname= BLI_gethome_folder("python");
- if(dirname) {
- i= mbstowcs(py_path, dirname, FILE_MAXDIR);
- printf("py path %s, %d\n", dirname, i);
- }
- return py_path;
-}
-#endif
-
-
-/* must be called before Py_Initialize */
-void BPY_start_python_path(void)
-{
- char *py_path_bundle= BLI_gethome_folder("python");
-
- if(py_path_bundle==NULL)
- return;
-
- /* set the environment path */
- printf("found bundled python: %s\n", py_path_bundle);
-
-#if (defined(WIN32) || defined(WIN64))
-#if defined(FREE_WINDOWS)
- {
- char py_path[FILE_MAXDIR + 11] = "";
- sprintf(py_path, "PYTHONPATH=%s", py_path_bundle);
- putenv(py_path);
- }
-#else
- _putenv_s("PYTHONPATH", py_path_bundle);
-#endif
-#else
-#ifdef __sgi
- {
- char py_path[FILE_MAXDIR + 11] = "";
- sprintf(py_path, "PYTHONPATH=%s", py_path_bundle);
- putenv(py_path);
- }
-#else
- setenv("PYTHONPATH", py_path_bundle, 1);
-#endif
-#endif
-
-}
-
-
void BPY_start_python( int argc, char **argv )
{
PyThreadState *py_tstate = NULL;
- BPY_start_python_path(); /* allow to use our own included python */
-
Py_Initialize( );
-#if (PY_VERSION_HEX < 0x03000000)
- PySys_SetArgv( argc, argv);
-#else
- /* sigh, why do python guys not have a char** version anymore? :( */
- {
- int i;
- PyObject *py_argv= PyList_New(argc);
-
- for (i=0; i<argc; i++)
- PyList_SET_ITEM(py_argv, i, PyUnicode_FromString(argv[i]));
-
- PySys_SetObject("argv", py_argv);
- Py_DECREF(py_argv);
- }
-#endif
+ //PySys_SetArgv( argc_copy, argv_copy );
/* Initialize thread support (also acquires lock) */
PyEval_InitThreads();
@@ -215,17 +131,10 @@ void BPY_start_python( int argc, char **argv )
/* bpy.* and lets us import it */
bpy_init_modules();
- { /* our own import and reload functions */
- PyObject *item;
- //PyObject *m = PyImport_AddModule("__builtin__");
- //PyObject *d = PyModule_GetDict(m);
- PyObject *d = PyEval_GetBuiltins( );
- PyDict_SetItemString(d, "reload", item=PyCFunction_New(bpy_reload_meth, NULL)); Py_DECREF(item);
- PyDict_SetItemString(d, "__import__", item=PyCFunction_New(bpy_import_meth, NULL)); Py_DECREF(item);
- }
py_tstate = PyGILState_GetThisThreadState();
PyEval_ReleaseThread(py_tstate);
+
}
void BPY_end_python( void )
@@ -241,7 +150,7 @@ void BPY_end_python( void )
}
/* Can run a file or text block */
-int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struct ReportList *reports)
+int BPY_run_python_script( bContext *C, const char *fn, struct Text *text )
{
PyObject *py_dict, *py_result;
PyGILState_STATE gilstate;
@@ -255,7 +164,6 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc
gilstate = PyGILState_Ensure();
BPY_update_modules(); /* can give really bad results if this isnt here */
- bpy_import_main_set(CTX_data_main(C));
py_dict = CreateGlobalDictionary(C);
@@ -270,7 +178,7 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc
MEM_freeN( buf );
if( PyErr_Occurred( ) ) {
- BPy_errors_to_report(reports);
+ PyErr_Print(); PyErr_Clear();
BPY_free_compiled_text( text );
PyGILState_Release(gilstate);
return 0;
@@ -286,14 +194,13 @@ int BPY_run_python_script( bContext *C, const char *fn, struct Text *text, struc
}
if (!py_result) {
- BPy_errors_to_report(reports);
+ PyErr_Print(); PyErr_Clear();
} else {
Py_DECREF( py_result );
}
Py_DECREF(py_dict);
PyGILState_Release(gilstate);
- bpy_import_main_set(NULL);
//BPY_end_python();
return py_result ? 1:0;
@@ -314,7 +221,7 @@ static void exit_pydraw( SpaceScript * sc, short err )
script = sc->script;
if( err ) {
- BPy_errors_to_report(NULL); // TODO, reports
+ PyErr_Print(); PyErr_Clear();
script->flags = 0; /* mark script struct for deletion */
SCRIPT_SET_NULL(script);
script->scriptname[0] = '\0';
@@ -343,7 +250,7 @@ static int bpy_run_script_init(bContext *C, SpaceScript * sc)
return 0;
if (sc->script->py_draw==NULL && sc->script->scriptname[0] != '\0')
- BPY_run_python_script(C, sc->script->scriptname, NULL, NULL);
+ BPY_run_python_script(C, sc->script->scriptname, NULL);
if (sc->script->py_draw==NULL)
return 0;
@@ -351,9 +258,9 @@ static int bpy_run_script_init(bContext *C, SpaceScript * sc)
return 1;
}
-int BPY_run_script_space_draw(const struct bContext *C, SpaceScript * sc)
+int BPY_run_script_space_draw(struct bContext *C, SpaceScript * sc)
{
- if (bpy_run_script_init( (bContext *)C, sc)) {
+ if (bpy_run_script_init(C, sc)) {
PyGILState_STATE gilstate = PyGILState_Ensure();
PyObject *result = PyObject_CallObject( sc->script->py_draw, NULL );
@@ -422,7 +329,7 @@ int BPY_run_python_script_space(const char *modulename, const char *func)
}
if (!py_result) {
- BPy_errors_to_report(NULL); // TODO - reports
+ PyErr_Print(); PyErr_Clear();
} else
Py_DECREF( py_result );
@@ -450,72 +357,69 @@ void BPY_run_ui_scripts(bContext *C, int reload)
DIR *dir;
struct dirent *de;
char *file_extension;
- char *dirname;
char path[FILE_MAX];
- char *dirs[] = {"io", "ui", NULL};
- int a;
+ char *dirname= BLI_gethome_folder("ui");
+ int filelen; /* filename length */
PyGILState_STATE gilstate;
PyObject *mod;
- PyObject *sys_path;
+ PyObject *sys_path_orig;
+ PyObject *sys_path_new;
+
+ if(!dirname)
+ return;
+
+ dir = opendir(dirname);
+ if(!dir)
+ return;
+
gilstate = PyGILState_Ensure();
+ /* backup sys.path */
+ sys_path_orig= PySys_GetObject("path");
+ Py_INCREF(sys_path_orig); /* dont free it */
+
+ sys_path_new= PyList_New(1);
+ PyList_SET_ITEM(sys_path_new, 0, PyUnicode_FromString(dirname));
+ PySys_SetObject("path", sys_path_new);
+ Py_DECREF(sys_path_new);
+
// XXX - evil, need to access context
BPy_SetContext(C);
- bpy_import_main_set(CTX_data_main(C));
-
-
- sys_path= PySys_GetObject("path"); /* borrow */
- PyList_Insert(sys_path, 0, Py_None); /* place holder, resizes the list */
-
- for(a=0; dirs[a]; a++) {
- dirname= BLI_gethome_folder(dirs[a]);
-
- if(!dirname)
- continue;
-
- dir = opendir(dirname);
-
- if(!dir)
- continue;
+
+ while((de = readdir(dir)) != NULL) {
+ /* We could stat the file but easier just to let python
+ * import it and complain if theres a problem */
- /* set the first dir in the sys.path for fast importing of modules */
- PyList_SetItem(sys_path, 0, PyUnicode_FromString(dirname)); /* steals the ref */
-
- while((de = readdir(dir)) != NULL) {
- /* We could stat the file but easier just to let python
- * import it and complain if theres a problem */
-
- file_extension = strstr(de->d_name, ".py");
+ file_extension = strstr(de->d_name, ".py");
+
+ if(file_extension && *(file_extension + 3) == '\0') {
+ filelen = strlen(de->d_name);
+ BLI_strncpy(path, de->d_name, filelen-2); /* cut off the .py on copy */
- if(file_extension && file_extension[3] == '\0') {
- BLI_strncpy(path, de->d_name, (file_extension - de->d_name) + 1); /* cut off the .py on copy */
- mod= PyImport_ImportModuleLevel(path, NULL, NULL, NULL, 0);
- if (mod) {
- if (reload) {
- PyObject *mod_orig= mod;
- mod= PyImport_ReloadModule(mod);
- Py_DECREF(mod_orig);
- }
- }
-
- if(mod) {
- Py_DECREF(mod); /* could be NULL from reloading */
- } else {
- BPy_errors_to_report(NULL);
- fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name);
+ mod= PyImport_ImportModuleLevel(path, NULL, NULL, NULL, 0);
+ if (mod) {
+ if (reload) {
+ PyObject *mod_orig= mod;
+ mod= PyImport_ReloadModule(mod);
+ Py_DECREF(mod_orig);
}
-
+ }
+
+ if(mod) {
+ Py_DECREF(mod); /* could be NULL from reloading */
+ } else {
+ PyErr_Print(); PyErr_Clear();
+ fprintf(stderr, "unable to import \"%s\" %s/%s\n", path, dirname, de->d_name);
}
}
-
- closedir(dir);
}
-
- PyList_SetSlice(sys_path, 0, 1, NULL); /* remove the first item */
- bpy_import_main_set(NULL);
+ closedir(dir);
+
+ PySys_SetObject("path", sys_path_orig);
+ Py_DECREF(sys_path_orig);
PyGILState_Release(gilstate);
#ifdef TIME_REGISTRATION
@@ -626,7 +530,7 @@ static float pydriver_error(ChannelDriver *driver)
driver->flag |= DRIVER_FLAG_INVALID; /* py expression failed */
fprintf(stderr, "\nError in Driver: The following Python expression failed:\n\t'%s'\n\n", driver->expression);
- BPy_errors_to_report(NULL); // TODO - reports
+ PyErr_Print(); PyErr_Clear();
return 0.0f;
}
@@ -685,7 +589,7 @@ float BPY_pydriver_eval (ChannelDriver *driver)
}
fprintf(stderr, "\tBPY_pydriver_eval() - couldn't add variable '%s' to namespace \n", dtar->name);
- BPy_errors_to_report(NULL); // TODO - reports
+ PyErr_Print(); PyErr_Clear();
}
}
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index b57ef54304b..004cf2fb7c7 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -68,7 +68,7 @@ static PyObject *pyop_base_call( PyObject * self, PyObject * args, PyObject * k
return NULL;
}
- ot= WM_operatortype_find(opname, 1);
+ ot= WM_operatortype_find(opname);
if (ot == NULL) {
PyErr_Format( PyExc_SystemError, "Operator \"%s\"could not be found", opname);
return NULL;
@@ -130,18 +130,11 @@ static PyObject *pyop_base_getattro( BPy_OperatorBase * self, PyObject *pyname )
PyObject *ret;
wmOperatorType *ot;
- /* First look for the operator, then our own methods if that fails.
- * when methods are searched first, PyObject_GenericGetAttr will raise an error
- * each time we want to call an operator, we could clear the error but I prefer
- * not to since calling operators is a lot more common then adding and removing. - Campbell */
-
- if ((ot= WM_operatortype_find(name, 1))) {
+ if ((ot= WM_operatortype_find(name))) {
ret = PyCFunction_New( pyop_base_call_meth, pyname); /* set the name string as self, PyCFunction_New incref's self */
}
else if ((ret = PyObject_GenericGetAttr((PyObject *)self, pyname))) {
- /* do nothing, this accounts for methoddef's add and remove
- * An exception is raised when PyObject_GenericGetAttr fails
- * but its ok because its overwritten below */
+ /* do nothing, this accounts for methoddef's add and remove */
}
else {
PyErr_Format( PyExc_AttributeError, "Operator \"%s\" not found", name);
@@ -177,7 +170,7 @@ static PyObject *pyop_base_rna(PyObject *self, PyObject *pyname)
char *name = _PyUnicode_AsString(pyname);
wmOperatorType *ot;
- if ((ot= WM_operatortype_find(name, 1))) {
+ if ((ot= WM_operatortype_find(name))) {
BPy_StructRNA *pyrna;
PointerRNA ptr;
diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c
index f8567414717..6ab990acdf5 100644
--- a/source/blender/python/intern/bpy_operator_wrap.c
+++ b/source/blender/python/intern/bpy_operator_wrap.c
@@ -40,13 +40,116 @@
#include "bpy_compat.h"
#include "bpy_util.h"
-#include "../generic/bpy_internal_import.h" // our own imports
-
#define PYOP_ATTR_PROP "__props__"
#define PYOP_ATTR_UINAME "__label__"
#define PYOP_ATTR_IDNAME "__name__" /* use pythons class name */
#define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */
+static PyObject *pyop_dict_from_event(wmEvent *event)
+{
+ PyObject *dict= PyDict_New();
+ PyObject *item;
+ char *cstring, ascii[2];
+
+ /* type */
+ item= PyUnicode_FromString(WM_key_event_string(event->type));
+ PyDict_SetItemString(dict, "type", item); Py_DECREF(item);
+
+ /* val */
+ switch(event->val) {
+ case KM_ANY:
+ cstring = "ANY";
+ break;
+ case KM_RELEASE:
+ cstring = "RELEASE";
+ break;
+ case KM_PRESS:
+ cstring = "PRESS";
+ break;
+ default:
+ cstring = "UNKNOWN";
+ break;
+ }
+
+ item= PyUnicode_FromString(cstring);
+ PyDict_SetItemString(dict, "val", item); Py_DECREF(item);
+
+ /* x, y (mouse) */
+ item= PyLong_FromLong(event->x);
+ PyDict_SetItemString(dict, "x", item); Py_DECREF(item);
+
+ item= PyLong_FromLong(event->y);
+ PyDict_SetItemString(dict, "y", item); Py_DECREF(item);
+
+ item= PyLong_FromLong(event->prevx);
+ PyDict_SetItemString(dict, "prevx", item); Py_DECREF(item);
+
+ item= PyLong_FromLong(event->prevy);
+ PyDict_SetItemString(dict, "prevy", item); Py_DECREF(item);
+
+ /* ascii */
+ ascii[0]= event->ascii;
+ ascii[1]= '\0';
+ item= PyUnicode_FromString(ascii);
+ PyDict_SetItemString(dict, "ascii", item); Py_DECREF(item);
+
+ /* modifier keys */
+ item= PyLong_FromLong(event->shift);
+ PyDict_SetItemString(dict, "shift", item); Py_DECREF(item);
+
+ item= PyLong_FromLong(event->ctrl);
+ PyDict_SetItemString(dict, "ctrl", item); Py_DECREF(item);
+
+ item= PyLong_FromLong(event->alt);
+ PyDict_SetItemString(dict, "alt", item); Py_DECREF(item);
+
+ item= PyLong_FromLong(event->oskey);
+ PyDict_SetItemString(dict, "oskey", item); Py_DECREF(item);
+
+
+
+ /* modifier */
+#if 0
+ item= PyTuple_New(0);
+ if(event->keymodifier & KM_SHIFT) {
+ _PyTuple_Resize(&item, size+1);
+ PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("SHIFT"));
+ size++;
+ }
+ if(event->keymodifier & KM_CTRL) {
+ _PyTuple_Resize(&item, size+1);
+ PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("CTRL"));
+ size++;
+ }
+ if(event->keymodifier & KM_ALT) {
+ _PyTuple_Resize(&item, size+1);
+ PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("ALT"));
+ size++;
+ }
+ if(event->keymodifier & KM_OSKEY) {
+ _PyTuple_Resize(&item, size+1);
+ PyTuple_SET_ITEM(item, size, _PyUnicode_AsString("OSKEY"));
+ size++;
+ }
+ PyDict_SetItemString(dict, "keymodifier", item); Py_DECREF(item);
+#endif
+
+ return dict;
+}
+
+/* TODO - a whole traceback would be ideal */
+static void pyop_error_report(ReportList *reports)
+{
+ PyObject *exception, *v, *tb;
+ PyErr_Fetch(&exception, &v, &tb);
+ if (exception == NULL)
+ return;
+ /* Now we know v != NULL too */
+ BKE_report(reports, RPT_ERROR, _PyUnicode_AsString(v));
+
+ PyErr_Print();
+}
+
static struct BPY_flag_def pyop_ret_flags[] = {
{"RUNNING_MODAL", OPERATOR_RUNNING_MODAL},
{"CANCELLED", OPERATOR_CANCELLED},
@@ -87,13 +190,9 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
PyObject *ret= NULL, *py_class_instance, *item= NULL;
int ret_flag= (mode==PYOP_POLL ? 0:OPERATOR_CANCELLED);
PointerRNA ptr_context;
- PointerRNA ptr_operator;
- PointerRNA ptr_event;
- PyObject *py_operator;
+ PyObject *py_context;
PyGILState_STATE gilstate = PyGILState_Ensure();
-
- bpy_import_main_set(CTX_data_main(C));
BPY_update_modules(); // XXX - the RNA pointers can change so update before running, would like a nicer solutuon for this.
@@ -107,9 +206,15 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
/* Assign instance attributes from operator properties */
{
+ PropertyRNA *prop, *iterprop;
+ CollectionPropertyIterator iter;
const char *arg_name;
- RNA_STRUCT_BEGIN(op->ptr, prop) {
+ iterprop= RNA_struct_iterator_property(op->ptr->type);
+ RNA_property_collection_begin(op->ptr, iterprop, &iter);
+
+ for(; iter.valid; RNA_property_collection_next(&iter)) {
+ prop= iter.ptr.data;
arg_name= RNA_property_identifier(prop);
if (strcmp(arg_name, "rna_type")==0) continue;
@@ -118,33 +223,23 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
PyObject_SetAttrString(py_class_instance, arg_name, item);
Py_DECREF(item);
}
- RNA_STRUCT_END;
- }
-
- /* set operator pointer RNA as instance "__operator__" attribute */
- RNA_pointer_create(NULL, &RNA_Operator, op, &ptr_operator);
- py_operator= pyrna_struct_CreatePyObject(&ptr_operator);
- PyObject_SetAttrString(py_class_instance, "__operator__", py_operator);
- Py_DECREF(py_operator);
- RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
+ RNA_property_collection_end(&iter);
+ }
+
if (mode==PYOP_INVOKE) {
item= PyObject_GetAttrString(py_class, "invoke");
- args = PyTuple_New(3);
-
- RNA_pointer_create(NULL, &RNA_Event, event, &ptr_event);
-
- // PyTuple_SET_ITEM "steals" object reference, it is
- // an object passed shouldn't be DECREF'ed
- PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
- PyTuple_SET_ITEM(args, 2, pyrna_struct_CreatePyObject(&ptr_event));
+ args = PyTuple_New(2);
+ PyTuple_SET_ITEM(args, 1, pyop_dict_from_event(event));
}
else if (mode==PYOP_EXEC) {
- item= PyObject_GetAttrString(py_class, "execute");
+ item= PyObject_GetAttrString(py_class, "exec");
args = PyTuple_New(2);
- PyTuple_SET_ITEM(args, 1, pyrna_struct_CreatePyObject(&ptr_context));
+ RNA_pointer_create(NULL, &RNA_Context, C, &ptr_context);
+ py_context = pyrna_struct_CreatePyObject(&ptr_context);
+ PyTuple_SET_ITEM(args, 1, py_context);
}
else if (mode==PYOP_POLL) {
item= PyObject_GetAttrString(py_class, "poll");
@@ -161,13 +256,13 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
}
if (ret == NULL) { /* covers py_class_instance failing too */
- BPy_errors_to_report(op->reports);
+ pyop_error_report(op->reports);
}
else {
if (mode==PYOP_POLL) {
if (PyBool_Check(ret) == 0) {
PyErr_SetString(PyExc_ValueError, "Python poll function return value ");
- BPy_errors_to_report(op->reports);
+ pyop_error_report(op->reports);
}
else {
ret_flag= ret==Py_True ? 1:0;
@@ -175,9 +270,8 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
} else if (BPY_flag_from_seq(pyop_ret_flags, ret, &ret_flag) == -1) {
/* the returned value could not be converted into a flag */
- BPy_errors_to_report(op->reports);
-
- ret_flag = OPERATOR_CANCELLED;
+ pyop_error_report(op->reports);
+
}
/* there is no need to copy the py keyword dict modified by
* pyot->py_invoke(), back to the operator props since they are just
@@ -190,34 +284,7 @@ static int PYTHON_OT_generic(int mode, bContext *C, wmOperator *op, wmEvent *eve
Py_DECREF(ret);
}
- /* print operator return value */
- if (mode != PYOP_POLL) {
- char flag_str[100];
- char class_name[100];
- BPY_flag_def *flag_def = pyop_ret_flags;
-
- strcpy(flag_str, "");
-
- while(flag_def->name) {
- if (ret_flag & flag_def->flag) {
- if(flag_str[1])
- sprintf(flag_str, "%s | %s", flag_str, flag_def->name);
- else
- strcpy(flag_str, flag_def->name);
- }
- flag_def++;
- }
-
- /* get class name */
- item= PyObject_GetAttrString(py_class, PYOP_ATTR_IDNAME);
- Py_DECREF(item);
- strcpy(class_name, _PyUnicode_AsString(item));
-
- fprintf(stderr, "%s's %s returned %s\n", class_name, mode == PYOP_EXEC ? "execute" : "invoke", flag_str);
- }
-
PyGILState_Release(gilstate);
- bpy_import_main_set(NULL);
return ret_flag;
}
@@ -267,7 +334,7 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
/* api callbacks, detailed checks dont on adding */
if (PyObject_HasAttrString(py_class, "invoke"))
ot->invoke= PYTHON_OT_invoke;
- if (PyObject_HasAttrString(py_class, "execute"))
+ if (PyObject_HasAttrString(py_class, "exec"))
ot->exec= PYTHON_OT_exec;
if (PyObject_HasAttrString(py_class, "poll"))
ot->poll= PYTHON_OT_poll;
@@ -320,7 +387,6 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata)
PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
{
PyObject *base_class, *item;
- wmOperatorType *ot;
char *idname= NULL;
@@ -331,8 +397,8 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
{PYOP_ATTR_UINAME, 's', 0, BPY_CLASS_ATTR_OPTIONAL},
{PYOP_ATTR_PROP, 'l', 0, BPY_CLASS_ATTR_OPTIONAL},
{PYOP_ATTR_DESCRIPTION, 's', 0, BPY_CLASS_ATTR_NONE_OK},
- {"execute", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
- {"invoke", 'f', 3, BPY_CLASS_ATTR_OPTIONAL},
+ {"exec", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
+ {"invoke", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
{"poll", 'f', 2, BPY_CLASS_ATTR_OPTIONAL},
{NULL, 0, 0, 0}
};
@@ -351,12 +417,9 @@ PyObject *PYOP_wrap_add(PyObject *self, PyObject *py_class)
Py_DECREF(item);
idname = _PyUnicode_AsString(item);
- /* remove if it already exists */
- if ((ot=WM_operatortype_exists(idname))) {
- if(ot->pyop_data) {
- Py_XDECREF((PyObject*)ot->pyop_data);
- }
- WM_operatortype_remove(idname);
+ if (WM_operatortype_find(idname)) {
+ PyErr_Format( PyExc_AttributeError, "Operator alredy exists with this name \"%s\"", idname);
+ return NULL;
}
/* If we have properties set, check its a list of dicts */
@@ -403,7 +466,7 @@ PyObject *PYOP_wrap_remove(PyObject *self, PyObject *value)
return NULL;
}
- if (!(ot= WM_operatortype_exists(idname))) {
+ if (!(ot= WM_operatortype_find(idname))) {
PyErr_Format( PyExc_AttributeError, "Operator \"%s\" does not exists, cant remove", idname);
return NULL;
}
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index 9ce9ec8e838..9fa7d1b6693 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -35,102 +35,16 @@
#include "RNA_define.h" /* for defining our own rna */
#include "MEM_guardedalloc.h"
-#include "BKE_utildefines.h"
#include "BKE_context.h"
#include "BKE_global.h" /* evil G.* */
#include "BKE_report.h"
-/* only for keyframing */
-#include "DNA_scene_types.h"
-#include "ED_keyframing.h"
-
-#define USE_MATHUTILS
-
-#ifdef USE_MATHUTILS
-#include "../generic/Mathutils.h" /* so we can have mathutils callbacks */
-
-/* bpyrna vector/euler/quat callbacks */
-static int mathutils_rna_array_cb_index= -1; /* index for our callbacks */
-
-static int mathutils_rna_generic_check(BPy_PropertyRNA *self)
-{
- return self->prop?1:0;
-}
-
-static int mathutils_rna_vector_get(BPy_PropertyRNA *self, int subtype, float *vec_from)
-{
- if(self->prop==NULL)
- return 0;
-
- RNA_property_float_get_array(&self->ptr, self->prop, vec_from);
- return 1;
-}
-
-static int mathutils_rna_vector_set(BPy_PropertyRNA *self, int subtype, float *vec_to)
-{
- if(self->prop==NULL)
- return 0;
-
- RNA_property_float_set_array(&self->ptr, self->prop, vec_to);
- return 1;
-}
-
-static int mathutils_rna_vector_get_index(BPy_PropertyRNA *self, int subtype, float *vec_from, int index)
-{
- if(self->prop==NULL)
- return 0;
-
- vec_from[index]= RNA_property_float_get_index(&self->ptr, self->prop, index);
- return 1;
-}
-
-static int mathutils_rna_vector_set_index(BPy_PropertyRNA *self, int subtype, float *vec_to, int index)
-{
- if(self->prop==NULL)
- return 0;
-
- RNA_property_float_set_index(&self->ptr, self->prop, index, vec_to[index]);
- return 1;
-}
-
-Mathutils_Callback mathutils_rna_array_cb = {
- (BaseMathCheckFunc) mathutils_rna_generic_check,
- (BaseMathGetFunc) mathutils_rna_vector_get,
- (BaseMathSetFunc) mathutils_rna_vector_set,
- (BaseMathGetIndexFunc) mathutils_rna_vector_get_index,
- (BaseMathSetIndexFunc) mathutils_rna_vector_set_index
-};
-
-
-/* bpyrna matrix callbacks */
-static int mathutils_rna_matrix_cb_index= -1; /* index for our callbacks */
-
-static int mathutils_rna_matrix_get(BPy_PropertyRNA *self, int subtype, float *mat_from)
-{
- if(self->prop==NULL)
- return 0;
-
- RNA_property_float_get_array(&self->ptr, self->prop, mat_from);
- return 1;
-}
-
-static int mathutils_rna_matrix_set(BPy_PropertyRNA *self, int subtype, float *mat_to)
-{
- if(self->prop==NULL)
- return 0;
-
- RNA_property_float_set_array(&self->ptr, self->prop, mat_to);
- return 1;
-}
-
-Mathutils_Callback mathutils_rna_matrix_cb = {
- (BaseMathCheckFunc) mathutils_rna_generic_check,
- (BaseMathGetFunc) mathutils_rna_matrix_get,
- (BaseMathSetFunc) mathutils_rna_matrix_set,
- (BaseMathGetIndexFunc) NULL,
- (BaseMathSetIndexFunc) NULL
-};
-
+#if 0
+#define bpy_PyObject_New(type, typeobj) \
+( (type *) PyObject_Init( \
+ (PyObject *) MEM_callocN( _PyObject_SIZE(typeobj), "python memory from bpy_rna.c" ), (typeobj)) )
+#else
+#define bpy_PyObject_New(type, typeobj) PyObject_New(type, typeobj)
#endif
static int pyrna_struct_compare( BPy_StructRNA * a, BPy_StructRNA * b )
@@ -167,39 +81,39 @@ static PyObject *pyrna_prop_richcmp(BPy_PropertyRNA * a, BPy_PropertyRNA * b, in
/*----------------------repr--------------------------------------------*/
static PyObject *pyrna_struct_repr( BPy_StructRNA * self )
{
- PyObject *pyob;
- char *name;
+ PropertyRNA *prop;
+ char str[512];
/* print name if available */
- name= RNA_struct_name_get_alloc(&self->ptr, NULL, 0);
- if(name) {
- pyob= PyUnicode_FromFormat( "[BPy_StructRNA \"%.200s\" -> \"%.200s\"]", RNA_struct_identifier(self->ptr.type), name);
- MEM_freeN(name);
- return pyob;
+ prop= RNA_struct_name_property(self->ptr.type);
+ if(prop) {
+ RNA_property_string_get(&self->ptr, prop, str);
+ return PyUnicode_FromFormat( "[BPy_StructRNA \"%s\" -> \"%s\"]", RNA_struct_identifier(self->ptr.type), str);
}
- return PyUnicode_FromFormat( "[BPy_StructRNA \"%.200s\"]", RNA_struct_identifier(self->ptr.type));
+ return PyUnicode_FromFormat( "[BPy_StructRNA \"%s\"]", RNA_struct_identifier(self->ptr.type));
}
static PyObject *pyrna_prop_repr( BPy_PropertyRNA * self )
{
- PyObject *pyob;
+ PropertyRNA *prop;
PointerRNA ptr;
- char *name;
+ char str[512];
/* if a pointer, try to print name of pointer target too */
if(RNA_property_type(self->prop) == PROP_POINTER) {
ptr= RNA_property_pointer_get(&self->ptr, self->prop);
- name= RNA_struct_name_get_alloc(&ptr, NULL, 0);
- if(name) {
- pyob= PyUnicode_FromFormat( "[BPy_PropertyRNA \"%.200s\" -> \"%.200s\" -> \"%.200s\" ]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), name);
- MEM_freeN(name);
- return pyob;
+ if(ptr.data) {
+ prop= RNA_struct_name_property(ptr.type);
+ if(prop) {
+ RNA_property_string_get(&ptr, prop, str);
+ return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%s\" -> \"%s\" -> \"%s\" ]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), str);
+ }
}
}
- return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%.200s\" -> \"%.200s\"]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop));
+ return PyUnicode_FromFormat( "[BPy_PropertyRNA \"%s\" -> \"%s\"]", RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop));
}
static long pyrna_struct_hash( BPy_StructRNA * self )
@@ -210,35 +124,24 @@ static long pyrna_struct_hash( BPy_StructRNA * self )
/* use our own dealloc so we can free a property if we use one */
static void pyrna_struct_dealloc( BPy_StructRNA * self )
{
+ /* Note!! for some weired reason calling PyObject_DEL() directly crashes blender! */
if (self->freeptr && self->ptr.data) {
IDP_FreeProperty(self->ptr.data);
MEM_freeN(self->ptr.data);
self->ptr.data= NULL;
}
- /* Note, for subclassed PyObjects we cant just call PyObject_DEL() directly or it will crash */
Py_TYPE(self)->tp_free(self);
return;
}
static char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop)
{
- EnumPropertyItem *item;
- char *result;
- int free= 0;
-
- RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free);
- if(item) {
- result= (char*)BPy_enum_as_string(item);
- }
- else {
- result= "";
- }
-
- if(free)
- MEM_freeN(item);
+ const EnumPropertyItem *item;
+ int totitem;
- return result;
+ RNA_property_enum_items(ptr, prop, &item, &totitem);
+ return (char*)BPy_enum_as_string((EnumPropertyItem*)item);
}
PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
@@ -249,52 +152,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
if (len > 0) {
/* resolve the array from a new pytype */
- PyObject *ret = pyrna_prop_CreatePyObject(ptr, prop);
-
-#ifdef USE_MATHUTILS
-
- /* return a mathutils vector where possible */
- if(RNA_property_type(prop)==PROP_FLOAT) {
- switch(RNA_property_subtype(prop)) {
- case PROP_VECTOR:
- if(len>=2 && len <= 4) {
- PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, 0);
- Py_DECREF(ret); /* the vector owns now */
- ret= vec_cb; /* return the vector instead */
- }
- break;
- case PROP_MATRIX:
- if(len==16) {
- PyObject *mat_cb= newMatrixObject_cb(ret, 4,4, mathutils_rna_matrix_cb_index, 0);
- Py_DECREF(ret); /* the matrix owns now */
- ret= mat_cb; /* return the matrix instead */
- }
- else if (len==9) {
- PyObject *mat_cb= newMatrixObject_cb(ret, 3,3, mathutils_rna_matrix_cb_index, 0);
- Py_DECREF(ret); /* the matrix owns now */
- ret= mat_cb; /* return the matrix instead */
- }
- break;
- case PROP_ROTATION:
- if(len==3) { /* euler */
- PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, 0);
- Py_DECREF(ret); /* the matrix owns now */
- ret= eul_cb; /* return the matrix instead */
- }
- else if (len==4) {
- PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, 0);
- Py_DECREF(ret); /* the matrix owns now */
- ret= quat_cb; /* return the matrix instead */
- }
- break;
- default:
- break;
- }
- }
-
-#endif
-
- return ret;
+ return pyrna_prop_CreatePyObject(ptr, prop);
}
/* see if we can coorce into a python type - PropertyType */
@@ -321,32 +179,11 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
const char *identifier;
int val = RNA_property_enum_get(ptr, prop);
- if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) {
+ if (RNA_property_enum_identifier(ptr, prop, val, &identifier)) {
ret = PyUnicode_FromString( identifier );
} else {
- EnumPropertyItem *item;
- int free= 0;
-
- /* don't throw error here, can't trust blender 100% to give the
- * right values, python code should not generate error for that */
- RNA_property_enum_items(BPy_GetContext(), ptr, prop, &item, NULL, &free);
- if(item && item->identifier) {
- ret = PyUnicode_FromString( item->identifier );
- }
- else {
- /* prefer not fail silently incase of api errors, maybe disable it later */
- char error_str[128];
- sprintf(error_str, "RNA Warning: Current value \"%d\" matches no enum", val);
- PyErr_Warn(PyExc_RuntimeWarning, error_str);
-
- ret = PyUnicode_FromString( "" );
- }
-
- if(free)
- MEM_freeN(item);
-
- /*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val);
- ret = NULL;*/
+ PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val);
+ ret = NULL;
}
break;
@@ -384,15 +221,23 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
const char *arg_name= NULL;
PyObject *item;
+ PropertyRNA *prop, *iterprop;
+ CollectionPropertyIterator iter;
+
+ iterprop= RNA_struct_iterator_property(ptr->type);
+ RNA_property_collection_begin(ptr, iterprop, &iter);
+
totkw = kw ? PyDict_Size(kw):0;
- RNA_STRUCT_BEGIN(ptr, prop) {
+ for(; iter.valid; RNA_property_collection_next(&iter)) {
+ prop= iter.ptr.data;
+
arg_name= RNA_property_identifier(prop);
if (strcmp(arg_name, "rna_type")==0) continue;
if (kw==NULL) {
- PyErr_Format( PyExc_AttributeError, "%.200s: no keywords, expected \"%.200s\"", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+ PyErr_Format( PyExc_AttributeError, "%s: no keywords, expected \"%s\"", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
error_val= -1;
break;
}
@@ -400,7 +245,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
item= PyDict_GetItemString(kw, arg_name);
if (item == NULL) {
- PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" missing", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+ PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" missing", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
error_val = -1; /* pyrna_py_to_prop sets the error */
break;
}
@@ -412,7 +257,8 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
totkw--;
}
- RNA_STRUCT_END;
+
+ RNA_property_collection_end(&iter);
if (error_val==0 && totkw > 0) { /* some keywords were given that were not used :/ */
PyObject *key, *value;
@@ -424,7 +270,7 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
arg_name= NULL;
}
- PyErr_Format( PyExc_AttributeError, "%.200s: keyword \"%.200s\" unrecognized", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
+ PyErr_Format( PyExc_AttributeError, "%s: keyword \"%s\" unrecognized", error_prefix, arg_name ? arg_name : "<UNKNOWN>");
error_val = -1;
}
@@ -433,15 +279,12 @@ int pyrna_pydict_to_props(PointerRNA *ptr, PyObject *kw, const char *error_prefi
static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw);
-PyObject *pyrna_func_to_py(BPy_StructRNA *pyrna, FunctionRNA *func)
+PyObject *pyrna_func_to_py(PointerRNA *ptr, FunctionRNA *func)
{
static PyMethodDef func_meth = {"<generic rna function>", (PyCFunction)pyrna_func_call, METH_VARARGS|METH_KEYWORDS, "python rna function"};
PyObject *self= PyTuple_New(2);
PyObject *ret;
-
- PyTuple_SET_ITEM(self, 0, (PyObject *)pyrna);
- Py_INCREF(pyrna);
-
+ PyTuple_SET_ITEM(self, 0, pyrna_struct_CreatePyObject(ptr));
PyTuple_SET_ITEM(self, 1, PyCObject_FromVoidPtr((void *)func, NULL));
ret= PyCFunction_New(&func_meth, self);
@@ -459,30 +302,15 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
if (len > 0) {
PyObject *item;
- int py_len = -1;
int i;
-
-#ifdef USE_MATHUTILS
- if(MatrixObject_Check(value)) {
- MatrixObject *mat = (MatrixObject*)value;
- if(!BaseMath_ReadCallback(mat))
- return -1;
-
- py_len = mat->rowSize * mat->colSize;
- } else /* continue... */
-#endif
- if (PySequence_Check(value)) {
- py_len= (int)PySequence_Length(value);
- }
- else {
- PyErr_Format(PyExc_TypeError, "RNA array assignment expected a sequence instead of %.200s instance.", Py_TYPE(value)->tp_name);
+ if (!PySequence_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, "expected a python sequence type assigned to an RNA array.");
return -1;
}
- /* done getting the length */
- if (py_len != len) {
- PyErr_Format(PyExc_AttributeError, "python sequence length %d did not match the RNA array length %d.", py_len, len);
+ if ((int)PySequence_Length(value) != len) {
+ PyErr_SetString(PyExc_AttributeError, "python sequence length did not match the RNA array.");
return -1;
}
@@ -548,21 +376,14 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
else param_arr = MEM_mallocN(sizeof(float) * len, "pyrna float array");
-#ifdef USE_MATHUTILS
- if(MatrixObject_Check(value) && RNA_property_subtype(prop) == PROP_MATRIX) {
- MatrixObject *mat = (MatrixObject*)value;
- memcpy(param_arr, mat->contigPtr, sizeof(float) * len);
- } else /* continue... */
-#endif
- {
- /* collect the variables */
- for (i=0; i<len; i++) {
- item = PySequence_GetItem(value, i);
- param_arr[i] = (float)PyFloat_AsDouble(item); /* deal with any errors later */
- Py_DECREF(item);
- }
+
+ /* collect the variables */
+ for (i=0; i<len; i++) {
+ item = PySequence_GetItem(value, i);
+ param_arr[i] = (float)PyFloat_AsDouble(item); /* deal with any errors later */
+ Py_DECREF(item);
}
-
+
if (PyErr_Occurred()) {
if(data==NULL)
MEM_freeN(param_arr);
@@ -637,17 +458,17 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
if (param==NULL) {
char *enum_str= pyrna_enum_as_string(ptr, prop);
- PyErr_Format(PyExc_TypeError, "expected a string enum type in (%.200s)", enum_str);
+ PyErr_Format(PyExc_TypeError, "expected a string enum type in (%s)", enum_str);
MEM_freeN(enum_str);
return -1;
} else {
int val;
- if (RNA_property_enum_value(BPy_GetContext(), ptr, prop, param, &val)) {
+ if (RNA_property_enum_value(ptr, prop, param, &val)) {
if(data) *((int*)data)= val;
else RNA_property_enum_set(ptr, prop, val);
} else {
char *enum_str= pyrna_enum_as_string(ptr, prop);
- PyErr_Format(PyExc_AttributeError, "enum \"%.200s\" not found in (%.200s)", param, enum_str);
+ PyErr_Format(PyExc_AttributeError, "enum \"%s\" not found in (%s)", param, enum_str);
MEM_freeN(enum_str);
return -1;
}
@@ -662,15 +483,13 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
if(!BPy_StructRNA_Check(value) && value != Py_None) {
PointerRNA tmp;
RNA_pointer_create(NULL, ptype, NULL, &tmp);
- PyErr_Format(PyExc_TypeError, "expected a %.200s type", RNA_struct_identifier(tmp.type));
+ PyErr_Format(PyExc_TypeError, "expected a %s type", RNA_struct_identifier(tmp.type));
return -1;
} else {
BPy_StructRNA *param= (BPy_StructRNA*)value;
int raise_error= 0;
if(data) {
- int flag = RNA_property_flag(prop);
-
- if(flag & PROP_RNAPTR) {
+ if(ptype == &RNA_AnyType) {
if(value == Py_None)
memset(data, 0, sizeof(PointerRNA));
else
@@ -699,7 +518,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
else {
PointerRNA tmp;
RNA_pointer_create(NULL, ptype, NULL, &tmp);
- PyErr_Format(PyExc_TypeError, "expected a %.200s type", RNA_struct_identifier(tmp.type));
+ PyErr_Format(PyExc_TypeError, "expected a %s type", RNA_struct_identifier(tmp.type));
return -1;
}
}
@@ -707,7 +526,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
if(raise_error) {
PointerRNA tmp;
RNA_pointer_create(NULL, ptype, NULL, &tmp);
- PyErr_Format(PyExc_TypeError, "expected a %.200s type", RNA_struct_identifier(tmp.type));
+ PyErr_Format(PyExc_TypeError, "expected a %s type", RNA_struct_identifier(tmp.type));
return -1;
}
}
@@ -718,10 +537,6 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
int seq_len, i;
PyObject *item;
PointerRNA itemptr;
- ListBase *lb;
- CollectionPointerLink *link;
-
- lb= (data)? (ListBase*)data: NULL;
/* convert a sequence of dict's into a collection */
if(!PySequence_Check(value)) {
@@ -737,15 +552,8 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
Py_XDECREF(item);
return -1;
}
-
- if(lb) {
- link= MEM_callocN(sizeof(CollectionPointerLink), "PyCollectionPointerLink");
- link->ptr= itemptr;
- BLI_addtail(lb, link);
- }
- else
- RNA_property_collection_add(ptr, prop, &itemptr);
-
+
+ RNA_property_collection_add(ptr, prop, &itemptr);
if(pyrna_pydict_to_props(&itemptr, item, "Converting a python list to an RNA collection")==-1) {
Py_DECREF(item);
return -1;
@@ -859,317 +667,117 @@ static Py_ssize_t pyrna_prop_len( BPy_PropertyRNA * self )
return len;
}
-/* internal use only */
-static PyObject *prop_subscript_collection_int(BPy_PropertyRNA * self, int keynum)
-{
- PointerRNA newptr;
-
- if(keynum < 0) keynum += RNA_property_collection_length(&self->ptr, self->prop);
-
- if(RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum, &newptr))
- return pyrna_struct_CreatePyObject(&newptr);
-
- PyErr_Format(PyExc_IndexError, "index %d out of range", keynum);
- return NULL;
-}
-static PyObject *prop_subscript_array_int(BPy_PropertyRNA * self, int keynum)
-{
- int len= RNA_property_array_length(self->prop);
-
- if(keynum < 0) keynum += len;
-
- if(keynum >= 0 && keynum < len)
- return pyrna_prop_to_py_index(&self->ptr, self->prop, keynum);
-
- PyErr_Format(PyExc_IndexError, "index %d out of range", keynum);
- return NULL;
-}
-
-static PyObject *prop_subscript_collection_str(BPy_PropertyRNA * self, char *keyname)
-{
- PointerRNA newptr;
- if(RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr))
- return pyrna_struct_CreatePyObject(&newptr);
-
- PyErr_Format(PyExc_KeyError, "key \"%.200s\" not found", keyname);
- return NULL;
-}
-/* static PyObject *prop_subscript_array_str(BPy_PropertyRNA * self, char *keyname) */
-
-
-
-
-#if PY_VERSION_HEX >= 0x03000000
-static PyObject *prop_subscript_collection_slice(BPy_PropertyRNA * self, int start, int stop)
+static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key )
{
+ PyObject *ret;
PointerRNA newptr;
- PyObject *list = PyList_New(stop - start);
- int count;
-
- start = MIN2(start,stop); /* values are clamped from */
-
- for(count = start; count < stop; count++) {
- if(RNA_property_collection_lookup_int(&self->ptr, self->prop, count - start, &newptr)) {
- PyList_SetItem(list, count - start, pyrna_struct_CreatePyObject(&newptr));
- }
- else {
- Py_DECREF(list);
-
- PyErr_SetString(PyExc_RuntimeError, "error getting an rna struct from a collection");
- return NULL;
- }
- }
-
- return list;
-}
-static PyObject *prop_subscript_array_slice(BPy_PropertyRNA * self, int start, int stop)
-{
- PyObject *list = PyList_New(stop - start);
- int count;
-
- start = MIN2(start,stop); /* values are clamped from PySlice_GetIndicesEx */
-
- for(count = start; count < stop; count++)
- PyList_SetItem(list, count - start, pyrna_prop_to_py_index(&self->ptr, self->prop, count));
-
- return list;
-}
-#endif
-
-static PyObject *prop_subscript_collection(BPy_PropertyRNA * self, PyObject *key)
-{
+ int keynum = 0;
+ char *keyname = NULL;
+
if (PyUnicode_Check(key)) {
- return prop_subscript_collection_str(self, _PyUnicode_AsString(key));
- }
- else if (PyIndex_Check(key)) {
- Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return NULL;
-
- return prop_subscript_collection_int(self, i);
- }
-#if PY_VERSION_HEX >= 0x03000000
- else if (PySlice_Check(key)) {
- int len= RNA_property_collection_length(&self->ptr, self->prop);
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
- return NULL;
-
- if (slicelength <= 0) {
- return PyList_New(0);
- }
- else if (step == 1) {
- return prop_subscript_collection_slice(self, start, stop);
- }
- else {
- PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna");
- return NULL;
- }
- }
-#endif
- else {
- PyErr_Format(PyExc_TypeError, "invalid rna key, key must be a string or an int instead of %.200s instance.", Py_TYPE(key)->tp_name);
- return NULL;
- }
-}
-
-static PyObject *prop_subscript_array(BPy_PropertyRNA * self, PyObject *key)
-{
- /*if (PyUnicode_Check(key)) {
- return prop_subscript_array_str(self, _PyUnicode_AsString(key));
- } else*/
- if (PyIndex_Check(key)) {
- Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return NULL;
- return prop_subscript_array_int(self, PyLong_AsSsize_t(key));
- }
-#if PY_VERSION_HEX >= 0x03000000
- else if (PySlice_Check(key)) {
- int len= RNA_property_array_length(self->prop);
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
- return NULL;
-
- if (slicelength <= 0) {
- return PyList_New(0);
- }
- else if (step == 1) {
- return prop_subscript_array_slice(self, start, stop);
- }
- else {
- PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna");
- return NULL;
- }
- }
-#endif
- else {
- PyErr_SetString(PyExc_AttributeError, "invalid key, key must be an int");
+ keyname = _PyUnicode_AsString(key);
+ } else if (PyLong_Check(key)) {
+ keynum = PyLong_AsSsize_t(key);
+ } else {
+ PyErr_SetString(PyExc_AttributeError, "invalid key, key must be a string or an int");
return NULL;
}
-}
-
-static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key )
-{
+
if (RNA_property_type(self->prop) == PROP_COLLECTION) {
- return prop_subscript_collection(self, key);
- } else if (RNA_property_array_length(self->prop)) { /* arrays are currently fixed length, zero length means its not an array */
- return prop_subscript_array(self, key);
+ int ok;
+ if (keyname) ok = RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr);
+ else ok = RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum, &newptr);
+
+ if (ok) {
+ ret = pyrna_struct_CreatePyObject(&newptr);
+ } else {
+ PyErr_SetString(PyExc_AttributeError, "out of range");
+ ret = NULL;
+ }
+
+ } else if (keyname) {
+ PyErr_SetString(PyExc_AttributeError, "string keys are only supported for collections");
+ ret = NULL;
} else {
- PyErr_SetString(PyExc_TypeError, "rna type is not an array or a collection");
- return NULL;
- }
-
-}
-
-#if PY_VERSION_HEX >= 0x03000000
-static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int end, PyObject *value)
-{
- int count;
-
- /* values are clamped from */
- begin = MIN2(begin,end);
-
- for(count = begin; count < end; count++) {
- if(pyrna_py_to_prop_index(&self->ptr, self->prop, count - begin, value) == -1) {
- /* TODO - this is wrong since some values have been assigned... will need to fix that */
- return -1; /* pyrna_struct_CreatePyObject should set the error */
+ int len = RNA_property_array_length(self->prop);
+
+ if (len==0) { /* not an array*/
+ PyErr_Format(PyExc_AttributeError, "not an array or collection %d", keynum);
+ ret = NULL;
+ }
+
+ if (keynum >= len){
+ PyErr_SetString(PyExc_AttributeError, "index out of range");
+ ret = NULL;
+ } else { /* not an array*/
+ ret = pyrna_prop_to_py_index(&self->ptr, self->prop, keynum);
}
}
-
- return 0;
+
+ return ret;
}
-#endif
-
-static int prop_subscript_ass_array_int(BPy_PropertyRNA * self, int keynum, PyObject *value)
-{
-
- int len= RNA_property_array_length(self->prop);
-
- if(keynum < 0) keynum += len;
- if(keynum >= 0 && keynum < len)
- return pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value);
- PyErr_SetString(PyExc_IndexError, "out of range");
- return -1;
-}
-
-static int pyrna_prop_ass_subscript( BPy_PropertyRNA * self, PyObject *key, PyObject *value )
+static int pyrna_prop_assign_subscript( BPy_PropertyRNA * self, PyObject *key, PyObject *value )
{
- /* char *keyname = NULL; */ /* not supported yet */
+ int ret = 0;
+ int keynum = 0;
+ char *keyname = NULL;
if (!RNA_property_editable(&self->ptr, self->prop)) {
- PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%.200s\" from \"%.200s\" is read-only", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) );
+ PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%s\" from \"%s\" is read-only", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) );
return -1;
}
- /* maybe one day we can support this... */
- if (RNA_property_type(self->prop) == PROP_COLLECTION) {
- PyErr_Format( PyExc_AttributeError, "PropertyRNA - attribute \"%.200s\" from \"%.200s\" is a collection, assignment not supported", RNA_property_identifier(self->prop), RNA_struct_identifier(self->ptr.type) );
+ if (PyUnicode_Check(key)) {
+ keyname = _PyUnicode_AsString(key);
+ } else if (PyLong_Check(key)) {
+ keynum = PyLong_AsSsize_t(key);
+ } else {
+ PyErr_SetString(PyExc_AttributeError, "PropertyRNA - invalid key, key must be a string or an int");
return -1;
}
-
- if (PyIndex_Check(key)) {
- Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred())
- return -1;
-
- return prop_subscript_ass_array_int(self, i, value);
- }
-#if PY_VERSION_HEX >= 0x03000000
- else if (PySlice_Check(key)) {
- int len= RNA_property_array_length(self->prop);
- Py_ssize_t start, stop, step, slicelength;
-
- if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
- return -1;
-
- if (slicelength <= 0) {
- return 0;
- }
- else if (step == 1) {
- return prop_subscript_ass_array_slice(self, start, stop, value);
+
+ if (RNA_property_type(self->prop) == PROP_COLLECTION) {
+ PyErr_SetString(PyExc_AttributeError, "PropertyRNA - assignment is not supported for collections (yet)");
+ ret = -1;
+ } else if (keyname) {
+ PyErr_SetString(PyExc_AttributeError, "PropertyRNA - string keys are only supported for collections");
+ ret = -1;
+ } else {
+ int len = RNA_property_array_length(self->prop);
+
+ if (len==0) { /* not an array*/
+ PyErr_Format(PyExc_AttributeError, "PropertyRNA - not an array or collection %d", keynum);
+ ret = -1;
}
- else {
- PyErr_SetString(PyExc_TypeError, "slice steps not supported with rna");
- return -1;
+
+ if (keynum >= len){
+ PyErr_SetString(PyExc_AttributeError, "PropertyRNA - index out of range");
+ ret = -1;
+ } else {
+ ret = pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value);
}
}
-#endif
- else {
- PyErr_SetString(PyExc_AttributeError, "invalid key, key must be an int");
- return -1;
- }
+
+ return ret;
}
+
static PyMappingMethods pyrna_prop_as_mapping = {
( lenfunc ) pyrna_prop_len, /* mp_length */
( binaryfunc ) pyrna_prop_subscript, /* mp_subscript */
- ( objobjargproc ) pyrna_prop_ass_subscript, /* mp_ass_subscript */
+ ( objobjargproc ) pyrna_prop_assign_subscript, /* mp_ass_subscript */
};
-static int pyrna_prop_contains(BPy_PropertyRNA * self, PyObject *value)
-{
- PointerRNA newptr; /* not used, just so RNA_property_collection_lookup_string runs */
- char *keyname = _PyUnicode_AsString(value);
-
- if(keyname==NULL) {
- PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, key must be a string type");
- return -1;
- }
-
- if (RNA_property_type(self->prop) != PROP_COLLECTION) {
- PyErr_SetString(PyExc_TypeError, "PropertyRNA - key in prop, is only valid for collection types");
- return -1;
- }
-
-
- if (RNA_property_collection_lookup_string(&self->ptr, self->prop, keyname, &newptr))
- return 1;
-
- return 0;
-}
-
-static PySequenceMethods pyrna_prop_as_sequence = {
- NULL, /* Cant set the len otherwise it can evaluate as false */
- NULL, /* sq_concat */
- NULL, /* sq_repeat */
- NULL, /* sq_item */
- NULL, /* sq_slice */
- NULL, /* sq_ass_item */
- NULL, /* sq_ass_slice */
- (objobjproc)pyrna_prop_contains, /* sq_contains */
-};
-
-
-static PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA * self, PyObject *args)
-{
- char *path;
- int index= 0;
- float cfra = CTX_data_scene(BPy_GetContext())->r.cfra;
-
- if(!RNA_struct_is_ID(self->ptr.type)) {
- PyErr_SetString( PyExc_TypeError, "StructRNA - keyframe_insert only for ID type");
- return NULL;
- }
-
- if (!PyArg_ParseTuple(args, "s|if:keyframe_insert", &path, &index, &cfra))
- return NULL;
-
- return PyBool_FromLong( insert_keyframe((ID *)self->ptr.data, NULL, NULL, path, index, cfra, 0));
-}
-
-
static PyObject *pyrna_struct_dir(BPy_StructRNA * self)
{
PyObject *ret, *dict;
PyObject *pystring;
/* for looping over attrs and funcs */
+ CollectionPropertyIterator iter;
PropertyRNA *iterprop;
/* Include this incase this instance is a subtype of a python class
@@ -1198,23 +806,26 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA * self)
/*
* Collect RNA attributes
*/
+ PropertyRNA *nameprop;
char name[256], *nameptr;
iterprop= RNA_struct_iterator_property(self->ptr.type);
+ RNA_property_collection_begin(&self->ptr, iterprop, &iter);
- RNA_PROP_BEGIN(&self->ptr, itemptr, iterprop) {
- nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name));
-
- if(nameptr) {
+ for(; iter.valid; RNA_property_collection_next(&iter)) {
+ if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) {
+ nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name));
+
pystring = PyUnicode_FromString(nameptr);
PyList_Append(ret, pystring);
Py_DECREF(pystring);
- if(name != nameptr)
+ if ((char *)&name != nameptr)
MEM_freeN(nameptr);
}
}
- RNA_PROP_END;
+ RNA_property_collection_end(&iter);
+
}
@@ -1227,25 +838,15 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA * self)
RNA_pointer_create(NULL, &RNA_Struct, self->ptr.type, &tptr);
iterprop= RNA_struct_find_property(&tptr, "functions");
- RNA_PROP_BEGIN(&tptr, itemptr, iterprop) {
- pystring = PyUnicode_FromString(RNA_function_identifier(itemptr.data));
- PyList_Append(ret, pystring);
- Py_DECREF(pystring);
- }
- RNA_PROP_END;
- }
-
- if(self->ptr.type == &RNA_Context) {
- ListBase lb = CTX_data_dir_get(self->ptr.data);
- LinkData *link;
+ RNA_property_collection_begin(&tptr, iterprop, &iter);
- for(link=lb.first; link; link=link->next) {
- pystring = PyUnicode_FromString(link->data);
+ for(; iter.valid; RNA_property_collection_next(&iter)) {
+ pystring = PyUnicode_FromString(RNA_function_identifier(iter.ptr.data));
PyList_Append(ret, pystring);
Py_DECREF(pystring);
}
- BLI_freelistN(&lb);
+ RNA_property_collection_end(&iter);
}
return ret;
@@ -1274,7 +875,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname )
ret = pyrna_prop_to_py(&self->ptr, prop);
}
else if ((func = RNA_struct_find_function(&self->ptr, name))) {
- ret = pyrna_func_to_py(self, func);
+ ret = pyrna_func_to_py(&self->ptr, func);
}
else if (self->ptr.type == &RNA_Context) {
PointerRNA newptr;
@@ -1305,7 +906,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname )
BLI_freelistN(&newlb);
}
else {
- PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name);
+ PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" not found", name);
ret = NULL;
}
@@ -1323,13 +924,13 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje
return 0;
}
else {
- PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" not found", name);
+ PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" not found", name);
return -1;
}
}
if (!RNA_property_editable(&self->ptr, prop)) {
- PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%.200s\" from \"%.200s\" is read-only", RNA_property_identifier(prop), RNA_struct_identifier(self->ptr.type) );
+ PyErr_Format( PyExc_AttributeError, "StructRNA - Attribute \"%s\" from \"%s\" is read-only", RNA_property_identifier(prop), RNA_struct_identifier(self->ptr.type) );
return -1;
}
@@ -1337,7 +938,7 @@ static int pyrna_struct_setattro( BPy_StructRNA * self, PyObject *pyname, PyObje
return pyrna_py_to_prop(&self->ptr, prop, NULL, value);
}
-static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
+PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
{
PyObject *ret;
if (RNA_property_type(self->prop) != PROP_COLLECTION) {
@@ -1345,31 +946,34 @@ static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self)
ret = NULL;
} else {
PyObject *item;
+ CollectionPropertyIterator iter;
+ PropertyRNA *nameprop;
char name[256], *nameptr;
ret = PyList_New(0);
- RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) {
- nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name));
-
- if(nameptr) {
+ RNA_property_collection_begin(&self->ptr, self->prop, &iter);
+ for(; iter.valid; RNA_property_collection_next(&iter)) {
+ if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) {
+ nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name));
+
/* add to python list */
item = PyUnicode_FromString( nameptr );
PyList_Append(ret, item);
Py_DECREF(item);
/* done */
- if(name != nameptr)
+ if ((char *)&name != nameptr)
MEM_freeN(nameptr);
}
}
- RNA_PROP_END;
+ RNA_property_collection_end(&iter);
}
return ret;
}
-static PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
+PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
{
PyObject *ret;
if (RNA_property_type(self->prop) != PROP_COLLECTION) {
@@ -1377,315 +981,60 @@ static PyObject *pyrna_prop_items(BPy_PropertyRNA *self)
ret = NULL;
} else {
PyObject *item;
+ CollectionPropertyIterator iter;
+ PropertyRNA *nameprop;
char name[256], *nameptr;
- int i= 0;
ret = PyList_New(0);
- RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) {
- if(itemptr.data) {
- /* add to python list */
- item= PyTuple_New(2);
- nameptr= RNA_struct_name_get_alloc(&itemptr, name, sizeof(name));
- if(nameptr) {
- PyTuple_SET_ITEM(item, 0, PyUnicode_FromString( nameptr ));
- if(name != nameptr)
- MEM_freeN(nameptr);
- }
- else {
- PyTuple_SET_ITEM(item, 0, PyLong_FromSsize_t(i)); /* a bit strange but better then returning an empty list */
- }
- PyTuple_SET_ITEM(item, 1, pyrna_struct_CreatePyObject(&itemptr));
+ RNA_property_collection_begin(&self->ptr, self->prop, &iter);
+ for(; iter.valid; RNA_property_collection_next(&iter)) {
+ if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) {
+ nameptr= RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name));
+ /* add to python list */
+ item = Py_BuildValue("(NN)", PyUnicode_FromString( nameptr ), pyrna_struct_CreatePyObject(&iter.ptr));
PyList_Append(ret, item);
Py_DECREF(item);
+ /* done */
- i++;
+ if ((char *)&name != nameptr)
+ MEM_freeN(nameptr);
}
}
- RNA_PROP_END;
+ RNA_property_collection_end(&iter);
}
return ret;
}
-static PyObject *pyrna_prop_values(BPy_PropertyRNA *self)
+PyObject *pyrna_prop_values(BPy_PropertyRNA *self)
{
PyObject *ret;
-
if (RNA_property_type(self->prop) != PROP_COLLECTION) {
PyErr_SetString( PyExc_TypeError, "values() is only valid for collection types" );
ret = NULL;
} else {
PyObject *item;
+ CollectionPropertyIterator iter;
+ PropertyRNA *nameprop;
+
ret = PyList_New(0);
- RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) {
- item = pyrna_struct_CreatePyObject(&itemptr);
- PyList_Append(ret, item);
- Py_DECREF(item);
- }
- RNA_PROP_END;
- }
-
- return ret;
-}
-
-static PyObject *pyrna_prop_get(BPy_PropertyRNA *self, PyObject *args)
-{
- PointerRNA newptr;
-
- char *key;
- PyObject* def = Py_None;
-
- if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
- return NULL;
-
- if(RNA_property_collection_lookup_string(&self->ptr, self->prop, key, &newptr))
- return pyrna_struct_CreatePyObject(&newptr);
-
- Py_INCREF(def);
- return def;
-}
-
-
-#if (PY_VERSION_HEX >= 0x03000000) /* foreach needs py3 */
-static void foreach_attr_type( BPy_PropertyRNA *self, char *attr,
- /* values to assign */
- RawPropertyType *raw_type, int *attr_tot, int *attr_signed )
-{
- PropertyRNA *prop;
- *raw_type= -1;
- *attr_tot= 0;
- *attr_signed= 0;
-
- RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) {
- prop = RNA_struct_find_property(&itemptr, attr);
- *raw_type= RNA_property_raw_type(prop);
- *attr_tot = RNA_property_array_length(prop);
- *attr_signed= (RNA_property_subtype(prop)==PROP_UNSIGNED) ? 0:1;
- break;
- }
- RNA_PROP_END;
-}
-
-/* pyrna_prop_foreach_get/set both use this */
-static int foreach_parse_args(
- BPy_PropertyRNA *self, PyObject *args,
-
- /*values to assign */
- char **attr, PyObject **seq, int *tot, int *size, RawPropertyType *raw_type, int *attr_tot, int *attr_signed)
-{
-#if 0
- int array_tot;
- int target_tot;
-#endif
-
- *size= *raw_type= *attr_tot= *attr_signed= 0;
-
- if(!PyArg_ParseTuple(args, "sO", attr, seq) || (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq))) {
- PyErr_SetString( PyExc_TypeError, "foreach_get(attr, sequence) expects a string and a sequence" );
- return -1;
- }
-
- *tot= PySequence_Length(*seq); // TODO - buffer may not be a sequence! array.array() is tho.
-
- if(*tot>0) {
- foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed);
- *size= RNA_raw_type_sizeof(*raw_type);
-
-#if 0 // works fine but not strictly needed, we could allow RNA_property_collection_raw_* to do the checks
- if((*attr_tot) < 1)
- *attr_tot= 1;
-
- if (RNA_property_type(self->prop) == PROP_COLLECTION)
- array_tot = RNA_property_collection_length(&self->ptr, self->prop);
- else
- array_tot = RNA_property_array_length(self->prop);
-
-
- target_tot= array_tot * (*attr_tot);
-
- /* rna_access.c - rna_raw_access(...) uses this same method */
- if(target_tot != (*tot)) {
- PyErr_Format( PyExc_TypeError, "foreach_get(attr, sequence) sequence length mismatch given %d, needed %d", *tot, target_tot);
- return -1;
- }
-#endif
- }
-
- return 0;
-}
-
-static int foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, const char *format)
-{
- char f = format ? *format:'B'; /* B is assumed when not set */
-
- switch(raw_type) {
- case PROP_RAW_CHAR:
- if (attr_signed) return (f=='b') ? 1:0;
- else return (f=='B') ? 1:0;
- case PROP_RAW_SHORT:
- if (attr_signed) return (f=='h') ? 1:0;
- else return (f=='H') ? 1:0;
- case PROP_RAW_INT:
- if (attr_signed) return (f=='i') ? 1:0;
- else return (f=='I') ? 1:0;
- case PROP_RAW_FLOAT:
- return (f=='f') ? 1:0;
- case PROP_RAW_DOUBLE:
- return (f=='d') ? 1:0;
- }
-
- return 0;
-}
-
-static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
-{
- PyObject *item;
- int i=0, ok, buffer_is_compat;
- void *array= NULL;
-
- /* get/set both take the same args currently */
- char *attr;
- PyObject *seq;
- int tot, size, attr_tot, attr_signed;
- RawPropertyType raw_type;
-
- if(foreach_parse_args(self, args, &attr, &seq, &tot, &size, &raw_type, &attr_tot, &attr_signed) < 0)
- return NULL;
-
- if(tot==0)
- Py_RETURN_NONE;
-
-
-
- if(set) { /* get the array from python */
- buffer_is_compat = 0;
- if(PyObject_CheckBuffer(seq)) {
- Py_buffer buf;
- PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT);
-
- /* check if the buffer matches */
-
- buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format);
-
- if(buffer_is_compat) {
- ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot);
- }
-
- PyBuffer_Release(&buf);
- }
-
- /* could not use the buffer, fallback to sequence */
- if(!buffer_is_compat) {
- array= PyMem_Malloc(size * tot);
-
- for( ; i<tot; i++) {
- item= PySequence_GetItem(seq, i);
- switch(raw_type) {
- case PROP_RAW_CHAR:
- ((char *)array)[i]= (char)PyLong_AsSsize_t(item);
- break;
- case PROP_RAW_SHORT:
- ((short *)array)[i]= (short)PyLong_AsSsize_t(item);
- break;
- case PROP_RAW_INT:
- ((int *)array)[i]= (int)PyLong_AsSsize_t(item);
- break;
- case PROP_RAW_FLOAT:
- ((float *)array)[i]= (float)PyFloat_AsDouble(item);
- break;
- case PROP_RAW_DOUBLE:
- ((double *)array)[i]= (double)PyFloat_AsDouble(item);
- break;
- }
-
- Py_DECREF(item);
- }
-
- ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, array, raw_type, tot);
- }
- }
- else {
- buffer_is_compat = 0;
- if(PyObject_CheckBuffer(seq)) {
- Py_buffer buf;
- PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT);
-
- /* check if the buffer matches, TODO - signed/unsigned types */
-
- buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format);
-
- if(buffer_is_compat) {
- ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot);
- }
-
- PyBuffer_Release(&buf);
- }
-
- /* could not use the buffer, fallback to sequence */
- if(!buffer_is_compat) {
- array= PyMem_Malloc(size * tot);
-
- ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, array, raw_type, tot);
-
- if(!ok) i= tot; /* skip the loop */
-
- for( ; i<tot; i++) {
-
- switch(raw_type) {
- case PROP_RAW_CHAR:
- item= PyLong_FromSsize_t( (Py_ssize_t) ((char *)array)[i] );
- break;
- case PROP_RAW_SHORT:
- item= PyLong_FromSsize_t( (Py_ssize_t) ((short *)array)[i] );
- break;
- case PROP_RAW_INT:
- item= PyLong_FromSsize_t( (Py_ssize_t) ((int *)array)[i] );
- break;
- case PROP_RAW_FLOAT:
- item= PyFloat_FromDouble( (double) ((float *)array)[i] );
- break;
- case PROP_RAW_DOUBLE:
- item= PyFloat_FromDouble( (double) ((double *)array)[i] );
- break;
- }
-
- PySequence_SetItem(seq, i, item);
+ RNA_property_collection_begin(&self->ptr, self->prop, &iter);
+ for(; iter.valid; RNA_property_collection_next(&iter)) {
+ if(iter.ptr.data && (nameprop = RNA_struct_name_property(iter.ptr.type))) {
+ item = pyrna_struct_CreatePyObject(&iter.ptr);
+ PyList_Append(ret, item);
Py_DECREF(item);
}
}
+ RNA_property_collection_end(&iter);
}
-
- if(PyErr_Occurred()) {
- /* Maybe we could make our own error */
- PyErr_Print();
- PyErr_SetString(PyExc_SystemError, "could not access the py sequence");
- return NULL;
- }
- if (!ok) {
- PyErr_SetString(PyExc_SystemError, "internal error setting the array");
- return NULL;
- }
-
- if(array)
- PyMem_Free(array);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *pyrna_prop_foreach_get(BPy_PropertyRNA *self, PyObject *args)
-{
- return foreach_getset(self, args, 0);
-}
-
-static PyObject *pyrna_prop_foreach_set(BPy_PropertyRNA *self, PyObject *args)
-{
- return foreach_getset(self, args, 1);
+
+ return ret;
}
-#endif /* #if (PY_VERSION_HEX >= 0x03000000) */
/* A bit of a kludge, make a list out of a collection or array,
* then return the lists iter function, not especially fast but convenient for now */
@@ -1721,26 +1070,14 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self)
}
static struct PyMethodDef pyrna_struct_methods[] = {
-
- /* maybe this become and ID function */
- {"keyframe_insert", (PyCFunction)pyrna_struct_keyframe_insert, METH_VARARGS, NULL},
-
- {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL},
+ {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, ""},
{NULL, NULL, 0, NULL}
};
static struct PyMethodDef pyrna_prop_methods[] = {
- {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, NULL},
- {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS,NULL},
- {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, NULL},
-
- {"get", (PyCFunction)pyrna_prop_get, METH_VARARGS, NULL},
-
-#if (PY_VERSION_HEX >= 0x03000000)
- /* array accessor function */
- {"foreach_get", (PyCFunction)pyrna_prop_foreach_get, METH_VARARGS, NULL},
- {"foreach_set", (PyCFunction)pyrna_prop_foreach_set, METH_VARARGS, NULL},
-#endif
+ {"keys", (PyCFunction)pyrna_prop_keys, METH_NOARGS, ""},
+ {"items", (PyCFunction)pyrna_prop_items, METH_NOARGS, ""},
+ {"values", (PyCFunction)pyrna_prop_values, METH_NOARGS, ""},
{NULL, NULL, 0, NULL}
};
@@ -1834,17 +1171,11 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
const char *identifier;
int val = *(int*)data;
- if (RNA_property_enum_identifier(BPy_GetContext(), ptr, prop, val, &identifier)) {
+ if (RNA_property_enum_identifier(ptr, prop, val, &identifier)) {
ret = PyUnicode_FromString( identifier );
} else {
- /* prefer not fail silently incase of api errors, maybe disable it later */
- char error_str[128];
- sprintf(error_str, "RNA Warning: Current value \"%d\" matches no enum", val);
- PyErr_Warn(PyExc_RuntimeWarning, error_str);
-
- ret = PyUnicode_FromString( "" );
- /*PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val);
- ret = NULL;*/
+ PyErr_Format(PyExc_AttributeError, "RNA Error: Current value \"%d\" matches no enum", val);
+ ret = NULL;
}
break;
@@ -1853,9 +1184,8 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
{
PointerRNA newptr;
StructRNA *type= RNA_property_pointer_type(ptr, prop);
- int flag = RNA_property_flag(prop);
- if(flag & PROP_RNAPTR) {
+ if(type == &RNA_AnyType) {
/* in this case we get the full ptr */
newptr= *(PointerRNA*)data;
}
@@ -1873,21 +1203,10 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
break;
}
case PROP_COLLECTION:
- {
- ListBase *lb= (ListBase*)data;
- CollectionPointerLink *link;
- PyObject *linkptr;
-
- ret = PyList_New(0);
-
- for(link=lb->first; link; link=link->next) {
- linkptr= pyrna_struct_CreatePyObject(&link->ptr);
- PyList_Append(ret, linkptr);
- Py_DECREF(linkptr);
- }
-
+ /* XXX not supported yet
+ * ret = pyrna_prop_CreatePyObject(ptr, prop); */
+ ret = NULL;
break;
- }
default:
PyErr_Format(PyExc_AttributeError, "RNA Error: unknown type \"%d\" (pyrna_param_to_py)", type);
ret = NULL;
@@ -1946,7 +1265,7 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw)
tid= RNA_struct_identifier(self_ptr->type);
fid= RNA_function_identifier(self_func);
- PyErr_Format(PyExc_AttributeError, "%.200s.%.200s(): required parameter \"%.200s\" not specified", tid, fid, pid);
+ PyErr_Format(PyExc_AttributeError, "%s.%s(): required parameter \"%s\" not specified", tid, fid, pid);
err= -1;
break;
}
@@ -1963,19 +1282,11 @@ static PyObject * pyrna_func_call(PyObject * self, PyObject *args, PyObject *kw)
ret= NULL;
if (err==0) {
/* call function */
- ReportList reports;
- bContext *C= BPy_GetContext();
-
- BKE_reports_init(&reports, RPT_STORE);
- RNA_function_call(C, &reports, self_ptr, self_func, parms);
-
- err= (BPy_reports_to_error(&reports))? -1: 0;
- BKE_reports_clear(&reports);
+ RNA_function_call(self_ptr, self_func, parms);
/* return value */
- if(err==0)
- if(pret)
- ret= pyrna_param_to_py(&funcptr, pret, retdata);
+ if(pret)
+ ret= pyrna_param_to_py(&funcptr, pret, retdata);
}
/* cleanup */
@@ -2064,7 +1375,7 @@ PyTypeObject pyrna_struct_Type = {
NULL, /* allocfunc tp_alloc; */
pyrna_struct_new, /* newfunc tp_new; */
/* Low-level free-memory routine */
- NULL, /* freefunc tp_free; */
+ NULL, //MEM_freeN, /* freefunc tp_free; */
/* For PyObject_IS_GC */
NULL, /* inquiry tp_is_gc; */
NULL, /* PyObject *tp_bases; */
@@ -2090,7 +1401,7 @@ PyTypeObject pyrna_prop_Type = {
sizeof( BPy_PropertyRNA ), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
- NULL, /* tp_dealloc */
+ NULL, /* tp_dealloc */
NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
@@ -2100,7 +1411,7 @@ PyTypeObject pyrna_prop_Type = {
/* Method suites for standard classes */
NULL, /* PyNumberMethods *tp_as_number; */
- &pyrna_prop_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
&pyrna_prop_as_mapping, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
@@ -2150,7 +1461,7 @@ PyTypeObject pyrna_prop_Type = {
NULL, /* allocfunc tp_alloc; */
pyrna_prop_new, /* newfunc tp_new; */
/* Low-level free-memory routine */
- NULL, /* freefunc tp_free; */
+ NULL, //MEM_freeN, /* freefunc tp_free; */
/* For PyObject_IS_GC */
NULL, /* inquiry tp_is_gc; */
NULL, /* PyObject *tp_bases; */
@@ -2185,52 +1496,43 @@ static void pyrna_subtype_set_rna(PyObject *newclass, StructRNA *srna)
/* done with rna instance */
}
-PyObject* pyrna_srna_Subtype(StructRNA *srna)
+PyObject* pyrna_struct_Subtype(PointerRNA *ptr)
{
PyObject *newclass = NULL;
+ PropertyRNA *nameprop;
- if (srna == NULL) {
+ if (ptr->type==NULL) {
newclass= NULL; /* Nothing to do */
- } else if ((newclass= RNA_struct_py_type_get(srna))) {
+ } else if ((newclass= RNA_struct_py_type_get(ptr->data))) {
Py_INCREF(newclass);
- } else {
- StructRNA *base;
-
+ } else if ((nameprop = RNA_struct_name_property(ptr->type))) {
/* for now, return the base RNA type rather then a real module */
- /* Assume RNA_struct_py_type_get(srna) was alredy checked */
+ /* Assume RNA_struct_py_type_get(ptr->data) was alredy checked */
/* subclass equivelents
- class myClass(myBase):
some='value' # or ...
- - myClass = type(name='myClass', bases=(myBase,), dict={'__module__':'bpy.types'})
+ - myClass = type(name='myClass', bases=(myBase,), dict={'some':'value'})
*/
- const char *descr= RNA_struct_ui_description(srna);
+ char name[256], *nameptr;
+ const char *descr= RNA_struct_ui_description(ptr->type);
PyObject *args = PyTuple_New(3);
PyObject *bases = PyTuple_New(1);
- PyObject *py_base= NULL;
PyObject *dict = PyDict_New();
PyObject *item;
-
+
+
+ nameptr= RNA_property_string_get_alloc(ptr, nameprop, name, sizeof(name));
// arg 1
//PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(tp_name));
- PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(RNA_struct_identifier(srna)));
+ PyTuple_SET_ITEM(args, 0, PyUnicode_FromString(nameptr));
// arg 2
- base= RNA_struct_base(srna);
- if(base && base != srna) {
- /*/printf("debug subtype %s %p\n", RNA_struct_identifier(srna), srna); */
- py_base= pyrna_srna_Subtype(base);
- }
-
- if(py_base==NULL) {
- py_base= (PyObject *)&pyrna_struct_Type;
- Py_INCREF(py_base);
- }
-
- PyTuple_SET_ITEM(bases, 0, py_base);
+ PyTuple_SET_ITEM(bases, 0, (PyObject *)&pyrna_struct_Type);
+ Py_INCREF(&pyrna_struct_Type);
PyTuple_SET_ITEM(args, 1, bases);
@@ -2241,13 +1543,6 @@ PyObject* pyrna_srna_Subtype(StructRNA *srna)
Py_DECREF(item);
}
- /* this isnt needed however its confusing if we get python script names in blender types,
- * because the __module__ is used when printing the class */
- item= PyUnicode_FromString("bpy.types"); /* just to know its an internal type */
- PyDict_SetItemString(dict, "__module__", item);
- Py_DECREF(item);
-
-
PyTuple_SET_ITEM(args, 2, dict); // fill with useful subclass things!
if (PyErr_Occurred()) {
@@ -2258,25 +1553,16 @@ PyObject* pyrna_srna_Subtype(StructRNA *srna)
newclass = PyObject_CallObject((PyObject *)&PyType_Type, args);
Py_DECREF(args);
- if (newclass) {
- pyrna_subtype_set_rna(newclass, srna);
- // PyObSpit("NewStructRNA Type: ", (PyObject *)newclass);
- }
- else {
- /* this should not happen */
- PyErr_Print();
- PyErr_Clear();
- }
+ if (newclass)
+ pyrna_subtype_set_rna(newclass, ptr->data);
+
+ if (name != nameptr)
+ MEM_freeN(nameptr);
}
return newclass;
}
-PyObject* pyrna_struct_Subtype(PointerRNA *ptr)
-{
- return pyrna_srna_Subtype((ptr->type == &RNA_Struct) ? ptr->data : ptr->type);
-}
-
/*-----------------------CreatePyObject---------------------------------*/
PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr )
{
@@ -2285,7 +1571,8 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr )
if (ptr->data==NULL && ptr->type==NULL) { /* Operator RNA has NULL data */
Py_RETURN_NONE;
}
- else {
+
+ if (ptr->type == &RNA_Struct) { /* always return a python subtype from rna struct types */
PyTypeObject *tp = (PyTypeObject *)pyrna_struct_Subtype(ptr);
if (tp) {
@@ -2293,10 +1580,13 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr )
}
else {
fprintf(stderr, "Could not make type\n");
- pyrna = ( BPy_StructRNA * ) PyObject_NEW( BPy_StructRNA, &pyrna_struct_Type );
+ pyrna = ( BPy_StructRNA * ) bpy_PyObject_New( BPy_StructRNA, &pyrna_struct_Type );
}
}
-
+ else {
+ pyrna = ( BPy_StructRNA * ) bpy_PyObject_New( BPy_StructRNA, &pyrna_struct_Type );
+ }
+
if( !pyrna ) {
PyErr_SetString( PyExc_MemoryError, "couldn't create BPy_StructRNA object" );
return NULL;
@@ -2304,9 +1594,6 @@ PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr )
pyrna->ptr= *ptr;
pyrna->freeptr= 0;
-
- // PyObSpit("NewStructRNA: ", (PyObject *)pyrna);
-
return ( PyObject * ) pyrna;
}
@@ -2314,7 +1601,7 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop )
{
BPy_PropertyRNA *pyrna;
- pyrna = ( BPy_PropertyRNA * ) PyObject_NEW( BPy_PropertyRNA, &pyrna_prop_Type );
+ pyrna = ( BPy_PropertyRNA * ) bpy_PyObject_New( BPy_PropertyRNA, &pyrna_prop_Type );
if( !pyrna ) {
PyErr_SetString( PyExc_MemoryError, "couldn't create BPy_rna object" );
@@ -2331,11 +1618,6 @@ PyObject *BPY_rna_module( void )
{
PointerRNA ptr;
-#ifdef USE_MATHUTILS // register mathutils callbacks, ok to run more then once.
- mathutils_rna_array_cb_index= Mathutils_RegisterCallback(&mathutils_rna_array_cb);
- mathutils_rna_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_rna_matrix_cb);
-#endif
-
/* This can't be set in the pytype struct because some compilers complain */
pyrna_prop_Type.tp_getattro = PyObject_GenericGetAttr;
pyrna_prop_Type.tp_setattro = PyObject_GenericSetAttr;
@@ -2382,12 +1664,12 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA * self, PyObject *pyna
if (RNA_property_collection_lookup_string(&self->ptr, self->prop, _PyUnicode_AsString(pyname), &newptr)) {
ret= pyrna_struct_Subtype(&newptr);
if (ret==NULL) {
- PyErr_Format(PyExc_SystemError, "bpy.types.%.200s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname));
+ PyErr_Format(PyExc_SystemError, "bpy.types.%s subtype could not be generated, this is a bug!", _PyUnicode_AsString(pyname));
}
return ret;
}
else { /* Override the error */
- PyErr_Format(PyExc_AttributeError, "bpy.types.%.200s not a valid RNA_Struct", _PyUnicode_AsString(pyname));
+ PyErr_Format(PyExc_AttributeError, "bpy.types.%s not a valid RNA_Struct", _PyUnicode_AsString(pyname));
return NULL;
}
}
@@ -2428,12 +1710,13 @@ PyObject *BPY_rna_types(void)
pyrna_basetype_Type.tp_getattro = ( getattrofunc )pyrna_basetype_getattro;
pyrna_basetype_Type.tp_flags = Py_TPFLAGS_DEFAULT;
pyrna_basetype_Type.tp_methods = pyrna_basetype_methods;
+ //pyrna_basetype_Type.tp_free = MEM_freeN;
if( PyType_Ready( &pyrna_basetype_Type ) < 0 )
return NULL;
}
- self= (BPy_BaseTypeRNA *)PyObject_NEW( BPy_BaseTypeRNA, &pyrna_basetype_Type );
+ self= (BPy_BaseTypeRNA *)bpy_PyObject_New( BPy_BaseTypeRNA, &pyrna_basetype_Type );
/* avoid doing this lookup for every getattr */
RNA_blender_rna_pointer_create(&self->ptr);
@@ -2442,44 +1725,7 @@ PyObject *BPY_rna_types(void)
return (PyObject *)self;
}
-static struct PyMethodDef props_methods[] = {
- {"FloatProperty", (PyCFunction)BPy_FloatProperty, METH_VARARGS|METH_KEYWORDS, ""},
- {"IntProperty", (PyCFunction)BPy_IntProperty, METH_VARARGS|METH_KEYWORDS, ""},
- {"BoolProperty", (PyCFunction)BPy_BoolProperty, METH_VARARGS|METH_KEYWORDS, ""},
- {"StringProperty", (PyCFunction)BPy_StringProperty, METH_VARARGS|METH_KEYWORDS, ""},
- {NULL, NULL, 0, NULL}
-};
-#if PY_VERSION_HEX >= 0x03000000
-static struct PyModuleDef props_module = {
- PyModuleDef_HEAD_INIT,
- "bpyprops",
- "",
- -1,/* multiple "initialization" just copies the module dict. */
- props_methods,
- NULL, NULL, NULL, NULL
-};
-#endif
-
-PyObject *BPY_rna_props( void )
-{
- PyObject *submodule, *mod;
-#if PY_VERSION_HEX >= 0x03000000
- submodule= PyModule_Create(&props_module);
-#else /* Py2.x */
- submodule= Py_InitModule3( "bpy.props", props_methods, "" );
-#endif
-
- mod = PyModule_New("props");
- PyModule_AddObject( submodule, "props", mod );
-
- /* INCREF since its its assumed that all these functions return the
- * module with a new ref like PyDict_New, since they are passed to
- * PyModule_AddObject which steals a ref */
- Py_INCREF(submodule);
-
- return submodule;
-}
/* Orphan functions, not sure where they should go */
@@ -2499,7 +1745,7 @@ PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- if (self && PyCObject_Check(self)) {
+ if (self) {
StructRNA *srna = PyCObject_AsVoidPtr(self);
RNA_def_float(srna, id, def, min, max, name, description, soft_min, soft_max);
Py_RETURN_NONE;
@@ -2526,7 +1772,7 @@ PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- if (self && PyCObject_Check(self)) {
+ if (self) {
StructRNA *srna = PyCObject_AsVoidPtr(self);
RNA_def_int(srna, id, def, min, max, name, description, soft_min, soft_max);
Py_RETURN_NONE;
@@ -2545,7 +1791,7 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
char *id, *name="", *description="";
int def=0;
- if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:BoolProperty", kwlist, &id, &name, &description, &def))
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssi:IntProperty", kwlist, &id, &name, &description, &def))
return NULL;
if (PyTuple_Size(args) > 0) {
@@ -2553,40 +1799,13 @@ PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
return NULL;
}
- if (self && PyCObject_Check(self)) {
+ if (self) {
StructRNA *srna = PyCObject_AsVoidPtr(self);
RNA_def_boolean(srna, id, def, name, description);
Py_RETURN_NONE;
} else {
PyObject *ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_BoolProperty, NULL));
- PyTuple_SET_ITEM(ret, 1, kw);
- Py_INCREF(kw);
- return ret;
- }
-}
-
-PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
-{
- static char *kwlist[] = {"attr", "name", "description", "maxlen", "default", NULL};
- char *id, *name="", *description="", *def="";
- int maxlen=0;
-
- if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ssis:StringProperty", kwlist, &id, &name, &description, &maxlen, &def))
- return NULL;
-
- if (PyTuple_Size(args) > 0) {
- PyErr_SetString(PyExc_ValueError, "all args must be keywors"); // TODO - py3 can enforce this.
- return NULL;
- }
-
- if (self && PyCObject_Check(self)) {
- StructRNA *srna = PyCObject_AsVoidPtr(self);
- RNA_def_string(srna, id, def, maxlen, name, description);
- Py_RETURN_NONE;
- } else {
- PyObject *ret = PyTuple_New(2);
- PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_StringProperty, NULL));
+ PyTuple_SET_ITEM(ret, 0, PyCObject_FromVoidPtr((void *)BPy_IntProperty, NULL));
PyTuple_SET_ITEM(ret, 1, kw);
Py_INCREF(kw);
return ret;
@@ -2629,7 +1848,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
if (base_class) {
if (!PyObject_IsSubclass(py_class, base_class)) {
PyObject *name= PyObject_GetAttrString(base_class, "__name__");
- PyErr_Format( PyExc_AttributeError, "expected %.200s subclass of class \"%.200s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>");
+ PyErr_Format( PyExc_AttributeError, "expected %s subclass of class \"%s\"", class_type, name ? _PyUnicode_AsString(name):"<UNKNOWN>");
Py_XDECREF(name);
return -1;
}
@@ -2652,7 +1871,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
if (item==NULL) {
if ((flag & FUNC_REGISTER_OPTIONAL)==0) {
- PyErr_Format( PyExc_AttributeError, "expected %.200s class to have an \"%.200s\" attribute", class_type, RNA_function_identifier(func));
+ PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, RNA_function_identifier(func));
return -1;
}
@@ -2667,7 +1886,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
fitem= item; /* py 3.x */
if (PyFunction_Check(fitem)==0) {
- PyErr_Format( PyExc_AttributeError, "expected %.200s class \"%.200s\" attribute to be a function", class_type, RNA_function_identifier(func));
+ PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" attribute to be a function", class_type, RNA_function_identifier(func));
return -1;
}
@@ -2679,7 +1898,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
Py_DECREF(py_arg_count);
if (arg_count != func_arg_count) {
- PyErr_Format( PyExc_AttributeError, "expected %.200s class \"%.200s\" function to have %d args", class_type, RNA_function_identifier(func), func_arg_count);
+ PyErr_Format( PyExc_AttributeError, "expected %s class \"%s\" function to have %d args", class_type, RNA_function_identifier(func), func_arg_count);
return -1;
}
}
@@ -2711,7 +1930,7 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
}
if (item==NULL && (flag & PROP_REGISTER_OPTIONAL)==0) {
- PyErr_Format( PyExc_AttributeError, "expected %.200s class to have an \"%.200s\" attribute", class_type, identifier);
+ PyErr_Format( PyExc_AttributeError, "expected %s class to have an \"%s\" attribute", class_type, identifier);
return -1;
}
@@ -2795,12 +2014,12 @@ static int bpy_class_call(PointerRNA *ptr, FunctionRNA *func, ParameterList *par
}
else {
Py_DECREF(py_class_instance);
- PyErr_Format(PyExc_AttributeError, "could not find function %.200s in %.200s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type));
+ PyErr_Format(PyExc_AttributeError, "could not find function %s in %s to execute callback.", RNA_function_identifier(func), RNA_struct_identifier(ptr->type));
err= -1;
}
}
else {
- PyErr_Format(PyExc_AttributeError, "could not create instance of %.200s to call callback function %.200s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func));
+ PyErr_Format(PyExc_AttributeError, "could not create instance of %s to call callback function %s.", RNA_struct_identifier(ptr->type), RNA_function_identifier(func));
err= -1;
}
@@ -2875,7 +2094,7 @@ PyObject *pyrna_basetype_register(PyObject *self, PyObject *args)
C= BPy_GetContext();
/* call the register callback */
- BKE_reports_init(&reports, RPT_STORE);
+ BKE_reports_init(&reports, RPT_PRINT);
srna= reg(C, &reports, py_class, bpy_class_validate, bpy_class_call, bpy_class_free);
if(!srna) {
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index d2f01b06336..a2a3015912b 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -63,7 +63,6 @@ typedef struct {
PyObject *BPY_rna_module( void );
/*PyObject *BPY_rna_doc( void );*/
PyObject *BPY_rna_types( void );
-PyObject *BPY_rna_props( void );
PyObject *pyrna_struct_CreatePyObject( PointerRNA *ptr );
PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop );
@@ -77,7 +76,6 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop);
PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw);
PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw);
-PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw);
/* function for registering types */
PyObject *pyrna_basetype_register(PyObject *self, PyObject *args);
diff --git a/source/blender/python/intern/bpy_ui.c b/source/blender/python/intern/bpy_ui.c
index 088fe436c69..c15315ca350 100644
--- a/source/blender/python/intern/bpy_ui.c
+++ b/source/blender/python/intern/bpy_ui.c
@@ -373,7 +373,7 @@ static struct PyMethodDef ui_methods[] = {
#if PY_VERSION_HEX >= 0x03000000
static struct PyModuleDef ui_module = {
PyModuleDef_HEAD_INIT,
- "bpy.ui",
+ "bpyui",
"",
-1,/* multiple "initialization" just copies the module dict. */
ui_methods,
diff --git a/source/blender/python/intern/bpy_util.c b/source/blender/python/intern/bpy_util.c
index b451923e780..c447e7de982 100644
--- a/source/blender/python/intern/bpy_util.c
+++ b/source/blender/python/intern/bpy_util.c
@@ -81,7 +81,6 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag)
char *cstring;
PyObject *item;
BPY_flag_def *fd;
- *flag = 0;
if (PySequence_Check(seq)) {
i= PySequence_Length(seq);
@@ -109,9 +108,6 @@ int BPY_flag_from_seq(BPY_flag_def *flagdef, PyObject *seq, int *flag)
error_val= 1;
}
- if (*flag == 0)
- error_val = 1;
-
if (error_val) {
char *buf = bpy_flag_error_str(flagdef);
PyErr_SetString(PyExc_AttributeError, buf);
@@ -171,13 +167,7 @@ void PyObSpit(char *name, PyObject *var) {
else {
PyObject_Print(var, stderr, 0);
fprintf(stderr, " ref:%d ", var->ob_refcnt);
- fprintf(stderr, " ptr:%p", (void *)var);
-
- fprintf(stderr, " type:");
- if(Py_TYPE(var))
- fprintf(stderr, "%s", Py_TYPE(var)->tp_name);
- else
- fprintf(stderr, "<NIL>");
+ fprintf(stderr, " ptr:%ld", (long)var);
}
fprintf(stderr, "\n");
}
@@ -339,81 +329,6 @@ int BPY_class_validate(const char *class_type, PyObject *class, PyObject *base_c
return 0;
}
-
-
-/* returns the exception string as a new PyUnicode object, depends on external StringIO module */
-PyObject *BPY_exception_buffer(void)
-{
- PyObject *stdout_backup = PySys_GetObject("stdout"); /* borrowed */
- PyObject *stderr_backup = PySys_GetObject("stderr"); /* borrowed */
- PyObject *string_io = NULL;
- PyObject *string_io_buf = NULL;
- PyObject *string_io_mod= NULL;
- PyObject *string_io_getvalue= NULL;
-
- PyObject *error_type, *error_value, *error_traceback;
-
- if (!PyErr_Occurred())
- return NULL;
-
- PyErr_Fetch(&error_type, &error_value, &error_traceback);
-
- PyErr_Clear();
-
- /* import StringIO / io
- * string_io = StringIO.StringIO()
- */
-
-#if PY_VERSION_HEX < 0x03000000
- if(! (string_io_mod= PyImport_ImportModule("StringIO")) ) {
-#else
- if(! (string_io_mod= PyImport_ImportModule("io")) ) {
-#endif
- goto error_cleanup;
- } else if (! (string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) {
- goto error_cleanup;
- } else if (! (string_io_getvalue= PyObject_GetAttrString(string_io, "getvalue"))) {
- goto error_cleanup;
- }
-
- Py_INCREF(stdout_backup); // since these were borrowed we dont want them freed when replaced.
- Py_INCREF(stderr_backup);
-
- PySys_SetObject("stdout", string_io); // both of these are free'd when restoring
- PySys_SetObject("stderr", string_io);
-
- PyErr_Restore(error_type, error_value, error_traceback);
- PyErr_Print(); /* print the error */
- PyErr_Clear();
-
- string_io_buf = PyObject_CallObject(string_io_getvalue, NULL);
-
- PySys_SetObject("stdout", stdout_backup);
- PySys_SetObject("stderr", stderr_backup);
-
- Py_DECREF(stdout_backup); /* now sys owns the ref again */
- Py_DECREF(stderr_backup);
-
- Py_DECREF(string_io_mod);
- Py_DECREF(string_io_getvalue);
- Py_DECREF(string_io); /* free the original reference */
-
- PyErr_Clear();
- return string_io_buf;
-
-
-error_cleanup:
- /* could not import the module so print the error and close */
- Py_XDECREF(string_io_mod);
- Py_XDECREF(string_io);
-
- PyErr_Restore(error_type, error_value, error_traceback);
- PyErr_Print(); /* print the error */
- PyErr_Clear();
-
- return NULL;
-}
-
char *BPy_enum_as_string(EnumPropertyItem *item)
{
DynStr *dynstr= BLI_dynstr_new();
@@ -421,8 +336,7 @@ char *BPy_enum_as_string(EnumPropertyItem *item)
char *cstring;
for (e= item; item->identifier; item++) {
- if(item->identifier[0])
- BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier);
+ BLI_dynstr_appendf(dynstr, (e==item)?"'%s'":", '%s'", item->identifier);
}
cstring = BLI_dynstr_get_cstring(dynstr);
@@ -444,33 +358,3 @@ int BPy_reports_to_error(ReportList *reports)
return (report_str != NULL);
}
-
-int BPy_errors_to_report(ReportList *reports)
-{
- PyObject *pystring;
- char *cstring;
-
- if (!PyErr_Occurred())
- return 1;
-
- /* less hassle if we allow NULL */
- if(reports==NULL) {
- PyErr_Print();
- PyErr_Clear();
- return 1;
- }
-
- pystring= BPY_exception_buffer();
-
- if(pystring==NULL) {
- BKE_report(reports, RPT_ERROR, "unknown py-exception, could not convert");
- return 0;
- }
-
- cstring= _PyUnicode_AsString(pystring);
-
- BKE_report(reports, RPT_ERROR, cstring);
- fprintf(stderr, "%s\n", cstring); // not exactly needed. just for testing
- Py_DECREF(pystring);
- return 1;
-}
diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h
index 6429af67eb0..49f48802249 100644
--- a/source/blender/python/intern/bpy_util.h
+++ b/source/blender/python/intern/bpy_util.h
@@ -47,8 +47,6 @@ void PyObSpit(char *name, PyObject *var);
void PyLineSpit(void);
void BPY_getFileAndNum(char **filename, int *lineno);
-PyObject *BPY_exception_buffer(void);
-
/* own python like utility function */
PyObject *PyObject_GetAttrStringArgs(PyObject *o, Py_ssize_t n, ...);
@@ -75,7 +73,6 @@ char *BPy_enum_as_string(struct EnumPropertyItem *item);
/* error reporting */
int BPy_reports_to_error(struct ReportList *reports);
-int BPy_errors_to_report(struct ReportList *reports);
/* TODO - find a better solution! */
struct bContext *BPy_GetContext(void);
diff --git a/source/blender/readblenfile/intern/BLO_readblenfile.c b/source/blender/readblenfile/intern/BLO_readblenfile.c
index 40a991ad702..496ac529406 100644
--- a/source/blender/readblenfile/intern/BLO_readblenfile.c
+++ b/source/blender/readblenfile/intern/BLO_readblenfile.c
@@ -170,4 +170,3 @@ cleanup:
return bfd;
}
-
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 65942a14be9..a047dc63829 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1439,7 +1439,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;
@@ -1456,7 +1456,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;
@@ -1671,8 +1671,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);
if(origindex) {
for(a=0; a<totface; a++)
strandbuf->totbound= MAX2(strandbuf->totbound, origindex[a]);
@@ -1732,7 +1732,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);
@@ -1807,7 +1807,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);
@@ -2889,10 +2889,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;
@@ -3068,7 +3068,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;
@@ -3129,8 +3129,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/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 130cda9f107..f67826a9806 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -377,25 +377,6 @@ void renderspothalo(ShadeInput *shi, float *col, float alpha)
/* ---------------- shaders ----------------------- */
-static double Normalize_d(double *n)
-{
- double d;
-
- d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
-
- if(d>0.00000000000000001) {
- d= sqrt(d);
-
- n[0]/=d;
- n[1]/=d;
- n[2]/=d;
- } else {
- n[0]=n[1]=n[2]= 0.0;
- d= 0.0;
- }
- return d;
-}
-
/* mix of 'real' fresnel and allowing control. grad defines blending gradient */
float fresnel_fac(float *view, float *vn, float grad, float fac)
{
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
index 3c8c1640b75..fc52f0fc9f4 100644
--- a/source/blender/render/intern/source/strand.c
+++ b/source/blender/render/intern/source/strand.c
@@ -943,7 +943,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
@@ -975,7 +975,7 @@ StrandSurface *cache_strand_surface(Render *re, ObjectRen *obr, DerivedMesh *dm,
Mat4MulVecfl(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;