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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_bad_level_calls.h9
-rw-r--r--source/blender/blenkernel/BKE_global.h3
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/stubs.c7
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c25
-rw-r--r--source/blender/blenkernel/intern/mesh.c14
-rw-r--r--source/blender/blenkernel/intern/scene.c10
-rw-r--r--source/blender/blenlib/BLI_editVert.h4
-rw-r--r--source/blender/blenloader/intern/readfile.c54
-rw-r--r--source/blender/blenloader/intern/writefile.c29
-rw-r--r--source/blender/include/BDR_drawobject.h3
-rw-r--r--source/blender/include/BDR_sculptmode.h77
-rw-r--r--source/blender/include/BIF_editmesh.h1
-rw-r--r--source/blender/include/BIF_glutil.h1
-rw-r--r--source/blender/include/BIF_previewrender.h5
-rw-r--r--source/blender/include/BIF_resources.h2
-rw-r--r--source/blender/include/BIF_retopo.h115
-rw-r--r--source/blender/include/BIF_space.h1
-rw-r--r--source/blender/include/BSE_view.h8
-rw-r--r--source/blender/include/butspace.h3
-rw-r--r--source/blender/include/multires.h54
-rw-r--r--source/blender/makesdna/DNA_curve_types.h1
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h4
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h60
-rw-r--r--source/blender/makesdna/DNA_scene_types.h80
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h1
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h6
-rw-r--r--source/blender/render/intern/source/convertblender.c55
-rw-r--r--source/blender/src/buttons_editing.c333
-rw-r--r--source/blender/src/buttons_shading.c31
-rw-r--r--source/blender/src/drawobject.c14
-rw-r--r--source/blender/src/drawview.c128
-rw-r--r--source/blender/src/editcurve.c3
-rw-r--r--source/blender/src/editmesh.c12
-rw-r--r--source/blender/src/editmesh_add.c47
-rw-r--r--source/blender/src/editobject.c12
-rw-r--r--source/blender/src/editscreen.c1
-rw-r--r--source/blender/src/editview.c8
-rw-r--r--source/blender/src/glutil.c14
-rw-r--r--source/blender/src/header_buttonswin.c15
-rw-r--r--source/blender/src/header_view3d.c296
-rw-r--r--source/blender/src/headerbuttons.c10
-rw-r--r--source/blender/src/multires.c1334
-rw-r--r--source/blender/src/renderwin.c6
-rw-r--r--source/blender/src/retopo.c831
-rw-r--r--source/blender/src/sculptmode.c1747
-rw-r--r--source/blender/src/space.c115
-rw-r--r--source/blender/src/toets.c9
-rwxr-xr-xsource/blender/src/transform_generics.c5
-rw-r--r--source/blender/src/view.c24
49 files changed, 5473 insertions, 154 deletions
diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h
index 0794e837977..a5ad16e752e 100644
--- a/source/blender/blenkernel/BKE_bad_level_calls.h
+++ b/source/blender/blenkernel/BKE_bad_level_calls.h
@@ -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
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 0c20b545f1e..a7f36e74dcb 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -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)
diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
index e9df9584e30..173a130a25e 100644
--- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c
+++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
@@ -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) {}
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 4dacfdc85d8..308a32439d4 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -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;
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index c0741e7137a..088f5af7e07 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -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)
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 272bfd38b37..60632b33dae 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -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);
diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h
index 7b3515c5135..0592f04f05d 100644
--- a/source/blender/blenlib/BLI_editVert.h
+++ b/source/blender/blenlib/BLI_editVert.h
@@ -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
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 0808ea636ad..39ba28912fd 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -105,6 +105,8 @@
#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"
@@ -136,6 +138,8 @@
#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;
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 3955530b3b3..0e16706eb74 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -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);
diff --git a/source/blender/include/BDR_drawobject.h b/source/blender/include/BDR_drawobject.h
index bd6d7cc2109..9899d56f294 100644
--- a/source/blender/include/BDR_drawobject.h
+++ b/source/blender/include/BDR_drawobject.h
@@ -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
index 00000000000..825c1b65468
--- /dev/null
+++ b/source/blender/include/BDR_sculptmode.h
@@ -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
diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h
index fc52405198b..8a1b480caaa 100644
--- a/source/blender/include/BIF_editmesh.h
+++ b/source/blender/include/BIF_editmesh.h
@@ -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 */
diff --git a/source/blender/include/BIF_glutil.h b/source/blender/include/BIF_glutil.h
index 60ac6a3b041..36bd6d0c8d7 100644
--- a/source/blender/include/BIF_glutil.h
+++ b/source/blender/include/BIF_glutil.h
@@ -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);
/**
diff --git a/source/blender/include/BIF_previewrender.h b/source/blender/include/BIF_previewrender.h
index 7ee9cc322ea..f5661fa313d 100644
--- a/source/blender/include/BIF_previewrender.h
+++ b/source/blender/include/BIF_previewrender.h
@@ -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
diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h
index 7525e4efce7..42def5ea697 100644
--- a/source/blender/include/BIF_resources.h
+++ b/source/blender/include/BIF_resources.h
@@ -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
index 00000000000..50dc23ead1c
--- /dev/null
+++ b/source/blender/include/BIF_retopo.h
@@ -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
diff --git a/source/blender/include/BIF_space.h b/source/blender/include/BIF_space.h
index 0faaae57028..7bf0814b82e 100644
--- a/source/blender/include/BIF_space.h
+++ b/source/blender/include/BIF_space.h
@@ -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
diff --git a/source/blender/include/BSE_view.h b/source/blender/include/BSE_view.h
index 2afbca2b30e..eddee0b1fdb 100644
--- a/source/blender/include/BSE_view.h
+++ b/source/blender/include/BSE_view.h
@@ -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
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
index 9ea29743d79..53779f4f3d5 100644
--- a/source/blender/include/butspace.h
+++ b/source/blender/include/butspace.h
@@ -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
index 00000000000..af5260e14e1
--- /dev/null
+++ b/source/blender/include/multires.h
@@ -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
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 04b7b4804b7..626e7cf4167 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -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
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index a57791be06d..d0ef6724ff0 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -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;
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index 34c3cc904f1..a091a2d4ce7 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -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
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 22bcf432c48..fe43676f1db 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -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
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index eb787682755..f9db4633280 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -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
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index dda40b67bf7..be3a5099d7b 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -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 */
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 8d23269166c..d16bbd28b9c 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -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);
+ }
}
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index e46bb72f154..cac9d93d57f 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -109,6 +109,7 @@
#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"
@@ -147,6 +148,7 @@
#include "BDR_editcurve.h"
#include "BDR_editface.h"
#include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
#include "BDR_vpaint.h"
#include "BDR_unwrapper.h"
@@ -162,6 +164,7 @@
#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();
diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c
index 20eeb4f7532..fdfa17fc858 100644
--- a/source/blender/src/buttons_shading.c
+++ b/source/blender/src/buttons_shading.c
@@ -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;
diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c
index 12f4b27a38e..69f15f212dd 100644
--- a/source/blender/src/drawobject.c
+++ b/source/blender/src/drawobject.c
@@ -104,12 +104,14 @@
#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 ) {
diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c
index 3ee670c646c..e21b867f697 100644
--- a/source/blender/src/drawview.c
+++ b/source/blender/src/drawview.c
@@ -110,6 +110,7 @@
#include "BIF_poseobject.h"
#include "BIF_previewrender.h"
#include "BIF_resources.h"
+#include "BIF_retopo.h"
#include "BIF_screen.h"
#include "BIF_space.h"
@@ -121,6 +122,7 @@
#include "BDR_drawobject.h"
#include "BDR_editobject.h"
#include "BDR_vpaint.h"
+#include "BDR_sculptmode.h"
#include "BSE_drawview.h"
#include "BSE_filesel.h"
@@ -142,6 +144,8 @@
#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);
}
-
}
diff --git a/source/blender/src/editcurve.c b/source/blender/src/editcurve.c
index 54645bce9c9..902a435e3b4 100644
--- a/source/blender/src/editcurve.c
+++ b/source/blender/src/editcurve.c
@@ -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();
diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c
index 7d2837df241..a45f413928e 100644
--- a/source/blender/src/editmesh.c
+++ b/source/blender/src/editmesh.c
@@ -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;
}
diff --git a/source/blender/src/editmesh_add.c b/source/blender/src/editmesh_add.c
index 18f8fbd20dc..c58a49212ba 100644
--- a/source/blender/src/editmesh_add.c
+++ b/source/blender/src/editmesh_add.c
@@ -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;
diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c
index e264f18ff24..5c7c151192d 100644
--- a/source/blender/src/editobject.c
+++ b/source/blender/src/editobject.c
@@ -138,6 +138,7 @@
#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"
@@ -156,6 +157,7 @@
#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);
}
diff --git a/source/blender/src/editscreen.c b/source/blender/src/editscreen.c
index 4085cb353f5..2fdc3bc6025 100644
--- a/source/blender/src/editscreen.c
+++ b/source/blender/src/editscreen.c
@@ -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) {
diff --git a/source/blender/src/editview.c b/source/blender/src/editview.c
index 6364831893e..78130f2ea88 100644
--- a/source/blender/src/editview.c
+++ b/source/blender/src/editview.c
@@ -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 */
}
diff --git a/source/blender/src/glutil.c b/source/blender/src/glutil.c
index 87d20c66ef9..711c809ce40 100644
--- a/source/blender/src/glutil.c
+++ b/source/blender/src/glutil.c
@@ -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);
diff --git a/source/blender/src/header_buttonswin.c b/source/blender/src/header_buttonswin.c
index 6e45644fefe..84735a49ca6 100644
--- a/source/blender/src/header_buttonswin.c
+++ b/source/blender/src/header_buttonswin.c
@@ -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;
+ }
}
}
}
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index 69859bcb7d8..868d4630733 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -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"
@@ -105,6 +107,7 @@
#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"
@@ -135,6 +138,7 @@
#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 */
diff --git a/source/blender/src/headerbuttons.c b/source/blender/src/headerbuttons.c
index cd69708931b..57d52edc109 100644
--- a/source/blender/src/headerbuttons.c
+++ b/source/blender/src/headerbuttons.c
@@ -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
index 00000000000..5f444094903
--- /dev/null
+++ b/source/blender/src/multires.c
@@ -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);
+}
diff --git a/source/blender/src/renderwin.c b/source/blender/src/renderwin.c
index ced1f1bd6f5..2152e65940c 100644
--- a/source/blender/src/renderwin.c
+++ b/source/blender/src/renderwin.c
@@ -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
index 00000000000..3d08f0a4e73
--- /dev/null
+++ b/source/blender/src/retopo.c
@@ -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
index 00000000000..6b908c1d593
--- /dev/null
+++ b/source/blender/src/sculptmode.c
@@ -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);
+}
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 1e3d6dd18c9..e4908fe4583 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -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"
@@ -115,6 +118,7 @@
#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"
@@ -140,6 +144,7 @@
#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 */
@@ -152,6 +157,7 @@
#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);
+ else if(!G.scene->sculptdata.propset)
+ sculpt();
+ }
+ else if (G.f & G_WEIGHTPAINT) {
weight_paint();
}
else if (G.f & G_VERTEXPAINT) {
@@ -1086,6 +1127,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
face_select();
else if( G.f & (G_VERTEXPAINT|G_TEXTUREPAINT))
sample_vpaint();
+ else if((G.f & G_SCULPTMODE) && G.qual==LR_SHIFTKEY+LR_CTRLKEY)
+ sculptmode_pmv(1);
else
mouse_select(); /* does poses too */
break;
@@ -1149,7 +1192,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
doredraw= 1;
break;
-
+
case ONEKEY:
if(G.qual==LR_CTRLKEY) {
if(ob && ob->type == OB_MESH) {
@@ -1345,11 +1388,14 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
imagestodisplist();
}
else if((G.qual==0)){
- pupval= pupmenu("Draw mode%t|BoundBox %x1|Wire %x2|OpenGL Solid %x3|Shaded Solid %x4|Textured Solid %x5");
- if(pupval>0) {
- G.vd->drawtype= pupval;
- doredraw= 1;
-
+ if(G.f & G_SCULPTMODE)
+ G.scene->sculptdata.propset= 1;
+ else {
+ pupval= pupmenu("Draw mode%t|BoundBox %x1|Wire %x2|OpenGL Solid %x3|Shaded Solid %x4|Textured Solid %x5");
+ if(pupval>0) {
+ G.vd->drawtype= pupval;
+ doredraw= 1;
+ }
}
}
@@ -1500,6 +1546,15 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
}
else if(G.f & G_FACESELECT)
hide_tface();
+ else if(G.f & G_SCULPTMODE) {
+ if(G.qual==LR_ALTKEY) {
+ waitcursor(1);
+ sculptmode_pmv_off(get_mesh(ob));
+ BIF_undo_push("Partial mesh hide");
+ allqueue(REDRAWVIEW3D,0);
+ waitcursor(0);
+ }
+ }
else if(ob && (ob->flag & OB_POSEMODE)) {
if (G.qual==0)
hide_selected_pose_bones();
@@ -2024,19 +2079,33 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
break;
case PAGEUPKEY:
- if(G.qual==LR_CTRLKEY)
- movekey_obipo(1);
- else if((G.qual==0))
- nextkey_obipo(1); /* in editipo.c */
+ if(G.f & G_SCULPTMODE) {
+ if(ob && ob->type == OB_MESH && ((Mesh*)ob->data)->mr) {
+ ((Mesh*)ob->data)->mr->newlvl= ((Mesh*)ob->data)->mr->current+1;
+ multires_set_level(ob,ob->data);
+ }
+ } else {
+ if(G.qual==LR_CTRLKEY)
+ movekey_obipo(1);
+ else if((G.qual==0))
+ nextkey_obipo(1); /* in editipo.c */
+ }
break;
case PAGEDOWNKEY:
- if(G.qual==LR_CTRLKEY)
- movekey_obipo(-1);
- else if((G.qual==0))
- nextkey_obipo(-1);
+ if(G.f & G_SCULPTMODE) {
+ if(ob && ob->type == OB_MESH && ((Mesh*)ob->data)->mr) {
+ ((Mesh*)ob->data)->mr->newlvl= ((Mesh*)ob->data)->mr->current-1;
+ multires_set_level(ob,ob->data);
+ }
+ } else {
+ if(G.qual==LR_CTRLKEY)
+ movekey_obipo(-1);
+ else if((G.qual==0))
+ nextkey_obipo(-1);
+ }
break;
-
+
case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
case PADENTER:
@@ -2111,6 +2180,8 @@ static void initview3d(ScrArea *sa)
vd->gridflag |= V3D_SHOW_Y;
vd->gridflag |= V3D_SHOW_FLOOR;
vd->gridflag &= ~V3D_SHOW_Z;
+
+ vd->depths= NULL;
}
@@ -3155,7 +3226,6 @@ void drawinfospace(ScrArea *sa, void *spacedata)
(xpos+edgsp+(4*mpref)+(4*midsp)),y1,mpref,buth,
&(U.uiflag), 0, 0, 0, 0, "Hide files/datablocks that start with a dot(.*)");
-
uiDefBut(block, LABEL,0,"OpenGL:",
(xpos+edgsp+(5*midsp)+(5*mpref)),y5label,mpref,buth,
0, 0, 0, 0, 0, "");
@@ -4947,6 +5017,12 @@ void freespacelist(ScrArea *sa)
}
if(vd->localvd) MEM_freeN(vd->localvd);
if(vd->clipbb) MEM_freeN(vd->clipbb);
+ if(vd->depths) {
+ if(vd->depths->depths) MEM_freeN(vd->depths->depths);
+ MEM_freeN(vd->depths);
+ vd->depths= NULL;
+ }
+ retopo_free_view_data(vd);
if(G.vd==vd) G.vd= NULL;
if(vd->ri) {
BIF_view3d_previewrender_free(vd);
@@ -5005,6 +5081,7 @@ void duplicatespacelist(ScrArea *newarea, ListBase *lb1, ListBase *lb2)
}
else if(sl->spacetype==SPACE_VIEW3D) {
BIF_view3d_previewrender_free((View3D *)sl);
+ ((View3D*)sl)->depths= NULL;
}
else if(sl->spacetype==SPACE_OOPS) {
SpaceOops *so= (SpaceOops *)sl;
diff --git a/source/blender/src/toets.c b/source/blender/src/toets.c
index be204c08c71..a9ec10e6114 100644
--- a/source/blender/src/toets.c
+++ b/source/blender/src/toets.c
@@ -79,6 +79,7 @@
#include "BIF_poseobject.h"
#include "BIF_previewrender.h"
#include "BIF_renderwin.h"
+#include "BIF_retopo.h"
#include "BIF_screen.h"
#include "BIF_space.h"
#include "BIF_toets.h"
@@ -86,6 +87,7 @@
#include "BIF_usiblender.h"
#include "BIF_writeimage.h"
+#include "BDR_sculptmode.h"
#include "BDR_vpaint.h"
#include "BDR_editobject.h"
#include "BDR_editface.h"
@@ -334,6 +336,11 @@ void persptoetsen(unsigned short event)
if(G.vd->persp<2) perspo= G.vd->persp;
}
+
+ if(G.vd->depths) G.vd->depths->damaged= 1;
+ retopo_queue_updates(G.vd);
+ if(retopo_mesh_paint_check() && G.vd->retopo_view_data)
+ retopo_paint_view_update(G.vd);
if(preview3d_event)
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
@@ -670,6 +677,8 @@ int blenderqread(unsigned short event, short val)
}
else if(ob->type==OB_MESH) {
if(ob==G.obedit) EM_selectmode_menu();
+ else if(G.f & G_SCULPTMODE)
+ sculptmode_selectbrush_menu();
else set_wpaint();
}
}
diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c
index 0ed75810b42..8b75586442b 100755
--- a/source/blender/src/transform_generics.c
+++ b/source/blender/src/transform_generics.c
@@ -58,6 +58,7 @@
#include "BIF_editmesh.h"
#include "BIF_editsima.h"
#include "BIF_meshtools.h"
+#include "BIF_retopo.h"
#ifdef WITH_VERSE
#include "BIF_verse.h"
@@ -224,6 +225,8 @@ void recalcData(TransInfo *t)
if(G.scene->toolsettings->editbutflag & B_MESH_X_MIRROR)
editmesh_apply_to_mirror(t);
+
+ retopo_do_all(0,G.obedit->data);
DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); /* sets recalc flags */
@@ -238,6 +241,8 @@ void recalcData(TransInfo *t)
testhandlesNurb(nu); /* test for bezier too */
nu= nu->next;
}
+
+ retopo_do_all(NULL,NULL);
}
else if(G.obedit->type==OB_ARMATURE){ /* no recalc flag, does pose */
bArmature *arm= G.obedit->data;
diff --git a/source/blender/src/view.c b/source/blender/src/view.c
index 911d18283f8..0a5b2a3d5f7 100644
--- a/source/blender/src/view.c
+++ b/source/blender/src/view.c
@@ -71,6 +71,7 @@
#include "BIF_space.h"
#include "BIF_mywindow.h"
#include "BIF_previewrender.h"
+#include "BIF_retopo.h"
#include "BIF_screen.h"
#include "BIF_toolbox.h"
@@ -559,7 +560,18 @@ void viewmove(int mode)
/* cumultime(0); */
- if (ob && (U.uiflag & USER_ORBIT_SELECTION)) {
+ if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
+ use_sel= 1;
+ VecCopyf(ofs, G.vd->ofs);
+
+ VecCopyf(obofs,&G.scene->sculptdata.pivot.x);
+ Mat4MulVecfl(ob->obmat, obofs);
+ obofs[0]= -obofs[0];
+ obofs[1]= -obofs[1];
+ obofs[2]= -obofs[2];
+ }
+ //else if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE) && U.uiflag & USER_ORBIT_SELECTION) {
+ else if (ob && (U.uiflag & USER_ORBIT_SELECTION)) {
use_sel = 1;
VECCOPY(ofs, G.vd->ofs);
@@ -761,6 +773,12 @@ void viewmove(int mode)
if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
if(G.f & G_SIMULATION) break;
+ /* If in retopo paint mode, update lines */
+ if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
+ G.vd->retopo_view_data->queue_matrix_update= 1;
+ retopo_paint_view_update(G.vd);
+ }
+
scrarea_do_windraw(curarea);
screen_swapbuffers();
}
@@ -777,6 +795,10 @@ void viewmove(int mode)
if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
}
+ if(G.vd->depths) G.vd->depths->damaged= 1;
+ retopo_queue_updates(G.vd);
+ allqueue(REDRAWVIEW3D, 0);
+
if(preview3d_event)
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
else