== Sculpt Mode ==

Added a new input control that smooths the brush stroke.

This option controlled by the menu item Sculpt>Input Control>Smooth Stroke. When enabled, the brush has a delayed effect on the model; a green line is drawn to indicate the smoothed path of the stroke. After ~200 pixels, the first half of the stroke will be applied to the model; the process then repeats, with a new segment of the stroke being applied to the model after every 200 pixels. On mouse up, any remaining portion of the stroke will be applied.

Other changes:
* Added a flags field to SculptData; currently only used for smooth stroke but other flags can be moved into it
* Moved the damaged_rects/verts into SculptSession
* Simplified brush application by moving init_editdata into do_symmetrical_brush_actions
* Removed Averaging from sculpt Input menu; smooth stroke should take its place

TODO:
* Fix display of the smooth line in Partial Redraw mode
* Make the smoothing and delay factors adjustable
* Optimize the stroke application (currently using the old 'dot' style of applying the brush)
This commit is contained in:
2007-06-24 22:28:28 +00:00
parent 296758ff01
commit 8cf2d5ca4a
6 changed files with 381 additions and 66 deletions

View File

@@ -175,6 +175,7 @@ SculptData *sculpt_data(void)
}
void sculpt_init_session(void);
void init_editdata(EditData *e, short *, short *);
SculptSession *sculpt_session(void)
{
@@ -881,7 +882,7 @@ float tex_strength(EditData *e, float *point, const float len,const unsigned vin
/* Mark area around the brush as damaged. projverts are marked if they are
inside the area and the damaged rectangle in 2D screen coordinates is
added to damaged_rects. */
void sculptmode_add_damaged_rect(EditData *e, ListBase *damaged_rects)
void sculptmode_add_damaged_rect(EditData *e)
{
short p[2];
const float radius= brush_size();
@@ -896,7 +897,7 @@ void sculptmode_add_damaged_rect(EditData *e, ListBase *damaged_rects)
rn->r.xmax= p[0]+radius;
rn->r.ymax= p[1]+radius;
BLI_addtail(damaged_rects,rn);
BLI_addtail(&sculpt_session()->damaged_rects, rn);
/* Update insides */
for(i=0; i<me->totvert; ++i) {
@@ -909,8 +910,7 @@ void sculptmode_add_damaged_rect(EditData *e, ListBase *damaged_rects)
}
}
void do_brush_action(float *vertexcosnos, EditData e,
ListBase *damaged_verts, ListBase *damaged_rects)
void do_brush_action(EditData e)
{
int i;
float av_dist;
@@ -920,8 +920,9 @@ void do_brush_action(float *vertexcosnos, EditData e,
Mesh *me= get_mesh(OBACT);
const float bstrength= brush_strength(&e);
KeyBlock *keyblock= ob_get_keyblock(OBACT);
SculptSession *ss = sculpt_session();
sculptmode_add_damaged_rect(&e,damaged_rects);
sculptmode_add_damaged_rect(&e);
/* Build a list of all vertices that are potentially within the brush's
area of influence. Only do this once for the grab brush. */
@@ -929,7 +930,7 @@ void do_brush_action(float *vertexcosnos, EditData e,
for(i=0; i<me->totvert; ++i) {
/* Projverts.inside provides a rough bounding box */
if(projverts[i].inside) {
vert= vertexcosnos ? &vertexcosnos[i*6] : me->mvert[i].co;
vert= ss->vertexcosnos ? &ss->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");
@@ -985,11 +986,11 @@ void do_brush_action(float *vertexcosnos, EditData e,
}
}
if(vertexcosnos)
if(ss->vertexcosnos)
BLI_freelistN(&active_verts);
else {
if(!e.grabdata)
addlisttolist(damaged_verts, &active_verts);
addlisttolist(&ss->damaged_verts, &active_verts);
}
}
}
@@ -1019,27 +1020,28 @@ EditData flip_editdata(EditData *e, const char symm)
return fe;
}
void do_symmetrical_brush_actions(float *vertexcosnos, EditData *e,
ListBase *damaged_verts, ListBase *damaged_rects)
void do_symmetrical_brush_actions(EditData * e, short co[2], short pr_co[2])
{
const char symm= sculpt_data()->symm;
init_editdata(e, co, pr_co);
do_brush_action(vertexcosnos, flip_editdata(e, 0), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, 0));
if(symm & SYMM_X)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, SYMM_X));
if(symm & SYMM_Y)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_Y), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, SYMM_Y));
if(symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_Z), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, SYMM_Z));
if(symm & SYMM_X && symm & SYMM_Y)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X | SYMM_Y), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, SYMM_X | SYMM_Y));
if(symm & SYMM_X && symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X | SYMM_Z), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, SYMM_X | SYMM_Z));
if(symm & SYMM_Y && symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_Y | SYMM_Z), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, SYMM_Y | SYMM_Z));
if(symm & SYMM_X && symm & SYMM_Y && symm & SYMM_Z)
do_brush_action(vertexcosnos, flip_editdata(e, SYMM_X | SYMM_Y | SYMM_Z), damaged_verts, damaged_rects);
do_brush_action(flip_editdata(e, SYMM_X | SYMM_Y | SYMM_Z));
}
void add_face_normal(vec3f *norm, const MFace* face)
@@ -1165,12 +1167,15 @@ void sculptmode_update_tex()
}
}
void init_editdata(SculptData *sd, EditData *e, short *mouse, short *pr_mouse, const char flip)
/* pr_mouse is only used for the grab brush, can be NULL otherwise */
void init_editdata(EditData *e, short *mouse, short *pr_mouse)
{
SculptData *sd = sculpt_data();
const float mouse_depth= get_depth(mouse[0],mouse[1]);
vec3f brush_edge_loc, zero_loc, oldloc;
ModifierData *md;
int i;
const char flip = (get_qual() == LR_SHIFTKEY);
e->flip= flip;
@@ -1182,6 +1187,10 @@ void init_editdata(SculptData *sd, EditData *e, short *mouse, short *pr_mouse, c
mouse_depth);
e->size= VecLenf(&e->center.x,&brush_edge_loc.x);
/* Set the pivot to allow the model to rotate around the center of the brush */
if(get_depth(mouse[0],mouse[1]) < 1.0)
sculpt_session()->pivot= e->center;
/* Now project the Up, Right, and Out normals from view to model coords */
zero_loc= unproject(0, 0, 0);
e->up= unproject(0, -1, 0);
@@ -1239,7 +1248,6 @@ void init_editdata(SculptData *sd, EditData *e, short *mouse, short *pr_mouse, c
}
}
}
void sculptmode_set_strength(const int delta)
{
int val = sculptmode_brush()->strength + delta;
@@ -1625,9 +1633,6 @@ void sculpt(void)
SculptSession *ss= sculpt_session();
Object *ob= OBACT;
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;
@@ -1649,6 +1654,13 @@ void sculpt(void)
ss= sd->session;
}
if(sd->flags & SCULPT_INPUT_SMOOTH)
sculpt_stroke_new(256);
ss->damaged_rects.first = ss->damaged_rects.last = NULL;
ss->damaged_verts.first = ss->damaged_verts.last = NULL;
ss->vertexcosnos = NULL;
/* Check that vertex users are up-to-date */
if(ob != active_ob || ss->vertex_users_size != get_mesh(ob)->totvert) {
sculptmode_free_vertexusers(ss);
@@ -1686,8 +1698,8 @@ void sculpt(void)
init_sculptmatrices();
if(modifier_calculations)
vertexcosnos= mesh_get_mapped_verts_nors(ob);
sculptmode_update_all_projverts(vertexcosnos);
ss->vertexcosnos= mesh_get_mapped_verts_nors(ob);
sculptmode_update_all_projverts(ss->vertexcosnos);
e.grabdata= NULL;
e.layer_disps= NULL;
@@ -1708,56 +1720,43 @@ void sculpt(void)
if(firsttime || mouse[0]!=mvalo[0] || mouse[1]!=mvalo[1] || sculptmode_brush()->airbrush) {
firsttime= 0;
if(sd->flags & SCULPT_INPUT_SMOOTH)
sculpt_stroke_add_point(mouse[0], mouse[1]);
spacing+= sqrt(pow(mvalo[0]-mouse[0],2)+pow(mvalo[1]-mouse[1],2));
if(modifier_calculations && !vertexcosnos)
vertexcosnos= mesh_get_mapped_verts_nors(ob);
if(modifier_calculations && !ss->vertexcosnos)
ss->vertexcosnos= mesh_get_mapped_verts_nors(ob);
if(G.scene->sculptdata.brush_type != GRAB_BRUSH && (sd->spacing==0 || spacing>sd->spacing)) {
char i;
float t= G.scene->sculptdata.averaging-1;
const float sub= 1/(t+1);
t/= (t+1);
for(i=0; i<G.scene->sculptdata.averaging; ++i) {
short avgco[2]= {mvalo[0]*t+mouse[0]*(1-t),
mvalo[1]*t+mouse[1]*(1-t)};
init_editdata(&G.scene->sculptdata,&e,avgco,mvalo,get_qual()==LR_SHIFTKEY);
if(get_depth(mouse[0],mouse[1]) < 1.0)
ss->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;
if(G.scene->sculptdata.brush_type != GRAB_BRUSH) {
if(sd->flags & SCULPT_INPUT_SMOOTH) {
sculpt_stroke_apply(&e);
}
else if(sd->spacing==0 || spacing>sd->spacing) {
do_symmetrical_brush_actions(&e, mouse, NULL);
spacing= 0;
}
spacing= 0;
}
else if(sd->brush_type==GRAB_BRUSH) {
init_editdata(&G.scene->sculptdata,&e,mouse,mvalo,0);
else {
do_symmetrical_brush_actions(&e, mouse, mvalo);
ss->pivot= unproject(mouse[0],mouse[1],e.grabdata->depth);
do_symmetrical_brush_actions(vertexcosnos,&e,&damaged_verts,&damaged_rects);
}
if(modifier_calculations || ob_get_keyblock(ob))
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
if(modifier_calculations || sd->brush_type == GRAB_BRUSH || !(sd->draw_flag & SCULPTDRAW_FAST)) {
calc_damaged_verts(&damaged_verts,e.grabdata);
calc_damaged_verts(&ss->damaged_verts,e.grabdata);
scrarea_do_windraw(curarea);
screen_swapbuffers();
} else { /* Optimized drawing */
calc_damaged_verts(&damaged_verts,e.grabdata);
calc_damaged_verts(&ss->damaged_verts,e.grabdata);
/* Draw the stored image to the screen */
glAccum(GL_RETURN, 1);
/* Clear each of the area(s) modified by the brush */
for(rn=damaged_rects.first; rn; rn= rn->next) {
for(rn=ss->damaged_rects.first; rn; rn= rn->next) {
float col[3];
rcti clp= rn->r;
rcti *win= &curarea->winrct;
@@ -1798,20 +1797,26 @@ void sculpt(void)
myswapbuffers();
}
BLI_freelistN(&damaged_rects);
BLI_freelistN(&ss->damaged_rects);
mvalo[0]= mouse[0];
mvalo[1]= mouse[1];
if(vertexcosnos) {
MEM_freeN(vertexcosnos);
vertexcosnos= NULL;
if(ss->vertexcosnos) {
MEM_freeN(ss->vertexcosnos);
ss->vertexcosnos= NULL;
}
}
else BIF_wait_for_statechange();
}
if(sd->flags & SCULPT_INPUT_SMOOTH) {
sculpt_stroke_apply_all(&e);
calc_damaged_verts(&ss->damaged_verts,e.grabdata);
BLI_freelistN(&ss->damaged_rects);
}
if(projverts) MEM_freeN(projverts);
projverts= NULL;
if(e.layer_disps) MEM_freeN(e.layer_disps);
@@ -1823,6 +1828,7 @@ void sculpt(void)
BLI_freelistN(&e.grabdata->active_verts[i]);
MEM_freeN(e.grabdata);
}
sculpt_stroke_free();
switch(G.scene->sculptdata.brush_type) {
case DRAW_BRUSH: