Merged Google Summer of Code sculptmode/multires/retopo tools.
authorNicholas Bishop <nicholasbishop@gmail.com>
Mon, 6 Nov 2006 01:08:26 +0000 (01:08 +0000)
committerNicholas Bishop <nicholasbishop@gmail.com>
Mon, 6 Nov 2006 01:08:26 +0000 (01:08 +0000)
From the tracker:
https://projects.blender.org/tracker/index.php?func=detail&aid=5018&group_id=9&atid=127

49 files changed:
source/blender/blenkernel/BKE_bad_level_calls.h
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/bad_level_call_stubs/stubs.c
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/scene.c
source/blender/blenlib/BLI_editVert.h
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/include/BDR_drawobject.h
source/blender/include/BDR_sculptmode.h [new file with mode: 0644]
source/blender/include/BIF_editmesh.h
source/blender/include/BIF_glutil.h
source/blender/include/BIF_previewrender.h
source/blender/include/BIF_resources.h
source/blender/include/BIF_retopo.h [new file with mode: 0644]
source/blender/include/BIF_space.h
source/blender/include/BSE_view.h
source/blender/include/butspace.h
source/blender/include/multires.h [new file with mode: 0644]
source/blender/makesdna/DNA_curve_types.h
source/blender/makesdna/DNA_mesh_types.h
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_view3d_types.h
source/blender/render/intern/source/convertblender.c
source/blender/src/buttons_editing.c
source/blender/src/buttons_shading.c
source/blender/src/drawobject.c
source/blender/src/drawview.c
source/blender/src/editcurve.c
source/blender/src/editmesh.c
source/blender/src/editmesh_add.c
source/blender/src/editobject.c
source/blender/src/editscreen.c
source/blender/src/editview.c
source/blender/src/glutil.c
source/blender/src/header_buttonswin.c
source/blender/src/header_view3d.c
source/blender/src/headerbuttons.c
source/blender/src/multires.c [new file with mode: 0644]
source/blender/src/renderwin.c
source/blender/src/retopo.c [new file with mode: 0644]
source/blender/src/sculptmode.c [new file with mode: 0644]
source/blender/src/space.c
source/blender/src/toets.c
source/blender/src/transform_generics.c
source/blender/src/view.c

index 0794e8379773a12cb9d70a759500053453dabf2e..a5ad16e752e157d641d0ee7ebc6f77a0c05191a4 100644 (file)
@@ -199,5 +199,14 @@ void post_layer_create(struct VLayer *vlayer);
 void post_layer_destroy(struct VLayer *vlayer);
 void post_server_add(void);
 
+/* multires.c */
+struct MultiresLevel;
+void multires_free(struct Mesh *me);
+void multires_set_level(void *ob, void *me_v);
+void multires_calc_level_maps(struct MultiresLevel *lvl);
+/* sculptmode.c */
+void sculptmode_free_vertexusers(struct Scene *sce);
+void sculptmode_init(struct Scene *sce);
+
 #endif
 
index 0c20b545f1e9356332823439aaaff9f948377295..a7f36e74dcbc6c34b3a783cab68926afb4478e41 100644 (file)
@@ -63,7 +63,6 @@ struct bSoundListener;
 struct BMF_Font;
 struct EditMesh;
 
-
 typedef struct Global {
 
        /* active pointers */
@@ -190,6 +189,8 @@ typedef struct Global {
 #define G_DRAW_VERSE_DEBUG (1 << 27)
 /*#endif*/
 
+#define G_SCULPTMODE    (1 << 28)
+
 /* G.fileflags */
 
 #define G_AUTOPACK               (1 << 0)
index e9df9584e300141dae9a57292cce747817e7a4f4..173a130a25e98f7945ec3d7837c32fa4e8b021c8 100644 (file)
@@ -285,4 +285,9 @@ void post_geometry_free_constraint(struct VNode *vnode) {}
 void post_layer_create(struct VLayer *vlayer) {}
 void post_layer_destroy(struct VLayer *vlayer) {}
 void post_server_add(void) {}
-
+ /* Multires/sculpt stubs */
+void multires_free(struct Mesh *me) {}
+void multires_set_level(void *ob, void *me_v) {}
+void multires_calc_level_maps(struct MultiresLevel *lvl) {}
+void sculptmode_init(struct Scene *sce) {}
+void sculptmode_free_all(struct Scene *sce) {}
index 4dacfdc85d84b770f1f35a60d7f0dda630f68138..308a32439d488aa21f87283a1195dd8bbc415a14 100644 (file)
@@ -78,6 +78,8 @@
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
+#include "multires.h"
+
 // headers for fluidsim bobj meshes
 #include <stdlib.h>
 #include "LBM_fluidsim.h"
@@ -3370,9 +3372,32 @@ DerivedMesh *mesh_get_derived_deform(Object *ob, int *needsFree_r)
 DerivedMesh *mesh_create_derived_render(Object *ob)
 {
        DerivedMesh *final;
+       Mesh *m= get_mesh(ob);
+       unsigned i;
+
+       /* Goto the pin level for multires */
+       if(m->mr) {
+               m->mr->newlvl= m->mr->pinlvl;
+               multires_set_level(ob,m);
+       }
 
        mesh_calc_modifiers(ob, NULL, NULL, &final, 1, 1, 0);
 
+       /* Propagate the changes to render level - fails if mesh topology changed */
+       if(m->mr) {
+               if(final->getNumVerts(final) == m->totvert &&
+                  final->getNumFaces(final) == m->totface) {
+                       for(i=0; i<m->totvert; ++i)
+                               memcpy(&m->mvert[i], CustomData_get(&final->vertData, i, LAYERTYPE_MVERT), sizeof(MVert));
+
+                       final->release(final);
+                       
+                       m->mr->newlvl= m->mr->renderlvl;
+                       multires_set_level(ob,m);
+                       final= getMeshDerivedMesh(m,ob,NULL);
+               }
+       }       
+
        return final;
 }
 
index c0741e7137ae47c5bceb6e151c5f341d84f73179..088f5af7e07095f7ccaccd1cdeaa219e206d675d 100644 (file)
@@ -55,6 +55,8 @@
 #include "DNA_meshdata_types.h"
 #include "DNA_ipo_types.h"
 
+#include "BDR_sculptmode.h"
+
 #include "BKE_depsgraph.h"
 #include "BKE_main.h"
 #include "BKE_DerivedMesh.h"
@@ -80,6 +82,8 @@
 #include "BLI_editVert.h"
 #include "BLI_arithb.h"
 
+#include "multires.h"
+
 
 
 int update_realtime_texture(TFace *tface, double time)
@@ -153,6 +157,14 @@ void free_mesh(Mesh *me)
 {
        unlink_mesh(me);
 
+       if(me->pv) {
+               if(me->pv->vert_map) MEM_freeN(me->pv->vert_map);
+               if(me->pv->edge_map) MEM_freeN(me->pv->edge_map);
+               if(me->pv->old_faces) MEM_freeN(me->pv->old_faces);
+               if(me->pv->old_edges) MEM_freeN(me->pv->old_edges);
+               MEM_freeN(me->pv);
+       }
+
        if(me->mvert) MEM_freeN(me->mvert);
        if(me->medge) MEM_freeN(me->medge);
        if(me->mface) MEM_freeN(me->mface);
@@ -166,6 +178,8 @@ void free_mesh(Mesh *me)
        
        if(me->bb) MEM_freeN(me->bb);
        if(me->mselect) MEM_freeN(me->mselect);
+
+       if(me->mr) multires_free(me);
 }
 
 void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount)
index 272bfd38b37ebdb62a4bb8f1675492b260da2ee3..60632b33daef8708350d4fcdc64c0d6b41596e40 100644 (file)
@@ -56,6 +56,7 @@
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_scriptlink_types.h"
+#include "DNA_texture_types.h"
 #include "DNA_userdef_types.h"
 
 #include "BKE_action.h"                        
@@ -76,6 +77,9 @@
 #include "BKE_world.h"
 #include "BKE_utildefines.h"
 
+#include "BIF_previewrender.h"
+#include "BDR_sculptmode.h"
+
 #include "BPY_extern.h"
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
@@ -162,6 +166,8 @@ void free_scene(Scene *sce)
                ntreeFreeTree(sce->nodetree);
                MEM_freeN(sce->nodetree);
        }
+
+       sculptmode_free_all(sce);
 }
 
 Scene *add_scene(char *name)
@@ -232,9 +238,11 @@ Scene *add_scene(char *name)
        strcpy(sce->r.backbuf, "//backbuf");
        strcpy(sce->r.pic, U.renderdir);
        strcpy(sce->r.ftype, "//ftype");
-       
+
        BLI_init_rctf(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f);
        sce->r.osa= 8;
+
+       sculptmode_init(sce);
        
        /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
        scene_add_render_layer(sce);
index 7b3515c5135fdabfab0009f6ba68cef57b335727..0592f04f05d2afb70197818757b82680fb62bdd8 100644 (file)
@@ -41,6 +41,7 @@
 #include "DNA_mesh_types.h"
 
 struct DerivedMesh;
+struct RetopoPaintData;
 
 /* note; changing this also might affect the undo copy in editmesh.c */
 typedef struct EditVert
@@ -163,6 +164,9 @@ typedef struct EditMesh
                 */
        struct DerivedMesh *derivedCage, *derivedFinal;
 
+       char retopo_mode; /* 0=OFF, 1=ON, 2=PAINT */
+       struct RetopoPaintData *retopo_paint_data;
+
 #ifdef WITH_VERSE
        void *vnode;
 #endif
index 0808ea636adab8fd30954d2eb12822d35c1048e1..39ba28912fdb8d19841c0b491664466c9be73174 100644 (file)
 #include "BLI_arithb.h"
 #include "BLI_storage_types.h" // for relname flags
 
+#include "BDR_sculptmode.h"
+
 #include "BKE_bad_level_calls.h" // for reopen_text build_seqar (from WHILE_SEQ) set_rects_butspace check_imasel_copy
 
 #include "BKE_action.h"
 #include "BLO_undofile.h"
 #include "BLO_readblenfile.h" // streaming read pipe, for BLO_readblenfile BLO_readblenfilememory
 
+#include "multires.h"
+
 #include "readfile.h"
 
 #include "genfile.h"
@@ -2249,6 +2253,31 @@ static void direct_link_mesh(FileData *fd, Mesh *mesh)
        mesh->oc= 0;
        mesh->dface= NULL;
        mesh->mselect= NULL;
+
+       /* Multires data */
+       mesh->mr= newdataadr(fd, mesh->mr);
+       if(mesh->mr) {
+               MultiresLevel *lvl;
+               link_list(fd, &mesh->mr->levels);
+               for(lvl= mesh->mr->levels.first; lvl; lvl= lvl->next) {
+                       lvl->verts= newdataadr(fd, lvl->verts);
+                       lvl->faces= newdataadr(fd, lvl->faces);
+                       lvl->edges= newdataadr(fd, lvl->edges);
+                       lvl->texcolfaces= newdataadr(fd, lvl->texcolfaces);
+
+                       /* Recalculating the maps is faster than reading them from the file */
+                       multires_calc_level_maps(lvl);
+               }
+       }
+
+       /* PMV */
+       mesh->pv= newdataadr(fd, mesh->pv);
+       if(mesh->pv) {
+               mesh->pv->vert_map= newdataadr(fd, mesh->pv->vert_map);
+               mesh->pv->edge_map= newdataadr(fd, mesh->pv->edge_map);
+               mesh->pv->old_faces= newdataadr(fd, mesh->pv->old_faces);
+               mesh->pv->old_edges= newdataadr(fd, mesh->pv->old_edges);
+       }
        
        if (mesh->tface) {
                TFace *tfaces= mesh->tface;
@@ -2699,7 +2728,8 @@ static void lib_link_scene(FileData *fd, Main *main)
        Base *base, *next;
        Editing *ed;
        Sequence *seq;
-
+       int a;
+       
        sce= main->scene.first;
        while(sce) {
                if(sce->id.flag & LIB_NEEDLINK) {
@@ -2711,6 +2741,13 @@ static void lib_link_scene(FileData *fd, Main *main)
                        sce->toolsettings->imapaint.brush=
                                newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush);
 
+                       /* Sculptdata textures */
+                       for(a=0; a<MAX_MTEX; ++a) {
+                               MTex *mtex= sce->sculptdata.mtex[a];
+                               if(mtex)
+                                       mtex->tex= newlibadr_us(fd, sce->id.lib, mtex->tex);
+                       }
+
                        base= sce->base.first;
                        while(base) {
                                next= base->next;
@@ -2792,7 +2829,18 @@ static void direct_link_scene(FileData *fd, Scene *sce)
        sce->radio= newdataadr(fd, sce->radio);
        
        sce->toolsettings= newdataadr(fd, sce->toolsettings);
-       
+
+       /* SculptData */
+       sce->sculptdata.active_ob= NULL;
+       sce->sculptdata.vertex_users= NULL;
+       sce->sculptdata.texrndr= NULL;
+       sce->sculptdata.propset= 0;
+       sce->sculptdata.undo_cur= NULL;
+       sce->sculptdata.undo.first= sce->sculptdata.undo.last= NULL;
+       /* SculptData textures */
+       for(a=0; a<MAX_MTEX; ++a)
+               sce->sculptdata.mtex[a]= newdataadr(fd,sce->sculptdata.mtex[a]);
+
        if(sce->ed) {
                ed= sce->ed= newdataadr(fd, sce->ed);
 
@@ -3030,6 +3078,7 @@ static void lib_link_screen(FileData *fd, Main *main)
                                                if(v3d->localvd) {
                                                        v3d->localvd->camera= newlibadr(fd, sc->id.lib, v3d->localvd->camera);
                                                }
+                                               v3d->depths= NULL;
                                                v3d->ri= NULL;
                                        }
                                        else if(sl->spacetype==SPACE_IPO) {
@@ -3352,6 +3401,7 @@ static void direct_link_screen(FileData *fd, bScreen *sc)
                                v3d->localvd= newdataadr(fd, v3d->localvd);
                                v3d->afterdraw.first= v3d->afterdraw.last= NULL;
                                v3d->clipbb= newdataadr(fd, v3d->clipbb);
+                               v3d->retopo_view_data= NULL;
                        }
                        else if (sl->spacetype==SPACE_OOPS) {
                                SpaceOops *soops= (SpaceOops*) sl;
index 3955530b3b32132926bf43f99b231d8bd782cf48..0e16706eb74a737545ae81f798b2070c72f6de69 100644 (file)
@@ -1007,6 +1007,7 @@ static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
 static void write_meshs(WriteData *wd, ListBase *idbase)
 {
        Mesh *mesh;
+       MultiresLevel *lvl;
 
        mesh= idbase->first;
        while(mesh) {
@@ -1029,7 +1030,7 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
                        /* direct data */
                        writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
 
-                       writestruct(wd, DATA, "MVert", mesh->totvert, mesh->mvert);
+                       writestruct(wd, DATA, "MVert", mesh->pv?mesh->pv->totvert:mesh->totvert, mesh->mvert);
                        writestruct(wd, DATA, "MEdge", mesh->totedge, mesh->medge);
                        writestruct(wd, DATA, "MFace", mesh->totface, mesh->mface);
                        writestruct(wd, DATA, "TFace", mesh->totface, mesh->tface);
@@ -1038,6 +1039,26 @@ static void write_meshs(WriteData *wd, ListBase *idbase)
 
                        write_dverts(wd, mesh->totvert, mesh->dvert);
 
+                       /* Multires data */
+                       writestruct(wd, DATA, "Multires", 1, mesh->mr);
+                       if(mesh->mr) {
+                               for(lvl= mesh->mr->levels.first; lvl; lvl= lvl->next) {
+                                       writestruct(wd, DATA, "MultiresLevel", 1, lvl);
+                                       writestruct(wd, DATA, "MVert", lvl->totvert, lvl->verts);
+                                       writestruct(wd, DATA, "MultiresFace", lvl->totface, lvl->faces);
+                                       writestruct(wd, DATA, "MultiresEdge", lvl->totedge, lvl->edges);
+                                       writestruct(wd, DATA, "MultiresTexColFace", lvl->totface, lvl->texcolfaces);
+                               }
+                       }
+
+                       /* PMV data */
+                       if(mesh->pv) {
+                               writestruct(wd, DATA, "PartialVisibility", 1, mesh->pv);
+                               writedata(wd, DATA, sizeof(unsigned int)*mesh->pv->totvert, mesh->pv->vert_map);
+                               writedata(wd, DATA, sizeof(int)*mesh->pv->totedge, mesh->pv->edge_map);
+                               writestruct(wd, DATA, "MFace", mesh->pv->totface, mesh->pv->old_faces);
+                               writestruct(wd, DATA, "MEdge", mesh->pv->totedge, mesh->pv->old_edges);
+                       }
                }
                mesh= mesh->id.next;
        }
@@ -1199,6 +1220,7 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
        Strip *strip;
        TimeMarker *marker;
        SceneRenderLayer *srl;
+       int a;
        
        sce= scebase->first;
        while(sce) {
@@ -1214,7 +1236,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
 
                writestruct(wd, DATA, "Radio", 1, sce->radio);
                writestruct(wd, DATA, "ToolSettings", 1, sce->toolsettings);
-               
+
+               for(a=0; a<MAX_MTEX; ++a)
+                       writestruct(wd, DATA, "MTex", 1, sce->sculptdata.mtex[a]);
+
                ed= sce->ed;
                if(ed) {
                        writestruct(wd, DATA, "Editing", 1, ed);
index bd6d7cc2109ff8c9306f315e4507a95234b2a7a8..9899d56f2947cef3df373b8ef377e1238825e044 100644 (file)
@@ -50,6 +50,9 @@ struct EditVert;
 struct EditFace;
 struct EditEdge;
 
+int set_gl_material(int nr);
+int init_gl_materials(struct Object *ob, int check_alpha);
+
 void mesh_foreachScreenVert(void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, int clipVerts);
 void mesh_foreachScreenEdge(void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts);
 void mesh_foreachScreenFace(void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData);
diff --git a/source/blender/include/BDR_sculptmode.h b/source/blender/include/BDR_sculptmode.h
new file mode 100644 (file)
index 0000000..825c1b6
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */ 
+
+#ifndef BDR_SCULPTMODE_H
+#define BDR_SCULPTMODE_H
+
+struct uiBlock;
+struct BrushData;
+struct Mesh;
+struct Object;
+struct Scene;
+struct ScrArea;
+
+typedef struct PropsetData {
+       short origloc[2];
+       short origsize;
+       char origstrength;
+       unsigned int tex;
+} PropsetData;
+
+/* Memory */
+void sculptmode_init(struct Scene *);
+void sculptmode_free_all(struct Scene *);
+
+/* Undo */
+void sculptmode_undo_push(char *str);
+void sculptmode_undo();
+void sculptmode_redo();
+void sculptmode_undo_menu();
+
+/* Interface */
+void sculptmode_draw_interface_tools(struct uiBlock *block,unsigned short cx, unsigned short cy);
+void sculptmode_draw_interface_textures(struct uiBlock *block,unsigned short cx, unsigned short cy);
+void sculptmode_rem_tex(void*,void*);
+void sculptmode_propset(const unsigned short event);
+void sculptmode_selectbrush_menu();
+void sculptmode_draw_mesh();
+
+struct BrushData *sculptmode_brush();
+
+void sculptmode_update_tex();
+void sculpt();
+void set_sculpt_object(struct Object *ob);
+void set_sculptmode();
+
+/* Partial Mesh Visibility */
+void sculptmode_revert_pmv(struct Mesh *me);
+void sculptmode_pmv_off(struct Mesh *me);
+void sculptmode_pmv(int mode);
+
+#endif
index fc52405198b89e1a4925242a4a836c52cfb8cc94..8a1b480caaab6ccbe5f1cdaa2faf0affa27951af 100644 (file)
@@ -72,6 +72,7 @@ extern void add_primitiveMesh(int type);
 extern void adduplicate_mesh(void);
 extern void add_click_mesh(void);
 extern void addedgeface_mesh(void);
+void addfaces_from_edgenet();
 
 /* ******************* editmesh_lib.c */
 
index 60ac6a3b04183ab7dd2b20c84788bb81773c15e6..36bd6d0c8d7b07b2f925ebcdb097435b2d5fd625 100644 (file)
@@ -43,6 +43,7 @@ struct rctf;
 void sdrawXORline(int x0, int y0, int x1, int y1);
 void sdrawXORline4(int nr, int x0, int y0, int x1, int y1);
 
+void fdrawXORellipse(float xofs, float yofs, float hw, float hh);
 void fdrawXORcirc(float xofs, float yofs, float rad);
 
        /**
index 7ee9cc322ea62a34c644bffcbf52006d33698664..f5661fa313d0121971e0e613edf155e7ad4e7cc9 100644 (file)
@@ -30,6 +30,9 @@
  * ***** END GPL/BL DUAL LICENSE BLOCK *****
  */
 
+#ifndef BIF_PREVIEWRENDER_H
+#define BIF_PREVIEWRENDER_H
+
 #include "DNA_vec_types.h"
 
 struct View3D;
@@ -87,3 +90,5 @@ void  BIF_view3d_previewdraw  (struct ScrArea *sa, struct uiBlock *block);
 void   BIF_view3d_previewrender_free(struct View3D *v3d);
 void   BIF_view3d_previewrender_clear(struct ScrArea *sa);
 void   BIF_view3d_previewrender_signal(struct ScrArea *sa, short signal);
+
+#endif
index 7525e4efce79721bd84e863acb3b93cb9d6e4c5b..42def5ea697991b4e26ba212ab181a6fa3596060 100644 (file)
@@ -161,7 +161,7 @@ typedef enum {
        ICON_UGLY_GREEN_RING,
        ICON_GHOST,
        ICON_SORTBYEXT,
-       ICON_BLANK33,
+       ICON_SCULPTMODE_HLT,
        ICON_VERTEXSEL,
        ICON_EDGESEL,
        ICON_FACESEL,
diff --git a/source/blender/include/BIF_retopo.h b/source/blender/include/BIF_retopo.h
new file mode 100644 (file)
index 0000000..50dc23e
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_RETOPO_H
+#define BIF_RETOPO_H
+
+#include "DNA_vec_types.h"
+
+struct EditVert;
+struct Mesh;
+struct View3D;
+
+typedef struct RetopoViewData {
+       /* OpenGL matrices */
+       double modelviewmat[16], projectionmat[16];
+       int viewport[4];
+
+       char queue_matrix_update;
+} RetopoViewData;
+
+typedef struct RetopoPaintPoint {
+       struct RetopoPaintPoint *next, *prev;
+       vec2s loc;
+       short index;
+       float co[3];
+       struct EditVert *eve;
+} RetopoPaintPoint;
+
+typedef struct RetopoPaintLine {
+       struct RetopoPaintLine *next, *prev;
+       ListBase points;
+       ListBase hitlist; /* RetopoPaintHit */
+       RetopoPaintPoint *cyclic;
+} RetopoPaintLine;
+
+typedef struct RetopoPaintSel {
+       struct RetopoPaintSel *next, *prev;
+       RetopoPaintLine *line;
+       char first;
+} RetopoPaintSel;
+
+typedef struct RetopoPaintData {
+       char mode;
+       char in_drag;
+       short sloc[2];
+
+       ListBase lines;
+       ListBase intersections; /* RetopoPaintPoint */
+
+       short seldist;
+       RetopoPaintSel nearest;
+
+       /* Interface controls */
+       char line_div;
+       char ellipse_div;
+} RetopoPaintData;
+
+/* RetopoPaintData.mode */
+#define RETOPO_PEN 1
+#define RETOPO_LINE 2
+#define RETOPO_ELLIPSE 4
+
+RetopoPaintData *get_retopo_paint_data();
+
+char retopo_mesh_check();
+char retopo_curve_check();
+
+void retopo_end_okee();
+
+void retopo_free_paint_data(RetopoPaintData *rpd);
+void retopo_free_paint();
+
+char retopo_mesh_paint_check();
+void retopo_paint_view_update(struct View3D *v3d);
+void retopo_paint_toggle(void*,void*);
+char retopo_paint(const unsigned short event);
+void retopo_draw_paint_lines();
+RetopoPaintData *retopo_paint_data_copy(RetopoPaintData *rpd);
+
+void retopo_toggle(void*,void*);
+void retopo_do_vert(struct View3D *v3d, float *v);
+void retopo_do_all(void*,void*);
+void retopo_queue_updates(struct View3D *v3d);
+
+void retopo_matrix_update(struct View3D *v3d);
+
+void retopo_free_view_data(struct View3D *v3d);
+
+#endif
index 0faaae57028f4a500917906184f2de498b6cfb60..7bf0814b82e1f71e4098d24f82dc0183f36f0663 100644 (file)
@@ -54,6 +54,7 @@ struct SpaceOops;
 #define VIEW3D_HANDLER_PROPERTIES      2
 #define VIEW3D_HANDLER_OBJECT          3
 #define VIEW3D_HANDLER_PREVIEW         4
+#define VIEW3D_HANDLER_MULTIRES         5
 
 /* ipo handler codes */
 #define IPO_HANDLER_PROPERTIES 20
index 2afbca2b30eb0cc053447b4a267d84ef0a834e28..eddee0b1fdb9066b67a318741776b810fdf9276c 100644 (file)
@@ -39,6 +39,14 @@ struct BoundBox;
 struct View3D;
 struct ScrArea;
 
+typedef struct ViewDepths {
+       unsigned short w, h;
+       float *depths;
+       double depth_range[2];
+
+       char damaged;
+} ViewDepths;
+
 #define PERSP_WIN      0
 #define PERSP_VIEW     1
 #define PERSP_STORE    2
index 9ea29743d797deac4c88c8976c0d6e19e7266560..53779f4f3d5f60343233680587031ca8e8b3de12 100644 (file)
@@ -554,6 +554,9 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
 #define B_BTEXDELETE   2856
 #define B_BRUSHKEEPDATA 2857
 
+/* Sculptmode */
+#define B_SCULPT_TEXBROWSE      2860
+
 /* *********************** */
 #define B_RADIOBUTS            3000
 
diff --git a/source/blender/include/multires.h b/source/blender/include/multires.h
new file mode 100644 (file)
index 0000000..af5260e
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */ 
+
+#ifndef MULTIRES_H
+#define MULTIRES_H
+
+struct uiBlock;
+struct Object;
+struct Mesh;
+struct MultiresLevel;
+
+void multires_draw_interface(struct uiBlock *block, unsigned short cx, unsigned short cy);
+void multires_disp_map(void *, void*);
+
+void multires_make(void *ob, void *me);
+void multires_delete(void *ob, void *me);
+void multires_free(Mesh *me);
+void multires_free_level(MultiresLevel *lvl);
+void multires_del_lower(void *ob, void *me);
+void multires_del_higher(void *ob, void *me);
+void multires_add_level(void *ob, void *me);
+void multires_set_level(void *ob, void *me);
+void multires_update_levels(Mesh *me);
+void multires_level_to_mesh(Object *ob, Mesh *me);
+void multires_calc_level_maps(MultiresLevel *lvl);
+void multires_edge_level_update(void *ob, void *me);
+
+#endif
index 04b7b4804b7f39fca89dce63b6634ebe5daea478..626e7cf41670f31b13dfc2fd8ba033eae9eef7f5 100644 (file)
@@ -229,6 +229,7 @@ typedef struct IpoCurve {
 #define CU_STRETCH             128
 #define CU_OFFS_PATHDIST       256
 #define CU_FAST                        512 /* Font: no filling inside editmode */
+#define CU_RETOPO               1024
 
 /* spacemode */
 #define CU_LEFT                        0
index a57791be06d3ad51e53fc40bf27157f55eff9d46..d0ef6724ff0490b8b562789634f5968320964579 100644 (file)
@@ -47,6 +47,8 @@ struct MCol;
 struct MSticky;
 struct Mesh;
 struct OcInfo;
+struct Multires;
+struct PartialVisibility;
 
 typedef struct TFace {
 
@@ -99,6 +101,8 @@ typedef struct Mesh {
        short totcol;
        short subsurftype; 
 
+       struct Multires *mr;            /* Multiresolution modeling data */
+       struct PartialVisibility *pv;
 /*ifdef WITH_VERSE*/
        /* not written in file, pointer at geometry VerseNode */
        void *vnode;
index 34c3cc904f11bd6450dc0a14bfc6364502531027..a091a2d4ce76532bef8a86e54296b3e8fe6d159b 100644 (file)
@@ -75,6 +75,66 @@ typedef struct MSelect {
        int index;
        int type;
 } MSelect;
+
+/* Multiresolution modeling */
+typedef struct MultiresCol {
+       float a, r, g, b, u, v;
+} MultiresCol;
+typedef struct MultiresFace {
+       unsigned int v[4];
+               unsigned int mid;
+       unsigned int childrenstart;
+       char flag, pad[3];
+} MultiresFace;
+typedef struct MultiresEdge {
+       unsigned int v[2];
+       unsigned int mid;
+} MultiresEdge;
+
+typedef struct MultiresTexColFace {
+       /* vertex colors and texfaces */
+       void *tex_page;
+       MultiresCol col[4];
+       short tex_mode, tex_tile, tex_unwrap;
+       char tex_flag, tex_transp;
+} MultiresTexColFace;
+
+typedef struct MultiresMapNode {
+       struct MultiresMapNode *next, *prev;
+       int Index, pad;
+} MultiresMapNode;
+
+typedef struct MultiresLevel {
+       struct MultiresLevel *next, *prev;
+
+       MVert *verts;
+       MultiresFace *faces;
+       MultiresTexColFace *texcolfaces;
+       MultiresEdge *edges;
+       ListBase *vert_edge_map;
+       ListBase *vert_face_map;
+
+       unsigned int totvert, totface, totedge, pad;
+} MultiresLevel;
+
+typedef struct Multires {
+       ListBase levels;
+       unsigned char level_count, current, newlvl, edgelvl, pinlvl, renderlvl;
+       unsigned char use_col, use_tex;
+
+       /* Vertex groups are stored only for the level 1 mesh, for all other
+        * levels it's calculated when multires_level_to_mesh() is called */
+       MDeformVert *dverts;
+} Multires;
+
+typedef struct PartialVisibility {
+       unsigned int *vert_map; /* vert_map[Old Index]= New Index */
+       int *edge_map; /* edge_map[Old Index]= New Index, -1= hidden */
+       MFace *old_faces;
+       MEdge *old_edges;
+       unsigned int totface, totedge, totvert, pad;
+} PartialVisibility;
+
 /* mvert->flag (1=SELECT) */
 #define ME_SPHERETEST  2
 #define ME_SPHERETEMP  4
index 22bcf432c4811766eda19c90ee94ab7b5dfb734e..fe43676f1dbd6bf20f1b1080174b01363108a219 100644 (file)
@@ -49,6 +49,7 @@ struct Scene;
 struct Image;
 struct Group;
 struct bNodeTree;
+struct PropsetData;
 
 typedef struct Base {
        struct Base *next, *prev;
@@ -357,6 +358,74 @@ typedef struct ToolSettings {
        
 } ToolSettings;
 
+/* Used by all brushes to store their properties, which can be directly set
+   by the interface code. Note that not all properties are actually used by
+   all the brushes. */
+typedef struct BrushData
+{
+       short size;
+       char strength, dir; /* Not used for smooth brush */
+       char airbrush;
+       char pad[7];
+} BrushData;
+       
+struct RenderInfo;
+struct SculptUndo;
+typedef struct SculptData
+{
+       /* Cache of the OpenGL matrices */
+       double modelviewmat[16];
+       double projectionmat[16];
+       int viewport[4];
+
+       /* Pointers to all of sculptmodes's textures */
+       struct MTex *mtex[10];
+
+       struct Object *active_ob;
+
+       /* An array of lists; array is sized as
+          large as the number of verts in the mesh,
+          the list for each vert contains the index
+          for all the faces that use that vertex */
+       struct ListBase *vertex_users;
+
+       /* Used to cache the render of the active texture */
+       struct RenderInfo *texrndr;
+
+       struct PropsetData *propset_data;
+
+       struct ListBase undo;
+       struct SculptUndo *undo_cur;
+
+       /* For rotating around a pivot point */
+       vec3f pivot;
+
+       /* Settings for each brush */
+       BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush;
+
+       /* Number of nodes in vertex_users */
+       int vertex_users_size;
+
+       short brush_type;
+
+       /* Symmetry is separate from the other BrushData because the same
+          settings are always used for all brush types */
+       short symm_x, symm_y, symm_z;
+
+       /* For the Brush Shape */
+       float texsize[3];
+       short texact, texnr;
+       short spacing;
+       char texrept;
+       char texfade;
+
+       char averaging, propset, pad[2];
+} SculptData;
+
+#define SCULPTREPT_DRAG 1
+#define SCULPTREPT_TILE 2
+#define SCULPTREPT_3D   3
+
 typedef struct Scene {
        ID id;
        struct Object *camera;
@@ -405,6 +474,9 @@ typedef struct Scene {
        struct  DagForest *theDag;
        short dagisvalid, dagflags;
        short pad4, recalc;                             /* recalc = counterpart of ob->recalc */
+
+       /* Sculptmode data */
+       struct SculptData sculptdata;
 } Scene;
 
 
@@ -549,6 +621,14 @@ typedef struct Scene {
 #define FFMPEG_MULTIPLEX_AUDIO  1
 #define FFMPEG_AUTOSPLIT_OUTPUT 2
 
+/* SculptData brushtype */
+#define DRAW_BRUSH 1
+#define SMOOTH_BRUSH 2
+#define PINCH_BRUSH 3
+#define INFLATE_BRUSH 4
+#define GRAB_BRUSH 5
+#define LAYER_BRUSH 6
+
 /* toolsettings->imagepaint_flag */
 #define IMAGEPAINT_DRAWING                             1
 #define IMAGEPAINT_DRAW_TOOL                   2
index eb787682755b77d8a2bdda8999752e03d613f02f..f9db4633280c85316b96310c475fa5f014ddf654 100644 (file)
@@ -258,7 +258,6 @@ extern UserDef U; /* from usiblender.c !!!! */
 #define USER_DISABLE_SOUND             2
 #define USER_DISABLE_MIPMAP            4
 
-
 /* vrml flag */
 
 #define USER_VRML_LAYERS               1
index dda40b67bf7234c7ab559178e8950a6478dd8a1b..be3a5099d7ba7259b7719325eacdd1e0af6f5c00 100644 (file)
@@ -34,6 +34,7 @@
 #ifndef DNA_VIEW3D_TYPES_H
 #define DNA_VIEW3D_TYPES_H
 
+struct ViewDepths;
 struct Object;
 struct Image;
 struct Tex;
@@ -41,6 +42,7 @@ struct SpaceLink;
 struct Base;
 struct BoundBox;
 struct RenderInfo;
+struct RetopoViewData;
 
 /* This is needed to not let VC choke on near and far... old
  * proprietary MS extensions... */
@@ -95,6 +97,8 @@ typedef struct View3D {
        struct BGpic *bgpic;
        struct View3D *localvd;
        struct RenderInfo *ri;
+       struct RetopoViewData *retopo_view_data;
+       struct ViewDepths *depths;
        
        /**
         * The drawing mode for the 3d display. Set to OB_WIRE, OB_SOLID,
@@ -104,7 +108,7 @@ typedef struct View3D {
        int lay, layact;
        short scenelock, around, camzoom;
        
-       short pad1;
+       char pivot_last, pad1; /* pivot_last is for rotating around the last edited element */
        
        float lens, grid, gridview, pixsize, near, far;
        float camdx, camdy;             /* camera view offsets, 1.0 = viewplane moves entire width/height */
index 8d23269166c8a9f562379909517ebab322cc879a..d16bbd28b9c319e8cc0a5ae931e05ad0532ab087 100644 (file)
@@ -92,6 +92,7 @@
 #include "IMB_imbuf_types.h"
 
 #include "envmap.h"
+#include "multires.h"
 #include "render_types.h"
 #include "rendercore.h"
 #include "renderdatabase.h"
@@ -1784,7 +1785,7 @@ static void use_mesh_edge_lookup(Render *re, Mesh *me, DispListMesh *dlm, MEdge
 
 static void init_render_mesh(Render *re, Object *ob, Object *par, int only_verts)
 {
-       Mesh *me;
+       Mesh *me, *me_store= NULL;
        MVert *mvert = NULL;
        MFace *mface;
        VlakRen *vlr; //, *vlr1;
@@ -1801,7 +1802,7 @@ static void init_render_mesh(Render *re, Object *ob, Object *par, int only_verts
        int end, do_autosmooth=0, totvert = 0, dm_needsfree;
        int useFluidmeshNormals= 0; // NT fluidsim, use smoothed normals?
        int use_original_normals= 0;
-       
+
        me= ob->data;
 
        paf = give_parteff(ob);
@@ -1853,9 +1854,49 @@ static void init_render_mesh(Render *re, Object *ob, Object *par, int only_verts
        
        if(!only_verts)
                if(need_orco) orco = get_object_orco(re, ob);
-       
+
+       /* If multires is enabled, a copy is made of the mesh
+          to allow multires to be applied with modifiers. */
+       if(me->mr) {
+               me_store= me;
+
+               {
+                       Mesh *men= MEM_callocN(sizeof(Mesh),"mrm render mesh");
+                       men->totvert= me->totvert;
+                       men->totedge= me->totedge;
+                       men->totface= me->totface;
+                       men->mvert= MEM_dupallocN(me->mvert);
+                       men->medge= MEM_dupallocN(me->medge);
+                       men->mface= MEM_dupallocN(me->mface);
+                       if(me->mr) {
+                               MultiresLevel *lvl, *nlvl;
+                               men->mr= MEM_dupallocN(me->mr);
+                               men->mr->levels.first= men->mr->levels.last= NULL;
+                               for(lvl= me->mr->levels.first; lvl; lvl= lvl->next) {
+                                       nlvl= MEM_dupallocN(lvl);
+                                       BLI_addtail(&men->mr->levels,nlvl);
+                                       nlvl->verts= MEM_dupallocN(lvl->verts);
+                                       nlvl->faces= MEM_dupallocN(lvl->faces);
+                                       nlvl->edges= MEM_dupallocN(lvl->edges);
+                                       multires_calc_level_maps(nlvl);
+                               }
+                       }
+
+                       me= men;
+
+               }
+               ob->data= me;
+       }
+
        dm = mesh_create_derived_render(ob);
        dm_needsfree= 1;
+
+       /* (Multires) Now switch the meshes back around */
+       if(me->mr) {
+               ob->data= me_store;
+               me_store= me;
+               me= ob->data;
+       }
        
        if(dm==NULL) return;    /* in case duplicated object fails? */
 
@@ -1864,7 +1905,7 @@ static void init_render_mesh(Render *re, Object *ob, Object *par, int only_verts
           (ob->fluidsimSettings->meshSurface) ) {
                useFluidmeshNormals = 1;
        }
-       
+
        dlm = dm->convertToDispListMesh(dm, 1);
 
        mvert= dlm->mvert;
@@ -2111,9 +2152,13 @@ static void init_render_mesh(Render *re, Object *ob, Object *par, int only_verts
                if(need_stress)
                        calc_edge_stress(re, me, totverto, totvlako);
        }
-       
+
        if(dlm) displistmesh_free(dlm);
        if(dm_needsfree) dm->release(dm);
+       if(me_store) {
+               free_mesh(me_store);
+               MEM_freeN(me_store);
+       }
 }
 
 /* ------------------------------------------------------------------------- */
index e46bb72f154267b4a9b280729e588420d93b249f..cac9d93d57fea795e2a0d08e2ac597a13e6ce45e 100644 (file)
 #include "BIF_poseobject.h"
 #include "BIF_renderwin.h"
 #include "BIF_resources.h"
+#include "BIF_retopo.h"
 #include "BIF_screen.h"
 #include "BIF_scrarea.h"
 #include "BIF_space.h"
 #include "BDR_editcurve.h"
 #include "BDR_editface.h"
 #include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
 #include "BDR_vpaint.h"
 #include "BDR_unwrapper.h"
 
 #include "RE_render_ext.h"             // make_sticky
 
 #include "butspace.h" // own module
+#include "multires.h"
 
 static float editbutweight=1.0;
 float editbutvweight=1;
@@ -669,6 +672,7 @@ void do_common_editbuts(unsigned short event) // old name, is a mix of object an
 static void editing_panel_mesh_type(Object *ob, Mesh *me)
 {
        uiBlock *block;
+       uiBut *but;
        float val;
 
        block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_type", UI_EMBOSS, UI_HELV, curarea->win);
@@ -678,9 +682,33 @@ static void editing_panel_mesh_type(Object *ob, Mesh *me)
        uiDefButBitS(block, TOG, ME_AUTOSMOOTH, REDRAWVIEW3D, "Auto Smooth",10,180,154,19, &me->flag, 0, 0, 0, 0, "Treats all set-smoothed faces with angles less than Degr: as 'smooth' during render");
        uiDefButS(block, NUM, B_DIFF, "Degr:",                          10,160,154,19, &me->smoothresh, 1, 80, 0, 0, "Defines maximum angle between face normals that 'Auto Smooth' will operate on");
 
+       /* Retopo */
+       if(G.obedit) {
+               uiBlockBeginAlign(block);
+               but= uiDefButBitC(block,TOG,1,B_NOP, "Retopo", 10,130,154,19, &G.editMesh->retopo_mode, 0,0,0,0, "Turn on the re-topology tool");
+               uiButSetFunc(but,retopo_toggle,ob,me);
+               if(G.editMesh->retopo_mode) {
+                       but= uiDefButBitC(block,TOG,2,B_NOP,"Paint", 10,110,50,19, &G.editMesh->retopo_mode,0,0,0,0, "");
+                       uiButSetFunc(but,retopo_paint_toggle,ob,me);
+                       but= uiDefBut(block,BUT,B_NOP,"Retopo All", 60,110,104,19, 0,0,0,0,0, "Apply the re-topology tool to all selected vertices");
+                       uiButSetFunc(but,retopo_do_all,ob,me);
+               }
+       }
+
        uiBlockBeginAlign(block);
        uiBlockSetCol(block, TH_AUTO);
 
+       val= me->mr ? 1.0 : 0.0;
+       uiDefBut(block, LABEL, 0, "Multires",10,70,70,20,0,val,0,0,0,"");
+       if(me->mr) {
+               but= uiDefBut(block,BUT,B_NOP,"Delete", 80,70,84,19,0,0,0,0,0,"");
+               uiButSetFunc(but,multires_delete,ob,me);
+       }
+       else {
+               but= uiDefBut(block,BUT,B_NOP,"Make", 80,70,84,19,0,0,0,0,0,"");
+               uiButSetFunc(but,multires_make,ob,me);
+       }
+
        if(me->mcol) val= 1.0; else val= 0.0;
        uiDefBut(block, LABEL, 0, "VertCol",                            10,50,70,20, 0, val, 0, 0, 0, "");
        if(me->mcol==NULL) {
@@ -1111,6 +1139,9 @@ static void modifiers_applyModifier(void *obv, void *mdv)
 
                BIF_undo_push("Apply modifier");
        }
+
+       if (G.f & G_SCULPTMODE)
+               set_sculpt_object(OBACT);
 }
 
 static void modifiers_copyModifier(void *ob_v, void *md_v)
@@ -2525,6 +2556,17 @@ static void editing_panel_curve_tools1(Object *ob, Curve *cu)
        uiBlockEndAlign(block);
 
        uiDefButF(block, NUM,   REDRAWVIEW3D, "NSize:", 400, 40, 150, 19, &G.scene->editbutsize, 0.001, 1.0, 10, 0, "Normal size for drawing");
+
+       if(G.obedit) {
+               uiBut *but;
+               uiBlockBeginAlign(block);
+               but= uiDefButBitS(block,TOG,CU_RETOPO,B_NOP, "Retopo", 560,180,100,19, &cu->flag, 0,0,0,0, "Turn on the re-topology tool");
+               uiButSetFunc(but,retopo_toggle,0,0);
+               if(cu->flag & CU_RETOPO) {
+                       but= uiDefBut(block,BUT,B_NOP,"Retopo All", 560,160,100,19, 0,0,0,0,0, "Apply the re-topology tool to all selected vertices");
+                       uiButSetFunc(but,retopo_do_all,0,0);
+               }
+       }
 }
 
 /* only for bevel or taper */
@@ -3921,13 +3963,168 @@ static void editing_panel_links(Object *ob)
        uiDefBut(block, BUT,B_MATASS,   "Assign",       292,47,162,26, 0, 0, 0, 0, 0, "In EditMode, assigns the active index to selected faces");
 
        uiBlockBeginAlign(block);
-       uiDefBut(block, BUT,B_SETSMOOTH,"Set Smooth",   291,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'smooth' rendering of selected faces");
-       uiDefBut(block, BUT,B_SETSOLID, "Set Solid",    373,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'solid' rendering of selected faces");
+       if(!(G.f & G_SCULPTMODE) || ((G.f & G_SCULPTMODE) && G.obedit))
+       {
+               
+               uiDefBut(block, BUT,B_SETSMOOTH,"Set Smooth",   291,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'smooth' rendering of selected faces");
+               uiDefBut(block, BUT,B_SETSOLID, "Set Solid",    373,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'solid' rendering of selected faces");
+               
+       }
        uiBlockEndAlign(block);
 
 
 }
 
+void editing_panel_sculpting_tools()
+{
+       uiBlock *block= uiNewBlock(&curarea->uiblocks, "editing_panel_sculpting_tools", UI_EMBOSS, UI_HELV, curarea->win);
+       if(uiNewPanel(curarea, block, "Sculpting Tools", "Editing", 300, 0, 318, 204)==0) return;
+
+       sculptmode_draw_interface_tools(block,0,200);
+}
+
+void editing_panel_sculpting_textures()
+{
+       uiBlock *block= uiNewBlock(&curarea->uiblocks, "editing_panel_sculpting_textures", UI_EMBOSS, UI_HELV, curarea->win);
+       if(uiNewPanel(curarea, block, "Brush Textures", "Editing", 300, 0, 318, 204)==0) return;
+
+       sculptmode_draw_interface_textures(block,0,200);
+}
+
+void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned short cy)
+{
+       SculptData *sd;
+       uiBut *but;
+
+       if(!G.scene) return;
+       sd= &G.scene->sculptdata;
+
+       uiBlockBeginAlign(block);
+
+       uiDefBut(block,LABEL,B_NOP,"Brush",cx,cy,90,19,NULL,0,0,0,0,"");
+       cy-= 20;
+       uiBlockBeginAlign(block);
+       uiDefButS(block,ROW,REDRAWBUTSEDIT,"Draw",cx,cy,67,19,&sd->brush_type,14.0,DRAW_BRUSH,0,0,"Draw lines on the model");
+       uiDefButS(block,ROW,REDRAWBUTSEDIT,"Smooth",cx+67,cy,67,19,&sd->brush_type,14.0,SMOOTH_BRUSH,0,0,"Interactively smooth areas of the model");
+       uiDefButS(block,ROW,REDRAWBUTSEDIT,"Pinch",cx+134,cy,66,19,&sd->brush_type,14.0,PINCH_BRUSH,0,0,"Interactively pinch areas of the model");
+       cy-= 20;
+       uiDefButS(block,ROW,REDRAWBUTSEDIT,"Inflate",cx,cy,67,19,&sd->brush_type,14,INFLATE_BRUSH,0,0,"Push vertices along the direction of their normals");
+       uiDefButS(block,ROW,REDRAWBUTSEDIT,"Grab", cx+67,cy,67,19,&sd->brush_type,14,GRAB_BRUSH,0,0,"Grabs a group of vertices and moves them with the mouse");
+       uiDefButS(block,ROW,REDRAWBUTSEDIT,"Layer", cx+134,cy,66,19,&sd->brush_type,14, LAYER_BRUSH,0,0,"Adds a layer of depth");
+       cy-= 25;
+
+       uiBlockBeginAlign(block);
+       uiDefBut(block,LABEL,B_NOP,"Shape",cx,cy,90,19,NULL,0,0,0,0,"");
+       cy-= 20;
+       uiBlockBeginAlign(block);
+       if(sd->brush_type!=SMOOTH_BRUSH && sd->brush_type!=GRAB_BRUSH) {
+               uiDefButC(block,ROW,B_NOP,"Add",cx,cy,67,19,&sculptmode_brush()->dir,15.0,1.0,0, 0,"Add depth to model [Shift]");
+               uiDefButC(block,ROW,B_NOP,"Sub",cx+67,cy,67,19,&sculptmode_brush()->dir,15.0,2.0,0, 0,"Subtract depth from model [Shift]");
+       }
+       if(sd->brush_type!=GRAB_BRUSH)
+               uiDefButC(block,TOG,B_NOP,"Airbrush",cx+134,cy,66,19,&sculptmode_brush()->airbrush,0,0,0,0,"Brush makes changes without waiting for the mouse to move");
+       cy-= 20;
+       but= uiDefButS(block,NUMSLI,B_NOP,"Size: ",cx,cy,200,19,&sculptmode_brush()->size,1.0,200.0,0,0,"Set brush radius in pixels");
+       cy-= 20;
+       uiDefButC(block,NUMSLI,B_NOP,"Strength: ",cx,cy,200,19,&sculptmode_brush()->strength,1.0,100.0,0,0,"Set brush strength");
+       cy-= 25;
+
+       uiBlockBeginAlign(block);
+       uiDefBut( block,LABEL,B_NOP,"Symmetry",cx,cy,90,19,NULL,0,0,0,0,"");
+       cy-= 20;
+       uiBlockBeginAlign(block);
+       uiDefButS(block,TOG,B_NOP,"X",cx,cy,67,19,&sd->symm_x,0,0,0,0,"Mirror brush across X axis");
+       uiDefButS(block,TOG,B_NOP,"Y",cx+67,cy,67,19,&sd->symm_y,0,0,0,0,"Mirror brush across Y axis");
+       uiDefButS(block,TOG,B_NOP,"Z",cx+134,cy,66,19,&sd->symm_z,0,0,0,0,"Mirror brush across Z axis");
+       
+       uiBlockEndAlign(block);
+
+       cx+= 210;
+}
+
+void sculptmode_draw_interface_textures(uiBlock *block, unsigned short cx, unsigned short cy)
+{
+       SculptData *sd= &G.scene->sculptdata;
+       MTex *mtex;
+       int i;
+       int orig_y= cy;
+       char *strp;
+       uiBut *but;
+
+       uiBlockBeginAlign(block);
+       uiDefBut(block,LABEL,B_NOP,"Texture",cx,cy,200,20,0,0,0,0,0,"");
+       cy-= 20;
+
+       /* TEX CHANNELS */
+       uiBlockSetCol(block, TH_BUT_NEUTRAL);
+       for(i=-1; i<8; i++) {
+               char str[64];
+               int loos;
+               mtex= sd->mtex[i];
+
+               if(i==-1)
+                       strcpy(str, "Default");
+               else {
+                       if(mtex && mtex->tex) splitIDname(mtex->tex->id.name+2, str, &loos);
+                       else strcpy(str, "");
+               }
+               str[10]= 0;
+               uiDefButS(block, ROW, REDRAWBUTSEDIT, str,cx, cy, 80, 20, &sd->texact, 3.0, (float)i, 0, 0, "Texture channel");
+               cy-= 18;
+       }
+
+       cy= orig_y-20;
+       cx+= 85;
+       mtex= sd->mtex[sd->texact];
+
+       if(sd->texact != -1) {
+               ID *id= NULL;
+               uiBlockBeginAlign(block);
+               
+               if(mtex && mtex->tex) id= &mtex->tex->id;
+               IDnames_to_pupstring(&strp, NULL, "ADD NEW %x 32767", &G.main->tex, id, &G.buts->texnr);
+
+               if(mtex && mtex->tex) {         
+                       uiDefBut(block, TEX, B_IDNAME, "TE:",cx,cy,115,19, mtex->tex->id.name+2, 0.0, 18.0, 0, 0, "Texture name");
+                       cy-= 20;
+                       
+                       uiDefButS(block,MENU,B_SCULPT_TEXBROWSE, strp, cx,cy,20,19, &G.buts->texnr, 0,0,0,0, "Selects an existing texture or creates new");
+                       uiDefIconBut(block, BUT, B_AUTOTEXNAME, ICON_AUTO, cx+21,cy,21,20, 0, 0, 0, 0, 0, "Auto-assigns name to texture");
+
+                       but= uiDefBut(block, BUT, B_NOP, "Clear",cx+43, cy, 72, 20, 0, 0, 0, 0, 0, "Erases link to texture");
+                       uiButSetFunc(but,sculptmode_rem_tex,0,0);
+                       cy-= 20;
+
+                       uiDefButC(block,ROW,B_NOP, "Drag", cx,   cy,39,19, &sd->texrept, 18,SCULPTREPT_DRAG,0,0,"Move the texture with the brush");
+                       uiDefButC(block,ROW,B_NOP, "Tile", cx+39,cy,39,19, &sd->texrept, 18,SCULPTREPT_TILE,0,0,"Treat the texture as a tiled image extending across the screen");
+                       uiDefButC(block,ROW,B_NOP, "3D",   cx+78,cy,37,19, &sd->texrept, 18,SCULPTREPT_3D,  0,0,"Use vertex coords as texture coordinates");
+                       cy-= 20;
+
+                       uiDefButF(block,NUM,B_NOP, "X",    cx,   cy,39,19, &sd->texsize[0],-20,20,10,0,"Scaling factor for texture's X axis");
+                       uiDefButF(block,NUM,B_NOP, "Y",    cx+39,cy,38,19, &sd->texsize[1],-20,20,10,0,"Scaling factor for texture's Y axis");
+                       uiDefButF(block,NUM,B_NOP, "Z",    cx+78,cy,38,19, &sd->texsize[2],-20,20,10,0,"Scaling factor for texture's Z axis");
+                       cy-= 20;
+                       
+                       uiDefButC(block,TOG,B_NOP, "Fade", cx,cy,50,19, &sd->texfade, 0,0,0,0,"Smooth the edges of the texture");
+                       uiDefButS(block,NUM,B_NOP, "Space", cx+50,cy,65,19, &sd->spacing, 0,500,20,0,"Non-zero inserts N pixels between dots");
+                       
+                       cy+= 40;
+               }
+               else {
+                      uiDefButS(block,TOG,B_SCULPT_TEXBROWSE, "Add New" ,cx, cy, 115, 19, &G.buts->texnr,-1,32767,0,0, "Adds a new texture");
+                      uiDefButS(block,MENU,B_SCULPT_TEXBROWSE, strp, cx,cy-20,20,19, &G.buts->texnr, 0,0,0,0, "Selects an existing texture or creates new");
+               }
+
+               MEM_freeN(strp);
+       }
+       else {
+               uiBlockBeginAlign(block);
+               uiDefButS(block,NUM,B_NOP, "Space", cx+50,cy,65,19, &sd->spacing, 0,500,20,0,"Non-zero inserts N pixels between dots");
+       }
+       
+       uiBlockEndAlign(block);
+}
+
 /* *************************** FACE/PAINT *************************** */
 
 void do_fpaintbuts(unsigned short event)
@@ -3937,8 +4134,12 @@ void do_fpaintbuts(unsigned short event)
        bDeformGroup *defGroup;
        TFace *activetf, *tf;
        int a;
+       SculptData *sd= &G.scene->sculptdata;
+       ID *id, *idtest;
        extern VPaint Gwp;         /* from vpaint */
        ToolSettings *settings= G.scene->toolsettings;
+       int nr= 1;
+       MTex *mtex;
 
        ob= OBACT;
        if(ob==NULL) return;
@@ -4073,6 +4274,68 @@ void do_fpaintbuts(unsigned short event)
                        allqueue(REDRAWVIEW3D, 0);
                        DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
                }
+               break;
+       case B_SCULPT_TEXBROWSE:
+               sd= &G.scene->sculptdata;
+
+               if(G.buts->texnr== -2) {
+                       id= NULL;
+                       if(sd) {
+                               mtex= sd->mtex[sd->texact];
+                               if(mtex) id= &mtex->tex->id;
+                       }
+
+                       activate_databrowse((ID *)id, ID_TE, 0, B_SCULPT_TEXBROWSE, &G.buts->texnr, do_global_buttons);
+                       return;
+               }
+               if(G.buts->texnr < 0) break;
+
+               if(G.buts->pin) {
+                       
+               }
+               else if(sd && sd->texact == -1) {
+                       error("No texture channel selected");
+                       allqueue(REDRAWBUTSSHADING, 0);
+               }
+               else if(sd && sd->texact != -1) {
+                       id= NULL;
+                       
+                       mtex= sd->mtex[sd->texact];
+                       if(mtex) id= &mtex->tex->id;
+
+                       idtest= G.main->tex.first;
+                       while(idtest) {
+                               if(nr==G.buts->texnr) {
+                                       break;
+                               }
+                               nr++;
+                               idtest= idtest->next;
+                       }
+                       if(idtest==0) { /* new tex */
+                               if(id)  idtest= (ID *)copy_texture((Tex *)id);
+                               else idtest= (ID *)add_texture("Tex");
+                               idtest->us--;
+                       }
+                       if(idtest!=id && sd) {
+                               
+                               if(sd->mtex[sd->texact]==0) {
+                                       sd->mtex[sd->texact]= add_mtex();
+                                       sd->mtex[sd->texact]->texco= TEXCO_VIEW;
+                               }
+                               sd->mtex[sd->texact]->tex= (Tex *)idtest;
+                               id_us_plus(idtest);
+                               if(id) id->us--;
+                               
+                               BIF_undo_push("Texture browse");
+                               allqueue(REDRAWBUTSEDIT, 0);
+                               allqueue(REDRAWBUTSSHADING, 0);
+                               allqueue(REDRAWIPO, 0);
+                               allqueue(REDRAWOOPS, 0);
+                               BIF_preview_changed(ID_TE);
+                       }
+               }
+               break;
+
        case B_BRUSHBROWSE:
                if(G.buts->menunr==-2) {
                        activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_BRUSHBROWSE, &G.buts->menunr, do_global_buttons);
@@ -4413,6 +4676,64 @@ static void editing_panel_mesh_uvautocalculation(void)
        uiBlockEndAlign(block);
 }
 
+void editing_panel_mesh_multires()
+{
+       uiBlock *block;
+       Object *ob= OBACT;
+       Mesh *me= get_mesh(ob);
+
+       if(!me->mr) return;
+
+       block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_multires", UI_EMBOSS, UI_HELV, curarea->win);
+       if(uiNewPanel(curarea, block, "Multires", "Editing", 500, 0, 220, 204)==0) return;
+
+       multires_draw_interface(block,100,0);
+}
+
+void multires_draw_interface(uiBlock *block, unsigned short cx, unsigned short cy)
+{
+       uiBut *but;
+       Object *ob= OBACT;
+       Mesh *me= get_mesh(ob);
+
+       uiBlockBeginAlign(block);
+       but= uiDefBut(block,BUT,B_NOP,"Add Level", cx,cy,200,19,0,0,0,0,0,"Add a new level of subdivision at the end of the chain");
+       uiButSetFunc(but,multires_add_level,ob,me);
+       cy-= 20;
+
+       if(me->mr->level_count>1) {
+               but= uiDefButC(block,NUM,B_NOP,"Level: ",cx,cy,200,19,&me->mr->newlvl,1.0,me->mr->level_count,0,0,"");
+               uiButSetFunc(but,multires_set_level,ob,me);
+               cy-= 20;
+
+               but= uiDefBut(block,BUT,B_NOP,"Del Lower", cx,cy,100,19,0,0,0,0,0,"Remove all levels of subdivision below the current one");
+               uiButSetFunc(but,multires_del_lower,ob,me);
+               but= uiDefBut(block,BUT,B_NOP,"Del Higher", cx+100,cy,100,19,0,0,0,0,0,"Remove all levels of subdivision above the current one");
+               uiButSetFunc(but,multires_del_higher,ob,me);
+               cy-= 20;
+
+               but= uiDefButC(block,NUM,B_NOP,"Edges: ",cx,cy,200,19,&me->mr->edgelvl,1.0,me->mr->level_count,0,0,"Set level of edges to display");
+               uiButSetFunc(but,multires_edge_level_update,ob,me);
+               cy-= 20;
+
+               uiBlockBeginAlign(block);
+               cy-= 5;
+               uiDefBut(block,LABEL,B_NOP,"Rendering",cx,cy,100,19,0,0,0,0,0,"");
+               cy-= 20;
+
+               uiDefButC(block,NUM,B_NOP,"Pin: ",cx,cy,200,19,&me->mr->pinlvl,1.0,me->mr->level_count,0,0,"Set level to apply modifiers to during render");
+               cy-= 20;
+
+               uiDefButC(block,NUM,B_NOP,"Render: ",cx,cy,200,19,&me->mr->renderlvl,1.0,me->mr->level_count,0,0,"Set level to render");
+               cy-= 20;
+
+               //but= uiDefBut(block,BUT,B_NOP,"Displacement Map", cx,cy,200,19,0,0,0,0,0,"");
+               //uiButSetFunc(but,multires_disp_map,me,0);
+       }
+
+       uiBlockEndAlign(block);
+}
+
 /* this is a mode context sensitive system */
 
 void editing_panels()
@@ -4435,11 +4756,17 @@ void editing_panels()
                editing_panel_modifiers(ob);
                editing_panel_shapes(ob);
                /* modes */
+               if(get_mesh(ob)->mr)
+                       editing_panel_mesh_multires();
                if(G.obedit) {
                        editing_panel_mesh_tools(ob, ob->data);
                        editing_panel_mesh_tools1(ob, ob->data);
                }
-               else {
+               else if(G.f & G_SCULPTMODE) {
+                       editing_panel_sculpting_tools();
+                       uiNewPanelTabbed("Sculpting Tools", "Editing");
+                       editing_panel_sculpting_textures();
+               } else {
                        if(G.f & G_FACESELECT) {
                                editing_panel_mesh_texface();
                                editing_panel_mesh_uvautocalculation();
index 20eeb4f7532ca48afb8d0272a7ffcfdcf761877d..fdfa17fc858a2ba82add43a6a8ee96bc765a2e2f 100644 (file)
@@ -1218,7 +1218,7 @@ static void texture_panel_colors(Tex *tex)
 }
 
 
-static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br)
+static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br, SculptData *sd)
 {
        MTex *mt=NULL;
        uiBlock *block;
@@ -1240,6 +1240,7 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
        else if(wrld) idfrom= &wrld->id;
        else if(la) idfrom= &la->id;
        else if(br) idfrom= &br->id;
+       else if(sd) idfrom= NULL; /* Not sure what this does */
        else idfrom= NULL;
        
        uiBlockSetCol(block, TH_BUT_SETTING2);
@@ -1255,6 +1256,9 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
        else if(br) {
                std_libbuttons(block, 10, 180, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->menunr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
        }
+       else if(sd) {
+               std_libbuttons(block, 10, 180, 0, NULL, B_SCULPT_TEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
+       }
        else if(node) {
 
        }
@@ -1272,6 +1276,7 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
                        else if(wrld) mt= wrld->mtex[a];
                        else if(la) mt= la->mtex[a];
                        else if(br) mt= br->mtex[a];
+                       else if(sd) mt= sd->mtex[a];
                        
                        if(mt && mt->tex) splitIDname(mt->tex->id.name+2, str, &loos);
                        else strcpy(str, "");
@@ -1293,6 +1298,10 @@ static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *l
                                uiDefButS(block, ROW, B_TEXCHANNEL, str,        10,yco,140,19, &(br->texact), 0.0, (float)a, 0, 0, "");
                                yco-= 20;
                        }
+                       else if(sd) {
+                               uiDefButS(block, ROW, B_TEXCHANNEL, str,        10,yco,140,19, &(sd->texact), 0.0, (float)a, 0, 0, "");
+                               yco-= 20;
+                       }
                }
                uiBlockEndAlign(block);
        }       
@@ -1335,7 +1344,7 @@ static void texture_panel_preview(MTex *mtex, int preview)
        uiDefButC(block, ROW, B_TEXREDR_PRV, "Mat",             200,175,80,25, &G.buts->texfrom, 3.0, 0.0, 0, 0, "Displays the textures of the active material");
        uiDefButC(block, ROW, B_TEXREDR_PRV, "World",   200,150,80,25, &G.buts->texfrom, 3.0, 1.0, 0, 0, "Displays the textures of the world block");
        uiDefButC(block, ROW, B_TEXREDR_PRV, "Lamp",    200,125,80,25, &G.buts->texfrom, 3.0, 2.0, 0, 0, "Displays the textures of the selected lamp");
-       uiDefButC(block, ROW, B_TEXREDR_PRV, "Brush",   200,100,80,25, &G.buts->texfrom, 3.0, 3.0, 0, 0, "Displays the textures of the selected lamp");
+       uiDefButC(block, ROW, B_TEXREDR_PRV, "Brush",   200,100,80,25, &G.buts->texfrom, 3.0, 3.0, 0, 0, "Displays the textures of the selected brush");
        uiBlockEndAlign(block);
        
        if(mtex && mtex->tex)
@@ -3459,6 +3468,7 @@ void texture_panels()
 {
        Material *ma=NULL;
        Brush *br=NULL;
+       SculptData *sd=NULL;
        Lamp *la=NULL;
        World *wrld=NULL;
        bNode *node=NULL;
@@ -3492,16 +3502,23 @@ void texture_panels()
                }
        }
        else if(G.buts->texfrom==3) {
-               br= G.scene->toolsettings->imapaint.brush;
-               if(br) mtex= br->mtex[br->texact];
+               if(G.f & G_SCULPTMODE) {
+                       sd= &G.scene->sculptdata;
+                       if(sd->texact != -1)
+                               mtex= sd->mtex[sd->texact];
+               }
+               else {
+                       br= G.scene->toolsettings->imapaint.brush;
+                       if(br) mtex= br->mtex[br->texact];
+               }
        }
        
-       texture_panel_preview(mtex, ma || wrld || la || br || node);    // for 'from' buttons
+       texture_panel_preview(mtex, ma || wrld || la || br || node || sd);      // for 'from' buttons
        
-       if(ma || wrld || la || br || node) {
+       if(ma || wrld || la || br || node || sd) {
                Tex *tex= NULL;
                
-               texture_panel_texture(mtex, ma, wrld, la, node, br);
+               texture_panel_texture(mtex, ma, wrld, la, node, br, sd);
                
                if(mtex) tex= mtex->tex;
                else if(node) tex= (Tex *)node->id;
index 12f4b27a38e93d42d3830c8c4da19e727152c37e..69f15f212dd04c63b9dfa24d502e01df0065db04 100644 (file)
 #include "BIF_glutil.h"
 #include "BIF_mywindow.h"
 #include "BIF_resources.h"
+#include "BIF_retopo.h"
 #include "BIF_screen.h"
 #include "BIF_space.h"
 
 #include "BDR_drawmesh.h"
 #include "BDR_drawobject.h"
 #include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
 #include "BDR_vpaint.h"
 
 #include "BSE_drawview.h"
@@ -139,7 +141,7 @@ static void draw_bounding_volume(Object *ob);
 static float matbuf[MAXMATBUF][2][4];
 static int totmat_gl= 0;
 
-static int set_gl_material(int nr)
+int set_gl_material(int nr)
 {
        static int last_gl_matnr= -1;
        static int last_ret_val= 1;
@@ -170,7 +172,7 @@ static int set_gl_material(int nr)
 }
 
 /* returns 1: when there's alpha needed to be drawn in a 2nd pass */
-static int init_gl_materials(Object *ob, int check_alpha)
+int init_gl_materials(Object *ob, int check_alpha)
 {
        extern Material defmaterial;    // render module abuse...
        Material *ma;
@@ -1900,6 +1902,8 @@ static void draw_em_fancy(Object *ob, EditMesh *em, DerivedMesh *cageDM, Derived
        draw_em_fancy_edges(cageDM);
 
        if(ob==G.obedit) {
+               retopo_matrix_update(G.vd);
+
                draw_em_fancy_verts(em, cageDM);
 
                if(G.f & G_DRAWNORMALS) {
@@ -2171,6 +2175,9 @@ static int draw_mesh_object(Base *base, int dt, int flag)
                if (cageNeedsFree) cageDM->release(cageDM);
                if (finalNeedsFree) finalDM->release(finalDM);
        }
+       else if(!G.obedit && G.scene->sculptdata.active_ob == ob) {
+               sculptmode_draw_mesh(NULL);
+       }
        else {
                /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */
                
@@ -3069,6 +3076,8 @@ static void drawnurb(Base *base, Nurb *nurb, int dt)
        Nurb *nu;
        BevList *bl;
 
+       retopo_matrix_update(G.vd);
+
        /* DispList */
        BIF_ThemeColor(TH_WIRE);
        drawDispList(base, dt);
@@ -3956,6 +3965,7 @@ void draw_object(Base *base, int flag)
                        }
                }
        }
+       
        /* draw-extra supported for boundbox drawmode too */
        if(dt>=OB_BOUNDBOX ) {
 
index 3ee670c646cf5a08baba418018b8028e656132c6..e21b867f69743e45e84b9d7d77f7f08a119af727 100644 (file)
 #include "BIF_poseobject.h"
 #include "BIF_previewrender.h"
 #include "BIF_resources.h"
+#include "BIF_retopo.h"
 #include "BIF_screen.h"
 #include "BIF_space.h"
 
 #include "BDR_drawobject.h"
 #include "BDR_editobject.h"
 #include "BDR_vpaint.h"
+#include "BDR_sculptmode.h"
 
 #include "BSE_drawview.h"
 #include "BSE_filesel.h"
 
 #include "RE_pipeline.h"       // make_stars
 
+#include "multires.h"
+
 /* Modules used */
 #include "radio.h"
 
@@ -1192,6 +1196,9 @@ ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax)
                dr++;
        }
        
+       ibuf->ftype= PNG;
+       IMB_saveiff(ibuf, "/tmp/rt.png", IB_rect);
+       
        /* put clipped result back, if needed */
        if(xminc==xmin && xmaxc==xmax && yminc==ymin && ymaxc==ymax) 
                return ibuf;
@@ -2217,8 +2224,12 @@ static void view3d_panel_object(short cntrl)     // VIEW3D_HANDLER_OBJECT
 /* (ton) can't use the rename trick for paint... panel names and settings are stored in the files and
    used to find previous locations when re-open. This causes flipping */
 
-       if(uiNewPanel(curarea, block, "Transform Properties", "View3d", 10, 230, 318, 204)==0) return;
-       
+       if((G.f & G_SCULPTMODE) && !G.obedit) {
+               if(!uiNewPanel(curarea, block, "Transform Properties", "View3d", 10, 230, 425, 234)) return;
+       } else {
+               if(!uiNewPanel(curarea, block, "Transform Properties", "View3d", 10, 230, 318, 204)) return;
+       }
+
        if(ob->id.lib) uiSetButLock(1, "Can't edit library data");
        
        if(G.f & (G_VERTEXPAINT|G_FACESELECT|G_TEXTUREPAINT|G_WEIGHTPAINT)) {
@@ -2260,7 +2271,10 @@ static void view3d_panel_object(short cntrl)     // VIEW3D_HANDLER_OBJECT
                        /* 'f' is for floating panel */
                        uiBlockPickerButtons(block, rgb, hsv, old, hexcol, 'f', REDRAWBUTSEDIT);
        }
-       else {
+       else if(G.f & G_SCULPTMODE) {
+               sculptmode_draw_interface_tools(block,10,150);
+               sculptmode_draw_interface_textures(block,220,150);
+       } else {
                BoundBox *bb = NULL;
 
                uiBlockBeginAlign(block);
@@ -2319,6 +2333,32 @@ static void view3d_panel_object(short cntrl)     // VIEW3D_HANDLER_OBJECT
        uiClearButLock();
 }
 
+static void view3d_panel_multires(short cntrl)         // VIEW3D_HANDLER_MULTIRES
+{
+       uiBlock *block;
+       uiBut *but;
+       Object *ob= OBACT;
+       
+       if(!ob || ob->type!=OB_MESH) return;
+
+       block= uiNewBlock(&curarea->uiblocks, "view3d_panel_multires", UI_EMBOSS, UI_HELV, curarea->win);
+       uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+       uiSetPanelHandler(VIEW3D_HANDLER_MULTIRES);  // for close and esc
+
+       if(!uiNewPanel(curarea, block, "Multires Properties", "View3d", 10, 230, 220, 200)) return;
+
+       if(ob->id.lib) uiSetButLock(1, "Can't edit library data");
+       
+       if(get_mesh(ob)->mr)
+               multires_draw_interface(block, 5,100);
+       else {
+               but= uiDefBut(block,BUT,B_NOP,"Make Multires", 5,100,120,19,0,0,0,0,0,"Adds multires data to mesh");
+               uiButSetFunc(but,multires_make,ob,get_mesh(ob));
+       }
+
+       uiClearButLock();
+}
+
 static void view3d_panel_background(short cntrl)       // VIEW3D_HANDLER_BACKGROUND
 {
        uiBlock *block;
@@ -2516,6 +2556,9 @@ static void view3d_blockhandlers(ScrArea *sa)
                case VIEW3D_HANDLER_PREVIEW:
                        view3d_panel_preview(sa, v3d->blockhandler[a+1]);
                        break;
+               case VIEW3D_HANDLER_MULTIRES:
+                       view3d_panel_multires(v3d->blockhandler[a+1]);
+                       break;
                        
                }
                /* clear action value for event */
@@ -2636,6 +2679,35 @@ static void draw_dupli_objects(View3D *v3d, Base *base)
                                
 }
 
+void view3d_update_depths(View3D *v3d)
+{
+       /* Create storage for, and, if necessary, copy depth buffer */
+       if(!v3d->depths) v3d->depths= MEM_callocN(sizeof(ViewDepths),"ViewDepths");
+       if(v3d->depths) {
+               ViewDepths *d= v3d->depths;
+               if(d->w != v3d->area->winx ||
+                  d->h != v3d->area->winy) {
+                       d->w= v3d->area->winx;
+                       d->h= v3d->area->winy;
+                       if(d->depths)
+                               MEM_freeN(d->depths);
+                       d->depths= MEM_mallocN(sizeof(float)*d->w*d->h,"View depths");
+                       d->damaged= 1;
+               }
+               
+               if(d->damaged) {
+                       glReadBuffer(GL_FRONT);
+                       glReadPixels(v3d->area->winrct.xmin,v3d->area->winrct.ymin,d->w,d->h,
+                                    GL_DEPTH_COMPONENT,GL_FLOAT, d->depths);
+                       glReadBuffer(GL_BACK);
+                       
+                       glGetDoublev(GL_DEPTH_RANGE,d->depth_range);
+                       
+                       d->damaged= 0;
+               }
+       }
+}
+
 void drawview3dspace(ScrArea *sa, void *spacedata)
 {
        View3D *v3d= spacedata;
@@ -2764,6 +2836,10 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
                        }
                }
        }
+
+       if(retopo_mesh_check() || retopo_curve_check())
+               view3d_update_depths(v3d);
+
        /* draw selected and editmode */
        for(base= G.scene->base.first; base; base= base->next) {
                if(v3d->lay & base->lay) {
@@ -2772,6 +2848,9 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
                }
        }
 
+       if(!(retopo_mesh_check() || retopo_curve_check()) && (G.f & G_SCULPTMODE))
+               view3d_update_depths(v3d);
+
        if(G.moving) {
                BIF_drawConstraint();
                if(G.obedit) BIF_drawPropCircle();      // only editmode has proportional edit
@@ -2794,7 +2873,47 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
        }
 
        persp(PERSP_WIN);  // set ortho
-       
+
+       /* Draw Sculpt Mode brush */
+       if(!G.obedit && (G.f & G_SCULPTMODE)) {
+               PropsetData *pd = G.scene->sculptdata.propset_data;
+               const short r= sculptmode_brush()->size;
+               if(pd) {
+                       /* Draw brush with texture */
+                       glEnable(GL_BLEND);
+                       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+                       glBindTexture(GL_TEXTURE_2D, pd->tex);
+
+                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+                       glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+                       glEnable(GL_TEXTURE_2D);
+                       glBegin(GL_QUADS);
+                       glColor4f(0,0,0,1);
+                       glTexCoord2f(0,0);
+                       glVertex2f(pd->origloc[0]-r, pd->origloc[1]-r);
+                       glTexCoord2f(1,0);
+                       glVertex2f(pd->origloc[0]+r, pd->origloc[1]-r);
+                       glTexCoord2f(1,1);
+                       glVertex2f(pd->origloc[0]+r, pd->origloc[1]+r);
+                       glTexCoord2f(0,1);
+                       glVertex2f(pd->origloc[0]-r, pd->origloc[1]+r);
+                       glEnd();
+                       glDisable(GL_TEXTURE_2D);
+
+                       if(pd->origsize != r)
+                               fdrawXORcirc(pd->origloc[0], pd->origloc[1], pd->origsize);
+                       fdrawXORcirc(pd->origloc[0], pd->origloc[1], r);
+               } else {
+                       short c[2];
+                       getmouseco_areawin(c);
+                       fdrawXORcirc((float)c[0], (float)c[1], r);
+               }
+       }
+       retopo_draw_paint_lines();
+
        if(v3d->persp>1) drawviewborder();
        if(v3d->flag2 & V3D_FLYMODE) drawviewborder_flymode();
        if(!(G.f & G_PLAYANIM)) drawcursor(v3d);
@@ -2841,7 +2960,6 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
                        !during_script()) {
                BPY_do_pyscript((ID *)G.scene, SCRIPT_REDRAW);
        }
-
 }
 
 
index 54645bce9c9aa66df80b6caf270b7d68a93922df..902a435e3b4fa5496cc852e202e19bc2db76efc1 100644 (file)
@@ -81,6 +81,7 @@
 #include "BIF_mywindow.h"
 #include "BIF_interface.h"
 #include "BIF_transform.h"
+#include "BIF_retopo.h"
 
 #include "BSE_view.h"  /* For persp... */
 #include "BSE_edit.h"
@@ -2710,6 +2711,8 @@ void addvert_Nurb(int mode)
                }
        }
 
+       retopo_do_all(0,0);
+
        test2DNurb(nu);
        DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
        countall();
index 7d2837df2416af45f4e9337ccd96fca683054e43..a45f413928e3d00d90c0f852047f2b6f97f2e44a 100644 (file)
@@ -84,6 +84,7 @@
 #include "BIF_interface.h"
 #include "BIF_meshtools.h"
 #include "BIF_mywindow.h"
+#include "BIF_retopo.h"
 #include "BIF_space.h"
 #include "BIF_screen.h"
 #include "BIF_toolbox.h"
@@ -605,6 +606,8 @@ void free_editMesh(EditMesh *em)
        mesh_octree_table(NULL, NULL, 'e');
        
        G.totvert= G.totface= 0;
+
+       if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data);
 }
 
 /* on G.editMesh */
@@ -1806,6 +1809,8 @@ typedef struct UndoMesh {
        TFace *tfaces;
        int totvert, totedge, totface,totsel;
        short selectmode;
+       RetopoPaintData *retopo_paint_data;
+       char retopo_mode;
 } UndoMesh;
 
 
@@ -1826,6 +1831,7 @@ static void free_undoMesh(void *umv)
        if(um->faces) MEM_freeN(um->faces);
        if(um->tfaces) MEM_freeN(um->tfaces);
        if(um->selected) MEM_freeN(um->selected);
+       if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
        MEM_freeN(um);
 }
 
@@ -1922,6 +1928,9 @@ static void *editMesh_to_undoMesh(void)
                else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l; 
                else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l;
        }
+
+       um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
+       um->retopo_mode= em->retopo_mode;
        
        return um;
 }
@@ -2028,6 +2037,9 @@ static void undoMesh_to_editMesh(void *umv)
                EM_free_index_arrays();
        }
 
+       retopo_free_paint();
+       em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
+       em->retopo_mode= um->retopo_mode;
 }
 
 
index 18f8fbd20dc3755280442ce8420252f6011f1b3a..c58a49212ba603440f218716a2a13d5ebfb587d5 100644 (file)
@@ -590,6 +590,53 @@ static void fix_new_face(EditFace *eface)
        }
 }
 
+void addfaces_from_edgenet()
+{
+       EditVert *eve1, *eve2, *eve3, *eve4;
+       EditMesh *em= G.editMesh;
+       
+       for(eve1= em->verts.first; eve1; eve1= eve1->next) {
+               for(eve2= em->verts.first; (eve1->f & 1) && eve2; eve2= eve2->next) {
+                       if(findedgelist(eve1,eve2)) {
+                               for(eve3= em->verts.first; eve3; eve3= eve3->next) {
+                                       if((eve2!=eve3 && findedgelist(eve1,eve3))) {
+                                               EditEdge *sh_edge= NULL;
+                                               EditVert *sh_vert= NULL;
+                                               
+                                               sh_edge= findedgelist(eve2,eve3);
+                                               
+                                               if(sh_edge) { /* Add a triangle */
+                                                       if(!exist_face_overlaps(eve1,eve2,eve3,NULL))
+                                                               fix_new_face(addfacelist(eve1,eve2,eve3,NULL,NULL,NULL));
+                                               }
+                                               else { /* Check for a shared vertex */
+                                                       for(eve4= em->verts.first; eve4; eve4= eve4->next) {
+                                                               if(eve4!=eve1 && eve4!=eve2 && eve4!=eve3 &&
+                                                                  !findedgelist(eve1,eve4) && findedgelist(eve2,eve4) &&
+                                                                  findedgelist(eve3,eve4)) {
+                                                                       sh_vert= eve4;
+                                                                       break;
+                                                               }
+                                                       }
+                                                       
+                                                       if(sh_vert) {
+                                                               if(sh_vert) {
+                                                                       if(!exist_face_overlaps(eve1,eve2,eve4,eve3))
+                                                                               fix_new_face(addfacelist(eve1,eve2,eve4,eve3,NULL,NULL));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       countall();
+
+       EM_select_flush();
+}
+
 void addedgeface_mesh(void)
 {
        EditMesh *em = G.editMesh;
index e264f18ff24fbfbfc1728699d3aeb26f3311f665..5c7c151192d38ce41e6dd03e2219c8cf731bac06 100644 (file)
 #include "BIF_meshtools.h"
 #include "BIF_mywindow.h"
 #include "BIF_resources.h"
+#include "BIF_retopo.h"
 #include "BIF_screen.h"
 #include "BIF_space.h"
 #include "BIF_toolbox.h"
 #include "BSE_editipo_types.h"
 
 #include "BDR_vpaint.h"
+#include "BDR_sculptmode.h"
 #include "BDR_editface.h"
 #include "BDR_editmball.h"
 #include "BDR_editobject.h"
@@ -262,6 +264,8 @@ void delete_obj(int ok)
        
        if(G.obedit) return;
        if(G.scene->id.lib) return;
+
+       if(G.f & G_SCULPTMODE) set_sculptmode();
        
        base= FIRSTBASE;
        while(base) {
@@ -1507,12 +1511,15 @@ void enter_editmode(int wc)
        if(wc) waitcursor(1);
        
        if(ob->type==OB_MESH) {
+               if(G.f & G_SCULPTMODE) set_sculpt_object(NULL);
+
                me= get_mesh(ob);
                if( me==0 ) return;
                if(me->id.lib) {
                        error("Can't edit library data");
                        return;
                }
+               if(me->pv) sculptmode_pmv_off(me);
                ok= 1;
                G.obedit= ob;
                make_editMesh();
@@ -1585,6 +1592,8 @@ void exit_editmode(int flag)      /* freedata==0 at render, 1= freedata, 2= do undo b
                /* temporal */
                countall();
 
+               retopo_end_okee();
+
                if(G.totvert>MESH_MAX_VERTS) {
                        error("Too many vertices");
                        return;
@@ -1636,6 +1645,9 @@ void exit_editmode(int flag)      /* freedata==0 at render, 1= freedata, 2= do undo b
        /* also flush ob recalc, doesn't take much overhead, but used for particles */
        DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
 
+       if(G.f & G_SCULPTMODE)
+               set_sculpt_object(ob);
+
        if(freedata) {
                setcursor_space(SPACE_VIEW3D, CURSOR_STD);
        }
index 4085cb353f5939fbfbb8d3d7b93f41660c185ba2..2fdc3bc6025d3e3baea649872ec5ffba6b58da28 100644 (file)
@@ -176,6 +176,7 @@ static int choose_cursor(ScrArea *sa)
                else if(G.f & G_VERTEXPAINT) return CURSOR_VPAINT;
                else if(G.f & G_WEIGHTPAINT) return CURSOR_VPAINT;
                else if(G.f & G_FACESELECT) return CURSOR_FACESEL;
+               else if(G.f & G_SCULPTMODE) return CURSOR_EDIT;
                else return CURSOR_STD;
        }
        else if (sa->spacetype==SPACE_TEXT) {
index 6364831893ea323ee4c4d8c5ceea8eed7d44e413..78130f2ea88e64084b33370e03203fc0762bf75a 100644 (file)
@@ -90,6 +90,7 @@
 #include "BIF_toolbox.h"
 
 #include "BDR_editobject.h"    /* For headerprint */
+#include "BDR_sculptmode.h"
 #include "BDR_vpaint.h"
 #include "BDR_editface.h"
 #include "BDR_drawobject.h"
@@ -1073,6 +1074,10 @@ void set_active_base(Base *base)
                                DAG_object_flush_update(G.scene, tbase->object, OB_RECALC_DATA);
                        }
                }
+
+               if(base->object->type==OB_MESH && G.f & G_SCULPTMODE) {
+                       set_sculpt_object(base->object);
+               }
        }
 }
 
@@ -1416,6 +1421,9 @@ void mouse_select(void)
                        
                        /* selecting a non-mesh, should end a couple of modes... */
                        if(basact->object->type!=OB_MESH) {
+                               if(G.f & G_SCULPTMODE) {
+                                       set_sculptmode();
+                               }
                                if(G.f & G_WEIGHTPAINT) {
                                        set_wpaint();   /* toggle */
                                }
index 87d20c66ef962990598da55c1b6d27975a714b5f..711c809ce40bf0e9d2dda856428b4e9aea46c17a 100644 (file)
@@ -137,6 +137,20 @@ void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
        set_inverted_drawing(0);
 }
 
+void fdrawXORellipse(float xofs, float yofs, float hw, float hh)
+{
+       if(hw==0) return;
+
+       set_inverted_drawing(1);
+
+       glPushMatrix();
+       glTranslatef(xofs, yofs, 0.0);
+       glScalef(1,hh/hw,1);
+       glutil_draw_lined_arc(0.0, M_PI*2.0, hw, 20);
+       glPopMatrix();
+
+       set_inverted_drawing(0);
+}
 void fdrawXORcirc(float xofs, float yofs, float rad)
 {
        set_inverted_drawing(1);
index 6e45644fefe2da5b510db7dd4bdd5612e6c0c980..84735a49ca6cd127bac44f8f4cc68f0318a16ee4 100644 (file)
@@ -323,10 +323,17 @@ void buttons_active_id(ID **id, ID **idfrom)
                                }
                        }
                        else if(G.buts->texfrom==3) {
-                               Brush *brush= G.scene->toolsettings->imapaint.brush;
-                               if (brush) {
-                                       mtex= brush->mtex[brush->texact];
-                                       if(mtex) *id= (ID*)mtex->tex;
+                               if(G.f & G_SCULPTMODE) {
+                                       if(G.scene->sculptdata.texact != -1) {
+                                               mtex= G.scene->sculptdata.mtex[G.scene->sculptdata.texact];
+                                               if(mtex) *id= (ID*)mtex->tex;
+                                       }
+                               } else {
+                                       Brush *brush= G.scene->toolsettings->imapaint.brush;
+                                       if (brush) {
+                                               mtex= brush->mtex[brush->texact];
+                                               if(mtex) *id= (ID*)mtex->tex;
+                                       }
                                }
                        }
                }
index 69859bcb7d846dc194b36b7fbae52d6e4ea006c0..868d463073360e72e8da9d54cd5ff9063617829b 100644 (file)
@@ -75,6 +75,7 @@
 
 #include "BLI_arithb.h"
 #include "BLI_blenlib.h"
+#include "BLI_editVert.h"
 
 #include "BSE_edit.h"
 #include "BSE_editipo.h"
@@ -86,6 +87,7 @@
 #include "BDR_editface.h"
 #include "BDR_editmball.h"
 #include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
 #include "BDR_imagepaint.h"
 #include "BDR_vpaint.h"
 
 #include "BIF_poseobject.h"
 #include "BIF_renderwin.h"
 #include "BIF_resources.h"
+#include "BIF_retopo.h"
 #include "BIF_screen.h"
 #include "BIF_space.h"
 #include "BIF_toets.h"
 
 #define V3D_OBJECTMODE_SEL                     ICON_OBJECT
 #define V3D_EDITMODE_SEL                       ICON_EDITMODE_HLT
+#define V3D_SCULPTMODE_SEL                     ICON_SCULPTMODE_HLT
 #define V3D_FACESELECTMODE_SEL         ICON_FACESEL_HLT
 #define V3D_VERTEXPAINTMODE_SEL                ICON_VPAINT_HLT
 #define V3D_TEXTUREPAINTMODE_SEL       ICON_TPAINT_HLT
@@ -2165,6 +2169,9 @@ static void do_view3d_edit_objectmenu(void *arg, int event)
        case 17: /* Transform snap to grid */
                G.vd->flag2 ^= V3D_TRANSFORM_SNAP;
                break;
+       case 18:
+               add_blockhandler(curarea, VIEW3D_HANDLER_MULTIRES, 0);
+               break;
        }
        allqueue(REDRAWVIEW3D, 0);
 }
@@ -2197,6 +2204,7 @@ static uiBlock *view3d_edit_objectmenu(void *arg_unused)
        
 
        uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N",             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 15, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Multires Properties",                0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 18, "");
        uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
        uiDefIconTextBlockBut(block, view3d_object_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
 
@@ -2731,6 +2739,9 @@ static void do_view3d_edit_meshmenu(void *arg, int event)
                if(session) b_verse_push_object(session, G.obedit);
                break;
 #endif
+       case 14:
+               add_blockhandler(curarea, VIEW3D_HANDLER_MULTIRES, 0);
+               break;
        case 17: /* Transform snap to grid */
                G.vd->flag2 ^= V3D_TRANSFORM_SNAP;
                break;
@@ -2767,6 +2778,7 @@ static uiBlock *view3d_edit_meshmenu(void *arg_unused)
                uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Transform Snap",                 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
 
        uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties...|N",          0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Multires Properties...",             0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
        uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
        uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, 120, 19, "");
        uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
@@ -3764,7 +3776,6 @@ static void do_view3d_vpaintmenu(void *arg, int event)
        allqueue(REDRAWVIEW3D, 0);
 }
 
-
 static uiBlock *view3d_vpaintmenu(void *arg_unused)
 {
        uiBlock *block;
@@ -3889,6 +3900,41 @@ static uiBlock *view3d_wpaintmenu(void *arg_unused)
        return block;
 }
 
+void do_view3d_sculptmenu(void *arg, int event)
+{
+       short avg= G.scene->sculptdata.averaging;
+       switch(event) {
+       case 0: /* Set sculptdata.averaging */
+               if(button(&avg,1,10,"Averaging:")==0) return;
+               G.scene->sculptdata.averaging= avg;
+               break;
+       }
+
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+uiBlock *view3d_sculptmenu(void *arg_unused_so_why_have_it/*?*/)
+{
+       uiBlock *block;
+       short yco= 0, menuwidth= 120;
+       
+       block= uiNewBlock(&curarea->uiblocks, "view3d_sculptmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+       uiBlockSetButmFunc(block, do_view3d_sculptmenu, NULL);
+       
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mouse averaging", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+       if(curarea->headertype==HEADERTOP) {
+               uiBlockSetDirection(block, UI_DOWN);
+       }
+       else {
+               uiBlockSetDirection(block, UI_TOP);
+               uiBlockFlipOrder(block);
+       }
+
+       uiTextBoundsBlock(block, 50);
+
+       return block;
+}
 
 static void do_view3d_facesel_propertiesmenu(void *arg, int event)
 {
@@ -4172,7 +4218,8 @@ static char *view3d_modeselect_pup(void)
        }
 
        if (ob->type == OB_MESH) {
-       
+
+               str += sprintf(str, formatstr, "Sculpt Mode", V3D_SCULPTMODE_SEL, ICON_SCULPTMODE_HLT);
                str += sprintf(str, formatstr, "UV Face Select", V3D_FACESELECTMODE_SEL, ICON_FACESEL_HLT);
                str += sprintf(str, formatstr, "Vertex Paint", V3D_VERTEXPAINTMODE_SEL, ICON_VPAINT_HLT);
                str += sprintf(str, formatstr, "Texture Paint", V3D_TEXTUREPAINTMODE_SEL, ICON_TPAINT_HLT);
@@ -4316,6 +4363,7 @@ void do_view3d_buttons(short event)
                if (G.vd->modeselect == V3D_OBJECTMODE_SEL) {
                        
                        G.vd->flag &= ~V3D_MODE;
+                       if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
                        if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
                        if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
                        if(G.f & G_WEIGHTPAINT) set_wpaint();           /* Switch off weight paint */
@@ -4326,6 +4374,7 @@ void do_view3d_buttons(short event)
                else if (G.vd->modeselect == V3D_EDITMODE_SEL) {
                        if(!G.obedit) {
                                G.vd->flag &= ~V3D_MODE;
+                               if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
                                if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
                                if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
                                if(G.f & G_WEIGHTPAINT) set_wpaint();           /* Switch off weight paint */
@@ -4334,6 +4383,18 @@ void do_view3d_buttons(short event)
                                BIF_undo_push("Original");      /* here, because all over code enter_editmode is abused */
                        }
                } 
+               else if (G.vd->modeselect == V3D_SCULPTMODE_SEL) {
+                       if (!(G.f & G_SCULPTMODE)) {
+                               G.vd->flag &= ~V3D_MODE;
+                               if(G.f & G_FACESELECT) set_faceselect(); /* Switch off face select */
+                               if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
+                               if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
+                               if(G.f & G_WEIGHTPAINT) set_wpaint();           /* Switch off weight paint */
+                               if(G.obedit) exit_editmode(2);  /* exit editmode and undo */
+                                       
+                               set_sculptmode();
+                       }
+               } 
                else if (G.vd->modeselect == V3D_FACESELECTMODE_SEL) {
                        if ((G.obedit) && (G.f & G_FACESELECT)) {
                                exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* exit editmode and undo */
@@ -4343,6 +4404,7 @@ void do_view3d_buttons(short event)
                                if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
                        } else {
                                G.vd->flag &= ~V3D_MODE;
+                               if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
                                if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
                                if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
                                if(G.f & G_WEIGHTPAINT) set_wpaint();           /* Switch off weight paint */
@@ -4354,6 +4416,7 @@ void do_view3d_buttons(short event)
                else if (G.vd->modeselect == V3D_VERTEXPAINTMODE_SEL) {
                        if (!(G.f & G_VERTEXPAINT)) {
                                G.vd->flag &= ~V3D_MODE;
+                               if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
                                if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
                                if(G.f & G_WEIGHTPAINT) set_wpaint();           /* Switch off weight paint */
                                if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);      /* exit editmode and undo */
@@ -4364,6 +4427,7 @@ void do_view3d_buttons(short event)
                else if (G.vd->modeselect == V3D_TEXTUREPAINTMODE_SEL) {
                        if (!(G.f & G_TEXTUREPAINT)) {
                                G.vd->flag &= ~V3D_MODE;
+                               if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
                                if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
                                if(G.f & G_WEIGHTPAINT) set_wpaint();           /* Switch off weight paint */
                                if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);      /* exit editmode and undo */
@@ -4374,6 +4438,7 @@ void do_view3d_buttons(short event)
                else if (G.vd->modeselect == V3D_WEIGHTPAINTMODE_SEL) {
                        if (!(G.f & G_WEIGHTPAINT) && (ob && ob->type == OB_MESH) ) {
                                G.vd->flag &= ~V3D_MODE;
+                               if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
                                if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
                                if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
                                if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);      /* exit editmode and undo */
@@ -4590,6 +4655,11 @@ static void view3d_header_pulldowns(uiBlock *block, short *xcoord)
                uiDefPulldownBut(block, view3d_tpaintmenu, NULL, "Paint", xco,-2, xmax-3, 24, "");
                xco+= xmax;
        }
+       else if( G.f & G_SCULPTMODE) {
+               xmax= GetButStringLength("Sculpt");
+               uiDefPulldownBut(block, view3d_sculptmenu, NULL, "Sculpt", xco, -2, xmax-3, 24, "");
+               xco+= xmax;
+       }
        else if (G.f & G_FACESELECT) {
                if (ob && ob->type == OB_MESH) {
                        xmax= GetButStringLength("Face");
@@ -4654,6 +4724,7 @@ void view3d_buttons(void)
        
        if (G.obedit) G.vd->modeselect = V3D_EDITMODE_SEL;
        else if(ob && (ob->flag & OB_POSEMODE)) G.vd->modeselect = V3D_POSEMODE_SEL;
+       else if (G.f & G_SCULPTMODE)  G.vd->modeselect = V3D_SCULPTMODE_SEL;
        else if (G.f & G_WEIGHTPAINT) G.vd->modeselect = V3D_WEIGHTPAINTMODE_SEL;
        else if (G.f & G_VERTEXPAINT) G.vd->modeselect = V3D_VERTEXPAINTMODE_SEL;
        else if (G.f & G_TEXTUREPAINT) G.vd->modeselect = V3D_TEXTUREPAINTMODE_SEL;
@@ -4679,123 +4750,152 @@ void view3d_buttons(void)
 
        /* around */
        xco+= XIC+18;
-       
+
+       /* Show wireframe for sculptmode */
+       if(!G.obedit && G.f & G_SCULPTMODE && ob) {
+               uiDefButBitC(block, TOG, OB_DRAWWIRE, REDRAWVIEW3D, "Wire", xco,0,30,20, &ob->dtx, 0,0,0,0, "Adds the active object's wireframe over solid drawing");
+               xco+= 35;
+               uiDefButC(block, TOG, B_NOP, "PvRot", xco,0,40,20,&G.vd->pivot_last, 0,0,0,0, "Rotate around the center of the last brush action");
+               xco+= 40;
+       }
+
        uiBlockBeginAlign(block);
-       uiDefIconTextButS(block, ICONTEXTROW,B_AROUND, ICON_ROTATE, around_pup(), xco,0,XIC+10,YIC, &(G.vd->around), 0, 3.0, 0, 0, "Rotation/Scaling Pivot (Hotkeys: Comma, Shift Comma, Period) ");
 
-       xco+= XIC+10;
+       if(retopo_mesh_paint_check()) {
+               RetopoPaintData *rpd= get_retopo_paint_data();
+               if(rpd) {
+                       uiDefButC(block,ROW,B_NOP,"Pen",xco,0,40,20,&rpd->mode,6.0,RETOPO_PEN,0,0,"");
+                       xco+=40;
+                       uiDefButC(block,ROW,B_NOP,"Line",xco,0,40,20,&rpd->mode,6.0,RETOPO_LINE,0,0,"");
+                       xco+=40;
+                       uiDefButC(block,ROW,B_NOP,"Ellipse",xco,0,60,20,&rpd->mode,6.0,RETOPO_ELLIPSE,0,0,"");
+                       xco+=65;
+                       
+                       uiBlockBeginAlign(block);
+                       uiDefButC(block,NUM,B_NOP,"LineDiv",xco,0,80,20,&rpd->line_div,1,50,0,0,"How much to subdivide each line made with the Line tool");
+                       xco+=80;
+                       uiDefButC(block,NUM,B_NOP,"EllDiv",xco,0,80,20,&rpd->ellipse_div,3,50,0,0,"How much to subdivide each ellipse made with the Ellipse tool");
+                       xco+=85;
+                       
+                       uiBlockEndAlign(block);
+               }
+       } else {
+               uiDefIconTextButS(block, ICONTEXTROW,B_AROUND, ICON_ROTATE, around_pup(), xco,0,XIC+10,YIC, &(G.vd->around), 0, 3.0, 0, 0, "Rotation/Scaling Pivot (Hotkeys: Comma, Shift Comma, Period) ");
+
+               xco+= XIC+10;
        
-       uiDefIconButBitS(block, TOG, V3D_ALIGN, B_AROUND, ICON_ALIGN,
-                               xco,0,XIC,YIC,
-                               &G.vd->flag, 0, 0, 0, 0, "Move object centers only");   
-       uiBlockEndAlign(block);
+               uiDefIconButBitS(block, TOG, V3D_ALIGN, B_AROUND, ICON_ALIGN,
+                                xco,0,XIC,YIC,
+                                &G.vd->flag, 0, 0, 0, 0, "Move object centers only");  
+               uiBlockEndAlign(block);
        
-       xco+= XIC+8;
+               xco+= XIC+8;
 
-       /* Transform widget / manipulators */
-       uiBlockBeginAlign(block);
-       uiDefIconButBitS(block, TOG, V3D_USE_MANIPULATOR, B_REDR, ICON_MANIPUL,xco,0,XIC,YIC, &G.vd->twflag, 0, 0, 0, 0, "Use 3d transform manipulator (Ctrl Space)");  
-       xco+= XIC;
-       
-       if(G.vd->twflag & V3D_USE_MANIPULATOR) {
-               uiDefIconButBitS(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Translate manipulator mode (Ctrl Alt G)");
-               xco+= XIC;
-               uiDefIconButBitS(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Rotate manipulator mode (Ctrl Alt R)");
-               xco+= XIC;
-               uiDefIconButBitS(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Scale manipulator mode (Ctrl Alt S)");
+               /* Transform widget / manipulators */
+               uiBlockBeginAlign(block);
+               uiDefIconButBitS(block, TOG, V3D_USE_MANIPULATOR, B_REDR, ICON_MANIPUL,xco,0,XIC,YIC, &G.vd->twflag, 0, 0, 0, 0, "Use 3d transform manipulator (Ctrl Space)");  
                xco+= XIC;
-       }
-       uiDefButS(block, MENU, B_NOP, "Orientation%t|Global%x0|Local%x1|Normal%x2|View%x3",xco,0,70,YIC, &G.vd->twmode, 0, 0, 0, 0, "Transform Orientation (Alt Space)");
-       xco+= 70;
-       uiBlockEndAlign(block);
-       xco+= 8;
        
-       /* LAYERS */
-       if(G.obedit==NULL && G.vd->localview==0) {
-               uiBlockBeginAlign(block);
-               for(a=0; a<5; a++)
-                       uiDefButBitI(block, TOG, 1<<a, B_LAY+a, "",     (short)(xco+a*(XIC/2)), (short)(YIC/2),(short)(XIC/2),(short)(YIC/2), &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Num, Shift Num)");
-               for(a=0; a<5; a++)
-                       uiDefButBitI(block, TOG, 1<<(a+10), B_LAY+10+a, "",(short)(xco+a*(XIC/2)), 0,                   XIC/2, (YIC)/2, &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Alt Num, Alt Shift Num)");
-               
-               xco+= 5;
-               uiBlockBeginAlign(block);
-               for(a=5; a<10; a++)
-                       uiDefButBitI(block, TOG, 1<<a, B_LAY+a, "",     (short)(xco+a*(XIC/2)), (short)(YIC/2),(short)(XIC/2),(short)(YIC/2), &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Num, Shift Num)");
-               for(a=5; a<10; a++)
-                       uiDefButBitI(block, TOG, 1<<(a+10), B_LAY+10+a, "",(short)(xco+a*(XIC/2)), 0,                   XIC/2, (YIC)/2, &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Alt Num, Alt Shift Num)");
-
+               if(G.vd->twflag & V3D_USE_MANIPULATOR) {
+                       uiDefIconButBitS(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Translate manipulator mode (Ctrl Alt G)");
+                       xco+= XIC;
+                       uiDefIconButBitS(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Rotate manipulator mode (Ctrl Alt R)");
+                       xco+= XIC;
+                       uiDefIconButBitS(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Scale manipulator mode (Ctrl Alt S)");
+                       xco+= XIC;
+               }
+               uiDefButS(block, MENU, B_NOP, "Orientation%t|Global%x0|Local%x1|Normal%x2|View%x3",xco,0,70,YIC, &G.vd->twmode, 0, 0, 0, 0, "Transform Orientation (Alt Space)");
+               xco+= 70;
                uiBlockEndAlign(block);
+               xco+= 8;
+       
+               /* LAYERS */
+               if(G.obedit==NULL && G.vd->localview==0) {
+                       uiBlockBeginAlign(block);
+                       for(a=0; a<5; a++)
+                               uiDefButBitI(block, TOG, 1<<a, B_LAY+a, "",     (short)(xco+a*(XIC/2)), (short)(YIC/2),(short)(XIC/2),(short)(YIC/2), &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Num, Shift Num)");
+                       for(a=0; a<5; a++)
+                               uiDefButBitI(block, TOG, 1<<(a+10), B_LAY+10+a, "",(short)(xco+a*(XIC/2)), 0,                   XIC/2, (YIC)/2, &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Alt Num, Alt Shift Num)");
+               
+                       xco+= 5;
+                       uiBlockBeginAlign(block);
+                       for(a=5; a<10; a++)
+                               uiDefButBitI(block, TOG, 1<<a, B_LAY+a, "",     (short)(xco+a*(XIC/2)), (short)(YIC/2),(short)(XIC/2),(short)(YIC/2), &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Num, Shift Num)");
+                       for(a=5; a<10; a++)
+                               uiDefButBitI(block, TOG, 1<<(a+10), B_LAY+10+a, "",(short)(xco+a*(XIC/2)), 0,                   XIC/2, (YIC)/2, &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Alt Num, Alt Shift Num)");
+
+                       uiBlockEndAlign(block);
                
-               xco+= (a-2)*(XIC/2)+3;
+                       xco+= (a-2)*(XIC/2)+3;
 
-               /* LOCK */
-               uiDefIconButS(block, ICONTOG, B_SCENELOCK, ICON_UNLOCKED, xco+=XIC,0,XIC,YIC, &(G.vd->scenelock), 0, 0, 0, 0, "Locks layers and used Camera to Scene (Ctrl `)");
-               xco+= XIC+10;
+                       /* LOCK */
+                       uiDefIconButS(block, ICONTOG, B_SCENELOCK, ICON_UNLOCKED, xco+=XIC,0,XIC,YIC, &(G.vd->scenelock), 0, 0, 0, 0, "Locks layers and used Camera to Scene (Ctrl `)");
+                       xco+= XIC+10;
 
-       }
+               }
        
-       /* proportional falloff */
-       if(G.obedit && (G.obedit->type == OB_MESH || G.obedit->type == OB_CURVE || G.obedit->type == OB_SURF || G.obedit->type == OB_LATTICE)) {
+               /* proportional falloff */
+               if(G.obedit && (G.obedit->type == OB_MESH || G.obedit->type == OB_CURVE || G.obedit->type == OB_SURF || G.obedit->type == OB_LATTICE)) {
                
-               uiBlockBeginAlign(block);
-               uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_PROP_OFF, "Proportional %t|Off %x0|On %x1|Connected %x2", xco,0,XIC+10,YIC, &(G.scene->proportional), 0, 1.0, 0, 0, "Proportional Edit Falloff (Hotkeys: O, Alt O) ");
-               xco+= XIC+10;
-               
-               if(G.scene->proportional) {
-                       uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_SMOOTHCURVE, propfalloff_pup(), xco,0,XIC+10,YIC, &(G.scene->prop_mode), 0.0, 0.0, 0, 0, "Proportional Edit Falloff (Hotkey: Shift O) ");
+                       uiBlockBeginAlign(block);
+                       uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_PROP_OFF, "Proportional %t|Off %x0|On %x1|Connected %x2", xco,0,XIC+10,YIC, &(G.scene->proportional), 0, 1.0, 0, 0, "Proportional Edit Falloff (Hotkeys: O, Alt O) ");
                        xco+= XIC+10;
+               
+                       if(G.scene->proportional) {
+                               uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_SMOOTHCURVE, propfalloff_pup(), xco,0,XIC+10,YIC, &(G.scene->prop_mode), 0.0, 0.0, 0, 0, "Proportional Edit Falloff (Hotkey: Shift O) ");
+                               xco+= XIC+10;
+                       }
+                       xco+= 10;
                }
-               xco+= 10;
-       }
 
-       /* selection modus */
-       if(G.obedit && (G.obedit->type == OB_MESH)) {
-               uiBlockBeginAlign(block);
-               uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode (Ctrl Tab 1)");
-               xco+= XIC;
-               uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Edge select mode (Ctrl Tab 2)");
-               xco+= XIC;
-               uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Face select mode (Ctrl Tab 3)");
-               xco+= XIC;
-               uiBlockEndAlign(block);
-               if(G.vd->drawtype > OB_WIRE) {
-                       uiDefIconButBitS(block, TOG, V3D_ZBUF_SELECT, B_REDR, ICON_ORTHO, xco,0,XIC,YIC, &G.vd->flag, 1.0, 0.0, 0, 0, "Limit selection to visible (clipped with depth buffer)");
+               /* selection modus */
+               if(G.obedit && (G.obedit->type == OB_MESH)) {
+                       uiBlockBeginAlign(block);
+                       uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode (Ctrl Tab 1)");
+                       xco+= XIC;
+                       uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Edge select mode (Ctrl Tab 2)");
                        xco+= XIC;
+                       uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Face select mode (Ctrl Tab 3)");
+                       xco+= XIC;
+                       uiBlockEndAlign(block);
+                       if(G.vd->drawtype > OB_WIRE) {
+                               uiDefIconButBitS(block, TOG, V3D_ZBUF_SELECT, B_REDR, ICON_ORTHO, xco,0,XIC,YIC, &G.vd->flag, 1.0, 0.0, 0, 0, "Limit selection to visible (clipped with depth buffer)");
+                               xco+= XIC;
+                       }
+                       xco+= 20;
                }
-               xco+= 20;
-       }
 
-       uiDefIconBut(block, BUT, B_VIEWRENDER, ICON_SCENE_DEHLT, xco,0,XIC,YIC, NULL, 0, 1.0, 0, 0, "Render this window (hold CTRL for anim)");
+               uiDefIconBut(block, BUT, B_VIEWRENDER, ICON_SCENE_DEHLT, xco,0,XIC,YIC, NULL, 0, 1.0, 0, 0, "Render this window (hold CTRL for anim)");
        
-       if (ob && (ob->flag & OB_POSEMODE)) {
-               xco+= XIC/2;
-               uiBlockBeginAlign(block);
-               if(curarea->headertype==HEADERTOP) {
-                       uiDefIconBut(block, BUT, B_ACTCOPY, ICON_COPYUP, 
-                                                xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
-                                                "Copies the current pose to the buffer");
-                       uiSetButLock(ob->id.lib!=0, "Can't edit library data");
-                       uiDefIconBut(block, BUT, B_ACTPASTE, ICON_PASTEUP,      
-                                                xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
-                                                "Pastes the pose from the buffer");
-                       uiDefIconBut(block, BUT, B_ACTPASTEFLIP, ICON_PASTEFLIPUP,
-                                                xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
-                                                "Pastes the mirrored pose from the buffer");
-               }
-               else {
-                       uiDefIconBut(block, BUT, B_ACTCOPY, ICON_COPYDOWN,
-                                                xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
-                                                "Copies the current pose to the buffer");
-                       uiSetButLock(ob->id.lib!=0, "Can't edit library data");
-                       uiDefIconBut(block, BUT, B_ACTPASTE, ICON_PASTEDOWN,
-                                                xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
-                                                "Pastes the pose from the buffer");
-                       uiDefIconBut(block, BUT, B_ACTPASTEFLIP, ICON_PASTEFLIPDOWN, 
-                                                xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
-                                                "Pastes the mirrored pose from the buffer");
+               if (ob && (ob->flag & OB_POSEMODE)) {
+                       xco+= XIC/2;
+                       uiBlockBeginAlign(block);
+                       if(curarea->headertype==HEADERTOP) {
+                               uiDefIconBut(block, BUT, B_ACTCOPY, ICON_COPYUP, 
+                                            xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
+                                            "Copies the current pose to the buffer");
+                               uiSetButLock(ob->id.lib!=0, "Can't edit library data");
+                               uiDefIconBut(block, BUT, B_ACTPASTE, ICON_PASTEUP,      
+                                            xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
+                                            "Pastes the pose from the buffer");
+                               uiDefIconBut(block, BUT, B_ACTPASTEFLIP, ICON_PASTEFLIPUP,
+                                            xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
+                                            "Pastes the mirrored pose from the buffer");
+                       }
+                       else {
+                               uiDefIconBut(block, BUT, B_ACTCOPY, ICON_COPYDOWN,
+                                            xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
+                                            "Copies the current pose to the buffer");
+                               uiSetButLock(ob->id.lib!=0, "Can't edit library data");
+                               uiDefIconBut(block, BUT, B_ACTPASTE, ICON_PASTEDOWN,
+                                            xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
+                                            "Pastes the pose from the buffer");
+                               uiDefIconBut(block, BUT, B_ACTPASTEFLIP, ICON_PASTEFLIPDOWN, 
+                                            xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, 
+                                            "Pastes the mirrored pose from the buffer");
+                       }
+                       uiBlockEndAlign(block);
                }
-               uiBlockEndAlign(block);
        }
 
        /* Always do this last */
index cd69708931b69e1f8b54341d494d180ed5bca0fa..57d52edc1093cbf47a2a5493f7e22d6327a6b2d0 100644 (file)
@@ -1291,6 +1291,16 @@ void do_global_buttons(unsigned short event)
                        allqueue(REDRAWOOPS, 0);
                        allqueue(REDRAWIMAGE, 0);
                }
+               else if(G.buts->mainb==CONTEXT_EDITING) {
+                       SculptData *sd= &G.scene->sculptdata;
+                       if(sd && sd->texact != -1) {
+                               if(sd->mtex[sd->texact]) autotexname(sd->mtex[sd->texact]);
+
+                               BIF_undo_push("Auto name");
+                               allqueue(REDRAWBUTSEDIT, 0);
+                               allqueue(REDRAWOOPS, 0);
+                       }
+               }
                break;
 
        case B_RESETAUTOSAVE:
diff --git a/source/blender/src/multires.c b/source/blender/src/multires.c
new file mode 100644 (file)
index 0000000..5f44409
--- /dev/null
@@ -0,0 +1,1334 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implements the multiresolution modeling tools.
+ *
+ * BIF_multires.h
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_vec_types.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
+
+#include "BSE_edit.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "multires.h"
+#include "mydevice.h"
+#include "parametrizer.h"
+
+#include <math.h>
+#include <string.h>
+
+void Vec3fAvg3(float *out, float *v1, float *v2, float *v3)
+{
+       out[0]= (v1[0]+v2[0]+v3[0])/3;
+       out[1]= (v1[1]+v2[1]+v3[1])/3;
+       out[2]= (v1[2]+v2[2]+v3[2])/3;
+}
+void Vec3fAvg4(float *out, float *v1, float *v2, float *v3, float *v4)
+{
+       out[0]= (v1[0]+v2[0]+v3[0]+v4[0])/4;
+       out[1]= (v1[1]+v2[1]+v3[1]+v4[1])/4;
+       out[2]= (v1[2]+v2[2]+v3[2]+v4[2])/4;
+}
+
+short multires_edge_is_boundary(MultiresLevel *lvl, unsigned e)
+{
+       MultiresMapNode *n1= lvl->vert_face_map[lvl->edges[e].v[0]].first;
+       unsigned total= 0;
+
+       while(n1) {
+               MultiresMapNode *n2= lvl->vert_face_map[lvl->edges[e].v[1]].first;
+               while(n2) {
+                       if(n1->Index == n2->Index) {
+                               ++total;
+
+                               if(total > 1)
+                                       return 0;
+                       }
+
+                       n2= n2->next;
+               }
+               n1= n1->next;
+       }
+
+       return 1;
+}
+
+short multires_vert_is_boundary(MultiresLevel *lvl, unsigned v)
+{
+       MultiresMapNode *node= lvl->vert_edge_map[v].first;
+       while(node) {
+               if(multires_edge_is_boundary(lvl,node->Index))
+                       return 1;
+               node= node->next;
+       }
+       return 0;
+}
+
+typedef struct FloatNode {
+       struct FloatNode *next, *prev;
+       float value;
+} FloatNode;
+typedef struct FloatArrayNode {
+       struct FloatArrayNode *next, *prev;
+       float *value;
+} FloatArrayNode;
+
+typedef struct MultiApplyData {
+       /* Smooth faces */
+       float *corner1, *corner2, *corner3, *corner4;
+       char quad;
+
+       /* Smooth edges */
+       char boundary;
+       float *edge_face_neighbor_midpoints_accum;
+       unsigned edge_face_neighbor_midpoints_total;
+       float *endpoint1, *endpoint2;
+
+       /* Smooth verts */
+       /* uses 'char boundary' */
+       float *original;
+       int edge_count;
+       float *vert_face_neighbor_midpoints_average;
+       float *vert_edge_neighbor_midpoints_average;
+       float *boundary_edges_average;
+} MultiApplyData;
+
+/* CATMULL-CLARK
+   ============= */
+
+/* Simply averages the four corners of a polygon. */
+float catmullclark_smooth_face(MultiApplyData *data, const unsigned i)
+{
+       const float total= data->corner1[i]+data->corner2[i]+data->corner3[i];
+       return data->quad ? (total+data->corner4[i])/4 : total/3;
+}
+
+float catmullclark_smooth_edge(MultiApplyData *data, const unsigned i)
+{
+       float accum= 0;
+       unsigned count= 2;
+
+       accum+= data->endpoint1[i] + data->endpoint2[i];
+
+       if(!data->boundary) {
+               accum+= data->edge_face_neighbor_midpoints_accum[i];
+               count+= data->edge_face_neighbor_midpoints_total;
+       }
+
+       return accum / count;
+}
+float catmullclark_smooth_vert(MultiApplyData *data, const unsigned i)
+{
+       if(data->boundary) {
+               return data->original[i]*0.75 + data->boundary_edges_average[i]*0.25;
+       } else {
+               return (data->vert_face_neighbor_midpoints_average[i] +
+                       2*data->vert_edge_neighbor_midpoints_average[i] +
+                       data->original[i]*(data->edge_count-3))/data->edge_count;
+       }
+}
+
+
+
+/* Call func count times, passing in[i] as the input and storing the output in out[i] */
+void multi_apply(float *out, MultiApplyData *data,
+                const unsigned count, float (*func)(MultiApplyData *, const unsigned))
+{
+       unsigned i;
+       for(i=0; i<count; ++i)
+               out[i]= func(data,i);
+}
+
+float get_float(void *array, const unsigned i, const unsigned j, const char stride)
+{
+       return ((float*)((char*)array+(i*stride)))[j];
+}
+
+void edge_face_neighbor_midpoints_accum(MultiApplyData *data, MultiresLevel *lvl,
+                                       void *array, const char stride, const MultiresEdge *e)
+{
+       ListBase *neighbors1= &lvl->vert_face_map[e->v[0]];
+       ListBase *neighbors2= &lvl->vert_face_map[e->v[1]];
+       MultiresMapNode *n1, *n2;
+       unsigned j,count= 0;
+       float *out= MEM_callocN(sizeof(float)*3, "edge_face_neighbor_midpoints_average");
+       
+       out[0]=out[1]=out[2]= 0;
+
+       for(n1= neighbors1->first; n1; n1= n1->next) {
+               for(n2= neighbors2->first; n2; n2= n2->next) {
+                       if(n1->Index == n2->Index) {
+                               for(j=0; j<3; ++j)
+                                       out[j]+= get_float(array,lvl->faces[n1->Index].mid,j,stride);
+                               ++count;
+                       }
+               }
+       }
+
+       data->edge_face_neighbor_midpoints_accum= out;
+       data->edge_face_neighbor_midpoints_total= count;
+}
+void vert_face_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl,
+                                         void *array, const char stride, const unsigned i)
+{
+       ListBase *neighbors= &lvl->vert_face_map[i];
+       MultiresMapNode *n1;
+       unsigned j,count= 0;
+       float *out= MEM_callocN(sizeof(float)*3, "vert_face_neighbor_midpoints_average");
+
+       out[0]=out[1]=out[2]= 0;
+
+       for(n1= neighbors->first; n1; n1= n1->next) {
+               for(j=0; j<3; ++j)
+                       out[j]+= get_float(array,lvl->faces[n1->Index].mid,j,stride);
+               ++count;
+       }
+       for(j=0; j<3; ++j) out[j]/= count;
+       data->vert_face_neighbor_midpoints_average= out;
+}
+void vert_edge_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl,
+                                         void *array, const char stride, const unsigned i)
+{
+       ListBase *neighbors= &lvl->vert_edge_map[i];
+       MultiresMapNode *n1;
+       unsigned j,count= 0;
+       float *out= MEM_callocN(sizeof(float)*3, "vert_edge_neighbor_midpoints_average");
+
+       out[0]=out[1]=out[2]= 0;
+
+       for(n1= neighbors->first; n1; n1= n1->next) {
+               for(j=0; j<3; ++j)
+                       out[j]+= (get_float(array,lvl->edges[n1->Index].v[0],j,stride) +
+                                 get_float(array,lvl->edges[n1->Index].v[1],j,stride)) / 2;
+               ++count;
+       }
+       for(j=0; j<3; ++j) out[j]/= count;
+       data->vert_edge_neighbor_midpoints_average= out;
+}
+void boundary_edges_average(MultiApplyData *data, MultiresLevel *lvl,
+                           void *array, const char stride, const unsigned i)
+{
+       ListBase *neighbors= &lvl->vert_edge_map[i];
+       MultiresMapNode *n1;
+       unsigned j,count= 0;
+       float *out= MEM_callocN(sizeof(float)*3, "edge_boundary_average");
+
+       out[0]=out[1]=out[2]= 0;
+       
+       for(n1= neighbors->first; n1; n1= n1->next) {
+               const MultiresEdge *e= &lvl->edges[n1->Index];
+               const unsigned end= e->v[0]==i ? e->v[1] : e->v[0];
+               
+               if(multires_edge_is_boundary(lvl,n1->Index)) {
+                       for(j=0; j<3; ++j)
+                               out[j]+= get_float(array,end,j,stride);
+                       ++count;
+               }
+       }
+       for(j=0; j<3; ++j) out[j]/= count;
+       data->boundary_edges_average= out;
+}
+
+/* Five functions for manipulating MultiresColors */
+void convert_to_multires_col(MultiresCol *mrc, MCol *mcol)
+{
+       mrc->a= mcol->a;
+       mrc->r= mcol->r;
+       mrc->g= mcol->g;
+       mrc->b= mcol->b;
+}
+void convert_to_multires_uvcol(MultiresCol *mrc, TFace *t, const unsigned char j)
+{
+       convert_to_multires_col(mrc, (MCol*)(&t->col[j]));
+       mrc->u= t->uv[j][0];
+       mrc->v= t->uv[j][1];
+}
+float clamp_component(const float c)
+{
+       if(c<0) return 0;
+       else if(c>255) return 255;
+       else return c;
+}
+
+void multirestexcol_to_mcol(MultiresTexColFace *f, MCol mcol[4])
+{
+       unsigned char j;
+       for(j=0; j<4; ++j) {
+               mcol->a= clamp_component(f->col[j].a);
+               mcol->r= clamp_component(f->col[j].r);
+               mcol->g= clamp_component(f->col[j].g);
+               mcol->b= clamp_component(f->col[j].b);
+               ++mcol;
+       }
+}
+
+void convert_from_multires_col(MultiresCol *mrc, MCol *mcol)
+{
+       mcol->a= clamp_component(mrc->a);
+       mcol->r= clamp_component(mrc->r);
+       mcol->g= clamp_component(mrc->g);
+       mcol->b= clamp_component(mrc->b);
+}
+void texcolface_to_tface(MultiresTexColFace *f, TFace *t)
+{
+       unsigned i;
+       for(i=0; i<4; ++i) {
+               convert_from_multires_col(&f->col[i], (MCol*)(&t->col[i]));
+               t->uv[i][0]= f->col[i].u;
+               t->uv[i][1]= f->col[i].v;
+       }
+       t->tpage= f->tex_page;
+       t->flag= f->tex_flag;
+       t->transp= f->tex_transp;
+       t->mode= f->tex_mode;
+       t->tile= f->tex_tile;
+       t->unwrap= f->tex_unwrap;
+}
+
+/* 1 <= count <= 4 */
+void multires_col_avg(MultiresCol *avg, MultiresCol cols[4], char count)
+{
+       unsigned i;
+       avg->a= avg->r= avg->g= avg->b= avg->u= avg->v= 0;
+       for(i=0; i<count; ++i) {
+               avg->a+= cols[i].a;
+               avg->r+= cols[i].r;
+               avg->g+= cols[i].g;
+               avg->b+= cols[i].b;
+               avg->u+= cols[i].u;
+               avg->v+= cols[i].v;
+       }
+       avg->a/= count;
+       avg->r/= count;
+       avg->g/= count;
+       avg->b/= count;
+       avg->u/= count;
+       avg->v/= count;
+}
+
+void multires_col_avg2(MultiresCol *avg, MultiresCol *c1, MultiresCol *c2)
+{
+       MultiresCol in[2];
+       in[0]= *c1;
+       in[1]= *c2;
+       multires_col_avg(avg,in,2);
+}
+
+void multires_add_dvert(MDeformVert *out, const MDeformVert *in, const float w)
+{
+       if(out && in) {
+               int i, j;
+               char found;
+
+               for(i=0; i<in->totweight; ++i) {
+                       found= 0;
+                       for(j=0; j<out->totweight; ++j) {
+                               if(out->dw[j].def_nr==in->dw[i].def_nr) {
+                                       out->dw[j].weight += w;
+                                       found= 1;
+                               }
+                       }
+                       if(!found) {
+                               MDeformWeight *newdw= MEM_callocN(sizeof(MDeformWeight)*(out->totweight+1), "multires dvert");
+                               if(out->dw) {
+                                       memcpy(newdw, out->dw, sizeof(MDeformWeight)*out->totweight);
+                                       MEM_freeN(out->dw);
+                               }
+
+                               out->dw= newdw;
+                               out->dw[out->totweight].weight= w;
+                               out->dw[out->totweight].def_nr= in->dw[i].def_nr;
+
+                               ++out->totweight;
+                       }
+               }
+       }
+}
+
+void multires_load_cols(Mesh *me)
+{
+       MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1), *cur;
+       unsigned i,j;
+
+       if(!me->mcol && !me->tface) return;
+
+       /* Add texcol data */
+       for(cur= me->mr->levels.first; cur; cur= cur->next)
+               if(!cur->texcolfaces)
+                       cur->texcolfaces= MEM_callocN(sizeof(MultiresTexColFace)*cur->totface,"TexColFaces");
+
+       if(me->mcol) {
+               me->mr->use_col= 1;
+               for(i=0; i<me->totface; ++i)
+                       for(j=0; j<4; ++j)
+                               convert_to_multires_col(&lvl->texcolfaces[i].col[j],&me->mcol[i*4+j]);
+       }
+
+       if(me->tface) {
+               me->mr->use_tex= 1;
+               for(i=0; i<me->totface; ++i) {
+                       MultiresTexColFace *f= &lvl->texcolfaces[i];
+                       TFace *t= &me->tface[i];
+                       for(j=0; j<4; ++j)
+                               convert_to_multires_uvcol(&f->col[j],t,j);
+
+                       f->tex_page= t->tpage;
+                       f->tex_transp= t->transp;
+                       f->tex_mode= t->mode;
+                       f->tex_tile= t->tile;
+                       f->tex_unwrap= t->unwrap;
+               }
+       }
+
+       /* Update higher levels */
+       lvl= lvl->next;
+       while(lvl) {
+               MultiresTexColFace *cf= lvl->texcolfaces;
+               for(i=0; i<lvl->prev->totface; ++i) {
+                       const char sides= lvl->prev->faces[i].v[3]?4:3;
+                       MultiresCol cntr;
+                       
+                       /* Find average color of 4 (or 3 for triangle) verts */
+                       multires_col_avg(&cntr,lvl->prev->texcolfaces[i].col,sides);
+                       
+                       for(j=0; j<sides; ++j) {
+                               MultiresTexColFace *pf= &lvl->prev->texcolfaces[i];
+
+                               multires_col_avg2(&cf->col[0],
+                                                 &pf->col[j],
+                                                 &pf->col[j==0?sides-1:j-1]);
+                               cf->col[1]= pf->col[j];
+                               multires_col_avg2(&cf->col[2],
+                                                 &pf->col[j],
+                                                 &pf->col[j==sides-1?0:j+1]);
+                               cf->col[3]= cntr;
+
+                               cf->tex_page= pf->tex_page;
+                               cf->tex_flag= pf->tex_flag;
+                               cf->tex_transp= pf->tex_transp;
+                               cf->tex_mode= pf->tex_mode;
+                               cf->tex_tile= pf->tex_tile;
+                               cf->tex_unwrap= pf->tex_unwrap;
+                               
+                               ++cf;
+                       }
+               }
+               lvl= lvl->next;
+       }
+
+       /* Update lower levels */
+       lvl= me->mr->levels.last;
+       lvl= lvl->prev;
+       while(lvl) {
+               unsigned curf= 0;
+               for(i=0; i<lvl->totface; ++i) {
+                       MultiresFace *f= &lvl->faces[i];
+                       for(j=0; j<(f->v[3]?4:3); ++j) {
+                               lvl->texcolfaces[i].col[j]= lvl->next->texcolfaces[curf].col[1];
+                               ++curf;
+                       }
+               }
+               lvl= lvl->prev;
+       }
+}
+
+void multires_make(void *ob, void *me_v)
+{
+       Mesh *me= me_v;
+       MultiresLevel *lvl= MEM_callocN(sizeof(MultiresLevel), "multires level");
+       int em= G.obedit!=NULL;
+       int i;
+
+       waitcursor(1);
+
+       if(me->pv) sculptmode_pmv_off(me);
+
+       me->mr= MEM_callocN(sizeof(Multires), "multires data");
+       
+       BLI_addtail(&me->mr->levels,lvl);
+       me->mr->current= 1;
+       me->mr->level_count= 1;
+       me->mr->edgelvl= 1;
+       me->mr->pinlvl= 1;
+       me->mr->renderlvl= 1;
+
+       /* Load mesh into modifier */
+       if(em) exit_editmode(2);
+
+       /* Load vertices */
+       lvl->verts= MEM_callocN(sizeof(MVert)*me->totvert,"multires verts");
+       lvl->totvert= me->totvert;
+       for(i=0; i<me->totvert; ++i) {
+               lvl->verts[i]= me->mvert[i];
+       }
+
+       /* Load faces */
+       lvl->faces= MEM_callocN(sizeof(MultiresFace)*me->totface,"multires faces");
+       lvl->totface= me->totface;
+       for(i=0; i<me->totface; ++i) {
+               MultiresFace* f= &lvl->faces[i];
+               f->v[0]= me->mface[i].v1;
+               f->v[1]= me->mface[i].v2;
+               f->v[2]= me->mface[i].v3;
+               f->v[3]= me->mface[i].v4;
+               f->mid= 0;
+               f->childrenstart= 0;
+               f->flag= me->mface[i].flag;
+       }
+
+       /* Load edges */
+       lvl->edges= MEM_callocN(sizeof(MultiresEdge)*me->totedge,"multires edges");
+       lvl->totedge= me->totedge;
+       for(i=0; i<me->totedge; ++i) {
+               lvl->edges[i].v[0]= me->medge[i].v1;
+               lvl->edges[i].v[1]= me->medge[i].v2;
+               lvl->edges[i].mid= 0;
+       }
+
+       /* Load dverts */
+       if(me->dvert) {
+               me->mr->dverts= MEM_dupallocN(me->dvert);
+               for(i=0; i<me->totvert; ++i) {
+                       if(me->mr->dverts[i].dw)
+                               me->mr->dverts[i].dw= MEM_dupallocN(me->mr->dverts[i].dw);
+               }
+       }
+
+       multires_load_cols(me);
+
+       multires_calc_level_maps(lvl);
+
+       if(em) enter_editmode(0);
+       
+       allqueue(REDRAWBUTSEDIT, 0);
+
+       BIF_undo_push("Make multires");
+
+       waitcursor(0);
+}
+
+void multires_delete(void *ob, void *me_v)
+{
+       multires_free(me_v);
+
+       allqueue(REDRAWBUTSEDIT, 0);
+
+       BIF_undo_push("Delete multires");
+}
+
+void multires_free(Mesh *me)
+{
+       if(me->mr) {
+               int i;
+
+               MultiresLevel* lvl= me->mr->levels.first;
+
+               /* Free the first-level data */
+               if(me->mr->dverts) {
+                       for(i=0; lvl && i<lvl->totvert; ++i)
+                               if(me->mr->dverts[i].dw) MEM_freeN(me->mr->dverts[i].dw);
+                       MEM_freeN(me->mr->dverts);
+               }
+
+               while(lvl) {
+                       multires_free_level(lvl);                       
+                       lvl= lvl->next;
+               }
+
+               BLI_freelistN(&me->mr->levels);
+
+               MEM_freeN(me->mr);
+               me->mr= NULL;
+       }
+}
+
+/* Does not actually free lvl itself! */
+void multires_free_level(MultiresLevel *lvl)
+{
+       if(lvl) {
+               unsigned i;
+
+               if(lvl->verts) MEM_freeN(lvl->verts);
+               if(lvl->faces) MEM_freeN(lvl->faces);
+               if(lvl->edges) MEM_freeN(lvl->edges);
+               if(lvl->texcolfaces) MEM_freeN(lvl->texcolfaces);
+               
+               /* Free all vertex maps */
+               for(i=0; i<lvl->totvert; ++i)
+                       BLI_freelistN(&lvl->vert_edge_map[i]);
+               for(i=0; i<lvl->totvert; ++i)
+                       BLI_freelistN(&lvl->vert_face_map[i]);
+               MEM_freeN(lvl->vert_edge_map);
+               MEM_freeN(lvl->vert_face_map);
+       }
+}
+
+void multires_del_lower(void *ob, void *me)
+{
+       Multires *mr= ((Mesh*)me)->mr;
+       MultiresLevel *lvl= BLI_findlink(&mr->levels,mr->current-1);
+
+       lvl= lvl->prev;
+       while(lvl) {
+               multires_free_level(lvl);
+               BLI_freelinkN(&mr->levels,lvl);
+               lvl= lvl->prev;
+               mr->current-= 1;
+               mr->level_count-= 1;
+       }
+       mr->newlvl= mr->current;
+
+       allqueue(REDRAWBUTSEDIT, 0);
+
+       BIF_undo_push("Multires delete lower");
+}
+
+void multires_del_higher(void *ob, void *me)
+{
+       Multires *mr= ((Mesh*)me)->mr;
+       MultiresLevel *lvl= BLI_findlink(&mr->levels,mr->current-1);
+
+       lvl= lvl->next;
+       while(lvl) {
+               multires_free_level(lvl);
+               BLI_freelinkN(&mr->levels,lvl);
+               lvl= lvl->next;
+               mr->level_count-= 1;
+       }
+
+       allqueue(REDRAWBUTSEDIT, 0);
+
+       BIF_undo_push("Multires delete higher");
+}
+
+unsigned int find_mid_edge(ListBase *vert_edge_map,
+                          MultiresLevel *lvl,
+                          const unsigned int v1,
+                          const unsigned int v2 )
+{
+       MultiresMapNode *n= vert_edge_map[v1].first;
+       while(n) {
+               if(lvl->edges[n->Index].v[0]==v2 ||
+                  lvl->edges[n->Index].v[1]==v2)
+                       return lvl->edges[n->Index].mid;
+
+               n= n->next;
+       }
+       return -1;
+}
+
+void check_colors(Mesh *me)
+{
+       /* Check if vertex colors have been deleted or added */
+       if(me->mr->use_col && !me->mcol)
+               me->mr->use_col= 0;
+       else if(!me->mr->use_col && me->mcol) {
+               me->mr->use_col= 1;
+               multires_load_cols(me);
+       }
+
+       /* Check if texfaces have been deleted or added */
+       if(me->mr->use_tex && !me->tface)
+               me->mr->use_tex= 0;
+       else if(!me->mr->use_tex && me->tface) {
+               me->mr->use_tex= 1;
+               multires_load_cols(me);
+       }
+}
+
+void multires_add_level(void *ob, void *me_v)
+{
+       int i,j, curf, cure;
+       Mesh *me= me_v;
+       MultiresLevel *lvl= MEM_callocN(sizeof(MultiresLevel), "multireslevel");
+       int em= G.obedit!=NULL;
+       MultiApplyData data;
+
+       waitcursor(1);
+
+       if(me->pv) sculptmode_pmv_off(me);
+               
+       if(em) exit_editmode(2);
+
+       check_colors(me);
+
+       ++me->mr->level_count;
+       BLI_addtail(&me->mr->levels,lvl);
+
+       /* Create vertices
+          =============== */
+       lvl->totvert= lvl->prev->totvert + lvl->prev->totedge + lvl->prev->totface;
+       lvl->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts");
+       /* Copy previous level's verts */
+       for(i=0; i<lvl->prev->totvert; ++i)
+               VecCopyf(lvl->verts[i].co,lvl->prev->verts[i].co);
+       /* Create new edge verts */
+       for(i=0; i<lvl->prev->totedge; ++i) {
+               VecMidf(lvl->verts[lvl->prev->totvert + i].co,
+                       lvl->prev->verts[lvl->prev->edges[i].v[0]].co,
+                       lvl->prev->verts[lvl->prev->edges[i].v[1]].co);
+               lvl->prev->edges[i].mid= lvl->prev->totvert + i;
+       }
+       /* Create new face verts */
+       for(i=0; i<lvl->prev->totface; ++i) {
+               lvl->prev->faces[i].mid= lvl->prev->totvert + lvl->prev->totedge + i;
+       }
+
+       /* Create faces
+          ============ */
+       /* Allocate all the new faces (each triangle creates three, and
+          each quad creates four */
+       lvl->totface= 0;
+       for(i=0; i<lvl->prev->totface; ++i)
+               lvl->totface+= lvl->prev->faces[i].v[3] ? 4 : 3;
+       lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces");
+
+       curf= 0;
+       for(i=0; i<lvl->prev->totface; ++i) {
+               const int max= lvl->prev->faces[i].v[3] ? 3 : 2;
+               
+               lvl->prev->faces[i].childrenstart= curf;
+               for(j=0; j<max+1; ++j) {
+                       lvl->faces[curf].v[0]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev,
+                                                            lvl->prev->faces[i].v[j],
+                                                            lvl->prev->faces[i].v[j==0?max:j-1]);
+                       lvl->faces[curf].v[1]= lvl->prev->faces[i].v[j];
+                       lvl->faces[curf].v[2]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev,
+                                                            lvl->prev->faces[i].v[j],
+                                                            lvl->prev->faces[i].v[j==max?0:j+1]);
+                       lvl->faces[curf].v[3]= lvl->prev->totvert + lvl->prev->totedge + i;
+                       lvl->faces[curf].flag= lvl->prev->faces[i].flag;
+
+                       ++curf;
+               }
+       }
+
+       /* Create edges
+          ============ */
+       /* Figure out how many edges to allocate */
+       lvl->totedge= lvl->prev->totedge*2;
+       for(i=0; i<lvl->prev->totface; ++i)
+               lvl->totedge+= lvl->prev->faces[i].v[3]?4:3;
+       lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges");
+
+       for(i=0; i<lvl->prev->totedge; ++i) {
+               lvl->edges[i*2].v[0]= lvl->prev->edges[i].v[0];
+               lvl->edges[i*2].v[1]= lvl->prev->edges[i].mid;
+               lvl->edges[i*2+1].v[0]= lvl->prev->edges[i].mid;
+               lvl->edges[i*2+1].v[1]= lvl->prev->edges[i].v[1];
+       }
+       /* Add edges inside of old polygons */
+       curf= 0;
+       cure= lvl->prev->totedge*2;
+       for(i=0; i<lvl->prev->totface; ++i) {
+               for(j=0; j<(lvl->prev->faces[i].v[3]?4:3); ++j) {
+                       lvl->edges[cure].v[0]= lvl->faces[curf].v[2];
+                       lvl->edges[cure].v[1]= lvl->faces[curf].v[3];
+                       ++cure;
+                       ++curf;
+               }
+       }
+
+       multires_calc_level_maps(lvl);
+       
+       /* Smooth vertices
+          =============== */
+       for(i=0; i<lvl->prev->totface; ++i) {
+               const MultiresFace *f= &lvl->prev->faces[i];
+               data.corner1= lvl->prev->verts[f->v[0]].co;
+               data.corner2= lvl->prev->verts[f->v[1]].co;
+               data.corner3= lvl->prev->verts[f->v[2]].co;
+               data.corner4= lvl->prev->verts[f->v[3]].co;
+               data.quad= f->v[3] ? 1 : 0;
+               multi_apply(lvl->verts[f->mid].co, &data, 3, catmullclark_smooth_face);
+       }
+
+       for(i=0; i<lvl->prev->totedge; ++i) {
+               const MultiresEdge *e= &lvl->prev->edges[i];
+               data.boundary= multires_edge_is_boundary(lvl->prev,i);
+               edge_face_neighbor_midpoints_accum(&data,lvl->prev,lvl->verts,sizeof(MVert),e);
+               data.endpoint1= lvl->prev->verts[e->v[0]].co;
+               data.endpoint2= lvl->prev->verts[e->v[1]].co;
+               multi_apply(lvl->verts[e->mid].co, &data, 3, catmullclark_smooth_edge);
+               MEM_freeN(data.edge_face_neighbor_midpoints_accum);
+       }
+       
+       for(i=0; i<lvl->prev->totvert; ++i) {
+               data.boundary= multires_vert_is_boundary(lvl->prev,i);
+               data.original= lvl->verts[i].co;
+               data.edge_count= BLI_countlist(&lvl->prev->vert_edge_map[i]);
+               if(data.boundary)
+                       boundary_edges_average(&data,lvl->prev,lvl->prev->verts,sizeof(MVert),i);
+               else {
+                       vert_face_neighbor_midpoints_average(&data,lvl->prev,lvl->verts,sizeof(MVert),i);
+                       vert_edge_neighbor_midpoints_average(&data,lvl->prev,lvl->prev->verts,sizeof(MVert),i);
+               }
+               multi_apply(lvl->verts[i].co, &data, 3, catmullclark_smooth_vert);
+               if(data.boundary)
+                       MEM_freeN(data.boundary_edges_average);
+               else {
+                       MEM_freeN(data.vert_face_neighbor_midpoints_average);
+                       MEM_freeN(data.vert_edge_neighbor_midpoints_average);
+               }
+       }
+
+       /* Vertex Colors
+          ============= */
+       curf= 0;
+       if(me->mr->use_col || me->mr->use_tex) {
+               MultiresTexColFace *cf= MEM_callocN(sizeof(MultiresTexColFace)*lvl->totface,"MultiresTexColFaces");
+               lvl->texcolfaces= cf;
+               for(i=0; i<lvl->prev->totface; ++i) {
+                       const char sides= lvl->prev->faces[i].v[3]?4:3;
+                       MultiresCol cntr;
+
+                       /* Find average color of 4 (or 3 for triangle) verts */
+                       multires_col_avg(&cntr,lvl->prev->texcolfaces[i].col,sides);
+
+                       for(j=0; j<sides; ++j) {
+                               multires_col_avg2(&cf->col[0],
+                                                 &lvl->prev->texcolfaces[i].col[j],
+                                                 &lvl->prev->texcolfaces[i].col[j==0?sides-1:j-1]);
+                               cf->col[1]= lvl->prev->texcolfaces[i].col[j];
+                               multires_col_avg2(&cf->col[2],
+                                                 &lvl->prev->texcolfaces[i].col[j],
+                                                 &lvl->prev->texcolfaces[i].col[j==sides-1?0:j+1]);
+                               cf->col[3]= cntr;
+                               
+                               cf->tex_page= lvl->prev->texcolfaces[i].tex_page;
+                               cf->tex_flag= lvl->prev->texcolfaces[i].tex_flag;
+                               cf->tex_transp= lvl->prev->texcolfaces[i].tex_transp;
+                               cf->tex_mode= lvl->prev->texcolfaces[i].tex_mode;
+                               cf->tex_tile= lvl->prev->texcolfaces[i].tex_tile;
+                               cf->tex_unwrap= lvl->prev->texcolfaces[i].tex_unwrap;
+
+                               ++cf;
+                       }
+               }
+       }
+
+       multires_update_levels(me);
+       me->mr->newlvl= me->mr->level_count;
+       me->mr->current= me->mr->newlvl;
+       multires_level_to_mesh(ob,me);
+       if(em) enter_editmode(0);
+       
+       allqueue(REDRAWBUTSEDIT, 0);
+
+       BIF_undo_push("Add multires level");
+
+       waitcursor(0);
+}
+
+void multires_set_level(void *ob, void *me_v)
+{
+       Mesh *me= me_v;
+       int em= G.obedit!=NULL;
+
+       waitcursor(1);
+
+       if(me->pv) sculptmode_pmv_off(me);
+
+       if(em) exit_editmode(2);
+
+       check_colors(me);
+       multires_update_levels(me);
+
+       me->mr->current= me->mr->newlvl;
+       if(me->mr->current<1) me->mr->current= 1;
+       else if(me->mr->current>me->mr->level_count) me->mr->current= me->mr->level_count;
+
+       multires_level_to_mesh(ob,me);
+
+       if(em) enter_editmode(0);
+
+       allqueue(REDRAWBUTSEDIT, 0);
+       
+       waitcursor(0);
+}
+
+void multires_level_to_mesh(Object *ob, Mesh *me)
+{
+       MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+       int i,sm= G.f & G_SCULPTMODE;
+       if(sm) set_sculptmode();
+
+       if(me->mvert) MEM_freeN(me->mvert);
+       if(me->mface) MEM_freeN(me->mface);
+       if(me->medge) MEM_freeN(me->medge);
+       if(me->dvert) {
+               for(i=0; i<me->totvert; ++i) {
+                       if(me->dvert[i].dw)
+                               MEM_freeN(me->dvert[i].dw);
+               }
+               MEM_freeN(me->dvert);
+       }
+
+       me->totvert= lvl->totvert;
+       me->totface= lvl->totface;
+       me->totedge= lvl->totedge;
+
+       me->mvert= MEM_callocN(sizeof(MVert)*me->totvert, "multires dlm mverts");
+       me->mface= MEM_callocN(sizeof(MFace)*me->totface, "multires dlm mfaces");
+       me->medge= MEM_callocN(sizeof(MEdge)*me->totedge, "multires dlm medges");
+
+       /* Vertices/Edges/Faces */
+       for(i=0; i<lvl->totvert; ++i)
+               me->mvert[i]= lvl->verts[i];
+       for(i=0; i<lvl->totface; ++i) {
+               me->mface[i].v1= lvl->faces[i].v[0];
+               me->mface[i].v2= lvl->faces[i].v[1];
+               me->mface[i].v3= lvl->faces[i].v[2];
+               me->mface[i].v4= lvl->faces[i].v[3];
+               me->mface[i].flag= lvl->faces[i].flag;
+       }
+       for(i=0; i<lvl->totedge; ++i) {
+               me->medge[i].v1= lvl->edges[i].v[0];
+               me->medge[i].v2= lvl->edges[i].v[1];
+       }
+
+       /* Vertex groups */
+       if(me->mr->dverts && lvl==me->mr->levels.first) {
+               me->dvert= MEM_dupallocN(me->mr->dverts);
+               for(i=0; i<lvl->totvert; ++i) {
+                       if(me->dvert[i].dw)
+                               me->dvert[i].dw= MEM_dupallocN(me->dvert[i].dw);
+               }
+       } else if(me->mr->dverts) {
+               MultiresLevel *dlvl, *lvl1= me->mr->levels.first;
+               MDeformVert **lvl_dverts;
+               MDeformVert *source;
+               int dlvl_ndx= 0;
+               int j;
+
+               lvl_dverts= MEM_callocN(sizeof(MDeformVert*) * (me->mr->current-1), "dvert prop array");
+               
+               /* dverts are not (yet?) propagated with catmull-clark  */
+               for(dlvl= lvl1->next; dlvl && dlvl != lvl->next; dlvl= dlvl->next) {
+                       lvl_dverts[dlvl_ndx]= MEM_callocN(sizeof(MDeformVert)*dlvl->totvert, "dvert prop data");
+
+                       source= dlvl->prev==lvl1 ? me->mr->dverts : lvl_dverts[dlvl_ndx-1];
+
+                       /* Copy lower level */
+                       for(i=0; i<dlvl->prev->totvert; ++i)
+                               multires_add_dvert(&lvl_dverts[dlvl_ndx][i],
+                                                  &source[i], 1);
+                       /* Edge verts */
+                       for(i=0; i<dlvl->prev->totedge; ++i) {
+                               multires_add_dvert(&lvl_dverts[dlvl_ndx][dlvl->prev->totvert+i],
+                                                  &source[dlvl->prev->edges[i].v[0]],0.5);
+                               multires_add_dvert(&lvl_dverts[dlvl_ndx][dlvl->prev->totvert+i],
+                                                  &source[dlvl->prev->edges[i].v[1]],0.5);
+                       }
+                       /* Face verts */
+                       for(i=0; i<dlvl->prev->totface; ++i) {
+                               for(j=0; j<(dlvl->prev->faces[i].v[3]?4:3); ++j)
+                                       multires_add_dvert(&lvl_dverts[dlvl_ndx][dlvl->prev->totvert+dlvl->prev->totedge+i],
+                                                          &source[dlvl->prev->faces[i].v[j]],
+                                                          dlvl->prev->faces[i].v[3]?0.25:(1/3));
+                       }
+
+                       ++dlvl_ndx;
+               }
+
+               dlvl= lvl1->next;
+               for(i=0; i<(dlvl_ndx-1); ++i) {
+                       for(j=0; j<dlvl->totvert; ++j)
+                               if(lvl_dverts[i][j].dw) MEM_freeN(lvl_dverts[i][j].dw);
+                       MEM_freeN(lvl_dverts[i]);
+               }
+
+               me->dvert= lvl_dverts[dlvl_ndx-1];
+
+               MEM_freeN(lvl_dverts);
+       }
+
+       if(me->mr->use_tex) {
+               if(me->tface) MEM_freeN(me->tface);
+               me->tface= MEM_callocN(sizeof(TFace)*me->totface, "multires dlm tface");
+               
+               for(i=0; i<lvl->totface; ++i)
+                       texcolface_to_tface(&lvl->texcolfaces[i],&me->tface[i]);
+                       
+       } else if(me->mr->use_col) {
+               if(me->mcol) MEM_freeN(me->mcol);
+               me->mcol= MEM_callocN(sizeof(MCol)*me->totface*4, "multires dlm mcol");
+
+               for(i=0; i<lvl->totface; ++i)
+                       multirestexcol_to_mcol(&lvl->texcolfaces[i], &me->mcol[i*4]);
+       }
+       multires_edge_level_update(ob,me);
+       
+       DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+       mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+       if(sm) set_sculptmode();
+
+       countall();
+
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+void multires_update_colors(Mesh *me)
+{
+       MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+       MultiresCol *pr_deltas= NULL, *cr_deltas= NULL;
+       unsigned i,j,curf= 0;
+
+       if(me->mr->use_col || me->mr->use_tex) {
+               /* Calc initial deltas */
+               cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"initial color/uv deltas");
+               if(me->mr->use_tex) {
+                       for(i=0; i<lvl->totface; ++i) {
+                               for(j=0; j<4; ++j) {
+                                       MultiresCol col;
+                                       convert_to_multires_uvcol(&col,&me->tface[i],j);
+                                       cr_deltas[i*4+j].a= col.a - lvl->texcolfaces[i].col[j].a;
+                                       cr_deltas[i*4+j].r= col.r - lvl->texcolfaces[i].col[j].r;
+                                       cr_deltas[i*4+j].g= col.g - lvl->texcolfaces[i].col[j].g;
+                                       cr_deltas[i*4+j].b= col.b - lvl->texcolfaces[i].col[j].b;
+                                       cr_deltas[i*4+j].u= col.u - lvl->texcolfaces[i].col[j].u;
+                                       cr_deltas[i*4+j].v= col.v - lvl->texcolfaces[i].col[j].v;
+                               }
+                       }
+               } else if(me->mr->use_col) {
+                       for(i=0; i<lvl->totface; ++i) {
+                               for(j=0; j<4; ++j) {
+                                       cr_deltas[i*4+j].a= me->mcol[i*4+j].a - lvl->texcolfaces[i].col[j].a;
+                                       cr_deltas[i*4+j].r= me->mcol[i*4+j].r - lvl->texcolfaces[i].col[j].r;
+                                       cr_deltas[i*4+j].g= me->mcol[i*4+j].g - lvl->texcolfaces[i].col[j].g;
+                                       cr_deltas[i*4+j].b= me->mcol[i*4+j].b - lvl->texcolfaces[i].col[j].b;
+                               }
+                       }
+               }
+               
+               /* Update current level */
+               for(i=0; i<lvl->totface; ++i) {
+                       for(j=0; j<4; ++j) {
+                               if(me->mr->use_tex)
+                                       convert_to_multires_uvcol(&lvl->texcolfaces[i].col[j],&me->tface[i],j);
+                               else
+                                       convert_to_multires_col(&lvl->texcolfaces[i].col[j],&me->mcol[i*4+j]);
+                       }
+               }
+
+               /* Update higher levels */
+               lvl= lvl->next;
+               while(lvl) {
+                       /* Set up new deltas, but keep the ones from the previous level */
+                       if(pr_deltas) MEM_freeN(pr_deltas);
+                       pr_deltas= cr_deltas;
+                       cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"color deltas");
+
+                       curf= 0;
+                       for(i=0; i<lvl->prev->totface; ++i) {
+                               const char sides= lvl->prev->faces[i].v[3]?4:3;
+                               MultiresCol cntr;
+                               
+                               /* Find average color of 4 (or 3 for triangle) verts */
+                               multires_col_avg(&cntr,&pr_deltas[i*4],sides);
+                               
+                               for(j=0; j<sides; ++j) {
+                                       multires_col_avg2(&cr_deltas[curf*4],
+                                                         &pr_deltas[i*4+j],
+                                                         &pr_deltas[i*4+(j==0?sides-1:j-1)]);
+                                       cr_deltas[curf*4+1]= pr_deltas[i*4+j];
+                                       multires_col_avg2(&cr_deltas[curf*4+2],
+                                                         &pr_deltas[i*4+j],
+                                                         &pr_deltas[i*4+(j==sides-1?0:j+1)]);
+                                       cr_deltas[curf*4+3]= cntr;
+                                       ++curf;
+                               }
+                       }
+
+                       for(i=0; i<lvl->totface; ++i) {
+                               for(j=0; j<4; ++j) {
+                                       lvl->texcolfaces[i].col[j].a+= cr_deltas[i*4+j].a;
+                                       lvl->texcolfaces[i].col[j].r+= cr_deltas[i*4+j].r;
+                                       lvl->texcolfaces[i].col[j].g+= cr_deltas[i*4+j].g;
+                                       lvl->texcolfaces[i].col[j].b+= cr_deltas[i*4+j].b;
+                                       lvl->texcolfaces[i].col[j].u+= cr_deltas[i*4+j].u;
+                                       lvl->texcolfaces[i].col[j].v+= cr_deltas[i*4+j].v;
+                               }
+                       }
+
+                       lvl= lvl->next;
+               }
+               if(pr_deltas) MEM_freeN(pr_deltas);
+               if(cr_deltas) MEM_freeN(cr_deltas);
+               
+               /* Update lower levels */
+               lvl= me->mr->levels.last;
+               lvl= lvl->prev;
+               while(lvl) {
+                       MultiresTexColFace *nf= lvl->next->texcolfaces;
+                       for(i=0; i<lvl->totface; ++i) {
+                               MultiresFace *f= &lvl->faces[i];
+                               for(j=0; j<(f->v[3]?4:3); ++j) {
+                                       lvl->texcolfaces[i].col[j]= nf->col[1];
+                                       ++nf;
+                               }
+                       }
+                       lvl= lvl->prev;
+               }
+       }
+}
+
+void multires_update_levels(Mesh *me)
+{
+       MultiresLevel *cr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1), *pr_lvl;
+       vec3f *pr_deltas= NULL, *cr_deltas= NULL;
+       MultiApplyData data;
+       unsigned i,j,curf;
+
+       /* Update special first-level data */
+       if(cr_lvl==me->mr->levels.first) {
+               if(me->mr->dverts) { /* First free the old dverts */
+                       MEM_freeN(me->mr->dverts);
+                       for(i=0; i<cr_lvl->totvert; ++i)
+                               if(me->mr->dverts[i].dw) MEM_freeN(me->mr->dverts[i].dw);
+               }
+               
+               if(me->dvert) {
+                       me->mr->dverts= MEM_dupallocN(me->dvert);
+                       for(i=0; i<cr_lvl->totvert; ++i)
+                               if(me->mr->dverts[i].dw) me->mr->dverts[i].dw= MEM_dupallocN(me->mr->dverts[i].dw);
+               }
+       }
+
+       /* Prepare deltas */
+       cr_deltas= MEM_callocN(sizeof(vec3f)*cr_lvl->totvert,"initial deltas");
+
+       /* Calculate initial deltas -- current mesh subtracted from current level*/
+       for(i=0; i<cr_lvl->totvert; ++i)
+               VecSubf(&cr_deltas[i].x,me->mvert[i].co,cr_lvl->verts[i].co);
+
+       /* Update current level -- copy current mesh into current level */
+       for(i=0; i<cr_lvl->totvert; ++i)
+               VecCopyf(cr_lvl->verts[i].co,me->mvert[i].co);
+       for(i=0; i<cr_lvl->totface; ++i)
+               cr_lvl->faces[i].flag= me->mface[i].flag;
+
+       /* Update higher levels */
+       pr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+       cr_lvl= pr_lvl->next;
+       while(cr_lvl) {
+               /* Set up new deltas, but keep the ones from the previous level */
+               if(pr_deltas) MEM_freeN(pr_deltas);
+               pr_deltas= cr_deltas;
+               cr_deltas= MEM_callocN(sizeof(vec3f)*cr_lvl->totvert,"deltas");
+
+               /* Calculate and add new deltas
+                  ============================*/
+
+               for(i=0; i<pr_lvl->totface; ++i) {
+                       const MultiresFace *f= &pr_lvl->faces[i];
+                       data.corner1= &pr_deltas[f->v[0]].x;
+                       data.corner2= &pr_deltas[f->v[1]].x;
+                       data.corner3= &pr_deltas[f->v[2]].x;
+                       data.corner4= &pr_deltas[f->v[3]].x;
+                       data.quad= f->v[3] ? 1 : 0;
+                       multi_apply(&cr_deltas[f->mid].x, &data, 3, catmullclark_smooth_face);
+
+                       VecAddf(cr_lvl->verts[f->mid].co,
+                               cr_lvl->verts[f->mid].co,
+                               &cr_deltas[f->mid].x);
+               }
+
+               for(i=0; i<pr_lvl->totedge; ++i) {
+                       const MultiresEdge *e= &pr_lvl->edges[i];
+                       data.boundary= multires_edge_is_boundary(pr_lvl,i);
+                       edge_face_neighbor_midpoints_accum(&data,pr_lvl,cr_deltas,sizeof(vec3f),e);
+                       data.endpoint1= &pr_deltas[e->v[0]].x;
+                       data.endpoint2= &pr_deltas[e->v[1]].x;
+                       multi_apply(&cr_deltas[e->mid].x, &data, 3, catmullclark_smooth_edge);
+                       MEM_freeN(data.edge_face_neighbor_midpoints_accum);
+               }
+               for(i=0; i<pr_lvl->totedge; ++i) {
+                       const unsigned ndx= pr_lvl->edges[i].mid;
+                       VecAddf(cr_lvl->verts[ndx].co,
+                               cr_lvl->verts[ndx].co,
+                               &cr_deltas[ndx].x);
+               }
+
+               for(i=0; i<pr_lvl->totvert; ++i) {
+                       data.boundary= multires_vert_is_boundary(pr_lvl,i);
+                       data.original= &pr_deltas[i].x;
+                       data.edge_count= BLI_countlist(&pr_lvl->vert_edge_map[i]);
+                       if(data.boundary)
+                               boundary_edges_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i);
+                       else {
+                               vert_face_neighbor_midpoints_average(&data,pr_lvl,cr_deltas,sizeof(vec3f),i);
+                               vert_edge_neighbor_midpoints_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i);
+                       }
+                       multi_apply(&cr_deltas[i].x, &data, 3, catmullclark_smooth_vert);
+                       if(data.boundary)
+                               MEM_freeN(data.boundary_edges_average);
+                       else {
+                               MEM_freeN(data.vert_face_neighbor_midpoints_average);
+                               MEM_freeN(data.vert_edge_neighbor_midpoints_average);
+                       }
+               }
+               for(i=0; i<pr_lvl->totvert; ++i) {
+                       VecAddf(cr_lvl->verts[i].co,
+                               cr_lvl->verts[i].co,
+                               &cr_deltas[i].x);
+               }
+
+               /* Update faces */
+               curf= 0;
+               for(i=0; i<cr_lvl->prev->totface; ++i) {
+                       const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3;
+                       for(j=0; j<sides; ++j) {
+                               if(pr_lvl->faces[i].flag & ME_SMOOTH)
+                                       cr_lvl->faces[curf].flag |= ME_SMOOTH;
+                               else
+                                       cr_lvl->faces[curf].flag &= ~ME_SMOOTH;
+                               ++curf;
+                       }
+               }
+
+               pr_lvl= pr_lvl->next;
+               cr_lvl= cr_lvl->next;
+       }
+       if(pr_deltas) MEM_freeN(pr_deltas);
+       if(cr_deltas) MEM_freeN(cr_deltas);
+
+       /* Update lower levels */
+       cr_lvl= me->mr->levels.last;
+       cr_lvl= cr_lvl->prev;
+       while(cr_lvl) {
+               for(i=0; i<cr_lvl->totvert; ++i)
+                       cr_lvl->verts[i]= cr_lvl->next->verts[i];
+
+               /* Update faces */
+               curf= 0;
+               for(i=0; i<cr_lvl->totface; ++i) {
+                       const int sides= cr_lvl->faces[i].v[3] ? 4 : 3;
+                       char smooth= 1;
+                       
+                       for(j=0; j<sides; ++j) {
+                               if(!(cr_lvl->next->faces[curf].flag & ME_SMOOTH)) {
+                                       smooth= 0;
+                                       break;
+                               }
+                               ++curf;
+                       }
+                       if(smooth)
+                               cr_lvl->faces[i].flag |= ME_SMOOTH;
+                       else
+                               cr_lvl->faces[i].flag &= ~ME_SMOOTH;
+               }
+
+               cr_lvl= cr_lvl->prev;
+       }
+
+       multires_update_colors(me);
+
+}
+
+void multires_calc_level_maps(MultiresLevel *lvl)
+{
+       unsigned i,j;
+       MultiresMapNode *indexnode= NULL;
+       
+       lvl->vert_edge_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_edge_map");
+       for(i=0; i<lvl->totedge; ++i) {
+               for(j=0; j<2; ++j) {
+                       indexnode= MEM_callocN(sizeof(MultiresMapNode),"vert_edge_map indexnode");
+                       indexnode->Index= i;
+                       BLI_addtail(&lvl->vert_edge_map[lvl->edges[i].v[j]],indexnode);
+               }
+       }
+
+
+               lvl->vert_face_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_face_map");
+       for(i=0; i<lvl->totface; ++i){
+               for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j){
+                       indexnode= MEM_callocN(sizeof(MultiresMapNode),"vert_face_map indexnode");
+                       indexnode->Index= i;
+                       BLI_addtail(&lvl->vert_face_map[lvl->faces[i].v[j]],indexnode);
+               }
+       }
+
+}
+
+unsigned powi(const unsigned b, const unsigned p)
+{
+       unsigned i,r= b;
+
+       if(p==0) return 1;
+
+       for(i=1; i<p; ++i)
+               r*= b;
+
+       return r;
+}
+
+void multires_edge_level_update(void *ob, void *me_v)
+{
+       Mesh *me= me_v;
+       MultiresLevel *cr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+       MultiresLevel *edge_lvl= BLI_findlink(&me->mr->levels,me->mr->edgelvl-1);
+       unsigned i;
+
+       for(i=0; i<cr_lvl->totedge; ++i) {
+               const int ndx= me->pv ? me->pv->edge_map[i] : i;
+               if(ndx != -1) { /* -1= hidden edge */
+                       if(me->mr->edgelvl >= me->mr->current ||
+                          i<edge_lvl->totedge*powi(2,me->mr->current-me->mr->edgelvl))
+                               me->medge[ndx].flag= ME_EDGEDRAW;
+                       else
+                               me->medge[ndx].flag= 0;
+               }
+       }
+
+       allqueue(REDRAWVIEW3D, 0);
+}
index ced1f1bd6f53ee1322ce6f7ce6034da07aad133b..2152e65940c30ac0c7fd6be4d2c681d795114aa0 100644 (file)
@@ -88,6 +88,7 @@
 #include "BIF_toolbox.h"
 #include "BIF_writeimage.h"
 
+#include "BDR_sculptmode.h"
 #include "BDR_editobject.h"
 #include "BPY_extern.h" /* for BPY_do_all_scripts */
 
@@ -1058,6 +1059,7 @@ static void do_render(int anim)
        Render *re= RE_NewRender(G.scene->id.name);
        unsigned int lay= G.scene->lay;
        int scemode= G.scene->r.scemode;
+       int sculptmode= G.f & G_SCULPTMODE;
        
        /* UGLY! we set this flag to prevent renderwindow queue to execute another render */
        /* is reset in RE_BlenderFrame */
@@ -1073,6 +1075,8 @@ static void do_render(int anim)
        if(G.obedit)
                exit_editmode(0);       /* 0 = no free data */
 
+       if(sculptmode) set_sculptmode();
+
        /* allow localview render for objects with lights in normal layers */
        if(curarea->spacetype==SPACE_VIEW3D) {
                if(G.vd->lay & 0xFF000000) {
@@ -1104,6 +1108,8 @@ static void do_render(int anim)
 //             }
                
        scene_update_for_newframe(G.scene, G.scene->lay);       // no redraw needed, this restores to view as we left it
+
+       if(sculptmode) set_sculptmode();
        
        waitcursor(0);
 }
diff --git a/source/blender/src/retopo.c b/source/blender/src/retopo.c
new file mode 100644 (file)
index 0000000..3d08f0a
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implements the Retopo tools
+ *
+ * BIF_retopo.h
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BDR_editobject.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "editmesh.h"
+#include "mydevice.h"
+
+#ifdef WIN32
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct RetopoPaintHit {
+       struct RetopoPaintHit *next, *prev;
+       RetopoPaintPoint *intersection;
+       short index;
+       float where;
+} RetopoPaintHit;
+
+void retopo_do_2d(View3D *v3d, short proj[2], float *v, char adj);
+void retopo_paint_debug_print(RetopoPaintData *rpd);
+
+/* Painting */
+RetopoPaintData *get_retopo_paint_data()
+{
+       if(!retopo_mesh_paint_check()) return NULL;
+       if(!G.editMesh) return NULL;
+       return G.editMesh->retopo_paint_data;
+}
+
+char retopo_mesh_paint_check()
+{
+       return retopo_mesh_check() && G.editMesh->retopo_mode==3;
+}
+
+void retopo_free_paint_data(RetopoPaintData *rpd)
+{
+       if(rpd) {
+               RetopoPaintLine *l;
+               for(l= rpd->lines.first; l; l= l->next) {
+                       BLI_freelistN(&l->points);
+                       BLI_freelistN(&l->hitlist);
+               }
+               BLI_freelistN(&rpd->lines);
+               
+               BLI_freelistN(&rpd->intersections);
+
+               MEM_freeN(rpd);
+       }
+}
+
+void retopo_free_paint()
+{
+       retopo_free_paint_data(G.editMesh->retopo_paint_data);
+       G.editMesh->retopo_paint_data= NULL;
+}
+
+char line_intersection_2d(const vec2s *a, const vec2s *b, const vec2s *c, const vec2s *d, vec2s *out,
+                         float *r, float *s)
+{
+       float den;
+       *r= (a->y - c->y) * (d->x - c->x) - (a->x - c->x) * (d->y - c->y);
+       *s= (a->y - c->y) * (b->x - a->x) - (a->x - c->x) * (b->y - a->y);
+       den= (b->x - a->x) * (d->y - c->y) - (b->y - a->y) * (d->x - c->x);
+
+       if((a->x==b->x && a->y==b->y) || (c->x==d->x && c->y==d->y)) return 0;
+
+       if(!den) return 0;
+
+       *r/= den;
+       *s/= den;
+
+       if(*s<0 || *s>=1 || *r<0 || *r>=1) return 0;
+
+       out->x= a->x + *r*(b->x - a->x);
+       out->y= a->y + *r*(b->y - a->y);
+       return 1;
+}
+
+void retopo_paint_add_line_hit(RetopoPaintLine *l, RetopoPaintPoint *p, RetopoPaintPoint *intersection, float w)
+{
+       RetopoPaintHit *prev, *hit= MEM_callocN(sizeof(RetopoPaintHit),"RetopoPaintHit");
+       
+       hit->intersection= intersection;
+       hit->index= p->index;
+       hit->where= w;
+
+       prev= l->hitlist.first;
+       if(!prev) {
+               BLI_addtail(&l->hitlist,hit);
+       }
+       else if(prev->index>hit->index) {
+               BLI_addhead(&l->hitlist,hit);
+       }
+       else {
+               /* Move forward until we hit the next highest index */
+               while(prev->next) {
+                       if(prev->next->index > hit->index) break;
+                       prev= prev->next;
+               }
+               /* Move backward until we hit the next lowest where */
+               while(prev->prev && prev->prev->index==prev->index &&
+                     prev->where > hit->where)
+                       prev=prev->prev;
+               BLI_insertlink(&l->hitlist,prev,hit);
+       }
+       
+       /* Removed duplicate intersections */
+       if(hit->prev && hit->prev->intersection==hit->intersection) {
+               BLI_freelinkN(&l->hitlist,hit);
+       }
+}
+
+char retopo_paint_add_intersection(RetopoPaintData *rpd, RetopoPaintLine *l1, RetopoPaintPoint *p1,
+                                  RetopoPaintLine *l2, RetopoPaintPoint *p2, vec2s *out, float r, float s)
+{
+       RetopoPaintPoint *p, *hit;
+       char found= 0;
+
+       for(p=rpd->intersections.first; p; p= p->next) {
+               if(sqrt(pow(p->loc.x-out->x,2)+pow(p->loc.y-out->y,2))<7) {
+                       found= 1;
+                       break;
+               }
+       }
+
+       if(!found) {
+               hit= MEM_callocN(sizeof(RetopoPaintPoint),"Retopo paint intersection");
+               hit->loc.x= out->x;
+               hit->loc.y= out->y;
+               BLI_addtail(&rpd->intersections,hit);
+       } else {
+               hit= p;
+       }
+
+       retopo_paint_add_line_hit(l1,p1,hit,r);
+       retopo_paint_add_line_hit(l2,p2,hit,s);
+
+       return !found;
+}
+
+
+/* Returns 1 if a new intersection was added */
+char do_line_intersection(RetopoPaintData *rpd, RetopoPaintLine *l1, RetopoPaintPoint *p1,
+                         RetopoPaintLine *l2, RetopoPaintPoint *p2)
+{
+       vec2s out;
+       float r,s;
+       if(line_intersection_2d(&p1->loc, &p1->next->loc,
+                               &p2->loc, &p2->next->loc,
+                               &out,&r,&s)) {
+               if(retopo_paint_add_intersection(rpd,l1,p1,l2,p2,&out,r,s))
+                       return 1;
+       }
+       return 0;
+}
+
+typedef struct FaceNode {
+       struct FaceNode *next, *prev;
+       MFace f;
+} FaceNode;
+
+char faces_equal(EditFace *f1, EditFace *f2)
+{
+       return editface_containsVert(f2,f1->v1) &&
+              editface_containsVert(f2,f1->v2) &&
+              editface_containsVert(f2,f1->v3) &&
+              (f1->v4 ? editface_containsVert(f2,f1->v4) : 1);
+}
+
+EditFace *addfaceif(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
+{
+       EditFace *efa;
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if(editface_containsVert(efa,v1) &&
+                  editface_containsVert(efa,v2) &&
+                  editface_containsVert(efa,v3) &&
+                  (v4 ? editface_containsVert(efa,v4) : 1))
+                       return NULL;
+       }
+
+       return addfacelist(v1,v2,v3,v4,NULL,NULL);
+}
+
+void retopo_paint_apply()
+{
+       RetopoPaintData *rpd= G.editMesh->retopo_paint_data;
+       EditVert *eve;
+
+       if(rpd) {
+               RetopoPaintLine *l1, *l2;
+               RetopoPaintPoint *p1, *p2;
+               unsigned hitcount= 0;
+               unsigned i;
+               RetopoPaintHit *h;
+               float hitco[3];
+               
+               /* Find intersections */
+               BLI_freelistN(&rpd->intersections);
+               for(l1= rpd->lines.first; l1; l1= l1->next) {
+                       for(l2= rpd->lines.first; l2; l2= l2->next) {
+                               if(l1!=l2) {
+                                       for(p1= l1->points.first; p1 && p1!=l1->points.last; p1= p1->next) {
+                                               for(p2= l2->points.first; p2 && p2!=l2->points.last; p2= p2->next) {
+                                                       if(p1!=p2) {
+                                                               if(do_line_intersection(rpd,l1,p1,l2,p2))
+                                                                       ++hitcount;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               /*topoPaintHit *hit;
+               l1= rpd->lines.first;
+               for(hit= l1->hitlist.first; hit; hit= hit->next) {
+                       printf("\nhit(%p,%d) ",hit->intersection,hit->index);
+               }
+               fflush(stdout);*/
+
+               /* Deselect */
+               for(eve= G.editMesh->verts.first; eve; eve= eve->next)
+                       eve->f &= ~SELECT;
+               EM_deselect_flush();
+
+               for(i=0; i<hitcount; ++i) {
+                       RetopoPaintPoint *intersection= BLI_findlink(&rpd->intersections,i);
+                       retopo_do_2d(G.vd,&intersection->loc.x, hitco, 1);
+                       intersection->eve= addvertlist(hitco);
+                       intersection->eve->f= SELECT;
+               }
+               
+               for(l1= rpd->lines.first; l1; l1= l1->next) {
+                       unsigned etcount= BLI_countlist(&l1->hitlist);
+                       if(etcount>=2) {
+                               for(h= l1->hitlist.first; (h && h->next); h= h->next)
+                                       addedgelist(h->intersection->eve,h->next->intersection->eve,NULL);
+                               if(etcount>=3 && l1->cyclic)
+                                       addedgelist(((RetopoPaintHit*)l1->hitlist.first)->intersection->eve,
+                                                   ((RetopoPaintHit*)l1->hitlist.last)->intersection->eve, NULL);
+                       }
+               }
+               
+               addfaces_from_edgenet();
+       }
+
+       retopo_free_paint();
+}
+
+void add_rppoint(RetopoPaintLine *l, short x, short y)
+{
+       RetopoPaintPoint *p= MEM_callocN(sizeof(RetopoPaintPoint),"RetopoPaintPoint");
+       p->loc.x= x;
+       p->loc.y= y;
+       BLI_addtail(&l->points,p);
+       p->index= p->prev?p->prev->index+1:0;
+
+       retopo_do_2d(G.vd, &p->loc.x, p->co, 1);
+}
+RetopoPaintLine *add_rpline(RetopoPaintData *rpd)
+{
+       RetopoPaintLine *l= MEM_callocN(sizeof(RetopoPaintLine),"RetopoPaintLine");
+       BLI_addtail(&rpd->lines,l);
+       return l;
+}
+
+void retopo_paint_toggle_cyclic(RetopoPaintLine *l)
+{
+       if(!l->cyclic) {
+               RetopoPaintPoint *pf= l->points.first;
+
+               if(pf) {
+                       add_rppoint(l, pf->loc.x, pf->loc.y);
+                       l->cyclic= l->points.last;
+               }
+       } else {
+               BLI_freelinkN(&l->points,l->cyclic);
+               l->cyclic= NULL;
+       }
+}
+
+void retopo_paint_add_line(RetopoPaintData *rpd, short mouse[2])
+{
+       RetopoPaintLine *l= add_rpline(rpd);
+       float range[2]= {mouse[0]-rpd->sloc[0],mouse[1]-rpd->sloc[1]};
+       int i;
+
+       /* Add initial point */
+       add_rppoint(l,rpd->sloc[0],rpd->sloc[1]);
+       for(i=0; i<rpd->line_div; ++i) {
+               const float mul= (i+1.0f)/rpd->line_div;
+               add_rppoint(l,rpd->sloc[0] + range[0]*mul,rpd->sloc[1] + range[1]*mul);
+       }
+
+       allqueue(REDRAWVIEW3D,0);
+}
+
+void retopo_paint_add_ellipse(RetopoPaintData *rpd, short mouse[2])
+{
+       int i;
+
+       add_rpline(rpd);
+       for (i=0; i<rpd->ellipse_div; i++) {
+               float t= (float) i/rpd->ellipse_div;
+               float cur= t*(M_PI*2);
+               
+               float w= abs(mouse[0]-rpd->sloc[0]);
+               float h= abs(mouse[1]-rpd->sloc[1]);
+
+               add_rppoint(rpd->lines.last,cos(cur)*w+rpd->sloc[0],sin(cur)*h+rpd->sloc[1]);
+       }
+
+       retopo_paint_toggle_cyclic(rpd->lines.last);
+
+       allqueue(REDRAWVIEW3D,0);
+}
+
+void retopo_end_okee()
+{
+       if(G.editMesh->retopo_mode==3) {
+               if(okee("Apply retopo paint?"))
+                       retopo_paint_apply();
+               else
+                       retopo_free_paint();
+               G.editMesh->retopo_mode= 1;
+       }
+}
+
+void retopo_paint_toggle(void *a, void *b)
+{
+       if(retopo_mesh_paint_check()) { /* Activate retopo paint */
+               RetopoPaintData *rpd= MEM_callocN(sizeof(RetopoPaintData),"RetopoPaintData");
+               
+               G.editMesh->retopo_paint_data= rpd;
+               rpd->mode= RETOPO_PEN;
+               rpd->seldist= 15;
+               rpd->nearest.line= NULL;
+               rpd->line_div= 25;
+               rpd->ellipse_div= 25;
+       } else retopo_end_okee();
+
+       BIF_undo_push("Retopo toggle");
+
+       allqueue(REDRAWVIEW3D, 1);
+}
+
+void retopo_paint_view_update(struct View3D *v3d)
+{
+       RetopoPaintData *rpd= get_retopo_paint_data();
+
+       if(rpd) {
+               RetopoPaintLine *l;
+               RetopoPaintPoint *p;
+               double ux, uy, uz;
+               
+               for(l= rpd->lines.first; l; l= l->next) {
+                       for(p= l->points.first; p; p= p->next) {
+                               gluProject(p->co[0],p->co[1],p->co[2], v3d->retopo_view_data->modelviewmat,
+                                          v3d->retopo_view_data->projectionmat,
+                                          v3d->retopo_view_data->viewport, &ux, &uy, &uz);
+                               p->loc.x= ux;
+                               p->loc.y= uy;
+                       }
+               }
+       }
+}
+
+/* Returns 1 if event should be processed by caller, 0 otherwise */
+char retopo_paint(const unsigned short event)
+{
+       RetopoPaintData *rpd= get_retopo_paint_data();
+
+       if(!event) return 1;
+       if(rpd) {
+               RetopoPaintLine *l;
+               short mouse[2];
+               char lbut= get_mbut() & L_MOUSE;
+       
+               getmouseco_areawin(mouse);
+
+               if(rpd->in_drag && !lbut) { /* End drag */
+                       rpd->in_drag= 0;
+
+                       switch(rpd->mode) {
+                       case RETOPO_PEN:
+                               break;
+                       case RETOPO_LINE:
+                               retopo_paint_add_line(rpd, mouse);
+                               break;
+                       case RETOPO_ELLIPSE:
+                               retopo_paint_add_ellipse(rpd, mouse);
+                               break;
+                       }
+                       BIF_undo_push("Retopo paint");
+               }
+
+               switch(event) {
+               case MOUSEX:
+               case MOUSEY:
+                       switch(rpd->mode) {
+                       case RETOPO_PEN:
+                               if(rpd->in_drag && rpd->lines.last) {
+                                       l= rpd->lines.last;
+
+                                       if(((RetopoPaintPoint*)l->points.last)->loc.x != mouse[0] ||
+                                          ((RetopoPaintPoint*)l->points.last)->loc.y != mouse[1]) {
+                                               add_rppoint(l,mouse[0],mouse[1]);
+                                       }
+                                       rpd->nearest.line= NULL;
+                                       
+                                       break;
+                               } else { /* Find nearest endpoint */
+                                       float sdist;
+                                       RetopoPaintLine *l= rpd->lines.first;
+                                       RetopoPaintSel n= {NULL,NULL,l,1};
+                                       sdist= rpd->seldist + 10;
+                                       for(l= rpd->lines.first; l; l= l->next) {
+                                               float tdist;
+                                               RetopoPaintPoint *p1= l->points.first, *p2= l->points.last;
+                                               
+                                               tdist= sqrt(pow(mouse[0] - p1->loc.x,2)+pow(mouse[1] - p1->loc.y,2));
+                                               if(tdist < sdist && tdist < rpd->seldist) {
+                                                       sdist= tdist;
+                                                       n.line= l;
+                                                       n.first= 1;
+                                               } else {
+                                                       tdist= sqrt(pow(mouse[0] - p2->loc.x,2)+pow(mouse[1] - p2->loc.y,2));
+                                                       if(tdist < sdist && tdist < rpd->seldist) {
+                                                               sdist= tdist;
+                                                               n.line= l;
+                                                               n.first= 0;
+                                                       }
+                                               }
+                                       }
+                                       
+                                       if(sdist < rpd->seldist)
+                                               rpd->nearest= n;
+                                       else rpd->nearest.line= NULL;
+                               }
+                               break;
+                       case RETOPO_LINE:
+                               break;
+                       case RETOPO_ELLIPSE:
+                               break;
+                       }
+                       allqueue(REDRAWVIEW3D,0);
+                       break;
+               case RETKEY:
+               case PADENTER:
+                       retopo_paint_apply();
+               case ESCKEY:
+                       G.editMesh->retopo_mode= 1;
+                       retopo_free_paint();
+
+                       BIF_undo_push("Retopo toggle");
+               
+                       allqueue(REDRAWVIEW3D, 1);
+                       allqueue(REDRAWBUTSEDIT,0);
+                       break;
+               case CKEY:
+                       retopo_paint_toggle_cyclic(rpd->lines.last);
+                       allqueue(REDRAWVIEW3D, 0);
+                       break;
+               case EKEY:
+                       rpd->mode= RETOPO_ELLIPSE;
+                       allqueue(REDRAWBUTSEDIT, 0);
+                       break;
+               case PKEY:
+                       rpd->mode= RETOPO_PEN;
+                       allqueue(REDRAWBUTSEDIT, 0);
+                       break;
+               case LEFTMOUSE:
+                       if(!rpd->in_drag) { /* Start new drag */
+                               rpd->in_drag= 1;
+                               
+                               /* Location of mouse down */
+                               rpd->sloc[0]= mouse[0];
+                               rpd->sloc[1]= mouse[1];
+                               
+                               switch(rpd->mode) {
+                               case RETOPO_PEN:
+                                       if(rpd->nearest.line) {
+                                               RetopoPaintPoint *p, *pt;
+                                               int i;
+                                               
+                                               BLI_remlink(&rpd->lines,rpd->nearest.line);
+                                               BLI_addtail(&rpd->lines,rpd->nearest.line);
+                                               
+                                               /* Check if we need to reverse the line */
+                                               if(rpd->nearest.first) {
+                                                       for(p= rpd->nearest.line->points.first; p; p= p->prev) {
+                                                               pt= p->prev;
+                                                               p->prev= p->next;
+                                                               p->next= pt;
+                                                       }
+                                                       pt= rpd->nearest.line->points.first;
+                                                       rpd->nearest.line->points.first= rpd->nearest.line->points.last;
+                                                       rpd->nearest.line->points.last= pt;
+                                                       
+                                                       /* Reverse indices */
+                                                       i= 0;
+                                                       for(p= rpd->nearest.line->points.first; p; p= p->next)
+                                                               p->index= i++;
+                                               }
+                                       } else {
+                                               add_rpline(rpd);
+                                               add_rppoint(rpd->lines.last,mouse[0],mouse[1]);
+                                       }
+                                       break;
+                               case RETOPO_LINE:
+                                       break;
+                               case RETOPO_ELLIPSE:
+                                       break;
+                               }
+                       }
+                       break;
+               case MIDDLEMOUSE:
+               case WHEELUPMOUSE:
+               case WHEELDOWNMOUSE:
+                       return 1;
+               }
+               return 0;
+       } else return 1;
+}
+void retopo_draw_paint_lines()
+{
+       RetopoPaintData *rpd= get_retopo_paint_data();
+
+       if(rpd) {
+               RetopoPaintLine *l;
+               RetopoPaintPoint *p;
+
+               glColor3f(0,0,0);
+               glLineWidth(2);
+
+               /* Draw existing lines */
+               for(l= rpd->lines.first; l; l= l->next) {
+                       if(l==rpd->lines.last)
+                               glColor3f(0.3,0,0);
+                       glBegin(l->cyclic?GL_LINE_LOOP:GL_LINE_STRIP);
+                       for(p= l->points.first; p; p= p->next) {
+                               glVertex2s(p->loc.x,p->loc.y);
+                       }
+                       glEnd();
+               }
+
+               /* Draw ellipse */
+               if(rpd->mode==RETOPO_ELLIPSE && rpd->in_drag) {
+                       short mouse[2];
+                       getmouseco_areawin(mouse);
+               
+                       setlinestyle(3);
+                       fdrawXORellipse(rpd->sloc[0],rpd->sloc[1],abs(mouse[0]-rpd->sloc[0]),abs(mouse[1]-rpd->sloc[1]));
+                       setlinestyle(0);
+               }
+               else if(rpd->mode==RETOPO_LINE && rpd->in_drag) {
+                       short mouse[2];
+                       getmouseco_areawin(mouse);
+
+                       setlinestyle(3);
+                       sdrawXORline(rpd->sloc[0],rpd->sloc[1],mouse[0],mouse[1]);
+                       setlinestyle(0);
+               }
+               else if(rpd->nearest.line) { /* Draw selection */
+                       RetopoPaintPoint *p= rpd->nearest.first ? rpd->nearest.line->points.first :
+                               rpd->nearest.line->points.last;
+                       if(p)
+                               fdrawXORcirc(p->loc.x, p->loc.y, rpd->seldist);
+               }
+
+               glLineWidth(1);
+       }
+}
+
+RetopoPaintData *retopo_paint_data_copy(RetopoPaintData *rpd)
+{
+       RetopoPaintData *copy;
+       RetopoPaintLine *l, *lcp;
+       RetopoPaintPoint *p, *pcp;
+
+       if(!rpd) return NULL;
+
+       copy= MEM_mallocN(sizeof(RetopoPaintData),"RetopoPaintDataCopy");
+
+       memcpy(copy,rpd,sizeof(RetopoPaintData));
+       copy->lines.first= copy->lines.last= NULL;
+       for(l= rpd->lines.first; l; l= l->next) {
+               lcp= MEM_mallocN(sizeof(RetopoPaintLine),"RetopoPaintLineCopy");
+               memcpy(lcp,l,sizeof(RetopoPaintLine));
+               BLI_addtail(&copy->lines,lcp);
+               
+               lcp->hitlist.first= lcp->hitlist.last= NULL;
+               lcp->points.first= lcp->points.last= NULL;
+               for(p= l->points.first; p; p= p->next) {
+                       pcp= MEM_mallocN(sizeof(RetopoPaintPoint),"RetopoPaintPointCopy");
+                       memcpy(pcp,p,sizeof(RetopoPaintPoint));
+                       BLI_addtail(&lcp->points,pcp);
+               }
+       }
+
+       copy->intersections.first= copy->intersections.last= NULL;
+
+       return copy;
+}
+
+char retopo_mesh_check()
+{
+       return G.obedit && G.obedit->type==OB_MESH && G.editMesh->retopo_mode;
+}
+char retopo_curve_check()
+{
+       return G.obedit && (G.obedit->type==OB_CURVE ||
+                           G.obedit->type==OB_SURF) && (((Curve*)G.obedit->data)->flag & CU_RETOPO);
+}
+
+void retopo_toggle(void *j1,void *j2)
+{
+       if(retopo_mesh_check() || retopo_curve_check()) {
+               if(G.vd->depths) G.vd->depths->damaged= 1;
+               retopo_queue_updates(G.vd);
+       }
+
+       allqueue(REDRAWBUTSEDIT, 0);
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+void retopo_do_2d(View3D *v3d, short proj[2], float *v, char adj)
+{
+       /* Check to make sure vert is visible in window */
+       if(proj[0]>0 && proj[1]>0 && proj[0] < v3d->depths->w && proj[1] < v3d->depths->h) {
+               float depth= v3d->depths->depths[(int)(proj[1]*v3d->depths->w+proj[0])];
+               double px, py, pz;
+               
+               /* Don't modify the point if it'll be mapped to the background */
+               if(depth==v3d->depths->depth_range[1]) {
+                       if(adj) {
+                               /* Find the depth of (0,0,0); */
+                               gluProject(0,0,0,v3d->retopo_view_data->modelviewmat,
+                                          v3d->retopo_view_data->projectionmat,
+                                          v3d->retopo_view_data->viewport,&px,&py,&pz);
+                               depth= pz;
+                       }
+                       else return;
+               }
+               
+               /* Find 3D location with new depth (unproject) */
+               gluUnProject(proj[0],proj[1],depth,v3d->retopo_view_data->modelviewmat,
+                            v3d->retopo_view_data->projectionmat,
+                            v3d->retopo_view_data->viewport,&px,&py,&pz);
+               
+               v[0]= px;
+               v[1]= py;
+               v[2]= pz;
+       }
+}
+
+void retopo_do_vert(View3D *v3d, float *v)
+{
+       short proj[2];
+       double px, py, pz;
+
+       /* Find 2D location (project) */
+       gluProject(v[0],v[1],v[2],v3d->retopo_view_data->modelviewmat,v3d->retopo_view_data->projectionmat,
+                  v3d->retopo_view_data->viewport,&px,&py,&pz);
+       proj[0]= px;
+       proj[1]= py;
+       
+       retopo_do_2d(v3d,proj,v,0);
+}
+
+void retopo_do_all(void *j1,void *j2)
+{
+       RetopoViewData *rvd= G.vd->retopo_view_data;
+       if(retopo_mesh_check()) {
+               if(rvd) {
+                       EditMesh *em= G.editMesh;
+                       EditVert *eve;
+                       
+                       /* Apply retopo to all selected vertices */
+                       eve= em->verts.first;
+                       while(eve) {
+                               if(eve->f & SELECT)
+                                       retopo_do_vert(G.vd,eve->co);
+                               eve= eve->next;
+                       }
+                       
+                       allqueue(REDRAWVIEW3D, 0);
+               }
+       }
+       else if(retopo_curve_check()) {
+               if(rvd) {
+                       extern ListBase editNurb;
+                       Nurb *nu;
+                       BPoint *bp;
+                       int i, j;
+
+                       for(nu= editNurb.first; nu; nu= nu->next)
+                       {
+                               if((nu->type & 7)!=CU_BEZIER) {
+                                       bp= nu->bp;
+                                       for(i=0; i<nu->pntsv; ++i) {
+                                               for(j=0; j<nu->pntsu; ++j, ++bp) {
+                                                       if(bp->f1 & 1)
+                                                               retopo_do_vert(G.vd,bp->vec);
+                                               }
+                                       }
+                               }
+                       }
+
+                       allqueue(REDRAWVIEW3D, 0);                      
+               }
+       }
+}
+
+void retopo_queue_updates(View3D *v3d)
+{
+       if(retopo_mesh_check() || retopo_curve_check()) {
+               if(!v3d->retopo_view_data)
+                       v3d->retopo_view_data= MEM_callocN(sizeof(RetopoViewData),"RetopoViewData");
+               
+               v3d->retopo_view_data->queue_matrix_update= 1;
+               
+               allqueue(REDRAWVIEW3D, 0);
+       }
+}
+
+void retopo_matrix_update(View3D *v3d)
+{
+       if(retopo_mesh_check() || retopo_curve_check()) {
+               RetopoViewData *rvd= v3d->retopo_view_data;
+               if(!rvd) {
+                       rvd= MEM_callocN(sizeof(RetopoViewData),"RetopoViewData");
+                       v3d->retopo_view_data= rvd;
+               }
+               if(rvd && rvd->queue_matrix_update) {
+                       glGetDoublev(GL_MODELVIEW_MATRIX, rvd->modelviewmat);
+                       glGetDoublev(GL_PROJECTION_MATRIX, rvd->projectionmat);
+                       glGetIntegerv(GL_VIEWPORT, rvd->viewport);
+                       rvd->viewport[0]= rvd->viewport[1]= 0;
+
+                       rvd->queue_matrix_update= 0;
+               }
+       }
+}
+
+void retopo_free_view_data(View3D *v3d)
+{
+       if(v3d->retopo_view_data) {
+               MEM_freeN(v3d->retopo_view_data);
+               v3d->retopo_view_data= NULL;
+       }
+}
+
+void retopo_paint_debug_print(RetopoPaintData *rpd)
+{
+       RetopoPaintLine *l;
+       RetopoPaintPoint *p;
+
+       for(l= rpd->lines.first; l; l= l->next) {
+               printf("Line:\n");
+               for(p= l->points.first; p; p= p->next) {
+                       printf("   Point(%d: %d,%d)\n",p->index,p->loc.x,p->loc.y);
+               }
+       }
+
+       fflush(stdout);
+}
diff --git a/source/blender/src/sculptmode.c b/source/blender/src/sculptmode.c
new file mode 100644 (file)
index 0000000..6b908c1
--- /dev/null
@@ -0,0 +1,1747 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implements the Sculpt Mode tools
+ *
+ * BDR_sculptmode.h
+ *
+ */
+
+#include "GHOST_Types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_glutil.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_sculptmode.h"
+
+#include "BSE_drawview.h"
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "RE_render_ext.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* ===== STRUCTS =====
+ *
+ */
+
+/* Used by vertex_users to store face indices in a list */
+typedef struct IndexNode {
+       struct IndexNode* next,* prev;
+       int Index;
+} IndexNode;
+
+
+/* ActiveData stores an Index into the mvert array of Mesh, plus Fade, which
+   stores how far the vertex is from the brush center, scaled to the range [0,1]. */
+typedef struct ActiveData {
+       struct ActiveData *next, *prev;
+       unsigned int Index;
+       float Fade;
+} ActiveData;
+
+typedef struct GrabData {
+       char firsttime;
+       ListBase active_verts[8];
+       unsigned char index;
+       vec3f delta, delta_symm;
+       float depth;
+} GrabData;
+
+typedef struct ProjVert {
+       short co[2];
+       char inside;
+} ProjVert;
+
+typedef struct EditData {
+       vec3f center;
+       float size;
+       char flip;
+       short mouse[2];
+
+       /* Normals */
+       vec3f up, right;
+
+       GrabData *grabdata;
+       float *layer_disps;
+       vec3f *layer_store;
+} EditData;
+
+typedef struct RectNode {
+       struct RectNode *next, *prev;
+       rcti r;
+} RectNode;
+
+static ProjVert *projverts= NULL;
+
+
+/* ===== MEMORY =====
+ * 
+ * Allocate/initialize/free data
+ */
+
+void sculptmode_init(Scene *sce)
+{
+       SculptData *sd;
+
+       if(!sce) {
+               error("Unable to initialize sculptmode: bad scene");
+               return;
+       }
+
+       sd= &sce->sculptdata;
+
+       memset(sd, 0, sizeof(SculptData));
+
+       sd->drawbrush.size=sd->smoothbrush.size=sd->pinchbrush.size=sd->inflatebrush.size=sd->grabbrush.size=sd->layerbrush.size= 50;
+       sd->drawbrush.strength=sd->smoothbrush.strength=sd->pinchbrush.strength=sd->inflatebrush.strength=sd->grabbrush.strength=sd->layerbrush.strength= 25;
+       sd->drawbrush.dir=sd->pinchbrush.dir=sd->inflatebrush.dir=sd->layerbrush.dir= 1;
+       sd->drawbrush.airbrush=sd->smoothbrush.airbrush=sd->pinchbrush.airbrush=sd->inflatebrush.airbrush=sd->layerbrush.airbrush= 0;
+       sd->brush_type= DRAW_BRUSH;
+       sd->texact= -1;
+       sd->texfade= 1;
+       sd->averaging= 1;
+       sd->texsize[0]= sd->texsize[1]= sd->texsize[2]= 1;
+       sd->texrept= SCULPTREPT_DRAG;
+}
+
+/* Free G.sculptdata->vertexusers */
+void sculptmode_free_vertexusers(struct Scene *sce)
+{
+       SculptData *sd;
+
+       if(!sce) return;
+
+       sd= &sce->sculptdata;
+       if(sd->vertex_users){
+               int i;
+               for(i=0; i<sd->vertex_users_size; ++i){
+                       BLI_freelistN(&sd->vertex_users[i]);
+               }
+               MEM_freeN(sd->vertex_users);
+               sd->vertex_users= NULL;
+               sd->vertex_users_size= 0;
+       }
+}
+
+
+typedef struct SculptUndo {
+       struct SculptUndo *next, *prev;
+       char *str;
+       MVert *verts;
+} SculptUndo;
+
+void sculptmode_undo_init()
+{
+       G.scene->sculptdata.undo.first= G.scene->sculptdata.undo.last= NULL;
+       G.scene->sculptdata.undo_cur= NULL;
+       sculptmode_undo_push("Original");
+}
+
+void sculptmode_undo_free_link(SculptUndo *su)
+{
+       MEM_freeN(su->verts);
+       MEM_freeN(su);
+}
+
+void sculptmode_undo_free(Scene *sce)
+{
+       SculptUndo *su;
+       for(su= sce->sculptdata.undo.first; su; su= su->next)
+               MEM_freeN(su->verts);
+       BLI_freelistN(&sce->sculptdata.undo);
+}
+
+void sculptmode_undo_push(char *str)
+{
+       int cnt= 7; /* 8 undo steps */
+       SculptData *sd= &G.scene->sculptdata;
+       SculptUndo *n= MEM_callocN(sizeof(SculptUndo), "SculptUndo"), *su, *chop;
+
+       /* Chop off undo data after cur */
+       for(su= sd->undo.last; su && su != sd->undo_cur; su= su->prev) {
+               su->prev->next= NULL;
+               sculptmode_undo_free_link(su);
+       }
+       sd->undo.last= sd->undo_cur;
+
+       /* Initialize undo data */
+       n->str= str;
+       n->verts= MEM_dupallocN(get_mesh(sd->active_ob)->mvert);
+
+       /* Add new undo step */
+       BLI_addtail(&sd->undo, n);
+
+       /* Chop off undo steps pass MAXSZ */
+       for(chop= sd->undo.last; chop && cnt; chop= chop->prev, --cnt);
+       if(!cnt && chop) {
+               for(su= sd->undo.first; su && su != chop; su= su->next) {
+                       su->next->prev= NULL;
+                       sculptmode_undo_free_link(su);
+               }
+               sd->undo.first= chop;
+       }
+
+       sd->undo_cur= n;
+}
+
+void sculptmode_undo_update()
+{
+       SculptData *sd= &G.scene->sculptdata;
+
+       MEM_freeN(get_mesh(sd->active_ob)->mvert);
+       get_mesh(sd->active_ob)->mvert= MEM_dupallocN(sd->undo_cur->verts);
+
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+void sculptmode_undo()
+{
+       SculptData *sd= &G.scene->sculptdata;
+
+       if(sd->undo_cur->prev)
+               sd->undo_cur= sd->undo_cur->prev;
+
+       sculptmode_undo_update();
+}
+
+void sculptmode_redo()
+{
+       SculptData *sd= &G.scene->sculptdata;
+
+       if(sd->undo_cur->next)
+               sd->undo_cur= sd->undo_cur->next;
+
+       sculptmode_undo_update();
+}
+
+void sculptmode_undo_menu()
+{
+       SculptUndo *su;
+       DynStr *ds= BLI_dynstr_new();
+       char *menu;
+       
+       BLI_dynstr_append(ds, "Sculpt Mode Undo History %t");
+       for(su= G.scene->sculptdata.undo.first; su; su= su->next) {
+               BLI_dynstr_append(ds, "|");
+               BLI_dynstr_append(ds, su->str);
+       }
+       menu= BLI_dynstr_get_cstring(ds);
+       BLI_dynstr_free(ds);
+       
+       if(menu) {
+               short event= pupmenu_col(menu, 20);
+               MEM_freeN(menu);
+
+               if(event>0) {
+                       int a= 1;
+                       for(su= G.scene->sculptdata.undo.first; su; su= su->next, a++)
+                               if(a==event) break;
+                       G.scene->sculptdata.undo_cur= su;
+                       sculptmode_undo_update();
+               }
+       }
+}
+
+void sculptmode_free_all(Scene *sce)
+{
+       SculptData *sd= &sce->sculptdata;
+       int a;
+
+       sculptmode_free_vertexusers(sce);
+       if(sd->texrndr) {
+               if(sd->texrndr->rect) MEM_freeN(sd->texrndr->rect);
+               MEM_freeN(sd->texrndr);
+       }
+       
+       for(a=0; a<MAX_MTEX; a++) {
+               MTex *mtex= sd->mtex[a];
+               if(mtex) {
+                       if(mtex->tex) mtex->tex->id.us--;
+                       MEM_freeN(mtex);
+               }
+       }
+
+       sculptmode_undo_free(sce);
+}
+
+void calc_vertex_users()
+{
+       int i,j;
+       IndexNode *node= 0;
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+
+       sculptmode_free_vertexusers(G.scene);
+
+       /* Allocate an array of ListBases, one per vertex */
+       G.scene->sculptdata.vertex_users= (ListBase*)MEM_mallocN(sizeof(ListBase) * me->totvert, "vertex_users");
+       G.scene->sculptdata.vertex_users_size= me->totvert;
+
+       /* Initialize */
+       for(i=0; i<me->totvert; ++i){
+               G.scene->sculptdata.vertex_users[i].first=G.scene->sculptdata.vertex_users[i].last= 0;
+       }
+
+       /* Find the users */
+       for(i=0; i<me->totface; ++i){
+               for(j=0; j<(me->mface[i].v4?4:3); ++j){
+                       node= (IndexNode*)MEM_mallocN(sizeof(IndexNode), "faceindex");
+                       node->Index=i;
+                       BLI_addtail(&G.scene->sculptdata.vertex_users[((unsigned int*)(&me->mface[i]))[j]], node);
+               }
+       }
+}
+
+void set_sculpt_object(struct Object *ob)
+{
+       G.scene->sculptdata.active_ob= ob;
+
+       if(ob)
+               calc_vertex_users();
+}
+
+/* ===== INTERFACE =====
+ */
+
+void sculptmode_rem_tex(void *junk0,void *junk1)
+{
+       MTex *mtex= G.scene->sculptdata.mtex[G.scene->sculptdata.texact];
+       if(mtex) {
+               mtex->tex->id.us--;
+               G.scene->sculptdata.mtex[G.scene->sculptdata.texact]= 0;
+               BIF_undo_push("Unlink brush texture");
+               allqueue(REDRAWBUTSEDIT, 0);
+               allqueue(REDRAWOOPS, 0);
+       }
+}
+
+/* ===== OPENGL =====
+ *
+ * Simple functions to get data from the GL
+ */
+
+void init_sculptmatrices()
+{
+       glPushMatrix();
+
+       glMatrixMode(GL_MODELVIEW);
+       glMultMatrixf(OBACT->obmat);
+
+       glGetDoublev(GL_MODELVIEW_MATRIX, G.scene->sculptdata.modelviewmat);
+       glGetDoublev(GL_PROJECTION_MATRIX, G.scene->sculptdata.projectionmat);
+       glGetIntegerv(GL_VIEWPORT, G.scene->sculptdata.viewport);
+       /* Set up viewport so that gluUnProject will give correct values */
+       G.scene->sculptdata.viewport[0] = 0;
+       G.scene->sculptdata.viewport[1] = 0;
+
+       glPopMatrix();
+
+}
+
+/* Uses window coordinates (x,y) to find the depth in the GL depth buffer */
+float get_depth(short x, short y)
+{
+       float depth;
+
+       if(x<0 || y<0) return 1;
+       if(x>=curarea->winx || y>=curarea->winy) return 1;
+
+       if(G.vd->depths && x<G.vd->depths->w && y<G.vd->depths->h)
+               return G.vd->depths->depths[y*G.vd->depths->w+x];
+       
+       x+= curarea->winrct.xmin;
+       y+= curarea->winrct.ymin;
+       
+       glReadBuffer(GL_FRONT);
+       glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
+       glReadBuffer(GL_BACK);
+
+       return depth;
+}
+
+/* Uses window coordinates (x,y) and depth component z to find a point in
+   modelspace */
+vec3f unproject(const short x, const short y, const float z)
+{
+       double ux, uy, uz;
+       vec3f p;
+
+        gluUnProject(x,y,z, G.scene->sculptdata.modelviewmat,
+                    G.scene->sculptdata.projectionmat,
+                    G.scene->sculptdata.viewport, &ux, &uy, &uz );
+       p.x= ux;
+       p.y= uy;
+       p.z= uz;
+       return p;
+}
+
+void project(const float v[3], short p[2])
+{
+       double ux, uy, uz;
+
+       gluProject(v[0],v[1],v[2], G.scene->sculptdata.modelviewmat,
+                  G.scene->sculptdata.projectionmat,
+                  G.scene->sculptdata.viewport, &ux, &uy, &uz);
+       p[0]= ux;
+       p[1]= uy;
+}
+
+/* ===== Sculpting =====
+ *
+ */
+
+float brush_strength(EditData *e)
+{
+       const BrushData* b= sculptmode_brush();
+       float dir= b->dir==1 ? 1 : -1;
+       float pressure= 1;
+       const GHOST_TabletData *td= get_tablet_data();
+       float flip= e->flip ? -1:1;
+
+       if(td) {
+               switch(td->Active) {
+               case 1:
+                       pressure= td->Pressure;
+                       break;
+               case 2:
+                       pressure= td->Pressure;
+                       dir = -dir;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       switch(G.scene->sculptdata.brush_type){
+       case DRAW_BRUSH:
+       case LAYER_BRUSH:
+               return b->strength / 5000.0f * dir * pressure * flip;
+       case SMOOTH_BRUSH:
+               return b->strength / 50.0f * pressure;
+       case PINCH_BRUSH:
+               return b->strength / 1000.0f * dir * pressure * flip;
+       case GRAB_BRUSH:
+               return 1;
+       case INFLATE_BRUSH:
+               return b->strength / 5000.0f * dir * pressure * flip;
+       default:
+               return 0;
+       }
+}
+
+/* Currently only for the draw brush; finds average normal for all active
+   vertices */
+vec3f calc_area_normal(const ListBase* active_verts)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       vec3f area_normal= {0,0,0};
+       ActiveData *node= active_verts->first;
+
+       while(node){
+               area_normal.x+= me->mvert[node->Index].no[0];
+               area_normal.y+= me->mvert[node->Index].no[1];
+               area_normal.z+= me->mvert[node->Index].no[2];
+               node= node->next;
+       }
+       Normalise(&area_normal.x);
+       return area_normal;
+}
+void do_draw_brush(const ListBase* active_verts)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       const vec3f area_normal= calc_area_normal(active_verts);
+       ActiveData *node= active_verts->first;
+
+       while(node){
+               me->mvert[node->Index].co[0] += area_normal.x * node->Fade;
+               me->mvert[node->Index].co[1] += area_normal.y * node->Fade;
+               me->mvert[node->Index].co[2] += area_normal.z * node->Fade;
+               node= node->next;
+       }
+}
+
+vec3f neighbor_average(const int vert)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       int i, skip= -1, total=0;
+       IndexNode *node= G.scene->sculptdata.vertex_users[vert].first;
+       vec3f avg= {0,0,0};
+       MFace *f;
+
+       while(node){
+               f= &me->mface[node->Index];
+               if(f->v4) {
+                       skip= (f->v1==vert?2:
+                              f->v2==vert?3:
+                              f->v3==vert?0:
+                              f->v4==vert?1:-1);
+               }
+
+               for(i=0; i<(f->v4?4:3); ++i) {
+                       if(i != skip) {
+                               VecAddf(&avg.x,&avg.x,me->mvert[(&f->v1)[i]].co);
+                               ++total;
+                       }
+               }
+
+               node= node->next;
+       }
+
+       avg.x/= total;
+       avg.y/= total;
+       avg.z/= total;
+
+       return avg;
+}
+
+void do_smooth_brush(const ListBase* active_verts)
+{
+       int cur;
+       ActiveData *node= active_verts->first;
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       vec3f avg;
+
+       while(node){
+               cur= node->Index;
+
+               if(BLI_countlist(&G.scene->sculptdata.vertex_users[cur]) > 2) {
+                       avg.x=avg.y=avg.z= 0;
+                       
+                       avg= neighbor_average(cur);
+                       
+                       me->mvert[cur].co[0]+= (avg.x - me->mvert[cur].co[0])*node->Fade;
+                       me->mvert[cur].co[1]+= (avg.y - me->mvert[cur].co[1])*node->Fade;
+                       me->mvert[cur].co[2]+= (avg.z - me->mvert[cur].co[2])*node->Fade;
+               }
+
+               node= node->next;
+       }
+}
+
+void do_pinch_brush(const ListBase* active_verts, const vec3f* center)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       ActiveData *node= active_verts->first;
+       float* co;
+
+       while(node) {
+               co= me->mvert[node->Index].co;
+               co[0] += (center->x - co[0]) * node->Fade;
+               co[1] += (center->y - co[1]) * node->Fade;
+               co[2] += (center->z - co[2]) * node->Fade;
+               node= node->next;
+       }
+}
+
+void do_grab_brush(EditData *e)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       ActiveData *node= e->grabdata->active_verts[e->grabdata->index].first;
+       float add[3];
+
+       while(node) {
+               VecCopyf(add,&e->grabdata->delta_symm.x);
+               VecMulf(add,node->Fade);
+               VecAddf(me->mvert[node->Index].co,me->mvert[node->Index].co,add);
+
+               node= node->next;
+       }
+}
+
+void do_layer_brush(EditData *e, const ListBase *active_verts)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       vec3f area_normal= calc_area_normal(active_verts);
+       ActiveData *node= active_verts->first;
+       const float bstr= brush_strength(e);
+
+       while(node){
+               float *disp= &e->layer_disps[node->Index];
+               
+               if((bstr > 0 && *disp < bstr) ||
+                 (bstr < 0 && *disp > bstr)) {
+                       *disp+= node->Fade;
+
+                       if(bstr < 0) {
+                               if(*disp < bstr)
+                                       *disp = bstr;
+                       } else {
+                               if(*disp > bstr)
+                                       *disp = bstr;
+                       }
+
+                       me->mvert[node->Index].co[0]= e->layer_store[node->Index].x + area_normal.x * *disp;
+                       me->mvert[node->Index].co[1]= e->layer_store[node->Index].y + area_normal.y * *disp;
+                       me->mvert[node->Index].co[2]= e->layer_store[node->Index].z + area_normal.z * *disp;
+               }
+
+               node= node->next;
+       }
+}
+
+void do_inflate_brush(const ListBase *active_verts)
+{
+       ActiveData *node= active_verts->first;
+       int cur;
+       float add[3];
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       
+       while(node) {
+               cur= node->Index;
+
+               add[0]= me->mvert[cur].no[0]/ 32767.0f;
+               add[1]= me->mvert[cur].no[1]/ 32767.0f;
+               add[2]= me->mvert[cur].no[2]/ 32767.0f;
+               VecMulf(add,node->Fade);
+               VecAddf(me->mvert[cur].co,me->mvert[cur].co,add);
+
+               node= node->next;
+       }
+}
+
+float simple_strength(float p, const float len)
+{
+       if(p > len) p= len;
+       return 0.5f * (cos(3*p/len) + 1);
+}
+
+float tex_strength(EditData *e, float *point, const float len,const unsigned vindex)
+{
+       float avg= 0;
+
+       if(G.scene->sculptdata.texact==-1)
+               avg= 1;
+       else if(G.scene->sculptdata.texrept==SCULPTREPT_3D) {
+               float jnk;
+               MTex mtex;
+               memset(&mtex,0,sizeof(MTex));
+               mtex.tex= G.scene->sculptdata.mtex[G.scene->sculptdata.texact]->tex;
+               mtex.projx= 1;
+               mtex.projy= 2;
+               mtex.projz= 3;
+               mtex.size[0]= G.scene->sculptdata.texsize[0];
+               mtex.size[1]= G.scene->sculptdata.texsize[1];
+               mtex.size[2]= G.scene->sculptdata.texsize[2];
+               
+               externtex(&mtex,point,&avg,&jnk,&jnk,&jnk,&jnk);
+       } else {
+               vec3f t2;
+               float theta, magn;
+               float cx;
+               int px, py;
+               unsigned i;
+               unsigned int *p;
+               RenderInfo *ri= G.scene->sculptdata.texrndr;
+
+               /* If no texture or Default, use smooth curve */
+               if(G.scene->sculptdata.texact == -1 || !G.scene->sculptdata.mtex[G.scene->sculptdata.texact] ||
+                  !G.scene->sculptdata.mtex[G.scene->sculptdata.texact]->tex->type)
+                       return simple_strength(len,e->size);
+
+               /* Find direction from center to point */
+               VecSubf(&t2.x,point,&e->center.x);
+               Normalise(&t2.x);
+
+               theta= e->right.x*t2.x+e->right.y*t2.y+e->right.z*t2.z;
+
+               /* Avoid NaN errors */
+               if( theta < -1 )
+                       theta = -1;
+               else if( theta > 1 )
+                       theta = 1;
+
+               theta = acos( theta );
+
+               /* Checks whether theta should be in the III/IV quadrants using the
+                  dot product with the Up vector */
+               if(e->up.x*t2.x+e->up.y*t2.y+e->up.z*t2.z > 0)
+                       theta = 2 * M_PI - theta;
+
+               magn= len/e->size;
+
+               /* XXX: This code assumes that the texture can be treated as a square */
+
+               /* Find alpha's center, we assume a square */
+               cx= ri->pr_rectx/2.0f;
+
+               /* Scale the magnitude to match the size of the tex */
+               magn*= cx;
+       
+               /* XXX: not sure if this +c business is correct....
+          
+               Find the pixel in the tex */
+               px= magn * cos(theta) + cx;
+               py= magn * sin(theta) + cx;
+
+               if(G.scene->sculptdata.texrept==SCULPTREPT_TILE) {
+                       px+= e->mouse[0];
+                       py+= e->mouse[1];
+                       p= ri->rect + (py%ri->pr_recty) * ri->pr_rectx + (px%ri->pr_rectx);
+                       p= ri->rect + (projverts[vindex].co[1]%ri->pr_recty) * ri->pr_rectx + (projverts[vindex].co[0]%ri->pr_rectx);
+               }
+               else p= ri->rect + py * ri->pr_rectx + px;
+               
+               for(i=0; i<3; ++i)
+                       avg+= ((unsigned char*)(p))[i] / 255.0f;
+
+               avg/= 3;
+       }
+
+       if(G.scene->sculptdata.texfade)
+               avg*= simple_strength(len,e->size); /* Smooth curve */
+
+       return avg;
+}
+
+void sculptmode_add_damaged_rect(EditData *e, ListBase *damaged_rects)
+{
+       short p[2];
+       const float radius= sculptmode_brush()->size;
+       RectNode *rn= MEM_mallocN(sizeof(RectNode),"RectNode");
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       unsigned i;
+
+       /* Find center */
+       project(&e->center.x, p);
+       rn->r.xmin= p[0]-radius;
+       rn->r.ymin= p[1]-radius;
+       rn->r.xmax= p[0]+radius;
+       rn->r.ymax= p[1]+radius;
+
+       BLI_addtail(damaged_rects,rn);
+
+       /* Update insides */
+       for(i=0; i<me->totvert; ++i) {
+               if(!projverts[i].inside) {
+                       if(projverts[i].co[0] > rn->r.xmin && projverts[i].co[1] > rn->r.ymin &&
+                          projverts[i].co[0] < rn->r.xmax && projverts[i].co[1] < rn->r.ymax) {
+                               projverts[i].inside= 1;
+                       }
+               }
+       }
+}
+
+void do_brush_action(float *vertexcosnos, EditData e,
+                    ListBase *damaged_verts, ListBase *damaged_rects)
+{
+       int i;
+       float av_dist;
+       ListBase active_verts={0,0};
+       ActiveData *adata= 0;
+       float *vert;
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       const float bstrength= brush_strength(&e);
+
+       sculptmode_add_damaged_rect(&e,damaged_rects);
+
+       if(!e.grabdata || (e.grabdata && e.grabdata->firsttime)) {
+               /* Find active vertices */
+               for(i=0; i<me->totvert; ++i)
+               {
+                       if(projverts[i].inside) {
+                               vert= vertexcosnos ? &vertexcosnos[i*6] : me->mvert[i].co;
+                               av_dist= VecLenf(&e.center.x,vert);
+                               if( av_dist < e.size )
+                               {
+                                       adata= (ActiveData*)MEM_mallocN(sizeof(ActiveData), "ActiveData");
+                                       adata->Index = i;
+                                       adata->Fade= tex_strength(&e,vert,av_dist,i) * bstrength;
+                                       if(e.grabdata && e.grabdata->firsttime)
+                                               BLI_addtail(&e.grabdata->active_verts[e.grabdata->index], adata);
+                                       else
+                                               BLI_addtail(&active_verts, adata);
+                               }
+                       }
+               }
+       }
+
+       switch(G.scene->sculptdata.brush_type){
+       case DRAW_BRUSH:
+               do_draw_brush(&active_verts);
+               break;
+       case SMOOTH_BRUSH:
+               do_smooth_brush(&active_verts);
+               break;
+       case PINCH_BRUSH:
+               do_pinch_brush(&active_verts, &e.center);
+               break;
+       case INFLATE_BRUSH:
+               do_inflate_brush(&active_verts);
+               break;
+       case GRAB_BRUSH:
+               do_grab_brush(&e);
+               break;
+       case LAYER_BRUSH:
+               do_layer_brush(&e, &active_verts);
+               break;
+       }
+
+       if(vertexcosnos)
+               BLI_freelistN(&active_verts);
+       else {
+               if(!e.grabdata)
+                       addlisttolist(damaged_verts, &active_verts);
+       }
+}
+
+EditData flip_editdata(EditData *e, short x, short y, short z)
+{
+       EditData fe= *e;
+       GrabData *gd= fe.grabdata;
+       if(x) {
+               fe.center.x= -fe.center.x;
+               fe.up.x= -fe.up.x;
+               fe.right.x= -fe.right.x;
+       }
+
+       if(y) {
+               fe.center.y= -fe.center.y;
+               fe.up.y= -fe.up.y;
+               fe.right.y= -fe.right.y;
+       }
+
+       if(z) {
+               fe.center.z= -fe.center.z;
+               fe.up.z= -fe.up.z;
+               fe.right.z= -fe.right.z;
+       }
+
+       project(&fe.center.x,fe.mouse);
+
+       if(gd) {
+               gd->index= x + y*2 + z*4;
+               gd->delta_symm= gd->delta;
+               if(x) gd->delta_symm.x= -gd->delta_symm.x;
+               if(y) gd->delta_symm.y= -gd->delta_symm.y;
+               if(z) gd->delta_symm.z= -gd->delta_symm.z;
+       }
+
+       return fe;
+}
+
+void do_symmetrical_brush_actions(float *vertexcosnos, EditData *e,
+                                 ListBase *damaged_verts, ListBase *damaged_rects)
+{
+       const SculptData *sd= &G.scene->sculptdata;
+
+       do_brush_action(vertexcosnos,flip_editdata(e,0,0,0),damaged_verts,damaged_rects);
+
+       if(sd->symm_x)
+               do_brush_action(vertexcosnos,flip_editdata(e,1,0,0),damaged_verts,damaged_rects);
+       if(sd->symm_y)
+               do_brush_action(vertexcosnos,flip_editdata(e,0,1,0),damaged_verts,damaged_rects);
+       if(sd->symm_z)
+               do_brush_action(vertexcosnos,flip_editdata(e,0,0,1),damaged_verts,damaged_rects);
+       if(sd->symm_x && sd->symm_y)
+               do_brush_action(vertexcosnos,flip_editdata(e,1,1,0),damaged_verts,damaged_rects);
+       if(sd->symm_x && sd->symm_z)
+               do_brush_action(vertexcosnos,flip_editdata(e,1,0,1),damaged_verts,damaged_rects);
+       if(sd->symm_y && sd->symm_z)
+               do_brush_action(vertexcosnos,flip_editdata(e,0,1,1),damaged_verts,damaged_rects);
+       if(sd->symm_x && sd->symm_y && sd->symm_z)
+               do_brush_action(vertexcosnos,flip_editdata(e,1,1,1),damaged_verts,damaged_rects);
+}
+
+void add_face_normal(vec3f *norm, const MFace* face)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+
+       vec3f c= {me->mvert[face->v1].co[0],me->mvert[face->v1].co[1],me->mvert[face->v1].co[2]};
+       vec3f b= {me->mvert[face->v2].co[0],me->mvert[face->v2].co[1],me->mvert[face->v2].co[2]};
+       vec3f a= {me->mvert[face->v3].co[0],me->mvert[face->v3].co[1],me->mvert[face->v3].co[2]};
+       vec3f s1, s2;
+
+       VecSubf(&s1.x,&a.x,&b.x);
+       VecSubf(&s2.x,&c.x,&b.x);
+
+       norm->x+= s1.y * s2.z - s1.z * s2.y;
+       norm->y+= s1.z * s2.x - s1.x * s2.z;
+       norm->z+= s1.x * s2.y - s1.y * s2.x;
+}
+
+void update_damaged_vert(Mesh *me, ListBase *lb)
+{
+       ActiveData *vert;
+       
+       for(vert= lb->first; vert; vert= vert->next) {
+               vec3f norm= {0,0,0};            
+               IndexNode *face= G.scene->sculptdata.vertex_users[vert->Index].first;
+
+               while(face){
+                       add_face_normal(&norm,&me->mface[face->Index]);
+                       face= face->next;
+               }
+               Normalise(&norm.x);
+               
+               me->mvert[vert->Index].no[0]=norm.x*32767;
+               me->mvert[vert->Index].no[1]=norm.y*32767;
+               me->mvert[vert->Index].no[2]=norm.z*32767;
+       }
+}
+
+void calc_damaged_verts(ListBase *damaged_verts, GrabData *grabdata)
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+
+       if(grabdata) {
+               int i;
+               for(i=0; i<8; ++i)
+                       update_damaged_vert(me,&grabdata->active_verts[i]);
+       } else {
+               update_damaged_vert(me,damaged_verts);
+               BLI_freelistN(damaged_verts);
+       }
+}
+
+BrushData *sculptmode_brush()
+{
+       SculptData *sd= &G.scene->sculptdata;
+       return (sd->brush_type==DRAW_BRUSH ? &sd->drawbrush :
+               sd->brush_type==SMOOTH_BRUSH ? &sd->smoothbrush :
+               sd->brush_type==PINCH_BRUSH ? &sd->pinchbrush :
+               sd->brush_type==INFLATE_BRUSH ? &sd->inflatebrush :
+               sd->brush_type==GRAB_BRUSH ? &sd->grabbrush :
+               sd->brush_type==LAYER_BRUSH ? &sd->layerbrush : NULL);
+}
+
+void sculptmode_update_tex()
+{
+       SculptData *sd= &G.scene->sculptdata;
+       RenderInfo *ri= sd->texrndr;
+
+       /* Skip Default brush shape and non-textures */
+       if(sd->texact == -1 || !sd->mtex[sd->texact]) return;
+
+       if(!ri) {
+               ri= MEM_callocN(sizeof(RenderInfo),"brush texture render");
+               sd->texrndr= ri;
+       }
+
+       if(ri->rect) {
+               MEM_freeN(ri->rect);
+               ri->rect= NULL;
+       }
+
+       ri->curtile= 0;
+       ri->tottile= 0;
+       if(ri->rect) MEM_freeN(ri->rect);
+       ri->rect = NULL;
+       ri->pr_rectx = 128; /* FIXME: might want to allow higher/lower sizes */
+       ri->pr_recty = 128;
+
+       BIF_previewrender(&sd->mtex[sd->texact]->tex->id, ri, NULL, PR_ICON_RENDER);
+}
+
+void init_editdata(SculptData *sd, EditData *e, short *mouse, short *pr_mouse, const char flip)
+{
+       const float mouse_depth= get_depth(mouse[0],mouse[1]);
+       vec3f brush_edge_loc, zero_loc, oldloc;
+
+       e->flip= flip;
+       
+       /* Convert the location and size of the brush to
+          modelspace coords */
+       e->center= unproject(mouse[0],mouse[1],mouse_depth);
+       brush_edge_loc= unproject(mouse[0] +
+                                 sculptmode_brush()->size,mouse[1],
+                                 mouse_depth);
+       e->size= VecLenf(&e->center.x,&brush_edge_loc.x);
+
+       /* Now project the Up and Right normals from view to model coords */
+       zero_loc= unproject(0,0,0);
+       e->up= unproject(0,-1,0);
+       e->right= unproject(1,0,0);
+       VecSubf(&e->up.x,&e->up.x,&zero_loc.x);
+       VecSubf(&e->right.x,&e->right.x,&zero_loc.x);
+       Normalise(&e->up.x);
+       Normalise(&e->right.x);
+
+       if(sd->brush_type == GRAB_BRUSH) {
+               vec3f gcenter;
+               if(!e->grabdata) {
+                       e->grabdata= MEM_callocN(sizeof(GrabData),"grab data");
+                       e->grabdata->firsttime= 1;
+                       e->grabdata->depth= mouse_depth;
+               }
+               else
+                       e->grabdata->firsttime= 0;
+               
+               /* Find the delta */
+               gcenter= unproject(mouse[0],mouse[1],e->grabdata->depth);
+               oldloc= unproject(pr_mouse[0],pr_mouse[1],e->grabdata->depth);
+               VecSubf(&e->grabdata->delta.x,&gcenter.x,&oldloc.x);
+       }
+       else if(sd->brush_type == LAYER_BRUSH) {
+               Mesh *me= get_mesh(sd->active_ob);
+
+               if(!e->layer_disps)
+                       e->layer_disps= MEM_callocN(sizeof(float)*me->totvert,"Layer disps");
+               if(!e->layer_store) {
+                       unsigned i;
+                       e->layer_store= MEM_mallocN(sizeof(vec3f)*me->totvert,"Layer store");
+                       for(i=0; i<me->totvert; ++i)
+                               VecCopyf(&e->layer_store[i].x,me->mvert[i].co);
+               }
+       }
+}
+
+void sculptmode_set_strength(const int delta)
+{
+       int val = sculptmode_brush()->strength + delta;
+       if(val < 1) val = 1;
+       if(val > 100) val = 100;
+       sculptmode_brush()->strength= val;
+}
+
+void sculptmode_propset(unsigned short event)
+{
+       PropsetData *pd= NULL;
+       short mouse[2];
+       short tmp[2];
+       const int tsz = 128;
+
+       /* Initialize */
+       if(!G.scene->sculptdata.propset_data) {
+               if(G.scene->sculptdata.propset==1) {
+                       float *d= MEM_mallocN(sizeof(float)*tsz*tsz, "Brush preview");
+                       int i,j;
+
+
+                       G.scene->sculptdata.propset_data= MEM_callocN(sizeof(PropsetData),"PropsetSize");
+                       pd= G.scene->sculptdata.propset_data;
+                       getmouseco_areawin(mouse);
+                       pd->origloc[0]= mouse[0];
+                       pd->origloc[1]= mouse[1];
+                       pd->origsize= sculptmode_brush()->size;
+                       pd->origstrength= sculptmode_brush()->strength;
+
+                       /* Prepare texture */
+                       glGenTextures(1, &pd->tex);
+                       glBindTexture(GL_TEXTURE_2D, pd->tex);
+
+                       if(G.scene->sculptdata.texrept!=SCULPTREPT_3D)
+                               sculptmode_update_tex();
+
+                       for(i=0; i<tsz; ++i)
+                               for(j=0; j<tsz; ++j)
+                                       d[i*tsz+j]= simple_strength(sqrt(pow(i-tsz/2,2)+pow(j-tsz/2,2)),tsz/2);
+                       if(G.scene->sculptdata.texrndr) {
+                               for(i=0; i<tsz; ++i)
+                                       for(j=0; j<tsz; ++j) {
+                                               const int col= G.scene->sculptdata.texrndr->rect[i*tsz+j];
+                                               d[i*tsz+j]*= (((char*)&col)[0]+((char*)&col)[1]+((char*)&col)[2])/3.0f/255.0f;
+                                       }
+                       }
+
+                       glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tsz, tsz, 0, GL_ALPHA, GL_FLOAT, d);
+                       MEM_freeN(d);
+               }
+       }
+
+       pd= G.scene->sculptdata.propset_data;
+
+       switch(event) {
+       case MOUSEX:
+       case MOUSEY:
+               getmouseco_areawin(mouse);
+               tmp[0]= pd->origloc[0]-mouse[0];
+               tmp[1]= pd->origloc[1]-mouse[1];
+               sculptmode_brush()->size= sqrt(tmp[0]*tmp[0]+tmp[1]*tmp[1]);
+               if(sculptmode_brush()->size>200) sculptmode_brush()->size= 200;
+               allqueue(REDRAWVIEW3D, 0);
+               break;
+       case WHEELUPMOUSE:
+               sculptmode_set_strength(5);
+               allqueue(REDRAWVIEW3D, 0);
+               break;
+       case WHEELDOWNMOUSE:
+               sculptmode_set_strength(-5);
+               allqueue(REDRAWVIEW3D, 0);
+               break;
+       case ESCKEY:
+       case RIGHTMOUSE:
+               sculptmode_brush()->size= pd->origsize;
+               sculptmode_brush()->strength= pd->origstrength;
+       case LEFTMOUSE:
+               while(get_mbut()==L_MOUSE);
+       case RETKEY:
+       case PADENTER:
+               //glDeleteTextures(1, &pd->tex);
+               G.scene->sculptdata.propset= 0;
+               MEM_freeN(pd);
+               G.scene->sculptdata.propset_data= NULL;
+               allqueue(REDRAWVIEW3D, 0);
+               allqueue(REDRAWBUTSEDIT, 0);
+               break;
+       default:
+               break;
+       };
+}
+
+void sculptmode_selectbrush_menu()
+{
+       SculptData *sd= &G.scene->sculptdata;
+       int val;
+       
+       pupmenu_set_active(sd->brush_type);
+       
+       val= pupmenu("Select Brush%t|Draw|Smooth|Pinch|Inflate|Grab|Layer");
+
+       if(val>0) {
+               sd->brush_type= val;
+               
+               allqueue(REDRAWVIEW3D, 1);
+               allqueue(REDRAWBUTSEDIT, 1);
+       }
+}
+
+void sculptmode_update_all_projverts()
+{
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       unsigned i;
+
+       if(projverts) MEM_freeN(projverts);
+       projverts= MEM_mallocN(sizeof(ProjVert)*me->totvert,"ProjVerts");
+       for(i=0; i<me->totvert; ++i) {
+               project(me->mvert[i].co, projverts[i].co);
+               projverts[i].inside= 0;
+       }
+}
+
+void sculptmode_draw_wires(char only_damaged, Mesh *me)
+{
+       int i;
+
+       bglPolygonOffset(1.0);
+       glDepthMask(0);
+       BIF_ThemeColor((G.scene->sculptdata.active_ob==OBACT)?TH_ACTIVE:TH_SELECT);
+
+       for(i=0; i<me->totedge; i++) {
+               MEdge *med= &me->medge[i];
+
+               if((!only_damaged || (projverts[med->v1].inside || projverts[med->v2].inside)) &&
+                  (med->flag & ME_EDGEDRAW)) {
+                       glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, &med->v1);
+               }
+       }
+
+       glDepthMask(1);
+       bglPolygonOffset(0.0);
+}
+
+void sculptmode_draw_mesh(ListBase *damaged_rects) {
+       Mesh *me= get_mesh(G.scene->sculptdata.active_ob);
+       SculptData *sd= &G.scene->sculptdata;
+       int i, j, dt;
+
+       persp(PERSP_VIEW);
+       mymultmatrix(sd->active_ob->obmat);
+       glEnable(GL_DEPTH_TEST);
+       glEnable(GL_LIGHTING);
+       init_gl_materials(sd->active_ob, 0);
+
+       glShadeModel(GL_SMOOTH);
+
+       glVertexPointer(3, GL_FLOAT, sizeof(MVert), &me->mvert[0].co);
+       glNormalPointer(GL_SHORT, sizeof(MVert), &me->mvert[0].no);
+
+       dt= MIN2(G.vd->drawtype, G.scene->sculptdata.active_ob->dt);
+       if(dt==OB_WIRE)
+               glColorMask(0,0,0,0);
+
+       /* Only draw faces within the modified areas of the screen */
+       if(damaged_rects) {
+               for(i=0; i<me->totface; ++i) {
+                       MFace *f= &me->mface[i];
+                       char inside= 0;
+                       for(j=0; j<(f->v4?4:3); ++j) {
+                               if(projverts[*((&f->v1)+j)].inside) {
+                                       inside= 1;
+                                       break;
+                               }
+                       }
+                       if(inside)
+                               glDrawElements(f->v4?GL_QUADS:GL_TRIANGLES,f->v4?4:3,GL_UNSIGNED_INT,&f->v1);
+               }
+               glEnd();
+       }
+       else { /* Draw entire model */
+               for(i=0; i<me->totface; ++i) {
+                       const char q= me->mface[i].v4?1:0;
+                       glDrawElements(q?GL_QUADS:GL_TRIANGLES,q?4:3,GL_UNSIGNED_INT,&me->mface[i].v1);
+               }
+       }
+
+       glDisable(GL_LIGHTING);
+       glColorMask(1,1,1,1);
+
+       if(dt==OB_WIRE || (sd->active_ob->dtx & OB_DRAWWIRE))
+               sculptmode_draw_wires(0, me);
+
+       glDisable(GL_DEPTH_TEST);
+}
+
+void sculpt()
+{
+       Object *ob= 0;
+       short mouse[2], mvalo[2], firsttime=1, mousebut;
+       ListBase damaged_verts= {0,0};
+       ListBase damaged_rects= {0,0};
+       float *vertexcosnos= 0;
+       short modifier_calculations= 0;
+       EditData e;
+       RectNode *rn= NULL;
+       SculptData *sd= &G.scene->sculptdata;
+       short spacing= 32000;
+
+       if((G.f & G_SCULPTMODE)==0) return;
+       if(G.obedit) return;
+       
+       ob= OBACT;
+       if(ob->id.lib) return;
+
+       /* Make sure that the active mesh is set correctly */
+       if(get_mesh(G.scene->sculptdata.active_ob) != get_mesh(ob))
+               set_sculpt_object(ob);
+               
+       glEnableClientState(GL_VERTEX_ARRAY);
+       glEnableClientState(GL_NORMAL_ARRAY);
+
+       if(!G.scene->sculptdata.active_ob || !get_mesh(G.scene->sculptdata.active_ob) ||
+          get_mesh(G.scene->sculptdata.active_ob)->totface==0) return;
+
+       if(ob->lay & G.vd->lay); else error("Active object is not in this layer");
+
+       persp(PERSP_VIEW);
+       
+       getmouseco_areawin(mvalo);
+
+       /* Make sure sculptdata has been init'd properly */
+       if(!G.scene->sculptdata.vertex_users) calc_vertex_users();
+       
+       /* Init texture
+          FIXME: Shouldn't be doing this every time! */
+       if(sd->texrept!=SCULPTREPT_3D)
+               sculptmode_update_tex();
+
+       getmouseco_areawin(mouse);
+       mvalo[0]= mouse[0];
+       mvalo[1]= mouse[1];
+
+       if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
+       else mousebut = L_MOUSE;
+
+       /* If modifier_calculations is true, then extra time must be spent
+          updating the mesh. This takes a *lot* longer, so it's worth
+          skipping if the modifier stack is empty. */
+       modifier_calculations= modifiers_getVirtualModifierList(ob) != NULL;
+
+       init_sculptmatrices();
+
+       sculptmode_update_all_projverts();
+
+       e.grabdata= NULL;
+       e.layer_disps= NULL;
+       e.layer_store= NULL;
+
+       /* Capture original copy */
+       glAccum(GL_LOAD, 1);
+
+       while (get_mbut() & mousebut) {
+               getmouseco_areawin(mouse);
+               
+               if(firsttime || mouse[0]!=mvalo[0] || mouse[1]!=mvalo[1] || sculptmode_brush()->airbrush) {
+                       firsttime= 0;
+
+                       spacing+= sqrt(pow(mvalo[0]-mouse[0],2)+pow(mvalo[1]-mouse[1],2));
+
+                       if(modifier_calculations)
+                               vertexcosnos= mesh_get_mapped_verts_nors(ob);
+
+                       if(G.scene->sculptdata.brush_type != GRAB_BRUSH && (sd->spacing==0 || spacing>sd->spacing)) {
+                               char i;
+                               float t= G.scene->sculptdata.averaging-1;
+                               const float sub= 1/(t+1);
+                               t/= (t+1);
+                               for(i=0; i<G.scene->sculptdata.averaging; ++i) {
+                                       short avgco[2]= {mvalo[0]*t+mouse[0]*(1-t),
+                                                        mvalo[1]*t+mouse[1]*(1-t)};
+                                       
+                                       init_editdata(&G.scene->sculptdata,&e,avgco,mvalo,get_qual()==LR_SHIFTKEY);
+                                       
+                                       if(get_depth(mouse[0],mouse[1]) < 1.0)
+                                               G.scene->sculptdata.pivot= e.center;
+                                       
+                                       /* The brush always has at least one area it affects,
+                                          right beneath the mouse. It can have up to seven
+                                          other areas that must also be modified, if all three
+                                          axes of symmetry are on. */
+                                       do_symmetrical_brush_actions(vertexcosnos,&e,&damaged_verts,&damaged_rects);
+
+                                       t-= sub;
+                               }
+                               spacing= 0;
+                       }
+                       else if(sd->brush_type==GRAB_BRUSH) {
+                               init_editdata(&G.scene->sculptdata,&e,mouse,mvalo,0);
+                               G.scene->sculptdata.pivot= unproject(mouse[0],mouse[1],e.grabdata->depth);
+                               do_symmetrical_brush_actions(vertexcosnos,&e,&damaged_verts,&damaged_rects);
+                       }
+
+                       if(modifier_calculations || sd->brush_type == GRAB_BRUSH) {
+                               calc_damaged_verts(&damaged_verts,e.grabdata);
+
+                               scrarea_do_windraw(curarea);
+                               persp(PERSP_WIN);
+                               fdrawXORcirc((float)mouse[0],(float)mouse[1],sculptmode_brush()->size);
+                               screen_swapbuffers();
+                               backdrawview3d(0);
+                       } else {
+                               calc_damaged_verts(&damaged_verts,e.grabdata);
+
+                               for(rn=damaged_rects.first; rn; rn= rn->next) {
+                                       float col[3];
+                                       rcti clp= rn->r;
+                                       rcti *win= &curarea->winrct;
+                                       
+                                       clp.xmin+= win->xmin;
+                                       clp.xmax+= win->xmin;
+                                       clp.ymin+= win->ymin;
+                                       clp.ymax+= win->ymin;
+                                       
+                                       if(clp.xmin<win->xmax && clp.xmax>win->xmin &&
+                                          clp.ymin<win->ymax && clp.ymax>win->ymin) {
+                                               if(clp.xmin<win->xmin) clp.xmin= win->xmin;
+                                               if(clp.ymin<win->ymin) clp.ymin= win->ymin;
+                                               if(clp.xmax>win->xmax) clp.xmax= win->xmax;
+                                               if(clp.ymax>win->ymax) clp.ymax= win->ymax;
+                                               glScissor(clp.xmin+1, clp.ymin+1,
+                                                         clp.xmax-clp.xmin-2,clp.ymax-clp.ymin-2);
+                                       }
+                                       
+                                       BIF_GetThemeColor3fv(TH_BACK, col);
+                                       glClearColor(col[0], col[1], col[2], 0.0);
+                                       glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
+                               }
+                               glDisable(GL_SCISSOR_TEST);
+                               
+                               sculptmode_draw_mesh(&damaged_rects);
+
+                               glAccum(GL_LOAD, 1);
+                               
+                               /* Draw cursor */
+                               persp(PERSP_WIN);
+                               glDisable(GL_DEPTH_TEST);
+                               fdrawXORcirc((float)mouse[0],(float)mouse[1],sculptmode_brush()->size);
+                               glRasterPos2i(0, 0);
+                               myswapbuffers();
+                               glAccum(GL_RETURN, 1);
+                               
+                               glEnable(GL_SCISSOR_TEST);
+                       }
+
+                       BLI_freelistN(&damaged_rects);
+       
+                       mvalo[0]= mouse[0];
+                       mvalo[1]= mouse[1];
+
+                       if(modifier_calculations)
+                               MEM_freeN(vertexcosnos);
+               }
+               else BIF_wait_for_statechange();
+       }
+
+       if(projverts) MEM_freeN(projverts);
+       projverts= NULL;
+       if(e.layer_disps) MEM_freeN(e.layer_disps);
+       if(e.layer_store) MEM_freeN(e.layer_store);
+       /* Free GrabData */
+       if(e.grabdata) {
+               int i;
+               for(i=0; i<8; ++i)
+                       BLI_freelistN(&e.grabdata->active_verts[i]);
+               MEM_freeN(e.grabdata);
+       }
+
+       switch(G.scene->sculptdata.brush_type) {
+       case DRAW_BRUSH:
+               sculptmode_undo_push("Draw Brush"); break;
+       case SMOOTH_BRUSH:
+               sculptmode_undo_push("Smooth Brush"); break;
+       case PINCH_BRUSH:
+               sculptmode_undo_push("Pinch Brush"); break;
+       case INFLATE_BRUSH:
+               sculptmode_undo_push("Inflate Brush"); break;
+       case GRAB_BRUSH:
+               sculptmode_undo_push("Grab Brush"); break;
+       case LAYER_BRUSH:
+               sculptmode_undo_push("Layer Brush"); break;
+       default:
+               sculptmode_undo_push("Sculpting"); break;
+       }
+
+       if(G.vd->depths) G.vd->depths->damaged= 1;
+       
+       allqueue(REDRAWVIEW3D, 0);
+}
+
+void set_sculptmode()
+{
+       if(G.f & G_SCULPTMODE) {
+               G.f &= ~G_SCULPTMODE;
+
+               set_sculpt_object(NULL);
+
+               sculptmode_undo_free(G.scene);
+
+               DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+       } else {
+               G.f |= G_SCULPTMODE;
+
+               if(!sculptmode_brush())
+                       sculptmode_init(G.scene);
+
+               if(G.vd->twflag) G.vd->twflag= 0;
+
+               set_sculpt_object(OBACT);
+
+               sculptmode_undo_init();
+               
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnableClientState(GL_NORMAL_ARRAY);
+
+               allqueue(REDRAWVIEW3D,0);
+       }
+
+       allqueue(REDRAWBUTSEDIT, 0);
+}
+
+/* Partial Mesh Visibility */
+void sculptmode_revert_pmv(Mesh *me)
+{
+       if(me->pv) {
+               unsigned i;
+               MVert *nve;
+
+               /* Temporarily exit sculptmode */
+               set_sculpt_object(NULL);
+
+               /* Reorder vertices */
+               nve= me->mvert;
+               me->mvert= MEM_mallocN(sizeof(MVert)*me->pv->totvert,"PMV revert verts");
+               me->totvert= me->pv->totvert;
+               for(i=0; i<me->totvert; ++i)
+                       me->mvert[i]= nve[me->pv->vert_map[i]];
+               MEM_freeN(nve);
+
+               /* Restore edges and faces */
+               MEM_freeN(me->mface);
+               MEM_freeN(me->medge);
+               me->totface= me->pv->totface;
+               me->totedge= me->pv->totedge;
+               me->mface= me->pv->old_faces;
+               me->medge= me->pv->old_edges;
+               me->pv->old_faces= NULL;
+               me->pv->old_edges= NULL;
+
+               /* Free maps */
+               MEM_freeN(me->pv->edge_map);
+               me->pv->edge_map= NULL;
+               MEM_freeN(me->pv->vert_map);
+               me->pv->vert_map= NULL;
+
+               DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+       }
+}
+
+void sculptmode_pmv_off(Mesh *me)
+{
+       if(me->pv) {
+               sculptmode_revert_pmv(me);
+               MEM_freeN(me->pv);
+               me->pv= NULL;
+       }
+}
+
+/* mode: 0=hide outside selection, 1=hide inside selection */
+void sculptmode_do_pmv(Object *ob, rcti *hb_2d, int mode)
+{
+       Mesh *me= get_mesh(OBACT);
+       vec3f hidebox[6];
+       vec3f plane_normals[4];
+       float plane_ds[4];
+       unsigned i, j;
+       unsigned ndx_show, ndx_hide;
+       MVert *nve;
+       unsigned face_cnt_show= 0, face_ndx_show= 0;
+       unsigned edge_cnt_show= 0, edge_ndx_show= 0;
+       unsigned *old_map= NULL;
+       const unsigned SHOW= 0, HIDE=1;
+
+       /* Convert hide box from 2D to 3D */
+       hidebox[0]= unproject(hb_2d->xmin, hb_2d->ymax, 1);
+       hidebox[1]= unproject(hb_2d->xmax, hb_2d->ymax, 1);
+       hidebox[2]= unproject(hb_2d->xmax, hb_2d->ymin, 1);
+       hidebox[3]= unproject(hb_2d->xmin, hb_2d->ymin, 1);
+       hidebox[4]= unproject(hb_2d->xmin, hb_2d->ymax, 0);
+       hidebox[5]= unproject(hb_2d->xmax, hb_2d->ymin, 0);
+       
+       /* Calculate normals for each side of hide box */
+       CalcNormFloat(&hidebox[0].x,&hidebox[1].x,&hidebox[4].x,&plane_normals[0].x);
+       CalcNormFloat(&hidebox[1].x,&hidebox[2].x,&hidebox[5].x,&plane_normals[1].x);
+       CalcNormFloat(&hidebox[2].x,&hidebox[3].x,&hidebox[5].x,&plane_normals[2].x);
+       CalcNormFloat(&hidebox[3].x,&hidebox[0].x,&hidebox[4].x,&plane_normals[3].x);
+       
+       /* Calculate D for each side of hide box */
+       for(i= 0; i<4; ++i)
+               plane_ds[i]= hidebox[i].x*plane_normals[i].x + hidebox[i].y*plane_normals[i].y +
+                       hidebox[i].z*plane_normals[i].z;
+       
+       /* Add partial visibility to mesh */
+       if(!me->pv) {
+               me->pv= MEM_callocN(sizeof(PartialVisibility),"PartialVisibility");
+       } else {
+               old_map= MEM_callocN(sizeof(unsigned)*me->pv->totvert,"PMV oldmap");
+               for(i=0; i<me->pv->totvert; ++i) {
+                       old_map[i]= me->pv->vert_map[i]<me->totvert?0:1;
+               }
+               sculptmode_revert_pmv(me);
+       }
+       
+       /* Kill sculpt data */
+       set_sculpt_object(NULL);
+       
+       /* Initalize map with which verts are to be hidden */
+       me->pv->vert_map= MEM_mallocN(sizeof(unsigned)*me->totvert, "PMV vertmap");
+       me->pv->totvert= me->totvert;
+       me->totvert= 0;
+       for(i=0; i<me->pv->totvert; ++i) {
+               me->pv->vert_map[i]= mode ? HIDE:SHOW;
+               for(j=0; j<4; ++j) {
+                       if(me->mvert[i].co[0] * plane_normals[j].x +
+                          me->mvert[i].co[1] * plane_normals[j].y +
+                          me->mvert[i].co[2] * plane_normals[j].z < plane_ds[j] ) {
+                               me->pv->vert_map[i]= mode ? SHOW:HIDE; /* Vert is outside the hide box */
+                               break;
+                       }
+               }
+               if(old_map && old_map[i]) me->pv->vert_map[i]= 1;
+               if(!me->pv->vert_map[i]) ++me->totvert;
+
+       }
+       if(old_map) MEM_freeN(old_map);
+
+       /* Find out how many faces to show */
+       for(i=0; i<me->totface; ++i) {
+               if(!me->pv->vert_map[me->mface[i].v1] &&
+                  !me->pv->vert_map[me->mface[i].v2] &&
+                  !me->pv->vert_map[me->mface[i].v3]) {
+                       if(me->mface[i].v4) {
+                               if(!me->pv->vert_map[me->mface[i].v4])
+                                       ++face_cnt_show;
+                       }
+                       else ++face_cnt_show;
+               }
+       }
+       /* Find out how many edges to show */
+       for(i=0; i<me->totedge; ++i) {
+               if(!me->pv->vert_map[me->medge[i].v1] &&
+                  !me->pv->vert_map[me->medge[i].v2])
+                       ++edge_cnt_show;
+       }
+
+       /* Create new vert array and reset each vert's map with map[old]=new index */
+       nve= MEM_mallocN(sizeof(MVert)*me->pv->totvert, "PMV verts");
+       ndx_show= 0; ndx_hide= me->totvert;
+       for(i=0; i<me->pv->totvert; ++i) {
+               if(me->pv->vert_map[i]) {
+                       me->pv->vert_map[i]= ndx_hide;
+                       nve[me->pv->vert_map[i]]= me->mvert[i];
+                       ++ndx_hide;
+               } else {
+                       me->pv->vert_map[i]= ndx_show;
+                       nve[me->pv->vert_map[i]]= me->mvert[i];
+                       ++ndx_show;
+               }
+       }
+       MEM_freeN(me->mvert);
+       me->mvert= nve;
+
+       /* Create new face array */
+       me->pv->old_faces= me->mface;
+       me->pv->totface= me->totface;
+       me->mface= MEM_mallocN(sizeof(MFace)*face_cnt_show, "PMV faces");
+       for(i=0; i<me->totface; ++i) {
+               MFace *pr_f= &me->pv->old_faces[i];
+               char show= 0;
+
+               if(me->pv->vert_map[pr_f->v1] < me->totvert &&
+                  me->pv->vert_map[pr_f->v2] < me->totvert &&
+                  me->pv->vert_map[pr_f->v3] < me->totvert) {
+                       if(pr_f->v4) {
+                               if(me->pv->vert_map[pr_f->v4] < me->totvert)
+                                       show= 1;
+                       }
+                       else show= 1;
+               }
+
+               if(show) {
+                       MFace *cr_f= &me->mface[face_ndx_show];
+                       *cr_f= *pr_f;
+                       cr_f->v1= me->pv->vert_map[pr_f->v1];
+                       cr_f->v2= me->pv->vert_map[pr_f->v2];
+                       cr_f->v3= me->pv->vert_map[pr_f->v3];
+                       cr_f->v4= pr_f->v4 ? me->pv->vert_map[pr_f->v4] : 0;
+                       test_index_face(cr_f,NULL,NULL,pr_f->v4?4:3);
+                       ++face_ndx_show;
+               }
+       }
+       me->totface= face_cnt_show;
+
+       /* Create new edge array */
+       me->pv->old_edges= me->medge;
+       me->pv->totedge= me->totedge;
+       me->medge= MEM_mallocN(sizeof(MEdge)*edge_cnt_show, "PMV edges");
+       me->pv->edge_map= MEM_mallocN(sizeof(int)*me->pv->totedge,"PMV edgemap");
+       for(i=0; i<me->totedge; ++i) {
+               if(me->pv->vert_map[me->pv->old_edges[i].v1] < me->totvert &&
+                  me->pv->vert_map[me->pv->old_edges[i].v2] < me->totvert) {
+                       MEdge *cr_e= &me->medge[edge_ndx_show];
+                       me->pv->edge_map[i]= edge_ndx_show;
+                       *cr_e= me->pv->old_edges[i];
+                       cr_e->v1= me->pv->vert_map[me->pv->old_edges[i].v1];
+                       cr_e->v2= me->pv->vert_map[me->pv->old_edges[i].v2];
+                       ++edge_ndx_show;
+               }
+               else me->pv->edge_map[i]= -1;
+       }
+       me->totedge= edge_cnt_show;
+
+       DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+}
+
+rcti sculptmode_pmv_box()
+{
+       short down[2], mouse[2];
+       rcti ret;
+
+       getmouseco_areawin(down);
+
+       while((get_mbut()&L_MOUSE) || (get_mbut()&R_MOUSE)) {
+               getmouseco_areawin(mouse);
+
+               scrarea_do_windraw(curarea);
+
+               persp(PERSP_WIN);
+               glLineWidth(2);
+               setlinestyle(2);
+               sdrawXORline(down[0],down[1],mouse[0],down[1]);
+               sdrawXORline(mouse[0],down[1],mouse[0],mouse[1]);
+               sdrawXORline(mouse[0],mouse[1],down[0],mouse[1]);
+               sdrawXORline(down[0],mouse[1],down[0],down[1]);
+               setlinestyle(0);
+               glLineWidth(1);
+               persp(PERSP_VIEW);
+
+               screen_swapbuffers();
+               backdrawview3d(0);
+       }
+
+       ret.xmin= down[0]<mouse[0]?down[0]:mouse[0];
+       ret.ymin= down[1]<mouse[1]?down[1]:mouse[1];
+       ret.xmax= down[0]>mouse[0]?down[0]:mouse[0];
+       ret.ymax= down[1]>mouse[1]?down[1]:mouse[1];
+       return ret;
+}
+
+void sculptmode_pmv(int mode)
+{
+       Object *ob= OBACT;
+       rcti hb_2d= sculptmode_pmv_box(); /* Get 2D hide box */
+
+       waitcursor(1);
+
+       if(hb_2d.xmax-hb_2d.xmin > 3 && hb_2d.ymax-hb_2d.ymin > 3) {
+               init_sculptmatrices();
+
+               sculptmode_do_pmv(ob,&hb_2d,mode);
+       }
+       else sculptmode_pmv_off(get_mesh(ob));
+
+       scrarea_do_windraw(curarea);
+
+       BIF_undo_push("Partial mesh hide");
+
+       waitcursor(0);
+}
index 1e3d6dd18c929daa65188f2c8a10e5fbfe8c84fb..e4908fe4583945fba12e13384d04a245610a2504 100644 (file)
@@ -52,6 +52,7 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_arithb.h"
+#include "BLI_gsqueue.h"
 #include "BLI_linklist.h"
 
 #include "DNA_action_types.h"
@@ -61,6 +62,7 @@
 #include "DNA_image_types.h"
 #include "DNA_ipo_types.h"
 #include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
 #include "DNA_modifier_types.h" /* used for select grouped hooks */
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
@@ -81,6 +83,7 @@
 #include "BKE_group.h"
 #include "BKE_ipo.h"
 #include "BKE_main.h"
+#include "BKE_mesh.h"
 #include "BKE_node.h"
 #include "BKE_scene.h"
 #include "BKE_utildefines.h"
 #include "BIF_poseobject.h"
 #include "BIF_outliner.h"
 #include "BIF_resources.h"
+#include "BIF_retopo.h"
 #include "BIF_screen.h"
 #include "BIF_space.h"
 #include "BIF_toets.h"
 #include "BDR_drawmesh.h"
 #include "BDR_drawobject.h"
 #include "BDR_imagepaint.h"
+#include "BDR_sculptmode.h"
 #include "BDR_unwrapper.h"
 
 #include "BLO_readfile.h" /* for BLO_blendhandle_close */
 #include "mydevice.h"
 #include "blendef.h"
 #include "datatoc.h"
+#include "multires.h"
 
 #include "BIF_transform.h"
 
@@ -776,6 +782,8 @@ void BIF_undo_push(char *str)
                else if (G.obedit->type==OB_ARMATURE)
                        undo_push_armature(str);
        }
+       else if(G.f & G_SCULPTMODE) {
+       }
        else {
                if(U.uiflag & USER_GLOBALUNDO) 
                        BKE_write_undo(str);
@@ -795,11 +803,16 @@ void BIF_undo(void)
                        vpaint_undo();
                else if(G.f & G_TEXTUREPAINT)
                        imagepaint_undo();
+               else if(G.f & G_SCULPTMODE)
+                       sculptmode_undo();
                else if(curarea->spacetype==SPACE_IMAGE && (G.sima->flag & SI_DRAWTOOL))
                        imagepaint_undo();
                else {
                        /* now also in faceselect mode */
                        if(U.uiflag & USER_GLOBALUNDO) {
+                               if(G.f & G_SCULPTMODE)
+                                       set_sculpt_object(NULL);
+
                                BKE_undo_step(1);
                                sound_initialize_sounds();
                        }
@@ -820,6 +833,8 @@ void BIF_redo(void)
                        vpaint_undo();
                else if(G.f & G_TEXTUREPAINT)
                        imagepaint_undo();
+               else if(G.f & G_SCULPTMODE)
+                       sculptmode_redo();
                else if(curarea->spacetype==SPACE_IMAGE && (G.sima->flag & SI_DRAWTOOL))
                        imagepaint_undo();
                else {
@@ -844,6 +859,8 @@ void BIF_undo_menu(void)
                        ;
                else if(G.f & G_VERTEXPAINT)
                        ;
+               else if(G.f & G_SCULPTMODE)
+                       sculptmode_undo_menu();
                else {
                        if(U.uiflag & USER_GLOBALUNDO) {
                                char *menu= BKE_undo_menu_string();
@@ -874,7 +891,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
        if(val) {
 
                if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
-               if(event==MOUSEY || event==MOUSEX) return;
+
+               //if(event==MOUSEY || event==MOUSEX) return;
                
                if(event==UI_BUT_EVENT) do_butspace(val); /* temporal, view3d deserves own queue? */
                
@@ -887,6 +905,23 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                        else if (event==RIGHTMOUSE) event = LEFTMOUSE;
                }
 
+               if(!G.obedit && (G.f & G_SCULPTMODE)) {
+                       if(G.scene->sculptdata.propset==1) {
+                               sculptmode_propset(event);
+                               return;
+                       }
+                       else if(event!=LEFTMOUSE && event!=MIDDLEMOUSE && (event==MOUSEY || event==MOUSEX)) {
+                               if(!bwin_qtest(sa->win))
+                                       allqueue(REDRAWVIEW3D, 0);
+                       }
+               }
+
+               /* Handle retopo painting */
+               if(retopo_mesh_paint_check()) {
+                       if(!retopo_paint(event))
+                               return;
+               }
+
                /* run any view3d event handler script links */
                if (event && sa->scriptlink.totscript)
                        if (BPY_do_spacehandlers(sa, event, SPACEHANDLER_VIEW3D_EVENT))
@@ -1031,10 +1066,16 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                         * based on user preference USER_LMOUSESELECT
                         */
                        case LEFTMOUSE: 
-                               if ((G.obedit) || !(G.f&(G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT))) {
+                               if ((G.obedit) || !(G.f&(G_SCULPTMODE|G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT))) {
                                        mouse_cursor();
                                }
-                               else if (G.f & G_WEIGHTPAINT){
+                               else if (G.f & G_SCULPTMODE) {
+                                       if(G.qual==LR_SHIFTKEY+LR_CTRLKEY)
+                                               sculptmode_pmv(0);
+