Integration of the Google Summer of Code Modifier Stack Upgrade project. The
authorBen Batt <benbatt@gmail.com>
Mon, 28 Aug 2006 01:12:36 +0000 (01:12 +0000)
committerBen Batt <benbatt@gmail.com>
Mon, 28 Aug 2006 01:12:36 +0000 (01:12 +0000)
main features are:
* Modifiers can now be in any order in the modifier stack
* DerivedMesh now has a standard framework for custom element data to be passed
  through the stack with mesh data (being copied and interpolated as
  appropriate), so modifiers can access whatever data they need
* The modifier stack code has been refactored and a number of bugs have been
  removed
* The EdgeSplit modifier has been added:
  http://mediawiki.blender.org/index.php/BlenderDev/EdgeSplitModifier
* The DerivedMesh modifier has been added:
  http://mediawiki.blender.org/index.php/BlenderDev/DisplaceModifier
* The UVProject modifier has been added:
  http://mediawiki.blender.org/index.php/BlenderDev/UVProjectModifier

For more info, see:
http://mediawiki.blender.org/index.php/User:Artificer/ModifierStackUpgrade
(currently undergoing reorganisation)

30 files changed:
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_booleanops.h
source/blender/blenkernel/BKE_cdderivedmesh.h [new file with mode: 0644]
source/blender/blenkernel/BKE_customdata.h [new file with mode: 0644]
source/blender/blenkernel/BKE_lattice.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/BKE_subsurf.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/cdderivedmesh.c [new file with mode: 0644]
source/blender/blenkernel/intern/customdata.c [new file with mode: 0644]
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenlib/BLI_editVert.h
source/blender/blenlib/BLI_linklist.h
source/blender/blenlib/intern/BLI_linklist.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/python/api2_2x/Mesh.c
source/blender/render/intern/source/texture.c
source/blender/src/booleanops.c
source/blender/src/buttons_editing.c
source/blender/src/drawobject.c
source/blender/src/editmesh.c
source/blender/src/editmesh_mods.c
source/blender/src/editobject.c
source/gameengine/Converter/BL_SkinDeformer.cpp

index 8b2882ca4e6bed5f29d24976159c095d8c5c70c4..fe371c325292da27a7f47cdff8c8370a85a665ef 100644 (file)
  *    conversion to DLM.
  */
 
+#include "BKE_customdata.h"
+
 struct MVert;
+struct MEdge;
+struct MFace;
 struct TFace;
 struct Object;
+struct Mesh;
 struct EditMesh;
 struct DispListMesh;
 struct ModifierData;
 
+/* 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
+
 typedef struct DerivedMesh DerivedMesh;
 struct DerivedMesh {
+       /* custom data for verts, edges & faces */
+       CustomData vertData, edgeData, faceData;
+
        /* Misc. Queries */
 
-               /* Also called in Editmode */
+       /* Also called in Editmode */
        int (*getNumVerts)(DerivedMesh *dm);
-               /* Also called in Editmode */
+       /* Also called in Editmode */
        int (*getNumFaces)(DerivedMesh *dm);
 
-               /* Iterate over each mapped vertex in the derived mesh, calling the
-                * given function with the original vert and the mapped vert's new
-                * coordinate and normal. For historical reasons the normal can be
-                * passed as a float or short array, only one should be non-NULL.
-                */
-       void (*foreachMappedVert)(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData);
-
-               /* Iterate over each mapped vertex in the derived mesh, calling the
-                * given function with the original vert and the mapped edge's new
-                * coordinates.
-                */
-       void (*foreachMappedEdge)(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData);
-
-               /* Iterate over each mapped face in the derived mesh, calling the
-                * given function with the original face and the mapped face's (or
-                * faces') center and normal.
-                */
-       void (*foreachMappedFaceCenter)(DerivedMesh *dm, void (*func)(void *userData, int index, float *cent, float *no), void *userData);
-
-               /* Convert to new DispListMesh, should be free'd by caller.
-                *
-                * If allowShared is true then the caller is committing to not free'ng
-                * the DerivedMesh before free'ng the DispListMesh, which means that
-                * certain fields of the returned DispListMesh can safely be share with
-                * the DerivedMesh's internal data.
-                */
-       struct DispListMesh* (*convertToDispListMesh)(DerivedMesh *dm, int allowShared);
-
-               /* Iterate over all vertex points, calling DO_MINMAX with given args.
-                *
-                * Also called in Editmode
-                */
+       int (*getNumEdges)(DerivedMesh *dm);
+
+       /* copy a single vert/edge/face from the derived mesh into
+        * *{vert/edge/face}_r
+        */
+       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);
+
+       /* copy all verts/edges/faces from the derived mesh into
+        * *{vert/edge/face}_r (must point to a buffer large enough)
+        */
+       void (*getVertArray)(DerivedMesh *dm, struct MVert *vert_r);
+       void (*getEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r);
+       void (*getFaceArray)(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);
+
+       /* 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
+        * a copy)
+        */
+       void *(*getVertData)(DerivedMesh *dm, int index, int type);
+       void *(*getEdgeData)(DerivedMesh *dm, int index, int type);
+       void *(*getFaceData)(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
+        * a copy)
+        */
+       void *(*getVertDataArray)(DerivedMesh *dm, int type);
+       void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
+       void *(*getFaceDataArray)(DerivedMesh *dm, int type);
+
+       /* Iterate over each mapped vertex in the derived mesh, calling the
+        * given function with the original vert and the mapped vert's new
+        * coordinate and normal. For historical reasons the normal can be
+        * passed as a float or short array, only one should be non-NULL.
+        */
+       void (*foreachMappedVert)(
+                             DerivedMesh *dm,
+                             void (*func)(void *userData, int index, float *co,
+                                          float *no_f, short *no_s),
+                             void *userData);
+
+       /* Iterate over each mapped edge in the derived mesh, calling the
+        * given function with the original edge and the mapped edge's new
+        * coordinates.
+        */
+       void (*foreachMappedEdge)(DerivedMesh *dm,
+                                 void (*func)(void *userData, int index,
+                                              float *v0co, float *v1co),
+                                 void *userData);
+
+       /* Iterate over each mapped face in the derived mesh, calling the
+        * given function with the original face and the mapped face's (or
+        * faces') center and normal.
+        */
+       void (*foreachMappedFaceCenter)(DerivedMesh *dm,
+                                       void (*func)(void *userData, int index,
+                                                    float *cent, float *no),
+                                       void *userData);
+
+       /* Convert to new DispListMesh, should be free'd by caller.
+        *
+        * If allowShared is true then the caller is committing to not free'ng
+        * the DerivedMesh before free'ng the DispListMesh, which means that
+        * certain fields of the returned DispListMesh can safely be share with
+        * the DerivedMesh's internal data.
+        */
+       struct DispListMesh* (*convertToDispListMesh)(DerivedMesh *dm,
+                                                     int allowShared);
+
+       /* Iterate over all vertex points, calling DO_MINMAX with given args.
+        *
+        * Also called in Editmode
+        */
        void (*getMinMax)(DerivedMesh *dm, float min_r[3], float max_r[3]);
 
        /* Direct Access Operations */
        /*  o Can be undefined */
        /*  o Must be defined for modifiers that only deform however */
-                       
-               /* Get vertex location, undefined if index is not valid */
+
+       /* Get vertex location, undefined if index is not valid */
        void (*getVertCo)(DerivedMesh *dm, int index, float co_r[3]);
 
-               /* Fill the array (of length .getNumVerts()) with all vertex locations  */
+       /* Fill the array (of length .getNumVerts()) with all vertex locations */
        void (*getVertCos)(DerivedMesh *dm, float (*cos_r)[3]);
 
-               /* Get vertex normal, undefined if index is not valid */
+       /* Get vertex normal, undefined if index is not valid */
        void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]);
 
        /* Drawing Operations */
 
-                       /* Draw all vertices as bgl points (no options) */
+       /* Draw all vertices as bgl points (no options) */
        void (*drawVerts)(DerivedMesh *dm);
 
-                       /* Draw edges in the UV mesh (if exists) */
+       /* Draw edges in the UV mesh (if exists) */
        void (*drawUVEdges)(DerivedMesh *dm);
 
-                       /* Draw all edges as lines (no options) 
-                        *
-                        * Also called for *final* editmode DerivedMeshes
-                        */
+       /* Draw all edges as lines (no options) 
+        *
+        * Also called for *final* editmode DerivedMeshes
+        */
        void (*drawEdges)(DerivedMesh *dm, int drawLooseEdges);
        
-                       /* Draw all loose edges (edges w/ no adjoining faces) */
+       /* Draw all loose edges (edges w/ no adjoining faces) */
        void (*drawLooseEdges)(DerivedMesh *dm);
 
-                       /* Draw all faces
-                        *  o Set face normal or vertex normal based on inherited face flag
-                        *  o Use inherited face material index to call setMaterial
-                        *  o Only if setMaterial returns true
-                        *
-                        * Also called for *final* editmode DerivedMeshes
-                        */
+       /* Draw all faces
+        *  o Set face normal or vertex normal based on inherited face flag
+        *  o Use inherited face material index to call setMaterial
+        *  o Only if setMaterial returns true
+        *
+        * Also called for *final* editmode DerivedMeshes
+        */
        void (*drawFacesSolid)(DerivedMesh *dm, int (*setMaterial)(int));
 
-                       /* Draw all faces
-                        *  o If useTwoSided, draw front and back using col arrays
-                        *  o col1,col2 are arrays of length numFace*4 of 4 component colors
-                        *    in ABGR format, and should be passed as per-face vertex color.
-                        */
-       void (*drawFacesColored)(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2);
-
-                       /* Draw all faces using TFace 
-                        *  o Drawing options too complicated to enumerate, look at code.
-                        */
-       void (*drawFacesTex)(DerivedMesh *dm, int (*setDrawOptions)(struct TFace *tface, int matnr));
-
-                       /* Draw mapped faces (no color, or texture)
-                        *  o Only if !setDrawOptions or setDrawOptions(userData, mapped-face-index, drawSmooth_r) returns true
-                        *
-                        * If drawSmooth is set to true then vertex normals should be set and glShadeModel
-                        * called with GL_SMOOTH. Otherwise the face normal should be set and glShadeModel
-                        * called with GL_FLAT.
-                        *
-                        * The setDrawOptions is allowed to not set drawSmooth (for example, when lighting
-                        * is disabled), in which case the implementation should draw as smooth shaded.
-                        */
-       void (*drawMappedFaces)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors);
-
-                       /* Draw mapped faces using TFace 
-                        *  o Drawing options too complicated to enumerate, look at code.
-                        */
-       void (*drawMappedFacesTex)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData);
-
-                       /* Draw mapped edges as lines
-                        *  o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge) returns true
-                        */
-       void (*drawMappedEdges)(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData);
-
-                       /* Draw mapped edges as lines with interpolation values
-                        *  o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t) returns true
-                        *
-                        * NOTE: This routine is optional!
-                        */
+       /* Draw all faces
+        *  o If useTwoSided, draw front and back using col arrays
+        *  o col1,col2 are arrays of length numFace*4 of 4 component colors
+        *    in ABGR format, and should be passed as per-face vertex color.
+        */
+       void (*drawFacesColored)(DerivedMesh *dm, int useTwoSided,
+                                unsigned char *col1, unsigned char *col2);
+
+       /* Draw all faces using TFace 
+        *  o Drawing options too complicated to enumerate, look at code.
+        */
+       void (*drawFacesTex)(DerivedMesh *dm,
+                            int (*setDrawOptions)(struct TFace *tface, int matnr));
+
+       /* Draw mapped faces (no color, or texture)
+        *  o Only if !setDrawOptions or
+        *    setDrawOptions(userData, mapped-face-index, drawSmooth_r)
+        *    returns true
+        *
+        * If drawSmooth is set to true then vertex normals should be set and
+        * glShadeModel called with GL_SMOOTH. Otherwise the face normal should
+        * be set and glShadeModel called with GL_FLAT.
+        *
+        * The setDrawOptions is allowed to not set drawSmooth (for example, when
+        * lighting is disabled), in which case the implementation should draw as
+        * smooth shaded.
+        */
+       void (*drawMappedFaces)(DerivedMesh *dm,
+                               int (*setDrawOptions)(void *userData, int index,
+                                                     int *drawSmooth_r),
+                               void *userData, int useColors);
+
+       /* Draw mapped faces using TFace 
+        *  o Drawing options too complicated to enumerate, look at code.
+        */
+       void (*drawMappedFacesTex)(DerivedMesh *dm,
+                                  int (*setDrawOptions)(void *userData,
+                                                        int index),
+                                  void *userData);
+
+       /* Draw mapped edges as lines
+        *  o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge)
+        *    returns true
+        */
+       void (*drawMappedEdges)(DerivedMesh *dm,
+                               int (*setDrawOptions)(void *userData, int index),
+                               void *userData);
+
+       /* Draw mapped edges as lines with interpolation values
+        *  o Only if !setDrawOptions or
+        *    setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t)
+        *    returns true
+        *
+        * NOTE: This routine is optional!
+        */
        void (*drawMappedEdgesInterp)(DerivedMesh *dm, 
-                                                                       int (*setDrawOptions)(void *userData, int index), 
-                                                                       void (*setDrawInterpOptions)(void *userData, int index, float t),
-                                                                       void *userData);
+                                     int (*setDrawOptions)(void *userData,
+                                                           int index), 
+                                     void (*setDrawInterpOptions)(void *userData,
+                                                                  int index,
+                                                                  float t),
+                                     void *userData);
 
        void (*release)(DerivedMesh *dm);
 };
 
+/* utility function to initialise a DerivedMesh's function pointers to
+ * the default implementation (for those functions which have a default)
+ */
+void DM_init_funcs(DerivedMesh *dm);
+
+/* utility function to initialise a DerivedMesh for the desired number
+ * 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);
+
+/* 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);
+
+/* utility function to release a DerivedMesh's layers
+ */
+void DM_release(DerivedMesh *dm);
+
+/* utility function to convert a DerivedMesh to a Mesh
+ */
+void DM_to_mesh(DerivedMesh *dm, struct Mesh *me);
+
+/* adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
+ * backed by an external data array
+ * if layer != NULL, it is used as the layer data array, otherwise new memory
+ * is allocated
+ * the layer data will be freed by dm->release unless
+ * (flag & LAYERFLAG_NOFREE) is true
+ */
+void DM_add_vert_layer(struct DerivedMesh *dm, int type, int flag,
+                       void *layer);
+void DM_add_edge_layer(struct DerivedMesh *dm, int type, int flag,
+                       void *layer);
+void DM_add_face_layer(struct DerivedMesh *dm, int type, int flag,
+                       void *layer);
+
+/* custom data access functions
+ * return pointer to data from first layer which matches type
+ * if they return NULL for valid indices, data doesn't exist
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
+void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
+void *DM_get_face_data(struct DerivedMesh *dm, int index, int type);
+
+/* custom data layer access functions
+ * return pointer to first data layer which matches type (a flat array)
+ * if they return NULL, data doesn't exist
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);
+
+/* custom data setting functions
+ * copy supplied data into first layer of type using layer's copy function
+ * (deep copy if appropriate)
+ */
+void DM_set_vert_data(struct DerivedMesh *dm, int index, int type, void *data);
+void DM_set_edge_data(struct DerivedMesh *dm, int index, int type, void *data);
+void DM_set_face_data(struct DerivedMesh *dm, int index, int type, void *data);
+
+/* custom data copy functions
+ * copy count elements from source_index in source to dest_index in dest
+ * these copy all layers for which the LAYERFLAG_NOCOPY flag is not set
+ */
+void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+                       int source_index, int dest_index, int count);
+void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+                       int source_index, int dest_index, int count);
+void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+                       int source_index, int dest_index, int count);
+
+/* custom data free functions
+ * free count elements, starting at index
+ * they free all layers for which the LAYERFLAG_NOFREE flag is not set
+ */
+void DM_free_vert_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_edge_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_face_data(struct DerivedMesh *dm, int index, int count);
+
+/* 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
+ */
+void DM_interp_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+                         int *src_indices, float *weights,
+                         int count, int dest_index);
+
+/* interpolates edge data from the edges indexed by src_indices in the
+ * source mesh using the given weights and stores the result in the edge indexed
+ * by dest_index in the dest mesh.
+ * if weights is NULL, all weights default to 1.
+ * if vert_weights is non-NULL, any per-vertex edge data is interpolated using
+ * vert_weights[i] multiplied by weights[i].
+ */
+typedef float EdgeVertWeight[SUB_ELEMS_EDGE][SUB_ELEMS_EDGE];
+void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+                         int *src_indices,
+                         float *weights, EdgeVertWeight *vert_weights,
+                         int count, int dest_index);
+
+/* interpolates face data from the faces indexed by src_indices in the
+ * source mesh using the given weights and stores the result in the face indexed
+ * by dest_index in the dest mesh.
+ * if weights is NULL, all weights default to 1.
+ * if vert_weights is non-NULL, any per-vertex face data is interpolated using
+ * 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,
+                         int *src_indices,
+                         float *weights, FaceVertWeight *vert_weights,
+                         int count, int dest_index);
+
     /* Simple function to get me->totvert amount of vertices/normals,
        correctly deformed and subsurfered. Needed especially when vertexgroups are involved.
        In use now by vertex/weigt paint and particles */
index f033dd7000328af84ffc5e6eec50a49a636c43b1..ddc24457ef4f75231d5eaf9b69e48e543ed7f149 100644 (file)
@@ -57,7 +57,10 @@ NewBooleanMesh(
 
 struct DispListMesh *NewBooleanMeshDLM(struct Object *ob, struct Object *ob_select, int int_op_type);
 
-       
+struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob,
+                                          struct Object *ob_select,
+                                          int int_op_type);
+
 /**
  * Functions exposed for use by BKE_booleanops_mesh
  */
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
new file mode 100644 (file)
index 0000000..b831344
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+* $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) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*/ 
+
+/* CDDerivedMesh interface.
+ * CDDerivedMesh (CD = Custom Data) is a DerivedMesh backend which stores
+ * mesh elements (vertices, edges and faces) as layers of custom element data.
+ */
+
+#ifndef BKE_CDDERIVEDMESH_H
+#define BKE_CDDERIVEDMESH_H
+
+#include "BKE_DerivedMesh.h"
+
+struct DerivedMesh;
+struct EditMesh;
+struct Mesh;
+
+/* creates a new CDDerivedMesh */
+struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces);
+
+/* creates a CDDerivedMesh from the given Mesh */
+struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh);
+
+/* creates a CDDerivedMesh from the given EditMesh */
+struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me);
+
+/* Copies the given DerivedMesh with verts, faces & edges stored as
+ * custom element data.
+ */
+struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
+
+/* creates a CDDerivedMesh with the same layer stack configuration as the
+ * given DerivedMesh and containing the requested numbers of elements.
+ * elements are initialised to all zeros
+ */
+struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source,
+                                  int numVerts, int numEdges, int numFaces);
+
+/* applies vertex coordinates to a CDDerivedMesh
+ */
+void CDDM_apply_vert_coords(struct DerivedMesh *cddm, float (*vertCoords)[3]);
+
+/* recalculates normals for a CDDerivedMesh
+ */
+void CDDM_calc_normals(struct DerivedMesh *dm);
+
+/* calculates edges for a CDDerivedMesh (from face data)
+ * this completely replaces the current edge data in the DerivedMesh
+ */
+void CDDM_calc_edges(struct DerivedMesh *dm);
+
+/* sets the number of vertices/edges/faces in a CDDerivedMesh
+ * if the value given is more than the maximum, the maximum is used
+ */
+void CDDM_set_num_verts(struct DerivedMesh *dm, int numVerts);
+void CDDM_set_num_edges(struct DerivedMesh *dm, int numEdges);
+void CDDM_set_num_faces(struct DerivedMesh *dm, int numFaces);
+
+/* vertex/edge/face access functions
+ * should always succeed if index is within bounds
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+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);
+
+/* vertex/edge/face array access functions - return the array holding the
+ * desired data
+ * should always succeed
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+struct MVert *CDDM_get_verts(struct DerivedMesh *dm);
+struct MEdge *CDDM_get_edges(struct DerivedMesh *dm);
+struct MFace *CDDM_get_faces(struct DerivedMesh *dm);
+#endif
+
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
new file mode 100644 (file)
index 0000000..6f8d991
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+* $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) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*/ 
+
+/* CustomData interface.
+ * CustomData is a structure which stores custom element data associated
+ * with mesh elements (vertices, edges or faces). The custom data is
+ * organised into a series of layers, each with a data type (e.g. TFace,
+ * MDeformVert, etc.).
+ */
+
+#ifndef BKE_CUSTOMDATA_H
+#define BKE_CUSTOMDATA_H
+
+typedef struct CustomData {
+       struct LayerDesc *layers; /* data layer descriptors, ordered by type */
+       int numLayers;            /* current number of layers */
+       int maxLayers;            /* maximum number of layers */
+       int numElems;             /* current number of elements */
+       int maxElems;             /* maximum number of elements */
+       int subElems;             /* number of sub-elements layers can have */
+} CustomData;
+
+/* custom data types */
+enum {
+       LAYERTYPE_MVERT = 0,
+       LAYERTYPE_MSTICKY,
+       LAYERTYPE_MDEFORMVERT,
+       LAYERTYPE_MEDGE,
+       LAYERTYPE_MFACE,
+       LAYERTYPE_TFACE,
+       LAYERTYPE_MCOL,
+       LAYERTYPE_ORIGINDEX,
+       LAYERTYPE_NORMAL,
+       LAYERTYPE_FLAGS,
+       LAYERTYPE_NUMTYPES
+};
+
+#define ORIGINDEX_NONE -1 /* indicates no original index for this element */
+
+/* layer flags - to be used with CustomData_add_layer */
+
+/* indicates layer should not be copied by CustomData_from_template or
+ * CustomData_copy_data (for temporary utility layers)
+ */
+#define LAYERFLAG_NOCOPY 1<<0
+
+/* indicates layer should not be freed (for layers backed by external data)
+ */
+#define LAYERFLAG_NOFREE 1<<1
+
+/* initialises a CustomData object with space for the given number
+ * of data layers and the given number of elements per layer
+ */
+void CustomData_init(CustomData *data,
+                     int maxLayers, int maxElems, int subElems);
+
+/* initialises a CustomData object with the same layer setup as source
+ * and memory space for maxElems elements
+ */
+void CustomData_from_template(const CustomData *source, CustomData *dest,
+                              int maxElems);
+
+/* frees data associated with a CustomData object (doesn't free the object
+ * itself, though)
+ */
+void CustomData_free(CustomData *data);
+
+/* adds a data layer of the given type to the CustomData object, optionally
+ * backed by an external data array
+ * if layer != NULL, it is used as the layer data array, otherwise new memory
+ * is allocated
+ * the layer data will be freed by CustomData_free unless
+ * (flag & LAYERFLAG_NOFREE) is true
+ * grows the number of layers in data if data->maxLayers has been reached
+ * returns 1 on success, 0 on failure
+ */
+int CustomData_add_layer(CustomData *data, int type, int flag, void *layer);
+
+/* returns 1 if the two objects are compatible (same layer types and
+ * flags in the same order), 0 if not
+ */
+int CustomData_compat(const CustomData *data1, const CustomData *data2);
+
+/* copies data from one CustomData object to another
+ * objects need not be compatible, each source layer is copied to the
+ * first dest layer of correct type (if there is none, the layer is skipped)
+ * return 1 on success, 0 on failure
+ */
+int CustomData_copy_data(const CustomData *source, CustomData *dest,
+                         int source_index, int dest_index, int count);
+
+/* frees data in a CustomData object
+ * return 1 on success, 0 on failure
+ */
+int CustomData_free_elem(CustomData *data, int index, int count);
+
+/* interpolates data from one CustomData object to another
+ * objects need not be compatible, each source layer is interpolated to the
+ * first dest layer of correct type (if there is none, the layer is skipped)
+ * if weights == NULL or sub_weights == NULL, they default to all 1's
+ *
+ * src_indices gives the source elements to interpolate from
+ * weights gives the weight for each source element
+ * sub_weights is an array of matrices of weights for sub-elements (matrices
+ *     should be source->subElems * source->subElems in size)
+ * count gives the number of source elements to interpolate from
+ * dest_index gives the dest element to write the interpolated value to
+ *
+ * returns 1 on success, 0 on failure
+ */
+int CustomData_interp(const CustomData *source, CustomData *dest,
+                      int *src_indices, float *weights, float *sub_weights,
+                      int count, int dest_index);
+
+/* gets a pointer to the data element at index from the first layer of type
+ * returns NULL if there is no layer of type
+ */
+void *CustomData_get(const CustomData *data, int index, int type);
+
+/* gets a pointer to the first layer of type
+ * returns NULL if there is no layer of type
+ */
+void *CustomData_get_layer(const CustomData *data, int type);
+
+/* copies the data from source to the data element at index in the first
+ * layer of type
+ * no effect if there is no layer of type
+ */
+void CustomData_set(const CustomData *data, int index, int type, void *source);
+
+/* sets the number of elements in a CustomData object
+ * if the value given is more than the maximum, the maximum is used
+ */
+void CustomData_set_num_elems(CustomData *data, int numElems);
+#endif
index 2f7ae6bb329f862a0650845ca85c1b880b3c5ae6..a7533a614eb8eb25e9b33cf0a76655a3563c4c6d 100644 (file)
@@ -36,6 +36,7 @@
 
 struct Lattice;
 struct Object;
+struct DerivedMesh;
 struct BPoint;
 
 extern struct Lattice *editLatt;
@@ -52,9 +53,13 @@ void calc_latt_deform(float *co, float weight);
 void end_latt_deform(void);
 int object_deform_mball(struct Object *ob);
 void outside_lattice(struct Lattice *lt);
-void curve_deform_verts(struct Object *cuOb, struct Object *target, float (*vertexCos)[3], int numVerts, char *vgroup);
-void lattice_deform_verts(struct Object *laOb, struct Object *target, float (*vertexCos)[3], int numVerts, char *vgroup);
-void armature_deform_verts(struct Object *armOb, struct Object *target, float (*vertexCos)[3], int numVerts, int deformflag);
+void curve_deform_verts(struct Object *cuOb, struct Object *target, struct DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup);
+void lattice_deform_verts(struct Object *laOb, struct Object *target,
+                          struct DerivedMesh *dm, float (*vertexCos)[3],
+                          int numVerts, char *vgroup);
+void armature_deform_verts(struct Object *armOb, struct Object *target,
+                           struct DerivedMesh *dm, float (*vertexCos)[3],
+                           int numVerts, int deformflag);
 float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3];
 void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]);
 void lattice_calc_modifiers(struct Object *ob);
index 9afefbfc5a9343350ceabf52fd194395cc1aac2e..a4c050429e51ea0485c9c48231d71152e1213b4c 100644 (file)
@@ -33,6 +33,7 @@
 #ifndef BKE_MODIFIER_H
 #define BKE_MODIFIER_H
 
+struct EditMesh;
 struct DerivedMesh;
 struct DagForest;
 struct DagNode;
@@ -41,14 +42,14 @@ struct ListBase;
 struct bArmature;
 
 typedef enum {
-               /* Should not be used, only for None modifier type */
+       /* Should not be used, only for None modifier type */
        eModifierTypeType_None,
 
-               /* Modifier only does deformation, implies that modifier
-                * type should have a valid deformVerts function. OnlyDeform
-                * style modifiers implicitly accept either mesh or CV
-                * input but should still declare flags appropriately.
-                */
+       /* Modifier only does deformation, implies that modifier
+        * type should have a valid deformVerts function. OnlyDeform
+        * style modifiers implicitly accept either mesh or CV
+        * input but should still declare flags appropriately.
+        */
        eModifierTypeType_OnlyDeform,
 
        eModifierTypeType_Constructive,
@@ -56,165 +57,203 @@ typedef enum {
 } ModifierTypeType;
 
 typedef enum {
-       eModifierTypeFlag_AcceptsMesh = (1<<0),
-       eModifierTypeFlag_AcceptsCVs = (1<<1),
-       eModifierTypeFlag_SupportsMapping = (1<<2),
-       eModifierTypeFlag_SupportsEditmode = (1<<3),
-       
-               /* For modifiers that support editmode this determines if the
-                * modifier should be enabled by default in editmode. This should
-                * only be used by modifiers that are relatively speedy and
-                * also generally used in editmode, otherwise let the user enable
-                * it by hand.
-                */
-       eModifierTypeFlag_EnableInEditmode = (1<<4),
-
-               /* For modifiers that require original data and so cannot
-                * be placed after any non-deformative modifier.
-                */
+       eModifierTypeFlag_AcceptsMesh          = (1<<0),
+       eModifierTypeFlag_AcceptsCVs           = (1<<1),
+       eModifierTypeFlag_SupportsMapping      = (1<<2),
+       eModifierTypeFlag_SupportsEditmode     = (1<<3),
+
+       /* For modifiers that support editmode this determines if the
+        * modifier should be enabled by default in editmode. This should
+        * only be used by modifiers that are relatively speedy and
+        * also generally used in editmode, otherwise let the user enable
+        * it by hand.
+        */
+       eModifierTypeFlag_EnableInEditmode     = (1<<4),
+
+       /* For modifiers that require original data and so cannot
+        * be placed after any non-deformative modifier.
+        */
        eModifierTypeFlag_RequiresOriginalData = (1<<5),
 } ModifierTypeFlag;
 
+typedef void (*ObjectWalkFunc)(void *userData, Object *ob, Object **obpoin);
+typedef void (*IDWalkFunc)(void *userData, Object *ob, ID **idpoin);
+
 typedef struct ModifierTypeInfo {
-               /* The user visible name for this modifier */
+       /* The user visible name for this modifier */
        char name[32];
 
-               /* The DNA struct name for the modifier data type, used to
-                * write the DNA data out.
-                */
+       /* The DNA struct name for the modifier data type, used to
+        * write the DNA data out.
+        */
        char structName[32];
 
-               /* The size of the modifier data type, used by allocation. */
+       /* The size of the modifier data type, used by allocation. */
        int structSize;
 
        ModifierTypeType type;
        ModifierTypeFlag flags;
 
-               /* Initialize new instance data for this modifier type, this function
-                * should set modifier variables to their default values.
-                * 
-                * This function is optional.
-                */
-       void (*initData)(ModifierData *md);
 
-               /* Copy instance data for this modifier type. Should copy all user
-                * level settings to the target modifier.
-                */
+       /********************* Non-optional functions *********************/
+
+       /* Copy instance data for this modifier type. Should copy all user
+        * level settings to the target modifier.
+        */
        void (*copyData)(ModifierData *md, ModifierData *target);
 
-               /* Free internal modifier data variables, this function should
-                * not free the _md_ variable itself.
-                *
-                * This function is optional.
-                */
+
+       /********************* Deform modifier functions *********************/
+
+       /* Only for deform types, should apply the deformation
+        * to the given vertex array. If the deformer requires information from
+        * the object it can obtain it from the derivedData argument if non-NULL,
+        * and otherwise the ob argument.
+        */
+       void (*deformVerts)(ModifierData *md, struct Object *ob,
+                           struct DerivedMesh *derivedData,
+                           float (*vertexCos)[3], int numVerts);
+
+       /* Like deformVerts but called during editmode (for supporting modifiers)
+        */
+       void (*deformVertsEM)(
+                   ModifierData *md, struct Object *ob,
+                   struct EditMesh *editData, struct DerivedMesh *derivedData,
+                   float (*vertexCos)[3], int numVerts);
+
+
+       /********************* Non-deform modifier functions *********************/
+
+       /* For non-deform types: apply the modifier and return a derived
+        * data object (type is dependent on object type).
+        *
+        * The derivedData argument should always be non-NULL; the modifier
+        * should read the object data from the derived object instead of the
+        * actual object data. 
+        *
+        * The useRenderParams argument indicates if the modifier is being
+        * applied in the service of the renderer which may alter quality
+        * settings.
+        *
+        * The isFinalCalc parameter indicates if the modifier is being
+        * calculated for a final result or for something temporary
+        * (like orcos). This is a hack at the moment, it is meant so subsurf
+        * can know if it is safe to reuse its internal cache.
+        *
+        * The modifier may reuse the derivedData argument (i.e. return it in
+        * modified form), but must not release it.
+        */
+       struct DerivedMesh *(*applyModifier)(
+                                   ModifierData *md, struct Object *ob,
+                                   struct DerivedMesh *derivedData,
+                                   int useRenderParams, int isFinalCalc);
+
+       /* Like applyModifier but called during editmode (for supporting
+        * modifiers).
+        * 
+        * The derived object that is returned must support the operations that
+        * are expected from editmode objects. The same qualifications regarding
+        * derivedData apply as for applyModifier.
+        */
+       struct DerivedMesh *(*applyModifierEM)(
+                                   ModifierData *md, struct Object *ob,
+                                   struct EditMesh *editData,
+                                   struct DerivedMesh *derivedData);
+
+
+       /********************* Optional functions *********************/
+
+       /* Initialize new instance data for this modifier type, this function
+        * should set modifier variables to their default values.
+        * 
+        * This function is optional.
+        */
+       void (*initData)(ModifierData *md);
+
+       /* Free internal modifier data variables, this function should
+        * not free the md variable itself.
+        *
+        * This function is optional.
+        */
        void (*freeData)(ModifierData *md);
 
-               /* Return a boolean value indicating if this modifier is able to be calculated
-                * based on the modifier data. This is *not* regarding the md->flag, that is
-                * tested by the system, this is just if the data validates (for example, a
-                * lattice will return false if the lattice object is not defined).
-                *
-                * This function is optional (assumes never disabled if not present).
-                */
+       /* Return a boolean value indicating if this modifier is able to be
+        * calculated based on the modifier data. This is *not* regarding the
+        * md->flag, that is tested by the system, this is just if the data
+        * validates (for example, a lattice will return false if the lattice
+        * object is not defined).
+        *
+        * This function is optional (assumes never disabled if not present).
+        */
        int (*isDisabled)(ModifierData *md);
 
-               /* Add the appropriate relations to the DEP graph depending on the modifier
-                * data. 
-                *
-                * This function is optional.
-                */
-       void (*updateDepgraph)(ModifierData *md, struct DagForest *forest, struct Object *ob, struct DagNode *obNode);
-
-               /* Should return true if the modifier needs to be recalculated on time changes.
-                *
-                * This function is optional (assumes false if not present).
-                */
-       int (*dependsOnTime)(ModifierData *md);
+       /* Add the appropriate relations to the DEP graph depending on the
+        * modifier data. 
+        *
+        * This function is optional.
+        */
+       void (*updateDepgraph)(ModifierData *md, struct DagForest *forest,
+                              struct Object *ob, struct DagNode *obNode);
 
-               /* Should call the given _walk_ function on with a pointer to each Object pointer
-                * that the modifier data stores. This is used for linking on file load and for
-                * unlinking objects or forwarding object references.
-                *
-                * This function is optional.
-                */
-       void (*foreachObjectLink)(ModifierData *md, struct Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData);
-
-               /* Only for deform types, should apply the deformation
-                * to the given vertex array. If the deformer requires information from
-                * the object it can obtain it from the _derivedData_ argument if non-NULL,
-                * and otherwise the _ob_ argument.
-                */
-       void (*deformVerts)(ModifierData *md, struct Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts);
-
-               /* Like deformVerts but called during editmode (for supporting modifiers) */
-       void (*deformVertsEM)(ModifierData *md, struct Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts);
-
-               /* For non-deform types: apply the modifier and return a new derived
-                * data object (type is dependent on object type). If the _derivedData_
-                * argument is non-NULL then the modifier should read the object data 
-                * from the derived object instead of the actual object data. 
-                *
-                * If the _vertexCos_ argument is non-NULL then the modifier should read 
-                * the vertex coordinates from that (even if _derivedData_ is non-NULL).
-                * The length of the _vertexCos_ array is either the number of verts in
-                * the derived object (if non-NULL) or otherwise the number of verts in
-                * the original object.
-                *
-                * The _useRenderParams_ indicates if the modifier is being applied in
-                * the service of the renderer which may alter quality settings.
-                *
-                * The _isFinalCalc_ parameter indicates if the modifier is being calculated
-                * for a final result or for something temporary (like orcos). This is a hack
-                * at the moment, it is meant so subsurf can know if it is safe to reuse its
-                * internal cache.
-                *
-                * The modifier *MAY NOT* reuse or release the _derivedData_ argument
-                * if non-NULL. The modifier *MAY NOT* share the _vertexCos_ argument.
-                */
-       void *(*applyModifier)(ModifierData *md, struct Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc);
-
-               /* Like applyModifier but called during editmode (for supporting modifiers).
-                * 
-                * The derived object that is returned must support the operations that are expected
-                * from editmode objects. The same qualifications regarding _derivedData_ and _vertexCos_
-                * apply as for applyModifier.
-                */
-       void *(*applyModifierEM)(ModifierData *md, struct Object *ob, void *editData, void *derivedData, float (*vertexCos)[3]);
-} ModifierTypeInfo;
+       /* Should return true if the modifier needs to be recalculated on time
+        * changes.
+        *
+        * This function is optional (assumes false if not present).
+        */
+       int (*dependsOnTime)(ModifierData *md);
 
-ModifierTypeInfo*              modifierType_getInfo    (ModifierType type);
+       /* Should call the given walk function on with a pointer to each Object
+        * pointer that the modifier data stores. This is used for linking on file
+        * load and for unlinking objects or forwarding object references.
+        *
+        * This function is optional.
+        */
+       void (*foreachObjectLink)(ModifierData *md, struct Object *ob,
+                                 ObjectWalkFunc walk, void *userData);
 
-       /* Modifier utility calls, do call through type pointer and return
-        * default values if pointer is optional.
+       /* Should call the given walk function with a pointer to each ID
+        * pointer (i.e. each datablock pointer) that the modifier data
+        * stores. This is used for linking on file load and for
+        * unlinking datablocks or forwarding datablock references.
+        *
+        * This function is optional. If it is not present, foreachObjectLink
+        * will be used.
         */
-ModifierData*  modifier_new                            (int type);
-void                   modifier_free                           (ModifierData *md);
+       void (*foreachIDLink)(ModifierData *md, struct Object *ob,
+                             IDWalkFunc walk, void *userData);
+} ModifierTypeInfo;
 
-void                   modifier_copyData                       (ModifierData *md, ModifierData *target);
-int                            modifier_dependsOnTime          (ModifierData *md);
-int                            modifier_supportsMapping        (ModifierData *md);
-int                            modifier_couldBeCage            (ModifierData *md);
-void                   modifier_setError                       (ModifierData *md, char *format, ...);
+ModifierTypeInfo *modifierType_getInfo (ModifierType type);
 
-void                   modifiers_foreachObjectLink     (struct Object *ob, void (*walk)(void *userData, struct Object *ob, struct Object **obpoin), void *userData);
-ModifierData*  modifiers_findByType            (struct Object *ob, ModifierType type);
-void                   modifiers_clearErrors           (struct Object *ob);
-int                            modifiers_getCageIndex          (struct Object *ob, int *lastPossibleCageIndex_r);
+/* Modifier utility calls, do call through type pointer and return
+ * default values if pointer is optional.
+ */
+ModifierData  *modifier_new(int type);
+void          modifier_free(ModifierData *md);
 
-int                            modifiers_isSoftbodyEnabled     (struct Object *ob);
-struct Object* modifiers_isDeformedByArmature(struct Object *ob);
-int                            modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
-int                            modifiers_isDeformed            (struct Object *ob);
+void          modifier_copyData(ModifierData *md, ModifierData *target);
+int           modifier_dependsOnTime(ModifierData *md);
+int           modifier_supportsMapping(ModifierData *md);
+int           modifier_couldBeCage(ModifierData *md);
+void          modifier_setError(ModifierData *md, char *format, ...);
 
-ModifierData*  modifiers_getVirtualModifierList        (struct Object *ob);
+void          modifiers_foreachObjectLink(struct Object *ob,
+                                          ObjectWalkFunc walk,
+                                          void *userData);
+void          modifiers_foreachIDLink(struct Object *ob,
+                                      IDWalkFunc walk,
+                                      void *userData);
+ModifierData  *modifiers_findByType(struct Object *ob, ModifierType type);
+void          modifiers_clearErrors(struct Object *ob);
+int           modifiers_getCageIndex(struct Object *ob,
+                                     int *lastPossibleCageIndex_r);
 
-       /* Modifier utility calls, do call through type pointer and return
-        * default values if pointer is optional.
-        */
-struct ModifierData*   modifier_new                    (int type);
-void                                   modifier_free                   (struct ModifierData *md);
+int           modifiers_isSoftbodyEnabled(struct Object *ob);
+struct Object *modifiers_isDeformedByArmature(struct Object *ob);
+int           modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
+int           modifiers_isDeformed(struct Object *ob);
 
-int                                            modifier_dependsOnTime  (struct ModifierData *md);
+ModifierData  *modifiers_getVirtualModifierList(struct Object *ob);
 
 #endif
 
index 2289fb027eb241547eec2d97aff7220dace35d98..3d1ffd3e52f636fc55782bee969465cf6ad315c6 100644 (file)
@@ -40,6 +40,11 @@ struct SubsurfModifierData;
 struct DerivedMesh *subsurf_make_derived_from_editmesh(struct EditMesh *em, struct SubsurfModifierData *smd, float (*vertexCos)[3]);
 struct DerivedMesh *subsurf_make_derived_from_dlm_em(struct DispListMesh *dlm, struct SubsurfModifierData *smd, float (*vertCos)[3]);
 struct DerivedMesh *subsurf_make_derived_from_mesh(struct Mesh *me, struct DispListMesh *dlm, struct SubsurfModifierData *smd, int useRenderParams, float (*vertCos)[3], int isFinalCalc);
+struct DerivedMesh *subsurf_make_derived_from_derived(
+                        struct DerivedMesh *dm,
+                        struct SubsurfModifierData *smd,
+                        int useRenderParams, float (*vertCos)[3],
+                        int isFinalCalc, int editMode);
 
 void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]);
 
index 4187e5c03201a2305e88f867107921f15ebcefa2..016d5c298c39037029479054d1032c8af7304a77 100644 (file)
@@ -44,6 +44,7 @@
 
 #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"
@@ -56,6 +57,7 @@
 #include "BLI_editVert.h"
 
 #include "BKE_utildefines.h"
+#include "BKE_cdderivedmesh.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_displist.h"
 #include "BKE_effect.h"
 
 ///////////////////////////////////
 ///////////////////////////////////
+#define DERIVEDMESH_INITIAL_LAYERS 5
+
+MVert *dm_dupVertArray(DerivedMesh *dm)
+{
+       MVert *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumVerts(dm),
+                                "dm_dupVertArray tmp");
+
+       if(tmp) dm->getVertArray(dm, tmp);
+
+       return tmp;
+}
+
+MEdge *dm_dupEdgeArray(DerivedMesh *dm)
+{
+       MEdge *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumEdges(dm),
+                                "dm_dupEdgeArray tmp");
+
+       if(tmp) dm->getEdgeArray(dm, tmp);
+
+       return tmp;
+}
+
+MFace *dm_dupFaceArray(DerivedMesh *dm)
+{
+       MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm),
+                                "dm_dupFaceArray tmp");
+
+       if(tmp) dm->getFaceArray(dm, tmp);
+
+       return tmp;
+}
+
+void DM_init_funcs(DerivedMesh *dm)
+{
+       /* default function implementations */
+       dm->dupVertArray = dm_dupVertArray;
+       dm->dupEdgeArray = dm_dupEdgeArray;
+       dm->dupFaceArray = dm_dupFaceArray;
+
+       dm->getVertData = DM_get_vert_data;
+       dm->getEdgeData = DM_get_edge_data;
+       dm->getFaceData = 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;
+}
+
+void DM_init(DerivedMesh *dm,
+             int numVerts, int numEdges, int numFaces)
+{
+       if(numVerts > 0) {
+               CustomData_init(&dm->vertData, DERIVEDMESH_INITIAL_LAYERS, numVerts,
+                               SUB_ELEMS_VERT);
+               CustomData_init(&dm->edgeData, DERIVEDMESH_INITIAL_LAYERS, numEdges,
+                               SUB_ELEMS_EDGE);
+               CustomData_init(&dm->faceData, DERIVEDMESH_INITIAL_LAYERS, numFaces,
+                               SUB_ELEMS_FACE);
+
+               CustomData_add_layer(&dm->vertData, LAYERTYPE_ORIGINDEX, 0, NULL);
+               CustomData_add_layer(&dm->edgeData, LAYERTYPE_ORIGINDEX, 0, NULL);
+               CustomData_add_layer(&dm->faceData, LAYERTYPE_ORIGINDEX, 0, NULL);
+       }
+
+       DM_init_funcs(dm);
+}
+
+void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
+                      int numVerts, int numEdges, int numFaces)
+{
+       if(numVerts > 0) {
+               CustomData_from_template(&source->vertData, &dm->vertData, numVerts);
+               CustomData_from_template(&source->edgeData, &dm->edgeData, numEdges);
+               CustomData_from_template(&source->faceData, &dm->faceData, numFaces);
+       }
+
+       DM_init_funcs(dm);
+}
+
+void DM_release(DerivedMesh *dm)
+{
+       CustomData_free(&dm->vertData);
+       CustomData_free(&dm->edgeData);
+       CustomData_free(&dm->faceData);
+}
+
+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 = *me;
+       int numVerts = dm->getNumVerts(dm);
+
+       tmp_me.dvert = NULL;
+       tmp_me.tface = NULL;
+       tmp_me.mcol = NULL;
+
+       tmp_me.totvert = numVerts;
+       tmp_me.totedge = dm->getNumEdges(dm);
+       tmp_me.totface = dm->getNumFaces(dm);
+
+       tmp_me.mvert = dm->dupVertArray(dm);
+       tmp_me.medge = dm->dupEdgeArray(dm);
+       tmp_me.mface = dm->dupFaceArray(dm);
+
+       if(dm->getFaceDataArray(dm, LAYERTYPE_TFACE))
+               tmp_me.tface = MEM_dupallocN(dm->getFaceDataArray(dm,
+                                                                 LAYERTYPE_TFACE));
+       if(dm->getFaceDataArray(dm, LAYERTYPE_MCOL))
+               tmp_me.mcol = MEM_dupallocN(dm->getFaceDataArray(dm,
+                                                                LAYERTYPE_MCOL));
+       if(dm->getVertDataArray(dm, LAYERTYPE_MDEFORMVERT)) {
+               int i;
+               MDeformVert *dv;
+
+               tmp_me.dvert = MEM_dupallocN(
+                                   dm->getVertDataArray(dm, LAYERTYPE_MDEFORMVERT));
+
+               for(i = 0, dv = tmp_me.dvert; i < numVerts; ++i, ++dv)
+                       dv->dw = MEM_dupallocN(dv->dw);
+       }
+
+       if(me->mvert) MEM_freeN(me->mvert);
+       if(me->dvert) free_dverts(me->dvert, me->totvert);
+       if(me->mface) MEM_freeN(me->mface);
+       if(me->tface) MEM_freeN(me->tface);
+       if(me->mcol) MEM_freeN(me->mcol);
+       if(me->medge) MEM_freeN(me->medge);
+
+       /* if the number of verts has changed, remove invalid data */
+       if(numVerts != me->totvert) {
+               if(me->msticky) MEM_freeN(me->msticky);
+               me->msticky = NULL;
+
+               if(me->key) me->key->id.us--;
+               me->key = NULL;
+       }
+
+       *me = tmp_me;
+}
+
+void DM_add_vert_layer(DerivedMesh *dm, int type, int flag, void *layer)
+{
+       CustomData_add_layer(&dm->vertData, type, flag, layer);
+}
+
+void DM_add_edge_layer(DerivedMesh *dm, int type, int flag, void *layer)
+{
+       CustomData_add_layer(&dm->edgeData, type, flag, layer);
+}
+
+void DM_add_face_layer(DerivedMesh *dm, int type, int flag, void *layer)
+{
+       CustomData_add_layer(&dm->faceData, type, flag, layer);
+}
+
+void *DM_get_vert_data(DerivedMesh *dm, int index, int type)
+{
+       return CustomData_get(&dm->vertData, index, type);
+}
+
+void *DM_get_edge_data(DerivedMesh *dm, int index, int type)
+{
+       return CustomData_get(&dm->edgeData, index, type);
+}
+
+void *DM_get_face_data(DerivedMesh *dm, int index, int type)
+{
+       return CustomData_get(&dm->faceData, index, type);
+}
+
+void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
+{
+       return CustomData_get_layer(&dm->vertData, type);
+}
+
+void *DM_get_edge_data_layer(DerivedMesh *dm, int type)
+{
+       return CustomData_get_layer(&dm->edgeData, type);
+}
+
+void *DM_get_face_data_layer(DerivedMesh *dm, int type)
+{
+       return CustomData_get_layer(&dm->faceData, type);
+}
+
+void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data)
+{
+       CustomData_set(&dm->vertData, index, type, data);
+}
+
+void DM_set_edge_data(DerivedMesh *dm, int index, int type, void *data)
+{
+       CustomData_set(&dm->edgeData, index, type, data);
+}
+
+void DM_set_face_data(DerivedMesh *dm, int index, int type, void *data)
+{
+       CustomData_set(&dm->faceData, index, type, data);
+}
+
+void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest,
+                       int source_index, int dest_index, int count)
+{
+       CustomData_copy_data(&source->vertData, &dest->vertData,
+                            source_index, dest_index,
+                            count);
+}
+
+void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest,
+                       int source_index, int dest_index, int count)
+{
+       CustomData_copy_data(&source->edgeData, &dest->edgeData,
+                            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->faceData, &dest->faceData,
+                            source_index, dest_index,
+                            count);
+}
+
+void DM_free_vert_data(struct DerivedMesh *dm, int index, int count)
+{
+       CustomData_free_elem(&dm->vertData, index, count);
+}
+
+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)
+{
+       CustomData_free_elem(&dm->faceData, index, count);
+}
+
+void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest,
+                         int *src_indices, float *weights,
+                         int count, int dest_index)
+{
+       CustomData_interp(&source->vertData, &dest->vertData, src_indices,
+                         weights, NULL, count, dest_index);
+}
+
+void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest,
+                         int *src_indices,
+                         float *weights, EdgeVertWeight *vert_weights,
+                         int count, int dest_index)
+{
+       CustomData_interp(&source->edgeData, &dest->edgeData, src_indices,
+                         weights, (float *)vert_weights, count, dest_index);
+}
+
+void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
+                         int *src_indices,
+                         float *weights, FaceVertWeight *vert_weights,
+                         int count, int dest_index)
+{
+       CustomData_interp(&source->faceData, &dest->faceData, src_indices,
+                         weights, (float *)vert_weights, count, dest_index);
+}
 
 typedef struct {
        DerivedMesh dm;
@@ -457,7 +722,7 @@ static void meshDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *
 
        for (i=0; i<me->totface; i++) {
                MFace *mf= &mface[i];
-               int drawSmooth = 1;
+               int drawSmooth = (mf->flag & ME_SMOOTH);
 
                if (!setDrawOptions || setDrawOptions(userData, i, &drawSmooth)) {
                        unsigned char *cp = NULL;
@@ -516,6 +781,15 @@ static int meshDM_getNumVerts(DerivedMesh *dm)
 
        return me->totvert;
 }
+
+static int meshDM_getNumEdges(DerivedMesh *dm)
+{
+       MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
+       Mesh *me = mdm->me;
+
+       return me->totedge;
+}
+
 static int meshDM_getNumFaces(DerivedMesh *dm)
 {
        MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
@@ -524,10 +798,51 @@ static int meshDM_getNumFaces(DerivedMesh *dm)
        return me->totface;
 }
 
+void meshDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+       MVert *verts = ((MeshDerivedMesh *)dm)->verts;
+
+       *vert_r = verts[index];
+}
+
+void meshDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+       Mesh *me = ((MeshDerivedMesh *)dm)->me;
+
+       *edge_r = me->medge[index];
+}
+
+void meshDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+       Mesh *me = ((MeshDerivedMesh *)dm)->me;
+
+       *face_r = me->mface[index];
+}
+
+void meshDM_getVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+       MeshDerivedMesh *mdm = (MeshDerivedMesh *)dm;
+       memcpy(vert_r, mdm->verts, sizeof(*vert_r) * mdm->me->totvert);
+}
+
+void meshDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+       MeshDerivedMesh *mdm = (MeshDerivedMesh *)dm;
+       memcpy(edge_r, mdm->me->medge, sizeof(*edge_r) * mdm->me->totedge);
+}
+
+void meshDM_getFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+       MeshDerivedMesh *mdm = (MeshDerivedMesh *)dm;
+       memcpy(face_r, mdm->me->mface, sizeof(*face_r) * mdm->me->totface);
+}
+
 static void meshDM_release(DerivedMesh *dm)
 {
        MeshDerivedMesh *mdm = (MeshDerivedMesh*) dm;
 
+       DM_release(dm);
+
        if (mdm->wpaintMCol) MEM_freeN(mdm->wpaintMCol);
        if (mdm->freeNors) MEM_freeN(mdm->nors);
        if (mdm->freeVerts) MEM_freeN(mdm->verts);
@@ -538,12 +853,22 @@ static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3]
 {
        MeshDerivedMesh *mdm = MEM_callocN(sizeof(*mdm), "mdm");
 
+       DM_init(&mdm->dm, me->totvert, me->totedge, me->totface);
+
        mdm->dm.getMinMax = meshDM_getMinMax;
 
        mdm->dm.convertToDispListMesh = meshDM_convertToDispListMesh;
        mdm->dm.getNumVerts = meshDM_getNumVerts;
+       mdm->dm.getNumEdges = meshDM_getNumEdges;
        mdm->dm.getNumFaces = meshDM_getNumFaces;
 
+       mdm->dm.getVert = meshDM_getVert;
+       mdm->dm.getEdge = meshDM_getEdge;
+       mdm->dm.getFace = meshDM_getFace;
+       mdm->dm.getVertArray = meshDM_getVertArray;
+       mdm->dm.getEdgeArray = meshDM_getEdgeArray;
+       mdm->dm.getFaceArray = meshDM_getFaceArray;
+
        mdm->dm.getVertCos = meshDM_getVertCos;
        mdm->dm.getVertCo = meshDM_getVertCo;
        mdm->dm.getVertNo = meshDM_getVertNo;
@@ -565,6 +890,21 @@ static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3]
 
        mdm->dm.release = meshDM_release;
 
+       /* add appropriate data layers (don't copy, just reference) */
+       if(me->msticky)
+               DM_add_vert_layer(&mdm->dm, LAYERTYPE_MSTICKY,
+                                 LAYERFLAG_NOFREE, me->msticky);
+       if(me->dvert)
+               DM_add_vert_layer(&mdm->dm, LAYERTYPE_MDEFORMVERT,
+                                 LAYERFLAG_NOFREE, me->dvert);
+
+       if(me->tface)
+               DM_add_face_layer(&mdm->dm, LAYERTYPE_TFACE,
+                                 LAYERFLAG_NOFREE, me->tface);
+       if(me->mcol)
+               DM_add_face_layer(&mdm->dm, LAYERTYPE_MCOL,
+                                 LAYERFLAG_NOFREE, me->mcol);
+
                /* Works in conjunction with hack during modifier calc */
        if ((G.f & G_WEIGHTPAINT) && ob==(G.scene->basact?G.scene->basact->object:NULL)) {
                mdm->wpaintMCol = MEM_dupallocN(me->mcol);
@@ -793,12 +1133,12 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
 
        if (emdm->vertexCos) {
                EditVert *eve, *preveve;
-               int drawSmooth = 1;
 
                for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
                        eve->prev = (EditVert*) i++;
 
                for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
+                       int drawSmooth = (efa->flag & ME_SMOOTH);
                        if(!setDrawOptions || setDrawOptions(userData, i, &drawSmooth)) {
                                glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 
@@ -828,9 +1168,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                for (preveve=NULL, eve=emdm->em->verts.first; eve; preveve=eve, eve= eve->next)
                        eve->prev = preveve;
        } else {
-               int drawSmooth = 1;
-
                for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
+                       int drawSmooth = (efa->flag & ME_SMOOTH);
                        if(!setDrawOptions || setDrawOptions(userData, i, &drawSmooth)) {
                                glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 
@@ -883,6 +1222,14 @@ static int emDM_getNumVerts(DerivedMesh *dm)
 
        return BLI_countlist(&emdm->em->verts);
 }
+
+static int emDM_getNumEdges(DerivedMesh *dm)
+{
+       EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+
+       return BLI_countlist(&emdm->em->edges);
+}
+
 static int emDM_getNumFaces(DerivedMesh *dm)
 {
        EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
@@ -890,10 +1237,182 @@ static int emDM_getNumFaces(DerivedMesh *dm)
        return BLI_countlist(&emdm->em->faces);
 }
 
+void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+       EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
+       int i;
+
+       for(i = 0; i < index; ++i) ev = ev->next;
+
+       VECCOPY(vert_r->co, ev->co);
+
+       vert_r->no[0] = ev->no[0] * 32767.0;
+       vert_r->no[1] = ev->no[1] * 32767.0;
+       vert_r->no[2] = ev->no[2] * 32767.0;
+
+       /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
+       vert_r->mat_nr = 0;
+}
+
+void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+       EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+       EditEdge *ee = em->edges.first;
+       EditVert *ev, *v1, *v2;
+       int i;
+
+       for(i = 0; i < index; ++i) ee = ee->next;
+
+       edge_r->crease = (unsigned char) (ee->crease*255.0f);
+       /* TODO what to do with edge_r->flag? */
+       edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
+       if (ee->seam) edge_r->flag |= ME_SEAM;
+       if (ee->sharp) edge_r->flag |= ME_SHARP;
+#if 0
+       /* this needs setup of f2 field */
+       if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+       /* goddamn, we have to search all verts to find indices */
+       v1 = ee->v1;
+       v2 = ee->v2;
+       for(i = 0, ev = em->verts.first; v1 || v2; i++, ev = ev->next) {
+               if(ev == v1) {
+                       edge_r->v1 = i;
+                       v1 = NULL;
+               }
+               if(ev == v2) {
+                       edge_r->v2 = i;
+                       v2 = NULL;
+               }
+       }
+}
+
+void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+       EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+       EditFace *ef = em->faces.first;
+       EditVert *ev, *v1, *v2, *v3, *v4;
+       int i;
+
+       for(i = 0; i < index; ++i) ef = ef->next;
+
+       face_r->mat_nr = ef->mat_nr;
+       face_r->flag = ef->flag;
+
+       /* goddamn, we have to search all verts to find indices */
+       v1 = ef->v1;
+       v2 = ef->v2;
+       v3 = ef->v3;
+       v4 = ef->v4;
+       if(!v4) face_r->v4 = 0;
+
+       for(i = 0, ev = em->verts.first; v1 || v2 || v3 || v4;
+           i++, ev = ev->next) {
+               if(ev == v1) {
+                       face_r->v1 = i;
+                       v1 = NULL;
+               }
+               if(ev == v2) {
+                       face_r->v2 = i;
+                       v2 = NULL;
+               }
+               if(ev == v3) {
+                       face_r->v3 = i;
+                       v3 = NULL;
+               }
+               if(ev == v4) {
+                       face_r->v4 = i;
+                       v4 = NULL;
+               }
+       }
+
+       test_index_face(face_r, NULL, NULL, ef->v4?4:3);
+}
+
+void emDM_getVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+       EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
+
+       for( ; ev; ev = ev->next, ++vert_r) {
+               VECCOPY(vert_r->co, ev->co);
+
+               vert_r->no[0] = ev->no[0] * 32767.0;
+               vert_r->no[1] = ev->no[1] * 32767.0;
+               vert_r->no[2] = ev->no[2] * 32767.0;
+
+               /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
+               vert_r->mat_nr = 0;
+               vert_r->flag = 0;
+       }
+}
+
+void emDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+       EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+       EditEdge *ee = em->edges.first;
+       EditVert *ev, *prevev;
+       int i;
+
+       /* store vert indices in the prev pointer (kind of hacky) */
+       for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
+               ev->prev = (EditVert*) i++;
+
+       for( ; ee; ee = ee->next, ++edge_r) {
+               edge_r->crease = (unsigned char) (ee->crease*255.0f);
+               /* TODO what to do with edge_r->flag? */
+               edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
+               if (ee->seam) edge_r->flag |= ME_SEAM;
+               if (ee->sharp) edge_r->flag |= ME_SHARP;
+#if 0
+               /* this needs setup of f2 field */
+               if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+               edge_r->v1 = (int)ee->v1->prev;
+               edge_r->v2 = (int)ee->v2->prev;
+       }
+
+       /* restore prev pointers */
+       for(prevev = NULL, ev = em->verts.first; ev; prevev = ev, ev = ev->next)
+               ev->prev = prevev;
+}
+
+void emDM_getFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+       EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+       EditFace *ef = em->faces.first;
+       EditVert *ev, *prevev;
+       int i;
+
+       /* store vert indices in the prev pointer (kind of hacky) */
+       for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
+               ev->prev = (EditVert*) i++;
+
+       for( ; ef; ef = ef->next, ++face_r) {
+               face_r->mat_nr = ef->mat_nr;
+               face_r->flag = ef->flag;
+
+               face_r->v1 = (int)ef->v1->prev;
+               face_r->v2 = (int)ef->v2->prev;
+               face_r->v3 = (int)ef->v3->prev;
+               if(ef->v4) face_r->v4 = (int)ef->v4->prev;
+               else face_r->v4 = 0;
+
+               test_index_face(face_r, NULL, NULL, ef->v4?4:3);
+       }
+
+       /* restore prev pointers */
+       for(prevev = NULL, ev = em->verts.first; ev; prevev = ev, ev = ev->next)
+               ev->prev = prevev;
+}
+
 static void emDM_release(DerivedMesh *dm)
 {
        EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 
+       DM_release(dm);
+
        if (emdm->vertexCos) {
                MEM_freeN(emdm->vertexCos);
                MEM_freeN(emdm->vertexNos);
@@ -903,14 +1422,28 @@ static void emDM_release(DerivedMesh *dm)
        MEM_freeN(emdm);
 }
 
-static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, float (*vertexCos)[3])
+static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob,
+                                           float (*vertexCos)[3])
 {
        EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm");
+       Mesh *me = ob->data;
+
+       DM_init(&emdm->dm, BLI_countlist(&em->verts),
+                        BLI_countlist(&em->edges), BLI_countlist(&em->faces));
 
        emdm->dm.getMinMax = emDM_getMinMax;
 
        emdm->dm.getNumVerts = emDM_getNumVerts;
+       emdm->dm.getNumEdges = emDM_getNumEdges;
        emdm->dm.getNumFaces = emDM_getNumFaces;
+
+       emdm->dm.getVert = emDM_getVert;
+       emdm->dm.getEdge = emDM_getEdge;
+       emdm->dm.getFace = emDM_getFace;
+       emdm->dm.getVertArray = emDM_getVertArray;
+       emdm->dm.getEdgeArray = emDM_getEdgeArray;
+       emdm->dm.getFaceArray = emDM_getFaceArray;
+
        emdm->dm.foreachMappedVert = emDM_foreachMappedVert;
        emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
        emdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
@@ -925,7 +1458,19 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, float (*vertexCos)[3])
        emdm->em = em;
        emdm->vertexCos = vertexCos;
 
-       if (vertexCos) {
+       if(me->dvert) {
+               EditVert *eve;
+               int i;
+               DM_add_vert_layer(&emdm->dm, LAYERTYPE_MDEFORMVERT, 0, NULL);
+
+               for(eve = em->verts.first, i = 0; eve; eve = eve->next, ++i) {
+                       if(eve->keyindex != -1)
+                               DM_set_vert_data(&emdm->dm, i, LAYERTYPE_MDEFORMVERT,
+                                                &me->dvert[eve->keyindex]);
+               }
+       }
+
+       if(vertexCos) {
                EditVert *eve, *preveve;
                EditFace *efa;
                int totface = BLI_countlist(&em->faces);
@@ -960,7 +1505,8 @@ static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, float (*vertexCos)[3])
 
                for(i=0, eve= em->verts.first; eve; i++, eve=eve->next) {
                        float *no = emdm->vertexNos[i];
-                       /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+                       /* following Mesh convention; we use vertex coordinate itself
+                        * for normal in this case */
                        if (Normalise(no)==0.0) {
                                VECCOPY(no, vertexCos[i]);
                                Normalise(no);
@@ -986,47 +1532,44 @@ static void ssDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData,
 {
        SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
        DispListMesh *dlm = ssdm->dlm;
-       int i, index=-1;
+       int i;
+       int *index = dm->getVertDataArray(dm, LAYERTYPE_ORIGINDEX);
 
-       for (i=0; i<dlm->totvert; i++) {
+       for (i=0; i<dlm->totvert; i++, index++) {
                MVert *mv = &dlm->mvert[i];
 
-               if (mv->flag&ME_VERT_STEPINDEX) {
-                       index++;
-
-                       func(userData, index, mv->co, NULL, mv->no);
-               }
+               if(*index != ORIGINDEX_NONE)
+                       func(userData, *index, mv->co, NULL, mv->no);
        }
 }
 static void ssDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
 {
        SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
        DispListMesh *dlm = ssdm->dlm;
-       int i, index=-1;
+       int i;
+       int *index = dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX);
 
-       for (i=0; i<dlm->totedge; i++) {
+       for (i=0; i<dlm->totedge; i++, index++) {
                MEdge *med = &dlm->medge[i];
 
-               if (med->flag&ME_EDGE_STEPINDEX) index++;
-
-               if (index!=-1) {
-                       func(userData, index, dlm->mvert[med->v1].co, dlm->mvert[med->v2].co);
-               }
+               if(*index != ORIGINDEX_NONE)
+                       func(userData, *index, dlm->mvert[med->v1].co,
+                            dlm->mvert[med->v2].co);
        }
 }
 static void ssDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) 
 {
        SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
        DispListMesh *dlm = ssdm->dlm;
-       int i, index=-1;
+       int i;
+       int *index = dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX);
 
        glBegin(GL_LINES);
-       for(i=0; i<dlm->totedge; i++) {
+       for(i=0; i<dlm->totedge; i++, index++) {
                MEdge *med = &dlm->medge[i];
 
-               if (med->flag&ME_EDGE_STEPINDEX) index++;
-
-               if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index))) {
+               if(*index != ORIGINDEX_NONE
+                  && (!setDrawOptions || setDrawOptions(userData, *index))) {
                        glVertex3fv(dlm->mvert[med->v1].co);
                        glVertex3fv(dlm->mvert[med->v2].co);
                }
@@ -1038,14 +1581,13 @@ static void ssDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use
 {
        SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
        DispListMesh *dlm = ssdm->dlm;
-       int i, index=-1;
+       int i;
+       int *index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX);
 
-       for (i=0; i<dlm->totface; i++) {
+       for (i=0; i<dlm->totface; i++, index++) {
                MFace *mf = &dlm->mface[i];
 
-               if (mf->flag&ME_FACE_STEPINDEX) index++;
-
-               if(index!=-1) {
+               if(*index != ORIGINDEX_NONE) {
                        float cent[3];
                        float no[3];
 
@@ -1062,7 +1604,7 @@ static void ssDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use
                                VecMulf(cent, 0.33333333333f);
                        }
 
-                       func(userData, index, cent, no);
+                       func(userData, *index, cent, no);
                }
        }
 }
@@ -1253,9 +1795,10 @@ static void ssDM_drawFacesTex_common(DerivedMesh *dm, int (*drawParams)(TFace *t
        MFace *mface= dlm->mface;
        TFace *tface = dlm->tface;
        float *nors = dlm->nors;
-       int a, index=-1;
+       int a;
+       int *index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX);
        
-       for (a=0; a<dlm->totface; a++) {
+       for (a=0; a<dlm->totface; a++, index++) {
                MFace *mf= &mface[a];
                TFace *tf = tface?&tface[a]:NULL;
                int flag;
@@ -1265,8 +1808,8 @@ static void ssDM_drawFacesTex_common(DerivedMesh *dm, int (*drawParams)(TFace *t
                        flag = drawParams(tf, mf->mat_nr);
                }
                else {
-                       if (mf->flag&ME_FACE_STEPINDEX) index++;
-                       flag = drawParamsMapped(userData, index);
+                       if(*index != ORIGINDEX_NONE)
+                               flag = drawParamsMapped(userData, *index);
                }
 
                if (flag==0) {
@@ -1324,15 +1867,16 @@ static void ssDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
        MVert *mvert= dlm->mvert;
        MFace *mface= dlm->mface;
        float *nors = dlm->nors;
-       int i, index=-1;
+       int i;
+       int *index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX);
 
-       for (i=0; i<dlm->totface; i++) {
+       for (i=0; i<dlm->totface; i++, index++) {
                MFace *mf = &mface[i];
-               int drawSmooth = 1;
-
-               if (mf->flag&ME_FACE_STEPINDEX) index++;
+               int drawSmooth = (mf->flag & ME_SMOOTH);
 
-               if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index, &drawSmooth))) {
+               if(*index != ORIGINDEX_NONE
+                  && (!setDrawOptions
+                      || setDrawOptions(userData, *index, &drawSmooth))) {
                        unsigned char *cp = NULL;
 
                        if (useColors) {
@@ -1412,6 +1956,14 @@ static int ssDM_getNumVerts(DerivedMesh *dm)
 
        return ssdm->dlm->totvert;
 }
+
+static int ssDM_getNumEdges(DerivedMesh *dm)
+{
+       SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
+
+       return ssdm->dlm->totedge;
+}
+
 static int ssDM_getNumFaces(DerivedMesh *dm)
 {
        SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
@@ -1419,6 +1971,39 @@ static int ssDM_getNumFaces(DerivedMesh *dm)
        return ssdm->dlm->totface;
 }
 
+void ssDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+       *vert_r = ((SSDerivedMesh *)dm)->dlm->mvert[index];
+}
+
+void ssDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+       *edge_r = ((SSDerivedMesh *)dm)->dlm->medge[index];
+}
+
+void ssDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+       *face_r = ((SSDerivedMesh *)dm)->dlm->mface[index];
+}
+
+void ssDM_getVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+       SSDerivedMesh *ssdm = (SSDerivedMesh *)dm;
+       memcpy(vert_r, ssdm->dlm->mvert, sizeof(*vert_r) * ssdm->dlm->totvert);
+}
+
+void ssDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+       SSDerivedMesh *ssdm = (SSDerivedMesh *)dm;
+       memcpy(edge_r, ssdm->dlm->medge, sizeof(*edge_r) * ssdm->dlm->totedge);
+}
+
+void ssDM_getFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+       SSDerivedMesh *ssdm = (SSDerivedMesh *)dm;
+       memcpy(face_r, ssdm->dlm->mface, sizeof(*face_r) * ssdm->dlm->totface);
+}
+
 static DispListMesh *ssDM_convertToDispListMesh(DerivedMesh *dm, int allowShared)
 {
        SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
@@ -1434,6 +2019,8 @@ static void ssDM_release(DerivedMesh *dm)
 {
        SSDerivedMesh *ssdm = (SSDerivedMesh*) dm;
 
+       DM_release(dm);
+
        displistmesh_free(ssdm->dlm);
 
        MEM_freeN(dm);
@@ -1443,10 +2030,21 @@ DerivedMesh *derivedmesh_from_displistmesh(DispListMesh *dlm, float (*vertexCos)
 {
        SSDerivedMesh *ssdm = MEM_callocN(sizeof(*ssdm), "ssdm");
 
+       DM_init(&ssdm->dm, dlm->totvert, dlm->totedge, dlm->totface);
+
        ssdm->dm.getMinMax = ssDM_getMinMax;
 
        ssdm->dm.getNumVerts = ssDM_getNumVerts;
+       ssdm->dm.getNumEdges = ssDM_getNumEdges;
        ssdm->dm.getNumFaces = ssDM_getNumFaces;
+
+       ssdm->dm.getVert = ssDM_getVert;
+       ssdm->dm.getEdge = ssDM_getEdge;
+       ssdm->dm.getFace = ssDM_getFace;
+       ssdm->dm.getVertArray = ssDM_getVertArray;
+       ssdm->dm.getEdgeArray = ssDM_getEdgeArray;
+       ssdm->dm.getFaceArray = ssDM_getFaceArray;
+
        ssdm->dm.convertToDispListMesh = ssDM_convertToDispListMesh;
 
        ssdm->dm.getVertCos = ssDM_getVertCos;
@@ -1991,27 +2589,36 @@ DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md)
 
                MEM_freeN(deformedVerts);
        } else {
-               dm = mti->applyModifier(md, ob, NULL, NULL, 0, 0);
+               DerivedMesh *tdm = getMeshDerivedMesh(me, ob, NULL);
+               dm = mti->applyModifier(md, ob, tdm, 0, 0);
+
+               if(tdm != dm) tdm->release(tdm);
        }
 
        return dm;
 }
 
-static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedMesh **deform_r, DerivedMesh **final_r, int useRenderParams, int useDeform, int needMapping)
+static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3],
+                                DerivedMesh **deform_r, DerivedMesh **final_r,
+                                int useRenderParams, int useDeform,
+                                int needMapping)
 {
        Mesh *me = ob->data;
-       ModifierData *md= modifiers_getVirtualModifierList(ob);
+       ModifierData *md = modifiers_getVirtualModifierList(ob);
        float (*deformedVerts)[3] = NULL;
        DerivedMesh *dm;
        int numVerts = me->totvert;
        int fluidsimMeshUsed = 0;
+       int required_mode;
 
        modifiers_clearErrors(ob);
 
-       if (deform_r) *deform_r = NULL;
+       if(deform_r) *deform_r = NULL;
        *final_r = NULL;
 
-       /* replace original mesh by fluidsim surface mesh for fluidsim domain objects */
+       /* replace original mesh by fluidsim surface mesh for fluidsim
+        * domain objects
+        */
        if((G.obedit!=ob) && !needMapping) {
                if (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) {
                        if(ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN) {
@@ -2023,30 +2630,35 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM
                        }
                }
        }
-       
-       if (useDeform) {
-               if(do_ob_key(ob))       /* shape key makes deform verts */
+
+       if(useRenderParams) required_mode = eModifierMode_Render;
+       else required_mode = eModifierMode_Realtime;
+
+       if(useDeform) {
+               if(do_ob_key(ob)) /* shape key makes deform verts */
                        deformedVerts = mesh_getVertexCos(me, &numVerts);
                
-                       /* Apply all leading deforming modifiers */
-               for (; md; md=md->next) {
+               /* Apply all leading deforming modifiers */
+               for(; md; md = md->next) {
                        ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-                       if (!(md->mode&(1<<useRenderParams))) continue;
-                       if (mti->isDisabled && mti->isDisabled(md)) continue;
+                       if((md->mode & required_mode) != required_mode) continue;
+                       if(mti->isDisabled && mti->isDisabled(md)) continue;
+
+                       if(mti->type == eModifierTypeType_OnlyDeform) {
+                               if(!deformedVerts)
+                                       deformedVerts = mesh_getVertexCos(me, &numVerts);
 
-                       if (mti->type==eModifierTypeType_OnlyDeform) {
-                               if (!deformedVerts) deformedVerts = mesh_getVertexCos(me, &numVerts);
                                mti->deformVerts(md, ob, NULL, deformedVerts, numVerts);
                        } else {
                                break;
                        }
                }
 
-                       /* Result of all leading deforming modifiers is cached for
-                        * places that wish to use the original mesh but with deformed
-                        * coordinates (vpaint, etc.)
-                        */
+               /* Result of all leading deforming modifiers is cached for
+                * places that wish to use the original mesh but with deformed
+                * coordinates (vpaint, etc.)
+                */
                if (deform_r)
 #ifdef WITH_VERSE
                        if(me->vnode) *deform_r = derivedmesh_from_versemesh(me->vnode, deformedVerts);
@@ -2056,46 +2668,50 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM
 #endif
        } else {
                if(!fluidsimMeshUsed) {
-                       // default behaviour for meshes
+                       /* default behaviour for meshes */
                        deformedVerts = inputVertexCos;
                } else {
-                       // the fluid sim mesh might have more vertices than the original 
-                       // one, so inputVertexCos shouldnt be used
+                       /* the fluid sim mesh might have more vertices than the original 
+                        * one, so inputVertexCos shouldnt be used
+                        */
                        deformedVerts = mesh_getVertexCos(me, &numVerts);
                }
        }
 
 
-               /* Now apply all remaining modifiers. If useDeform is off then skip
-                * OnlyDeform ones. 
-                */
+       /* Now apply all remaining modifiers. If useDeform is off then skip
+        * OnlyDeform ones. 
+        */
        dm = NULL;
-       for (; md; md=md->next) {
+       for(; md; md = md->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-               if (!(md->mode&(1<<useRenderParams))) continue;
-               if (mti->type==eModifierTypeType_OnlyDeform && !useDeform) continue;
-               if ((mti->flags&eModifierTypeFlag_RequiresOriginalData) && dm) {
-                       modifier_setError(md, "Internal error, modifier requires original data (bad stack position).");
+               if((md->mode & required_mode) != required_mode) continue;
+               if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue;
+               if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+                       modifier_setError(md, "Internal error, modifier requires "
+                                         "original data (bad stack position).");
                        continue;
                }
-               if (mti->isDisabled && mti->isDisabled(md)) continue;
-               if (needMapping && !modifier_supportsMapping(md)) continue;
+               if(mti->isDisabled && mti->isDisabled(md)) continue;
+               if(needMapping && !modifier_supportsMapping(md)) continue;
 
-                       /* How to apply modifier depends on (a) what we already have as
-                        * a result of previous modifiers (could be a DerivedMesh or just
-                        * deformed vertices) and (b) what type the modifier is.
-                        */
+               /* How to apply modifier depends on (a) what we already have as
+                * a result of previous modifiers (could be a DerivedMesh or just
+                * deformed vertices) and (b) what type the modifier is.
+                */
 
-               if (mti->type==eModifierTypeType_OnlyDeform) {
-                               /* No existing verts to deform, need to build them. */
-                       if (!deformedVerts) {
-                               if (dm) {
-                                               /* Deforming a derived mesh, read the vertex locations out of the mesh and
-                                                * deform them. Once done with this run of deformers verts will be written back.
-                                                */
+               if(mti->type == eModifierTypeType_OnlyDeform) {
+                       /* No existing verts to deform, need to build them. */
+                       if(!deformedVerts) {
+                               if(dm) {
+                                       /* Deforming a derived mesh, read the vertex locations
+                                        * out of the mesh and deform them. Once done with this
+                                        * run of deformers verts will be written back.
+                                        */
                                        numVerts = dm->getNumVerts(dm);
-                                       deformedVerts = MEM_mallocN(sizeof(*deformedVerts)*numVerts, "dfmv");
+                                       deformedVerts =
+                                           MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
                                        dm->getVertCos(dm, deformedVerts);
                                } else {
                                        deformedVerts = mesh_getVertexCos(me, &numVerts);
@@ -2104,38 +2720,58 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM
 
                        mti->deformVerts(md, ob, dm, deformedVerts, numVerts);
                } else {
-                               /* There are 4 cases here (have deform? have dm?) but they all are handled
-                                * by the modifier apply function, which will also free the DerivedMesh if
-                                * it exists.
-                                */
-                       DerivedMesh *ndm = mti->applyModifier(md, ob, dm, deformedVerts, useRenderParams, !inputVertexCos);
+                       DerivedMesh *ndm;
 
-                       if (ndm) {
-                               if (dm) dm->release(dm);
+                       /* apply vertex coordinates or build a DerivedMesh as necessary */
+                       if(dm) {
+                               if(deformedVerts) {
+                                       DerivedMesh *tdm = CDDM_copy(dm);
+                                       dm->release(dm);
+                                       dm = tdm;
+
+                                       CDDM_apply_vert_coords(dm, deformedVerts);
+                                       CDDM_calc_normals(dm);
+                               }
+                       } else {
+                               dm = CDDM_from_mesh(me);
+
+                               if(deformedVerts) {
+                                       CDDM_apply_vert_coords(dm, deformedVerts);
+                                       CDDM_calc_normals(dm);
+                               }
+                       }
+
+                       ndm = mti->applyModifier(md, ob, dm, useRenderParams,
+                                                !inputVertexCos);
+
+                       if(ndm) {
+                               /* if the modifier returned a new dm, release the old one */
+                               if(dm && dm != ndm) dm->release(dm);
 
                                dm = ndm;
 
-                               if (deformedVerts) {
-                                       if (deformedVerts!=inputVertexCos) {
+                               if(deformedVerts) {
+                                       if(deformedVerts != inputVertexCos)
                                                MEM_freeN(deformedVerts);
-                                       }
+
                                        deformedVerts = NULL;
                                }
                        } 
                }
        }
 
-               /* Yay, we are done. If we have a DerivedMesh and deformed vertices need to apply
-                * these back onto the DerivedMesh. If we have no DerivedMesh then we need to build
-                * one.
-                */
-       if (dm && deformedVerts) {
-               DispListMesh *dlm = dm->convertToDispListMesh(dm, 0);
+       /* Yay, we are done. If we have a DerivedMesh and deformed vertices
+        * need to apply these back onto the DerivedMesh. If we have no
+        * DerivedMesh then we need to build one.
+        */
+       if(dm && deformedVerts) {
+               *final_r = CDDM_copy(dm);
 
                dm->release(dm);
 
-               *final_r = derivedmesh_from_displistmesh(dlm, deformedVerts);
-       } else if (dm) {
+               CDDM_apply_vert_coords(*final_r, deformedVerts);
+               CDDM_calc_normals(*final_r);
+       } else if(dm) {
                *final_r = dm;
        } else {
 #ifdef WITH_VERSE
@@ -2146,10 +2782,10 @@ static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3], DerivedM
 #endif
        }
 
-       if (deformedVerts && deformedVerts!=inputVertexCos) {
+       if(deformedVerts && deformedVerts != inputVertexCos)
                MEM_freeN(deformedVerts);
-       }
-       // restore mesh in any case
+
+       /* restore mesh in any case */
        if(fluidsimMeshUsed) ob->data = ob->fluidsimSettings->orgMesh;
 }
 
@@ -2175,40 +2811,43 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r)
        float (*deformedVerts)[3] = NULL;
        DerivedMesh *dm;
        int i, numVerts = 0, cageIndex = modifiers_getCageIndex(ob, NULL);
+       int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
 
        modifiers_clearErrors(ob);
 
-       if (cage_r && cageIndex==-1) {
-               *cage_r = getEditMeshDerivedMesh(em, NULL);
+       if(cage_r && cageIndex == -1) {
+               *cage_r = getEditMeshDerivedMesh(em, ob, NULL);
        }
 
        dm = NULL;
-       for (i=0,md= ob->modifiers.first; md; i++,md=md->next) {
+       for(i = 0, md = ob->modifiers.first; md; i++, md = md->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-               if (!(md->mode&eModifierMode_Realtime)) continue;
-               if (!(md->mode&eModifierMode_Editmode)) continue;
-               if ((mti->flags&eModifierTypeFlag_RequiresOriginalData) && dm) {
-                       modifier_setError(md, "Internal error, modifier requires original data (bad stack position).");
+               if((md->mode & required_mode) != required_mode) continue;
+               if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+                       modifier_setError(md, "Internal error, modifier requires"
+                                         "original data (bad stack position).");
                        continue;
                }
-               if (mti->isDisabled && mti->isDisabled(md)) continue;
-               if (!(mti->flags&eModifierTypeFlag_SupportsEditmode)) continue;
+               if(mti->isDisabled && mti->isDisabled(md)) continue;
+               if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
 
-                       /* How to apply modifier depends on (a) what we already have as
-                        * a result of previous modifiers (could be a DerivedMesh or just
-                        * deformed vertices) and (b) what type the modifier is.
-                        */
+               /* How to apply modifier depends on (a) what we already have as
+                * a result of previous modifiers (could be a DerivedMesh or just
+                * deformed vertices) and (b) what type the modifier is.
+                */
 
-               if (mti->type==eModifierTypeType_OnlyDeform) {
-                               /* No existing verts to deform, need to build them. */
-                       if (!deformedVerts) {
-                               if (dm) {
-                                               /* Deforming a derived mesh, read the vertex locations out of the mesh and
-                                                * deform them. Once done with this run of deformers verts will be written back.
-                                                */
+               if(mti->type == eModifierTypeType_OnlyDeform) {
+                       /* No existing verts to deform, need to build them. */
+                       if(!deformedVerts) {
+                               if(dm) {
+                                       /* Deforming a derived mesh, read the vertex locations
+                                        * out of the mesh and deform them. Once done with this
+                                        * run of deformers verts will be written back.
+                                        */
                                        numVerts = dm->getNumVerts(dm);
-                                       deformedVerts = MEM_mallocN(sizeof(*deformedVerts)*numVerts, "dfmv");
+                                       deformedVerts =
+                                           MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
                                        dm->getVertCos(dm, deformedVerts);
                                } else {
                                        deformedVerts = editmesh_getVertexCos(em, &numVerts);
@@ -2217,14 +2856,37 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r)
 
                        mti->deformVertsEM(md, ob, em, dm, deformedVerts, numVerts);
                } else {
-                               /* There are 4 cases here (have deform? have dm?) but they all are handled
-                                * by the modifier apply function, which will also free the DerivedMesh if
-                                * it exists.
-                                */
-                       DerivedMesh *ndm = mti->applyModifierEM(md, ob, em, dm, deformedVerts);
+                       DerivedMesh *ndm;
+
+                       /* apply vertex coordinates or build a DerivedMesh as necessary */
+                       if(dm) {
+                               if(deformedVerts) {
+                                       DerivedMesh *tdm = CDDM_copy(dm);
+                                       if(!(cage_r && dm == *cage_r)) dm->release(dm);
+                                       dm = tdm;
+
+                                       CDDM_apply_vert_coords(dm, deformedVerts);
+                                       CDDM_calc_normals(dm);
+                               } else if(cage_r && dm == *cage_r) {
+                                       /* dm may be changed by this modifier, so we need to copy it
+                                        */
+                                       dm = CDDM_copy(dm);
+                               }
+
+                       } else {
+                               dm = CDDM_from_editmesh(em, ob->data);
+
+                               if(deformedVerts) {
+                                       CDDM_apply_vert_coords(dm, deformedVerts);
+                                       CDDM_calc_normals(dm);
+                               }
+                       }
+
+                       ndm = mti->applyModifierEM(md, ob, em, dm);
 
                        if (ndm) {
-                               if (dm && (!cage_r || dm!=*cage_r)) dm->release(dm);
+                               if(dm && dm != ndm)
+                                       dm->release(dm);
 
                                dm = ndm;
 
@@ -2235,36 +2897,37 @@ static void editmesh_calc_modifiers(DerivedMesh **cage_r, DerivedMesh **final_r)
                        }
                }
 
-               if (cage_r && i==cageIndex) {
-                       if (dm && deformedVerts) {
-                               DispListMesh *dlm;
-
-                               dlm = dm->convertToDispListMesh(dm, 0);
-
-                               *cage_r = derivedmesh_from_displistmesh(dlm, deformedVerts);
-                       } else if (dm) {
+               if(cage_r && i == cageIndex) {
+                       if(dm && deformedVerts) {
+                               *cage_r = CDDM_copy(dm);
+                               CDDM_apply_vert_coords(*cage_r, deformedVerts);
+                       } else if(dm) {
                                *cage_r = dm;
                        } else {
-                               *cage_r = getEditMeshDerivedMesh(em, deformedVerts?MEM_dupallocN(deformedVerts):NULL);
+                               *cage_r =
+                                   getEditMeshDerivedMesh(em, ob,
+                                       deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
                        }
                }
        }
 
-               /* Yay, we are done. If we have a DerivedMesh and deformed vertices need to apply
-                * these back onto the DerivedMesh. If we have no DerivedMesh then we need to build
-                * one.
-                */
-       if (dm && deformedVerts) {
-               DispListMesh *dlm = dm->convertToDispListMesh(dm, 0);
+       /* Yay, we are done. If we have a DerivedMesh and deformed vertices need
+        * to apply these back onto the DerivedMesh. If we have no DerivedMesh
+        * then we need to build one.
+        */
+       if(dm && deformedVerts) {
+               *final_r = CDDM_copy(dm);
 
-               if (!cage_r || dm!=*cage_r) dm->release(dm);
+               if(!(cage_r && dm == *cage_r)) dm->release(dm);
+
+               CDDM_apply_vert_coords(*final_r, deformedVerts);
+               CDDM_calc_normals(*final_r);
 
-               *final_r = derivedmesh_from_displistmesh(dlm, deformedVerts);
                MEM_freeN(deformedVerts);
        } else if (dm) {
                *final_r = dm;
        } else {
-               *final_r = getEditMeshDerivedMesh(em, deformedVerts);
+               *final_r = getEditMeshDerivedMesh(em, ob, deformedVerts);
        }
 }
 
@@ -2384,18 +3047,22 @@ static void mesh_build_data(Object *ob)
                        MCol *mcol = me->mcol;
                        TFace *tface =  me->tface;
 
-                       me->tface = NULL;
                        me->mcol = (MCol*) calc_weightpaint_colors(ob);
+                       if(me->tface) {
+                               me->tface = MEM_dupallocN(me->tface);
+                               mcol_to_tface(me, 1);
+                       }
 
                        mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, &ob->derivedFinal, 0, 1,
                                            needMapping);
 
-                       MEM_freeN(me->mcol);
+                       if(me->mcol) MEM_freeN(me->mcol);
+                       if(me->tface) MEM_freeN(me->tface);
                        me->mcol = mcol;
                        me->tface = tface;
                } else {
-                       mesh_calc_modifiers(ob, NULL, &ob->derivedDeform, &ob->derivedFinal, 0, 1,
-                                           needMapping);
+                       mesh_calc_modifiers(ob, NULL, &ob->derivedDeform,
+                                           &ob->derivedFinal, 0, 1, needMapping);
                }
 
                INIT_MINMAX(min, max);
@@ -2525,7 +3192,7 @@ DerivedMesh *editmesh_get_derived_cage(int *needsFree_r)
 
 DerivedMesh *editmesh_get_derived_base(void)
 {
-       return getEditMeshDerivedMesh(G.editMesh, NULL);
+       return getEditMeshDerivedMesh(G.editMesh, G.obedit, NULL);
 }
 
 
@@ -2536,6 +3203,10 @@ static void make_vertexcosnos__mapFunc(void *userData, int index, float *co, flo
        float *vec = userData;
        
        vec+= 6*index;
+
+       /* check if we've been here before (normal should not be 0) */
+       if(vec[3] || vec[4] || vec[5]) return;
+
        VECCOPY(vec, co);
        vec+= 3;
        if(no_f) {
@@ -2563,7 +3234,7 @@ float *mesh_get_mapped_verts_nors(Object *ob)
                return NULL;
        
        dm= mesh_get_derived_final(ob, &needsFree);
-       vertexcosnos= MEM_mallocN(6*sizeof(float)*me->totvert, "vertexcosnos map");
+       vertexcosnos= MEM_callocN(6*sizeof(float)*me->totvert, "vertexcosnos map");
        
        if(dm->foreachMappedVert) {
                dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos);
index b0341e6ddccb45c71ba89e0cebca1a899c7f393b..545efdf10e6b377ae147cc1e031de58b70b90ad2 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "BKE_curve.h"
 #include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
 #include "BKE_displist.h"
 #include "BKE_global.h"
 #include "BKE_main.h"
@@ -661,16 +662,18 @@ static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, flo
        (*contrib)+=weight;
 }
 
-void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3], int numVerts, int deformflag) 
+void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
+                           float (*vertexCos)[3], int numVerts, int deformflag) 
 {
        bPoseChannel *pchan, **defnrToPC = NULL;
-       MDeformVert *dverts= NULL;
+       MDeformVert *dverts = NULL;
        float obinv[4][4], premat[4][4], postmat[4][4];
-       int use_envelope= deformflag & ARM_DEF_ENVELOPE;
-       int numGroups= 0;   /* safety for vertexgroup index overflow too */
+       int use_envelope = deformflag & ARM_DEF_ENVELOPE;
+       int numGroups = 0;   /* safety for vertexgroup index overflow too */
        int i;
+       int use_dverts = 0;
 
-       if(armOb==G.obedit) return;
+       if(armOb == G.obedit) return;
        
        Mat4Invert(obinv, target->obmat);
        Mat4CpyMat4(premat, target->obmat);
@@ -681,23 +684,32 @@ void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3],
        /* bone defmats are already in the channels, chan_mat */
        
        /* initialize B_bone matrices */
-       for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) {
+       for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
                if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                       if(pchan->bone->segments>1)
+                       if(pchan->bone->segments > 1)
                                pchan_b_bone_defmats(pchan);
        }
 
        /* get a vertex-deform-index to posechannel array */
        if(deformflag & ARM_DEF_VGROUP) {
-               if (target->type==OB_MESH){
+               if(target->type == OB_MESH){
                        bDeformGroup *dg;
                
                        numGroups = BLI_countlist(&target->defbase);
-                       
                        dverts = ((Mesh*)target->data)->dvert;
-                       if(dverts) {
-                               defnrToPC = MEM_callocN(sizeof(*defnrToPC)*numGroups, "defnrToBone");
-                               for (i=0,dg=target->defbase.first; dg; i++,dg=dg->next) {
+                       
+                       /* if we have a DerivedMesh, only use dverts if it has them */
+                       if(dm)
+                               if(dm->getVertData(dm, 0, LAYERTYPE_MDEFORMVERT))
+                                       use_dverts = 1;
+                               else use_dverts = 0;
+                       else if(dverts) use_dverts = 1;
+
+                       if(use_dverts) {
+                               defnrToPC = MEM_callocN(sizeof(*defnrToPC) * numGroups,
+                                                       "defnrToBone");
+                               for(i = 0, dg = target->defbase.first; dg;
+                                   i++, dg = dg->next) {
                                        defnrToPC[i] = get_pose_channel(armOb->pose, dg->name);
                                        /* exclude non-deforming bones */
                                        if(defnrToPC[i]) {
@@ -709,77 +721,84 @@ void armature_deform_verts(Object *armOb, Object *target, float (*vertexCos)[3],
                }
        }
 
-       for(i=0; i<numVerts; i++) {
+       for(i = 0; i < numVerts; i++) {
                MDeformVert *dvert;
                float *co = vertexCos[i];
                float   vec[3];
-               float   contrib=0.0;
+               float   contrib = 0.0;
                int             j;
 
-               vec[0]=vec[1]=vec[2]=0;
+               vec[0] = vec[1] = vec[2] = 0;
 
                /* Apply the object's matrix */
                Mat4MulVecfl(premat, co);
                
-               if(dverts && i<((Mesh*)target->data)->totvert)
-                       dvert= dverts+i;
-               else
-                       dvert= NULL;
+               if(use_dverts) {
+                       if(dm) dvert = dm->getVertData(dm, i, LAYERTYPE_MDEFORMVERT);
+                       else if(i < ((Mesh*)target->data)->totvert) dvert = dverts + i;
+               } else
+                       dvert = NULL;
                
                if(dvert && dvert->totweight) { // use weight groups ?
-                       int deformed= 0;
+                       int deformed = 0;
                        
-                       for (j=0; j<dvert->totweight; j++){
-                               int index= dvert->dw[j].def_nr;
-                               pchan = index<numGroups?defnrToPC[index]:NULL;
-                               if (pchan) {
-                                       float weight= dvert->dw[j].weight;
-                                       Bone *bone= pchan->bone;
+                       for(j = 0; j < dvert->totweight; j++){
+                               int index = dvert->dw[j].def_nr;
+                               pchan = index < numGroups?defnrToPC[index]:NULL;
+                               if(pchan) {
+                                       float weight = dvert->dw[j].weight;
+                                       Bone *bone = pchan->bone;
                                        
-                                       deformed= 1;
+                                       deformed = 1;
                                        
                                        if(bone && bone->flag & BONE_MULT_VG_ENV) {
-                                               
-                                               weight*= distfactor_to_bone(co, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
+                                               weight *= distfactor_to_bone(co, bone->arm_head,
+                                                                            bone->arm_tail,
+                                                                            bone->rad_head,
+                                                                            bone->rad_tail,
+                                                                            bone->dist);
                                        }
                                        pchan_bone_deform(pchan, weight, vec, co, &contrib);
                                }
                        }
-                       /* if there are vertexgroups but not groups with bones (like for softbody groups) */
-                       if(deformed==0 && use_envelope) {
-                               for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) {
+                       /* if there are vertexgroups but not groups with bones
+                        * (like for softbody groups)
+                        */
+                       if(deformed == 0 && use_envelope) {
+                               for(pchan = armOb->pose->chanbase.first; pchan;
+                                   pchan = pchan->next) {
                                        if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                               contrib+= dist_bone_deform(pchan, vec, co);
+                                               contrib += dist_bone_deform(pchan, vec, co);
                                }
                        }
                }
                else if(use_envelope) {
-                       for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) {
+                       for(pchan = armOb->pose->chanbase.first; pchan;
+                           pchan = pchan->next) {
                                if(!(pchan->bone->flag & BONE_NO_DEFORM))
-                                       contrib+= dist_bone_deform(pchan, vec, co);
+                                       contrib += dist_bone_deform(pchan, vec, co);
                        }
                }
 
-               if (contrib>0.0){
-                       vec[0]/=contrib;
-                       vec[1]/=contrib;
-                       vec[2]/=contrib;
+               if(contrib > 0.0){
+                       vec[0] /= contrib;
+                       vec[1] /= contrib;
+                       vec[2] /= contrib;
                }
 
                VecAddf(co, vec, co);
                Mat4MulVecfl(postmat, co);
        }
 
-       if (defnrToPC) MEM_freeN(defnrToPC);
+       if(defnrToPC) MEM_freeN(defnrToPC);
        
        /* free B_bone matrices */
-       for(pchan= armOb->pose->chanbase.first; pchan; pchan= pchan->next) {
+       for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
                if(pchan->b_bone_mats) {
                        MEM_freeN(pchan->b_bone_mats);
-                       pchan->b_bone_mats= NULL;
+                       pchan->b_bone_mats = NULL;
                }
        }
-       
 }
 
 /* ************ END Armature Deform ******************* */
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
new file mode 100644 (file)
index 0000000..2429da6
--- /dev/null
@@ -0,0 +1,1045 @@
+/*
+* $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) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Implementation of CDDerivedMesh.
+*
+* BKE_cdderivedmesh.h contains the function prototypes for this file.
+*
+*/ 
+
+/* TODO maybe BIF_gl.h should include string.h? */
+#include <string.h>
+#include "BIF_gl.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+#include "BLI_ghash.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include <string.h>
+#include <limits.h>
+
+
+/**************** DerivedMesh interface functions ****************/
+static int cdDM_getNumVerts(DerivedMesh *dm)
+{
+       return dm->vertData.numElems;
+}
+
+static int cdDM_getNumFaces(DerivedMesh *dm)
+{
+       return dm->faceData.numElems;
+}
+
+static int cdDM_getNumEdges(DerivedMesh *dm)
+{
+       return dm->edgeData.numElems;
+}
+
+static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+       *vert_r = *CDDM_get_vert(dm, index);
+}
+
+static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+       *edge_r = *CDDM_get_edge(dm, index);
+}
+
+static void cdDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+       *face_r = *CDDM_get_face(dm, index);
+}
+
+static void cdDM_getVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+       memcpy(vert_r, CDDM_get_verts(dm), sizeof(*vert_r) * dm->getNumVerts(dm));
+}
+
+static void cdDM_getEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+       memcpy(edge_r, CDDM_get_edges(dm), sizeof(*edge_r) * dm->getNumEdges(dm));
+}
+
+static void cdDM_getFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+       memcpy(face_r, CDDM_get_faces(dm), sizeof(*face_r) * dm->getNumFaces(dm));
+}
+
+static void cdDM_foreachMappedVert(
+                           DerivedMesh *dm,
+                           void (*func)(void *userData, int index, float *co,
+                                        float *no_f, short *no_s),
+                           void *userData)
+{
+       int i;
+       int maxVerts = dm->getNumVerts(dm);
+       MVert *mv = CDDM_get_verts(dm);
+       int *index = DM_get_vert_data_layer(dm, LAYERTYPE_ORIGINDEX);
+
+       for(i = 0; i < maxVerts; i++, mv++, index++) {
+               if(*index == ORIGINDEX_NONE) continue;
+
+               func(userData, *index, mv->co, NULL, mv->no);
+       }
+}
+
+static void cdDM_foreachMappedEdge(
+                           DerivedMesh *dm,
+                           void (*func)(void *userData, int index,
+                                        float *v0co, float *v1co),
+                           void *userData)
+{
+       int i;
+       int maxEdges = dm->getNumEdges(dm);
+       MEdge *med = CDDM_get_edges(dm);
+       MVert *mv = CDDM_get_verts(dm);
+       int *index = DM_get_edge_data_layer(dm, LAYERTYPE_ORIGINDEX);
+
+       for(i = 0; i < maxEdges; i++, med++, index++) {
+               if(*index == ORIGINDEX_NONE) continue;
+
+               func(userData, *index, mv[med->v1].co, mv[med->v2].co);
+       }
+}
+
+static void cdDM_foreachMappedFaceCenter(
+                           DerivedMesh *dm,
+                           void (*func)(void *userData, int index,
+                                        float *cent, float *no),
+                           void *userData)
+{
+       int i;
+       int maxFaces = dm->getNumFaces(dm);
+       MFace *mf = CDDM_get_faces(dm);
+       MVert *mv = CDDM_get_verts(dm);
+       int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX);
+
+       for(i = 0; i < maxFaces; i++, mf++, index++) {
+               float cent[3];
+               float no[3];
+
+               if(*index == ORIGINDEX_NONE) continue;
+
+               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);
+               } else {
+                       CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+                                     mv[mf->v3].co, no);
+                       VecMulf(cent, 0.33333333333f);
+               }
+
+               func(userData, *index, cent, no);
+       }
+}
+
+static DispListMesh *cdDM_convertToDispListMesh(DerivedMesh *dm,
+                                                int allowShared)
+{
+       DispListMesh *dlm = MEM_callocN(sizeof(*dlm),
+                                       "cdDM_convertToDispListMesh dlm");
+
+       dlm->totvert = dm->vertData.numElems;
+       dlm->totedge = dm->edgeData.numElems;
+       dlm->totface = dm->faceData.numElems;
+       dlm->mvert = dm->dupVertArray(dm);
+       dlm->medge = dm->dupEdgeArray(dm);
+       dlm->mface = dm->dupFaceArray(dm);
+
+       dlm->tface = dm->getFaceDataArray(dm, LAYERTYPE_TFACE);
+       if(dlm->tface)
+               dlm->tface = MEM_dupallocN(dlm->tface);
+
+       dlm->mcol = dm->getFaceDataArray(dm, LAYERTYPE_MCOL);
+       if(dlm->mcol)
+               dlm->mcol = MEM_dupallocN(dlm->mcol);
+
+       dlm->nors = NULL;
+       dlm->dontFreeVerts = dlm->dontFreeOther = dlm->dontFreeNors = 0;
+
+       return dlm;
+}
+
+static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+{
+       int i;
+
+       for(i = 0; i < dm->vertData.numElems; i++) {
+               DO_MINMAX(CDDM_get_vert(dm, i)->co, min_r, max_r);
+       }
+}
+
+static void cdDM_getVertCo(DerivedMesh *dm, int index, float co_r[3])
+{
+       VECCOPY(co_r, CDDM_get_vert(dm, index)->co);
+}
+
+static void cdDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
+{
+       int i;
+       MVert *mv = CDDM_get_verts(dm);
+
+       for(i = 0; i < dm->vertData.numElems; i++, mv++)
+               VECCOPY(cos_r[i], mv->co);
+}
+
+static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
+{
+       short *no = CDDM_get_vert(dm, index)->no;
+
+       no_r[0] = no[0] / 32767.f;
+       no_r[1] = no[1] / 32767.f;
+       no_r[2] = no[2] / 32767.f;
+}
+
+static void cdDM_drawVerts(DerivedMesh *dm)
+{
+       int i;
+       MVert *mv = CDDM_get_verts(dm);
+
+       glBegin(GL_POINTS);
+       for(i = 0; i < dm->vertData.numElems; i++, mv++)
+               glVertex3fv(mv->co);
+       glEnd();
+}
+
+static void cdDM_drawUVEdges(DerivedMesh *dm)
+{
+       int i;
+       TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE);
+       MFace *mf = CDDM_get_faces(dm);
+
+       if(tf) {
+               glBegin(GL_LINES);
+               for(i = 0; i < dm->faceData.numElems; i++, tf++, mf++) {
+                       if(!(tf->flag&TF_HIDE)) {
+                               glVertex2fv(tf->uv[0]);
+                               glVertex2fv(tf->uv[1]);
+
+                               glVertex2fv(tf->uv[1]);
+                               glVertex2fv(tf->uv[2]);
+
+                               if(!mf->v4) {
+                                       glVertex2fv(tf->uv[2]);
+                                       glVertex2fv(tf->uv[0]);
+                               } else {
+                                       glVertex2fv(tf->uv[2]);
+                                       glVertex2fv(tf->uv[3]);
+
+                                       glVertex2fv(tf->uv[3]);
+                                       glVertex2fv(tf->uv[0]);
+                               }
+                       }
+               }
+               glEnd();
+       }
+}
+
+static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
+{
+       int i;
+       MEdge *medge = CDDM_get_edges(dm);
+       MVert *mvert = CDDM_get_verts(dm);
+               
+       glBegin(GL_LINES);
+       for(i = 0; i < dm->edgeData.numElems; i++, medge++) {
+               if((medge->flag&ME_EDGEDRAW)
+                  && (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) {
+                       glVertex3fv(mvert[medge->v1].co);
+                       glVertex3fv(mvert[medge->v2].co);
+               }
+       }
+       glEnd();
+}
+
+static void cdDM_drawLooseEdges(DerivedMesh *dm)
+{
+       MEdge *medge = CDDM_get_edges(dm);
+       MVert *mvert = CDDM_get_verts(dm);
+       int i;
+
+       glBegin(GL_LINES);
+       for(i = 0; i < dm->edgeData.numElems; i++, medge++) {
+               if(medge->flag&ME_LOOSEEDGE) {
+                       glVertex3fv(mvert[medge->v1].co);
+                       glVertex3fv(mvert[medge->v2].co);
+               }
+       }
+       glEnd();
+}
+
+static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
+{
+       int a;
+       int glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
+       MFace *mface = CDDM_get_faces(dm);
+       MVert *mvert = CDDM_get_verts(dm);
+
+#define PASSVERT(index) {                                              \
+       if(shademodel == GL_SMOOTH) {                           \
+               short *no = mvert[index].no;                    \
+               glNormal3sv(no);                                                \
+       }                                                                                       \
+       glVertex3fv(mvert[index].co);   \
+}
+
+       glBegin(glmode = GL_QUADS);
+       for(a = 0; a < dm->faceData.numElems; a++, mface++) {
+               int new_glmode, new_matnr, new_shademodel;
+
+               new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+               new_matnr = mface->mat_nr + 1;
+               new_shademodel = (mface->flag & ME_SMOOTH)?GL_SMOOTH:GL_FLAT;
+               
+               if(new_glmode != glmode || new_matnr != matnr
+                  || new_shademodel != shademodel) {
+                       glEnd();
+
+                       drawCurrentMat = setMaterial(matnr = new_matnr);
+
+                       glShadeModel(shademodel = new_shademodel);
+                       glBegin(glmode = new_glmode);
+               } 
+               
+               if(drawCurrentMat) {
+                       /* TODO make this better (cache facenormals as layer?) */
+                       if(shademodel == GL_FLAT) {
+                               float nor[3];
+                               if(mface->v4) {
+                                       CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                      mvert[mface->v3].co, mvert[mface->v4].co,
+                                                      nor);
+                               } else {
+                                       CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                     mvert[mface->v3].co, nor);
+                               }
+                               glNormal3fv(nor);
+                       }
+
+                       PASSVERT(mface->v1);
+                       PASSVERT(mface->v2);
+                       PASSVERT(mface->v3);
+                       if(mface->v4) {
+                               PASSVERT(mface->v4);
+                       }
+               }
+       }
+       glEnd();
+
+       glShadeModel(GL_FLAT);
+#undef PASSVERT
+}
+
+static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2)
+{
+       int a, glmode;
+       unsigned char *cp1, *cp2;
+       MFace *mface = CDDM_get_faces(dm);
+       MVert *mvert = CDDM_get_verts(dm);
+
+       cp1 = col1;
+       if(col2) {
+               cp2 = col2;
+       } else {
+               cp2 = NULL;
+               useTwoSided = 0;
+       }
+
+       /* there's a conflict here... twosided colors versus culling...? */
+       /* defined by history, only texture faces have culling option */
+       /* we need that as mesh option builtin, next to double sided lighting */
+       if(col1 && col2)
+               glEnable(GL_CULL_FACE);
+       
+       glShadeModel(GL_SMOOTH);
+       glBegin(glmode = GL_QUADS);
+       for(a = 0; a < dm->faceData.numElems; a++, mface++, cp1 += 16) {
+               int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+
+               if(new_glmode != glmode) {
+                       glEnd();
+                       glBegin(glmode = new_glmode);
+               }
+                       
+               glColor3ub(cp1[3], cp1[2], cp1[1]);
+               glVertex3fv(mvert[mface->v1].co);
+               glColor3ub(cp1[7], cp1[6], cp1[5]);
+               glVertex3fv(mvert[mface->v2].co);
+               glColor3ub(cp1[11], cp1[10], cp1[9]);
+               glVertex3fv(mvert[mface->v3].co);
+               if(mface->v4) {
+                       glColor3ub(cp1[15], cp1[14], cp1[13]);
+                       glVertex3fv(mvert[mface->v4].co);
+               }
+                       
+               if(useTwoSided) {
+                       glColor3ub(cp2[11], cp2[10], cp2[9]);
+                       glVertex3fv(mvert[mface->v3].co );
+                       glColor3ub(cp2[7], cp2[6], cp2[5]);
+                       glVertex3fv(mvert[mface->v2].co );
+                       glColor3ub(cp2[3], cp2[2], cp2[1]);
+                       glVertex3fv(mvert[mface->v1].co );
+                       if(mface->v4) {
+                               glColor3ub(cp2[15], cp2[14], cp2[13]);
+                               glVertex3fv(mvert[mface->v4].co );
+                       }
+               }
+               if(col2) cp2 += 16;
+       }
+       glEnd();
+
+       glShadeModel(GL_FLAT);
+       glDisable(GL_CULL_FACE);
+}
+
+static void cdDM_drawFacesTex_common(DerivedMesh *dm,
+               int (*drawParams)(TFace *tface, int matnr),
+               int (*drawParamsMapped)(void *userData, int index),
+               void *userData) 
+{
+       int i;
+       MFace *mf = CDDM_get_faces(dm);
+       TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE);
+       MVert *mv = CDDM_get_verts(dm);
+       int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX);
+
+       for(i = 0; i < dm->faceData.numElems; i++, mf++, index++) {
+               MVert *mvert;
+               int flag;
+               unsigned char *cp = NULL;
+
+               if(drawParams)
+                       if(tf) flag = drawParams(&tf[i], mf->mat_nr);
+                       else flag = drawParams(NULL, mf->mat_nr);
+               else if(*index != ORIGINDEX_NONE)
+                       flag = drawParamsMapped(userData, *index);
+               else
+                       flag = 0;
+
+               if(flag == 0) {
+                       continue;
+               } else if(flag == 1) {
+                       if(tf) {
+                               cp = (unsigned char *)tf[i].col;
+                       } else {
+                               cp = DM_get_face_data(dm, i, LAYERTYPE_MCOL);
+                       }
+               }
+
+               /* TODO make this better (cache facenormals as layer?) */
+               if(!(mf->flag&ME_SMOOTH)) {
+                       float nor[3];
+                       if(mf->v4) {
+                               CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+                                                          mv[mf->v3].co, mv[mf->v4].co, nor);
+                       } else {
+                               CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+                                                         mv[mf->v3].co, nor);
+                       }
+                       glNormal3fv(nor);
+               }
+
+               glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
+               if(tf) glTexCoord2fv(tf[i].uv[0]);
+               if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+               mvert = &mv[mf->v1];
+               if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+               glVertex3fv(mvert->co);
+                       
+               if(tf) glTexCoord2fv(tf[i].uv[1]);
+               if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+               mvert = &mv[mf->v2];
+               if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+               glVertex3fv(mvert->co);
+
+               if(tf) glTexCoord2fv(tf[i].uv[2]);
+               if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+               mvert = &mv[mf->v3];
+               if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+               glVertex3fv(mvert->co);
+
+               if(mf->v4) {
+                       if(tf) glTexCoord2fv(tf[i].uv[3]);
+                       if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+                       mvert = &mv[mf->v4];
+                       if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+                       glVertex3fv(mvert->co);
+               }
+               glEnd();
+       }
+}
+
+static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(TFace *tface, int matnr))
+{
+       cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+}
+
+static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
+{
+       int i;
+       MFace *mf = CDDM_get_faces(dm);
+       MVert *mv = CDDM_get_verts(dm);
+       int *index = DM_get_face_data_layer(dm, LAYERTYPE_ORIGINDEX);
+       TFace *tf = DM_get_face_data_layer(dm, LAYERTYPE_TFACE);
+       MCol *mc = DM_get_face_data_layer(dm, LAYERTYPE_MCOL);
+
+       for(i = 0; i < dm->faceData.numElems; i++, mf++, index++) {
+               int drawSmooth = (mf->flag & ME_SMOOTH);
+
+               if(setDrawOptions && *index == ORIGINDEX_NONE) continue;
+
+               if(!setDrawOptions || setDrawOptions(userData, *index, &drawSmooth)) {
+                       unsigned char *cp = NULL;
+
+                       if(useColors) {
+                               if(tf) {
+                                       cp = (unsigned char *)tf[i].col;
+                               } else if(mc) {
+                                       cp = (unsigned char *)&mc[i * 4];
+                               }
+                       }
+
+                       glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+                       glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
+
+                       if(!drawSmooth) {
+                               /* TODO make this better (cache facenormals as layer?) */
+                               float nor[3];
+                               if(mf->v4) {
+                                       CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+                                                                  mv[mf->v3].co, mv[mf->v4].co, nor);
+                               } else {
+                                       CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+                                                                 mv[mf->v3].co, nor);
+                               }
+                               glNormal3fv(nor);
+
+                               if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+                               glVertex3fv(mv[mf->v1].co);
+                               if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+                               glVertex3fv(mv[mf->v2].co);
+                               if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+                               glVertex3fv(mv[mf->v3].co);
+                               if(mf->v4) {
+                                       if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+                                       glVertex3fv(mv[mf->v4].co);
+                               }
+                       } else {
+                               if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+                               glNormal3sv(mv[mf->v1].no);
+                               glVertex3fv(mv[mf->v1].co);
+                               if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+                               glNormal3sv(mv[mf->v2].no);
+                               glVertex3fv(mv[mf->v2].co);
+                               if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+                               glNormal3sv(mv[mf->v3].no);
+                               glVertex3fv(mv[mf->v3].co);
+                               if(mf->v4) {
+                                       if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+                                       glNormal3sv(mv[mf->v4].no);
+                                       glVertex3fv(mv[mf->v4].co);
+                               }
+                       }
+
+                       glEnd();
+               }
+       }
+}
+
+static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+       cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+}
+
+static void cdDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+       int i;
+       int *index = DM_get_edge_data_layer(dm, LAYERTYPE_ORIGINDEX);
+       MEdge *edge = CDDM_get_edges(dm);
+       MVert *vert = CDDM_get_verts(dm);
+
+       glBegin(GL_LINES);
+       for(i = 0; i < dm->edgeData.numElems; i++, edge++, index++) {
+
+               if(setDrawOptions && *index == ORIGINDEX_NONE) continue;
+
+               if(!setDrawOptions || setDrawOptions(userData, *index)) {
+                       glVertex3fv(vert[edge->v1].co);
+                       glVertex3fv(vert[edge->v2].co);
+               }
+       }
+       glEnd();
+}
+
+static void cdDM_release(DerivedMesh *dm)
+{
+       CustomData_free(&dm->vertData);
+       CustomData_free(&dm->edgeData);
+       CustomData_free(&dm->faceData);
+
+       MEM_freeN(dm);
+}
+
+
+/**************** CDDM interface functions ****************/
+static DerivedMesh *cdDM_create(const char *desc)
+{
+       DerivedMesh *dm;
+
+       dm = MEM_callocN(sizeof(*dm), desc);
+
+       dm->getMinMax = cdDM_getMinMax;
+
+       dm->convertToDispListMesh = cdDM_convertToDispListMesh;
+
+       dm->getNumVerts = cdDM_getNumVerts;
+       dm->getNumFaces = cdDM_getNumFaces;
+       dm->getNumEdges = cdDM_getNumEdges;
+
+       dm->getVert = cdDM_getVert;
+       dm->getEdge = cdDM_getEdge;
+       dm->getFace = cdDM_getFace;
+       dm->getVertArray = cdDM_getVertArray;
+       dm->getEdgeArray = cdDM_getEdgeArray;
+       dm->getFaceArray = cdDM_getFaceArray;
+       dm->getVertData = DM_get_vert_data;
+       dm->getEdgeData = DM_get_edge_data;
+       dm->getFaceData = 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->getVertCos = cdDM_getVertCos;
+       dm->getVertCo = cdDM_getVertCo;
+       dm->getVertNo = cdDM_getVertNo;
+
+       dm->drawVerts = cdDM_drawVerts;
+
+       dm->drawUVEdges = cdDM_drawUVEdges;
+       dm->drawEdges = cdDM_drawEdges;
+       dm->drawLooseEdges = cdDM_drawLooseEdges;
+       dm->drawMappedEdges = cdDM_drawMappedEdges;
+
+       dm->drawFacesSolid = cdDM_drawFacesSolid;
+       dm->drawFacesColored = cdDM_drawFacesColored;
+       dm->drawFacesTex = cdDM_drawFacesTex;
+       dm->drawMappedFaces = cdDM_drawMappedFaces;
+       dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
+
+       dm->foreachMappedVert = cdDM_foreachMappedVert;
+       dm->foreachMappedEdge = cdDM_foreachMappedEdge;
+       dm->foreachMappedFaceCenter = cdDM_foreachMappedFaceCenter;
+
+       dm->release = cdDM_release;
+
+       return dm;
+}
+
+DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
+{
+       DerivedMesh *dm = cdDM_create("CDDM_new dm");
+       DM_init(dm, numVerts, numEdges, numFaces);
+
+       CustomData_add_layer(&dm->vertData, LAYERTYPE_MVERT, LAYERFLAG_NOCOPY,
+                            NULL);
+       CustomData_add_layer(&dm->edgeData, LAYERTYPE_MEDGE, LAYERFLAG_NOCOPY,
+                            NULL);
+       CustomData_add_layer(&dm->faceData, LAYERTYPE_MFACE, LAYERFLAG_NOCOPY,
+                            NULL);
+
+       return dm;
+}
+
+DerivedMesh *CDDM_from_mesh(Mesh *mesh)
+{
+       DerivedMesh *dm = CDDM_new(mesh->totvert, mesh->totedge, mesh->totface);
+       int i;
+
+       if(mesh->msticky)
+               CustomData_add_layer(&dm->vertData, LAYERTYPE_MSTICKY, 0, NULL);
+       if(mesh->dvert)
+               CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL);
+
+       if(mesh->tface)
+               CustomData_add_layer(&dm->faceData, LAYERTYPE_TFACE, 0, NULL);
+       if(mesh->mcol)
+               CustomData_add_layer(&dm->faceData, LAYERTYPE_MCOL, 0, NULL);
+
+       for(i = 0; i < mesh->totvert; ++i) {
+               DM_set_vert_data(dm, i, LAYERTYPE_MVERT, &mesh->mvert[i]);
+               if(mesh->msticky)
+                       DM_set_vert_data(dm, i, LAYERTYPE_MSTICKY, &mesh->msticky[i]);
+               if(mesh->dvert)
+                       DM_set_vert_data(dm, i, LAYERTYPE_MDEFORMVERT, &mesh->dvert[i]);
+
+               DM_set_vert_data(dm, i, LAYERTYPE_ORIGINDEX, &i);
+       }
+
+       for(i = 0; i < mesh->totedge; ++i) {
+               DM_set_edge_data(dm, i, LAYERTYPE_MEDGE, &mesh->medge[i]);
+
+               DM_set_edge_data(dm, i, LAYERTYPE_ORIGINDEX, &i);
+       }
+
+       for(i = 0; i < mesh->totface; ++i) {
+               DM_set_face_data(dm, i, LAYERTYPE_MFACE, &mesh->mface[i]);
+               if(mesh->tface)
+                       DM_set_face_data(dm, i, LAYERTYPE_TFACE, &mesh->tface[i]);
+               if(mesh->mcol)
+                       DM_set_face_data(dm, i, LAYERTYPE_MCOL, &mesh->mcol[i * 4]);
+
+               DM_set_face_data(dm, i, LAYERTYPE_ORIGINDEX, &i);
+       }
+
+       return dm;
+}
+
+DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
+{
+       DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
+                                  BLI_countlist(&em->edges),
+                                  BLI_countlist(&em->faces));
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       int i;
+       MVert *mvert = CDDM_get_verts(dm);
+       MEdge *medge = CDDM_get_edges(dm);
+       MFace *mface = CDDM_get_faces(dm);
+       int *index;
+
+       /* this maps from vert pointer to vert index */
+       GHash *vertHash = BLI_ghash_new(BLI_ghashutil_ptrhash,
+                                       BLI_ghashutil_ptrcmp);
+
+       for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
+               BLI_ghash_insert(vertHash, eve, (void *)i);
+
+       if(me->msticky)
+               CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL);
+       if(me->dvert)
+               CustomData_add_layer(&dm->vertData, LAYERTYPE_MDEFORMVERT, 0, NULL);
+
+       if(me->tface)
+               CustomData_add_layer(&dm->faceData, LAYERTYPE_TFACE, 0, NULL);
+
+       /* Need to be able to mark loose edges */
+       for(eed = em->edges.first; eed; eed = eed->next) {
+               eed->f2 = 0;
+       }
+       for(efa = em->faces.first; efa; efa = efa->next) {
+               efa->e1->f2 = 1;
+               efa->e2->f2 = 1;
+               efa->e3->f2 = 1;
+               if(efa->e4) efa->e4->f2 = 1;
+       }
+
+       index = dm->getVertDataArray(dm, LAYERTYPE_ORIGINDEX);
+       for(i = 0, eve = em->verts.first; i < dm->vertData.numElems;
+           i++, eve = eve->next, index++) {
+               MVert *mv = &mvert[i];
+
+               VECCOPY(mv->co, eve->co);
+
+               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->mat_nr = 0;
+               mv->flag = 0;
+
+               *index = i;
+
+               if(me->msticky && eve->keyindex != -1)
+                       DM_set_vert_data(dm, i, LAYERTYPE_MSTICKY,
+                                        &me->msticky[eve->keyindex]);
+               if(me->dvert && eve->keyindex != -1)
+                       DM_set_vert_data(dm, i, LAYERTYPE_MDEFORMVERT,
+                                        &me->dvert[eve->keyindex]);
+       }
+
+       index = dm->getEdgeDataArray(dm, LAYERTYPE_ORIGINDEX);
+       for(i = 0, eed = em->edges.first; i < dm->edgeData.numElems;
+           i++, eed = eed->next, index++) {
+               MEdge *med = &medge[i];
+
+               med->v1 = (int) BLI_ghash_lookup(vertHash, eed->v1);
+               med->v2 = (int) BLI_ghash_lookup(vertHash, eed->v2);
+               med->crease = (unsigned char) (eed->crease * 255.0f);
+               med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+               
+               if(eed->seam) med->flag |= ME_SEAM;
+               if(eed->sharp) med->flag |= ME_SHARP;
+               if(!eed->f2) med->flag |= ME_LOOSEEDGE;
+
+               *index = i;
+       }
+
+       index = dm->getFaceDataArray(dm, LAYERTYPE_ORIGINDEX);
+       for(i = 0, efa = em->faces.first; i < dm->faceData.numElems;
+           i++, efa = efa->next, index++) {
+               MFace *mf = &mface[i];
+
+               mf->v1 = (int) BLI_ghash_lookup(vertHash, efa->v1);
+               mf->v2 = (int) BLI_ghash_lookup(vertHash, efa->v2);
+               mf->v3 = (int) BLI_ghash_lookup(vertHash, efa->v3);
+               mf->v4 = efa->v4 ? (int)BLI_ghash_lookup(vertHash, efa->v4) : 0;
+               mf->mat_nr = efa->mat_nr;
+               mf->flag = efa->flag;
+               test_index_face(mf, NULL, NULL, efa->v4?4:3);
+
+               *index = i;
+
+               if(me->tface)
+                       DM_set_face_data(dm, i, LAYERTYPE_TFACE, &efa->tf);
+       }
+
+       BLI_ghash_free(vertHash, NULL, NULL);
+
+       return dm;
+}
+
+DerivedMesh *CDDM_copy(DerivedMesh *source)
+{
+       DerivedMesh *dest = CDDM_from_template(source,
+                                              source->vertData.numElems,
+                                              source->edgeData.numElems,
+                                              source->faceData.numElems);
+
+       CustomData_copy_data(&source->vertData, &dest->vertData, 0, 0,
+                            source->vertData.numElems);
+       CustomData_copy_data(&source->edgeData, &dest->edgeData, 0, 0,
+                            source->edgeData.numElems);
+       CustomData_copy_data(&source->faceData, &dest->faceData, 0, 0,
+                            source->faceData.numElems);
+
+       /* copy vert/face/edge data from source */
+       source->getVertArray(source, CDDM_get_verts(dest));
+       source->getEdgeArray(source, CDDM_get_edges(dest));
+       source->getFaceArray(source, CDDM_get_faces(dest));
+
+       return dest;
+}
+
+DerivedMesh *CDDM_from_template(DerivedMesh *source,
+                                int numVerts, int numEdges, int numFaces)
+{
+       DerivedMesh *dest = cdDM_create("CDDM_from_template dest");
+       DM_from_template(dest, source, numVerts, numEdges, numFaces);
+
+       /* if no vert/face/edge layers in custom data, add them */
+       if(!CDDM_get_verts(dest))
+               CustomData_add_layer(&dest->vertData, LAYERTYPE_MVERT,
+                                    LAYERFLAG_NOCOPY, NULL);
+       if(!CDDM_get_edges(dest))
+               CustomData_add_layer(&dest->edgeData, LAYERTYPE_MEDGE,
+                                    LAYERFLAG_NOCOPY, NULL);
+       if(!CDDM_get_faces(dest))
+               CustomData_add_layer(&dest->faceData, LAYERTYPE_MFACE,
+                                    LAYERFLAG_NOCOPY, NULL);
+
+       return dest;
+}
+
+void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3])
+{
+       int i;
+       MVert *vert = CDDM_get_verts(dm);
+
+       for(i = 0; i < dm->vertData.numElems; ++i, ++vert)
+               VECCOPY(vert->co, vertCoords[i]);
+}
+
+/* adapted from mesh_calc_normals */
+void CDDM_calc_normals(DerivedMesh *dm)
+{
+       float (*temp_nors)[3];
+       float (*face_nors)[3];
+       int i;
+       int numVerts = dm->getNumVerts(dm);
+       int numFaces = dm->getNumFaces(dm);
+       MFace *mf;
+       MVert *mv = CDDM_get_verts(dm);
+
+       if(!mv) return;
+
+       temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
+                               "CDDM_calc_normals temp_nors");
+       face_nors = MEM_mallocN(numFaces * sizeof(*face_nors),
+                               "CDDM_calc_normals face_nors");
+
+       mf = CDDM_get_faces(dm);
+       for(i = 0; i < numFaces; i++, mf++) {
+               float *f_no = face_nors[i];
+
+               if(mf->v4)
+                       CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+                                      mv[mf->v3].co, mv[mf->v4].co, f_no);
+               else
+                       CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+                                     mv[mf->v3].co, f_no);
+               
+               VecAddf(temp_nors[mf->v1], temp_nors[mf->v1], f_no);
+               VecAddf(temp_nors[mf->v2], temp_nors[mf->v2], f_no);
+               VecAddf(temp_nors[mf->v3], temp_nors[mf->v3], f_no);
+               if(mf->v4)
+                       VecAddf(temp_nors[mf->v4], temp_nors[mf->v4], f_no);
+       }
+
+       for(i = 0; i < numVerts; i++, mv++) {
+               float *no = temp_nors[i];
+               
+               if (Normalise(no) == 0.0) {
+                       VECCOPY(no, mv->co);
+                       Normalise(no);
+               }
+
+               mv->no[0] = (short)(no[0] * 32767.0);
+               mv->no[1] = (short)(no[1] * 32767.0);
+               mv->no[2] = (short)(no[2] * 32767.0);
+       }
+       
+       MEM_freeN(temp_nors);
+
+       /* TODO maybe cache face normals here? */
+       MEM_freeN(face_nors);
+}
+
+void CDDM_calc_edges(DerivedMesh *dm)
+{
+       CustomData edgeData;
+       EdgeHash *eh = BLI_edgehash_new();
+       EdgeHashIterator *ehi;
+       int i;
+       int maxFaces = dm->getNumFaces(dm);
+       MFace *mf = CDDM_get_faces(dm);
+       MEdge *med;
+
+       for (i = 0; i < maxFaces; 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);
+               }
+       }
+
+       CustomData_from_template(&dm->edgeData, &edgeData, BLI_edgehash_size(eh));
+
+       if(!CustomData_get_layer(&edgeData, LAYERTYPE_MEDGE))
+               CustomData_add_layer(&edgeData, LAYERTYPE_MEDGE,
+                                    LAYERFLAG_NOCOPY, NULL);
+
+       ehi = BLI_edgehashIterator_new(eh);
+       med = CustomData_get_layer(&edgeData, LAYERTYPE_MEDGE);
+       for(i = 0; !BLI_edgehashIterator_isDone(ehi);
+           BLI_edgehashIterator_step(ehi), ++i, ++med) {
+               BLI_edgehashIterator_getKey(ehi, &med->v1, &med->v2);
+
+               med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+       }
+       BLI_edgehashIterator_free(ehi);
+
+       CustomData_free(&dm->edgeData);
+       dm->edgeData = edgeData;
+
+       BLI_edgehash_free(eh, NULL);
+}
+
+void CDDM_set_num_verts(DerivedMesh *dm, int numVerts)
+{
+       CustomData_set_num_elems(&dm->vertData, numVerts);
+}
+
+void CDDM_set_num_edges(DerivedMesh *dm, int numEdges)
+{
+       CustomData_set_num_elems(&dm->edgeData, numEdges);
+}
+
+void CDDM_set_num_faces(DerivedMesh *dm, int numFaces)
+{
+       CustomData_set_num_elems(&dm->faceData, numFaces);
+}
+
+MVert *CDDM_get_vert(DerivedMesh *dm, int index)
+{
+       return CustomData_get(&dm->vertData, index, LAYERTYPE_MVERT);
+}
+
+MEdge *CDDM_get_edge(DerivedMesh *dm, int index)
+{
+       return CustomData_get(&dm->edgeData, index, LAYERTYPE_MEDGE);
+}
+
+MFace *CDDM_get_face(DerivedMesh *dm, int index)
+{
+       return CustomData_get(&dm->faceData, index, LAYERTYPE_MFACE);
+}
+
+MVert *CDDM_get_verts(DerivedMesh *dm)
+{
+       return CustomData_get_layer(&dm->vertData, LAYERTYPE_MVERT);
+}
+
+MEdge *CDDM_get_edges(DerivedMesh *dm)
+{
+       return CustomData_get_layer(&dm->edgeData, LAYERTYPE_MEDGE);
+}
+
+MFace *CDDM_get_faces(DerivedMesh *dm)
+{
+       return CustomData_get_layer(&dm->faceData, LAYERTYPE_MFACE);
+}
+
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
new file mode 100644 (file)
index 0000000..d774324
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+* $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) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Implementation of CustomData.
+*
+* BKE_customdata.h contains the function prototypes for this file.
+*
+*/ 
+
+#include "BKE_customdata.h"
+
+#include "BLI_linklist.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include <string.h>
+
+/* number of layers to add when growing a CustomData object */
+#define CUSTOMDATA_GROW 5
+
+/* descriptor and storage for a custom data layer */
+typedef struct LayerDesc {
+       int type;   /* type of data in layer */
+       int flag;   /* general purpose flag */
+       void *data; /* layer data */
+} LayerDesc;
+
+/********************* Layer type information **********************/
+typedef struct LayerTypeInfo {
+       int size; /* the memory size of one element of this layer's data */
+
+       /* a function to copy count elements of this layer's data
+        * (deep copy if appropriate)
+        * size should be the size of one element of this layer's data (e.g.
+        * LayerTypeInfo.size)
+        * if NULL, memcpy is used
+        */
+       void (*copy)(const void *source, void *dest, int count, int size);
+
+       /* a function to free any dynamically allocated components of this
+        * layer's data (note the data pointer itself should not be freed)
+        * size should be the size of one element of this layer's data (e.g.
+        * LayerTypeInfo.size)
+        */
+       void (*free)(void *data, int count, int size);
+
+       /* a function to interpolate between count source elements of this
+        * layer's data and store the result in dest
+        * if weights == NULL or sub_weights == NULL, they should default to 1
+        *
+        * weights gives the weight for each element in sources
+        * sub_weights gives the sub-element weights for each element in sources
+        *    (there should be (sub element count)^2 weights per element)
+        * count gives the number of elements in sources
+        */
+       void (*interp)(void **sources, float *weights, float *sub_weights,
+                      int count, void *dest);
+} LayerTypeInfo;
+
+static void layerCopy_mdeformvert(const void *source, void *dest,
+                                  int count, int size);
+
+static void layerFree_mdeformvert(void *data, int count, int size);
+
+static void layerInterp_mdeformvert(void **sources, float *weights,
+                                    float *sub_weights, int count, void *dest);
+
+static void layerInterp_tface(void **sources, float *weights,
+                              float *sub_weights, int count, void *dest);
+
+static void layerInterp_mcol(void **sources, float *weights,
+                             float *sub_weights, int count, void *dest);
+
+const LayerTypeInfo LAYERTYPEINFO[LAYERTYPE_NUMTYPES] = {
+       {sizeof(MVert), NULL, NULL, NULL},
+       {sizeof(MSticky), NULL, NULL, NULL},
+       {sizeof(MDeformVert),
+        layerCopy_mdeformvert, layerFree_mdeformvert, layerInterp_mdeformvert},
+       {sizeof(MEdge), NULL, NULL, NULL},
+       {sizeof(MFace), NULL, NULL, NULL},
+       {sizeof(TFace), NULL, NULL, layerInterp_tface},
+       /* 4 MCol structs per face */
+       {sizeof(MCol) * 4, NULL, NULL, layerInterp_mcol},
+       {sizeof(int), NULL, NULL, NULL},
+       /* 3 floats per normal vector */
+       {sizeof(float) * 3, NULL, NULL, NULL},
+       {sizeof(int), NULL, NULL, NULL},
+};
+
+const LayerTypeInfo *layerType_getInfo(int type)
+{
+       if(type < 0 || type >= LAYERTYPE_NUMTYPES) return NULL;
+
+       return &LAYERTYPEINFO[type];
+}
+
+static void layerCopy_mdeformvert(const void *source, void *dest,
+                                  int count, int size)
+{
+       int i;
+
+       memcpy(dest, source, count * size);
+
+       for(i = 0; i < count; ++i) {
+               MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size);
+               MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw),
+                                               "layerCopy_mdeformvert dw");
+
+               memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
+               dvert->dw = dw;
+       }
+}
+
+static void layerFree_mdeformvert(void *data, int count, int size)
+{
+       int i;
+
+       for(i = 0; i < count; ++i) {
+               MDeformVert *dvert = (MDeformVert *)((char *)data + i * size);
+
+               if(dvert->dw) {
+                       MEM_freeN(dvert->dw);
+                       dvert->dw = NULL;
+               }
+       }
+}
+
+static void linklist_free_simple(void *link)
+{
+       MEM_freeN(link);
+}
+
+static void layerInterp_mdeformvert(void **sources, float *weights,
+                                    float *sub_weights, int count, void *dest)
+{
+       MDeformVert *dvert = dest;
+       LinkNode *dest_dw = NULL; /* a list of lists of MDeformWeight pointers */
+       LinkNode *node;
+       int i, j, totweight;
+
+       if(count <= 0) return;
+
+       /* build a list of unique def_nrs for dest */
+       totweight = 0;
+       for(i = 0; i < count; ++i) {
+               MDeformVert *source = sources[i];
+               float interp_weight = weights ? weights[i] : 1.0f;
+
+               for(j = 0; j < source->totweight; ++j) {
+                       MDeformWeight *dw = &source->dw[j];
+
+                       for(node = dest_dw; node; node = node->next) {
+                               MDeformWeight *tmp_dw = (MDeformWeight *)node->link;
+
+                               if(tmp_dw->def_nr == dw->def_nr) {
+                                       tmp_dw->weight += dw->weight * interp_weight;
+                                       break;
+                               }
+                       }
+
+                       /* if this def_nr is not in the list, add it */
+                       if(!node) {
+                               MDeformWeight *tmp_dw = MEM_callocN(sizeof(*tmp_dw),
+                                                           "layerInterp_mdeformvert tmp_dw");
+                               tmp_dw->def_nr = dw->def_nr;
+                               tmp_dw->weight = dw->weight * interp_weight;
+                               BLI_linklist_prepend(&dest_dw, tmp_dw);
+                               totweight++;
+                       }
+               }
+       }
+
+       /* now we know how many unique deform weights there are, so realloc */
+       if(dvert->dw) MEM_freeN(dvert->dw);
+       dvert->dw = MEM_callocN(sizeof(*dvert->dw) * totweight,
+                               "layerInterp_mdeformvert dvert->dw");
+       dvert->totweight = totweight;
+
+       for(i = 0, node = dest_dw; node; node = node->next, ++i)
+               dvert->dw[i] = *((MDeformWeight *)node->link);
+
+       BLI_linklist_free(dest_dw, linklist_free_simple);
+}
+
+static void layerInterp_tface(void **sources, float *weights,
+                              float *sub_weights, int count, void *dest)
+{
+       TFace *tf = dest;
+       int i, j, k;
+       float uv[4][2];
+       float col[4][4];
+
+       if(count <= 0) return;
+
+       memset(uv, 0, sizeof(uv));
+       memset(col, 0, sizeof(col));
+
+       for(i = 0; i < count; ++i) {
+               float weight = weights ? weights[i] : 1;
+               TFace *src = sources[i];
+
+               for(j = 0; j < 4; ++j) {
+                       if(sub_weights) {
+                               for(k = 0; k < 4; ++k) {
+                                       float sub_weight = sub_weights[j * 4 + k];
+                                       char *tmp_col = (char *)&src->col[k];
+                                       float *tmp_uv = src->uv[k];
+
+                                       uv[j][0] += tmp_uv[0] * sub_weight * weight;
+                                       uv[j][1] += tmp_uv[1] * sub_weight * weight;
+
+                                       col[j][0] += tmp_col[0] * sub_weight * weight;
+                                       col[j][1] += tmp_col[1] * sub_weight * weight;
+                                       col[j][2] += tmp_col[2] * sub_weight * weight;
+                                       col[j][3] += tmp_col[3] * sub_weight * weight;
+                               }
+                       } else {
+                               char *tmp_col = (char *)&src->col[j];
+                               uv[j][0] += src->uv[j][0] * weight;
+                               uv[j][1] += src->uv[j][1] * weight;
+
+                               col[j][0] += tmp_col[0] * weight;
+                               col[j][1] += tmp_col[1] * weight;
+                               col[j][2] += tmp_col[2] * weight;
+                               col[j][3] += tmp_col[3] * weight;
+                       }
+               }
+       }
+
+       *tf = *(TFace *)sources[0];
+       for(j = 0; j < 4; ++j) {
+               char *tmp_col = (char *)&tf->col[j];
+
+               tf->uv[j][0] = uv[j][0];
+               tf->uv[j][1] = uv[j][1];
+
+               tmp_col[0] = (int)col[j][0];
+               tmp_col[1] = (int)col[j][1];
+               tmp_col[2] = (int)col[j][2];
+               tmp_col[3] = (int)col[j][3];
+       }
+}
+
+static void layerInterp_mcol(void **sources, float *weights,
+                             float *sub_weights, int count, void *dest)
+{
+       MCol *mc = dest;
+       int i, j, k;
+       struct {
+               float a;
+               float r;
+               float g;
+               float b;
+       } col[4];
+
+       if(count <= 0) return;
+
+       memset(col, 0, sizeof(col));
+
+       for(i = 0; i < count; ++i) {
+               float weight = weights ? weights[i] : 1;
+               float *sub_weight = sub_weights;
+
+               for(j = 0; j < 4; ++j) {
+                       if(sub_weights) {
+                               MCol *src = sources[i];
+                               for(k = 0; k < 4; ++k, ++sub_weight, ++src) {
+                                       col[j].a += src->a * (*sub_weight) * weight;
+                                       col[j].r += src->r * (*sub_weight) * weight;
+                                       col[j].g += src->g * (*sub_weight) * weight;
+                                       col[j].b += src->b * (*sub_weight) * weight;
+                               }
+                       } else {
+                               MCol *src = sources[i];
+                               col[j].a += src[j].a * weight;
+                               col[j].r += src[j].r * weight;
+                               col[j].g += src[j].g * weight;
+                               col[j].b += src[j].b * weight;
+                       }
+               }
+       }
+
+       for(j = 0; j < 4; ++j) {
+               mc[j].a = (int)col[j].a;
+               mc[j].r = (int)col[j].r;
+               mc[j].g = (int)col[j].g;
+               mc[j].b = (int)col[j].b;
+       }
+}
+
+/********************* CustomData functions *********************/
+void CustomData_init(CustomData *data,
+                     int maxLayers, int maxElems, int subElems)
+{
+       data->layers = MEM_callocN(maxLayers * sizeof(*data->layers),
+                                   "CustomData->layers");
+       data->numLayers = 0;
+       data->maxLayers = maxLayers;
+       data->numElems = maxElems;
+       data->maxElems = maxElems;
+       data->subElems = subElems;
+}
+
+void CustomData_from_template(const CustomData *source, CustomData *dest,
+                              int maxElems)
+{
+       int i;
+
+       CustomData_init(dest, source->maxLayers, maxElems, source->subElems);
+
+       for(i = 0; i < source->numLayers; ++i) {
+               if(source->layers[i].flag & LAYERFLAG_NOCOPY) continue;
+
+               CustomData_add_layer(dest, source->layers[i].type,
+                                    source->layers[i].flag & ~LAYERFLAG_NOFREE, NULL);
+       }
+}
+
+void CustomData_free(CustomData *data)
+{
+       int i;
+       const LayerTypeInfo *typeInfo;
+
+       for(i = 0; i < data->numLayers; ++i) {
+               if(!(data->layers[i].flag & LAYERFLAG_NOFREE)) {
+                       typeInfo = layerType_getInfo(data->layers[i].type);
+                       if(typeInfo->free)
+                               typeInfo->free(data->layers[i].data, data->numElems,
+                                              typeInfo->size);
+
+                       MEM_freeN(data->layers[i].data);
+               }
+       }
+
+       data->numLayers = 0;
+
+       if(data->layers) {
+               MEM_freeN(data->layers);
+               data->layers = NULL;
+       }
+}
+
+static int customData_grow(CustomData *data, int amount)
+{
+       LayerDesc *tmp = MEM_callocN(sizeof(*tmp) * (data->maxLayers + amount),
+                                 "CustomData->layers");
+       if(!tmp) return 0;
+
+       data->maxLayers += amount;
+       memcpy(tmp, data->layers, sizeof(*tmp) * data->numLayers);
+
+       MEM_freeN(data->layers);
+       data->layers = tmp;
+
+       return 1;
+}
+
+static int customData_add_layer__internal(CustomData *data, int type,
+                                          int flag, void *layer)
+{
+       int index = data->numLayers;
+
+       if(index >= data->maxLayers)
+               if(!customData_grow(data, CUSTOMDATA_GROW)) return 0;
+
+       /* keep layers ordered by type */
+       for( ; index > 0 && data->layers[index - 1].type > type; --index)
+               data->layers[index] = data->layers[index - 1];
+
+       data->layers[index].type = type;
+       data->layers[index].flag = flag;
+       data->layers[index].data = layer;
+
+       data->numLayers++;
+
+       return 1;
+}
+
+int CustomData_add_layer(CustomData *data, int type, int flag, void *layer)
+{
+       int size = layerType_getInfo(type)->size * data->numElems;
+       void *tmp_layer = layer;
+
+       if(!layer) tmp_layer = MEM_callocN(size, "LayerDesc.data");
+
+       if(!tmp_layer) return 0;
+
+       if(customData_add_layer__internal(data, type, flag, tmp_layer))
+               return 1;
+       else {
+               MEM_freeN(tmp_layer);
+               return 0;
+       }
+}
+
+int CustomData_compat(const CustomData *data1, const CustomData *data2)
+{
+       int i;
+
+       if(data1->numLayers != data2->numLayers) return 0;
+
+       for(i = 0; i < data1->numLayers; ++i) {
+               if(data1->layers[i].type != data2->layers[i].type) return 0;
+               if(data1->layers[i].flag != data2->layers[i].flag) return 0;
+       }
+
+       return 1;
+}
+
+/* gets index of first layer matching type after start_index
+ * if start_index < 0, starts searching at 0
+ * returns -1 if there is no layer of type
+ */
+static int CustomData_find_next(const CustomData *data, int type,
+                                int start_index)
+{
+       int i = start_index + 1;
+
+       if(i < 0) i = 0;
+
+       for(; i < data->numLayers; ++i)
+               if(data->layers[i].type == type) return i;
+
+       return -1;
+}
+
+int CustomData_copy_data(const CustomData *source, CustomData *dest,
+                         int source_index, int dest_index, int count)
+{
+       const LayerTypeInfo *type_info;
+       int src_i, dest_i;
+       int src_offset;
+       int dest_offset;
+
+       if(count < 0) return 0;
+       if(source_index < 0 || (source_index + count) > source->numElems)
+               return 0;
+       if(dest_index < 0 || (dest_index + count) > dest->numElems)
+               return 0;
+
+       /* copies a layer at a time */
+       dest_i = 0;
+       for(src_i = 0; src_i < source->numLayers; ++src_i) {
+               if(source->layers[src_i].flag & LAYERFLAG_NOCOPY) continue;
+
+               /* find the first dest layer with type >= the source type
+                * (this should work because layers are ordered by type)
+                */
+               while(dest_i < dest->numLayers
+                     && dest->layers[dest_i].type < source->layers[src_i].type)
+                       ++dest_i;
+
+               /* if there are no more dest layers, we're done */
+               if(dest_i >= dest->numLayers) return 1;
+
+               /* if we found a matching layer, copy the data */
+               if(dest->layers[dest_i].type == source->layers[src_i].type) {
+                       char *src_data = source->layers[src_i].data;
+                       char *dest_data = dest->layers[dest_i].data;
+
+                       type_info = layerType_getInfo(source->layers[src_i].type);
+
+                       src_offset = source_index * type_info->size;
+                       dest_offset = dest_index * type_info->size;
+
+                       if(type_info->copy)
+                               type_info->copy(src_data + src_offset,
+                                               dest_data + dest_offset,
+                                               count, type_info->size);
+                       else
+                               memcpy(dest_data + dest_offset,
+                                      src_data + src_offset,
+                                      count * type_info->size);
+
+                       /* if there are multiple source & dest layers of the same type,
+                        * we don't want to copy all source layers to the same dest, so
+                        * increment dest_i
+                        */
+                       ++dest_i;
+               }
+       }
+
+       return 1;
+}
+
+int CustomData_free_elem(CustomData *data, int index, int count)
+{
+       int i;
+       const LayerTypeInfo *typeInfo;
+
+       if(index < 0 || count <= 0 || index + count > data->numElems) return 0;
+
+       for(i = 0; i < data->numLayers; ++i) {
+               if(!(data->layers[i].flag & LAYERFLAG_NOFREE)) {
+                       typeInfo = layerType_getInfo(data->layers[i].type);
+
+                       if(typeInfo->free) {
+                               int offset = typeInfo->size * index;
+
+                               typeInfo->free((char *)data->layers[i].data + offset,
+                                              count, typeInfo->size);
+                       }
+               }
+       }
+
+       return 1;
+}
+
+#define SOURCE_BUF_SIZE 100
+
+int CustomData_interp(const CustomData *source, CustomData *dest,
+                      int *src_indices, float *weights, float *sub_weights,
+                      int count, int dest_index)
+{
+       int src_i, dest_i;
+       int dest_offset;
+       int j;
+       void *source_buf[SOURCE_BUF_SIZE];
+       void **sources = source_buf;
+
+       if(count <= 0) return 0;
+       if(dest_index < 0 || dest_index >= dest->numElems) return 0;
+
+       /* slow fallback in case we're interpolating a ridiculous number of
+        * elements
+        */
+       if(count > SOURCE_BUF_SIZE)
+               sources = MEM_callocN(sizeof(*sources) * count,
+                                     "CustomData_interp sources");
+
+       /* interpolates a layer at a time */
+       for(src_i = 0; src_i < source->numLayers; ++src_i) {
+               LayerDesc *source_layer = &source->layers[src_i];
+               const LayerTypeInfo *type_info =
+                                       layerType_getInfo(source_layer->type);
+
+               dest_i = CustomData_find_next(dest, source_layer->type, -1);
+
+               if(dest_i >= 0 && type_info->interp) {
+                       void *src_data = source_layer->data; 
+
+                       for(j = 0; j < count; ++j)
+                               sources[j] = (char *)src_data
+                                            + type_info->size * src_indices[j];
+
+                       dest_offset = dest_index * type_info->size;
+
+                       type_info->interp(sources, weights, sub_weights, count,
+                                      (char *)dest->layers[dest_i].data + dest_offset);
+               }
+       }
+
+       if(count > SOURCE_BUF_SIZE) MEM_freeN(sources);
+       return 1;
+}
+
+void *CustomData_get(const CustomData *data, int index, int type)
+{
+       int offset;
+       int layer_index;
+       
+       if(index < 0 || index > data->numElems) return NULL;
+
+       /* get the layer index of the first layer of type */
+       layer_index = CustomData_find_next(data, type, -1);
+       if(layer_index < 0) return NULL;
+
+       /* get the offset of the desired element */
+       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 first layer of type */
+       int layer_index = CustomData_find_next(data, type, -1);
+
+       if(layer_index < 0) return NULL;
+
+       return data->layers[layer_index].data;
+}
+
+void CustomData_set(const CustomData *data, int index, int type, void *source)
+{
+       void *dest = CustomData_get(data, index, type);
+       const LayerTypeInfo *type_info = layerType_getInfo(type);
+
+       if(!dest) return;
+
+       if(type_info->copy)
+               type_info->copy(source, dest, 1, type_info->size);
+       else
+               memcpy(dest, source, type_info->size);
+}
+
+void CustomData_set_num_elems(CustomData *data, int numElems)
+{
+       if(numElems < 0) return;
+       if(numElems < data->maxElems) data->numElems = numElems;
+       else data->numElems = data->maxElems;
+}
index 8f92a0a0d680e7a21867daf61e9f029845ea7b8d..b262dac695a3fb31114a5c61d5e9416321f3963c 100644 (file)
@@ -1189,13 +1189,18 @@ static ModifierData *curve_get_tesselate_point(Object *ob, int forRender, int ed
 {
        ModifierData *md = modifiers_getVirtualModifierList(ob);
        ModifierData *preTesselatePoint;
+       int required_mode;
+
+       if(forRender) required_mode = eModifierMode_Render;
+       else required_mode = eModifierMode_Realtime;
+
+       if(editmode) required_mode |= eModifierMode_Editmode;
 
        preTesselatePoint = NULL;
        for (; md; md=md->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-               if (!(md->mode&(1<<forRender))) continue;
-               if (editmode && !(md->mode&eModifierMode_Editmode)) continue;
+               if ((md->mode & required_mode) != required_mode) continue;
                if (mti->isDisabled && mti->isDisabled(md)) continue;
 
                if (md->type==eModifierType_Hook || md->type==eModifierType_Softbody) {
@@ -1214,6 +1219,12 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float (
        int numVerts = 0;
        float (*originalVerts)[3] = NULL;
        float (*deformedVerts)[3] = NULL;
+       int required_mode;
+
+       if(forRender) required_mode = eModifierMode_Render;
+       else required_mode = eModifierMode_Realtime;
+
+       if(editmode) required_mode |= eModifierMode_Editmode;
 
        if(ob!=G.obedit && do_ob_key(ob)) {
                deformedVerts = curve_getVertexCos(ob->data, nurb, &numVerts);
@@ -1224,8 +1235,7 @@ void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float (
                for (; md; md=md->next) {
                        ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-                       if (!(md->mode&(1<<forRender))) continue;
-                       if (editmode && !(md->mode&eModifierMode_Editmode)) continue;
+                       if ((md->mode & required_mode) != required_mode) continue;
                        if (mti->isDisabled && mti->isDisabled(md)) continue;
                        if (mti->type!=eModifierTypeType_OnlyDeform) continue;
 
@@ -1256,6 +1266,12 @@ void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, i
        ModifierData *md = modifiers_getVirtualModifierList(ob);
        ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode);
        DispList *dl;
+       int required_mode;
+
+       if(forRender) required_mode = eModifierMode_Render;
+       else required_mode = eModifierMode_Realtime;
+
+       if(editmode) required_mode |= eModifierMode_Editmode;
 
        if (preTesselatePoint) {
                md = preTesselatePoint->next;
@@ -1264,8 +1280,7 @@ void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, i
        for (; md; md=md->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-               if (!(md->mode&(1<<forRender))) continue;
-               if (editmode && !(md->mode&eModifierMode_Editmode)) continue;
+               if ((md->mode & required_mode) != required_mode) continue;
                if (mti->isDisabled && mti->isDisabled(md)) continue;
                if (mti->type!=eModifierTypeType_OnlyDeform) continue;
 
index 81f7eb7a0eb10a5eb11d9cf1a04da94d1f54cb77..768fedd86eac886f1bbea3f6e06bc496851aa66b 100644 (file)
@@ -56,6 +56,8 @@
 #include "BKE_anim.h"
 #include "BKE_armature.h"
 #include "BKE_curve.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
 #include "BKE_deform.h"
 #include "BKE_displist.h"
 #include "BKE_global.h"
@@ -161,7 +163,7 @@ void resizelattice(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
 
                Mat4CpyMat4(mat, ltOb->obmat);
                Mat4One(ltOb->obmat);
-               lattice_deform_verts(ltOb, NULL, vertexCos, uNew*vNew*wNew, NULL);
+               lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew*vNew*wNew, NULL);
                Mat4CpyMat4(ltOb->obmat, mat);
 
                lt->typeu = typeu;
@@ -556,52 +558,85 @@ static void calc_curve_deform(Object *par, float *co, short axis, CurveDeform *c
 
 }
 
-void curve_deform_verts(Object *cuOb, Object *target, float (*vertexCos)[3], int numVerts, char *vgroup)
+void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup)
 {
        Curve *cu = cuOb->data;
        int a, flag = cu->flag;
        CurveDeform cd;
+       int use_vgroups;
        
        cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist
 
        init_curve_deform(cuOb, target, &cd);
                
-       INIT_MINMAX(cd.dmin, cd.dmax);
-               
-       for(a=0; a<numVerts; a++) {
-               Mat4MulVecfl(cd.curvespace, vertexCos[a]);
-               DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
-       }
-       
-       if(vgroup && vgroup[0] && target->type==OB_MESH) {
+       /* check whether to use vertex groups (only possible if target is a Mesh)
+        * we want either a Mesh with no derived data, or derived data with
+        * deformverts
+        */
+       if(target && target->type==OB_MESH) {
+               /* if there's derived data without deformverts, don't use vgroups */
+               if(dm && !dm->getVertData(dm, 0, LAYERTYPE_MDEFORMVERT))
+                       use_vgroups = 0;
+               else
+                       use_vgroups = 1;
+       } else
+               use_vgroups = 0;
+       
+       if(vgroup && vgroup[0] && use_vgroups) {
                bDeformGroup *curdef;
                Mesh *me= target->data;
-               int index= 0;
+               int index;
                
                /* find the group (weak loop-in-loop) */
-               for (curdef = target->defbase.first; curdef; curdef=curdef->next, index++)
+               for(index = 0, curdef = target->defbase.first; curdef;
+                   curdef = curdef->next, index++)
                        if (!strcmp(curdef->name, vgroup))
                                break;
-               /* check for numVerts because old files can have modifier over subsurf still */
-               if(curdef && me->dvert && numVerts==me->totvert) {
-                       MDeformVert *dvert= me->dvert;
+
+               if(curdef && (me->dvert || dm)) {
+                       MDeformVert *dvert = me->dvert;
                        float vec[3];
                        int j;
-                       
-                       for(a=0; a<numVerts; a++, dvert++) {
-                               for(j=0; j<dvert->totweight; j++) {
-                                       if (dvert->dw[j].def_nr == index) {
+
+                       INIT_MINMAX(cd.dmin, cd.dmax);
+
+                       for(a = 0; a < numVerts; a++, dvert++) {
+                               if(dm) dvert = dm->getVertData(dm, a, LAYERTYPE_MDEFORMVERT);
+
+                               for(j = 0; j < dvert->totweight; j++) {
+                                       if(dvert->dw[j].def_nr == index) {
+                                               Mat4MulVecfl(cd.curvespace, vertexCos[a]);
+                                               DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       dvert = me->dvert;
+                       for(a = 0; a < numVerts; a++, dvert++) {
+                               if(dm) dvert = dm->getVertData(dm, a, LAYERTYPE_MDEFORMVERT);
+
+                               for(j = 0; j < dvert->totweight; j++) {
+                                       if(dvert->dw[j].def_nr == index) {
                                                VECCOPY(vec, vertexCos[a]);
                                                calc_curve_deform(cuOb, vec, target->trackflag, &cd);
-                                               VecLerpf(vertexCos[a], vertexCos[a], vec, dvert->dw[j].weight);
+                                               VecLerpf(vertexCos[a], vertexCos[a], vec,
+                                                        dvert->dw[j].weight);
                                                Mat4MulVecfl(cd.objectspace, vertexCos[a]);
+                                               break;
                                        }
                                }
                        }
                }
-       }
-       else {
-               for(a=0; a<numVerts; a++) {
+       } else {
+               INIT_MINMAX(cd.dmin, cd.dmax);
+                       
+               for(a = 0; a < numVerts; a++) {
+                       Mat4MulVecfl(cd.curvespace, vertexCos[a]);
+                       DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
+               }
+
+               for(a = 0; a < numVerts; a++) {
                        calc_curve_deform(cuOb, vertexCos[a], target->trackflag, &cd);
                        Mat4MulVecfl(cd.objectspace, vertexCos[a]);
                }
@@ -609,37 +644,52 @@ void curve_deform_verts(Object *cuOb, Object *target, float (*vertexCos)[3], int
        cu->flag = flag;
 }
 
-void lattice_deform_verts(Object *laOb, Object *target, float (*vertexCos)[3], int numVerts, char *vgroup)
+void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
+                          float (*vertexCos)[3], int numVerts, char *vgroup)
 {
        int a;
+       int use_vgroups;
 
        init_latt_deform(laOb, target);
-       
-       if(vgroup && vgroup[0] && target->type==OB_MESH) {
+
+       /* check whether to use vertex groups (only possible if target is a Mesh)
+        * we want either a Mesh with no derived data, or derived data with
+        * deformverts
+        */
+       if(target && target->type==OB_MESH) {
+               /* if there's derived data without deformverts, don't use vgroups */
+               if(dm && !dm->getVertData(dm, 0, LAYERTYPE_MDEFORMVERT))
+                       use_vgroups = 0;
+               else
+                       use_vgroups = 1;
+       } else
+               use_vgroups = 0;
+       
+       if(vgroup && vgroup[0] && use_vgroups) {
                bDeformGroup *curdef;
-               Mesh *me= target->data;
-               int index= 0;
+               Mesh *me = target->data;
+               int index = 0;
                
                /* find the group (weak loop-in-loop) */
-               for (curdef = target->defbase.first; curdef; curdef=curdef->next, index++)
-                       if (!strcmp(curdef->name, vgroup))
-                               break;
-               /* check for numVerts because old files can have modifier over subsurf still */
-               if(curdef && me->dvert && numVerts==me->totvert) {
-                       MDeformVert *dvert= me->dvert;
+               for(curdef = target->defbase.first; curdef;
+                   curdef = curdef->next, index++)
+                       if(!strcmp(curdef->name, vgroup)) break;
+
+               if(curdef && (me->dvert || dm)) {
+                       MDeformVert *dvert = me->dvert;
                        int j;
                        
-                       for(a=0; a<numVerts; a++, dvert++) {
-                               for(j=0; j<dvert->totweight; j++) {
+                       for(a = 0; a < numVerts; a++, dvert++) {
+                               if(dm) dvert = dm->getVertData(dm, a, LAYERTYPE_MDEFORMVERT);
+                               for(j = 0; j < dvert->totweight; j++) {
                                        if (dvert->dw[j].def_nr == index) {
                                                calc_latt_deform(vertexCos[a], dvert->dw[j].weight);
                                        }
                                }
                        }
                }
-       }
-       else {
-               for(a=0; a<numVerts; a++) {
+       } else {
+               for(a = 0; a < numVerts; a++) {
                        calc_latt_deform(vertexCos[a], 1.0f);
                }
        }
@@ -652,7 +702,8 @@ int object_deform_mball(Object *ob)
                DispList *dl;
 
                for (dl=ob->disp.first; dl; dl=dl->next) {
-                       lattice_deform_verts(ob->parent, ob, (float(*)[3]) dl->verts, dl->nr, NULL);
+                       lattice_deform_verts(ob->parent, ob, NULL,
+                                            (float(*)[3]) dl->verts, dl->nr, NULL);
                }
 
                return 1;
@@ -765,7 +816,7 @@ void lattice_calc_modifiers(Object *ob)
        for (; md; md=md->next) {
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
-               if (!(md->mode&(1<<0))) continue;
+               if (!(md->mode&eModifierMode_Realtime)) continue;
                if (editmode && !(md->mode&eModifierMode_Editmode)) continue;
                if (mti->isDisabled && mti->isDisabled(md)) continue;
                if (mti->type!=eModifierTypeType_OnlyDeform) continue;
index c565cfa5979d242d1c6dd9eee4e879d948004320..9e43e30fa7c55daf2052761a5010800c4d50d764 100644 (file)
@@ -1,3 +1,41 @@
+/*
+* $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) 2005 by the Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Daniel Dunbar
+*                 Ton Roosendaal,
+*                 Ben Batt,
+*                 Brecht Van Lommel,
+*                 Campbell Barton
+*
+* ***** 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 "BLI_blenlib.h"
 #include "BLI_rand.h"
 #include "BLI_arithb.h"
+#include "BLI_linklist.h"
 #include "BLI_edgehash.h"
+#include "BLI_ghash.h"
 
 #include "MEM_guardedalloc.h"
 
 #include "DNA_armature_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_scene_types.h"
+#include "DNA_texture_types.h"
 #include "DNA_curve_types.h"
+#include "DNA_camera_types.h"
 
 #include "BLI_editVert.h"
 
 #include "MTC_matrixops.h"
 #include "MTC_vectorops.h"
 
+#include "BKE_main.h"
 #include "BKE_anim.h"
 #include "BKE_bad_level_calls.h"
 #include "BKE_global.h"
 #include "BKE_utildefines.h"
+#include "BKE_cdderivedmesh.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_booleanops.h"
 #include "BKE_displist.h"
@@ -37,6 +82,7 @@
 #include "BKE_object.h"
 #include "BKE_mesh.h"
 #include "BKE_softbody.h"
+#include "BKE_material.h"
 #include "depsgraph_private.h"
 
 #include "LOD_DependKludge.h"
@@ -44,6 +90,8 @@
 
 #include "CCGSubSurf.h"
 
+#include "RE_shader_ext.h"
+
 /* helper function for modifiers - usage is of this is discouraged, but
    avoids duplicate modifier code for DispListMesh and EditMesh */
 
@@ -85,7 +133,7 @@ DispListMesh *displistmesh_from_editmesh(EditMesh *em)
 
                VECCOPY(mv->co, eve->co);
                mv->mat_nr = 0;
-               mv->flag = ME_VERT_STEPINDEX;
+               mv->flag = 0;
        }
        for (i=0,eed=em->edges.first; i<outDLM->totedge; i++,eed=eed->next) {
                MEdge *med = &outDLM->medge[i];
@@ -93,7 +141,7 @@ DispListMesh *displistmesh_from_editmesh(EditMesh *em)
                med->v1 = (int) eed->v1->prev;
                med->v2 = (int) eed->v2->prev;
                med->crease = (unsigned char) (eed->crease*255.0f);
-               med->flag = ME_EDGEDRAW|ME_EDGERENDER|ME_EDGE_STEPINDEX;
+               med->flag = ME_EDGEDRAW | ME_EDGERENDER;
                
                if (eed->seam) med->flag |= ME_SEAM;
                if (!eed->f2) med->flag |= ME_LOOSEEDGE;
@@ -105,7 +153,7 @@ DispListMesh *displistmesh_from_editmesh(EditMesh *em)
                mf->v3 = (int) efa->v3->prev;
                mf->v4 = efa->v4?(int) efa->v4->prev:0;
                mf->mat_nr = efa->mat_nr;
-               mf->flag = efa->flag|ME_FACE_STEPINDEX;
+               mf->flag = efa->flag;
                test_index_face(mf, NULL, NULL, efa->v4?4:3);
        }
 
@@ -139,34 +187,51 @@ static int curveModifier_isDisabled(ModifierData *md)
        return !cmd->object;
 }
 
-static void curveModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData)
+static void curveModifier_foreachObjectLink(
+                ModifierData *md, Object *ob,
+                void (*walk)(void *userData, Object *ob, Object **obpoin),
+                void *userData)
 {
        CurveModifierData *cmd = (CurveModifierData*) md;
 
        walk(userData, ob, &cmd->object);
 }
 
-static void curveModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode)
+static void curveModifier_updateDepgraph(
+                ModifierData *md, DagForest *forest,
+                Object *ob, DagNode *obNode)
 {
        CurveModifierData *cmd = (CurveModifierData*) md;
 
        if (cmd->object) {
                DagNode *curNode = dag_get_node(forest, cmd->object);
 
-               dag_add_relation(forest, curNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+               dag_add_relation(forest, curNode, obNode,
+                                DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
        }
 }
 
-static void curveModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts)
+static void curveModifier_deformVerts(
+                ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                float (*vertexCos)[3], int numVerts)
 {
        CurveModifierData *cmd = (CurveModifierData*) md;
 
-       curve_deform_verts(cmd->object, ob, vertexCos, numVerts, cmd->name);
+       curve_deform_verts(cmd->object, ob, derivedData, vertexCos, numVerts,
+                          cmd->name);
 }
 
-static void curveModifier_deformVertsEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts)
+static void curveModifier_deformVertsEM(
+                ModifierData *md, Object *ob, EditMesh *editData,
+                DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
 {
-       curveModifier_deformVerts(md, ob, NULL, vertexCos, numVerts);
+       DerivedMesh *dm = derivedData;
+
+       if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+       curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts);
+
+       if(!derivedData) dm->release(dm);
 }
 
 /* Lattice */
@@ -186,34 +251,50 @@ static int latticeModifier_isDisabled(ModifierData *md)
        return !lmd->object;
 }
 
-static void latticeModifier_foreachObjectLink(ModifierData *md, Object *ob, void (*walk)(void *userData, Object *ob, Object **obpoin), void *userData)
+static void latticeModifier_foreachObjectLink(
+                   ModifierData *md, Object *ob,
+                   void (*walk)(void *userData, Object *ob, Object **obpoin),
+                   void *userData)
 {
        LatticeModifierData *lmd = (LatticeModifierData*) md;
 
        walk(userData, ob, &lmd->object);
 }
 
-static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest, Object *ob, DagNode *obNode)
+static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest,
+                                           Object *ob, DagNode *obNode)
 {
        LatticeModifierData *lmd = (LatticeModifierData*) md;
 
-       if (lmd->object) {
+       if(lmd->object) {
                DagNode *latNode = dag_get_node(forest, lmd->object);
 
-               dag_add_relation(forest, latNode, obNode, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+               dag_add_relation(forest, latNode, obNode,
+                                DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
        }
 }
 
-static void latticeModifier_deformVerts(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int numVerts)
+static void latticeModifier_deformVerts(
+                ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                float (*vertexCos)[3], int numVerts)
 {
        LatticeModifierData *lmd = (LatticeModifierData*) md;
 
-       lattice_deform_verts(lmd->object, ob, vertexCos, numVerts, lmd->name);
+       lattice_deform_verts(lmd->object, ob, derivedData,
+                            vertexCos, numVerts, lmd->name);
 }
 
-static void latticeModifier_deformVertsEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3], int numVerts)
+static void latticeModifier_deformVertsEM(
+                ModifierData *md, Object *ob, EditMesh *editData,
+                DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
 {
-       latticeModifier_deformVerts(md, ob, NULL, vertexCos, numVerts);
+       DerivedMesh *dm = derivedData;
+
+       if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+       latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts);
+
+       if(!derivedData) dm->release(dm);
 }
 
 /* Subsurf */
@@ -221,7 +302,7 @@ static void latticeModifier_deformVertsEM(ModifierData *md, Object *ob, void *ed
 static void subsurfModifier_initData(ModifierData *md)
 {
        SubsurfModifierData *smd = (SubsurfModifierData*) md;
-       
+
        smd->levels = 1;
        smd->renderLevels = 2;
        smd->flags |= eSubsurfModifierFlag_SubsurfUv;
@@ -242,55 +323,39 @@ static void subsurfModifier_freeData(ModifierData *md)
 {
        SubsurfModifierData *smd = (SubsurfModifierData*) md;
 
-       if (smd->mCache) {
+       if(smd->mCache) {
                ccgSubSurf_free(smd->mCache);
        }
-       if (smd->emCache) {
+       if(smd->emCache) {
                ccgSubSurf_free(smd->emCache);
        }
-}      
+}
 
-static void *subsurfModifier_applyModifier(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc)
+static DerivedMesh *subsurfModifier_applyModifier(
+                 ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                 int useRenderParams, int isFinalCalc)
 {
-       DerivedMesh *dm = derivedData;
        SubsurfModifierData *smd = (SubsurfModifierData*) md;
-       Mesh *me = ob->data;
+       DerivedMesh *result;
 
-       if (dm) {
-               DispListMesh *dlm = dm->convertToDispListMesh(dm, 0);
-               int i;
-
-               if (vertexCos) {
-                       int numVerts = dm->getNumVerts(dm);
-
-                       for (i=0; i<numVerts; i++) {
-                               VECCOPY(dlm->mvert[i].co, vertexCos[i]);
-                       }
-               }
-
-               dm = subsurf_make_derived_from_mesh(me, dlm, smd, useRenderParams, NULL, isFinalCalc);
+       result = subsurf_make_derived_from_derived(derivedData, smd,
+                                                  useRenderParams, NULL,
+                                                  isFinalCalc, 0);
 
-               return dm;
-       } else {
-               return subsurf_make_derived_from_mesh(me, NULL, smd, useRenderParams, vertexCos, isFinalCalc);
-       }
+       return result;
 }
 
-static void *subsurfModifier_applyModifierEM(ModifierData *md, Object *ob, void *editData, void *derivedData, float (*vertexCos)[3])
+static DerivedMesh *subsurfModifier_applyModifierEM(
+                 ModifierData *md, Object *ob, EditMesh *editData,
+                 DerivedMesh *derivedData)
 {
-       EditMesh *em = editData;
-       DerivedMesh *dm = derivedData;
        SubsurfModifierData *smd = (SubsurfModifierData*) md;
+       DerivedMesh *result;
 
-       if (dm) {
-               DispListMesh *dlm = dm->convertToDispListMesh(dm, 0);
-
-               dm = subsurf_make_derived_from_dlm_em(dlm, smd, vertexCos);
+       result = subsurf_make_derived_from_derived(derivedData, smd, 0,
+                                                  NULL, 0, 1);
 
-               return dm;
-       } else {
-               return subsurf_make_derived_from_editmesh(em, smd, vertexCos);
-       }
+       return result;
 }
 
 /* Build */
@@ -319,214 +384,213 @@ static int buildModifier_dependsOnTime(ModifierData *md)
        return 1;
 }
 
-static void *buildModifier_applyModifier(ModifierData *md, Object *ob, void *derivedData, float (*vertexCos)[3], int useRenderParams, int isFinalCalc)
+static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
+                                         DerivedMesh *derivedData,
+                                         int useRenderParams, int isFinalCalc)
 {
        DerivedMesh *dm = derivedData;
+       DerivedMesh *result;
        BuildModifierData *bmd = (BuildModifierData*) md;
-       DispListMesh *dlm=NULL, *ndlm = MEM_callocN(sizeof(*ndlm), "build_dlm");
-       MVert *mvert;
-       MEdge *medge;
-       MFace *mface;
-       MCol *mcol;
-       TFace *tface;
-       int totvert, totedge, totface;
-       int i,j;
+       int i;
+       int numFaces, numEdges;
+       int maxVerts, maxEdges, maxFaces;
+       int *vertMap, *edgeMap, *faceMap;
        float frac;
-
-       if (dm) {
-               dlm = dm->convertToDispListMesh(dm, 1);
-               mvert = dlm->mvert;
-               medge = dlm->medge;
-               mface = dlm->mface;
-               mcol = dlm->mcol;
-               tface = dlm->tface;
-               totvert = dlm->totvert;
-               totedge = dlm->totedge;
-               totface = dlm->totface;
-       } else {
-               Mesh *me = ob->data;
-               mvert = me->mvert;
-               medge = me->medge;
-               mface = me->mface;
-               mcol = me->mcol;
-               tface = me->tface;
-               totvert = me->totvert;
-               totedge = me->totedge;
-               totface = me->totface;
-       }
+       GHashIterator *hashIter;
+       /* maps vert indices in old mesh to indices in new mesh */
+       GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash,
+                                                                       BLI_ghashutil_intcmp);
+       /* maps edge indices in new mesh to indices in old mesh */
+       GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash,
+                                                                       BLI_ghashutil_intcmp);
+
+       maxVerts = dm->getNumVerts(dm);
+       vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts,
+                             "build modifier vertMap");
+       for(i = 0; i < maxVerts; ++i) vertMap[i] = i;
+
+       maxEdges = dm->getNumEdges(dm);
+       edgeMap = MEM_callocN(sizeof(*edgeMap) * maxEdges,
+                             "build modifier edgeMap");
+       for(i = 0; i < maxEdges; ++i) edgeMap[i] = i;
+
+       maxFaces = dm->getNumFaces(dm);
+       faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces,
+                             "build modifier faceMap");
+       for(i = 0; i < maxFaces; ++i) faceMap[i] = i;
 
        if (ob) {
-               frac = bsystem_time(ob, 0, (float)G.scene->r.cfra, bmd->start-1.0f)/bmd->length;
+               frac = bsystem_time(ob, 0, (float)G.scene->r.cfra,
+                                   bmd->start - 1.0f) / bmd->length;
        } else {
-               frac = G.scene->r.cfra - bmd->start/bmd->length;
+               frac = G.scene->r.cfra - bmd->start / bmd->length;
        }
        CLAMP(frac, 0.0, 1.0);
 
-       ndlm->totface = totface*frac;
-       ndlm->totedge = totedge*frac;
-       if (ndlm->totface) {
-               ndlm->mvert = MEM_mallocN(sizeof(*ndlm->mvert)*totvert, "build_mvert");
-               memcpy(ndlm->mvert, mvert, sizeof(*mvert)*totvert);
-               for (i=0; i<totvert; i++) {
-                       if (vertexCos)
-                               VECCOPY(ndlm->mvert[i].co, vertexCos[i]);
-                       ndlm->mvert[i].flag = 0;
-               }
-
-               if (bmd->randomize) {
-                       ndlm->mface = MEM_dupallocN(mface);
-                       BLI_array_randomize(ndlm->mface, sizeof(*mface), totface, bmd->seed);
+       numFaces = dm->getNumFaces(dm) * frac;
+       numEdges = dm->getNumEdges(dm) * frac;
 
-                       if (tface) {
-                               ndlm->tface = MEM_dupallocN(tface);
-                               BLI_array_randomize(ndlm->tface, sizeof(*tface), totface, bmd->seed);
-                       } else if (mcol) {
-                               ndlm->mcol = MEM_dupallocN(mcol);
-                               BLI_array_randomize(ndlm->mcol, sizeof(*mcol)*4, totface, bmd->seed);
-                       }
-               } else {
-                       ndlm->mface = MEM_mallocN(sizeof(*ndlm->mface)*ndlm->totface, "build_mf");
-                       memcpy(ndlm->mface, mface, sizeof(*mface)*ndlm->totface);
-
-                       if (tface) {
-                               ndlm->tface = MEM_mallocN(sizeof(*ndlm->tface)*ndlm->totface, "build_tf");
-                               memcpy(ndlm->tface, tface, sizeof(*tface)*ndlm->totface);
-                       } else if (mcol) {
-                               ndlm->mcol = MEM_mallocN(sizeof(*ndlm->mcol)*4*ndlm->totface, "build_mcol");
-                               memcpy(ndlm->mcol, mcol, sizeof(*mcol)*4*ndlm->totface);
-                       }
-               }
+       /* if there's at least one face, build based on faces */
+       if(numFaces) {
+               int maxEdges;
 
-               for (i=0; i<ndlm->totface; i++) {
-                       MFace *mf = &ndlm->mface[i];
+               if(bmd->randomize)
+                       BLI_array_randomize(faceMap, sizeof(*faceMap),
+                                           maxFaces, bmd->seed);
 
-                       ndlm->mvert[mf->v1].flag = 1;
-                       ndlm->mvert[mf->v2].flag = 1;
-                       ndlm->mvert[mf->v3].flag = 1;
-                       if (mf->v4) ndlm->mvert[mf->v4].flag = 1;
+               /* get the set of all vert indices that will be in the final mesh,
+                * mapped to the new indices
+                */
+               for(i = 0; i < numFaces; ++i) {
+                       MFace mf;
+                       dm->getFace(dm, faceMap[i], &mf);
+
+                       if(!BLI_ghash_haskey(vertHash, (void *)mf.v1))
+                               BLI_ghash_insert(vertHash, (void *)mf.v1,
+                                                (void *)BLI_ghash_size(vertHash));
+                       if(!BLI_ghash_haskey(vertHash, (void *)mf.v2))
+                               BLI_ghash_insert(vertHash, (void *)mf.v2,
+                                                (void *)BLI_ghash_size(vertHash));
+                       if(!BLI_ghash_haskey(vertHash, (void *)mf.v3))
+                               BLI_ghash_insert(vertHash, (void *)mf.v3,
+                                                (void *)BLI_ghash_size(vertHash));
+                       if(mf.v4 && !BLI_ghash_haskey(vertHash, (void *)mf.v4))
+                               BLI_ghash_insert(vertHash, (void *)mf.v4,
+                                                (void *)BLI_ghash_size(vertHash));
                }
 
-                       /* Store remapped indices in *((int*) mv->no) */
-               ndlm->totvert = 0;
-               for (i=0; i<totvert; i++) {
-                       MVert *mv = &ndlm->mvert[i];
-
-                       if (mv->flag) 
-                               *((int*) mv->no) = ndlm->totvert++;
+               /* get the set of edges that will be in the new mesh (i.e. all edges
+                * that have both verts in the new mesh)
+                */
+               maxEdges = dm->getNumEdges(dm);
+               for(i = 0; i < maxEdges; ++i) {
+                       MEdge me;
+                       dm->getEdge(dm, i, &me);
+
+                       if(BLI_ghash_haskey(vertHash, (void *)me.v1)
+                          && BLI_ghash_haskey(vertHash, (void *)me.v2))
+                               BLI_ghash_insert(edgeHash,
+                                                (void *)BLI_ghash_size(edgeHash), (void *)i);
                }
+       } else if(numEdges) {
+               if(bmd->randomize)
+                       BLI_array_randomize(edgeMap, sizeof(*edgeMap),
+                                           maxEdges, bmd->seed);
 
-                       /* Remap face vertex indices */
-               for (i=0; i<ndlm->totface; i++) {
-                       MFace *mf = &ndlm->mface[i];
-
-                       mf->v1 = *((int*) ndlm->mvert[mf->v1].no);
-                       mf->v2 = *((int*) ndlm->mvert[mf->v2].no);
-                       mf->v3 = *((int*) ndlm->mvert[mf->v3].no);
-                       if (mf->v4) mf->v4 = *((int*) ndlm->mvert[mf->v4].no);
+               /* get the set of all vert indices that will be in the final mesh,
+                * mapped to the new indices
+                */
+               for(i = 0; i < numEdges; ++i) {
+                       MEdge me;
+                       dm->getEdge(dm, edgeMap[i], &me);
+
+                       if(!BLI_ghash_haskey(vertHash, (void *)me.v1))
+                               BLI_ghash_insert(vertHash, (void *)me.v1,
+                                                (void *)BLI_ghash_size(vertHash));
+                       if(!BLI_ghash_haskey(vertHash, (void *)me.v2))
+                               BLI_ghash_insert(vertHash, (void *)me.v2,
+                                                (void *)BLI_ghash_size(vertHash));
                }
-                       /* Copy in all edges that have both vertices (remap in process) */
-               if (totedge) {
-                       ndlm->totedge = 0;
-                       ndlm->medge = MEM_mallocN(sizeof(*ndlm->medge)*totedge, "build_med");
-
-                       for (i=0; i<totedge; i++) {
-                               MEdge *med = &medge[i];
-
-                               if (ndlm->mvert[med->v1].flag && ndlm->mvert[med->v2].flag) {
-                                       MEdge *nmed = &ndlm->medge[ndlm->totedge++];
 
-                                       memcpy(nmed, med, sizeof(*med));
+               /* get the set of edges that will be in the new mesh
+                */
+               for(i = 0; i < numEdges; ++i) {
+                       MEdge me;
+                       dm->getEdge(dm, edgeMap[i], &me);
 
-                                       nmed->v1 = *((int*) ndlm->mvert[nmed->v1].no);
-                                       nmed->v2 = *((int*) ndlm->mvert[nmed->v2].no);
-                               }
-                       }
+                       BLI_ghash_insert(edgeHash, (void *)BLI_ghash_size(edgeHash),
+                                        (void *)edgeMap[i]);
                }
+       } else {
+               int numVerts = dm->getNumVerts(dm) * frac;
 
-                       /* Collapse vertex array to remove unused verts */
-               for(i=j=0; i<totvert; i++) {
-                       MVert *mv = &ndlm->mvert[i];
+               if(bmd->randomize)
+                       BLI_array_randomize(vertMap, sizeof(*vertMap),
+                                           maxVerts, bmd->seed);
 
-                       if (mv->flag) {
-                               if (j!=i) 
-                                       memcpy(&ndlm->mvert[j], mv, sizeof(*mv));
-                               j++;
-                       }
-               }
-       } else if (ndlm->totedge) {
-               ndlm->mvert = MEM_mallocN(sizeof(*ndlm->mvert)*totvert, "build_mvert");
-               memcpy(ndlm->mvert, mvert, sizeof(*mvert)*totvert);
-               for (i=0; i<totvert; i++) {
-                       if (vertexCos)
-                               VECCOPY(ndlm->mvert[i].co, vertexCos[i]);
-                       ndlm->mvert[i].flag = 0;
-               }
+               /* get the set of all vert indices that will be in the final mesh,
+                * mapped to the new indices
+                */
+               for(i = 0; i < numVerts; ++i)
+                       BLI_ghash_insert(vertHash, (void *)vertMap[i], (void *)i);
+       }
 
-               if (bmd->randomize) {
-                       ndlm->medge = MEM_dupallocN(medge);
-                       BLI_array_randomize(ndlm->medge, sizeof(*medge), totedge, bmd->seed);
-               } else {
-                       ndlm->medge = MEM_mallocN(sizeof(*ndlm->medge)*ndlm->totedge, "build_mf");
-                       memcpy(ndlm->medge, medge, sizeof(*medge)*ndlm->totedge);
-               }
+       /* now we know the number of verts, edges and faces, we can create
+        * the mesh
+        */
+       result = CDDM_from_template(dm, BLI_ghash_size(vertHash),
+                                   BLI_ghash_size(edgeHash), numFaces);
+
+       /* copy the vertices across */
+       for(hashIter = BLI_ghashIterator_new(vertHash);
+               !BLI_ghashIterator_isDone(hashIter);
+               BLI_ghashIterator_step(hashIter)) {
+               MVert source;
+               MVert *dest;
+               int oldIndex = (int)BLI_ghashIterator_getKey(hashIter);
+               int newIndex = (int)BLI_ghashIterator_getValue(hashIter);
+
+               dm->getVert(dm, oldIndex, &source);
+               dest = CDDM_get_vert(result, newIndex);
+
+               DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
+               *dest = source;
+       }
+       BLI_ghashIterator_free(hashIter);
 
-               for (i=0; i<ndlm->totedge; i++) {
-                       MEdge *med = &ndlm->medge[i];
+       /* copy the edges across, remapping indices */
+       for(i = 0; i < BLI_ghash_size(edgeHash); ++i) {
+               MEdge source;
+               MEdge *dest;
+               int oldIndex = (int)BLI_ghash_lookup(edgeHash, (void *)i);
 
-                       ndlm->mvert[med->v1].flag = 1;
-                       ndlm->mvert[med->v2].flag = 1;
-               }
+               dm->getEdge(dm, oldIndex, &source);
+               dest = CDDM_get_edge(result, i);
 
-                       /* Store remapped indices in *((int*) mv->no) */
-               ndlm->totvert = 0;
-               for (i=0; i<totvert; i++) {
-                       MVert *mv = &ndlm->mvert[i];
+               source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1);
+               source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2);
 
-                       if (mv->flag) 
-                               *((int*) mv->no) = ndlm->totvert++;
-               }
+               DM_copy_edge_data(dm, result, oldIndex, i, 1);
+               *dest = source;
+       }
 
-                       /* Remap edge vertex indices */
-               for (i=0; i<ndlm->totedge; i++) {
-                       MEdge *med = &ndlm->medge[i];
+       /* copy the faces across, remapping indices */
+       for(i = 0; i < numFaces; ++i) {
+               MFace source;
+               MFace *dest;
+               TFace *tf;
+               MCol *mc;
+               int orig_v4;
 
-                       med->v1 = *((int*) ndlm->mvert[med->v1].no);
-                       med->v2 = *((int*) ndlm->mvert[med->v2].no);
-               }
+               dm->getFace(dm, faceMap[i], &source);
+               dest = CDDM_get_face(result, i);
 
-                       /* Collapse vertex array to remove unused verts */
-               for(i=j=0; i<totvert; i++) {
-                       MVert *mv = &ndlm->mvert[i];
+               orig_v4 = source.v4;
 
-                       if (mv->flag) {
-                               if (j!=i) 
-                                       memcpy(&ndlm->mvert[j], mv, sizeof(*mv));
-                               j++;
-                       }
-               }
-       } else {
-               ndlm->totvert = totvert*frac;
+               source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1);
+               source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2);
+               source.v3 = (int)BLI_ghash_lookup(vertHash, (void *)source.v3);
+               if(source.v4)
+                       source.v4 = (int)BLI_ghash_lookup(vertHash, (void *)source.v4);
 
-               if (bmd->randomize) {
-                       ndlm->mvert = MEM_dupallocN(mvert);
-                       BLI_array_randomize(ndlm->mvert, sizeof(*mvert), totvert, bmd->seed);
-               } else {
-                       ndlm->mvert = MEM_mallocN(sizeof(*ndlm->mvert)*ndlm->totvert, "build_mvert");
-                       memcpy(ndlm->mvert, mvert, sizeof(*mvert)*ndlm->totvert);
-               }
+               DM_copy_face_data(dm, result, faceMap[i], i, 1);
+               *dest = source;
 
-               if (vertexCos) {
-                       for (i=0; i<ndlm->totvert; i++) {
-                               VECCOPY(ndlm->mvert[i].co, vertexCos[i]);
-                       }
-               }
+               tf = DM_get_face_data(result, i, LAYERTYPE_TFACE);
+               mc = DM_get_face_data(result, i, LAYERTYPE_MCOL);
+               test_index_face(dest, mc, tf, (orig_v4 ? 4 : 3));
        }
 
-       if (dlm) displistmesh_free(dlm);
+       CDDM_calc_normals(result);
 
-       mesh_calc_normals(ndlm->mvert, ndlm->totvert, ndlm->mface, ndlm->totface, &ndlm->nors);
-       
-       return derivedmesh_from_displistmesh(ndlm, NULL);
+       BLI_ghash_free(vertHash, NULL, NULL);
+       BLI_ghash_free(edgeHash, NULL, NULL);
+
+       MEM_freeN(vertMap);
+       MEM_freeN(edgeMap);
+       MEM_freeN(faceMap);
+
+       return result;
 }
 
 /* Array */
@@ -569,10 +633,10 @@ static void arrayModifier_copyData(ModifierData *md, ModifierData *target)
        tamd->flags = amd->flags;
 }
 
-static void arrayModifier_foreachObjectLink(ModifierData *md,
-                  Object *ob,
-                  void (*walk)(void *userData, Object *ob, Object **obpoin),
-                  void *userData)
+static void arrayModifier_foreachObjectLink(
+                ModifierData *md, Object *ob,
+                void (*walk)(void *userData, Object *ob, Object **obpoin),
+                void *userData)
 {
        ArrayModifierData *amd = (ArrayModifierData*) md;
 
@@ -580,10 +644,8 @@ static void arrayModifier_foreachObjectLink(ModifierData *md,
        walk(userData, ob, &amd->offset_ob);
 }
 
-static void arrayModifier_updateDepgraph(ModifierData *md,
-                                         DagForest *forest,
-                                         Object *ob,
-                                         DagNode *obNode)
+static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest,
+                                         Object *ob, DagNode *obNode)
 {
        ArrayModifierData *amd = (ArrayModifierData*) md;
 
@@ -591,32 +653,30 @@ static void arrayModifier_updateDepgraph(ModifierData *md,
                DagNode *curNode = dag_get_node(forest, amd->curve_ob);
 
                dag_add_relation(forest, curNode, obNode,
-                                DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+                                DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
        }
        if (amd->offset_ob) {
                DagNode *curNode = dag_get_node(forest, amd->offset_ob);
 
                dag_add_relation(forest, curNode, obNode,
-                                DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+                                DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
        }
 }
 
-float displistmesh_width(DispListMesh *dlm, int axis)
+float vertarray_size(MVert *mvert, int numVerts, int axis)
 {
        int i;
        float min_co, max_co;
-       MVert *mv;
 
        /* if there are no vertices, width is 0 */
-       if(dlm->totvert == 0) return 0;
+       if(numVerts == 0) return 0;
 
        /* find the minimum and maximum coordinates on the desired axis */
-       min_co = max_co = dlm->mvert[0].co[axis];
-       for (i=1; i < dlm->totvert; i++) {
-               mv = &dlm->mvert[i];
-
-               if(mv->co[axis] < min_co) min_co = mv->co[axis];
-               if(mv->co[axis] > max_co) max_co = mv->co[axis];
+       min_co = max_co = mvert->co[axis];
+       ++mvert;
+       for(i = 1; i < numVerts; ++i, ++mvert) {
+               if(mvert->co[axis] < min_co) min_co = mvert->co[axis];
+               if(mvert->co[axis] > max_co) max_co = mvert->co[axis];
        }
 
        return max_co - min_co;
@@ -650,6 +710,7 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldVert, int copy)
                int mergeVert = indexMap[oldVert].merge;
 
                /* follow the chain of merges to the end */
+               /* TODO should this only go as far as the number of copies allows? */
                while(indexMap[mergeVert].merge >= 0
                      && indexMap[mergeVert].merge != mergeVert)
                        mergeVert = indexMap[mergeVert].merge;
@@ -665,10 +726,9 @@ static int calc_mapping(IndexMapEntry *indexMap, int oldVert, int copy)
        return newVert;
 }
 
-static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd,
-                                           Object *ob, DispListMesh *inDLM,
-                                           float (*vertexCos)[3],
-                                           int initFlags)
+static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
+                                          Object *ob, DerivedMesh *dm,
+                                          int initFlags)
 {
        int i, j;
        /* offset matrix */
@@ -677,7 +737,12 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd,
        float tmp_mat[4][4];
        float length = amd->length;
        int count = amd->count;
-       DispListMesh *dlm = MEM_callocN(sizeof(*dlm), "array_dlm");
+       int numVerts, numEdges, numFaces;
+       int maxVerts, maxEdges, maxFaces;
+       DerivedMesh *result;
+       MVert *mvert, *src_mvert;
+       MEdge *medge;
+       MFace *mface;
 
        IndexMapEntry *indexMap;
 
@@ -685,11 +750,19 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd,
 
        MTC_Mat4One(offset);
 
+       indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm),
+                              "indexmap");
+
+       src_mvert = dm->dupVertArray(dm);
+
+       maxVerts = dm->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] * displistmesh_width(inDLM, j);
+                       offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
+                                                                      maxVerts, j);
        }
 
        if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
@@ -736,24 +809,10 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd,
        if(count < 1)
                count = 1;
 
-       dlm->totvert = dlm->totedge = dlm->totface = 0;
-       indexMap = MEM_callocN(sizeof(*indexMap)*inDLM->totvert, "indexmap");
-
        /* allocate memory for count duplicates (including original) */
-       dlm->mvert = MEM_callocN(sizeof(*dlm->mvert)*inDLM->totvert*count,
-                                "dlm_mvert");
-       dlm->mface = MEM_callocN(sizeof(*dlm->mface)*inDLM->totface*count,
-                                "dlm_mface");
-
-       if (inDLM->medge)
-               dlm->medge = MEM_callocN(sizeof(*dlm->medge)*inDLM->totedge*count,
-                                        "dlm_medge");
-       if (inDLM->tface)
-               dlm->tface = MEM_callocN(sizeof(*dlm->tface)*inDLM->totface*count,
-                                        "dlm_tface");
-       if (inDLM->mcol)
-               dlm->mcol = MEM_callocN(sizeof(*dlm->mcol)*inDLM->totface*4*count,
-                                       "dlm_mcol");
+       result = CDDM_from_template(dm, dm->getNumVerts(dm) * count,
+                                   dm->getNumEdges(dm) * count,
+                                   dm->getNumFaces(dm) * count);
 
        /* calculate the offset matrix of the final copy (for merging) */ 
        MTC_Mat4One(final_offset);
@@ -763,20 +822,22 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd,
                MTC_Mat4CpyMat4(final_offset, tmp_mat);
        }
 
-       for (i=0; i<inDLM->totvert; i++) {
-               MVert *inMV = &inDLM->mvert[i];
-               MVert *mv = &dlm->mvert[dlm->totvert++];
+       numVerts = numEdges = numFaces = 0;
+       mvert = CDDM_get_verts(result);
+
+       for (i = 0; i < maxVerts; i++) {
+               MVert *inMV;
+               MVert *mv = &mvert[numVerts];
                MVert *mv2;
                float co[3];
 
-               *mv = *inMV;
+               inMV = &src_mvert[i];
 
-               if (vertexCos) {
-                       VECCOPY(mv->co, vertexCos[i]);
-               }
-               if (initFlags) mv->flag |= ME_VERT_STEPINDEX;
+               DM_copy_vert_data(dm, result, i, numVerts, 1);
+               *mv = *inMV;
+               numVerts++;
 
-               indexMap[i].new = dlm->totvert-1;
+               indexMap[i].new = numVerts - 1;
                indexMap[i].merge = -1; /* default to no merge */
                indexMap[i].merge_final = 0; /* default to no merge */
 
@@ -793,16 +854,16 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd,
                        VECCOPY(tmp_co, mv->co);
                        MTC_Mat4MulVecfl(offset, tmp_co);
 
-                       for(j = 0; j < inDLM->totvert; j++) {
-                               inMV = &inDLM->mvert[j];
+                       for(j = 0; j < maxVerts; j++) {
+                               inMV = &src_mvert[j];
                                /* if this vert is within merge limit, merge */
                                if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) {
                                        indexMap[i].merge = j;
 
                                        /* test for merging with final copy of merge target */
                                        if(amd->flags & MOD_ARR_MERGEFINAL) {
-                                               inMV = &inDLM->mvert[i];
-                                               VECCOPY(tmp_co, inDLM->mvert[j].co);
+                                               VECCOPY(tmp_co, inMV->co);
+                                               inMV = &src_mvert[i];
                                                MTC_Mat4MulVecfl(final_offset, tmp_co);
                                                if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist))
                                                        indexMap[i].merge_final = 1;
@@ -815,448 +876,1799 @@ static DispListMesh *arrayModifier_doArray(ArrayModifierData *amd,
                /* if no merging, generate copies of this vert */
                if(indexMap[i].merge < 0) {
                        for(j=0; j < count - 1; j++) {
-                               mv2 = &dlm->mvert[dlm->totvert++];
+                               mv2 = &mvert[numVerts];
 
+                               DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1);
                                *mv2 = *mv;
+                               numVerts++;
+
                                MTC_Mat4MulVecfl(offset, co);
                                VECCOPY(mv2->co, co);
-                               mv2->flag &= ~ME_VERT_STEPINDEX;
                        }
                } else if(indexMap[i].merge != i && indexMap[i].merge_final) {
                        /* if this vert is not merging with itself, and it is merging
                         * with the final copy of its merge target, remove the first copy
                         */
-                       dlm->totvert--;
+                       numVerts--;
+                       DM_free_vert_data(result, numVerts, 1);
+               }
+       }
+
+       /* make a hashtable so we can avoid duplicate edges from merging */
+       edges = BLI_edgehash_new();
+
+       maxEdges = dm->getNumEdges(dm);
+       medge = CDDM_get_edges(result);
+       for(i = 0; i < maxEdges; i++) {
+               MEdge inMED;
+               MEdge med;
+               MEdge *med2;
+               int vert1, vert2;
+
+               dm->getEdge(dm, i, &inMED);
+
+               med = inMED;
+               med.v1 = indexMap[inMED.v1].new;
+               med.v2 = indexMap[inMED.v2].new;
+
+               /* if vertices are to be merged with the final copies of their
+                * merge targets, calculate that final copy
+                */
+               if(indexMap[inMED.v1].merge_final) {
+                       med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge,
+                                             count - 2);
+               }
+               if(indexMap[inMED.v2].merge_final) {
+                       med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge,
+                                             count - 2);
+               }
+
+               if (initFlags) {
+                       med.flag |= ME_EDGEDRAW | ME_EDGERENDER;
+               }
+
+               if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
+                       DM_copy_edge_data(dm, result, i, numEdges, 1);
+                       medge[numEdges] = med;
+                       numEdges++;
+
+                       BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
+               }
+
+               for(j=0; j < count - 1; j++)
+               {
+                       vert1 = calc_mapping(indexMap, inMED.v1, j);
+                       vert2 = calc_mapping(indexMap, inMED.v2, j);
+                       /* avoid duplicate edges */
+                       if(!BLI_edgehash_haskey(edges, vert1, vert2)) {
+                               med2 = &medge[numEdges];
+
+                               DM_copy_edge_data(dm, result, i, numEdges, 1);
+                               *med2 = med;
+                               numEdges++;
+
+                               med2->v1 = vert1;
+                               med2->v2 = vert2;
+
+                               BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL);
+                       }
+               }
+       }
+
+       /* don't need the hashtable any more */
+       BLI_edgehash_free(edges, NULL);
+
+       maxFaces = dm->getNumFaces(dm);
+       mface = CDDM_get_faces(result);
+       for (i=0; i < maxFaces; i++) {
+               MFace inMF;
+               TFace *tf;
+               MCol *mc;
+               MFace *mf = &mface[numFaces];
+
+               dm->getFace(dm, i, &inMF);
+
+               DM_copy_face_data(dm, result, i, numFaces, 1);
+               tf = DM_get_face_data(result, numFaces, LAYERTYPE_TFACE);
+               mc = DM_get_face_data(result, numFaces, LAYERTYPE_MCOL);
+               *mf = inMF;
+               numFaces++;
+
+               mf->v1 = indexMap[inMF.v1].new;
+               mf->v2 = indexMap[inMF.v2].new;
+               mf->v3 = indexMap[inMF.v3].new;
+               if(inMF.v4)
+                       mf->v4 = indexMap[inMF.v4].new;
+
+               /* if vertices are to be merged with the final copies of their
+                * merge targets, calculate that final copy
+                */
+               if(indexMap[inMF.v1].merge_final)
+                       mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-2);
+               if(indexMap[inMF.v2].merge_final)
+                       mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-2);
+               if(indexMap[inMF.v3].merge_final)
+                       mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-2);
+               if(inMF.v4 && indexMap[inMF.v4].merge_final)
+                       mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-2);
+
+               test_index_face(mf, mc, tf, inMF.v4?4:3);
+
+               /* if the face has fewer than 3 vertices, don't create it */
+               if(mf->v3 == 0) {
+                       numFaces--;
+                       DM_free_face_data(result, numFaces, 1);
+               }
+
+               for(j=0; j < count - 1; j++)
+               {
+                       MFace *mf2 = &mface[numFaces];
+
+                       DM_copy_face_data(dm, result, i, numFaces, 1);
+                       tf = DM_get_face_data(result, numFaces, LAYERTYPE_TFACE);
+                       mc = DM_get_face_data(result, numFaces, LAYERTYPE_MCOL);
+                       *mf2 = *mf;
+                       numFaces++;
+
+                       mf2->v1 = calc_mapping(indexMap, inMF.v1, j);
+                       mf2->v2 = calc_mapping(indexMap, inMF.v2, j);
+                       mf2->v3 = calc_mapping(indexMap, inMF.v3, j);
+                       if (inMF.v4)
+                               mf2->v4 = calc_mapping(indexMap, inMF.v4, j);
+
+                       test_index_face(mf2, mc, tf, inMF.v4?4:3);
+
+                       /* if the face has fewer than 3 vertices, don't create it */
+                       if(mf2->v3 == 0) {
+                               numFaces--;
+                               DM_free_face_data(result, numFaces, 1);
+                       }
+               }
+       }
+
+       MEM_freeN(src_mvert);
+       MEM_freeN(indexMap);
+
+       CDDM_set_num_verts(result, numVerts);
+       CDDM_set_num_edges(result, numEdges);
+       CDDM_set_num_faces(result, numFaces);
+
+       return result;
+}
+
+static DerivedMesh *arrayModifier_applyModifier(
+                        ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                        int useRenderParams, int isFinalCalc)
+{
+       DerivedMesh *result;
+       ArrayModifierData *amd = (ArrayModifierData*) md;
+
+       result = arrayModifier_doArray(amd, ob, derivedData, 0);
+
+       CDDM_calc_normals(result);
+
+       return result;
+}
+
+static DerivedMesh *arrayModifier_applyModifierEM(
+                        ModifierData *md, Object *ob, EditMesh *editData,
+                        DerivedMesh *derivedData)
+{
+       return arrayModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* Mirror */
+
+static void mirrorModifier_initData(ModifierData *md)
+{
+       MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+       mmd->tolerance = 0.001;
+}
+
+static void mirrorModifier_copyData(ModifierData *md, ModifierData *target)
+{
+       MirrorModifierData *mmd = (MirrorModifierData*) md;
+       MirrorModifierData *tmmd = (MirrorModifierData*) target;
+
+       tmmd->axis = mmd->axis;
+       tmmd->tolerance = mmd->tolerance;
+}
+
+static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
+                                             DerivedMesh *dm,
+                                             int initFlags)
+{
+       int i, axis = mmd->axis;
+       float tolerance = mmd->tolerance;
+       DerivedMesh *result;
+       int numVerts, numEdges, numFaces;
+       int maxVerts = dm->getNumVerts(dm);
+       int maxEdges = dm->getNumEdges(dm);
+       int maxFaces = dm->getNumFaces(dm);
+       int (*indexMap)[2];
+
+       numVerts = numEdges = numFaces = 0;
+
+       indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
+
+       result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
+
+       for(i = 0; i < maxVerts; i++) {
+               MVert inMV;
+               MVert *mv = CDDM_get_vert(result, numVerts);
+               int isShared;
+
+               dm->getVert(dm, i, &inMV);
+               isShared = ABS(inMV.co[axis])<=tolerance;
+
+               /* Because the topology result (# of vertices) must be the same if
+                * the mesh data is overridden by vertex cos, have to calc sharedness
+                * based on original coordinates. This is why we test before copy.
+                */
+               DM_copy_vert_data(dm, result, i, numVerts, 1);
+               *mv = inMV;
+               numVerts++;
+
+               indexMap[i][0] = numVerts - 1;
+               indexMap[i][1] = !isShared;
+
+               if(isShared) {
+                       mv->co[axis] = 0;
+                       mv->flag |= ME_VERT_MERGED;
+               } else {
+                       MVert *mv2 = CDDM_get_vert(result, numVerts);
+
+                       DM_copy_vert_data(dm, result, i, numVerts, 1);
+                       *mv2 = *mv;
+                       numVerts++;
+
+                       mv2->co[axis] = -mv2->co[axis];
+               }
+       }
+
+       for(i = 0; i < maxEdges; i++) {
+               MEdge inMED;
+               MEdge *med = CDDM_get_edge(result, numEdges);
+
+               dm->getEdge(dm, i, &inMED);
+
+               DM_copy_edge_data(dm, result, i, numEdges, 1);
+               *med = inMED;
+               numEdges++;
+
+               med->v1 = indexMap[inMED.v1][0];
+               med->v2 = indexMap[inMED.v2][0];
+               if(initFlags)
+                       med->flag |= ME_EDGEDRAW | ME_EDGERENDER;
+
+               if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) {
+                       MEdge *med2 = CDDM_get_edge(result, numEdges);
+
+                       DM_copy_edge_data(dm, result, i, numEdges, 1);
+                       *med2 = *med;
+                       numEdges++;
+
+                       med2->v1 += indexMap[inMED.v1][1];
+                       med2->v2 += indexMap[inMED.v2][1];
+               }
+       }
+
+       for(i = 0; i < maxFaces; i++) {
+               MFace inMF;
+               MFace *mf = CDDM_get_face(result, numFaces);
+
+               dm->getFace(dm, i, &inMF);
+
+               DM_copy_face_data(dm, result, i, numFaces, 1);
+               *mf = inMF;
+               numFaces++;
+
+               mf->v1 = indexMap[inMF.v1][0];
+               mf->v2 = indexMap[inMF.v2][0];
+               mf->v3 = indexMap[inMF.v3][0];
+               mf->v4 = indexMap[inMF.v4][0];
+               
+               if(indexMap[inMF.v1][1]
+                  || indexMap[inMF.v2][1]
+                  || indexMap[inMF.v3][1]
+                  || (mf->v4 && indexMap[inMF.v4][1])) {
+                       MFace *mf2 = CDDM_get_face(result, numFaces);
+                       TFace *tf = DM_get_face_data(result, numFaces, LAYERTYPE_TFACE);
+                       MCol *mc = DM_get_face_data(result, numFaces, LAYERTYPE_MCOL);
+
+                       DM_copy_face_data(dm, result, i, numFaces, 1);
+                       *mf2 = *mf;
+                       numFaces++;
+
+                       mf2->v1 += indexMap[inMF.v1][1];
+                       mf2->v2 += indexMap[inMF.v2][1];
+                       mf2->v3 += indexMap[inMF.v3][1];
+                       if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1];
+
+                       /* Flip face normal */
+                       SWAP(int, mf2->v1, mf2->v3);
+                       if(tf) {
+                               SWAP(unsigned int, tf->col[0], tf->col[2]);
+                               SWAP(float, tf->uv[0][0], tf->uv[2][0]);
+                               SWAP(float, tf->uv[0][1], tf->uv[2][1]);
+                       } else if (mc) {
+                               SWAP(MCol, mc[0], mc[2]);
+                       }
+
+                       test_index_face(mf2, mc, tf, inMF.v4?4:3);
                }
        }
 
-       /* make a hashtable so we can avoid duplicate edges from merging */
-       edges = BLI_edgehash_new();
+       MEM_freeN(indexMap);
+
+       CDDM_set_num_verts(result, numVerts);
+       CDDM_set_num_edges(result, numEdges);
+       CDDM_set_num_faces(result, numFaces);
+
+       return result;
+}
+
+static DerivedMesh *mirrorModifier_applyModifier(
+                 ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                 int useRenderParams, int isFinalCalc)
+{
+       DerivedMesh *result;
+       MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+       result = mirrorModifier__doMirror(mmd, derivedData, 0);
+
+       CDDM_calc_normals(result);
+       
+       return result;
+}
+
+static DerivedMesh *mirrorModifier_applyModifierEM(
+                 ModifierData *md, Object *ob, EditMesh *editData,
+                 DerivedMesh *derivedData)
+{
+       return mirrorModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* EdgeSplit */
+/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag
+ * or edge angle (can be used to achieve autosmoothing)
+*/
+#if 0
+#define EDGESPLIT_DEBUG_1
+#define EDGESPLIT_DEBUG_2
+#define EDGESPLIT_DEBUG_0
+#endif
+
+static void edgesplitModifier_initData(ModifierData *md)
+{
+       EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+
+       /* default to 30-degree split angle, sharpness from both angle & flag
+       */
+       emd->split_angle = 30;
+       emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
+}
+
+static void edgesplitModifier_copyData(ModifierData *md, ModifierData *target)
+{
+       EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+       EdgeSplitModifierData *tamd = (EdgeSplitModifierData*) target;
+
+       tamd->split_angle = emd->split_angle;
+       tamd->flags = emd->flags;
+}
+
+static void linklist_copy(LinkNode **target, LinkNode *source);
+
+/* Mesh data for edgesplit operation */
+typedef struct SmoothVert {
+       LinkNode *faces;     /* all faces which use this vert */
+       int oldIndex; /* the index of the original DispListMesh vert */
+       int newIndex; /* the index of the new DispListMesh vert */
+} SmoothVert;
+
+static SmoothVert *smoothvert_copy(SmoothVert *vert)
+{
+       SmoothVert *copy = MEM_callocN(sizeof(*copy), "copy_smoothvert");
+
+       *copy = *vert;
+       linklist_copy(&copy->faces, vert->faces);
+
+       return copy;
+}
+
+static void smoothvert_free(void *vert)
+{
+       BLI_linklist_free(((SmoothVert *)vert)->faces, NULL);
+       MEM_freeN(vert);
+}
+
+#define SMOOTHEDGE_NUM_VERTS 2
+
+typedef struct SmoothEdge {
+       SmoothVert *verts[SMOOTHEDGE_NUM_VERTS]; /* the verts used by this edge */
+       LinkNode *faces;     /* all faces which use this edge */
+       int oldIndex; /* the index of the original DispListMesh edge */
+       int newIndex; /* the index of the new DispListMesh edge */
+       short flag; /* the flags from the original DispListMesh edge */
+} SmoothEdge;
+
+static void smoothedge_free(void *edge)
+{
+       BLI_linklist_free(((SmoothEdge *)edge)->faces, NULL);
+       MEM_freeN(edge);
+}
+
+static SmoothEdge *smoothedge_copy(SmoothEdge *edge)
+{
+       SmoothEdge *copy = MEM_callocN(sizeof(*copy), "copy_smoothedge");
+
+       *copy = *edge;
+       linklist_copy(&copy->faces, edge->faces);
+
+       return copy;
+}
+
+static int smoothedge_has_vert(SmoothEdge *edge, SmoothVert *vert)
+{
+       int i;
+       for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++)
+               if(edge->verts[i] == vert) return 1;
+
+       return 0;
+}
+
+#define SMOOTHFACE_MAX_EDGES 4
+
+typedef struct SmoothFace {
+       SmoothEdge *edges[SMOOTHFACE_MAX_EDGES]; /* nonexistent edges == NULL */
+       int flip[SMOOTHFACE_MAX_EDGES]; /* 1 = flip edge dir, 0 = don't flip */
+       float normal[3]; /* the normal of this face */
+       int oldIndex; /* the index of the original DispListMesh face */
+       int newIndex; /* the index of the new DispListMesh face */
+} SmoothFace;
+
+static void smoothface_free(void *face)
+{
+       MEM_freeN(face);
+}
+
+static int smoothface_has_edge(SmoothFace *face, SmoothEdge *edge)
+{
+       int i;
+       for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++)
+               if(face->edges[i] == edge) return 1;
+
+       return 0;
+}
+
+
+typedef struct SmoothMesh {
+       GHash *verts;
+       GHash *edges;
+       GHash *faces;
+       DerivedMesh *dm;
+} SmoothMesh;
+
+static SmoothMesh *smoothmesh_new()
+{
+       SmoothMesh *mesh = MEM_callocN(sizeof(*mesh), "smoothmesh");
+       mesh->verts = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp);
+       mesh->edges = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp);
+       mesh->faces = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp);
+
+       return mesh;
+}
+
+static void smoothmesh_free(SmoothMesh *mesh)
+{
+       BLI_ghash_free(mesh->verts, NULL, smoothvert_free);
+       BLI_ghash_free(mesh->edges, NULL, smoothedge_free);
+       BLI_ghash_free(mesh->faces, NULL, smoothface_free);
+       MEM_freeN(mesh);
+}
+
+static void smoothmesh_print(SmoothMesh *mesh)
+{
+       int i, j;
+       DerivedMesh *dm = mesh->dm;
+
+       printf("--- SmoothMesh ---\n");
+       printf("--- Vertices ---\n");
+       for(i = 0; i < BLI_ghash_size(mesh->verts); i++) {
+               SmoothVert *vert = BLI_ghash_lookup(mesh->verts, (void *)i);
+               LinkNode *node;
+               MVert mv;
+
+               dm->getVert(dm, vert->oldIndex, &mv);
+
+               printf("%3d: ind={%3d, %3d}, pos={% 5.1f, % 5.1f, % 5.1f}",
+                      i, vert->oldIndex, vert->newIndex,
+                      mv.co[0], mv.co[1], mv.co[2]);
+               printf(", faces={");
+               for(node = vert->faces; node != NULL; node = node->next) {
+                       printf(" %d", ((SmoothFace *)node->link)->newIndex);
+               }
+               printf("}\n");
+       }
+
+       printf("\n--- Edges ---\n");
+       for(i = 0; i < BLI_ghash_size(mesh->edges); i++) {
+               SmoothEdge *edge = BLI_ghash_lookup(mesh->edges, (void *)i);
+               LinkNode *node;
+
+               printf("%4d: indices={%4d, %4d}, verts={%4d, %4d}",
+                      i,
+                      edge->oldIndex, edge->newIndex,
+                      edge->verts[0]->newIndex, edge->verts[1]->newIndex);
+               if(edge->verts[0] == edge->verts[1]) printf(" <- DUPLICATE VERTEX");
+               printf(", faces={");
+               for(node = edge->faces; node != NULL; node = node->next) {
+                       printf(" %d", ((SmoothFace *)node->link)->newIndex);
+               }
+               printf("}\n");
+       }
+
+       printf("\n--- Faces ---\n");
+       for(i = 0; i < BLI_ghash_size(mesh->faces); i++) {
+               SmoothFace *face = BLI_ghash_lookup(mesh->faces, (void *)i);
+
+               printf("%4d: indices={%4d, %4d}, edges={", i,
+                      face->oldIndex, face->newIndex);
+               for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+                       if(face->flip[j])
+                               printf(" -%-2d", face->edges[j]->newIndex);
+                       else
+                               printf("  %-2d", face->edges[j]->newIndex);
+               }
+               printf("}, verts={");
+               for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+                       printf(" %d", face->edges[j]->verts[face->flip[j]]->newIndex);
+               }
+               printf("}\n");
+       }
+}
+
+static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm)
+{
+       SmoothMesh *mesh = smoothmesh_new();
+       EdgeHash *edges = BLI_edgehash_new();
+       int i;
+       int totvert, totedge, totface;
+
+       mesh->dm = dm;
+
+       totvert = dm->getNumVerts(dm);
+       for(i = 0; i < totvert; i++) {
+               SmoothVert *vert = MEM_callocN(sizeof(*vert), "smoothvert");
+
+               vert->oldIndex = vert->newIndex = i;
+               BLI_ghash_insert(mesh->verts, (void *)i, vert);
+       }
+
+       totedge = dm->getNumEdges(dm);
+       for(i = 0; i < totedge; i++) {
+               SmoothEdge *edge = MEM_callocN(sizeof(*edge), "smoothedge");
+               MEdge med;
+
+               dm->getEdge(dm, i, &med);
+               edge->verts[0] = BLI_ghash_lookup(mesh->verts, (void *)med.v1);
+               edge->verts[1] = BLI_ghash_lookup(mesh->verts, (void *)med.v2);
+               edge->oldIndex = edge->newIndex = i;
+               edge->flag = med.flag;
+               BLI_ghash_insert(mesh->edges, (void *)i, edge);
+               BLI_edgehash_insert(edges, med.v1, med.v2, edge);
+       }
+
+       totface = dm->getNumFaces(dm);
+       for(i = 0; i < totface; i++) {
+               SmoothFace *face = MEM_callocN(sizeof(*face), "smoothface");
+               MFace mf;
+               MVert v1, v2, v3;
+               int j;
+
+               dm->getFace(dm, i, &mf);
+
+               dm->getVert(dm, mf.v1, &v1);
+               dm->getVert(dm, mf.v2, &v2);
+               dm->getVert(dm, mf.v3, &v3);
+               face->edges[0] = BLI_edgehash_lookup(edges, mf.v1, mf.v2);
+               if(face->edges[0]->verts[1]->oldIndex == mf.v1) face->flip[0] = 1;
+               face->edges[1] = BLI_edgehash_lookup(edges, mf.v2, mf.v3);
+               if(face->edges[1]->verts[1]->oldIndex == mf.v2) face->flip[1] = 1;
+               if(mf.v4) {
+                       MVert v4;
+                       dm->getVert(dm, mf.v4, &v4);
+                       face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v4);
+                       if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
+                       face->edges[3] = BLI_edgehash_lookup(edges, mf.v4, mf.v1);
+                       if(face->edges[3]->verts[1]->oldIndex == mf.v4) face->flip[3] = 1;
+                       CalcNormFloat4(v1.co, v2.co, v3.co, v4.co, face->normal);
+               } else {
+                       face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v1);
+                       if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
+                       face->edges[3] = NULL;
+                       CalcNormFloat(v1.co, v2.co, v3.co, face->normal);
+               }
+
+               for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+                       SmoothEdge *edge = face->edges[j];
+                       BLI_linklist_prepend(&edge->faces, face);
+                       BLI_linklist_prepend(&edge->verts[face->flip[j]]->faces, face);
+               }
+
+               face->oldIndex = face->newIndex = i;
+               BLI_ghash_insert(mesh->faces, (void *)i, face);
+       }
+
+       BLI_edgehash_free(edges, NULL);
+
+       return mesh;
+}
+
+static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
+{
+       DerivedMesh *result = CDDM_from_template(mesh->dm,
+                                                BLI_ghash_size(mesh->verts),
+                                                BLI_ghash_size(mesh->edges),
+                                                BLI_ghash_size(mesh->faces));
+       GHashIterator *i;
+       MVert *new_verts = CDDM_get_verts(result);
+       MEdge *new_edges = CDDM_get_edges(result);
+       MFace *new_faces = CDDM_get_faces(result);
+
+       for(i = BLI_ghashIterator_new(mesh->verts); !BLI_ghashIterator_isDone(i);
+           BLI_ghashIterator_step(i)) {
+               SmoothVert *vert = BLI_ghashIterator_getValue(i);
+               MVert *newMV = &new_verts[vert->newIndex];
+
+               DM_copy_vert_data(mesh->dm, result,
+                                 vert->oldIndex, vert->newIndex, 1);
+               mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV);
+       }
+       BLI_ghashIterator_free(i);
+
+       for(i = BLI_ghashIterator_new(mesh->edges); !BLI_ghashIterator_isDone(i);
+           BLI_ghashIterator_step(i)) {
+               SmoothEdge *edge = BLI_ghashIterator_getValue(i);
+               MEdge *newME = &new_edges[edge->newIndex];
+
+               DM_copy_edge_data(mesh->dm, result,
+                                 edge->oldIndex, edge->newIndex, 1);
+               mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME);
+               newME->v1 = edge->verts[0]->newIndex;
+               newME->v2 = edge->verts[1]->newIndex;
+       }
+       BLI_ghashIterator_free(i);
+
+       for(i = BLI_ghashIterator_new(mesh->faces); !BLI_ghashIterator_isDone(i);
+           BLI_ghashIterator_step(i)) {
+               SmoothFace *face = BLI_ghashIterator_getValue(i);
+               MFace *newMF = &new_faces[face->newIndex];
+
+               DM_copy_face_data(mesh->dm, result,
+                                 face->oldIndex, face->newIndex, 1);
+               mesh->dm->getFace(mesh->dm, face->oldIndex, newMF);
+
+               newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex;
+               newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex;
+               newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex;
+
+               if(face->edges[3]) {
+                       newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex;
+               } else {
+                       newMF->v4 = 0;
+               }
+       }
+       BLI_ghashIterator_free(i);
+
+       return result;
+}
+
+/* returns the other edge in the given face that uses the given vert
+ * returns NULL if no other edge in the given face uses the given vert
+ * (this should never happen)
+ */
+static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert,
+                              SmoothEdge *edge)
+{
+       int i,j;
+       for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
+               SmoothEdge *tmp_edge = face->edges[i];
+               if(tmp_edge == edge) continue;
+
+               for(j = 0; j < SMOOTHEDGE_NUM_VERTS; j++)
+                       if(tmp_edge->verts[j] == vert) return tmp_edge;
+       }
+
+       /* if we get to here, something's wrong (there should always be 2 edges
+        * which use the same vert in a face)
+        */
+       return NULL;
+}
+
+/* returns the face attached to the given edge which is smoothest with the
+ * given face. Returns NULL if no other faces use this edge.
+ */
+static SmoothFace *smoothest_face(SmoothEdge *edge, SmoothFace *face)
+{
+       /* face with maximum dot product to this face's normal is smoothest */
+       float max_dot = -2;
+       SmoothFace *best_face = NULL;
+       LinkNode *node;
+
+       for(node = edge->faces; node != NULL; node = node->next) {
+               SmoothFace *tmp_face = node->link;
+               float dot;
+               if(tmp_face == face) continue;
+
+               dot = MTC_dot3Float(tmp_face->normal, face->normal);
+
+               if(dot > max_dot) {
+                       max_dot = dot;
+                       best_face = tmp_face;
+               }
+       }
+
+       return best_face;
+}
+
+/* copies source list to target, overwriting target (target is not freed)
+ * nodes in the copy will be in the same order as in source
+ */
+static void linklist_copy(LinkNode **target, LinkNode *source)
+{
+       LinkNode *node = NULL;
+       *target = NULL;
+
+       for(; source; source = source->next) {
+               if(node) {
+                       node->next = MEM_mallocN(sizeof(*node->next), "nlink_copy");
+                       node = node->next;
+               } else {
+                       node = *target = MEM_mallocN(sizeof(**target), "nlink_copy");
+               }
+               node->link = source->link;
+               node->next = NULL;
+       }
+}
+
+/* appends source to target if it's not already in target */
+static void linklist_append_unique(LinkNode **target, void *source) 
+{
+       LinkNode *node;
+       LinkNode *prev = NULL;
+
+       /* check if source value is already in the list */
+       for(node = *target; node; prev = node, node = node->next)
+               if(node->link == source) return;
+
+       node = MEM_mallocN(sizeof(*node), "nlink");
+       node->next = NULL;
+       node->link = source;
+
+       if(prev) prev->next = node;
+       else *target = node;
+}
+
+/* appends elements of source which aren't already in target to target */
+static void linklist_append_list_unique(LinkNode **target, LinkNode *source)
+{
+       for(; source; source = source->next)
+               linklist_append_unique(target, source->link);
+}
+
+/* prepends prepend to list - doesn't copy nodes, just joins the lists */
+static void linklist_prepend_linklist(LinkNode **list, LinkNode *prepend)
+{
+       if(prepend) {
+               LinkNode *node = prepend;
+               while(node->next) node = node->next;
+
+               node->next = *list;
+               *list = prepend;
+       }
+}
+
+/* empties the linked list
+ * frees pointers with freefunc if freefunc is not NULL
+ */
+static void linklist_empty(LinkNode **list, LinkNodeFreeFP freefunc)
+{
+       BLI_linklist_free(*list, freefunc);
+       *list = NULL;
+}
+
+/* removes the first instance of value from the linked list
+ * frees the pointer with freefunc if freefunc is not NULL
+ */
+static void linklist_remove_first(LinkNode **list, void *value,
+                                  LinkNodeFreeFP freefunc)
+{
+       LinkNode *node = *list;
+       LinkNode *prev = NULL;
+
+       while(node && node->link != value) {
+               prev = node;
+               node = node->next;
+       }
+
+       if(node) {
+               if(prev)
+                       prev->next = node->next;
+               else
+                       *list = node->next;
+
+               if(freefunc)
+                       freefunc(node->link);
+
+               MEM_freeN(node);
+       }
+}
+
+/* removes all elements in source from target */
+static void linklist_remove_list(LinkNode **target, LinkNode *source,
+                                 LinkNodeFreeFP freefunc)
+{
+       for(; source; source = source->next)
+               linklist_remove_first(target, source->link, freefunc);
+}
+
+static void print_ptr(void *ptr)
+{
+       printf("%p\n", ptr);
+}
+
+static void print_edge(void *ptr)
+{
+       SmoothEdge *edge = ptr;
+       printf(" %4d", edge->newIndex);
+}
+
+static void print_face(void *ptr)
+{
+       SmoothFace *face = ptr;
+       printf(" %4d", face->newIndex);
+}
+
+typedef struct ReplaceData {
+       void *find;
+       void *replace;
+} ReplaceData;
+
+static void edge_replace_vert(void *ptr, void *userdata)
+{
+       SmoothEdge *edge = ptr;
+       SmoothVert *find = ((ReplaceData *)userdata)->find;
+       SmoothVert *replace = ((ReplaceData *)userdata)->replace;
+       int i;
+
+#ifdef EDGESPLIT_DEBUG_2
+       printf("replacing vert %4d with %4d in edge %4d",
+              find->newIndex, replace->newIndex, edge->newIndex);
+       printf(": {%4d, %4d}", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
+#endif
+
+       for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) {
+               if(edge->verts[i] == find) {
+                       linklist_append_list_unique(&replace->faces, edge->faces);
+                       linklist_remove_list(&find->faces, edge->faces, NULL);
+
+                       edge->verts[i] = replace;
+               }
+       }
+
+#ifdef EDGESPLIT_DEBUG_2
+       printf(" -> {%4d, %4d}\n", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
+#endif
+}
+
+static void face_replace_vert(void *ptr, void *userdata)
+{
+       SmoothFace *face = ptr;
+       int i;
+
+       for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++)
+               edge_replace_vert(face->edges[i], userdata);
+}
+
+static void face_replace_edge(void *ptr, void *userdata)
+{
+       SmoothFace *face = ptr;
+       SmoothEdge *find = ((ReplaceData *)userdata)->find;
+       SmoothEdge *replace = ((ReplaceData *)userdata)->replace;
+       int i;
+
+#ifdef EDGESPLIT_DEBUG_2
+       printf("replacing edge %4d with %4d in face %4d",
+                  find->newIndex, replace->newIndex, face->newIndex);
+       if(face->edges[3])
+               printf(": {%2d %2d %2d %2d}",
+                      face->edges[0]->newIndex, face->edges[1]->newIndex,
+                      face->edges[2]->newIndex, face->edges[3]->newIndex);
+       else
+               printf(": {%2d %2d %2d}",
+                      face->edges[0]->newIndex, face->edges[1]->newIndex,
+                      face->edges[2]->newIndex);
+#endif
+
+       for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
+               if(face->edges[i] == find) {
+                       linklist_remove_first(&face->edges[i]->faces, face, NULL);
+                       BLI_linklist_prepend(&replace->faces, face);
+                       face->edges[i] = replace;
+               }
+       }
+
+#ifdef EDGESPLIT_DEBUG_2
+       if(face->edges[3])
+               printf(" -> {%2d %2d %2d %2d}\n",
+                      face->edges[0]->newIndex, face->edges[1]->newIndex,
+                      face->edges[2]->newIndex, face->edges[3]->newIndex);
+       else
+               printf(" -> {%2d %2d %2d}\n",
+                      face->edges[0]->newIndex, face->edges[1]->newIndex,
+                      face->edges[2]->newIndex);
+#endif
+}
+
+static int edge_is_sharp(SmoothEdge *edge, int flags,
+                         float threshold)
+{
+       /* if all flags are disabled, edge cannot be sharp */
+       if(!(flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG)))
+               return 0;
+
+       /* edge can only be sharp if it has at least 2 faces */
+       if(edge->faces && edge->faces->next) {
+               LinkNode *node1;
+               LinkNode *node2;
+
+               if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP))
+                   return 1;
+
+               if(flags & MOD_EDGESPLIT_FROMANGLE) {
+                       /* check angles between all faces */
+                       for(node1 = edge->faces; node1; node1 = node1->next) {
+                               SmoothFace *face1 = node1->link;
+                               for(node2 = node1->next; node2; node2 = node2->next) {
+                                       SmoothFace *face2 = node2->link;
+                                       float edge_angle_cos = MTC_dot3Float(face1->normal,
+                                                                            face2->normal);
+                                       if(edge_angle_cos < threshold) return 1;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/* returns 1 if vert was split, 0 if not */
+static int split_vert(SmoothVert *vert,
+                      SmoothEdge *start_edge, SmoothEdge *copy_edge,
+                      SmoothFace *start_face, SmoothMesh *mesh,
+                      float threshold, int flags)
+{
+       ReplaceData repdata;
+       SmoothVert *copy_vert;
+       LinkNode *split_edges = NULL; /* edges to use the copy vert */
+
+       SmoothFace *current_face = start_face;
+       SmoothEdge *current_edge;
+       SmoothEdge *sharp_edge = NULL;
+       SmoothFace *end_face = NULL;
+       GHash *visited_edges;
+
+#ifdef EDGESPLIT_DEBUG_2
+       printf(">>>>>>>>>>>>>>>>>>>>> split_vert start >>>>>>>>>>>>>>>>>>>>>\n");
+       printf("vert = %4d, start_edge =%4d, copy_edge = %4d, start_face = %4d\n",
+              vert->newIndex, start_edge->newIndex, copy_edge->newIndex,
+              start_face->newIndex);
+       printf("*** Beginning face traversal ***\n");
+#endif
+
+       /* sanity check */
+       if(!smoothface_has_edge(current_face, copy_edge)) return 0;
+       if(!smoothedge_has_vert(copy_edge, vert)) return 0;
+
+       visited_edges = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+       /* make sure we don't include start_edge in the split edge list */
+       BLI_ghash_insert(visited_edges, start_edge, NULL);
+
+       end_face = current_face;
+       current_edge = other_edge(current_face, vert, copy_edge);
+       current_face = smoothest_face(current_edge, current_face);
+
+       /* find another sharp edge attached to the current vert */
+       while(current_face && !BLI_ghash_haskey(visited_edges, current_edge)) {
+               BLI_ghash_insert(visited_edges, current_edge, NULL);
+
+               /* if this edge is sharp, use it */
+               if(edge_is_sharp(current_edge, flags, threshold)) {
+                       sharp_edge = current_edge;
+                       break;
+               }
+
+               /* save end face for edge replacement later */
+               end_face = current_face;
+
+               /* this edge should use the copy vert */
+               BLI_linklist_prepend(&split_edges, current_edge);
+
+               /* get the next edge around the vert */ 
+               current_edge = other_edge(current_face, vert, current_edge);
+               /* get the smoothest next face */
+               current_face = smoothest_face(current_edge, current_face);
+       }
+#ifdef EDGESPLIT_DEBUG_2
+       printf("*** Ending face traversal ***\n");
+#endif
+       BLI_ghash_free(visited_edges, NULL, NULL);
+
+       /* if we've returned to the starting point without finding a sharp edge,
+        * don't split the vert
+        */
+       if(current_edge == start_edge || (current_face && !sharp_edge)) {
+               BLI_linklist_free(split_edges, NULL);
+               return 0;
+       }
+
+       /* if current_face == NULL, we've hit a loose edge
+        * before finding a sharp edge
+        */
+       if(!current_face) BLI_linklist_prepend(&split_edges, current_edge);
+
+       /* copy the vertex */
+       copy_vert = smoothvert_copy(vert);
+       copy_vert->newIndex = BLI_ghash_size(mesh->verts);
+       linklist_empty(&copy_vert->faces, NULL);
+       BLI_ghash_insert(mesh->verts, (void *)copy_vert->newIndex, copy_vert);
+
+       /* add copy_edge to split_edges so it will undergo vertex replacement */
+       BLI_linklist_prepend(&split_edges, copy_edge);
+
+       /* replace the vertex with the copy in edges being split off */
+       repdata.find = vert;
+       repdata.replace = copy_vert;
+       BLI_linklist_apply(split_edges, edge_replace_vert, &repdata);
+
+       /* if sharp_edge == NULL, we didn't find a sharp edge, so don't split
+        * any more edges
+        */
+       if(sharp_edge) {
+               /* copy the sharpest edge */
+               SmoothEdge *copy_sharp = smoothedge_copy(sharp_edge);
+               copy_sharp->newIndex = BLI_ghash_size(mesh->edges);
+               linklist_empty(&copy_sharp->faces, NULL);
+               BLI_ghash_insert(mesh->edges, (void *)copy_sharp->newIndex, copy_sharp);
+
+#ifdef EDGESPLIT_DEBUG_2
+               printf("sharpest edge is %4d\n",
+                      sharp_edge->newIndex);
+#endif
+               /* replace the sharpest edge with the copy in end_face
+                */
+               repdata.find = sharp_edge;
+               repdata.replace = copy_sharp;
+               face_replace_edge(end_face, &repdata);
+
+               /* replace the vertex with its copy in copy_sharp */
+               repdata.find = vert;
+               repdata.replace = copy_vert;
+               edge_replace_vert(copy_sharp, &repdata);
+
+               /* split the other vertex (don't need to check return value as it
+                * doesn't matter if the split succeeds - the edge will be split
+                * regardless
+                */
+               if(copy_sharp->verts[0] == copy_vert)
+                       split_vert(copy_sharp->verts[1], sharp_edge, copy_sharp,
+                                  end_face, mesh, threshold, flags);
+               else
+                       split_vert(copy_sharp->verts[0], sharp_edge, copy_sharp,
+                                  end_face, mesh, threshold, flags);
+       }
+
+       BLI_linklist_free(split_edges, NULL);
+#ifdef EDGESPLIT_DEBUG_2
+       printf("<<<<<<<<<<<<<<<<<<<<< split_vert end <<<<<<<<<<<<<<<<<<<<<\n");
+#endif
+
+       return 1;
+}
+
+static void split_edge(SmoothEdge *edge, SmoothMesh *mesh, float threshold,
+                       int flags)
+{
+       LinkNode *split_node;
+
+       /* split all the faces off but the first */
+       for(split_node = edge->faces->next; split_node; ) {
+               ReplaceData repdata;
+               int success[2];
+               SmoothFace *split_face = split_node->link;
+
+               /* copy the start edge */
+               SmoothEdge *copy_edge = smoothedge_copy(edge);
+               copy_edge->newIndex = BLI_ghash_size(mesh->edges);
+               linklist_empty(&copy_edge->faces, NULL);
+               BLI_ghash_insert(mesh->edges, (void *)copy_edge->newIndex, copy_edge);
+
+#ifdef EDGESPLIT_DEBUG_2
+               printf(">>>>>>>>>>>>>>>>>>>> split_edge start >>>>>>>>>>>>>>>>>>>>\n");
+#endif
+               /* we need to go to the next node before we replace the edge,
+                * otherwise the current node will have been removed from the list
+                */
+               split_node = split_node->next;
+
+               /* replace the start edge with the copy in the face being split off */
+               repdata.find = edge;
+               repdata.replace = copy_edge;
+               face_replace_edge(split_face, &repdata);
+
+#ifdef EDGESPLIT_DEBUG_2
+               printf("******************* splitting verts[0] *******************\n");
+#endif
+               success[0] = split_vert(edge->verts[0], edge, copy_edge,
+                                       split_face, mesh, threshold, flags);
+#ifdef EDGESPLIT_DEBUG_2
+               printf("******************* splitting verts[1] *******************\n");
+#endif
+               success[1] = split_vert(edge->verts[1], edge, copy_edge,
+                                       split_face, mesh, threshold, flags);
+#ifdef EDGESPLIT_DEBUG_2
+               printf("<<<<<<<<<<<<<<<<<<<<< split_edge end <<<<<<<<<<<<<<<<<<<<<\n");
+#endif
+               /* if neither split operation succeeded, remove the edge */
+               if(!success[0] && !success[1]) {
+                       repdata.find = copy_edge;
+                       repdata.replace = edge;
+                       face_replace_edge(split_face, &repdata);
+                       
+                       BLI_ghash_remove(mesh->edges, (void *)copy_edge->newIndex,
+                                        NULL, smoothedge_free);
+               }
+       }
+}
+
+static void split_sharp_edges(SmoothMesh *mesh, float split_angle, int flags)
+{
+       int i;
+       int num_edges = BLI_ghash_size(mesh->edges);
+       /* if normal1 dot normal2 < threshold, angle is greater, so split */
+       /* FIXME not sure if this always works */
+       /* 0.00001 added for floating-point rounding */
+       float threshold = cos((split_angle + 0.00001) * M_PI / 180.0);
+
+       /* loop through edges, splitting sharp ones */
+       /* can't use an iterator here, because we'll be adding edges */
+       for(i = 0; i < num_edges; i++) {
+               SmoothEdge *edge = BLI_ghash_lookup(mesh->edges, (void *)i);
+
+               if(edge_is_sharp(edge, flags, threshold))
+                       split_edge(edge, mesh, threshold, flags);
+       }
+
+}
+
+static void split_single_vert(SmoothVert *vert, SmoothFace *face,
+                              SmoothMesh *mesh)
+{
+       SmoothVert *copy_vert;
+       ReplaceData repdata;
+
+       copy_vert = smoothvert_copy(vert);
+       copy_vert->newIndex = BLI_ghash_size(mesh->verts);
+       linklist_empty(&copy_vert->faces, NULL);
+       BLI_ghash_insert(mesh->verts, (void *)copy_vert->newIndex, copy_vert);
+
+       repdata.find = vert;
+       repdata.replace = copy_vert;
+       face_replace_vert(face, &repdata);
+}
+
+static void split_single_verts(SmoothMesh *mesh)
+{
+       int num_faces = BLI_ghash_size(mesh->faces);
+       int i,j;
+
+       for(i = 0; i < num_faces; i++) {
+               SmoothFace *face = BLI_ghash_lookup(mesh->faces, (void *)i);
+
+               for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+                       SmoothEdge *edge = face->edges[j];
+                       SmoothEdge *next_edge;
+                       SmoothVert *vert = edge->verts[1 - face->flip[j]];
+                       int next = (j + 1) % SMOOTHFACE_MAX_EDGES;
+
+                       /* wrap next around if at last edge */
+                       if(!face->edges[next]) next = 0;
+
+                       next_edge = face->edges[next];
+
+                       /* if there are other faces sharing this vertex but not
+                        * these edges, split the vertex
+                        */
+                       /* vert has to have at least one face (this one), so faces != 0 */
+                       if(!edge->faces->next && !next_edge->faces->next
+                           && vert->faces->next)
+                               /* FIXME this needs to find all faces that share edges with
+                                * this one and split off together
+                                */
+                               split_single_vert(vert, face, mesh);
+               }
+       }
+}
+
+static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd,
+                                         Object *ob, DerivedMesh *dm)
+{
+       SmoothMesh *mesh;
+       DerivedMesh *result;
+
+       mesh = smoothmesh_from_derivedmesh(dm);
+
+#ifdef EDGESPLIT_DEBUG_1
+       printf("********** Pre-split **********\n");
+       smoothmesh_print(mesh);
+#endif
+
+       split_sharp_edges(mesh, emd->split_angle, emd->flags);
+#ifdef EDGESPLIT_DEBUG_1
+       printf("********** Post-edge-split **********\n");
+       smoothmesh_print(mesh);
+#endif
+       split_single_verts(mesh);
+
+#ifdef EDGESPLIT_DEBUG_1
+       printf("********** Post-vert-split **********\n");
+       smoothmesh_print(mesh);
+#endif
+
+       result = CDDM_from_smoothmesh(mesh);
+       smoothmesh_free(mesh);
+
+       return result;
+}
+
+static DerivedMesh *edgesplitModifier_applyModifier(
+                ModifierData *md, Object *ob, DerivedMesh *derivedData,
+                int useRenderParams, int isFinalCalc)
+{
+       DerivedMesh *result;
+       EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+
+       result = edgesplitModifier_do(emd, ob, derivedData);
 
-       for (i=0; i<inDLM->totedge; i++) {
-               MEdge *inMED = &inDLM->medge[i];
-               MEdge med;
-               MEdge *med2;
-               int vert1, vert2;
+       CDDM_calc_normals(result);
 
-               med = *inMED;
-               med.v1 = indexMap[inMED->v1].new;
-               med.v2 = indexMap[inMED->v2].new;
+       return result;
+}
 
-               /* if vertices are to be merged with the final copies of their
-                * merge targets, calculate that final copy
-                */
-               if(indexMap[inMED->v1].merge_final) {
-                       med.v1 = calc_mapping(indexMap, indexMap[inMED->v1].merge,
-                                             count - 2);
-               }
-               if(indexMap[inMED->v2].merge_final) {
-                       med.v2 = calc_mapping(indexMap, indexMap[inMED->v2].merge,
-                                             count - 2);
-               }
+static DerivedMesh *edgesplitModifier_applyModifierEM(
+                        ModifierData *md, Object *ob, EditMesh *editData,
+                        DerivedMesh *derivedData)
+{
+       return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
 
-               if (initFlags) {
-                       med.flag |= ME_EDGEDRAW|ME_EDGERENDER|ME_EDGE_STEPINDEX;
-               }
+/* Displace */
 
-               if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
-                       dlm->medge[dlm->totedge++] = med;
-                       BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
-               }
+static void displaceModifier_initData(ModifierData *md)
+{
+       DisplaceModifierData *dmd = (DisplaceModifierData*) md;
 
-               for(j=0; j < count - 1; j++)
-               {
-                       vert1 = calc_mapping(indexMap, inMED->v1, j);
-                       vert2 = calc_mapping(indexMap, inMED->v2, j);
-                       /* avoid duplicate edges */
-                       if(!BLI_edgehash_haskey(edges, vert1, vert2)) {
-                               med2 = &dlm->medge[dlm->totedge++];
+       dmd->texture = NULL;
+       dmd->strength = 1;
+       dmd->direction = MOD_DISP_DIR_NOR;
+       dmd->midlevel = 0.5;
+}
 
-                               *med2 = med;
-                               med2->v1 = vert1;
-                               med2->v2 = vert2;
-                               med2->flag &= ~ME_EDGE_STEPINDEX;
+static void displaceModifier_copyData(ModifierData *md, ModifierData *target)
+{
+       DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+       DisplaceModifierData *tdmd = (DisplaceModifierData*) target;
 
-                               BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL);
-                       }
-               }
-       }
+       *tdmd = *dmd;
+}
 
-       /* don't need the hashtable any more */
-       BLI_edgehash_free(edges, NULL);
+static void displaceModifier_foreachObjectLink(ModifierData *md, Object *ob,
+                                         ObjectWalkFunc walk, void *userData)
+{
+       DisplaceModifierData *dmd = (DisplaceModifierData*) md;
 
-       for (i=0; i<inDLM->totface; i++) {
-               MFace *inMF = &inDLM->mface[i];
-               MFace *mf = &dlm->mface[dlm->totface++];
-               MFace *mf2;
-               TFace *tf = NULL;
-               MCol *mc = NULL;
+       walk(userData, ob, &dmd->map_object);
+}
 
-               *mf = *inMF;
-               mf->v1 = indexMap[inMF->v1].new;
-               mf->v2 = indexMap[inMF->v2].new;
-               mf->v3 = indexMap[inMF->v3].new;
-               if(inMF->v4)
-                       mf->v4 = indexMap[inMF->v4].new;
+static void displaceModifier_foreachIDLink(ModifierData *md, Object *ob,
+                                           IDWalkFunc walk, void *userData)
+{
+       DisplaceModifierData *dmd = (DisplaceModifierData*) md;
 
-               /* if vertices are to be merged with the final copies of their
-                * merge targets, calculate that final copy
-                */
-               if(indexMap[inMF->v1].merge_final)
-                       mf->v1 = calc_mapping(indexMap, indexMap[inMF->v1].merge, count-2);
-               if(indexMap[inMF->v2].merge_final)
-                       mf->v2 = calc_mapping(indexMap, indexMap[inMF->v2].merge, count-2);
-               if(indexMap[inMF->v3].merge_final)
-                       mf->v3 = calc_mapping(indexMap, indexMap[inMF->v3].merge, count-2);
-               if(inMF->v4 && indexMap[inMF->v4].merge_final)
-                       mf->v4 = calc_mapping(indexMap, indexMap[inMF->v4].merge, count-2);
-
-               if (initFlags) mf->flag |= ME_FACE_STEPINDEX;
-
-               if (inDLM->tface) {
-                       TFace *inTF = &inDLM->tface[i];
-                       tf = &dlm->tface[dlm->totface-1];
-
-                       *tf = *inTF;
-               } else if (inDLM->mcol) {
-                       MCol *inMC = &inDLM->mcol[i*4];
-                       mc = &dlm->mcol[(dlm->totface-1)*4];
-
-                       mc[0] = inMC[0];
-                       mc[1] = inMC[1];
-                       mc[2] = inMC[2];
-                       mc[3] = inMC[3];
-               }
-               
-               test_index_face(mf, mc, tf, inMF->v4?4:3);
+       walk(userData, ob, (ID **)&dmd->texture);
 
-               /* if the face has fewer than 3 vertices, don't create it */
-               if(mf->v3 == 0)
-                       dlm->totface--;
+       displaceModifier_foreachObjectLink(md, ob, (ObjectWalkFunc) walk, userData);
+}
 
-               for(j=0; j < count - 1; j++)
-               {
-                       mf2 = &dlm->mface[dlm->totface++];
+static int displaceModifier_isDisabled(ModifierData *md)
+{
+       DisplaceModifierData *dmd = (DisplaceModifierData*) md;
 
-                       *mf2 = *mf;
+       return !dmd->texture;
+}
 
-                       mf2->v1 = calc_mapping(indexMap, inMF->v1, j);
-                       mf2->v2 = calc_mapping(indexMap, inMF->v2, j);
-                       mf2->v3 = calc_mapping(indexMap, inMF->v3, j);
-                       if (inMF->v4)
-                               mf2->v4 = calc_mapping(indexMap, inMF->v4, j);
+static void displaceModifier_updateDepgraph(
+                                    ModifierData *md, DagForest *forest,
+                                    Object *ob, DagNode *obNode)
+{
+       DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+
+       if(dmd->map_object) {
+               DagNode *curNode = dag_get_node(forest, dmd->map_object);
+
+               dag_add_relation(forest, curNode, obNode,
+                                DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+       }
+}
 
-                       mf2->flag &= ~ME_FACE_STEPINDEX;
+static void get_texture_coords(DisplaceModifierData *dmd, Object *ob,
+                               DerivedMesh *dm,
+                               float (*co)[3], float (*texco)[3],
+                               int numVerts)
+{
+       int i;
+       int texmapping = dmd->texmapping;
 
-                       if (inDLM->tface) {
-                               TFace *inTF = &inDLM->tface[i];
-                               tf = &dlm->tface[dlm->totface-1];
+       if(texmapping == MOD_DISP_MAP_OBJECT) {
+               if(dmd->map_object)
+                       Mat4Invert(dmd->map_object->imat, dmd->map_object->obmat);
+               else /* if there is no map object, default to local */
+                       texmapping = MOD_DISP_MAP_LOCAL;
+       }
 
-                               *tf = *inTF;
-                       } else if (inDLM->mcol) {
-                               MCol *inMC = &inDLM->mcol[i*4];
-                               mc = &dlm->mcol[(dlm->totface-1)*4];
+       /* UVs need special handling, since they come from faces */
+       if(texmapping == MOD_DISP_MAP_UV) {
+               if(dm->getFaceDataArray(dm, LAYERTYPE_TFACE)) {
+                       MFace *mface = dm->dupFaceArray(dm);
+                       MFace *mf;
+                       char *done = MEM_callocN(sizeof(*done) * numVerts,<