Sculpt:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 25 Nov 2009 17:51:16 +0000 (17:51 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 25 Nov 2009 17:51:16 +0000 (17:51 +0000)
svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r24483:24889

82 files changed:
intern/guardedalloc/intern/mallocn.c
release/scripts/ui/properties_data_modifier.py
release/scripts/ui/properties_physics_softbody.py
release/scripts/ui/properties_render.py
release/scripts/ui/space_console.py
release/scripts/ui/space_sequencer.py
release/scripts/ui/space_view3d.py
release/scripts/ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_btex.h [new file with mode: 0644]
source/blender/blenkernel/BKE_customdata.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/BKE_multires.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/BKE_subsurf.h
source/blender/blenkernel/intern/CCGSubSurf.c
source/blender/blenkernel/intern/CCGSubSurf.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/btex.c [new file with mode: 0644]
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/multires.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/paint.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/pointcache.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenlib/BLI_math_matrix.h
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/BLI_pbvh.h [new file with mode: 0644]
source/blender/blenlib/BLI_string.h
source/blender/blenlib/CMakeLists.txt
source/blender/blenlib/SConscript
source/blender/blenlib/intern/math_matrix.c
source/blender/blenlib/intern/math_vector.c
source/blender/blenlib/intern/math_vector_inline.c
source/blender/blenlib/intern/pbvh.c [new file with mode: 0644]
source/blender/blenlib/intern/string.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/include/ED_sculpt.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/mesh/editface.c
source/blender/editors/object/object_modifier.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_stroke.c
source/blender/editors/sculpt_paint/paint_undo.c [new file with mode: 0644]
source/blender/editors/sculpt_paint/paint_utils.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/sculpt_paint/sculpt_intern.h
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/util/ed_util.c
source/blender/editors/util/undo.c
source/blender/gpu/gpu_buffers.h
source/blender/gpu/intern/gpu_buffers.c
source/blender/makesdna/DNA_brush_types.h
source/blender/makesdna/DNA_customdata_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/makesrna/intern/rna_brush.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/render/intern/source/convertblender.c
source/blender/windowmanager/intern/wm_files.c

index d1114af..5f7c725 100644 (file)
@@ -402,15 +402,51 @@ void MEM_printmemlist_stats()
        }
        totpb= b+1;
 
+#define MEM_IN_MB(mem) ((double)mem/(double)(1024*1024))
+
        /* sort by length and print */
        qsort(printblock, totpb, sizeof(MemPrintBlock), compare_len);
-       printf("\ntotal memory len: %.3f MB\n", (double)mem_in_use/(double)(1024*1024));
+       printf("\ntotal memory len: %.3f MB\n", MEM_IN_MB(mem_in_use));
        for(a=0, pb=printblock; a<totpb; a++, pb++)
-               printf("%s items: %d, len: %.3f MB\n", pb->name, pb->items, (double)pb->len/(double)(1024*1024));
+               printf("%s items: %d, len: %.3f MB\n", pb->name, pb->items, MEM_IN_MB(pb->len));
+       
+       {
+               uintptr_t other= mem_in_use;
+
+               printf(
+                       "from pylab import *\n"
+                       "\n"
+                       "figure(1, figsize=(10,10))\n"
+                       "\n"
+                       "memory = [\n");
+
+               for(a=0, pb=printblock; a<totpb; a++, pb++) {
+                       printf("[\"%s (%.3f MB)\", %.3f],\n", pb->name, MEM_IN_MB(pb->len), MEM_IN_MB(pb->len));
+                       other -= pb->len;
+
+                       if((double)pb->len/(double)mem_in_use < 0.025)
+                               break;
+               }
+
+               printf(
+                       "[\"other\", %.3f]]\n"
+                       "\n"
+                       "labels = [m[0] for m in memory]\n"
+                       "fracs = [m[1] for m in memory]\n"
+                       "map = cm.get_cmap(\"Paired\")\n"
+                       "colors = [map(float(i)/len(fracs)) for i in range(0, len(fracs))]\n"
+                       "\n"
+                       "pie(fracs, labels=labels, colors=colors, autopct='%%1.1f%%%%')\n"
+                       "title(\"Memory Usage: %.3f MB\")\n"
+                       "\n"
+                       "show()\n", MEM_IN_MB(other), MEM_IN_MB(mem_in_use));
+       }
 
        free(printblock);
        
        mem_unlock_thread();
+
+#undef MEM_IN_MB
 }
 
 /* Prints in python syntax for easy */
index 46355ba..74f16ed 100644 (file)
@@ -430,16 +430,21 @@ class DATA_PT_modifiers(DataButtonsPanel):
             layout.row().prop(md, "subdivision_type", expand=True)
         else:
             layout.row().prop(md, "subdivision_type", text="")
-        layout.prop(md, "level")
 
         split = layout.split()
-
         col = split.column()
-        col.operator("object.multires_subdivide", text="Subdivide")
+        col.prop(md, "levels", text="Preview")
+        col.prop(md, "sculpt_levels", text="Sculpt")
+        col.prop(md, "render_levels", text="Render")
 
         if wide_ui:
             col = split.column()
+
+        col.operator("object.multires_subdivide", text="Subdivide")
         col.operator("object.multires_higher_levels_delete", text="Delete Higher")
+        row = col.row()
+        row.enabled = md.total_levels > 0
+        row.prop(md, "external")
 
     def PARTICLE_INSTANCE(self, layout, ob, md, wide_ui):
         layout.prop(md, "object")
@@ -597,7 +602,6 @@ class DATA_PT_modifiers(DataButtonsPanel):
             col = split.column()
         col.label(text="Options:")
         col.prop(md, "optimal_draw", text="Optimal Display")
-        col.prop(md, "subsurf_uv")
 
     def SURFACE(self, layout, ob, md, wide_ui):
         layout.label(text="See Fields panel.")
index 60b9c08..4cecb7e 100644 (file)
@@ -177,6 +177,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel):
         col.prop(softbody, "bending")
         col.prop(softbody, "spring_length", text="Length")
         col.prop_object(softbody, "spring_vertex_group", ob, "vertex_groups", text="Springs:")
+        col.item_pointerR(softbody, "spring_vertex_group", ob, "vertex_groups", text="Springs:")
 
         if wide_ui:
             col = split.column()
index 3f176e9..f267a0c 100644 (file)
@@ -554,4 +554,4 @@ bpy.types.register(RENDER_PT_output)
 bpy.types.register(RENDER_PT_encoding)
 bpy.types.register(RENDER_PT_performance)
 bpy.types.register(RENDER_PT_post_processing)
-bpy.types.register(RENDER_PT_stamp)
\ No newline at end of file
+bpy.types.register(RENDER_PT_stamp)
index 63e8055..e4c4072 100644 (file)
@@ -69,6 +69,7 @@ class CONSOLE_MT_console(bpy.types.Menu):
         layout.operator("console.copy")
         layout.operator("console.paste")
         layout.menu("CONSOLE_MT_language")
+        layout.itemM("CONSOLE_MT_language")
 
 
 class CONSOLE_MT_report(bpy.types.Menu):
@@ -82,6 +83,8 @@ class CONSOLE_MT_report(bpy.types.Menu):
         layout.operator("console.report_delete")
         layout.operator("console.report_copy")
 
+class CONSOLE_MT_language(bpy.types.Menu):
+    bl_label = "Languages..."
 
 class CONSOLE_MT_language(bpy.types.Menu):
     bl_label = "Languages..."
index 8ac77a5..86c6b97 100644 (file)
@@ -238,6 +238,7 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
                 layout.separator()
                 layout.operator("sequencer.image_change")
                 layout.operator("sequencer.rendersize")
+                layout.itemO("sequencer.rendersize")
             elif stype == 'SCENE':
                 layout.separator()
                 layout.operator("sequencer.scene_change", text="Change Scene")
@@ -245,6 +246,7 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
                 layout.separator()
                 layout.operator("sequencer.movie_change")
                 layout.operator("sequencer.rendersize")
+                layout.itemO("sequencer.rendersize")
 
         layout.separator()
 
index edc526f..f9401c0 100644 (file)
@@ -376,6 +376,7 @@ class VIEW3D_MT_select_particle(bpy.types.Menu):
         layout.operator("particle.select_all_toggle", text="Select/Deselect All")
         layout.operator("particle.select_linked")
         layout.operator("particle.select_inverse")
+        layout.itemO("particle.select_inverse")
 
         layout.separator()
 
@@ -409,6 +410,8 @@ class VIEW3D_MT_select_edit_mesh(bpy.types.Menu):
         layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
         layout.operator("mesh.faces_select_interior", text="Interior Faces")
         layout.operator("mesh.select_axis", text="Side of Active")
+        layout.itemO("mesh.faces_select_interior", text="Interior Faces")
+        layout.itemO("mesh.select_axis", text="Side of Active")
 
         layout.separator()
 
@@ -1530,6 +1533,10 @@ class VIEW3D_PT_3dview_properties(bpy.types.Panel):
 
         layout.column().prop(scene, "cursor_location", text="3D Cursor:")
 
+class VIEW3D_PT_3dview_item(bpy.types.Panel):
+    bl_space_type = 'VIEW_3D'
+    bl_region_type = 'UI'
+    bl_label = "Item"
 
 class VIEW3D_PT_3dview_name(bpy.types.Panel):
     bl_space_type = 'VIEW_3D'
index f9147dc..4e2e2f1 100644 (file)
@@ -105,6 +105,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel):
         col.operator("mesh.duplicate_move")
         col.operator("mesh.spin")
         col.operator("mesh.screw")
+        col.itemO("mesh.flip_normals")
 
         col = layout.column(align=True)
         col.label(text="Remove:")
@@ -553,6 +554,9 @@ class VIEW3D_PT_tools_brush(PaintPanel):
                 if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'):
                     col.row().prop(brush, "direction", expand=True)
 
+                if brush.sculpt_tool in ('DRAW', 'INFLATE', 'LAYER'):
+                    col.prop(brush, "use_accumulate")
+
                 if brush.sculpt_tool == 'LAYER':
                     col.prop(brush, "use_persistent")
                     col.operator("sculpt.set_persistent_base")
@@ -695,8 +699,8 @@ class VIEW3D_PT_sculpt_options(PaintPanel):
         sculpt = context.tool_settings.sculpt
 
         col = layout.column()
-        col.prop(sculpt, "partial_redraw", text="Partial Refresh")
         col.prop(sculpt, "show_brush")
+        col.prop(sculpt, "fast_navigate")
 
         split = self.layout.split()
 
index 514411e..bcafc4c 100644 (file)
@@ -60,12 +60,24 @@ struct MCol;
 struct ColorBand;
 struct GPUVertexAttribs;
 struct GPUDrawObject;
+struct ListBase;
+struct PBVH;
 
 /* number of sub-elements each mesh element has (for interpolation) */
 #define SUB_ELEMS_VERT 0
 #define SUB_ELEMS_EDGE 2
 #define SUB_ELEMS_FACE 4
 
+typedef struct DMGridData {
+       float co[3];
+       float no[3];
+} DMGridData;
+
+typedef struct DMGridAdjacency {
+       int index[4];
+       int rotation[4];
+} DMGridAdjacency;
+
 typedef struct DerivedMesh DerivedMesh;
 struct DerivedMesh {
        /* Private DerivedMesh data, only for internal DerivedMesh use */
@@ -74,6 +86,7 @@ struct DerivedMesh {
        int needsFree; /* checked on ->release, is set to 0 for cached results */
        int deformedOnly; /* set by modifier stack if only deformed from original */
        BVHCache bvhCache;
+
        struct GPUDrawObject *drawObject;
 
        /* Misc. Queries */
@@ -133,6 +146,12 @@ struct DerivedMesh {
        void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
        void *(*getFaceDataArray)(DerivedMesh *dm, int type);
 
+       /* optional grid access for subsurf */
+       int (*getNumGrids)(DerivedMesh *dm);
+       int (*getGridSize)(DerivedMesh *dm);
+       DMGridData **(*getGridData)(DerivedMesh *dm);
+       DMGridAdjacency *(*getGridAdjacency)(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
@@ -181,6 +200,14 @@ struct DerivedMesh {
        /* Get vertex normal, undefined if index is not valid */
        void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]);
 
+       /* Get a map of vertices to faces
+        */
+       struct ListBase *(*getFaceMap)(DerivedMesh *dm);
+
+       /* Get the BVH used for paint modes
+        */
+       struct PBVH *(*getPBVH)(struct Object *ob, DerivedMesh *dm);
+
        /* Drawing Operations */
 
        /* Draw all vertices as bgl points (no options) */
@@ -205,8 +232,8 @@ struct DerivedMesh {
         *
         * Also called for *final* editmode DerivedMeshes
         */
-       void (*drawFacesSolid)(DerivedMesh *dm,
-                              int (*setMaterial)(int, void *attribs));
+       void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
+                              int fast, int (*setMaterial)(int, void *attribs));
 
        /* Draw all faces
         *  o If useTwoSided, draw front and back using col arrays
diff --git a/source/blender/blenkernel/BKE_btex.h b/source/blender/blenkernel/BKE_btex.h
new file mode 100644 (file)
index 0000000..cb73fd1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * $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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_BTEX_H
+#define BKE_BTEX_H
+
+#define BTEX_TYPE_IMAGE        0
+#define BTEX_TYPE_MESH 1
+
+#define BTEX_LAYER_NAME_MAX    64
+
+typedef struct BTex BTex;
+typedef struct BTexLayer BTexLayer;
+
+/* Create/Free */
+
+BTex *btex_create(int type);
+void btex_free(BTex *btex);
+
+/* File read/write/remove */
+
+int btex_read_open(BTex *btex, char *filename);
+int btex_read_layer(BTex *btex, BTexLayer *blay);
+int btex_read_data(BTex *btex, int size, void *data);
+void btex_read_close(BTex *btex);
+
+int btex_write_open(BTex *btex, char *filename);
+int btex_write_layer(BTex *btex, BTexLayer *blay);
+int btex_write_data(BTex *btex, int size, void *data);
+void btex_write_close(BTex *btex);
+
+void btex_remove(char *filename);
+
+/* Layers */
+
+BTexLayer *btex_layer_find(BTex *btex, int type, char *name);
+BTexLayer *btex_layer_add(BTex *btex, int type, char *name);
+void btex_layer_remove(BTex *btex, BTexLayer *blay);
+
+/* Mesh */
+
+void btex_mesh_set_grids(BTex *btex, int totgrid, int gridsize, int datasize);
+
+#endif /* BKE_BTEX_H */
+
index 95ee918..5ce4b39 100644 (file)
@@ -278,4 +278,20 @@ int CustomData_verify_versions(struct CustomData *data, int index);
 void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata);
 void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
 void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize);
+
+/* External file storage */
+
+void CustomData_external_add(struct CustomData *data,
+       int type, const char *name, int totelem);
+void CustomData_external_remove(struct CustomData *data,
+       int type, int totelem);
+void CustomData_external_remove_object(struct CustomData *data);
+int CustomData_external_test(struct CustomData *data, int type);
+
+void CustomData_external_write(struct CustomData *data,
+       CustomDataMask mask, int totelem, int free);
+void CustomData_external_read(struct CustomData *data,
+       CustomDataMask mask, int totelem);
+
 #endif
+
index 09c1ab9..edb4e2c 100644 (file)
@@ -47,6 +47,7 @@ struct Object;
 struct MTFace;
 struct VecNor;
 struct CustomData;
+struct Scene;
 
 #ifdef __cplusplus
 extern "C" {
index c30bfa3..6fe6a68 100644 (file)
@@ -228,7 +228,7 @@ typedef struct ModifierTypeInfo {
         *
         * This function is optional (assumes never disabled if not present).
         */
-       int (*isDisabled)(struct ModifierData *md);
+       int (*isDisabled)(struct ModifierData *md, int userRenderParams);
 
        /* Add the appropriate relations to the DEP graph depending on the
         * modifier data. 
index a331479..53ead3a 100644 (file)
@@ -39,23 +39,6 @@ typedef struct MultiresSubsurf {
        int local_mmd;
 } MultiresSubsurf;
 
-/* MultiresDM */
-struct Object *MultiresDM_get_object(struct DerivedMesh *dm);
-struct Mesh *MultiresDM_get_mesh(struct DerivedMesh *dm);
-struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*, int, int, int);
-void *MultiresDM_get_vertnorm(struct DerivedMesh *);
-void *MultiresDM_get_orco(struct DerivedMesh *);
-struct MVert *MultiresDM_get_subco(struct DerivedMesh *);
-struct ListBase *MultiresDM_get_vert_face_map(struct DerivedMesh *);
-struct ListBase *MultiresDM_get_vert_edge_map(struct DerivedMesh *);
-int *MultiresDM_get_face_offsets(struct DerivedMesh *);
-int MultiresDM_get_totlvl(struct DerivedMesh *);
-int MultiresDM_get_lvl(struct DerivedMesh *);
-void MultiresDM_set_update(struct DerivedMesh *, void (*)(struct DerivedMesh*));
-
-/* The displacements will only be updated when
-   the MultiresDM has been marked as modified */
-void MultiresDM_mark_as_modified(struct DerivedMesh *);
 void multires_mark_as_modified(struct Object *ob);
 
 void multires_force_update(struct Object *ob);
@@ -64,10 +47,9 @@ struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*
                                                    struct Object *, int, int);
 
 struct MultiresModifierData *find_multires_modifier(struct Object *ob);
-int multiresModifier_switch_level(struct Object *, const int);
 void multiresModifier_join(struct Object *);
 void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
-void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int distance,
+void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob,
                                int updateblock, int simple);
 int multiresModifier_reshape(struct MultiresModifierData *mmd, struct Object *dst, struct Object *src);
 
index b532b08..1688ecb 100644 (file)
@@ -34,6 +34,7 @@ struct MultireModifierData;
 struct MVert;
 struct Object;
 struct Paint;
+struct PBVH;
 struct Scene;
 struct StrokeCache;
 
@@ -68,25 +69,24 @@ typedef struct SculptSession {
        struct MFace *mface;
        int totvert, totface;
        float *face_normals;
-
+       struct PBVH *tree;
        struct Object *ob;
        struct KeyBlock *kb, *refkb;
        
        /* Mesh connectivity */
        struct ListBase *fmap;
-       struct IndexNode *fmap_mem;
-       int fmap_size;
 
        /* Used temporarily per-stroke */
        float *vertexcosnos;
-       ListBase damaged_rects;
-       ListBase damaged_verts;
+
+       /* Partial redraw */
+       int partial_redraw;
        
        /* Used to cache the render of the active texture */
        unsigned int texcache_side, *texcache, texcache_actual;
 
        /* Layer brush persistence between strokes */
-       float (*mesh_co_orig)[3]; /* Copy of the mesh vertices' locations */
+       float (*layer_co)[3]; /* Copy of the mesh vertices' locations */
        float *layer_disps; /* Displacements for each vertex */
 
        struct SculptStroke *stroke;
index f6dc22f..7b8adb7 100644 (file)
@@ -34,21 +34,60 @@ struct DerivedMesh;
 struct EditMesh;
 struct MultiresSubsurf;
 struct SubsurfModifierData;
+struct _CCGSubsurf;
+struct _CCGVert;
+struct _CCGEdge;
+struct _CCGFace;
+struct PBVH;
+struct DMGridData;
+struct DMGridAdjacency;
 
-struct DerivedMesh *subsurf_make_derived_from_derived(
-                        struct DerivedMesh *dm,
-                        struct SubsurfModifierData *smd,
-                        int useRenderParams, float (*vertCos)[3],
-                        int isFinalCalc, int editMode);
+/**************************** External *****************************/
 
-struct DerivedMesh *subsurf_make_derived_from_derived_with_multires(
+struct DerivedMesh *subsurf_make_derived_from_derived(
                         struct DerivedMesh *dm,
                         struct SubsurfModifierData *smd,
-                       struct MultiresSubsurf *ms,
                         int useRenderParams, float (*vertCos)[3],
                         int isFinalCalc, int editMode);
 
 void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]);
 
+/**************************** Internal *****************************/
+
+typedef struct CCGDerivedMesh {
+       DerivedMesh dm;
+
+       struct _CCGSubSurf *ss;
+       int freeSS;
+       int drawInteriorEdges, useSubsurfUv;
+
+       struct {int startVert; struct _CCGVert *vert;} *vertMap;
+       struct {int startVert; int startEdge; struct _CCGEdge *edge;} *edgeMap;
+       struct {int startVert; int startEdge;
+               int startFace; struct _CCGFace *face;} *faceMap;
+
+       short *edgeFlags;
+       char *faceFlags;
+
+       struct PBVH *pbvh;
+
+       struct DMGridData **gridData;
+       struct DMGridAdjacency *gridAdjacency;
+       struct _CCGFace **gridFaces;
+
+       struct {
+               struct MultiresModifierData *mmd;
+               int local_mmd;
+
+               int lvl, totlvl;
+               float (*orco)[3];
+
+               Object *ob;
+               int modified;
+
+               void (*update)(DerivedMesh*);
+       } multires;
+} CCGDerivedMesh;
+
 #endif
 
index 355ea70..7c2c6d4 100644 (file)
@@ -1133,6 +1133,643 @@ CCGError ccgSubSurf_processSync(CCGSubSurf *ss) {
        return eCCGError_None;
 }
 
+#define FACE_getIFNo(f, lvl, S, x, y)          _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset)
+#define FACE_calcIFNo(f, lvl, S, x, y, no)     _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
+static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
+       CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
+       int numEffectedV, int numEffectedE, int numEffectedF) {
+       int i,ptrIdx;
+       int subdivLevels = ss->subdivLevels;
+       int lvl = ss->subdivLevels;
+       int edgeSize = 1 + (1<<lvl);
+       int gridSize = 1 + (1<<(lvl-1));
+       int normalDataOffset = ss->normalDataOffset;
+       int vertDataSize = ss->meshIFC.vertDataSize;
+
+       for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+               CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+               int S, x, y;
+
+               for (S=0; S<f->numVerts; S++) {
+                       for (y=0; y<gridSize-1; y++)
+                               for (x=0; x<gridSize-1; x++)
+                                       NormZero(FACE_getIFNo(f, lvl, S, x, y));
+
+                       if (FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected)
+                               for (x=0; x<gridSize-1; x++)
+                                       NormZero(FACE_getIFNo(f, lvl, S, x, gridSize-1));
+                       if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
+                               for (y=0; y<gridSize-1; y++)
+                                       NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, y));
+                       if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
+                               NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1));
+               }
+       }
+
+       for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+               CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+               int S, x, y;
+               float no[3];
+
+               for (S=0; S<f->numVerts; S++) {
+                       int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected);
+                       int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected);
+                       int yLimitNext = xLimit;
+                       int xLimitPrev = yLimit;
+                       
+                       for (y=0; y<gridSize - 1; y++) {
+                               for (x=0; x<gridSize - 1; x++) {
+                                       int xPlusOk = (!xLimit || x<gridSize-2);
+                                       int yPlusOk = (!yLimit || y<gridSize-2);
+
+                                       FACE_calcIFNo(f, lvl, S, x, y, no);
+
+                                       NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+0), no);
+                                       if (xPlusOk)
+                                               NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+0), no);
+                                       if (yPlusOk)
+                                               NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+1), no);
+                                       if (xPlusOk && yPlusOk) {
+                                               if (x<gridSize-2 || y<gridSize-2 || FACE_getVerts(f)[S]->flags&Vert_eEffected) {
+                                                       NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no);
+                                               }
+                                       }
+
+                                       if (x==0 && y==0) {
+                                               int K;
+
+                                               if (!yLimitNext || 1<gridSize-1)
+                                                       NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, 1), no);
+                                               if (!xLimitPrev || 1<gridSize-1)
+                                                       NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, 1, 0), no);
+
+                                               for (K=0; K<f->numVerts; K++) {
+                                                       if (K!=S) {
+                                                               NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
+                                                       }
+                                               }
+                                       } else if (y==0) {
+                                               NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no);
+                                               if (!yLimitNext || x<gridSize-2)
+                                                       NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x+1), no);
+                                       } else if (x==0) {
+                                               NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no);
+                                               if (!xLimitPrev || y<gridSize-2)
+                                                       NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y+1, 0), no);
+                                       }
+                               }
+                       }
+               }
+       }
+               // XXX can I reduce the number of normalisations here?
+       for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
+               CCGVert *v = (CCGVert*) effectedV[ptrIdx];
+               float length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset);
+
+               NormZero(no);
+
+               for (i=0; i<v->numFaces; i++) {
+                       CCGFace *f = v->faces[i];
+                       NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1));
+               }
+
+               length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
+
+               if (length>EPSILON) {
+                       float invLength = 1.0f/length;
+                       no[0] *= invLength;
+                       no[1] *= invLength;
+                       no[2] *= invLength;
+               } else {
+                       NormZero(no);
+               }
+
+               for (i=0; i<v->numFaces; i++) {
+                       CCGFace *f = v->faces[i];
+                       NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no);
+               }
+       }
+       for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+               CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
+
+               if (e->numFaces) {
+                       CCGFace *fLast = e->faces[e->numFaces-1];
+                       int x;
+
+                       for (i=0; i<e->numFaces-1; i++) {
+                               CCGFace *f = e->faces[i];
+
+                               for (x=1; x<edgeSize-1; x++) {
+                                       NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+                                                       _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
+                               }
+                       }
+
+                       for (i=0; i<e->numFaces-1; i++) {
+                               CCGFace *f = e->faces[i];
+
+                               for (x=1; x<edgeSize-1; x++) {
+                                       NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+                                                       _face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
+                               }
+                       }
+               }
+       }
+       for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+               CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+               int S;
+
+               for (S=0; S<f->numVerts; S++) {
+                       NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1),
+                                        FACE_getIFNo(f, lvl, S, gridSize-1, 0));
+               }
+       }
+       for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+               CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+               int S, x, y;
+
+               for (S=0; S<f->numVerts; S++) {
+                       for (y=0; y<gridSize; y++) {
+                               for (x=0; x<gridSize; x++) {
+                                       float *no = FACE_getIFNo(f, lvl, S, x, y);
+                                       float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
+
+                                       if (length>EPSILON) {
+                                               float invLength = 1.0f/length;
+                                               no[0] *= invLength;
+                                               no[1] *= invLength;
+                                               no[2] *= invLength;
+                                       } else {
+                                               NormZero(no);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+#undef FACE_getIFNo
+
+#define VERT_getCo(v, lvl)                             _vert_getCo(v, lvl, vertDataSize)
+#define EDGE_getCo(e, lvl, x)                  _edge_getCo(e, lvl, x, vertDataSize)
+#define FACE_getIECo(f, lvl, S, x)             _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
+#define FACE_getIFCo(f, lvl, S, x, y)  _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
+static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
+       CCGVert **effectedV, CCGEdge **effectedE, CCGFace **effectedF,
+       int numEffectedV, int numEffectedE, int numEffectedF, int curLvl) {
+       int subdivLevels = ss->subdivLevels;
+       int edgeSize = 1 + (1<<curLvl);
+       int gridSize = 1 + (1<<(curLvl-1));
+       int nextLvl = curLvl+1;
+       int ptrIdx, S, y, x, i, cornerIdx;
+       void *q = ss->q, *r = ss->r;
+       int vertDataSize = ss->meshIFC.vertDataSize;
+
+       for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+               CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+
+                       /* interior face midpoints
+                        *  o old interior face points
+                        */
+               for (S=0; S<f->numVerts; S++) {
+                       for (y=0; y<gridSize-1; y++) {
+                               for (x=0; x<gridSize-1; x++) {
+                                       int fx = 1 + 2*x;
+                                       int fy = 1 + 2*y;
+                                       void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0);
+                                       void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0);
+                                       void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1);
+                                       void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
+                                       void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+                                       VertDataAvg4(co, co0, co1, co2, co3);
+                               }
+                       }
+               }
+
+                       /* interior edge midpoints
+                        *  o old interior edge points
+                        *  o new interior face midpoints
+                        */
+               for (S=0; S<f->numVerts; S++) {
+                       for (x=0; x<gridSize-1; x++) {
+                               int fx = x*2 + 1;
+                               void *co0 = FACE_getIECo(f, curLvl, S, x+0);
+                               void *co1 = FACE_getIECo(f, curLvl, S, x+1);
+                               void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx);
+                               void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
+                               void *co = FACE_getIECo(f, nextLvl, S, fx);
+                               
+                               VertDataAvg4(co, co0, co1, co2, co3);
+                       }
+
+                                       /* interior face interior edge midpoints
+                                        *  o old interior face points
+                                        *  o new interior face midpoints
+                                        */
+
+                               /* vertical */
+                       for (x=1; x<gridSize-1; x++) {
+                               for (y=0; y<gridSize-1; y++) {
+                                       int fx = x*2;
+                                       int fy = y*2+1;
+                                       void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0);
+                                       void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1);
+                                       void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy);
+                                       void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
+                                       void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+                                       VertDataAvg4(co, co0, co1, co2, co3);
+                               }
+                       }
+
+                               /* horizontal */
+                       for (y=1; y<gridSize-1; y++) {
+                               for (x=0; x<gridSize-1; x++) {
+                                       int fx = x*2+1;
+                                       int fy = y*2;
+                                       void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y);
+                                       void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y);
+                                       void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1);
+                                       void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
+                                       void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+                                       VertDataAvg4(co, co0, co1, co2, co3);
+                               }
+                       }
+               }
+       }
+
+               /* exterior edge midpoints
+                *  o old exterior edge points
+                *  o new interior face midpoints
+                */
+       for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+               CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
+               float sharpness = EDGE_getSharpness(e, curLvl);
+
+               if (_edge_isBoundary(e) || sharpness>1.0) {
+                       for (x=0; x<edgeSize-1; x++) {
+                               int fx = x*2 + 1;
+                               void *co0 = EDGE_getCo(e, curLvl, x+0);
+                               void *co1 = EDGE_getCo(e, curLvl, x+1);
+                               void *co = EDGE_getCo(e, nextLvl, fx);
+
+                               VertDataCopy(co, co0);
+                               VertDataAdd(co, co1);
+                               VertDataMulN(co, 0.5);
+                       }
+               } else {
+                       for (x=0; x<edgeSize-1; x++) {
+                               int fx = x*2 + 1;
+                               void *co0 = EDGE_getCo(e, curLvl, x+0);
+                               void *co1 = EDGE_getCo(e, curLvl, x+1);
+                               void *co = EDGE_getCo(e, nextLvl, fx);
+                               int numFaces = 0;
+
+                               VertDataCopy(q, co0);
+                               VertDataAdd(q, co1);
+
+                               for (i=0; i<e->numFaces; i++) {
+                                       CCGFace *f = e->faces[i];
+                                       VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
+                                       numFaces++;
+                               }
+
+                               VertDataMulN(q, 1.0f/(2.0f+numFaces));
+
+                               VertDataCopy(r, co0);
+                               VertDataAdd(r, co1);
+                               VertDataMulN(r, 0.5);
+
+                               VertDataCopy(co, q);
+                               VertDataSub(r, q);
+                               VertDataMulN(r, sharpness);
+                               VertDataAdd(co, r);
+                       }
+               }
+       }
+
+               /* exterior vertex shift
+                *  o old vertex points (shifting)
+                *  o old exterior edge points
+                *  o new interior face midpoints
+                */
+       for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
+               CCGVert *v = (CCGVert*) effectedV[ptrIdx];
+               void *co = VERT_getCo(v, curLvl);
+               void *nCo = VERT_getCo(v, nextLvl);
+               int sharpCount = 0, allSharp = 1;
+               float avgSharpness = 0.0;
+               int seam = VERT_seam(v), seamEdges = 0;
+
+               for (i=0; i<v->numEdges; i++) {
+                       CCGEdge *e = v->edges[i];
+                       float sharpness = EDGE_getSharpness(e, curLvl);
+
+                       if (seam && _edge_isBoundary(e))
+                               seamEdges++;
+
+                       if (sharpness!=0.0f) {
+                               sharpCount++;
+                               avgSharpness += sharpness;
+                       } else {
+                               allSharp = 0;
+                       }
+               }
+
+               if(sharpCount) {
+                       avgSharpness /= sharpCount;
+                       if (avgSharpness>1.0) {
+                               avgSharpness = 1.0;
+                       }
+               }
+
+               if (seam && seamEdges < 2)
+                       seam = 0;
+
+               if (!v->numEdges) {
+                       VertDataCopy(nCo, co);
+               } else if (_vert_isBoundary(v)) {
+                       int numBoundary = 0;
+
+                       VertDataZero(r);
+                       for (i=0; i<v->numEdges; i++) {
+                               CCGEdge *e = v->edges[i];
+                               if (_edge_isBoundary(e)) {
+                                       VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+                                       numBoundary++;
+                               }
+                       }
+
+                       VertDataCopy(nCo, co);
+                       VertDataMulN(nCo, 0.75);
+                       VertDataMulN(r, 0.25f/numBoundary);
+                       VertDataAdd(nCo, r);
+               } else {
+                       int cornerIdx = (1 + (1<<(curLvl))) - 2;
+                       int numEdges = 0, numFaces = 0;
+
+                       VertDataZero(q);
+                       for (i=0; i<v->numFaces; i++) {
+                               CCGFace *f = v->faces[i];
+                               VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
+                               numFaces++;
+                       }
+                       VertDataMulN(q, 1.0f/numFaces);
+                       VertDataZero(r);
+                       for (i=0; i<v->numEdges; i++) {
+                               CCGEdge *e = v->edges[i];
+                               VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
+                               numEdges++;
+                       }
+                       VertDataMulN(r, 1.0f/numEdges);
+
+                       VertDataCopy(nCo, co);
+                       VertDataMulN(nCo, numEdges-2.0f);
+                       VertDataAdd(nCo, q);
+                       VertDataAdd(nCo, r);
+                       VertDataMulN(nCo, 1.0f/numEdges);
+               }
+
+               if ((sharpCount>1 && v->numFaces) || seam) {
+                       VertDataZero(q);
+
+                       if (seam) {
+                               avgSharpness = 1.0f;
+                               sharpCount = seamEdges;
+                               allSharp = 1;
+                       }
+
+                       for (i=0; i<v->numEdges; i++) {
+                               CCGEdge *e = v->edges[i];
+                               float sharpness = EDGE_getSharpness(e, curLvl);
+
+                               if (seam) {
+                                       if (_edge_isBoundary(e))
+                                               VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+                               } else if (sharpness != 0.0) {
+                                       VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+                               }
+                       }
+
+                       VertDataMulN(q, (float) 1/sharpCount);
+
+                       if (sharpCount!=2 || allSharp) {
+                                       // q = q + (co-q)*avgSharpness
+                               VertDataCopy(r, co);
+                               VertDataSub(r, q);
+                               VertDataMulN(r, avgSharpness);
+                               VertDataAdd(q, r);
+                       }
+
+                               // r = co*.75 + q*.25
+                       VertDataCopy(r, co);
+                       VertDataMulN(r, .75);
+                       VertDataMulN(q, .25);
+                       VertDataAdd(r, q);
+
+                               // nCo = nCo  + (r-nCo)*avgSharpness
+                       VertDataSub(r, nCo);
+                       VertDataMulN(r, avgSharpness);
+                       VertDataAdd(nCo, r);
+               }
+       }
+
+               /* exterior edge interior shift
+                *  o old exterior edge midpoints (shifting)
+                *  o old exterior edge midpoints
+                *  o new interior face midpoints
+                */
+       for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+               CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
+               float sharpness = EDGE_getSharpness(e, curLvl);
+               int sharpCount = 0;
+               float avgSharpness = 0.0;
+
+               if (sharpness!=0.0f) {
+                       sharpCount = 2;
+                       avgSharpness += sharpness;
+
+                       if (avgSharpness>1.0) {
+                               avgSharpness = 1.0;
+                       }
+               } else {
+                       sharpCount = 0;
+                       avgSharpness = 0;
+               }
+
+               if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) {
+                       for (x=1; x<edgeSize-1; x++) {
+                               int fx = x*2;
+                               void *co = EDGE_getCo(e, curLvl, x);
+                               void *nCo = EDGE_getCo(e, nextLvl, fx);
+                               VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
+                               VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
+                               VertDataMulN(r, 0.5);
+                               VertDataCopy(nCo, co);
+                               VertDataMulN(nCo, 0.75);
+                               VertDataMulN(r, 0.25);
+                               VertDataAdd(nCo, r);
+                       }
+               } else {
+                       for (x=1; x<edgeSize-1; x++) {
+                               int fx = x*2;
+                               void *co = EDGE_getCo(e, curLvl, x);
+                               void *nCo = EDGE_getCo(e, nextLvl, fx);
+                               int numFaces = 0;
+
+                               VertDataZero(q);
+                               VertDataZero(r);
+                               VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
+                               VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
+                               for (i=0; i<e->numFaces; i++) {
+                                       CCGFace *f = e->faces[i];
+                                       VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
+                                       VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
+
+                                       VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
+                                       numFaces++;
+                               }
+                               VertDataMulN(q, 1.0/(numFaces*2.0f));
+                               VertDataMulN(r, 1.0/(2.0f + numFaces));
+
+                               VertDataCopy(nCo, co);
+                               VertDataMulN(nCo, (float) numFaces);
+                               VertDataAdd(nCo, q);
+                               VertDataAdd(nCo, r);
+                               VertDataMulN(nCo, 1.0f/(2+numFaces));
+
+                               if (sharpCount==2) {
+                                       VertDataCopy(q, co);
+                                       VertDataMulN(q, 6.0f);
+                                       VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
+                                       VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
+                                       VertDataMulN(q, 1/8.0f);
+
+                                       VertDataSub(q, nCo);
+                                       VertDataMulN(q, avgSharpness);
+                                       VertDataAdd(nCo, q);
+                               }
+                       }
+               }
+       }
+
+       for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+               CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+
+                       /* interior center point shift
+                        *  o old face center point (shifting)
+                        *  o old interior edge points
+                        *  o new interior face midpoints
+                        */
+               VertDataZero(q);
+               for (S=0; S<f->numVerts; S++) {
+                       VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
+               }
+               VertDataMulN(q, 1.0f/f->numVerts);
+               VertDataZero(r);
+               for (S=0; S<f->numVerts; S++) {
+                       VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
+               }
+               VertDataMulN(r, 1.0f/f->numVerts);
+
+               VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
+               VertDataAdd(FACE_getCenterData(f), q);
+               VertDataAdd(FACE_getCenterData(f), r);
+               VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
+
+               for (S=0; S<f->numVerts; S++) {
+                               /* interior face shift
+                                *  o old interior face point (shifting)
+                                *  o new interior edge midpoints
+                                *  o new interior face midpoints
+                                */
+                       for (x=1; x<gridSize-1; x++) {
+                               for (y=1; y<gridSize-1; y++) {
+                                       int fx = x*2;
+                                       int fy = y*2;
+                                       void *co = FACE_getIFCo(f, curLvl, S, x, y);
+                                       void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
+                                       
+                                       VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
+                                               FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
+                                               FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
+                                               FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
+
+                                       VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
+                                               FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
+                                               FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
+                                               FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
+
+                                       VertDataCopy(nCo, co);
+                                       VertDataSub(nCo, q);
+                                       VertDataMulN(nCo, 0.25f);
+                                       VertDataAdd(nCo, r);
+                               }
+                       }
+
+                               /* interior edge interior shift
+                                *  o old interior edge point (shifting)
+                                *  o new interior edge midpoints
+                                *  o new interior face midpoints
+                                */
+                       for (x=1; x<gridSize-1; x++) {
+                               int fx = x*2;
+                               void *co = FACE_getIECo(f, curLvl, S, x);
+                               void *nCo = FACE_getIECo(f, nextLvl, S, fx);
+                               
+                               VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
+                                       FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
+                                       FACE_getIFCo(f, nextLvl, S, fx+1, +1),
+                                       FACE_getIFCo(f, nextLvl, S, fx-1, +1));
+
+                               VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1),
+                                       FACE_getIECo(f, nextLvl, S, fx+1),
+                                       FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
+                                       FACE_getIFCo(f, nextLvl, S, fx, 1));
+
+                               VertDataCopy(nCo, co);
+                               VertDataSub(nCo, q);
+                               VertDataMulN(nCo, 0.25f);
+                               VertDataAdd(nCo, r);
+                       }
+               }
+       }
+
+               /* copy down */
+       edgeSize = 1 + (1<<(nextLvl));
+       gridSize = 1 + (1<<((nextLvl)-1));
+       cornerIdx = gridSize-1;
+       for (i=0; i<numEffectedE; i++) {
+               CCGEdge *e = effectedE[i];
+               VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
+               VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
+       }
+       for (i=0; i<numEffectedF; i++) {
+               CCGFace *f = effectedF[i];
+               for (S=0; S<f->numVerts; S++) {
+                       CCGEdge *e = FACE_getEdges(f)[S];
+                       CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
+
+                       VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
+                       VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
+                       VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
+                       VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
+                       for (x=1; x<gridSize-1; x++) {
+                               void *co = FACE_getIECo(f, nextLvl, S, x);
+                               VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
+                               VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
+                       }
+                       for (x=0; x<gridSize-1; x++) {
+                               int eI = gridSize-1-x;
+                               VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
+                               VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
+                       }
+               }
+       }
+}
+
+
 static void ccgSubSurf__sync(CCGSubSurf *ss) {
        CCGVert **effectedV;
        CCGEdge **effectedE;
@@ -1140,11 +1777,9 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
        int numEffectedV, numEffectedE, numEffectedF;
        int subdivLevels = ss->subdivLevels;
        int vertDataSize = ss->meshIFC.vertDataSize;
-       int i,ptrIdx,cornerIdx;
-       int S,x,y;
-       void *q = ss->q, *r = ss->r;
+       int i, j, ptrIdx, S;
        int curLvl, nextLvl;
-       int j;
+       void *q = ss->q, *r = ss->r;
 
        effectedV = CCGSUBSURF_alloc(ss, sizeof(*effectedV)*ss->vMap->numEntries);
        effectedE = CCGSUBSURF_alloc(ss, sizeof(*effectedE)*ss->eMap->numEntries);
@@ -1175,10 +1810,6 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
                }
        }
 
-#define VERT_getCo(v, lvl)                             _vert_getCo(v, lvl, vertDataSize)
-#define EDGE_getCo(e, lvl, x)                  _edge_getCo(e, lvl, x, vertDataSize)
-#define FACE_getIECo(f, lvl, S, x)             _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
-#define FACE_getIFCo(f, lvl, S, x, y)  _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
        curLvl = 0;
        nextLvl = curLvl+1;
 
@@ -1391,645 +2022,340 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
        }
 
        for (curLvl=1; curLvl<subdivLevels; curLvl++) {
-               int edgeSize = 1 + (1<<curLvl);
-               int gridSize = 1 + (1<<(curLvl-1));
-               nextLvl = curLvl+1;
+               ccgSubSurf__calcSubdivLevel(ss,
+                       effectedV, effectedE, effectedF,
+                       numEffectedV, numEffectedE, numEffectedF, curLvl);
+       }
 
-               for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
-                       CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+       if (ss->calcVertNormals)
+               ccgSubSurf__calcVertNormals(ss,
+                       effectedV, effectedE, effectedF,
+                       numEffectedV, numEffectedE, numEffectedF);
 
-                               /* interior face midpoints
-                                *  o old interior face points
-                                */
-                       for (S=0; S<f->numVerts; S++) {
-                               for (y=0; y<gridSize-1; y++) {
-                                       for (x=0; x<gridSize-1; x++) {
-                                               int fx = 1 + 2*x;
-                                               int fy = 1 + 2*y;
-                                               void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0);
-                                               void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0);
-                                               void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1);
-                                               void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
-                                               void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
-                                               VertDataAvg4(co, co0, co1, co2, co3);
-                                       }
-                               }
-                       }
+       for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
+               CCGVert *v = effectedV[ptrIdx];
+               v->flags = 0;
+       }
+       for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+               CCGEdge *e = effectedE[ptrIdx];
+               e->flags = 0;
+       }
 
-                               /* interior edge midpoints
-                                *  o old interior edge points
-                                *  o new interior face midpoints
-                                */
-                       for (S=0; S<f->numVerts; S++) {
-                               for (x=0; x<gridSize-1; x++) {
-                                       int fx = x*2 + 1;
-                                       void *co0 = FACE_getIECo(f, curLvl, S, x+0);
-                                       void *co1 = FACE_getIECo(f, curLvl, S, x+1);
-                                       void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx);
-                                       void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
-                                       void *co = FACE_getIECo(f, nextLvl, S, fx);
-                                       
-                                       VertDataAvg4(co, co0, co1, co2, co3);
-                               }
+       CCGSUBSURF_free(ss, effectedF);
+       CCGSUBSURF_free(ss, effectedE);
+       CCGSUBSURF_free(ss, effectedV);
+}
 
-                                               /* interior face interior edge midpoints
-                                                *  o old interior face points
-                                                *  o new interior face midpoints
-                                                */
-
-                                       /* vertical */
-                               for (x=1; x<gridSize-1; x++) {
-                                       for (y=0; y<gridSize-1; y++) {
-                                               int fx = x*2;
-                                               int fy = y*2+1;
-                                               void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0);
-                                               void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1);
-                                               void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy);
-                                               void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
-                                               void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
-                                               VertDataAvg4(co, co0, co1, co2, co3);
-                                       }
-                               }
+static void ccgSubSurf__allFaces(CCGSubSurf *ss, CCGFace ***faces, int *numFaces, int *freeFaces)
+{
+       CCGFace **array;
+       int i, num;
 
-                                       /* horizontal */
-                               for (y=1; y<gridSize-1; y++) {
-                                       for (x=0; x<gridSize-1; x++) {
-                                               int fx = x*2+1;
-                                               int fy = y*2;
-                                               void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y);
-                                               void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y);
-                                               void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1);
-                                               void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
-                                               void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
-
-                                               VertDataAvg4(co, co0, co1, co2, co3);
-                                       }
-                               }
-                       }
+       if(!*faces) {
+               array = CCGSUBSURF_alloc(ss, sizeof(*array)*ss->fMap->numEntries);
+               num = 0;
+               for (i=0; i<ss->fMap->curSize; i++) {
+                       CCGFace *f = (CCGFace*) ss->fMap->buckets[i];
+
+                       for (; f; f = f->next)
+                               array[num++] = f;
                }
 
-                       /* exterior edge midpoints
-                        *  o old exterior edge points
-                        *  o new interior face midpoints
-                        */
-               for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
-                       CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
-                       float sharpness = EDGE_getSharpness(e, curLvl);
+               *faces = array;
+               *numFaces = num;
+               *freeFaces= 1;
+       }
+       else
+               *freeFaces= 0;
+}
 
-                       if (_edge_isBoundary(e) || sharpness>1.0) {
-                               for (x=0; x<edgeSize-1; x++) {
-                                       int fx = x*2 + 1;
-                                       void *co0 = EDGE_getCo(e, curLvl, x+0);
-                                       void *co1 = EDGE_getCo(e, curLvl, x+1);
-                                       void *co = EDGE_getCo(e, nextLvl, fx);
+static void ccgSubSurf__effectedFaceNeighbours(CCGSubSurf *ss, CCGFace **faces, int numFaces, CCGVert ***verts, int *numVerts, CCGEdge ***edges, int *numEdges)
+{
+       CCGVert **arrayV;
+       CCGEdge **arrayE;
+       int numV, numE, i, j;
 
-                                       VertDataCopy(co, co0);
-                                       VertDataAdd(co, co1);
-                                       VertDataMulN(co, 0.5);
-                               }
-                       } else {
-                               for (x=0; x<edgeSize-1; x++) {
-                                       int fx = x*2 + 1;
-                                       void *co0 = EDGE_getCo(e, curLvl, x+0);
-                                       void *co1 = EDGE_getCo(e, curLvl, x+1);
-                                       void *co = EDGE_getCo(e, nextLvl, fx);
-                                       int numFaces = 0;
-
-                                       VertDataCopy(q, co0);
-                                       VertDataAdd(q, co1);
-
-                                       for (i=0; i<e->numFaces; i++) {
-                                               CCGFace *f = e->faces[i];
-                                               VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
-                                               numFaces++;
-                                       }
+       arrayV = CCGSUBSURF_alloc(ss, sizeof(*arrayV)*ss->vMap->numEntries);
+       arrayE = CCGSUBSURF_alloc(ss, sizeof(*arrayE)*ss->eMap->numEntries);
+       numV = numE = 0;
 
-                                       VertDataMulN(q, 1.0f/(2.0f+numFaces));
+       for (i=0; i<numFaces; i++) {
+               CCGFace *f = faces[i];
+               f->flags |= Face_eEffected;
+       }
 
-                                       VertDataCopy(r, co0);
-                                       VertDataAdd(r, co1);
-                                       VertDataMulN(r, 0.5);
+       for (i=0; i<ss->vMap->curSize; i++) {
+               CCGVert *v = (CCGVert*) ss->vMap->buckets[i];
 
-                                       VertDataCopy(co, q);
-                                       VertDataSub(r, q);
-                                       VertDataMulN(r, sharpness);
-                                       VertDataAdd(co, r);
-                               }
+               for (; v; v = v->next) {
+                       for(j=0; j<v->numFaces; j++)
+                               if(!(v->faces[j]->flags & Face_eEffected))
+                                       break;
+                       
+                       if(j == v->numFaces) {
+                               arrayV[numV++] = v;
+                               v->flags |= Vert_eEffected;
                        }
                }
+       }
 
-                       /* exterior vertex shift
-                        *  o old vertex points (shifting)
-                        *  o old exterior edge points
-                        *  o new interior face midpoints
-                        */
-               for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
-                       CCGVert *v = (CCGVert*) effectedV[ptrIdx];
-                       void *co = VERT_getCo(v, curLvl);
-                       void *nCo = VERT_getCo(v, nextLvl);
-                       int sharpCount = 0, allSharp = 1;
-                       float avgSharpness = 0.0;
-                       int seam = VERT_seam(v), seamEdges = 0;
+       for (i=0; i<ss->eMap->curSize; i++) {
+               CCGEdge *e = (CCGEdge*) ss->eMap->buckets[i];
 
-                       for (i=0; i<v->numEdges; i++) {
-                               CCGEdge *e = v->edges[i];
-                               float sharpness = EDGE_getSharpness(e, curLvl);
+               for (; e; e = e->next) {
+                       for(j=0; j<e->numFaces; j++)
+                               if(!(e->faces[j]->flags & Face_eEffected))
+                                       break;
+                       
+                       if(j == e->numFaces) {
+                               e->flags |= Edge_eEffected;
+                               arrayE[numE++] = e;
+                       }
+               }
+       }
 
-                               if (seam && _edge_isBoundary(e))
-                                       seamEdges++;
+       *verts = arrayV;
+       *numVerts = numV;
+       *edges = arrayE;
+       *numEdges = numE;
+}
 
-                               if (sharpness!=0.0f) {
-                                       sharpCount++;
-                                       avgSharpness += sharpness;
-                               } else {
-                                       allSharp = 0;
-                               }
-                       }
+/* copy face grid coordinates to other places */
+CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
+{
+       int i, S, x, gridSize, cornerIdx, subdivLevels;
+       int vertDataSize = ss->meshIFC.vertDataSize, freeF;
 
-                       if(sharpCount) {
-                               avgSharpness /= sharpCount;
-                               if (avgSharpness>1.0) {
-                                       avgSharpness = 1.0;
-                               }
-                       }
+       subdivLevels = ss->subdivLevels;
+       lvl = (lvl)? lvl: subdivLevels;
+       gridSize = 1 + (1<<(lvl-1));
+       cornerIdx = gridSize-1;
 
-                       if (seam && seamEdges < 2)
-                               seam = 0;
+       ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
 
-                       if (!v->numEdges) {
-                               VertDataCopy(nCo, co);
-                       } else if (_vert_isBoundary(v)) {
-                               int numBoundary = 0;
+       for (i=0; i<numEffectedF; i++) {
+               CCGFace *f = effectedF[i];
 
-                               VertDataZero(r);
-                               for (i=0; i<v->numEdges; i++) {
-                                       CCGEdge *e = v->edges[i];
-                                       if (_edge_isBoundary(e)) {
-                                               VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
-                                               numBoundary++;
-                                       }
-                               }
+               for (S=0; S<f->numVerts; S++) {
+                       CCGEdge *e = FACE_getEdges(f)[S];
+                       CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
 
-                               VertDataCopy(nCo, co);
-                               VertDataMulN(nCo, 0.75);
-                               VertDataMulN(r, 0.25f/numBoundary);
-                               VertDataAdd(nCo, r);
-                       } else {
-                               int cornerIdx = (1 + (1<<(curLvl))) - 2;
-                               int numEdges = 0, numFaces = 0;
+                       VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
+                       VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
 
-                               VertDataZero(q);
-                               for (i=0; i<v->numFaces; i++) {
-                                       CCGFace *f = v->faces[i];
-                                       VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
-                                       numFaces++;
-                               }
-                               VertDataMulN(q, 1.0f/numFaces);
-                               VertDataZero(r);
-                               for (i=0; i<v->numEdges; i++) {
-                                       CCGEdge *e = v->edges[i];
-                                       VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
-                                       numEdges++;
-                               }
-                               VertDataMulN(r, 1.0f/numEdges);
+                       for (x=0; x<gridSize; x++)
+                               VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
 
-                               VertDataCopy(nCo, co);
-                               VertDataMulN(nCo, numEdges-2.0f);
-                               VertDataAdd(nCo, q);
-                               VertDataAdd(nCo, r);
-                               VertDataMulN(nCo, 1.0f/numEdges);
+                       for (x=0; x<gridSize; x++) {
+                               int eI = gridSize-1-x;
+                               VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
+                               VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
                        }
+               }
+       }
 
-                       if ((sharpCount>1 && v->numFaces) || seam) {
-                               VertDataZero(q);
-
-                               if (seam) {
-                                       avgSharpness = 1.0f;
-                                       sharpCount = seamEdges;
-                                       allSharp = 1;
-                               }
+       if(freeF) CCGSUBSURF_free(ss, effectedF);
 
-                               for (i=0; i<v->numEdges; i++) {
-                                       CCGEdge *e = v->edges[i];
-                                       float sharpness = EDGE_getSharpness(e, curLvl);
+       return eCCGError_None;
+}
 
-                                       if (seam) {
-                                               if (_edge_isBoundary(e))
-                                                       VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
-                                       } else if (sharpness != 0.0) {
-                                               VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
-                                       }
-                               }
+/* stitch together face grids, averaging coordinates at edges
+   and vertices, for multires displacements */
+CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
+{
+       CCGVert **effectedV;
+       CCGEdge **effectedE;
+       int numEffectedV, numEffectedE, freeF;
+       int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize;
+       int vertDataSize = ss->meshIFC.vertDataSize;
 
-                               VertDataMulN(q, (float) 1/sharpCount);
+       subdivLevels = ss->subdivLevels;
+       lvl = (lvl)? lvl: subdivLevels;
+       gridSize = 1 + (1<<(lvl-1));
+       edgeSize = 1 + (1<<lvl);
+       cornerIdx = gridSize-1;
 
-                               if (sharpCount!=2 || allSharp) {
-                                               // q = q + (co-q)*avgSharpness
-                                       VertDataCopy(r, co);
-                                       VertDataSub(r, q);
-                                       VertDataMulN(r, avgSharpness);
-                                       VertDataAdd(q, r);
-                               }
+       ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+       ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
+               &effectedV, &numEffectedV, &effectedE, &numEffectedE);
 
-                                       // r = co*.75 + q*.25
-                               VertDataCopy(r, co);
-                               VertDataMulN(r, .75);
-                               VertDataMulN(q, .25);
-                               VertDataAdd(r, q);
+       /* zero */
+       for (i=0; i<numEffectedV; i++) {
+               CCGVert *v = effectedV[i];
+               VertDataZero(VERT_getCo(v, lvl));
+       }
 
-                                       // nCo = nCo  + (r-nCo)*avgSharpness
-                               VertDataSub(r, nCo);
-                               VertDataMulN(r, avgSharpness);
-                               VertDataAdd(nCo, r);
-                       }
-               }
+       for (i=0; i<numEffectedE; i++) {
+               CCGEdge *e = effectedE[i];
 
-                       /* exterior edge interior shift
-                        *  o old exterior edge midpoints (shifting)
-                        *  o old exterior edge midpoints
-                        *  o new interior face midpoints
-                        */
-               for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
-                       CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
-                       float sharpness = EDGE_getSharpness(e, curLvl);
-                       int sharpCount = 0;
-                       float avgSharpness = 0.0;
+               for (x=0; x<edgeSize; x++)
+                       VertDataZero(EDGE_getCo(e, lvl, x));
+       }
 
-                       if (sharpness!=0.0f) {
-                               sharpCount = 2;
-                               avgSharpness += sharpness;
+       /* add */
+       for (i=0; i<numEffectedF; i++) {
+               CCGFace *f = effectedF[i];
 
-                               if (avgSharpness>1.0) {
-                                       avgSharpness = 1.0;
-                               }
-                       } else {
-                               sharpCount = 0;
-                               avgSharpness = 0;
-                       }
+               VertDataZero(FACE_getCenterData(f));
 
-                       if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) {
-                               for (x=1; x<edgeSize-1; x++) {
-                                       int fx = x*2;
-                                       void *co = EDGE_getCo(e, curLvl, x);
-                                       void *nCo = EDGE_getCo(e, nextLvl, fx);
-                                       VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
-                                       VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
-                                       VertDataMulN(r, 0.5);
-                                       VertDataCopy(nCo, co);
-                                       VertDataMulN(nCo, 0.75);
-                                       VertDataMulN(r, 0.25);
-                                       VertDataAdd(nCo, r);
-                               }
-                       } else {
-                               for (x=1; x<edgeSize-1; x++) {
-                                       int fx = x*2;
-                                       void *co = EDGE_getCo(e, curLvl, x);
-                                       void *nCo = EDGE_getCo(e, nextLvl, fx);
-                                       int numFaces = 0;
-
-                                       VertDataZero(q);
-                                       VertDataZero(r);
-                                       VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
-                                       VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
-                                       for (i=0; i<e->numFaces; i++) {
-                                               CCGFace *f = e->faces[i];
-                                               VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
-                                               VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
-
-                                               VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
-                                               numFaces++;
-                                       }
-                                       VertDataMulN(q, 1.0/(numFaces*2.0f));
-                                       VertDataMulN(r, 1.0/(2.0f + numFaces));
+               for (S=0; S<f->numVerts; S++)
+                       for (x=0; x<gridSize; x++)
+                               VertDataZero(FACE_getIECo(f, lvl, S, x));
 
-                                       VertDataCopy(nCo, co);
-                                       VertDataMulN(nCo, (float) numFaces);
-                                       VertDataAdd(nCo, q);
-                                       VertDataAdd(nCo, r);
-                                       VertDataMulN(nCo, 1.0f/(2+numFaces));
-
-                                       if (sharpCount==2) {
-                                               VertDataCopy(q, co);
-                                               VertDataMulN(q, 6.0f);
-                                               VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
-                                               VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
-                                               VertDataMulN(q, 1/8.0f);
-
-                                               VertDataSub(q, nCo);
-                                               VertDataMulN(q, avgSharpness);
-                                               VertDataAdd(nCo, q);
-                                       }
-                               }
-                       }
-               }
+               for (S=0; S<f->numVerts; S++) {
+                       int prevS = (S+f->numVerts-1)%f->numVerts;
+                       CCGEdge *e = FACE_getEdges(f)[S];
+                       CCGEdge *prevE = FACE_getEdges(f)[prevS];
 
-               for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
-                       CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+                       VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
+                       VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
 
-                               /* interior center point shift
-                                *  o old face center point (shifting)
-                                *  o old interior edge points
-                                *  o new interior face midpoints
-                                */
-                       VertDataZero(q);
-                       for (S=0; S<f->numVerts; S++) {
-                               VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
-                       }
-                       VertDataMulN(q, 1.0f/f->numVerts);
-                       VertDataZero(r);
-                       for (S=0; S<f->numVerts; S++) {
-                               VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
+                       for (x=1; x<gridSize-1; x++) {
+                               VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
+                               VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x));
                        }
-                       VertDataMulN(r, 1.0f/f->numVerts);
-
-                       VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
-                       VertDataAdd(FACE_getCenterData(f), q);
-                       VertDataAdd(FACE_getCenterData(f), r);
-                       VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
-
-                       for (S=0; S<f->numVerts; S++) {
-                                       /* interior face shift
-                                        *  o old interior face point (shifting)
-                                        *  o new interior edge midpoints
-                                        *  o new interior face midpoints
-                                        */
-                               for (x=1; x<gridSize-1; x++) {
-                                       for (y=1; y<gridSize-1; y++) {
-                                               int fx = x*2;
-                                               int fy = y*2;
-                                               void *co = FACE_getIFCo(f, curLvl, S, x, y);
-                                               void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
-                                               
-                                               VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
-                                                       FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
-                                                       FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
-                                                       FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
-
-                                               VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
-                                                       FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
-                                                       FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
-                                                       FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
-
-                                               VertDataCopy(nCo, co);
-                                               VertDataSub(nCo, q);
-                                               VertDataMulN(nCo, 0.25f);
-                                               VertDataAdd(nCo, r);
-                                       }
-                               }
-
-                                       /* interior edge interior shift
-                                        *  o old interior edge point (shifting)
-                                        *  o new interior edge midpoints
-                                        *  o new interior face midpoints
-                                        */
-                               for (x=1; x<gridSize-1; x++) {
-                                       int fx = x*2;
-                                       void *co = FACE_getIECo(f, curLvl, S, x);
-                                       void *nCo = FACE_getIECo(f, nextLvl, S, fx);
-                                       
-                                       VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
-                                               FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
-                                               FACE_getIFCo(f, nextLvl, S, fx+1, +1),
-                                               FACE_getIFCo(f, nextLvl, S, fx-1, +1));
 
-                                       VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1),
-                                               FACE_getIECo(f, nextLvl, S, fx+1),
-                                               FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
-                                               FACE_getIFCo(f, nextLvl, S, fx, 1));
-
-                                       VertDataCopy(nCo, co);
-                                       VertDataSub(nCo, q);
-                                       VertDataMulN(nCo, 0.25f);
-                                       VertDataAdd(nCo, r);
-                               }
+                       for (x=0; x<gridSize-1; x++) {
+                               int eI = gridSize-1-x;
+                               VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
+                               if(x != 0)
+                                       VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
                        }
                }
+       }
 
-                       /* copy down */
-               edgeSize = 1 + (1<<(nextLvl));
-               gridSize = 1 + (1<<((nextLvl)-1));
-               cornerIdx = gridSize-1;
-               for (i=0; i<numEffectedE; i++) {
-                       CCGEdge *e = effectedE[i];
-                       VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
-                       VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
-               }
-               for (i=0; i<numEffectedF; i++) {
-                       CCGFace *f = effectedF[i];
-                       for (S=0; S<f->numVerts; S++) {
-                               CCGEdge *e = FACE_getEdges(f)[S];
-                               CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
-
-                               VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
-                               VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
-                               VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
-                               VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
-                               for (x=1; x<gridSize-1; x++) {
-                                       void *co = FACE_getIECo(f, nextLvl, S, x);
-                                       VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
-                                       VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
-                               }
-                               for (x=0; x<gridSize-1; x++) {
-                                       int eI = gridSize-1-x;
-                                       VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
-                                       VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
-                               }
-                       }
-               }
+       /* average */
+       for (i=0; i<numEffectedV; i++) {
+               CCGVert *v = effectedV[i];
+               VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces);
        }
 
-#define FACE_getIFNo(f, lvl, S, x, y)          _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset)
-#define FACE_calcIFNo(f, lvl, S, x, y, no)     _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
-       if (ss->calcVertNormals) {
-               int lvl = ss->subdivLevels;
-               int edgeSize = 1 + (1<<lvl);
-               int gridSize = 1 + (1<<(lvl-1));
-               int normalDataOffset = ss->normalDataOffset;
+       for (i=0; i<numEffectedE; i++) {
+               CCGEdge *e = effectedE[i];
 
-               for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
-                       CCGFace *f = (CCGFace*) effectedF[ptrIdx];
-                       int S, x, y;
+               VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl));
+               VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl));
 
-                       for (S=0; S<f->numVerts; S++) {
-                               for (y=0; y<gridSize-1; y++)
-                                       for (x=0; x<gridSize-1; x++)
-                                               NormZero(FACE_getIFNo(f, lvl, S, x, y));
-
-                               if (FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected)
-                                       for (x=0; x<gridSize-1; x++)
-                                               NormZero(FACE_getIFNo(f, lvl, S, x, gridSize-1));
-                               if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
-                                       for (y=0; y<gridSize-1; y++)
-                                               NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, y));
-                               if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
-                                       NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1));
-                       }
-               }
+               for (x=1; x<edgeSize-1; x++)
+                       VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces);
+       }
 
-               for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
-                       CCGFace *f = (CCGFace*) effectedF[ptrIdx];
-                       int S, x, y;
-                       float no[3];
+       /* copy */
+       for (i=0; i<numEffectedF; i++) {
+               CCGFace *f = effectedF[i];
 
-                       for (S=0; S<f->numVerts; S++) {
-                               int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected);
-                               int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected);
-                               int yLimitNext = xLimit;
-                               int xLimitPrev = yLimit;
-                               
-                               for (y=0; y<gridSize - 1; y++) {
-                                       for (x=0; x<gridSize - 1; x++) {
-                                               int xPlusOk = (!xLimit || x<gridSize-2);
-                                               int yPlusOk = (!yLimit || y<gridSize-2);
-
-                                               FACE_calcIFNo(f, lvl, S, x, y, no);
-
-                                               NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+0), no);
-                                               if (xPlusOk)
-                                                       NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+0), no);
-                                               if (yPlusOk)
-                                                       NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+1), no);
-                                               if (xPlusOk && yPlusOk) {
-                                                       if (x<gridSize-2 || y<gridSize-2 || FACE_getVerts(f)[S]->flags&Vert_eEffected) {
-                                                               NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no);
-                                                       }
-                                               }
+               VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
 
-                                               if (x==0 && y==0) {
-                                                       int K;
+               for (S=0; S<f->numVerts; S++)
+                       for (x=1; x<gridSize-1; x++)
+                               VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f);
 
-                                                       if (!yLimitNext || 1<gridSize-1)
-                                                               NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, 1), no);
-                                                       if (!xLimitPrev || 1<gridSize-1)
-                                                               NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, 1, 0), no);
+               for (S=0; S<f->numVerts; S++) {
+                       int prevS = (S+f->numVerts-1)%f->numVerts;
+                       CCGEdge *e = FACE_getEdges(f)[S];
+                       CCGEdge *prevE = FACE_getEdges(f)[prevS];
 
-                                                       for (K=0; K<f->numVerts; K++) {
-                                                               if (K!=S) {
-                                                                       NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
-                                                               }
-                                                       }
-                                               } else if (y==0) {
-                                                       NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no);
-                                                       if (!yLimitNext || x<gridSize-2)
-                                                               NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x+1), no);
-                                               } else if (x==0) {
-                                                       NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no);
-                                                       if (!xLimitPrev || y<gridSize-2)
-                                                               NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y+1, 0), no);
-                                               }
-                                       }
-                               }
+                       VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
+                       VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
+
+                       for (x=1; x<gridSize-1; x++) {
+                               VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
+                               VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
+                       }
+
+                       for (x=0; x<gridSize-1; x++) {
+                               int eI = gridSize-1-x;
+                               VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
+                               VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
                        }
+
+                       VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f));
+                       VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0));
                }
-                       // XXX can I reduce the number of normalisations here?
-               for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
-                       CCGVert *v = (CCGVert*) effectedV[ptrIdx];
-                       float length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset);
+       }
 
-                       NormZero(no);
+       for (i=0; i<numEffectedV; i++)
+               effectedV[i]->flags = 0;
+       for (i=0; i<numEffectedE; i++)
+               effectedE[i]->flags = 0;
+       for (i=0; i<numEffectedF; i++)
+               effectedF[i]->flags = 0;
 
-                       for (i=0; i<v->numFaces; i++) {
-                               CCGFace *f = v->faces[i];
-                               NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1));
-                       }
+       CCGSUBSURF_free(ss, effectedE);
+       CCGSUBSURF_free(ss, effectedV);
+       if(freeF) CCGSUBSURF_free(ss, effectedF);
 
-                       length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
+       return eCCGError_None;
+}
 
-                       if (length>EPSILON) {
-                               float invLength = 1.0f/length;
-                               no[0] *= invLength;
-                               no[1] *= invLength;
-                               no[2] *= invLength;
-                       } else {
-                               NormZero(no);
-                       }
+/* update normals for specified faces */
+CCGError ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **effectedF, int numEffectedF) {
+       CCGVert **effectedV;
+       CCGEdge **effectedE;
+       int i, numEffectedV, numEffectedE, freeF;
 
-                       for (i=0; i<v->numFaces; i++) {
-                               CCGFace *f = v->faces[i];
-                               NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no);
-                       }
-               }
-               for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
-                       CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
+       ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+       ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
+               &effectedV, &numEffectedV, &effectedE, &numEffectedE);
 
-                       if (e->numFaces) {
-                               CCGFace *fLast = e->faces[e->numFaces-1];
-                               int x;
+       if (ss->calcVertNormals)
+               ccgSubSurf__calcVertNormals(ss,
+                       effectedV, effectedE, effectedF,
+                       numEffectedV, numEffectedE, numEffectedF);
 
-                               for (i=0; i<e->numFaces-1; i++) {
-                                       CCGFace *f = e->faces[i];
+       for (i=0; i<numEffectedV; i++)
+               effectedV[i]->flags = 0;
+       for (i=0; i<numEffectedE; i++)
+               effectedE[i]->flags = 0;
+       for (i=0; i<numEffectedF; i++)
+               effectedF[i]->flags = 0;
 
-                                       for (x=1; x<edgeSize-1; x++) {
-                                               NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
-                                                               _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
-                                       }
-                               }
+       CCGSUBSURF_free(ss, effectedE);
+       CCGSUBSURF_free(ss, effectedV);
+       if(freeF) CCGSUBSURF_free(ss, effectedF);
 
-                               for (i=0; i<e->numFaces-1; i++) {
-                                       CCGFace *f = e->faces[i];
+       return eCCGError_None;
+}
 
-                                       for (x=1; x<edgeSize-1; x++) {
-                                               NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
-                                                               _face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
-                                       }
-                               }
-                       }
-               }
-               for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
-                       CCGFace *f = (CCGFace*) effectedF[ptrIdx];
-                       int S;
+/* compute subdivision levels from a given starting point, used by
+   multires subdivide/propagate, by filling in coordinates at a
+   certain level, and then subdividing that up to the highest level */
+CCGError ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **effectedF, int numEffectedF)
+{
+       CCGVert **effectedV;
+       CCGEdge **effectedE;
+       int numEffectedV, numEffectedE, freeF, i;
+       int curLvl, subdivLevels = ss->subdivLevels;
 
-                       for (S=0; S<f->numVerts; S++) {
-                               NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1),
-                                                FACE_getIFNo(f, lvl, S, gridSize-1, 0));
-                       }
-               }
-               for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
-                       CCGFace *f = (CCGFace*) effectedF[ptrIdx];
-                       int S, x, y;
-
-                       for (S=0; S<f->numVerts; S++) {
-                               for (y=0; y<gridSize; y++) {
-                                       for (x=0; x<gridSize; x++) {
-                                               float *no = FACE_getIFNo(f, lvl, S, x, y);
-                                               float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
-
-                                               if (length>EPSILON) {
-                                                       float invLength = 1.0f/length;
-                                                       no[0] *= invLength;
-                                                       no[1] *= invLength;
-                                                       no[2] *= invLength;
-                                               } else {
-                                                       NormZero(no);
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-#undef FACE_getIFNo
+       ccgSubSurf__allFaces(ss, &effectedF, &numEffectedF, &freeF);
+       ccgSubSurf__effectedFaceNeighbours(ss, effectedF, numEffectedF,
+               &effectedV, &numEffectedV, &effectedE, &numEffectedE);
 
-       for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
-               CCGVert *v = effectedV[ptrIdx];
-               v->flags = 0;
-       }
-       for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
-               CCGEdge *e = effectedE[ptrIdx];
-               e->flags = 0;
+       for (curLvl=lvl; curLvl<subdivLevels; curLvl++) {
+               ccgSubSurf__calcSubdivLevel(ss,
+                       effectedV, effectedE, effectedF,
+                       numEffectedV, numEffectedE, numEffectedF, curLvl);
        }
 
-#undef VERT_getCo
-#undef EDGE_getCo
-#undef FACE_getIECo
-#undef FACE_getIFCo
+       for (i=0; i<numEffectedV; i++)
+               effectedV[i]->flags = 0;
+       for (i=0; i<numEffectedE; i++)
+               effectedE[i]->flags = 0;
+       for (i=0; i<numEffectedF; i++)
+               effectedF[i]->flags = 0;
 
-       CCGSUBSURF_free(ss, effectedF);
        CCGSUBSURF_free(ss, effectedE);
        CCGSUBSURF_free(ss, effectedV);
+       if(freeF) CCGSUBSURF_free(ss, effectedF);
+
+       return eCCGError_None;
 }
 
+#undef VERT_getCo
+#undef EDGE_getCo
+#undef FACE_getIECo
+#undef FACE_getIFCo
+
 /*** External API accessor functions ***/
 
 int ccgSubSurf_getNumVerts(CCGSubSurf *ss) {
index fbd0aec..d51cf01 100644 (file)
@@ -59,6 +59,11 @@ CCGError     ccgSubSurf_syncFaceDel  (CCGSubSurf *ss, CCGFaceHDL fHDL);
 
 CCGError       ccgSubSurf_processSync  (CCGSubSurf *ss);
 
+CCGError       ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
+CCGError       ccgSubSurf_updateNormals(CCGSubSurf *ss, CCGFace **faces, int numFaces);
+CCGError       ccgSubSurf_updateLevels(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
+CCGError       ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **faces, int numFaces);
+
 CCGError       ccgSubSurf_setSubdivisionLevels         (CCGSubSurf *ss, int subdivisionLevels);
 
 CCGError       ccgSubSurf_setAllowEdgeCreation         (CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData);
index 209e461..c2921a1 100644 (file)
@@ -1555,7 +1555,7 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, Modifier
        md->scene= scene;
        
        if (!(md->mode&eModifierMode_Realtime)) return NULL;
-       if (mti->isDisabled && mti->isDisabled(md)) return NULL;
+       if (mti->isDisabled && mti->isDisabled(md, 0)) return NULL;
 
        if (mti->type==eModifierTypeType_OnlyDeform) {
                int numVerts;
@@ -1906,7 +1906,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
 
                                mask &= ~CD_MASK_ORCO;
                                DM_set_only_copy(orcodm, mask);
-                               ndm = mti->applyModifier(md, ob, orcodm, useRenderParams, !inputVertexCos);
+                               ndm = mti->applyModifier(md, ob, orcodm, useRenderParams, 0);
 
                                if(ndm) {
                                        /* if the modifier returned a new dm, release the old one */
index a9d72d9..09d73f2 100644 (file)
@@ -75,13 +75,14 @@ Brush *add_brush(const char *name)
        brush->rgb[2]= 1.0f;
        brush->alpha= 0.2f;
        brush->size= 25;
-       brush->spacing= 10.0f;
+       brush->spacing= 7.5f;
        brush->smooth_stroke_radius= 75;
        brush->smooth_stroke_factor= 0.9;
        brush->rate= 0.1f;
        brush->jitter= 0.0f;
        brush->clone.alpha= 0.5;
        brush->sculpt_tool = SCULPT_TOOL_DRAW;
+       brush->flag |= BRUSH_SPACE;
 
        brush_curve_preset(brush, BRUSH_PRESET_SMOOTH);
 
diff --git a/source/blender/blenkernel/intern/btex.c b/source/blender/blenkernel/intern/btex.c
new file mode 100644 (file)
index 0000000..363e515
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * $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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_fileops.h"
+#include "BLI_string.h"
+
+#include "BKE_btex.h"
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+/************************* File Format Definitions ***************************/
+
+#define BTEX_ENDIAN_LITTLE     0
+#define BTEX_ENDIAN_BIG                1
+
+#define BTEX_DATA_FLOAT        0
+
+typedef struct BTexHeader {
+       char ID[4];                                     /* "BTEX" */
+       char endian;                            /* little, big */
+       char version;                           /* non-compatible versions */
+       char subversion;                        /* compatible sub versions */
+       char pad;                                       /* padding */
+
+       int structbytes;                        /* size of this struct in bytes */
+       int type;                                       /* image, mesh */
+       int totlayer;                           /* number of layers in the file */
+} BTexHeader;
+
+typedef struct BTexImageHeader {
+       int structbytes;                        /* size of this struct in bytes */
+       int width;                                      /* image width */
+       int height;                                     /* image height */
+       int tile_size;                          /* tile size (required power of 2) */
+} BTexImageHeader;
+
+typedef struct BTexMeshHeader {
+       int structbytes;                        /* size of this struct in bytes */
+       int totgrid;                            /* number of grids */
+       int gridsize;                           /* width of grids */
+} BTexMeshHeader;
+
+struct BTexLayer {
+       int structbytes;                                /* size of this struct in bytes */
+       int datatype;                                   /* only float for now */
+       int datasize;                                   /* size of data in layer */
+       int type;                                               /* layer type */
+       char name[BTEX_LAYER_NAME_MAX]; /* layer name */
+};
+
+/**************************** Other Definitions ******************************/
+
+#define BTEX_VERSION           0
+#define BTEX_SUBVERSION                0
+#define BTEX_TILE_SIZE         64
+
+struct BTex {
+       int type;
+
+       BTexHeader header;
+       union {
+               BTexImageHeader image;
+               BTexMeshHeader mesh;
+       } btype;
+
+       BTexLayer *layer;
+       int totlayer;
+
+       FILE *readf;
+       FILE *writef;
+       int switchendian;
+       size_t dataoffset;
+};
+
+/********************************* Create/Free *******************************/
+
+static int btex_endian(void)
+{
+       if(ENDIAN_ORDER == L_ENDIAN)
+               return BTEX_ENDIAN_LITTLE;
+       else
+               return BTEX_ENDIAN_BIG;
+}
+
+/*static int btex_data_type_size(int datatype)
+{
+       if(datatype == BTEX_DATA_FLOAT)
+               return sizeof(float);
+       
+       return 0;
+}*/
+
+BTex *btex_create(int type)
+{
+       BTex *btex= MEM_callocN(sizeof(BTex), "BTex");
+
+       btex->type= type;
+
+       return btex;
+}
+
+void btex_free(BTex *btex)
+{
+       btex_read_close(btex);
+       btex_write_close(btex);
+
+       if(btex->layer)
+               MEM_freeN(btex->layer);
+
+       MEM_freeN(btex);
+}
+
+/********************************* Read/Write ********************************/
+
+static int btex_read_header(BTex *btex)
+{
+       BTexHeader *header;
+       BTexImageHeader *image;
+       BTexMeshHeader *mesh;
+       BTexLayer *layer;
+       FILE *f= btex->readf;
+       size_t offset = 0;
+       int a;
+
+       header= &btex->header;
+
+       if(!fread(header, sizeof(BTexHeader), 1, btex->readf))
+               return 0;
+       
+       if(memcmp(header->ID, "BTEX", sizeof(header->ID)) != 0)
+               return 0;
+       if(header->version > BTEX_VERSION)
+               return 0;
+
+       btex->switchendian= header->endian != btex_endian();
+       header->endian= btex_endian();
+
+       if(btex->switchendian) {
+               SWITCH_INT(header->type);
+               SWITCH_INT(header->totlayer);
+               SWITCH_INT(header->structbytes);
+       }
+
+       if(!ELEM(header->type, BTEX_TYPE_IMAGE, BTEX_TYPE_MESH))
+               return 0;
+
+       offset += header->structbytes;
+       header->structbytes= sizeof(BTexHeader);
+
+       if(fseek(f, offset, SEEK_SET) != 0)
+               return 0;
+       
+       if(header->type == BTEX_TYPE_IMAGE) {
+               image= &btex->btype.image;
+               if(!fread(image, sizeof(BTexImageHeader), 1, f))
+                       return 0;
+
+               if(btex->switchendian) {
+                       SWITCH_INT(image->width);
+                       SWITCH_INT(image->height);
+                       SWITCH_INT(image->tile_size);
+                       SWITCH_INT(image->structbytes);
+               }
+
+               offset += image->structbytes;
+               image->structbytes= sizeof(BTexImageHeader);
+       }
+       else if(header->type == BTEX_TYPE_MESH) {
+               mesh= &btex->btype.mesh;
+               if(!fread(mesh, sizeof(BTexMeshHeader), 1, f))
+                       return 0;
+
+               if(btex->switchendian) {
+                       SWITCH_INT(mesh->totgrid);
+                       SWITCH_INT(mesh->gridsize);
+                       SWITCH_INT(mesh->structbytes);
+               }
+
+               offset += mesh->structbytes;
+               mesh->structbytes= sizeof(BTexMeshHeader);
+       }
+
+       if(fseek(f, offset, SEEK_SET) != 0)
+               return 0;
+
+       btex->layer= MEM_callocN(sizeof(BTexLayer)*header->totlayer, "BTexLayer");
+       btex->totlayer= header->totlayer;
+
+       for(a=0; a<header->totlayer; a++) {
+               layer= &btex->layer[a];
+
+               if(!fread(layer, sizeof(BTexLayer), 1, f))
+                       return 0;
+
+               if(btex->switchendian) {
+                       SWITCH_INT(layer->type);
+                       SWITCH_INT(layer->datatype);
+                       SWITCH_INT(layer->datasize);
+                       SWITCH_INT(layer->structbytes);
+               }
+
+               if(layer->datatype != BTEX_DATA_FLOAT)
+                       return 0;
+
+               offset += layer->structbytes;
+               layer->structbytes= sizeof(BTexLayer);
+
+               if(fseek(f, offset, SEEK_SET) != 0)
+                       return 0;
+       }
+
+       btex->dataoffset= offset;
+
+       return 1;
+}
+
+static int btex_write_header(BTex *btex)
+{
+       BTexHeader *header;
+       BTexImageHeader *image;
+       BTexMeshHeader *mesh;
+       BTexLayer *layer;
+       FILE *f= btex->writef;
+       int a;
+
+       header= &btex->header;
+
+       if(!fwrite(header, sizeof(BTexHeader), 1, f))
+               return 0;
+       
+       if(header->type == BTEX_TYPE_IMAGE) {
+               image= &btex->btype.image;
+               if(!fwrite(image, sizeof(BTexImageHeader), 1, f))
+                       return 0;
+       }
+       else if(header->type == BTEX_TYPE_MESH) {
+               mesh= &btex->btype.mesh;
+               if(!fwrite(mesh, sizeof(BTexMeshHeader), 1, f))
+                       return 0;
+       }
+
+       for(a=0; a<header->totlayer; a++) {
+               layer= &btex->layer[a];
+
+               if(!fwrite(layer, sizeof(BTexLayer), 1, f))
+                       return 0;
+       }
+
+       return 1;
+}
+
+int btex_read_open(BTex *btex, char *filename)
+{
+       FILE *f;
+
+       f= fopen(filename, "rb");
+       if(!f)
+               return 0;
+       
+       btex->readf= f;
+
+       if(!btex_read_header(btex)) {
+               btex_read_close(btex);
+               return 0;
+       }
+
+       if(btex->header.type != btex->type) {
+               btex_read_close(btex);
+               return 0;
+       }
+
+       return 1;
+}
+
+int btex_read_layer(BTex *btex, BTexLayer *blay)
+{
+       size_t offset;
+       int a;
+
+       /* seek to right location in file */
+       offset= btex->dataoffset;
+       for(a=0; a<btex->totlayer; a++) {
+               if(&btex->layer[a] == blay)
+                       break;
+               else
+                       offset += btex->layer[a].datasize;
+       }
+
+       return (fseek(btex->readf, offset, SEEK_SET) == 0);
+}
+
+int btex_read_data(BTex *btex, int size, void *data)
+{
+       float *fdata;
+       int a;
+       
+       /* read data */
+       if(!fread(data, size, 1, btex->readf))
+               return 0;
+
+       /* switch endian if necessary */
+       if(btex->switchendian) {
+               fdata= data;
+
+               for(a=0; a<size/sizeof(float); a++)
+                       SWITCH_INT(fdata[a])
+       }
+
+       return 1;
+}
+
+void btex_read_close(BTex *btex)
+{
+       if(btex->readf) {
+               fclose(btex->readf);
+               btex->readf= NULL;
+       }
+}
+
+int btex_write_open(BTex *btex, char *filename)
+{
+       BTexHeader *header;
+       BTexImageHeader *image;
+       BTexMeshHeader *mesh;
+       FILE *f;
+
+       f= fopen(filename, "wb");
+       if(!f)
+               return 0;
+       
+       btex->writef= f;
+
+       /* fill header */
+       header= &btex->header;
+       strcpy(header->ID, "BTEX");
+       header->endian= btex_endian();
+       header->version= BTEX_VERSION;
+       header->subversion= BTEX_SUBVERSION;
+
+       header->structbytes= sizeof(BTexHeader);
+       header->type= btex->type;
+       header->totlayer= btex->totlayer;
+
+       if(btex->type == BTEX_TYPE_IMAGE) {
+               /* fill image header */
+               image= &btex->btype.image;
+               image->structbytes= sizeof(BTexImageHeader);
+               image->tile_size= BTEX_TILE_SIZE;
+       }
+       else if(btex->type == BTEX_TYPE_MESH) {
+               /* fill mesh header */
+               mesh= &btex->btype.mesh;
+               mesh->structbytes= sizeof(BTexMeshHeader);
+       }
+
+       btex_write_header(btex);
+
+       return 1;
+}
+
+int btex_write_layer(BTex *btex, BTexLayer *blay)
+{
+       return 1;
+}
+
+int btex_write_data(BTex *btex, int size, void *data)
+{
+       /* write data */
+       if(!fwrite(data, size, 1, btex->writef))
+               return 0;
+
+       return 1;
+}
+
+void btex_write_close(BTex *btex)
+{
+       if(btex->writef) {
+               fclose(btex->writef);
+               btex->writef= NULL;
+       }
+}
+
+void btex_remove(char *filename)
+{
+       BLI_delete(filename, 0, 0);
+}
+
+/********************************** Layers ***********************************/
+
+BTexLayer *btex_layer_find(BTex *btex, int type, char *name)
+{
+       BTexLayer *layer;
+       int a;
+
+       for(a=0; a<btex->totlayer; a++) {
+               layer= &btex->layer[a];
+
+               if(layer->type == type && strcmp(layer->name, name) == 0)
+                       return layer;
+       }
+       
+       return NULL;
+}
+
+BTexLayer *btex_layer_add(BTex *btex, int type, char *name)
+{
+       BTexLayer *newlayer, *layer;
+
+       /* expand array */
+       newlayer= MEM_callocN(sizeof(BTexLayer)*(btex->totlayer+1), "BTexLayer");
+       memcpy(newlayer, btex->layer, sizeof(BTexLayer)*btex->totlayer);
+       btex->layer= newlayer;
+
+       btex->totlayer++;
+
+       /* fill in new layer */
+       layer= &btex->layer[btex->totlayer-1];
+       layer->structbytes= sizeof(BTexLayer);
+       layer->datatype= BTEX_DATA_FLOAT;
+       layer->type= type;
+       BLI_strncpy(layer->name, name, BTEX_LAYER_NAME_MAX);
+
+       return layer;
+}
+
+void btex_layer_remove(BTex *btex, BTexLayer *layer)
+{
+       BTexLayer *newlayer;
+       int index= layer - btex->layer;
+
+       /* expand array */
+       newlayer= MEM_callocN(sizeof(BTexLayer)*(btex->totlayer-1), "BTexLayer");
+       if(index > 0)
+               memcpy(newlayer, btex->layer, sizeof(BTexLayer)*index);
+       if(index+1 < btex->totlayer)
+               memcpy(newlayer+index, btex->layer+index+1, sizeof(BTexLayer)*(btex->totlayer-(index+1)));
+       btex->layer= newlayer;
+
+       btex->totlayer--;
+}
+
+/********************************* Mesh **************************************/
+
+void btex_mesh_set_grids(BTex *btex, int totgrid, int gridsize, int datasize)
+{
+       BTexLayer *layer;
+       int a;
+
+       btex->btype.mesh.totgrid= totgrid;
+       btex->btype.mesh.gridsize= gridsize;
+
+       for(a=0; a<btex->totlayer; a++) {
+               layer= &btex->layer[a];
+               layer->datasize= datasize;
+       }
+}
+
index 30d1b65..77ad9fb 100644 (file)
@@ -49,7 +49,7 @@
 #include "BLI_blenlib.h"
 #include "BLI_edgehash.h"
 #include "BLI_editVert.h"
-#include "BLI_ghash.h"
+#include "BLI_pbvh.h"
 
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
@@ -77,6 +77,12 @@ typedef struct {
        MVert *mvert;
        MEdge *medge;
        MFace *mface;
+
+       /* Cached */
+       struct PBVH *pbvh;
+       /* Mesh connectivity */
+       struct ListBase *fmap;
+       struct IndexNode *fmap_mem;
 } CDDerivedMesh;
 
 /**************** DerivedMesh interface functions ****************/
@@ -171,6 +177,33 @@ static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
        no_r[2] = no[2]/32767.f;
 }
 
+static ListBase *cdDM_getFaceMap(DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+
+       if(!cddm->fmap) {
+               create_vert_face_map(&cddm->fmap, &cddm->fmap_mem, cddm->mface,
+                                    dm->getNumVerts(dm), dm->getNumFaces(dm));
+       }
+
+       return cddm->fmap;
+}
+
+static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+
+       if(!cddm->pbvh && ob->type == OB_MESH) {
+               Mesh *me= ob->data;
+
+               cddm->pbvh = BLI_pbvh_new();
+               BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert,
+                              me->totface, me->totvert);
+       }
+
+       return cddm->pbvh;
+}
+
 static void cdDM_drawVerts(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -360,7 +393,9 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
        }
 }
 
-static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *attribs))
+static void cdDM_drawFacesSolid(DerivedMesh *dm,
+                               float (*partial_redraw_planes)[4],
+                               int fast, int (*setMaterial)(int, void *attribs))
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mvert = cddm->mvert;
@@ -376,6 +411,20 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *a
        glVertex3fv(mvert[index].co);   \
 }
 
+       if(cddm->pbvh) {
+               float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+
+               /* should be per face */
+               if(dm->numFaceData && mface->flag & ME_SMOOTH)
+                       glShadeModel(GL_SMOOTH);
+
+               BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors);
+
+               glShadeModel(GL_FLAT);
+
+               return;
+       }
+
        if( GPU_buffer_legacy(dm) ) {
                DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" );
                glBegin(glmode = GL_QUADS);
@@ -886,7 +935,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                continue;
                        }
                        else if(setDrawOptions) {
-                               orig = index[a];
+                               orig = (index)? index[a]: a;
 
                                if(orig == ORIGINDEX_NONE)
                                        continue;
@@ -1275,12 +1324,21 @@ static void cdDM_foreachMappedFaceCenter(
        }
 }
 
+static void cdDM_free_internal(CDDerivedMesh *cddm)
+{
+       if(cddm->pbvh) BLI_pbvh_free(cddm->pbvh);
+       if(cddm->fmap) MEM_freeN(cddm->fmap);
+       if(cddm->fmap_mem) MEM_freeN(cddm->fmap_mem);
+}
+
 static void cdDM_release(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 
-       if (DM_release(dm))
+       if (DM_release(dm)) {
+               cdDM_free_internal(cddm);
                MEM_freeN(cddm);
+       }
 }
 
 /**************** CDDM interface functions ****************/
@@ -1315,6 +1373,9 @@ static CDDerivedMesh *cdDM_create(const char *desc)
        dm->getVertCo = cdDM_getVertCo;
        dm->getVertNo = cdDM_getVertNo;
 
+       dm->getPBVH = cdDM_getPBVH;
+       dm->getFaceMap = cdDM_getFaceMap;
+
        dm->drawVerts = cdDM_drawVerts;
 
        dm->drawUVEdges = cdDM_drawUVEdges;
@@ -1366,17 +1427,12 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm");
        DerivedMesh *dm = &cddm->dm;
        CustomDataMask mask = CD_MASK_MESH & (~CD_MASK_MDISPS);
-       int i, *index, alloctype;
+       int alloctype;
 
-       /* this does a referenced copy, the only new layers being ORIGINDEX,
-        * with an exception for fluidsim */
+       /* this does a referenced copy, with an exception for fluidsim */
 
        DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface);
 
-       CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totvert);
-       CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totedge);
-       CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
-
        dm->deformedOnly = 1;
 
        alloctype= CD_REFERENCE;
@@ -1392,18 +1448,6 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
 
-       index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX);
-       for(i = 0; i < mesh->totvert; ++i, ++index)
-               *index = i;
-
-       index = CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX);
-       for(i = 0; i < mesh->totedge; ++i, ++index)
-               *index = i;
-
-       index = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
-       for(i = 0; i < mesh->totface; ++i, ++index)
-               *index = i;
-
        return dm;
 }
 
@@ -1514,6 +1558,11 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
        int numEdges = source->numEdgeData;
        int numFaces = source->numFaceData;
 
+       /* ensure these are created if they are made on demand */
+       source->getVertDataArray(source, CD_ORIGINDEX);
+       source->getEdgeDataArray(source, CD_ORIGINDEX);
+       source->getFaceDataArray(source, CD_ORIGINDEX);
+
        /* this initializes dm, and copies all non mvert/medge/mface layers */
        DM_from_template(dm, source, numVerts, numEdges, numFaces);
        dm->deformedOnly = source->deformedOnly;
@@ -1548,6 +1597,13 @@ DerivedMesh *CDDM_from_template(DerivedMesh *source,
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
 
+       if(!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
+       if(!CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+       if(!CustomData_get_layer(&dm->faceData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
@@ -1754,207 +1810,3 @@ MFace *CDDM_get_faces(DerivedMesh *dm)
        return ((CDDerivedMesh*)dm)->mface;
 }
 
-/* Multires DerivedMesh, extends CDDM */
-typedef struct MultiresDM {
-       CDDerivedMesh cddm;
-
-       MultiresModifierData *mmd;
-       int local_mmd;
-
-       int lvl, totlvl;
-       float (*orco)[3];
-       MVert *subco;
-
-       ListBase *vert_face_map, *vert_edge_map;
-       IndexNode *vert_face_map_mem, *vert_edge_map_mem;
-       int *face_offsets;
-
-       Object *ob;
-       int modified;
-
-       void (*update)(DerivedMesh*);
-} MultiresDM;
-
-static void MultiresDM_release(DerivedMesh *dm)
-{
-       MultiresDM *mrdm = (MultiresDM*)dm;
-       int mvert_layer;
-
-       /* Before freeing, need to update the displacement map */
-       if(dm->needsFree && mrdm->modified) {
-               /* Check that mmd still exists */
-               if(!mrdm->local_mmd && BLI_findindex(&mrdm->ob->modifiers, mrdm->mmd) < 0)
-                       mrdm->mmd = NULL;
-               if(mrdm->mmd)
-                       mrdm->update(dm);
-       }
-
-       /* If the MVert data is being used as the sculpt undo store, don't free it */
-       mvert_layer = CustomData_get_layer_index(&dm->vertData, CD_MVERT);
-       if(mvert_layer != -1) {
-               CustomDataLayer *cd = &dm->vertData.layers[mvert_layer];
-               if(mrdm->mmd && cd->data == mrdm->mmd->undo_verts)
-                       cd->flag |= CD_FLAG_NOFREE;
-       }
-
-       if(DM_release(dm)) {
-               MEM_freeN(mrdm->subco);
-               MEM_freeN(mrdm->orco);
-               if(mrdm->vert_face_map)
-                       MEM_freeN(mrdm->vert_face_map);
-               if(mrdm->vert_face_map_mem)
-                       MEM_freeN(mrdm->vert_face_map_mem);
-               if(mrdm->vert_edge_map)
-                       MEM_freeN(mrdm->vert_edge_map);
-               if(mrdm->vert_edge_map_mem)
-                       MEM_freeN(mrdm->vert_edge_map_mem);
-               if(mrdm->face_offsets)
-                       MEM_freeN(mrdm->face_offsets);
-               MEM_freeN(mrdm);
-       }
-}
-
-DerivedMesh *MultiresDM_new(MultiresSubsurf *ms, DerivedMesh *orig, int numVerts, int numEdges, int numFaces)
-{
-       MultiresDM *mrdm = MEM_callocN(sizeof(MultiresDM), "MultiresDM");
-       CDDerivedMesh *cddm = cdDM_create("MultiresDM CDDM");
-       DerivedMesh *dm = NULL;
-
-       mrdm->cddm = *cddm;
-       MEM_freeN(cddm);
-       dm = &mrdm->cddm.dm;
-
-       mrdm->mmd = ms->mmd;
-       mrdm->ob = ms->ob;
-       mrdm->local_mmd = ms->local_mmd;
-
-       if(dm) {
-               MDisps *disps;
-               MVert *mvert;
-               int i;
-
-               DM_from_template(dm, orig, numVerts, numEdges, numFaces);
-               CustomData_free_layers(&dm->faceData, CD_MDISPS, numFaces);
-
-               disps = CustomData_get_layer(&orig->faceData, CD_MDISPS);
-               if(disps)
-                       CustomData_add_layer(&dm->faceData, CD_MDISPS, CD_REFERENCE, disps, numFaces);
-
-
-               mvert = CustomData_get_layer(&orig->vertData, CD_MVERT);
-               mrdm->orco = MEM_callocN(sizeof(float) * 3 * orig->getNumVerts(orig), "multires orco");
-               for(i = 0; i < orig->getNumVerts(orig); ++i)
-                       copy_v3_v3(mrdm->orco[i], mvert[i].co);
-       }
-       else
-               DM_init(dm, numVerts, numEdges, numFaces);
-
-       CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
-       CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
-       CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
-
-       mrdm->cddm.mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
-       mrdm->cddm.medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
-       mrdm->cddm.mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
-
-       mrdm->lvl = ms->mmd->lvl;
-       mrdm->totlvl = ms->mmd->totlvl;
-       mrdm->subco = MEM_callocN(sizeof(MVert)*numVerts, "multires subdivided verts");
-       mrdm->modified = 0;
-
-       dm->release = MultiresDM_release;
-
-       return dm;
-}
-
-Mesh *MultiresDM_get_mesh(DerivedMesh *dm)
-{
-       return get_mesh(((MultiresDM*)dm)->ob);
-}
-
-Object *MultiresDM_get_object(DerivedMesh *dm)
-{
-       return ((MultiresDM*)dm)->ob;
-}
-
-void *MultiresDM_get_orco(DerivedMesh *dm)
-{
-       return ((MultiresDM*)dm)->orco;
-
-}
-
-MVert *MultiresDM_get_subco(DerivedMesh *dm)
-{
-       return ((MultiresDM*)dm)->subco;
-}
-
-int MultiresDM_get_totlvl(DerivedMesh *dm)
-{
-       return ((MultiresDM*)dm)->totlvl;
-}
-
-int MultiresDM_get_lvl(DerivedMesh *dm)
-{
-       return ((MultiresDM*)dm)->lvl;
-}
-
-void MultiresDM_set_orco(DerivedMesh *dm, float (*orco)[3])
-{
-       ((MultiresDM*)dm)->orco = orco;
-}
-
-void MultiresDM_set_update(DerivedMesh *dm, void (*update)(DerivedMesh*))
-{
-       ((MultiresDM*)dm)->update = update;
-}
-
-ListBase *MultiresDM_get_vert_face_map(DerivedMesh *dm)
-{
-       MultiresDM *mrdm = (MultiresDM*)dm;
-       Mesh *me = mrdm->ob->data;
-
-       if(!mrdm->vert_face_map)
-               create_vert_face_map(&mrdm->vert_face_map, &mrdm->vert_face_map_mem, me->mface,
-                                    me->totvert, me->totface);
-
-       return mrdm->vert_face_map;
-}
-
-ListBase *MultiresDM_get_vert_edge_map(DerivedMesh *dm)
-{
-       MultiresDM *mrdm = (MultiresDM*)dm;
-       Mesh *me = mrdm->ob->data;
-
-       if(!mrdm->vert_edge_map)
-               create_vert_edge_map(&mrdm->vert_edge_map, &mrdm->vert_edge_map_mem, me->medge,
-                                    me->totvert, me->totedge);
-
-       return mrdm->vert_edge_map;
-}
-
-int *MultiresDM_get_face_offsets(DerivedMesh *dm)
-{
-       MultiresDM *mrdm = (MultiresDM*)dm;
-       Mesh *me = mrdm->ob->data;
-       int i, accum = 0;
-
-       if(!mrdm->face_offsets) {
-               int len = (int)pow(2, mrdm->lvl - 2) - 1;
-               int area = len * len;
-               int t = 1 + len * 3 + area * 3, q = t + len + area;
-
-               mrdm->face_offsets = MEM_callocN(sizeof(int) * me->totface, "mrdm face offsets");
-               for(i = 0; i < me->totface; ++i) {
-                       mrdm->face_offsets[i] = accum;
-
-                       accum += (me->mface[i].v4 ? q : t);
-               }
-       }
-
-       return mrdm->face_offsets;
-}
-
-void MultiresDM_mark_as_modified(DerivedMesh *dm)
-{
-       ((MultiresDM*)dm)->modified = 1;
-}
index 0f3213c..aff3bf0 100644 (file)
@@ -440,15 +440,14 @@ static void contarget_get_mesh_mat (Scene *scene, Object *ob, char *substring, f
        /* only continue if there's a valid DerivedMesh */
        if (dm) {
                MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
-               int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
                int numVerts = dm->getNumVerts(dm);
                int i, j, count = 0;
                float co[3], nor[3];
                
-               /* check that dvert and index are valid pointers (just in case) */
-               if (dvert && index) {
+               /* check that dvert is a valid pointers (just in case) */
+               if (dvert) {
                        /* get the average of all verts with that are in the vertex-group */
-                       for (i = 0; i < numVerts; i++, index++) {       
+                       for (i = 0; i < numVerts; i++) {        
                                for (j = 0; j < dvert[i].totweight; j++) {
                                        /* does this vertex belong to nominated vertex group? */
                                        if (dvert[i].dw[j].def_nr == dgroup) {
index 7b75402..8f16731 100644 (file)
 *
 */ 
 
-#include "BKE_customdata.h"
-#include "BKE_utildefines.h" // CLAMP
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_linklist.h"
-#include "BLI_mempool.h"
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
 
 #include "DNA_customdata_types.h"
 #include "DNA_listBase.h"
 #include "DNA_meshdata_types.h"
+#include "DNA_ID.h"
 
-#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+#include "BLI_string.h"
 
-#include <math.h>
-#include <string.h>
+#include "BKE_btex.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
 
 /* number of layers to add when growing a CustomData object */
 #define CUSTOMDATA_GROW 5
@@ -89,6 +94,12 @@ typedef struct LayerTypeInfo {
     /* a function to set a layer's data to default values. if NULL, the
           default is assumed to be all zeros */
        void (*set_default)(void *data, int count);
+
+    /* a function to read data from a btex file */
+       int (*read)(BTex *btex, void *data, int count);
+
+    /* a function to write data to a btex file */
+       int (*write)(BTex *btex, void *data, int count);
 } LayerTypeInfo;
 
 static void layerCopy_mdeformvert(const void *source, void *dest,
@@ -381,6 +392,7 @@ static void layerDefault_origspace_face(void *data, int count)
                osf[i] = default_osf;
 }
 
+#if 0
 /* Adapted from sculptmode.c */
 static void mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float v)
 {
@@ -426,9 +438,12 @@ static void mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, fl
 
        add_v3_v3v3(out, d2[0], d2[1]);
 }
+#endif
 
 static void layerSwap_mdisps(void *data, int *ci)
 {
+       // XXX
+#if 0
        MDisps *s = data;
        float (*d)[3] = NULL;
        int x, y, st;
@@ -447,11 +462,14 @@ static void layerSwap_mdisps(void *data, int *ci)
        if(s->disps)
                MEM_freeN(s->disps);
        s->disps = d;
+#endif
 }
 
 static void layerInterp_mdisps(void **sources, float *weights, float *sub_weights,
                               int count, void *dest)
 {
+       // XXX
+#if 0
        MDisps *d = dest;
        MDisps *s = NULL;
        int st, stl;
@@ -496,6 +514,7 @@ static void layerInterp_mdisps(void **sources, float *weights, float *sub_weight
                        copy_v3_v3(d->disps[y * st + x], srcdisp);
                }
        }
+#endif
 }
 
 static void layerCopy_mdisps(const void *source, void *dest, int count)
@@ -530,6 +549,39 @@ static void layerFree_mdisps(void *data, int count, int size)
        }
 }
 
+static int layerRead_mdisps(BTex *btex, void *data, int count)
+{
+       MDisps *d = data;
+       int i;
+
+       for(i = 0; i < count; ++i) {
+               if(!d[i].disps)
+                       d[i].disps = MEM_callocN(sizeof(float)*3*d[i].totdisp, "mdisps read");
+
+               if(!btex_read_data(btex, d[i].totdisp*3*sizeof(float), d[i].disps)) {
+                       printf("failed to read %d/%d %d\n", i, count, d[i].totdisp);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+static int layerWrite_mdisps(BTex *btex, void *data, int count)
+{
+       MDisps *d = data;
+       int i;
+
+       for(i = 0; i < count; ++i) {
+               if(!btex_write_data(btex, d[i].totdisp*3*sizeof(float), d[i].disps)) {
+                       printf("failed to write %d/%d %d\n", i, count, d[i].totdisp);
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
 /* --------- */
 
 static void layerDefault_mloopcol(void *data, int count)
@@ -723,7 +775,7 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
        {sizeof(MLoopCol), "MLoopCol", 1, "Col", NULL, NULL, layerInterp_mloopcol, NULL, layerDefault_mloopcol},
        {sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
        {sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
-        layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL},
+        layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, layerRead_mdisps, layerWrite_mdisps},
        {sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol,
         layerSwap_mcol, layerDefault_mcol},
         {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
@@ -785,6 +837,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
        CustomDataLayer *layer, *newlayer;
        int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0;
 
+       CustomData_external_read(dest, mask, totelem);
+
        for(i = 0; i < source->totlayer; ++i) {
                layer = &source->layers[i];
                typeInfo = layerType_getInfo(layer->type);
@@ -845,6 +899,14 @@ static void customData_free_layer__internal(CustomDataLayer *layer, int totelem)
        }
 }
 
+static void CustomData_external_free(CustomData *data)
+{
+       if(data->external) {
+               MEM_freeN(data->external);
+               data->external= NULL;
+       }
+}
+
 void CustomData_free(CustomData *data, int totelem)
 {
        int i;
@@ -855,6 +917,8 @@ void CustomData_free(CustomData *data, int totelem)
        if(data->layers)
                MEM_freeN(data->layers);
        
+       CustomData_external_free(data);
+       
        memset(data, 0, sizeof(*data));
 }
 
@@ -2230,3 +2294,232 @@ int CustomData_verify_versions(struct CustomData *data, int index)
        return keeplayer;
 }
 
+/****************************** External Files *******************************/
+
+static void customdata_external_filename(char filename[FILE_MAX], CustomDataExternal *external)
+{
+       BLI_strncpy(filename, external->filename, FILE_MAX);
+       BLI_convertstringcode(filename, G.sce);
+}
+
+void CustomData_external_read(CustomData *data, CustomDataMask mask, int totelem)
+{
+       CustomDataExternal *external= data->external;
+       CustomDataLayer *layer;
+       BTex *btex;
+       BTexLayer *blay;
+       char filename[FILE_MAX];
+       const LayerTypeInfo *typeInfo;
+       int i, update = 0;
+
+       if(!external)
+               return;
+       
+       for(i=0; i<data->totlayer; i++) {
+               layer = &data->layers[i];
+               typeInfo = layerType_getInfo(layer->type);
+
+               if(!(mask & (1<<layer->type)));
+               else if(layer->flag & CD_FLAG_IN_MEMORY);
+               else if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read)
+                       update= 1;
+       }
+
+       if(!update)
+               return;
+
+       customdata_external_filename(filename, external);
+
+       btex= btex_create(BTEX_TYPE_MESH);
+       if(!btex_read_open(btex, filename))
+               return;
+
+       for(i=0; i<data->totlayer; i++) {
+               layer = &data->layers[i];
+               typeInfo = layerType_getInfo(layer->type);
+
+               if(!(mask & (1<<layer->type)));
+               else if(layer->flag & CD_FLAG_IN_MEMORY);
+               else if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) {
+                       blay= btex_layer_find(btex, layer->type, layer->name);
+
+                       if(blay) {
+                               if(btex_read_layer(btex, blay)) {
+                                       if(typeInfo->read(btex, layer->data, totelem));
+                                       else break;
+                                       layer->flag |= CD_FLAG_IN_MEMORY;
+                               }
+                               else
+                                       break;
+                       }
+               }
+       }
+
+       btex_read_close(btex);
+       btex_free(btex);
+}
+
+void CustomData_external_write(CustomData *data, CustomDataMask mask, int totelem, int free)
+{
+       CustomDataExternal *external= data->external;
+       CustomDataLayer *layer;
+       BTex *btex;
+       BTexLayer *blay;
+       const LayerTypeInfo *typeInfo;
+       int i, update = 0;
+       char filename[FILE_MAX];
+
+       if(!external)
+               return;
+
+       for(i=0; i<data->totlayer; i++) {
+               layer = &data->layers[i];
+               typeInfo = layerType_getInfo(layer->type);
+
+               if(!(mask & (1<<layer->type)));
+               else if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write)
+                       update= 1;
+       }
+
+       if(!update)
+               return;
+
+       CustomData_external_read(data, mask, totelem);
+
+       btex= btex_create(BTEX_TYPE_MESH);
+
+       for(i=0; i<data->totlayer; i++) {
+               layer = &data->layers[i];
+               typeInfo = layerType_getInfo(layer->type);
+
+               if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write)
+                       btex_layer_add(btex, layer->type, layer->name);
+       }
+
+       customdata_external_filename(filename, external);
+       if(!btex_write_open(btex, filename))
+               return;
+
+       for(i=0; i<data->totlayer; i++) {
+               layer = &data->layers[i];
+               typeInfo = layerType_getInfo(layer->type);
+
+               if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
+                       blay= btex_layer_find(btex, layer->type, layer->name);
+
+                       if(btex_write_layer(btex, blay)) {
+                               if(typeInfo->write(btex, layer->data, totelem));
+                               else break;
+                       }
+                       else
+                               break;
+               }
+       }
+
+       if(i != data->totlayer) {
+               btex_free(btex);
+               return;
+       }
+
+       for(i=0; i<data->totlayer; i++) {
+               layer = &data->layers[i];
+               typeInfo = layerType_getInfo(layer->type);
+
+               if((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) {
+                       if(free) {
+                               if(typeInfo->free)
+                                       typeInfo->free(layer->data, totelem, typeInfo->size);
+                               layer->flag &= ~CD_FLAG_IN_MEMORY;
+                       }
+               }
+       }
+
+       btex_write_close(btex);
+       btex_free(btex);
+}
+
+void CustomData_external_add(CustomData *data, int type, const char *name, int totelem)
+{
+       CustomDataExternal *external= data->external;
+       CustomDataLayer *layer;
+       int layer_index;
+
+       layer_index = CustomData_get_active_layer_index(data, type);
+       if(layer_index < 0) return;
+
+       layer = &data->layers[layer_index];
+
+       if(layer->flag & CD_FLAG_EXTERNAL)
+               return;
+
+       if(!external) {
+               char hex[MAX_ID_NAME*2];
+
+               external= MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal");
+               BLI_strhex(hex, sizeof(hex), name);
+               BLI_snprintf(external->filename, sizeof(external->filename), "//%s_mesh.btex", hex);
+               data->external= external;
+       }
+
+       layer->flag |= CD_FLAG_EXTERNAL|CD_FLAG_IN_MEMORY;
+}
+
+void CustomData_external_remove(CustomData *data, int type, int totelem)
+{
+       CustomDataExternal *external= data->external;
+       CustomDataLayer *layer;
+       char filename[FILE_MAX];
+       int layer_index, i, remove_file;
+
+       layer_index = CustomData_get_active_layer_index(data, type);
+       if(layer_index < 0) return;
+
+       layer = &data->layers[layer_index];
+
+       if(!external)
+               return;
+
+       if(layer->flag & CD_FLAG_EXTERNAL) {
+               if(!(layer->flag & CD_FLAG_IN_MEMORY))
+                       CustomData_external_read(data, (1<<layer->type), totelem);
+
+               layer->flag &= ~CD_FLAG_EXTERNAL;
+
+               remove_file= 1;
+               for(i=0; i<data->totlayer; i++)
+                       if(data->layers[i].flag & CD_FLAG_EXTERNAL)
+                               remove_file= 0;
+
+               if(remove_file) {
+                       customdata_external_filename(filename, external);
+                       btex_remove(filename);
+                       CustomData_external_free(data);
+               }
+       }
+}
+
+int CustomData_external_test(CustomData *data, int type)
+{
+       CustomDataLayer *layer;
+       int layer_index;
+
+       layer_index = CustomData_get_active_layer_index(data, type);
+       if(layer_index < 0) return 0;
+
+       layer = &data->layers[layer_index];
+       return (layer->flag & CD_FLAG_EXTERNAL);
+}
+
+void CustomData_external_remove_object(CustomData *data)
+{
+       CustomDataExternal *external= data->external;
+       char filename[FILE_MAX];
+
+       if(!external)
+               return;
+
+       customdata_external_filename(filename, external);
+       btex_remove(filename);
+       CustomData_external_free(data);
+}
+
index 48fb283..b35cf91 100644 (file)
@@ -1225,7 +1225,7 @@ static ModifierData *curve_get_tesselate_point(Object *ob, int forRender, int ed
                ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
                if ((md->mode & required_mode) != required_mode) continue;
-               if (mti->isDisabled && mti->isDisabled(md)) continue;
+               if (mti->isDisabled && mti->isDisabled(md, forRender)) continue;
 
                if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
                        preTesselatePoint  = md;
@@ -1275,7 +1275,7 @@ static void curve_calc_modifiers_pre(Scene *scene, Object *ob, int forRender, fl
                        md->scene= scene;
                        
                        if ((md->mode & required_mode) != required_mode) continue;
-                       if (mti->isDisabled && mti->isDisabled(md)) continue;
+                       if (mti->isDisabled && mti->isDisabled(md, forRender)) continue;
                        if (mti->type!=eModifierTypeType_OnlyDeform) continue;
 
                        if (!deformedVerts) {
@@ -1330,7 +1330,7 @@ static void curve_calc_modifiers_post(Scene *scene, Object *ob, ListBase *dispba
                md->scene= scene;
                
                if ((md->mode & required_mode) != required_mode) continue;
-               if (mti->isDisabled && mti->isDisabled(md)) continue;
+               if (mti->isDisabled && mti->isDisabled(md, forRender)) continue;
                if (mti->type!=eModifierTypeType_OnlyDeform && mti->type!=eModifierTypeType_DeformOrConstruct) continue;
 
                /* need to put all verts in 1 block for curve deform */
index dc548ed..e963b2e 100644 (file)
@@ -1002,7 +1002,7 @@ void lattice_calc_modifiers(Scene *scene, Object *ob)
                
                if (!(md->mode&eModifierMode_Realtime)) continue;
                if (editmode && !(md->mode&eModifierMode_Editmode)) continue;
-               if (mti->isDisabled && mti->isDisabled(md)) continue;
+               if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
                if (mti->type!=eModifierTypeType_OnlyDeform) continue;
 
                if (!vertexCos) vertexCos = lattice_getVertexCos(ob, &numVerts);
index b5e0ca9..31849ac 100644 (file)
@@ -187,7 +187,7 @@ static DerivedMesh *get_original_dm(Scene *scene, Object *ob, float (*vertexCos)
 
 /***/
 
-static int noneModifier_isDisabled(ModifierData *md)
+static int noneModifier_isDisabled(ModifierData *md, int userRenderParams)
 {
        return 1;
 }
@@ -222,7 +222,7 @@ static CustomDataMask curveModifier_requiredDataMask(Object *ob, ModifierData *m
        return dataMask;
 }
 
-static int curveModifier_isDisabled(ModifierData *md)
+static int curveModifier_isDisabled(ModifierData *md, int userRenderParams)
 {
        CurveModifierData *cmd = (CurveModifierData*) md;
 
@@ -298,7 +298,7 @@ static CustomDataMask latticeModifier_requiredDataMask(Object *ob, ModifierData
        return dataMask;
 }
 
-static int latticeModifier_isDisabled(ModifierData *md)
+static int latticeModifier_isDisabled(ModifierData *md, int userRenderParams)
 {
        LatticeModifierData *lmd = (LatticeModifierData*) md;
 
@@ -402,6 +402,13 @@ static void subsurfModifier_freeData(ModifierData *md)
        }
 }
 
+static int subsurfModifier_isDisabled(ModifierData *md, int useRenderParams)
+{
+       SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+       return (useRenderParams)? (smd->renderLevels == 0): (smd->levels == 0);
+}
+
 static DerivedMesh *subsurfModifier_applyModifier(
                ModifierData *md, Object *ob, DerivedMesh *derivedData,
   int useRenderParams, int isFinalCalc)
@@ -410,8 +417,13 @@ static DerivedMesh *subsurfModifier_applyModifier(
        DerivedMesh *result;
 
        result = subsurf_make_derived_from_derived(derivedData, smd,
-                       useRenderParams, NULL,
-   isFinalCalc, 0);
+                       useRenderParams, NULL, isFinalCalc, 0);
+       
+       if(useRenderParams || !isFinalCalc) {
+               DerivedMesh *cddm= CDDM_copy(result);
+               result->release(result);
+               result= cddm;
+       }
 
        return result;
 }
@@ -3524,7 +3536,7 @@ static void displaceModifier_foreachIDLink(ModifierData *md, Object *ob,
        displaceModifier_foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
 }
 
-static int displaceModifier_isDisabled(ModifierData *md)
+static int displaceModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        DisplaceModifierData *dmd = (DisplaceModifierData*) md;
 
@@ -4268,7 +4280,7 @@ static void smoothModifier_copyData(ModifierData *md, ModifierData *target)
        strncpy(tsmd->defgrp_name, smd->defgrp_name, 32);
 }
 
-static int smoothModifier_isDisabled(ModifierData *md)
+static int smoothModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        SmoothModifierData *smd = (SmoothModifierData*) md;
        short flag;
@@ -4498,7 +4510,7 @@ static void castModifier_copyData(ModifierData *md, ModifierData *target)
        strncpy(tcmd->defgrp_name, cmd->defgrp_name, 32);
 }
 
-static int castModifier_isDisabled(ModifierData *md)
+static int castModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        CastModifierData *cmd = (CastModifierData*) md;
        short flag;
@@ -5487,7 +5499,7 @@ static CustomDataMask armatureModifier_requiredDataMask(Object *ob, ModifierData
        return dataMask;
 }
 
-static int armatureModifier_isDisabled(ModifierData *md)
+static int armatureModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        ArmatureModifierData *amd = (ArmatureModifierData*) md;
 
@@ -5610,7 +5622,7 @@ static void hookModifier_freeData(ModifierData *md)
        if (hmd->indexar) MEM_freeN(hmd->indexar);
 }
 
-static int hookModifier_isDisabled(ModifierData *md)
+static int hookModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        HookModifierData *hmd = (HookModifierData*) md;
 
@@ -5682,7 +5694,7 @@ static void hookModifier_deformVerts(
                                /* if DerivedMesh is present and has original index data,
                                * use it
                                */
-                               if(dm && dm->getVertData(dm, 0, CD_ORIGINDEX)) {
+                               if(dm && dm->getVertDataArray(dm, CD_ORIGINDEX)) {
                                        int j;
                                        int orig_index;
                                        for(j = 0; j < numVerts; ++j) {
@@ -6308,7 +6320,7 @@ static void booleanModifier_copyData(ModifierData *md, ModifierData *target)
        tbmd->operation = bmd->operation;
 }
 
-static int booleanModifier_isDisabled(ModifierData *md)
+static int booleanModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        BooleanModifierData *bmd = (BooleanModifierData*) md;
 
@@ -7757,7 +7769,7 @@ static CustomDataMask meshdeformModifier_requiredDataMask(Object *ob, ModifierDa
        return dataMask;
 }
 
-static int meshdeformModifier_isDisabled(ModifierData *md)
+static int meshdeformModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
 
@@ -8047,15 +8059,10 @@ static void multiresModifier_initData(ModifierData *md)
 {
        MultiresModifierData *mmd = (MultiresModifierData*)md;
 
-       mmd->lvl = mmd->totlvl = 1;
-}
-
-static void multiresModifier_freeData(ModifierData *md)
-{
-       MultiresModifierData *mmd = (MultiresModifierData*)md;
-
-       if(mmd->undo_verts)
-               MEM_freeN(mmd->undo_verts);
+       mmd->lvl = 0;
+       mmd->sculptlvl = 0;
+       mmd->renderlvl = 0;
+       mmd->totlvl = 0;
 }
 
 static void multiresModifier_copyData(ModifierData *md, ModifierData *target)
@@ -8063,37 +8070,35 @@ static void multiresModifier_copyData(ModifierData *md, ModifierData *target)
        MultiresModifierData *mmd = (MultiresModifierData*) md;
        MultiresModifierData *tmmd = (MultiresModifierData*) target;
 
-       tmmd->totlvl = mmd->totlvl;
        tmmd->lvl = mmd->lvl;
+       tmmd->sculptlvl = mmd->sculptlvl;
+       tmmd->renderlvl = mmd->renderlvl;
+       tmmd->totlvl = mmd->totlvl;
 }
 
 static DerivedMesh *multiresModifier_applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
                                                   int useRenderParams, int isFinalCalc)
 {
        MultiresModifierData *mmd = (MultiresModifierData*)md;
-       DerivedMesh *final;
+       DerivedMesh *result;
 
-       /* TODO: for now just skip a level1 mesh */
-       if(mmd->lvl == 1)
-               return dm;
+       result = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams, isFinalCalc);
 
-       final = multires_dm_create_from_derived(mmd, 0, dm, ob, useRenderParams, isFinalCalc);
-       if(mmd->undo_signal && mmd->undo_verts && mmd->undo_verts_tot == final->getNumVerts(final)) {
-               int i;
-               MVert *dst = CDDM_get_verts(final);
-               for(i = 0; i < mmd->undo_verts_tot; ++i) {
-                       copy_v3_v3(dst[i].co, mmd->undo_verts[i].co);
-               }
-               CDDM_calc_normals(final);
-
-               MultiresDM_mark_as_modified(final);
+       if(result == dm)
+               return dm;
 
-               MEM_freeN(mmd->undo_verts);
-               mmd->undo_signal = 0;
-               mmd->undo_verts = NULL;
+       if(useRenderParams || !isFinalCalc) {
+               DerivedMesh *cddm= CDDM_copy(result);
+               result->release(result);
+               result= cddm;
+       }
+       else if(ob->mode & OB_MODE_SCULPT) {
+               /* would be created on the fly too, just nicer this
+                  way on first stroke after e.g. switching levels */
+               result->getPBVH(ob, result);
        }
 
-       return final;
+       return result;
 }
 
 /* Shrinkwrap */
@@ -8142,7 +8147,7 @@ static CustomDataMask shrinkwrapModifier_requiredDataMask(Object *ob, ModifierDa
        return dataMask;
 }
 
-static int shrinkwrapModifier_isDisabled(ModifierData *md)
+static int shrinkwrapModifier_isDisabled(ModifierData *md, int useRenderParams)
 {
        ShrinkwrapModifierData *smd = (ShrinkwrapModifierData*) md;
        return !smd->target;
@@ -8438,6 +8443,7 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
                mti->initData = subsurfModifier_initData;
                mti->copyData = subsurfModifier_copyData;
                mti->freeData = subsurfModifier_freeData;
+               mti->isDisabled = subsurfModifier_isDisabled;
                mti->applyModifier = subsurfModifier_applyModifier;
                mti->applyModifierEM = subsurfModifier_applyModifierEM;
 
@@ -8770,7 +8776,6 @@ ModifierTypeInfo *modifierType_getInfo(ModifierType type)
                mti->type = eModifierTypeType_Constructive;
                mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData;
                mti->initData = multiresModifier_initData;
-               mti->freeData = multiresModifier_freeData;
                mti->copyData = multiresModifier_copyData;
                mti->applyModifier = multiresModifier_applyModifier;
 
@@ -8920,7 +8925,7 @@ int modifier_couldBeCage(ModifierData *md)
 
        return (        (md->mode & eModifierMode_Realtime) &&
                        (md->mode & eModifierMode_Editmode) &&
-                       (!mti->isDisabled || !mti->isDisabled(md)) &&
+                       (!mti->isDisabled || !mti->isDisabled(md, 0)) &&
                        modifier_supportsMapping(md));  
 }
 
@@ -8963,7 +8968,7 @@ int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r, int virtual
 
                if (!(md->mode & eModifierMode_Realtime)) continue;
                if (!(md->mode & eModifierMode_Editmode)) continue;
-               if (mti->isDisabled && mti->isDisabled(md)) continue;
+               if (mti->isDisabled && mti->isDisabled(md, 0)) continue;
                if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
                if (md->mode & eModifierMode_DisableTemporary) continue;
 
@@ -9005,7 +9010,7 @@ int modifier_isEnabled(ModifierData *md, int required_mode)
        ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
        if((md->mode & required_mode) != required_mode) return 0;
-       if(mti->isDisabled && mti->isDisabled(md)) return 0;
+       if(mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return 0;
        if(md->mode & eModifierMode_DisableTemporary) return 0;
        if(required_mode & eModifierMode_Editmode)
                if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) return 0;
index 47b2914..a709b45 100644 (file)
@@ -40,6 +40,7 @@
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
 
+#include "BKE_btex.h"
 #include "BKE_cdderivedmesh.h"
 #include "BKE_customdata.h"
 #include "BKE_depsgraph.h"
 #include "BKE_multires.h"
 #include "BKE_object.h"
 #include "BKE_subsurf.h"
+#include "BKE_utildefines.h"
+
+#include "CCGSubSurf.h"
 
 #include <math.h>
 #include <string.h>
 
 /* MULTIRES MODIFIER */
 static const int multires_max_levels = 13;
-static const int multires_quad_tot[] = {4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
-static const int multires_side_tot[] = {2, 3, 5,  9,  17,  33,   65,   129,   257,   513,    1025,    2049,    4097};
+static const int multires_grid_tot[] = {1, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
+static const int multires_side_tot[] = {1, 2, 3, 5,  9,  17,  33,   65,   129,   257,   513,    1025,    2049,    4097};
+
+static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl);
 
 MultiresModifierData *find_multires_modifier(Object *ob)
 {
@@ -72,23 +78,32 @@ MultiresModifierData *find_multires_modifier(Object *ob)
        }
 
        return mmd;
+}
 
+static int multires_get_level(Object *ob, MultiresModifierData *mmd, int render)
+{
+       if(render)
+               return mmd->renderlvl;
+       else if(ob->mode == OB_MODE_SCULPT)
+               return mmd->sculptlvl;
+       else
+               return mmd->lvl;
 }
 
-int multiresModifier_switch_level(Object *ob, const int distance)
+static void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
 {
-       MultiresModifierData *mmd = find_multires_modifier(ob);
-
-       if(mmd) {
-               mmd->lvl += distance;
-               if(mmd->lvl < 1) mmd->lvl = 1;
-               else if(mmd->lvl > mmd->totlvl) mmd->lvl = mmd->totlvl;
-               /* XXX: DAG_id_flush_update(&ob->id, OB_RECALC_DATA); 
-                  object_handle_update(ob);*/
-               return 1;
+       mmd->totlvl = lvl;
+
+       if(ob->mode != OB_MODE_SCULPT) {
+               mmd->lvl = MAX2(mmd->lvl, lvl);
+               CLAMP(mmd->lvl, 0, mmd->totlvl);
        }
-       else
-               return 0;
+
+       mmd->sculptlvl = MAX2(mmd->sculptlvl, lvl);
+       CLAMP(mmd->sculptlvl, 0, mmd->totlvl);
+
+       mmd->renderlvl = MAX2(mmd->renderlvl, lvl);
+       CLAMP(mmd->renderlvl, 0, mmd->totlvl);
 }
 
 /* XXX */
@@ -156,6 +171,8 @@ void multiresModifier_join(Object *ob)
 /* Returns 0 on success, 1 if the src's totvert doesn't match */
 int multiresModifier_reshape(MultiresModifierData *mmd, Object *dst, Object *src)
 {
+       /* XXX */
+#if 0
        Mesh *src_me = get_mesh(src);
        DerivedMesh *mrdm = dst->derivedFinal;
 
@@ -172,319 +189,139 @@ int multiresModifier_reshape(MultiresModifierData *mmd, Object *dst, Object *src
 
                return 0;
        }
+#endif
 
        return 1;
 }
 
-static void Mat3FromColVecs(float mat[][3], float v1[3], float v2[3], float v3[3])
+static void column_vectors_to_mat3(float mat[][3], float v1[3], float v2[3], float v3[3])
 {
        copy_v3_v3(mat[0], v1);
        copy_v3_v3(mat[1], v2);
        copy_v3_v3(mat[2], v3);
 }
 
-static DerivedMesh *multires_subdisp_pre(DerivedMesh *mrdm, int distance, int simple)
+static void multires_copy_grid(float (*gridA)[3], float (*gridB)[3], int sizeA, int sizeB)
 {
-       DerivedMesh *final;
-       SubsurfModifierData smd;
-
-       memset(&smd, 0, sizeof(SubsurfModifierData));
-       smd.levels = distance;
-       if(simple)
-               smd.subdivType = ME_SIMPLE_SUBSURF;
+       int x, y, j, skip;
 
-       final = subsurf_make_derived_from_derived_with_multires(mrdm, &smd, NULL, 0, NULL, 0, 0);
+       if(sizeA > sizeB) {
+               skip = (sizeA-1)/(sizeB-1);
 
-       return final;
-}
+               for(j = 0, y = 0; y < sizeB; y++)
+                       for(x = 0; x < sizeB; x++, j++)
+                               copy_v3_v3(gridA[y*skip*sizeA + x*skip], gridB[j]);
+       }
+       else {
+               skip = (sizeB-1)/(sizeA-1);
 
-static void VecAddUf(float a[3], float b[3])
-{
-       a[0] += b[0];
-       a[1] += b[1];
-       a[2] += b[2];
+               for(j = 0, y = 0; y < sizeA; y++)
+                       for(x = 0; x < sizeA; x++, j++)
+                               copy_v3_v3(gridA[j], gridB[y*skip*sizeB + x*skip]);
+       }
 }
 
-static void multires_subdisp(DerivedMesh *orig, Object *ob, DerivedMesh *final, int lvl, int totlvl,
-                            int totsubvert, int totsubedge, int totsubface, int addverts)
+static void multires_copy_dm_grid(DMGridData *gridA, DMGridData *gridB, int sizeA, int sizeB)
 {
-       DerivedMesh *mrdm;
-       Mesh *me = ob->data;
-       MultiresModifierData mmd_sub;
-       MVert *mvs = CDDM_get_verts(final);
-       MVert *mvd, *mvd_f1, *mvs_f1, *mvd_f3, *mvd_f4;
-       MVert *mvd_f2, *mvs_f2, *mvs_e1, *mvd_e1, *mvs_e2;
-       int totvert;
-       int slo1 = multires_side_tot[lvl - 1];
-       int sll = slo1 / 2;
-       int slo2 = multires_side_tot[totlvl - 2];
-       int shi2 = multires_side_tot[totlvl - 1];
-       int skip = multires_side_tot[totlvl - lvl] - 1;
-       int i, j, k;
-
-       memset(&mmd_sub, 0, sizeof(MultiresModifierData));
-       mmd_sub.lvl = mmd_sub.totlvl = totlvl;
-       mrdm = multires_dm_create_from_derived(&mmd_sub, 1, orig, ob, 0, 0);
-               
-       mvd = CDDM_get_verts(mrdm);
-       /* Need to map from ccg to mrdm */
-       totvert = mrdm->getNumVerts(mrdm);
-
-       if(!addverts) {
-               for(i = 0; i < totvert; ++i) {
-                       float z[3] = {0,0,0};
-                       copy_v3_v3(mvd[i].co, z);
-               }
-       }
-
-       /* Load base verts */
-       for(i = 0; i < me->totvert; ++i)
-               VecAddUf(mvd[totvert - me->totvert + i].co, mvs[totvert - me->totvert + i].co);
-
-       mvd_f1 = mvd;
-       mvs_f1 = mvs;
-       mvd_f2 = mvd;
-       mvs_f2 = mvs + totvert - totsubvert;
-       mvs_e1 = mvs + totsubface * (skip-1) * (skip-1);
-
-       for(i = 0; i < me->totface; ++i) {
-               const int end = me->mface[i].v4 ? 4 : 3;
-               int x, y, x2, y2, mov= 0;
-
-               mvd_f1 += 1 + end * (slo2-2); //center+edgecross
-               mvd_f3 = mvd_f4 = mvd_f1;
-
-               for(j = 0; j < end; ++j) {
-                       mvd_f1 += (skip/2 - 1) * (slo2 - 2) + (skip/2 - 1);
-                       /* Update sub faces */
-                       for(y = 0; y < sll; ++y) {
-                               for(x = 0; x < sll; ++x) {
-                                       /* Face center */
-                                       VecAddUf(mvd_f1->co, mvs_f1->co);
-                                       mvs_f1 += 1;
-
-                                       /* Now we hold the center of the subface at mvd_f1
-                                          and offset it to the edge cross and face verts */
-
-                                       /* Edge cross */
-                                       for(k = 0; k < 4; ++k) {
-                                               if(k == 0) mov = -1;
-                                               else if(k == 1) mov = slo2 - 2;
-                                               else if(k == 2) mov = 1;
-                                               else if(k == 3) mov = -(slo2 - 2);
-
-                                               for(x2 = 1; x2 < skip/2; ++x2) {
-                                                       VecAddUf((mvd_f1 + mov * x2)->co, mvs_f1->co);
-                                                       ++mvs_f1;
-                                               }
-                                       }
+       int x, y, j, skip;
 
-                                       /* Main face verts */
-                                       for(k = 0; k < 4; ++k) {
-                                               int movx= 0, movy= 0;
-
-                                               if(k == 0) { movx = -1; movy = -(slo2 - 2); }
-                                               else if(k == 1) { movx = slo2 - 2; movy = -1; }
-                                               else if(k == 2) { movx = 1; movy = slo2 - 2; }
-                                               else if(k == 3) { movx = -(slo2 - 2); movy = 1; }
-
-                                               for(y2 = 1; y2 < skip/2; ++y2) {
-                                                       for(x2 = 1; x2 < skip/2; ++x2) {
-                                                               VecAddUf((mvd_f1 + movy * y2 + movx * x2)->co, mvs_f1->co);
-                                                               ++mvs_f1;
-                                                       }
-                                               }
-                                       }
-                                                       
-                                       mvd_f1 += skip;
-                               }
-                               mvd_f1 += (skip - 1) * (slo2 - 2) - 1;
-                       }
-                       mvd_f1 -= (skip - 1) * (slo2 - 2) - 1 + skip;
-                       mvd_f1 += (slo2 - 2) * (skip/2-1) + skip/2-1 + 1;
-               }
-
-               /* update face center verts */
-               VecAddUf(mvd_f2->co, mvs_f2->co);
-
-               mvd_f2 += 1;
-               mvs_f2 += 1;
-
-               /* update face edge verts */
-               for(j = 0; j < end; ++j) {
-                       MVert *restore;
-
-                       /* Super-face edge cross */
-                       for(k = 0; k < skip-1; ++k) {
-                               VecAddUf(mvd_f2->co, mvs_e1->co);
-                               mvd_f2++;
-                               mvs_e1++;
-                       }
-                       for(x = 1; x < sll; ++x) {
-                               VecAddUf(mvd_f2->co, mvs_f2->co);
-                               mvd_f2++;
-                               mvs_f2++;
-
-                               for(k = 0; k < skip-1; ++k) {
-                                       VecAddUf(mvd_f2->co, mvs_e1->co);
-                                       mvd_f2++;
-                                       mvs_e1++;
-                               }
-                       }
-
-                       restore = mvs_e1;
-                       for(y = 0; y < sll - 1; ++y) {
-                               for(x = 0; x < sll; ++x) {
-                                       for(k = 0; k < skip - 1; ++k) {
-                                               VecAddUf(mvd_f3[(skip-1)+(y*skip) + (x*skip+k)*(slo2-2)].co,
-                                                        mvs_e1->co);
-                                               ++mvs_e1;
-                                       }
-                                       mvs_e1 += skip-1;
-                               }
-                       }
-                       
-                       mvs_e1 = restore + skip - 1;
-                       for(y = 0; y < sll - 1; ++y) {
-                               for(x = 0; x < sll; ++x) {
-                                       for(k = 0; k < skip - 1; ++k) {
-                                               VecAddUf(mvd_f3[(slo2-2)*(skip-1)+(x*skip)+k + y*skip*(slo2-2)].co,
-                                                        mvs_e1->co);
-                                               ++mvs_e1;
-                                       }
-                                       mvs_e1 += skip - 1;
-                               }
-                       }
-
-                       mvd_f3 += (slo2-2)*(slo2-2);
-                       mvs_e1 -= skip - 1;
-               }
+       if(sizeA > sizeB) {
+               skip = (sizeA-1)/(sizeB-1);
 
-               /* update base (2) face verts */
-               for(j = 0; j < end; ++j) {
-                       mvd_f2 += (slo2 - 1) * (skip - 1);
-                       for(y = 0; y < sll - 1; ++y) {
-                               for(x = 0; x < sll - 1; ++x) {
-                                       VecAddUf(mvd_f2->co, mvs_f2->co);
-                                       mvd_f2 += skip;
-                                       ++mvs_f2;
-                               }
-                               mvd_f2 += (slo2 - 1) * (skip - 1);
-                       }
-                       mvd_f2 -= (skip - 1);
-               }
+               for(j = 0, y = 0; y < sizeB; y++)
+                       for(x = 0; x < sizeB; x++, j++)
+                               copy_v3_v3(gridA[y*skip*sizeA + x*skip].co, gridB[j].co);
        }
+       else {
+               skip = (sizeB-1)/(sizeA-1);
 
-       /* edges */
-       mvd_e1 = mvd + totvert - me->totvert - me->totedge * (shi2-2);
-       mvs_e2 = mvs + totvert - me->totvert - me->totedge * (slo1-2);
-       for(i = 0; i < me->totedge; ++i) {
-               for(j = 0; j < skip - 1; ++j) {
-                       VecAddUf(mvd_e1->co, mvs_e1->co);
-                       mvd_e1++;
-                       mvs_e1++;
-               }
-               for(j = 0; j < slo1 - 2; j++) {
-                       VecAddUf(mvd_e1->co, mvs_e2->co);
-                       mvd_e1++;
-                       mvs_e2++;
-                       
-                       for(k = 0; k < skip - 1; ++k) {
-                               VecAddUf(mvd_e1->co, mvs_e1->co);
-                               mvd_e1++;
-                               mvs_e1++;
-                       }
-               }
+               for(j = 0, y = 0; y < sizeA; y++)
+                       for(x = 0; x < sizeA; x++, j++)
+                               copy_v3_v3(gridA[j].co, gridB[y*skip*sizeB + x*skip].co);
        }
-
-       final->needsFree  = 1;
-       final->release(final);
-       mrdm->needsFree = 1;
-       MultiresDM_mark_as_modified(mrdm);
-       mrdm->release(mrdm);
 }
 
 /* direction=1 for delete higher, direction=0 for lower (not implemented yet) */
 void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Object *ob, int direction)
 {
        Mesh *me = get_mesh(ob);
-       int distance = mmd->totlvl - mmd->lvl;
-       MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+       int lvl = multires_get_level(ob, mmd, 0);
+       int levels = mmd->totlvl - lvl;
+       MDisps *mdisps;
+       
+       CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface);
+       mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
 
        multires_force_update(ob);
 
-       if(mdisps && distance > 0 && direction == 1) {
-               int skip = multires_side_tot[distance] - 1;
-               int st = multires_side_tot[mmd->totlvl - 1];
-               int totdisp = multires_quad_tot[mmd->lvl - 1];
-               int i, j, x, y;
+       if(mdisps && levels > 0 && direction == 1) {
+               int nsize = multires_side_tot[lvl];
+               int hsize = multires_side_tot[mmd->totlvl];
+               int i;
 
                for(i = 0; i < me->totface; ++i) {
-                       float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires del disps");
-                       
-                       for(j = 0, y = 0; y < st; y += skip) {
-                               for(x = 0; x < st; x += skip) {
-                                       copy_v3_v3(disps[j], mdisps[i].disps[y * st + x]);
-                                       ++j;
-                               }
+                       MDisps *mdisp= &mdisps[i];
+                       float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
+                       int nvert = (me->mface[i].v4)? 4: 3;
+                       int totdisp = multires_grid_tot[lvl]*nvert;
+                       int S;
+
+                       disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
+
+                       ndisps = disps;
+                       hdisps = mdisp->disps;
+
+                       for(S = 0; S < nvert; S++) {
+                               multires_copy_grid(ndisps, hdisps, nsize, hsize);
+
+                               ndisps += nsize*nsize;
+                               hdisps += hsize*hsize;
                        }
 
-                       MEM_freeN(mdisps[i].disps);
-                       mdisps[i].disps = disps;
-                       mdisps[i].totdisp = totdisp;
+                       MEM_freeN(mdisp->disps);
+                       mdisp->disps = disps;
+                       mdisp->totdisp = totdisp;
                }
        }
 
-       mmd->totlvl = mmd->lvl;
+       multires_set_tot_level(ob, mmd, lvl);
 }
 
-void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int distance, int updateblock, int simple)
+static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple)
 {
-       DerivedMesh *final = NULL;
-       int totsubvert = 0, totsubface = 0, totsubedge = 0;
-       Mesh *me = get_mesh(ob);
-       MDisps *mdisps;
-       int i;
+       MultiresModifierData mmd;
 
-       if(distance == 0)
-               return;
+       memset(&mmd, 0, sizeof(MultiresModifierData));
+       mmd.lvl = lvl;
+       mmd.sculptlvl = lvl;
+       mmd.renderlvl = lvl;
+       mmd.totlvl = totlvl;
+       mmd.simple = simple;
 
-       if(mmd->totlvl > multires_max_levels)
-               mmd->totlvl = multires_max_levels;
-       if(mmd->lvl > multires_max_levels)
-               mmd->lvl = multires_max_levels;
+       return multires_dm_create_from_derived(&mmd, 1, dm, ob, 0, 0);
+}
 
-       multires_force_update(ob);
+static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple)
+{
+       SubsurfModifierData smd;
 
-       mmd->lvl = mmd->totlvl;
-       mmd->totlvl += distance;
+       memset(&smd, 0, sizeof(SubsurfModifierData));
+       smd.levels = smd.renderLevels = lvl;
+       smd.flags |= eSubsurfModifierFlag_SubsurfUv;
+       if(simple)
+               smd.subdivType = ME_SIMPLE_SUBSURF;
 
-       mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
-       if(!mdisps)
-               mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
+       return subsurf_make_derived_from_derived(dm, &smd, 0, NULL, 0, 0);
+}
 
-       if(mdisps->disps && !updateblock && mmd->totlvl > 2) {
-               DerivedMesh *orig, *mrdm;
-               MultiresModifierData mmd_sub;
-
-               orig = CDDM_from_mesh(me, NULL);
-               memset(&mmd_sub, 0, sizeof(MultiresModifierData));
-               mmd_sub.lvl = mmd_sub.totlvl = mmd->lvl;
-               mmd_sub.simple = simple;
-               mrdm = multires_dm_create_from_derived(&mmd_sub, 1, orig, ob, 0, 0);
-               totsubvert = mrdm->getNumVerts(mrdm);
-               totsubedge = mrdm->getNumEdges(mrdm);
-               totsubface = mrdm->getNumFaces(mrdm);
-               orig->needsFree = 1;
-               orig->release(orig);
-               
-               final = multires_subdisp_pre(mrdm, distance, simple);
-               mrdm->needsFree = 1;
-               mrdm->release(mrdm);
-       }
+static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
+{
+       int i;
 
+       /* reallocate displacements to be filled in */
        for(i = 0; i < me->totface; ++i) {
-               const int totdisp = multires_quad_tot[mmd->totlvl - 1];
+               int nvert = (me->mface[i].v4)? 4: 3;
+               int totdisp = multires_grid_tot[lvl]*nvert;
                float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
 
                if(mdisps[i].disps)
@@ -493,732 +330,353 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int dista
                mdisps[i].disps = disps;
                mdisps[i].totdisp = totdisp;
        }
-
-
-       if(final) {
-               DerivedMesh *orig;
-
-               orig = CDDM_from_mesh(me, NULL);
-
-               multires_subdisp(orig, ob, final, mmd->lvl, mmd->totlvl, totsubvert, totsubedge, totsubface, 0);
-
-               orig->needsFree = 1;
-               orig->release(orig);
-       }
-
-       mmd->lvl = mmd->totlvl;
 }
 
-typedef struct DisplacerEdges {
-       /* DerivedMesh index at the start of each edge (using face x/y directions to define the start) */
-       int base[4];
-       /* 1 if edge moves in the positive x or y direction, -1 otherwise */
-       int dir[4];
-} DisplacerEdges;
-
-typedef struct DisplacerSpill {
-       /* Index of face (in base mesh), -1 for none */
-       int face;
-
-       /* Spill flag */
-       /* 1 = Negative variable axis */
-       /* 2 = Near fixed axis */
-       /* 4 = Flip axes */
-       int f;
-
-       /* Neighboring edges */
-       DisplacerEdges edges;
-} DisplacerSpill;
-
-typedef struct MultiresDisplacer {
-       Mesh *me;
-       MDisps *grid;
-       MFace *face;
-       
-       int dm_first_base_vert_index;
-
-       int spacing;
-       int sidetot, interior_st, disp_st;
-       int sidendx;
-       int type;
-       int invert;
-       MVert *subco;
-       int subco_index, face_index;
-       float weight;
-
-       /* Valence for each corner */
-       int valence[4];
-
-       /* Neighboring edges for current face */
-       DisplacerEdges edges_primary;
-
-       /* Neighboring faces */
-       DisplacerSpill spill_x, spill_y;
-
-       int *face_offsets;
-
-       int x, y, ax, ay;
-} MultiresDisplacer;
-
-static int mface_v(MFace *f, int v)
+void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple)
 {
-       return v == 0 ? f->v1 : v == 1 ? f->v2 : v == 2 ? f->v3 : v == 3 ? f->v4 : -1;
-}
+       Mesh *me = ob->data;
+       MDisps *mdisps;
+       int lvl= mmd->totlvl;
+       int totlvl= mmd->totlvl+1;
 
-/* Get the edges (and their directions) */
-static void find_displacer_edges(MultiresDisplacer *d, DerivedMesh *dm, DisplacerEdges *de, MFace *f)
-{
-       ListBase *emap = MultiresDM_get_vert_edge_map(dm);
-       IndexNode *n;
-       int i, end = f->v4 ? 4 : 3;
-       int offset = dm->getNumVerts(dm) - d->me->totvert - d->me->totedge * d->interior_st;
+       if(totlvl > multires_max_levels)
+               return;
 
-       for(i = 0; i < end; ++i) {
-               int vcur = mface_v(f, i);
-               int vnext = mface_v(f, i == end - 1 ? 0 : i + 1);
+       multires_force_update(ob);
 
-               de->dir[i] = 1;
-               
-               for(n = emap[vcur].first; n; n = n->next) {
-                       MEdge *e = &d->me->medge[n->index];
-                       
-                       if(e->v1 == vnext || e->v2 == vnext) {
-                               de->base[i] = n->index * d->interior_st;
-                               if(((i == 0 || i == 1) && e->v1 == vnext) ||
-                                  ((i == 2 || i == 3) && e->v2 == vnext)) {
-                                       de->dir[i] = -1;
-                                       de->base[i] += d->interior_st - 1;
-                               }
-                               de->base[i] += offset;
-                               break;
-                       }
-               }
-       }
-}
+       mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+       if(!mdisps)
+               mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
 
-/* Returns in out the corners [0-3] that use v1 and v2 */
-static void find_face_corners(MFace *f, int v1, int v2, int out[2])
-{
-       int i, end = f->v4 ? 4 : 3;
-
-       for(i = 0; i < end; ++i) {
-               int corner = mface_v(f, i);
-               if(corner == v1)
-                       out[0] = i;
-               if(corner == v2)
-                       out[1] = i;
-       }
-}
+       if(mdisps->disps && !updateblock && totlvl > 1) {
+               /* upsample */
+               DerivedMesh *lowdm, *cddm, *highdm;
+               DMGridData **highGridData, **lowGridData, **subGridData;
+               CCGSubSurf *ss;
+               int i, numGrids, highGridSize, lowGridSize;
+
+               /* create subsurf DM from original mesh at high level */
+               cddm = CDDM_from_mesh(me, NULL);
+               highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple);
+
+               /* create multires DM from original mesh at low level */
+               lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple);
+               cddm->release(cddm);
+
+               /* copy subsurf grids and replace them with low displaced grids */
+               numGrids = highdm->getNumGrids(highdm);
+               highGridSize = highdm->getGridSize(highdm);
+               highGridData = highdm->getGridData(highdm);
+               lowGridSize = lowdm->getGridSize(lowdm);
+               lowGridData = lowdm->getGridData(lowdm);
+
+               subGridData = MEM_callocN(sizeof(float*)*numGrids, "subGridData*");
+
+               for(i = 0; i < numGrids; ++i) {
+                       /* backup subsurf grids */
+                       subGridData[i] = MEM_callocN(sizeof(DMGridData)*highGridSize*highGridSize, "subGridData");
+                       memcpy(subGridData[i], highGridData[i], sizeof(DMGridData)*highGridSize*highGridSize);
+
+                       /* overwrite with current displaced grids */
+                       multires_copy_dm_grid(highGridData[i], lowGridData[i], highGridSize, lowGridSize);
+               }
 
-static void multires_displacer_get_spill_faces(MultiresDisplacer *d, DerivedMesh *dm, MFace *mface)
-{
-       ListBase *map = MultiresDM_get_vert_face_map(dm);
-       IndexNode *n1, *n2;
-       int v4 = d->face->v4 ? d->face->v4 : d->face->v1;
-       int crn[2], lv;
+               /* low lower level dm no longer needed at this point */
+               lowdm->release(lowdm);
 
-       memset(&d->spill_x, 0, sizeof(DisplacerSpill));
-       memset(&d->spill_y, 0, sizeof(DisplacerSpill));
-       d->spill_x.face = d->spill_y.face = -1;
+               /* subsurf higher levels again with displaced data */
+               ss= ((CCGDerivedMesh*)highdm)->ss;
+               ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0);
+               ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
 
-       for(n1 = map[d->face->v3].first; n1; n1 = n1->next) {
-               if(n1->index == d->face_index)
-                       continue;
+               /* reallocate displacements */
+               multires_reallocate_mdisps(me, mdisps, totlvl); 
 
-               for(n2 = map[d->face->v2].first; n2; n2 = n2->next) {
-                       if(n1->index == n2->index)
-                               d->spill_x.face = n1->index;
-               }
-               for(n2 = map[v4].first; n2; n2 = n2->next) {
-                       if(n1->index == n2->index)
-                               d->spill_y.face = n1->index;
-               }
-       }
+               /* compute displacements */
+               multiresModifier_disp_run(highdm, me, 1, 0, subGridData, totlvl);
 
-       if(d->spill_x.face != -1) {
-               /* Neighbor of v2/v3 found, find flip and orientation */
-               find_face_corners(&mface[d->spill_x.face], d->face->v2, d->face->v3, crn);
-               lv = mface[d->spill_x.face].v4 ? 3 : 2;
-
-               if(crn[0] == 0 && crn[1] == lv)
-                       d->spill_x.f = 0+2+0;
-               else if(crn[0] == lv && crn[1] == 0)
-                       d->spill_x.f = 1+2+0;
-               else if(crn[0] == 1 && crn[1] == 0)
-                       d->spill_x.f = 1+2+4;
-               else if(crn[0] == 0 && crn[1] == 1)
-                       d->spill_x.f = 0+2+4;
-               else if(crn[0] == 2 && crn[1] == 1)
-                       d->spill_x.f = 1+0+0;
-               else if(crn[0] == 1 && crn[1] == 2)
-                       d->spill_x.f = 0+0+0;
-               else if(crn[0] == 3 && crn[1] == 2)
-                       d->spill_x.f = 0+0+4;
-               else if(crn[0] == 2 && crn[1] == 3)
-                       d->spill_x.f = 1+0+4;
-
-               find_displacer_edges(d, dm, &d->spill_x.edges, &mface[d->spill_x.face]);
+               /* free */
+               highdm->release(highdm);
+               for(i = 0; i < numGrids; ++i)
+                       MEM_freeN(subGridData[i]);
+               MEM_freeN(subGridData);
        }
-
-       if(d->spill_y.face != -1) {
-               /* Neighbor of v3/v4 found, find flip and orientation */
-               find_face_corners(&mface[d->spill_y.face], d->face->v3, v4, crn);
-               lv = mface[d->spill_y.face].v4 ? 3 : 2;
-
-               if(crn[0] == 1 && crn[1] == 0)
-                       d->spill_y.f = 1+2+0;
-               else if(crn[0] == 0 && crn[1] == 1)
-                       d->spill_y.f = 0+2+0;
-               else if(crn[0] == 2 && crn[1] == 1)
-                       d->spill_y.f = 1+0+4;
-               else if(crn[0] == 1 && crn[1] == 2)
-                       d->spill_y.f = 0+0+4;
-               else if(crn[0] == 3 && crn[1] == 2)
-                       d->spill_y.f = 0+0+0;
-               else if(crn[0] == 2 && crn[1] == 3)
-                       d->spill_y.f = 1+0+0;
-               else if(crn[0] == 0 && crn[1] == lv)
-                       d->spill_y.f = 0+2+4;
-               else if(crn[0] == lv && crn[1] == 0)
-                       d->spill_y.f = 1+2+4;
-
-               find_displacer_edges(d, dm, &d->spill_y.edges, &mface[d->spill_y.face]);
+       else {
+               /* only reallocate, nothing to upsample */
+               multires_reallocate_mdisps(me, mdisps, totlvl); 
        }
-}
-
-static void find_corner_valences(MultiresDisplacer *d, DerivedMesh *dm)
-{
-       int i;
-
-       d->valence[3] = -1;
 
-       /* Set the vertex valence for the corners */
-       for(i = 0; i < (d->face->v4 ? 4 : 3); ++i)
-               d->valence[i] = BLI_countlist(&MultiresDM_get_vert_edge_map(dm)[mface_v(d->face, i)]);
+       multires_set_tot_level(ob, mmd, totlvl);
 }
 
-static void multires_displacer_init(MultiresDisplacer *d, DerivedMesh *dm,
-                            const int face_index, const int invert)
+static void grid_adjacent_rotate(int rotation, int gridSize, int *x, int *y)
 {
-       Mesh *me = MultiresDM_get_mesh(dm);
-
-       d->me = me;
-       d->face = me->mface + face_index;
-       d->face_index = face_index;
-       d->face_offsets = MultiresDM_get_face_offsets(dm);
-       /* Get the multires grid from customdata */
-       d->grid = CustomData_get_layer(&me->fdata, CD_MDISPS);
-       if(d->grid)
-               d->grid += face_index;
-
-       d->spacing = pow(2, MultiresDM_get_totlvl(dm) - MultiresDM_get_lvl(dm));
-       d->sidetot = multires_side_tot[MultiresDM_get_lvl(dm) - 1];
-       d->interior_st = d->sidetot - 2;
-       d->disp_st = multires_side_tot[MultiresDM_get_totlvl(dm) - 1];
-       d->invert = invert;
-
-       multires_displacer_get_spill_faces(d, dm, me->mface);
-       find_displacer_edges(d, dm, &d->edges_primary, d->face);
-       find_corner_valences(d, dm);
-
-       d->dm_first_base_vert_index = dm->getNumVerts(dm) - me->totvert;
-}
+       /* we rotate (rotation * 90°) counterclockwise around center */
+       int nx, ny;
+
+       switch(rotation) {
+               case 0: nx = *x; ny = *y; break;
+               case 1: nx = *y; ny = *x; break;
+               case 2: nx = *x; ny = *y; break; //gridSize - 1 - *x; ny = gridSize - 1 - *y; break;
+               case 3: nx = *y; ny = *x; break;
+       }
 
-static void multires_displacer_weight(MultiresDisplacer *d, const float w)
-{
-       d->weight = w;
+       *x = nx;
+       *y = ny;
 }
 
-static void multires_displacer_anchor(MultiresDisplacer *d, const int type, const int side_index)
+static void grid_adjacent_jump(DMGridAdjacency *adj, int gridSize, int *index, int *x, int *y)
 {
-       d->sidendx = side_index;
-       d->x = d->y = d->sidetot / 2;
-       d->type = type;
-
-       if(type == 2) {
-               if(side_index == 0)
-                       d->y -= 1;
-               else if(side_index == 1)
-                       d->x += 1;
-               else if(side_index == 2)
-                       d->y += 1;
-               else if(side_index == 3)
-                       d->x -= 1;
-       }
-       else if(type == 3) {
-               if(side_index == 0) {
-                       d->x -= 1;
-                       d->y -= 1;
+       if(*x < 0) {
+               if(adj->index[3] == -1) {
+                       /* no adjacent grid, clamp */
+                       *x = 0;
                }
-               else if(side_index == 1) {
-                       d->x += 1;
-                       d->y -= 1;
+               else {
+                       /* jump to adjacent grid */
+                       *index = adj->index[3];
+                       *x += gridSize;
+                       grid_adjacent_rotate(adj->rotation[3], gridSize, x, y);
                }
-               else if(side_index == 2) {
-                       d->x += 1;
-                       d->y += 1;
+       }
+       else if(*x >= gridSize) {
+               if(adj->index[1] == -1) {
+                       /* no adjacent grid, take a step back */
+                       *x = gridSize - 1;
                }
-               else if(side_index == 3) {
-                       d->x -= 1;
-                       d->y += 1;
+               else {
+                       /* jump to adjacent grid */
+                       *index = adj->index[1];
+                       *x -= gridSize;
+                       grid_adjacent_rotate(adj->rotation[1], gridSize, x, y);
                }
        }
-
-       d->ax = d->x;
-       d->ay = d->y;
-}
-
-static void multires_displacer_anchor_edge(MultiresDisplacer *d, int v1, int v2, int x)
-{
-       d->type = 4;
-
-       if(v1 == d->face->v1) {
-               d->x = 0;
-               d->y = 0;
-               if(v2 == d->face->v2)
-                       d->x += x;
-               else if(v2 == d->face->v3) {
-                       if(x < d->sidetot / 2)
-                               d->y = x;
-                       else {
-                               d->x = x;
-                               d->y = d->sidetot - 1;
-                       }
+       else if(*y < 0) {
+               if(adj->index[0] == -1) {
+                       /* no adjacent grid, clamp */
+                       *y = 0;
                }
-               else
-                       d->y += x;
-       }
-       else if(v1 == d->face->v2) {
-               d->x = d->sidetot - 1;
-               d->y = 0;
-               if(v2 == d->face->v1)
-                       d->x -= x;
-               else
-                       d->y += x;
-       }
-       else if(v1 == d->face->v3) {
-               d->x = d->sidetot - 1;
-               d->y = d->sidetot - 1;
-               if(v2 == d->face->v2)
-                       d->y -= x;
-               else if(v2 == d->face->v1) {
-                       if(x < d->sidetot / 2)
-                               d->x -= x;
-                       else {
-                               d->x = 0;
-                               d->y -= x;
-                       }
+               else {
+                       /* jump to adjacent grid */
+                       *index = adj->index[0];
+                       *y += gridSize;
+                       grid_adjacent_rotate(adj->rotation[0], gridSize, x, y);
                }
-               else
-                       d->x -= x;
        }
-       else if(v1 == d->face->v4) {
-               d->x = 0;
-               d->y = d->sidetot - 1;
-               if(v2 == d->face->v3)
-                       d->x += x;
-               else
-                       d->y -= x;
+       else if(*y >= gridSize) {
+               if(adj->index[2] == -1) {
+                       /* no adjacent grid, take a step back */
+                       *y = gridSize - 1;
+               }
+               else {
+                       /* jump to adjacent grid */
+                       *index = adj->index[2];
+                       *y -= gridSize;
+                       grid_adjacent_rotate(adj->rotation[2], gridSize, x, y);
+               }
        }
 }
 
-static void multires_displacer_anchor_vert(MultiresDisplacer *d, const int v)
-{
-       const int e = d->sidetot - 1;
-
-       d->type = 5;
-
-       d->x = d->y = 0;
-       if(v == d->face->v2)
-               d->x = e;
-       else if(v == d->face->v3)
-               d->x = d->y = e;
-       else if(v == d->face->v4)
-               d->y = e;
-}
-
-static void multires_displacer_jump(MultiresDisplacer *d)
+static void grid_tangent(DMGridAdjacency *adj, int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
 {
-       if(d->sidendx == 0) {
-               d->x -= 1;
-               d->y = d->ay;
-       }
-       else if(d->sidendx == 1) {
-               d->x = d->ax;
-               d->y -= 1;
-       }
-       else if(d->sidendx == 2) {
-               d->x += 1;
-               d->y = d->ay;
-       }
-       else if(d->sidendx == 3) {
-               d->x = d->ax;
-               d->y += 1;
+       int jindex = index, jx = x, jy = y;
+
+       if(axis == 0) {
+               if(adj->index[1] == -1 && x == gridSize - 1) {
+                       if(adj->index[2] == -1 && y == gridSize - 1)
+                               sub_v3_v3v3(t, gridData[index][x + gridSize*(y - 1)].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
+                       else
+                               sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x - 1 + gridSize*y].co);
+               }
+               else {
+                       jx += 1;
+                       grid_adjacent_jump(adj, gridSize, &jindex, &jx, &jy);
+                       sub_v3_v3v3(t, gridData[jindex][jx + gridSize*jy].co, gridData[index][x + gridSize*y].co);
+               }
        }
-}
-
-/* Treating v1 as (0,0) and v3 as (st-1,st-1),
-   returns the index of the vertex at (x,y).
-   If x or y is >= st, wraps over to the adjacent face,
-   or if there is no adjacent face, returns -2. */
-static int multires_index_at_loc(int face_index, int x, int y, MultiresDisplacer *d, DisplacerEdges *de)
-{
-       int coord_edge = d->sidetot - 1; /* Max value of x/y at edge of grid */
-       int mid = d->sidetot / 2;
-       int lim = mid - 1;
-       int qtot = lim * lim;
-       int base = d->face_offsets[face_index];
-       /* Edge spillover */
-       if(x == d->sidetot || y == d->sidetot) {
-               int flags, v_axis, f_axis, lx, ly;
-
-               if(x == d->sidetot && d->spill_x.face != -1) {
-                       flags = d->spill_x.f;
-
-                       /* Handle triangle seam between v1 and v3 */
-                       if(!d->me->mface[d->spill_x.face].v4 &&
-                          ((flags == 2 && y >= mid) || (flags == 3 && y < mid)))
-                               flags += 2;
-
-                       v_axis = (flags & 1) ? d->sidetot - 1 - y : y;
-                       f_axis = (flags & 2) ? 1 : d->sidetot - 2;
-                       lx = f_axis, ly = v_axis;
-
-                       if(flags & 4) {
-                               lx = v_axis;
-                               ly = f_axis;
+       else if(axis == 1) {
+               if(adj->index[2] == -1 && y == gridSize - 1) {
+                       if(adj->index[1] == -1 && x == gridSize - 1) {
+                               sub_v3_v3v3(t, gridData[index][x - 1 + gridSize*y].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
                        }
-
-                       return multires_index_at_loc(d->spill_x.face, lx, ly, d, &d->spill_x.edges);
-               }
-               else if(y == d->sidetot && d->spill_y.face != -1) {
-                       flags = d->spill_y.f;
-
-                       /* Handle triangle seam between v1 and v3 */
-                       if(!d->me->mface[d->spill_y.face].v4 &&
-                          ((flags == 6 && x >= mid) || (flags == 7 && x < mid)))
-                               flags = ~flags;
-
-                       v_axis = (flags & 1) ? x : d->sidetot - 1 - x;
-                       f_axis = (flags & 2) ? 1 : d->sidetot - 2;
-                       lx = v_axis, ly = f_axis;
-
-                       if(flags & 4) {
-                               lx = f_axis;
-                               ly = v_axis;
+                       else {
+                               sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x + gridSize*(y - 1)].co);
                        }
-                       
-                       return multires_index_at_loc(d->spill_y.face, lx, ly, d, &d->spill_y.edges);
                }
-               else
-                       return -2;
-       }
-       /* Corners */
-       else if(x == 0 && y == 0)
-               return d->dm_first_base_vert_index + d->face->v1;
-       else if(x == coord_edge && y == 0)
-               return d->dm_first_base_vert_index + d->face->v2;
-       else if(x == coord_edge && y == coord_edge)
-               return d->dm_first_base_vert_index + d->face->v3;
-       else if(x == 0 && y == coord_edge)
-               return d->dm_first_base_vert_index + d->face->v4;
-       /* Edges */
-       else if(x == 0) {
-               if(d->face->v4)
-                       return de->base[3] + de->dir[3] * (y - 1);
-               else
-                       return de->base[2] + de->dir[2] * (y - 1);
-       }
-       else if(y == 0)
-               return de->base[0] + de->dir[0] * (x - 1);
-       else if(x == d->sidetot - 1)
-               return de->base[1] + de->dir[1] * (y - 1);
-       else if(y == d->sidetot - 1)
-               return de->base[2] + de->dir[2] * (x - 1);
-       /* Face center */
-       else if(x == mid && y == mid)
-               return base;
-       /* Cross */
-       else if(x == mid && y < mid)
-               return base + (mid - y);
-       else if(y == mid && x > mid)
-               return base + lim + (x - mid);
-       else if(x == mid && y > mid)
-               return base + lim*2 + (y - mid);
-       else if(y == mid && x < mid) {
-               if(d->face->v4)
-                       return base + lim*3 + (mid - x);
-               else
-                       return base + lim*2 + (mid - x);
-       }
-       /* Quarters */
-       else {
-               int offset = base + lim * (d->face->v4 ? 4 : 3);
-               if(x < mid && y < mid)
-                       return offset + ((mid - x - 1)*lim + (mid - y));
-               else if(x > mid && y < mid)
-                       return offset + qtot + ((mid - y - 1)*lim + (x - mid));
-               else if(x > mid && y > mid)
-                       return offset + qtot*2 + ((x - mid - 1)*lim + (y - mid));
-               else if(x < mid && y > mid)
-                       return offset + qtot*3 + ((y - mid - 1)*lim + (mid - x));
-       }
-               
-       return -1;
-}
-
-/* Calculate the TS matrix used for applying displacements.
-   Uses the undisplaced subdivided mesh's curvature to find a
-   smoothly normal and tangents. */
-static void calc_disp_mat(MultiresDisplacer *d, float mat[3][3])
-{
-       int u = multires_index_at_loc(d->face_index, d->x + 1, d->y, d, &d->edges_primary);
-       int v = multires_index_at_loc(d->face_index, d->x, d->y + 1, d, &d->edges_primary);
-       float norm[3], t1[3], t2[3], inv[3][3];
-       MVert *base = d->subco + d->subco_index;
-
-       //printf("f=%d, x=%d, y=%d, i=%d, u=%d, v=%d ", d->face_index, d->x, d->y, d->subco_index, u, v);
-       
-       norm[0] = base->no[0] / 32767.0f;
-       norm[1] = base->no[1] / 32767.0f;
-       norm[2] = base->no[2] / 32767.0f;
-
-       /* Special handling for vertices of valence 3 */
-       if(d->valence[1] == 3 && d->x == d->sidetot - 1 && d->y == 0)
-               u = -1;
-       else if(d->valence[2] == 3 && d->x == d->sidetot - 1 && d->y == d->sidetot - 1)
-               u = v = -1;
-       else if(d->valence[3] == 3 && d->x == 0 && d->y == d->sidetot - 1)
-               v = -1;
-
-       /* If either u or v is -2, it's on a boundary. In this
-          case, back up by one row/column and use the same
-          vector as the preceeding sub-edge. */
-
-       if(u < 0) {
-               u = multires_index_at_loc(d->face_index, d->x - 1, d->y, d, &d->edges_primary);
-               sub_v3_v3v3(t1, base->co, d->subco[u].co);
-       }
-       else
-               sub_v3_v3v3(t1, d->subco[u].co, base->co);
-
-       if(v < 0) {
-               v = multires_index_at_loc(d->face_index, d->x, d->y - 1, d, &d->edges_primary);
-               sub_v3_v3v3(t2, base->co, d->subco[v].co);
-       }
-       else
-               sub_v3_v3v3(t2, d->subco[v].co, base->co);
-
-       //printf("uu=%d, vv=%d\n", u, v);
-
-       normalize_v3(t1);
-       normalize_v3(t2);
-       Mat3FromColVecs(mat, t1, t2, norm);
-
-       if(d->invert) {
-               invert_m3_m3(inv, mat);
-               copy_m3_m3(mat, inv);
+               else {
+                       jy += 1;
+                       grid_adjacent_jump(adj, gridSize, &jindex, &jx, &jy);
+                       sub_v3_v3v3(t, gridData[jindex][jx + gridSize*jy].co, gridData[index][x + gridSize*y].co);
+               }
        }
 }
 
-static void multires_displace(MultiresDisplacer *d, float co[3])
+static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl)
 {
-       float disp[3], mat[3][3];
-       float *data;
-       MVert *subco = &d->subco[d->subco_index];
-
-       if(!d->grid || !d->grid->disps) return;
-
-       data = d->grid->disps[(d->y * d->spacing) * d->disp_st + (d->x * d->spacing)];
-
-       if(d->invert)
-               sub_v3_v3v3(disp, co, subco->co);
-       else
-               copy_v3_v3(disp, data);
-
-
-       /* Apply ts matrix to displacement */
-       calc_disp_mat(d, mat);
-       mul_m3_v3(mat, disp);
-
-       if(d->invert) {
-               copy_v3_v3(data, disp);
-               
-       }
-       else {
-               if(d->type == 4 || d->type == 5)
-                       mul_v3_fl(disp, d->weight);
-               add_v3_v3v3(co, co, disp);
-       }
+       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
+       DMGridData **gridData, **subGridData;
+       DMGridAdjacency *gridAdjacency;
+       MFace *mface = me->mface;
+       MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
+       int i, S, x, y, numGrids, gIndex, gridSize, dGridSize, dSkip;
 
-       if(d->type == 2) {
-               if(d->sidendx == 0)
-                       d->y -= 1;
-               else if(d->sidendx == 1)
-                       d->x += 1;
-               else if(d->sidendx == 2)
-                       d->y += 1;
-               else if(d->sidendx == 3)
-                       d->x -= 1;
-       }
-       else if(d->type == 3) {
-               if(d->sidendx == 0)
-                       d->y -= 1;
-               else if(d->sidendx == 1)
-                       d->x += 1;
-               else if(d->sidendx == 2)
-                       d->y += 1;
-               else if(d->sidendx == 3)
-                       d->x -= 1;
-       }
-}
+       numGrids = dm->getNumGrids(dm);
+       gridSize = dm->getGridSize(dm);
+       gridData = dm->getGridData(dm);
+       gridAdjacency = dm->getGridAdjacency(dm);
+       subGridData = (oldGridData)? oldGridData: gridData;
 
-static void multiresModifier_disp_run(DerivedMesh *dm, MVert *subco, int invert)
-{
-       const int lvl = MultiresDM_get_lvl(dm);
-       const int gridFaces = multires_side_tot[lvl - 2] - 1;
-       const int edgeSize = multires_side_tot[lvl - 1] - 1;
-       MVert *mvert = CDDM_get_verts(dm);
-       MEdge *medge = MultiresDM_get_mesh(dm)->medge;
-       MFace *mface = MultiresDM_get_mesh(dm)->mface;
-       ListBase *map = MultiresDM_get_vert_face_map(dm);
-       Mesh *me = MultiresDM_get_mesh(dm);
-       MultiresDisplacer d;
-       int i, S, x, y;
-
-       d.subco = subco;
-       d.subco_index = 0;
+       dGridSize = multires_side_tot[totlvl];
+       dSkip = (dGridSize-1)/(gridSize-1);
 
-       for(i = 0; i < me->totface; ++i) {
+       for(gIndex = 0, i = 0; i < me->totface; ++i) {
                const int numVerts = mface[i].v4 ? 4 : 3;
-               
-               /* Center */
-               multires_displacer_init(&d, dm, i, invert);
-               multires_displacer_anchor(&d, 1, 0);
-               multires_displace(&d, mvert->co);
-               ++mvert;
-               ++d.subco_index;
-
-               /* Cross */
-               for(S = 0; S < numVerts; ++S) {
-                       multires_displacer_anchor(&d, 2, S);
-                       for(x = 1; x < gridFaces; ++x) {
-                               multires_displace(&d, mvert->co);
-                               ++mvert;
-                               ++d.subco_index;
-                       }
-               }
-
-               /* Quarters */
-               for(S = 0; S < numVerts; S++) {
-                       multires_displacer_anchor(&d, 3, S);
-                       for(y = 1; y < gridFaces; y++) {
-                               for(x = 1; x < gridFaces; x++) {
-                                       multires_displace(&d, mvert->co);
-                                       ++mvert;
-                                       ++d.subco_index;
-                               }
-                               multires_displacer_jump(&d);
-                       }
-               }
-       }
-
-       for(i = 0; i < me->totedge; ++i) {
-               const MEdge *e = &medge[i];
-               for(x = 1; x < edgeSize; ++x) {
-                       IndexNode *n1, *n2;
-                       int numFaces = 0;
-                       for(n1 = map[e->v1].first; n1; n1 = n1->next) {
-                               for(n2 = map[e->v2].first; n2; n2 = n2->next) {
-                                       if(n1->index == n2->index)
-                                               ++numFaces;
-                               }
-                       }
-                       multires_displacer_weight(&d, 1.0f / numFaces);
-                       /* TODO: Better to have these loops outside the x loop */
-                       for(n1 = map[e->v1].first; n1; n1 = n1->next) {
-                               for(n2 = map[e->v2].first; n2; n2 = n2->next) {
-                                       if(n1->index == n2->index) {
-                                               multires_displacer_init(&d, dm, n1->index, invert);
-                                               multires_displacer_anchor_edge(&d, e->v1, e->v2, x);
-                                               multires_displace(&d, mvert->co);
+               MDisps *mdisp = &mdisps[i];
+
+               for(S = 0; S < numVerts; ++S, ++gIndex) {
+                       DMGridData *grid = gridData[gIndex];
+                       DMGridData *subgrid = subGridData[gIndex];
+                       DMGridAdjacency *adj = &gridAdjacency[gIndex];
+                       float (*dispgrid)[3] = &mdisp->disps[S*dGridSize*dGridSize];
+
+                       for(y = 0; y < gridSize; y++) {
+                               for(x = 0; x < gridSize; x++) {
+                                       float *co = grid[x + y*gridSize].co;
+                                       float *sco = subgrid[x + y*gridSize].co;
+                                       float *no = subgrid[x + y*gridSize].no;
+                                       float *data = dispgrid[dGridSize*y*dSkip + x*dSkip];
+                                       float mat[3][3], tx[3], ty[3], disp[3], d[3];
+
+                                       /* construct tangent space matrix */
+                                       grid_tangent(adj, gridSize, gIndex, x, y, 0, subGridData, tx);
+                                       normalize_v3(tx);
+
+                                       grid_tangent(adj, gridSize, gIndex, x, y, 1, subGridData, ty);
+                                       normalize_v3(ty);
+
+                                       column_vectors_to_mat3(mat, tx, ty, no);
+
+                                       if(!invert) {
+                                               /* convert to object space and add */
+                                               mul_v3_m3v3(disp, mat, data);
+                                               add_v3_v3v3(co, sco, disp);
+                                       }
+                                       else if(!add) {
+                                               /* convert difference to tangent space */
+                                               sub_v3_v3v3(disp, co, sco);
+                                               invert_m3(mat);
+                                               mul_v3_m3v3(data, mat, disp);
+                                       }
+                                       else {
+                                               /* convert difference to tangent space */
+                                               invert_m3(mat);
+                                               mul_v3_m3v3(d, mat, co);
+                                               add_v3_v3(data, d);
                                        }
                                }
                        }
-                       ++mvert;
-                       ++d.subco_index;
-               }
-       }
-               
-       for(i = 0; i < me->totvert; ++i) {
-               IndexNode *n;
-               multires_displacer_weight(&d, 1.0f / BLI_countlist(&map[i]));
-               for(n = map[i].first; n; n = n->next) {
-                       multires_displacer_init(&d, dm, n->index, invert);
-                       multires_displacer_anchor_vert(&d, i);
-                       multires_displace(&d, mvert->co);
                }
-               ++mvert;
-               ++d.subco_index;
        }
 
-       if(!invert)
-               CDDM_calc_normals(dm);
+       if(!invert) {
+               ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
+               ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0);
+       }
 }
 
 static void multiresModifier_update(DerivedMesh *dm)
 {
+       CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
        Object *ob;
        Mesh *me;
        MDisps *mdisps;
+       MultiresModifierData *mmd;
 
-       ob = MultiresDM_get_object(dm);
-       me = MultiresDM_get_mesh(dm);
+       ob = ccgdm->multires.ob;
+       me = ccgdm->multires.ob->data;
+       mmd = ccgdm->multires.mmd;
+       CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface);
        mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
 
        if(mdisps) {
-               const int lvl = MultiresDM_get_lvl(dm);
-               const int totlvl = MultiresDM_get_totlvl(dm);
+               int lvl = ccgdm->multires.lvl;
+               int totlvl = ccgdm->multires.totlvl;
                
                if(lvl < totlvl) {
-                       /* Propagate disps upwards */
-                       DerivedMesh *final, *subco_dm, *orig;
-                       MVert *verts_new = NULL, *cur_lvl_orig_verts = NULL;
-                       MultiresModifierData mmd;
-                       int i;
-
-                       orig = CDDM_from_mesh(me, NULL);
-                       
-                       /* Regenerate the current level's vertex coordinates
-                          (includes older displacements but not new sculpts) */
-                       mmd.totlvl = totlvl;
-                       mmd.lvl = lvl;
-                       subco_dm = multires_dm_create_from_derived(&mmd, 1, orig, ob, 0, 0);
-                       cur_lvl_orig_verts = CDDM_get_verts(subco_dm);
-
-                       /* Subtract the original vertex cos from the new vertex cos */
-                       verts_new = CDDM_get_verts(dm);
-                       for(i = 0; i < dm->getNumVerts(dm); ++i)
-                               sub_v3_v3v3(verts_new[i].co, verts_new[i].co, cur_lvl_orig_verts[i].co);
-
-                       final = multires_subdisp_pre(dm, totlvl - lvl, 0);
-
-                       multires_subdisp(orig, ob, final, lvl, totlvl, dm->getNumVerts(dm), dm->getNumEdges(dm),
-                                        dm->getNumFaces(dm), 1);
-
-                       subco_dm->release(subco_dm);
-                       orig->release(orig);
+                       Mesh *me = ob->data;
+                       DerivedMesh *lowdm, *cddm, *highdm;
+                       DMGridData **highGridData, **lowGridData, **subGridData, **gridData, *diffGrid;
+                       CCGSubSurf *ss;
+                       int i, j, numGrids, highGridSize, lowGridSize;
+
+                       /* create subsurf DM from original mesh at high level */
+                       cddm = CDDM_from_mesh(me, NULL);
+                       highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple);
+
+                       /* create multires DM from original mesh and displacements */
+                       lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple);
+                       cddm->release(cddm);
+
+                       /* gather grid data */
+                       numGrids = highdm->getNumGrids(highdm);
+                       highGridSize = highdm->getGridSize(highdm);
+                       highGridData = highdm->getGridData(highdm);
+                       lowGridSize = lowdm->getGridSize(lowdm);
+                       lowGridData = lowdm->getGridData(lowdm);
+                       gridData = dm->getGridData(dm);
+
+                       subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
+                       diffGrid = MEM_callocN(sizeof(DMGridData)*lowGridSize*lowGridSize, "diff");
+
+                       for(i = 0; i < numGrids; ++i) {
+                               /* backup subsurf grids */
+                               subGridData[i] = MEM_callocN(sizeof(DMGridData)*highGridSize*highGridSize, "subGridData");
+                               memcpy(subGridData[i], highGridData[i], sizeof(DMGridData)*highGridSize*highGridSize);
+
+                               /* write difference of subsurf and displaced low level into high subsurf */
+                               for(j = 0; j < lowGridSize*lowGridSize; ++j)
+                                       sub_v3_v3v3(diffGrid[j].co, gridData[i][j].co, lowGridData[i][j].co);
+
+                               multires_copy_dm_grid(highGridData[i], diffGrid, highGridSize, lowGridSize);
+                       }
+
+                       /* lower level dm no longer needed at this point */
+                       MEM_freeN(diffGrid);
+                       lowdm->release(lowdm);
+
+                       /* subsurf higher levels again with difference of coordinates */
+                       ss= ((CCGDerivedMesh*)highdm)->ss;
+                       ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0);
+                       ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
+
+                       /* add to displacements */
+                       multiresModifier_disp_run(highdm, me, 1, 1, subGridData, mmd->totlvl);
+
+                       /* free */
+                       highdm->release(highdm);
+                       for(i = 0; i < numGrids; ++i)
+                               MEM_freeN(subGridData[i]);
+                       MEM_freeN(subGridData);
+               }
+               else {
+                       DerivedMesh *cddm, *subdm;
+
+                       cddm = CDDM_from_mesh(me, NULL);
+                       subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple);
+                       cddm->release(cddm);
+
+                       multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
+
+                       subdm->release(subdm);
                }
-               else
-                       multiresModifier_disp_run(dm, MultiresDM_get_subco(dm), 1);
        }
 }
 
 void multires_mark_as_modified(struct Object *ob)
 {
        if(ob && ob->derivedFinal) {
-               MultiresDM_mark_as_modified(ob->derivedFinal);
+               CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)ob->derivedFinal;
+               ccgdm->multires.modified = 1;
        }
 }
 
@@ -1234,24 +692,47 @@ void multires_force_update(Object *ob)
 struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob,
                                                    int useRenderParams, int isFinalCalc)
 {
-       SubsurfModifierData smd;
-       MultiresSubsurf ms;
+       Mesh *me= ob->data;
        DerivedMesh *result;
-       int i;
+       CCGDerivedMesh *ccgdm;
+       DMGridData **gridData, **subGridData;
+       int lvl= multires_get_level(ob, mmd, useRenderParams);
+       int i, gridSize, numGrids;
+
+       if(lvl == 0)
+               return dm;
+
+       result = subsurf_dm_create_local(ob, dm, lvl, 0);
+
+       if(!local_mmd) {
+               ccgdm = (CCGDerivedMesh*)result;
+
+               ccgdm->multires.ob = ob;
+               ccgdm->multires.mmd = mmd;
+               ccgdm->multires.local_mmd = local_mmd;
+               ccgdm->multires.lvl = lvl;
+               ccgdm->multires.totlvl = mmd->totlvl;
+               ccgdm->multires.modified = 0;
+               ccgdm->multires.update = multiresModifier_update;
+       }
 
-       ms.mmd = mmd;
-       ms.ob = ob;
-       ms.local_mmd = local_mmd;
+       numGrids = result->getNumGrids(result);
+       gridSize = result->getGridSize(result);
+       gridData = result->getGridData(result);
 
-       memset(&smd, 0, sizeof(SubsurfModifierData));
-       smd.levels = smd.renderLevels = mmd->lvl - 1;
-       smd.flags |= eSubsurfModifierFlag_SubsurfUv;
+       subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
 
-       result = subsurf_make_derived_from_derived_with_multires(dm, &smd, &ms, useRenderParams, NULL, isFinalCalc, 0);
-       for(i = 0; i < result->getNumVerts(result); ++i)
-               MultiresDM_get_subco(result)[i] = CDDM_get_verts(result)[i];
-       multiresModifier_disp_run(result, MultiresDM_get_subco(result), 0);
-       MultiresDM_set_update(result, multiresModifier_update);
+       for(i = 0; i < numGrids; i++) {
+               subGridData[i] = MEM_callocN(sizeof(DMGridData)*gridSize*gridSize, "subGridData");
+               memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize);
+       }
+
+       CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface);
+       multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl);
+
+       for(i = 0; i < numGrids; i++)
+               MEM_freeN(subGridData[i]);
+       MEM_freeN(subGridData);
 
        return result;
 }
@@ -1425,9 +906,9 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
        MultiresLevel *lvl, *lvl1;
        MVert *vsrc, *vdst;
        int src, dst;
-       int totlvl = MultiresDM_get_totlvl(dm);
-       int st = multires_side_tot[totlvl - 2] - 1;
-       int extedgelen = multires_side_tot[totlvl - 1] - 2;
+       int totlvl = 2; // XXX MultiresDM_get_totlvl(dm);
+       int st = multires_side_tot[totlvl - 1] - 1;
+       int extedgelen = multires_side_tot[totlvl] - 2;
        int *vvmap; // inorder for dst, map to src
        int crossedgelen;
        int i, j, s, x, totvert, tottri, totquad;
@@ -1454,9 +935,9 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
                lvl = lvl1->next;
 
                for(j = 2; j <= mr->level_count; ++j) {
-                       int base = multires_side_tot[totlvl - j] - 2;
-                       int skip = multires_side_tot[totlvl - j + 1] - 1;
-                       int st = multires_side_tot[j - 2] - 1;
+                       int base = multires_side_tot[totlvl - j + 1] - 2;
+                       int skip = multires_side_tot[totlvl - j + 2] - 1;
+                       int st = multires_side_tot[j - 1] - 1;
 
                        for(x = 0; x < st; ++x)
                                vvmap[ldst + base + x * skip] = lsrc + st * i + x;
@@ -1483,7 +964,7 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
 
                /* Face edge cross */
                tottri = totquad = 0;
-               crossedgelen = multires_side_tot[totlvl - 2] - 2;
+               crossedgelen = multires_side_tot[totlvl - 1] - 2;
                dst = 0;
                for(i = 0; i < lvl1->totface; ++i) {
                        int sides = lvl1->faces[i].v[3] ? 4 : 3;
@@ -1492,8 +973,8 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
                        ++dst;
 
                        for(j = 3; j <= mr->level_count; ++j) {
-                               int base = multires_side_tot[totlvl - j] - 2;
-                               int skip = multires_side_tot[totlvl - j + 1] - 1;
+                               int base = multires_side_tot[totlvl - j + 1] - 2;
+                               int skip = multires_side_tot[totlvl - j + 2] - 1;
                                int st = pow(2, j - 2);
                                int st2 = pow(2, j - 3);
                                int lsrc = lvl->prev->totvert;
@@ -1541,8 +1022,8 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
                        int ldst = dst + 1 + sides * (st - 1);
 
                        for(s = 0; s < sides; ++s) {
-                               int st2 = multires_side_tot[totlvl - 2] - 2;
-                               int st3 = multires_side_tot[totlvl - 3] - 2;
+                               int st2 = multires_side_tot[totlvl - 1] - 2;
+                               int st3 = multires_side_tot[totlvl - 2] - 2;
                                int st4 = st3 == 0 ? 1 : (st3 + 1) / 2;
                                int mid = ldst + st2 * st3 + st3;
                                int cv = lvl1->faces[j].v[s];
@@ -1583,3 +1064,4 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
 
        MEM_freeN(vvmap);
 }
+
index 078ff9d..660d522 100644 (file)
@@ -228,14 +228,6 @@ void free_sculptsession(SculptSession **ssp)
 {
        if(ssp && *ssp) {
                SculptSession *ss = *ssp;
-               if(ss->projverts)
-                       MEM_freeN(ss->projverts);
-
-               if(ss->fmap)
-                       MEM_freeN(ss->fmap);
-
-               if(ss->fmap_mem)
-                       MEM_freeN(ss->fmap_mem);
 
                if(ss->texcache)
                        MEM_freeN(ss->texcache);
@@ -243,8 +235,8 @@ void free_sculptsession(SculptSession **ssp)
                if(ss->layer_disps)
                        MEM_freeN(ss->layer_disps);
 
-               if(ss->mesh_co_orig)
-                       MEM_freeN(ss->mesh_co_orig);
+               if(ss->layer_co)
+                       MEM_freeN(ss->layer_co);
 
                MEM_freeN(ss);
 
@@ -1786,13 +1778,15 @@ static void give_parvert(Object *par, int nr, float *vec)
                        DerivedMesh *dm = par->derivedFinal;
                        
                        if(dm) {
-                               int i, count = 0, numVerts = dm->getNumVerts(dm);
+                               int i, count = 0, vindex, numVerts = dm->getNumVerts(dm);
                                int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
                                float co[3];
 
                                /* get the average of all verts with (original index == nr) */
-                               for(i = 0; i < numVerts; ++i, ++index) {
-                                       if(*index == nr) {
+                               for(i = 0; i < numVerts; ++i) {
+                                       vindex= (index)? *index: i;
+
+                                       if(vindex == nr) {
                                                dm->getVertCo(dm, i, co);
                                                add_v3_v3v3(vec, vec, co);
                                                count++;
index 27fcfa8..4fe63a9 100644 (file)
@@ -175,6 +175,8 @@ void paint_init(Paint *p, const char col[3])
 
        memcpy(p->paint_cursor_col, col, 3);
        p->paint_cursor_col[3] = 128;
+
+       p->flags |= PAINT_SHOW_BRUSH;
 }
 
 void free_paint(Paint *paint)
index e241d58..8605336 100644 (file)
@@ -790,7 +790,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
        totface= dm->getNumFaces(dm);
        totorigface= me->totface;
 
-       if(totface == 0 || totorigface == 0 || origindex == NULL)
+       if(totface == 0 || totorigface == 0)
                return tot;
 
        facearea= MEM_callocN(sizeof(float)*totorigface, "SimplifyFaceArea");
@@ -807,14 +807,14 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
 
        /* compute number of children per original face */
        for(a=0; a<tot; a++) {
-               b= origindex[ctx->index[a]];
+               b= (origindex)? origindex[ctx->index[a]]: ctx->index[a];
                if(b != -1)
                        elems[b].totchild++;
        }
 
        /* compute areas and centers of original faces */
        for(mf=mface, a=0; a<totface; a++, mf++) {
-               b= origindex[a];
+               b= (origindex)? origindex[a]: a;
 
                if(b != -1) {
                        VECCOPY(co1, mvert[mf->v1].co);
@@ -910,7 +910,7 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
 
        skipped= 0;
        for(a=0, newtot=0; a<tot; a++) {
-               b= origindex[ctx->index[a]];
+               b= (origindex)? origindex[ctx->index[a]]: ctx->index[a];
                if(b != -1) {
                        if(elems[b].curchild++ < ceil(elems[b].lambda*elems[b].totchild)) {
                                ctx->index[newtot]= ctx->index[a];
@@ -943,7 +943,7 @@ int psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float
        if(!data->dosimplify)
                return 0;
        
-       b= data->origindex[cpa->num];
+       b= (data->origindex)? data->origindex[cpa->num]: cpa->num;
        if(b == -1)
                return 0;
 
index 075c6f6..ffb35d5 100644 (file)
@@ -287,12 +287,12 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
                if(psys->part->from == PART_FROM_VERT) {
                        totdmelem= dm->getNumVerts(dm);
                        totelem= me->totvert;
-                       origindex= DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+                       origindex= dm->getVertDataArray(dm, CD_ORIGINDEX);
                }
                else { /* FROM_FACE/FROM_VOLUME */
                        totdmelem= dm->getNumFaces(dm);
                        totelem= me->totface;
-                       origindex= DM_get_face_data_layer(dm, CD_ORIGINDEX);
+                       origindex= dm->getFaceDataArray(dm, CD_ORIGINDEX);
                }
        
                nodedmelem= MEM_callocN(sizeof(LinkNode)*totdmelem, "psys node elems");
@@ -948,7 +948,8 @@ static int psys_threads_init_distribution(ParticleThread *threads, Scene *scene,
        if(totpart==0)
                return 0;
 
-       if (!finaldm->deformedOnly && !CustomData_has_layer( &finaldm->faceData, CD_ORIGINDEX ) ) {
+       if (!finaldm->deformedOnly && !finaldm->getFaceDataArray(finaldm, CD_ORIGINDEX)) {
+               printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
 // XXX         error("Can't paint with the current modifier stack, disable destructive modifiers");
                return 0;
        }
index c2798b4..e552f08 100644 (file)
@@ -1075,12 +1075,11 @@ static int BKE_ptcache_id_filename(PTCacheID *pid, char *filename, int cfra, sho
        }
        if(strcmp(pid->cache->name, "")==0 && (pid->cache->flag & PTCACHE_EXTERNAL)==0) {
                idname = (pid->ob->id.name+2);
+
                /* convert chars to hex so they are always a valid filename */
-               while('\0' != *idname) {
-                       snprintf(newname, MAX_PTCACHE_FILE, "%02X", (char)(*idname++));
-                       newname+=2;
-                       len += 2;
-               }
+               BLI_strhex(newname, MAX_PTCACHE_FILE - len, idname);
+               len += strlen(newname);
+               newname = filename + len;
        }
        else {
                int temp = (int)strlen(pid->cache->name); 
index cb2e2c4..716229e 100644 (file)
 #include "BKE_subsurf.h"
 
 #include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
 #include "BLI_editVert.h"
-#include "BLI_math.h"
 #include "BLI_linklist.h"
+#include "BLI_math.h"
 #include "BLI_memarena.h"
-#include "BLI_edgehash.h"
+#include "BLI_pbvh.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
 #include "CCGSubSurf.h"
 
-typedef struct _VertData {
-       float co[3];
-       float no[3];
-} VertData;
-
-struct CCGDerivedMesh {
-       DerivedMesh dm;
-
-       CCGSubSurf *ss;
-       int drawInteriorEdges, useSubsurfUv;
-
-       struct {int startVert; CCGVert *vert;} *vertMap;
-       struct {int startVert; int startEdge; CCGEdge *edge;} *edgeMap;
-       struct {int startVert; int startEdge;
-               int startFace; CCGFace *face;} *faceMap;
-};
-
-typedef struct CCGDerivedMesh CCGDerivedMesh;
-
 static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v);
 static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e);
 static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f);
@@ -136,7 +118,7 @@ static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int useAgin
        } else {
                ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8;
        }
-       ifc.vertDataSize = sizeof(VertData);
+       ifc.vertDataSize = sizeof(DMGridData);
 
        if (useArena) {
                CCGAllocatorIFC allocatorIFC;
@@ -156,7 +138,7 @@ static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int useAgin
                ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8);
        }
 
-       ccgSubSurf_setCalcVertexNormals(ccgSS, 1, BLI_STRUCT_OFFSET(VertData, no));
+       ccgSubSurf_setCalcVertexNormals(ccgSS, 1, BLI_STRUCT_OFFSET(DMGridData, no));
 
        return ccgSS;
 }
@@ -340,7 +322,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
        if(!dmtface || !tface)
                return;
 
-       /* create a CCGSubsurf from uv's */
+       /* create a CCGSubSurf from uv's */
        uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 0, 1, 0);
 
        if(!ss_sync_from_uv(uvss, ss, dm, dmtface)) {
@@ -348,7 +330,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
                return;
        }
 
-       /* get some info from CCGSubsurf */
+       /* get some info from CCGSubSurf */
        totface = ccgSubSurf_getNumFaces(uvss);
        edgeSize = ccgSubSurf_getEdgeSize(uvss);
        gridSize = ccgSubSurf_getGridSize(uvss);
@@ -372,7 +354,7 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
                int numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                for (S=0; S<numVerts; S++) {
-                       VertData *faceGridData= ccgSubSurf_getFaceGridDataArray(uvss, f, S);
+                       DMGridData *faceGridData= ccgSubSurf_getFaceGridDataArray(uvss, f, S);
 
                        for(y = 0; y < gridFaces; y++) {
                                for(x = 0; x < gridFaces; x++) {
@@ -396,37 +378,6 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
        MEM_freeN(faceMap);
 }
 
-#if 0
-static unsigned int ss_getEdgeFlags(CCGSubSurf *ss, CCGEdge *e, int ssFromEditmesh, DispListMesh *dlm, MEdge *medge, MTFace *tface)
-{
-       unsigned int flags = 0;
-       int N = ccgSubSurf_getEdgeNumFaces(e);
-
-       if (!N) flags |= ME_LOOSEEDGE;
-
-       if (ssFromEditmesh) {
-               EditEdge *eed = ccgSubSurf_getEdgeEdgeHandle(e);
-
-               flags |= ME_EDGEDRAW|ME_EDGERENDER;
-               if (eed->seam) {
-                       flags |= ME_SEAM;
-               }
-       } else {
-               if (edgeIdx!=-1) {
-                       MEdge *origMed = &medge[edgeIdx];
-
-                       if (dlm) {
-                               flags |= origMed->flag&~ME_EDGE_STEPINDEX;
-                       } else {
-                               flags |= (origMed->flag&ME_SEAM)|ME_EDGEDRAW|ME_EDGERENDER;
-                       }
-               }
-       }
-
-       return flags;
-}
-#endif
-
 /* face weighting */
 static void calc_ss_weights(int gridFaces,
                             FaceVertWeight **qweight, FaceVertWeight **tweight)
@@ -471,360 +422,6 @@ static void calc_ss_weights(int gridFaces,
        }
 }
 
-static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
-                                 int drawInteriorEdges, int useSubsurfUv,
-                                 DerivedMesh *dm, MultiresSubsurf *ms)
-{
-       DerivedMesh *result;
-       int edgeSize = ccgSubSurf_getEdgeSize(ss);
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       int edgeBase, faceBase;
-       int i, j, k, S, x, y, index;
-       CCGVertIterator *vi;
-       CCGEdgeIterator *ei;
-       CCGFaceIterator *fi;
-       CCGFace **faceMap2;
-       CCGEdge **edgeMap2;
-       CCGVert **vertMap2;
-       int totvert, totedge, totface;
-       MVert *mvert;
-       MEdge *med;
-       MFace *mf;
-       int *origIndex;
-       FaceVertWeight *qweight, *tweight;
-
-       calc_ss_weights(gridFaces, &qweight, &tweight);
-
-       /* vert map */
-       totvert = ccgSubSurf_getNumVerts(ss);
-       vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap");
-       vi = ccgSubSurf_getVertIterator(ss);
-       for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
-               CCGVert *v = ccgVertIterator_getCurrent(vi);
-
-               vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))] = v;
-       }
-       ccgVertIterator_free(vi);
-
-       totedge = ccgSubSurf_getNumEdges(ss);
-       edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap");
-       ei = ccgSubSurf_getEdgeIterator(ss);
-       for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
-               CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
-
-               edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
-       }
-
-       totface = ccgSubSurf_getNumFaces(ss);
-       faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap");
-       fi = ccgSubSurf_getFaceIterator(ss);
-       for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
-               CCGFace *f = ccgFaceIterator_getCurrent(fi);
-
-               faceMap2[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f))] = f;
-       }
-       ccgFaceIterator_free(fi);
-
-       if(ms) {
-               result = MultiresDM_new(ms, dm, ccgSubSurf_getNumFinalVerts(ss),
-                                       ccgSubSurf_getNumFinalEdges(ss),
-                                       ccgSubSurf_getNumFinalFaces(ss));
-       }
-       else {
-               if(dm) {
-                       result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss),
-                                                   ccgSubSurf_getNumFinalEdges(ss),
-                                                   ccgSubSurf_getNumFinalFaces(ss));
-               } else {
-                       result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss),
-                                         ccgSubSurf_getNumFinalEdges(ss),
-                                         ccgSubSurf_getNumFinalFaces(ss));
-               }
-       }
-
-       // load verts
-       faceBase = i = 0;
-       mvert = CDDM_get_verts(result);
-       origIndex = result->getVertData(result, 0, CD_ORIGINDEX);
-
-       for(index = 0; index < totface; index++) {
-               CCGFace *f = faceMap2[index];
-               int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-               FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
-               int vertIdx[4];
-
-               for(S = 0; S < numVerts; S++) {
-                       CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
-
-                       vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
-               }
-
-               DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i);
-               copy_v3_v3(mvert->co, ccgSubSurf_getFaceCenterData(f));
-               *origIndex = ORIGINDEX_NONE;
-               ++mvert;
-               ++origIndex;
-               i++;
-
-               for(S = 0; S < numVerts; S++) {
-                       int prevS = (S - 1 + numVerts) % numVerts;
-                       int nextS = (S + 1) % numVerts;
-                       int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
-
-                       for(x = 1; x < gridFaces; x++) {
-                               float w[4];
-                               w[prevS]  = weight[x][0][0];
-                               w[S]      = weight[x][0][1];
-                               w[nextS]  = weight[x][0][2];
-                               w[otherS] = weight[x][0][3];
-                               DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
-                               copy_v3_v3(mvert->co,
-                                        ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
-
-                               *origIndex = ORIGINDEX_NONE;
-                               ++mvert;
-                               ++origIndex;
-                               i++;
-                       }
-               }
-
-               for(S = 0; S < numVerts; S++) {
-                       int prevS = (S - 1 + numVerts) % numVerts;
-                       int nextS = (S + 1) % numVerts;
-                       int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
-
-                       for(y = 1; y < gridFaces; y++) {
-                               for(x = 1; x < gridFaces; x++) {
-                                       float w[4];
-                                       w[prevS]  = weight[y * gridFaces + x][0][0];
-                                       w[S]      = weight[y * gridFaces + x][0][1];
-                                       w[nextS]  = weight[y * gridFaces + x][0][2];
-                                       w[otherS] = weight[y * gridFaces + x][0][3];
-                                       DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
-                           &nb