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 #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; itotvert; ++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; asculptdata.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; asculptdata.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; asculptdata.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; - - 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; + 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) "); - /* 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)"); - 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<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<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; - - /* 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)) { - - 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; - } - - /* 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; + 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); - 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+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)"); xco+= XIC; } - 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)"); - - 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"); - } + 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<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<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; + + /* 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)) { + + 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; + } + + /* 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; + } + + 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"); + } + 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 +#include + +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; ivert_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; ia+= 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; itotweight; ++i) { + found= 0; + for(j=0; jtotweight; ++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; itotface; ++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; itotface; ++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; iprev->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; jprev->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; itotface; ++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; itotvert; ++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; itotface; ++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; itotedge; ++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; itotvert; ++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 && itotvert; ++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; itotvert; ++i) + BLI_freelistN(&lvl->vert_edge_map[i]); + for(i=0; itotvert; ++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; iprev->totvert; ++i) + VecCopyf(lvl->verts[i].co,lvl->prev->verts[i].co); + /* Create new edge verts */ + for(i=0; iprev->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; iprev->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; iprev->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; iprev->totface; ++i) { + const int max= lvl->prev->faces[i].v[3] ? 3 : 2; + + lvl->prev->faces[i].childrenstart= curf; + for(j=0; jfaces[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; iprev->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; iprev->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; iprev->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; iprev->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; iprev->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; iprev->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; iprev->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; jcol[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; itotvert; ++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; itotvert; ++i) + me->mvert[i]= lvl->verts[i]; + for(i=0; itotface; ++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; itotedge; ++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; itotvert; ++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; iprev->totvert; ++i) + multires_add_dvert(&lvl_dverts[dlvl_ndx][i], + &source[i], 1); + /* Edge verts */ + for(i=0; iprev->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; iprev->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; jtotvert; ++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; itotface; ++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; itotface; ++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; itotface; ++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; itotface; ++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; itotface; ++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; iprev->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; jtotface; ++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; itotface; ++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; itotvert; ++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; itotvert; ++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; itotvert; ++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; itotvert; ++i) + VecCopyf(cr_lvl->verts[i].co,me->mvert[i].co); + for(i=0; itotface; ++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; itotface; ++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; itotedge; ++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; itotedge; ++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; itotvert; ++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; itotvert; ++i) { + VecAddf(cr_lvl->verts[i].co, + cr_lvl->verts[i].co, + &cr_deltas[i].x); + } + + /* Update faces */ + curf= 0; + for(i=0; iprev->totface; ++i) { + const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3; + for(j=0; jfaces[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; itotvert; ++i) + cr_lvl->verts[i]= cr_lvl->next->verts[i]; + + /* Update faces */ + curf= 0; + for(i=0; itotface; ++i) { + const int sides= cr_lvl->faces[i].v[3] ? 4 : 3; + char smooth= 1; + + for(j=0; jnext->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; itotedge; ++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; itotface; ++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; imr->levels,me->mr->current-1); + MultiresLevel *edge_lvl= BLI_findlink(&me->mr->levels,me->mr->edgelvl-1); + unsigned i; + + for(i=0; itotedge; ++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 || + itotedge*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 +#include +#include + +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; iintersections,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; iline_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; iellipse_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(©->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; ipntsv; ++i) { + for(j=0; jpntsu; ++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 +#include +#include + +/* ===== 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; ivertex_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; amtex[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; itotvert; ++i){ + G.scene->sculptdata.vertex_users[i].first=G.scene->sculptdata.vertex_users[i].last= 0; + } + + /* Find the users */ + for(i=0; itotface; ++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 && xdepths->w && ydepths->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; itotvert; ++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; itotvert; ++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; itotvert; ++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; isculptdata.texrndr) { + for(i=0; isculptdata.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; itotvert; ++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; itotedge; 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; itotface; ++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; itotface; ++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; isculptdata.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.xminxmax && clp.xmax>win->xmin && + clp.yminymax && clp.ymax>win->ymin) { + if(clp.xminxmin) clp.xmin= win->xmin; + if(clp.yminymin) 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; itotvert; ++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; ipv->totvert; ++i) { + old_map[i]= me->pv->vert_map[i]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; ipv->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; itotface; ++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; itotedge; ++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; ipv->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; itotface; ++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; itotedge; ++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.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