Brought back sculpt smooth brush. Also added a new brush flag for setting whether to use brush spacing.
This commit is contained in:
@@ -109,6 +109,16 @@ UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned
|
||||
UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v);
|
||||
void free_uv_vert_map(UvVertMap *vmap);
|
||||
|
||||
/* Connectivity data */
|
||||
typedef struct IndexNode {
|
||||
struct IndexNode *next, *prev;
|
||||
int index;
|
||||
} IndexNode;
|
||||
void create_vert_face_map(ListBase **map, IndexNode **mem, const struct MFace *mface,
|
||||
const int totvert, const int totface);
|
||||
void create_vert_edge_map(ListBase **map, IndexNode **mem, const struct MEdge *medge,
|
||||
const int totvert, const int totedge);
|
||||
|
||||
/* Partial Mesh Visibility */
|
||||
struct PartialVisibility *mesh_pmv_copy(struct PartialVisibility *);
|
||||
void mesh_pmv_free(struct PartialVisibility *);
|
||||
|
||||
@@ -38,16 +38,6 @@ typedef struct MultiresSubsurf {
|
||||
struct Mesh *me;
|
||||
} MultiresSubsurf;
|
||||
|
||||
typedef struct IndexNode {
|
||||
struct IndexNode *next, *prev;
|
||||
int index;
|
||||
} IndexNode;
|
||||
|
||||
void create_vert_face_map(ListBase **map, IndexNode **mem, const struct MFace *mface,
|
||||
const int totvert, const int totface);
|
||||
void create_vert_edge_map(ListBase **map, IndexNode **mem, const struct MEdge *medge,
|
||||
const int totvert, const int totedge);
|
||||
|
||||
/* MultiresDM */
|
||||
struct Mesh *MultiresDM_get_mesh(struct DerivedMesh *dm);
|
||||
struct DerivedMesh *MultiresDM_new(struct MultiresSubsurf *, struct DerivedMesh*, int, int, int);
|
||||
|
||||
@@ -40,13 +40,10 @@ struct StrokeCache;
|
||||
typedef struct SculptSession {
|
||||
struct ProjVert *projverts;
|
||||
|
||||
/* 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;
|
||||
struct IndexNode *vertex_users_mem;
|
||||
int vertex_users_size;
|
||||
/* Mesh connectivity */
|
||||
struct ListBase *fmap;
|
||||
struct IndexNode *fmap_mem;
|
||||
int fmap_size;
|
||||
|
||||
/* Used temporarily per-stroke */
|
||||
float *vertexcosnos;
|
||||
@@ -66,6 +63,5 @@ typedef struct SculptSession {
|
||||
} SculptSession;
|
||||
|
||||
void sculptsession_free(struct Sculpt *sculpt);
|
||||
void sculpt_vertexusers_free(struct SculptSession *ss);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1149,6 +1149,48 @@ void free_uv_vert_map(UvVertMap *vmap)
|
||||
}
|
||||
}
|
||||
|
||||
/* Generates a map where the key is the vertex and the value is a list
|
||||
of faces that use that vertex as a corner. The lists are allocated
|
||||
from one memory pool. */
|
||||
void create_vert_face_map(ListBase **map, IndexNode **mem, const MFace *mface, const int totvert, const int totface)
|
||||
{
|
||||
int i,j;
|
||||
IndexNode *node = NULL;
|
||||
|
||||
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
|
||||
(*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem");
|
||||
node = *mem;
|
||||
|
||||
/* Find the users */
|
||||
for(i = 0; i < totface; ++i){
|
||||
for(j = 0; j < (mface[i].v4?4:3); ++j, ++node) {
|
||||
node->index = i;
|
||||
BLI_addtail(&(*map)[((unsigned int*)(&mface[i]))[j]], node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generates a map where the key is the vertex and the value is a list
|
||||
of edges that use that vertex as an endpoint. The lists are allocated
|
||||
from one memory pool. */
|
||||
void create_vert_edge_map(ListBase **map, IndexNode **mem, const MEdge *medge, const int totvert, const int totedge)
|
||||
{
|
||||
int i, j;
|
||||
IndexNode *node = NULL;
|
||||
|
||||
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map");
|
||||
(*mem) = MEM_callocN(sizeof(IndexNode) * totedge * 2, "vert edge map mem");
|
||||
node = *mem;
|
||||
|
||||
/* Find the users */
|
||||
for(i = 0; i < totedge; ++i){
|
||||
for(j = 0; j < 2; ++j, ++node) {
|
||||
node->index = i;
|
||||
BLI_addtail(&(*map)[((unsigned int*)(&medge[i].v1))[j]], node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Partial Mesh Visibility */
|
||||
PartialVisibility *mesh_pmv_copy(PartialVisibility *pmv)
|
||||
{
|
||||
|
||||
@@ -54,42 +54,6 @@
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
void create_vert_face_map(ListBase **map, IndexNode **mem, const MFace *mface, const int totvert, const int totface)
|
||||
{
|
||||
int i,j;
|
||||
IndexNode *node = NULL;
|
||||
|
||||
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert face map");
|
||||
(*mem) = MEM_callocN(sizeof(IndexNode) * totface*4, "vert face map mem");
|
||||
node = *mem;
|
||||
|
||||
/* Find the users */
|
||||
for(i = 0; i < totface; ++i){
|
||||
for(j = 0; j < (mface[i].v4?4:3); ++j, ++node) {
|
||||
node->index = i;
|
||||
BLI_addtail(&(*map)[((unsigned int*)(&mface[i]))[j]], node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void create_vert_edge_map(ListBase **map, IndexNode **mem, const MEdge *medge, const int totvert, const int totedge)
|
||||
{
|
||||
int i, j;
|
||||
IndexNode *node = NULL;
|
||||
|
||||
(*map) = MEM_callocN(sizeof(ListBase) * totvert, "vert edge map");
|
||||
(*mem) = MEM_callocN(sizeof(IndexNode) * totedge * 2, "vert edge map mem");
|
||||
node = *mem;
|
||||
|
||||
/* Find the users */
|
||||
for(i = 0; i < totedge; ++i){
|
||||
for(j = 0; j < 2; ++j, ++node) {
|
||||
node->index = i;
|
||||
BLI_addtail(&(*map)[((unsigned int*)(&medge[i].v1))[j]], node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* MULTIRES MODIFIER */
|
||||
static const int multires_max_levels = 13;
|
||||
static const int multires_quad_tot[] = {4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
|
||||
|
||||
@@ -651,17 +651,6 @@ void scene_add_render_layer(Scene *sce)
|
||||
srl->passflag= SCE_PASS_COMBINED|SCE_PASS_Z;
|
||||
}
|
||||
|
||||
void sculpt_vertexusers_free(SculptSession *ss)
|
||||
{
|
||||
if(ss && ss->vertex_users){
|
||||
MEM_freeN(ss->vertex_users);
|
||||
MEM_freeN(ss->vertex_users_mem);
|
||||
ss->vertex_users= NULL;
|
||||
ss->vertex_users_mem= NULL;
|
||||
ss->vertex_users_size= 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sculptsession_free(Sculpt *sculpt)
|
||||
{
|
||||
SculptSession *ss= sculpt->session;
|
||||
@@ -672,7 +661,12 @@ void sculptsession_free(Sculpt *sculpt)
|
||||
if(ss->radialcontrol)
|
||||
MEM_freeN(ss->radialcontrol);
|
||||
|
||||
sculpt_vertexusers_free(ss);
|
||||
if(ss->fmap)
|
||||
MEM_freeN(ss->fmap);
|
||||
|
||||
if(ss->fmap_mem)
|
||||
MEM_freeN(ss->fmap_mem);
|
||||
|
||||
if(ss->texcache)
|
||||
MEM_freeN(ss->texcache);
|
||||
MEM_freeN(ss);
|
||||
|
||||
@@ -181,32 +181,6 @@ typedef struct ProjVert {
|
||||
char inside;
|
||||
} ProjVert;
|
||||
|
||||
/* vertex_users is an array of Lists that store all the faces that use a
|
||||
particular vertex. vertex_users is in the same order as mesh.mvert */
|
||||
static void calc_vertex_users(SculptSession *ss)
|
||||
{
|
||||
int i,j;
|
||||
IndexNode *node= NULL;
|
||||
StrokeCache *cache = ss->cache;
|
||||
|
||||
sculpt_vertexusers_free(ss);
|
||||
|
||||
/* For efficiency, use vertex_users_mem as a memory pool (may be larger
|
||||
than necessary if mesh has triangles, but only one alloc is needed.) */
|
||||
ss->vertex_users= MEM_callocN(sizeof(ListBase) * cache->totvert, "vertex_users");
|
||||
ss->vertex_users_size= cache->totvert;
|
||||
ss->vertex_users_mem= MEM_callocN(sizeof(IndexNode)*cache->totface*4, "vertex_users_mem");
|
||||
node= ss->vertex_users_mem;
|
||||
|
||||
/* Find the users */
|
||||
for(i=0; i<cache->totface; ++i){
|
||||
for(j=0; j<(cache->mface[i].v4?4:3); ++j, ++node) {
|
||||
node->index=i;
|
||||
BLI_addtail(&ss->vertex_users[((unsigned int*)(&cache->mface[i]))[j]], node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== INTERFACE =====
|
||||
*/
|
||||
|
||||
@@ -326,7 +300,7 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache)
|
||||
case SCULPT_TOOL_LAYER:
|
||||
return sd->brush->alpha / 50.0f * dir * pressure * flip * anchored; /*XXX: not sure why? multiplied by G.vd->grid */;
|
||||
case SCULPT_TOOL_SMOOTH:
|
||||
return sd->brush->alpha / .5f * pressure * anchored;
|
||||
return sd->brush->alpha / .5 * pressure * anchored;
|
||||
case SCULPT_TOOL_PINCH:
|
||||
return sd->brush->alpha / 10.0f * dir * pressure * flip * anchored;
|
||||
case SCULPT_TOOL_GRAB:
|
||||
@@ -449,8 +423,8 @@ static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_
|
||||
static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
|
||||
{
|
||||
int i, skip= -1, total=0;
|
||||
IndexNode *node= ss->vertex_users[vert].first;
|
||||
char ncount= BLI_countlist(&ss->vertex_users[vert]);
|
||||
IndexNode *node= ss->fmap[vert].first;
|
||||
char ncount= BLI_countlist(&ss->fmap[vert]);
|
||||
MFace *f;
|
||||
|
||||
avg[0] = avg[1] = avg[2] = 0;
|
||||
@@ -472,7 +446,7 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
|
||||
}
|
||||
|
||||
for(i=0; i<(f->v4?4:3); ++i) {
|
||||
if(i != skip && (ncount!=2 || BLI_countlist(&ss->vertex_users[(&f->v1)[i]]) <= 2)) {
|
||||
if(i != skip && (ncount!=2 || BLI_countlist(&ss->fmap[(&f->v1)[i]]) <= 2)) {
|
||||
VecAddf(avg, avg, ss->cache->mvert[(&f->v1)[i]].co);
|
||||
++total;
|
||||
}
|
||||
@@ -1000,7 +974,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, StrokeCache *cache)
|
||||
int i;
|
||||
|
||||
/* Brush spacing: only apply dot if next dot is far enough away */
|
||||
if(sd->brush->spacing > 0 && !(sd->brush->flag & BRUSH_ANCHORED) && !cache->first_time) {
|
||||
if((sd->brush->flag & BRUSH_SPACE) && !(sd->brush->flag & BRUSH_ANCHORED) && !cache->first_time) {
|
||||
int dx = cache->last_dot[0] - cache->mouse[0];
|
||||
int dy = cache->last_dot[1] - cache->mouse[1];
|
||||
if(sqrt(dx*dx+dy*dy) < sd->brush->spacing)
|
||||
@@ -1052,7 +1026,7 @@ static void update_damaged_vert(SculptSession *ss, ListBase *lb)
|
||||
|
||||
for(vert= lb->first; vert; vert= vert->next) {
|
||||
vec3f norm= {0,0,0};
|
||||
IndexNode *face= ss->vertex_users[vert->Index].first;
|
||||
IndexNode *face= ss->fmap[vert->Index].first;
|
||||
|
||||
while(face){
|
||||
float *fn = NULL;
|
||||
@@ -1419,8 +1393,10 @@ static struct MultiresModifierData *sculpt_multires_active(Object *ob)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void sculpt_update_mesh_elements(StrokeCache *cache, Object *ob)
|
||||
static void sculpt_update_mesh_elements(SculptSession *ss, Object *ob)
|
||||
{
|
||||
StrokeCache *cache = ss->cache;
|
||||
|
||||
if(sculpt_multires_active(ob)) {
|
||||
DerivedMesh *dm = mesh_get_derived_final(NULL, ob, CD_MASK_BAREMESH); /* XXX scene=? */
|
||||
cache->multires = 1;
|
||||
@@ -1439,6 +1415,11 @@ static void sculpt_update_mesh_elements(StrokeCache *cache, Object *ob)
|
||||
cache->mface = me->mface;
|
||||
cache->face_normals = NULL;
|
||||
}
|
||||
|
||||
if(cache->totvert != ss->fmap_size) {
|
||||
create_vert_face_map(&ss->fmap, &ss->fmap_mem, cache->mface, cache->totvert, cache->totface);
|
||||
ss->fmap_size = cache->totvert;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: lots of drawing code (partial redraw), has to go elsewhere */
|
||||
@@ -1621,7 +1602,7 @@ static void sculpt_update_cache_invariants(Sculpt *sd, bContext *C, wmOperator *
|
||||
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
|
||||
sculpt_load_mats(cache->mats, &cache->vc);
|
||||
|
||||
sculpt_update_mesh_elements(cache, cache->vc.obact);
|
||||
sculpt_update_mesh_elements(sd->session, cache->vc.obact);
|
||||
|
||||
/* Make copies of the mesh vertex locations and normals for some tools */
|
||||
if(sd->brush->sculpt_tool == SCULPT_TOOL_LAYER || (sd->brush->flag & BRUSH_ANCHORED)) {
|
||||
@@ -1906,13 +1887,6 @@ static void draw_paint_cursor(bContext *C, int x, int y)
|
||||
glTranslatef((float)-x, (float)-y, 0.0f);
|
||||
}
|
||||
|
||||
static void init_sculpt(ToolSettings *ts)
|
||||
{
|
||||
ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data");
|
||||
|
||||
/* XXX: initialize persistent sculpt settings */
|
||||
}
|
||||
|
||||
static int sculpt_toggle_mode(bContext *C, wmOperator *op)
|
||||
{
|
||||
ToolSettings *ts = CTX_data_tool_settings(C);
|
||||
@@ -1931,12 +1905,23 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
|
||||
/* Enter sculptmode */
|
||||
|
||||
G.f |= G_SCULPTMODE;
|
||||
|
||||
|
||||
/* Create persistent sculpt mode data */
|
||||
if(!ts->sculpt)
|
||||
init_sculpt(ts);
|
||||
ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data");
|
||||
|
||||
/* Create sculpt mode session data */
|
||||
if(ts->sculpt->session)
|
||||
MEM_freeN(ts->sculpt->session);
|
||||
ts->sculpt->session = MEM_callocN(sizeof(SculptSession), "sculpt session");
|
||||
|
||||
/* Activate visible brush */
|
||||
ts->sculpt->session->cursor =
|
||||
WM_paint_cursor_activate(CTX_wm_manager(C), sculpt_brush_stroke_poll, draw_paint_cursor);
|
||||
|
||||
|
||||
|
||||
/* XXX: testing */
|
||||
/* Needed for testing, if there's no brush then create one */
|
||||
ts->sculpt->brush = add_brush("test brush");
|
||||
/* Also for testing, set the brush texture to the first available one */
|
||||
@@ -1947,10 +1932,6 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
|
||||
mtex->tex = G.main->tex.first;
|
||||
mtex->size[0] = mtex->size[1] = mtex->size[2] = 50;
|
||||
}
|
||||
|
||||
/* Activate visible brush */
|
||||
ts->sculpt->session->cursor =
|
||||
WM_paint_cursor_activate(CTX_wm_manager(C), sculpt_brush_stroke_poll, draw_paint_cursor);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
|
||||
@@ -79,6 +79,7 @@ typedef struct Brush {
|
||||
#define BRUSH_RAKE 128
|
||||
#define BRUSH_ANCHORED 256
|
||||
#define BRUSH_DIR_IN 512
|
||||
#define BRUSH_SPACE 1024
|
||||
|
||||
/* Brush.blend */
|
||||
#define BRUSH_BLEND_MIX 0
|
||||
|
||||
@@ -159,6 +159,10 @@ void rna_def_brush(BlenderRNA *brna)
|
||||
prop= RNA_def_property(srna, "flip_direction", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_DIR_IN);
|
||||
RNA_def_property_ui_text(prop, "Flip Direction", "Move vertices in the opposite direction.");
|
||||
|
||||
prop= RNA_def_property(srna, "space", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SPACE);
|
||||
RNA_def_property_ui_text(prop, "Space", "Limit brush application to the distance specified by spacing.");
|
||||
|
||||
/* not exposed in the interface yet
|
||||
prop= RNA_def_property(srna, "fixed_tex", PROP_BOOLEAN, PROP_NONE);
|
||||
|
||||
Reference in New Issue
Block a user