== 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

@@ -30,13 +30,15 @@
#ifndef BDR_SCULPTMODE_H
#define BDR_SCULPTMODE_H
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
/* For bglMats */
#include "BIF_glutil.h"
#include "transform.h"
struct uiBlock;
struct BrushData;
struct EditData;
struct IndexNode;
struct KeyBlock;
struct Mesh;
@@ -45,6 +47,7 @@ struct PartialVisibility;
struct Scene;
struct ScrArea;
struct SculptData;
struct SculptStroke;
typedef enum PropsetMode {
PropsetNone = 0,
@@ -75,6 +78,11 @@ typedef struct SculptSession {
struct ListBase *vertex_users;
struct IndexNode *vertex_users_mem;
int vertex_users_size;
/* Used temporarily per-stroke */
float *vertexcosnos;
ListBase damaged_rects;
ListBase damaged_verts;
/* Used to cache the render of the active texture */
unsigned int texcache_w, texcache_h, *texcache;
@@ -83,6 +91,8 @@ typedef struct SculptSession {
/* For rotating around a pivot point */
vec3f pivot;
struct SculptStroke *stroke;
} SculptSession;
SculptSession *sculpt_session(void);
@@ -102,15 +112,26 @@ void sculptmode_propset(const unsigned short event);
void sculptmode_selectbrush_menu(void);
void sculptmode_draw_mesh(int);
void sculpt_paint_brush(char clear);
void sculpt_stroke_draw();
struct BrushData *sculptmode_brush(void);
float tex_angle(void);
void do_symmetrical_brush_actions(struct EditData *e, short *, short *);
void sculptmode_update_tex(void);
char sculpt_modifiers_active(struct Object *ob);
void sculpt(void);
void set_sculptmode(void);
/* Stroke */
void sculpt_stroke_new(const int max);
void sculpt_stroke_free();
void sculpt_stroke_add_point(const short x, const short y);
void sculpt_stroke_apply(struct EditData *);
void sculpt_stroke_apply_all(struct EditData *e);
void sculpt_stroke_draw();
/* Partial Mesh Visibility */
struct PartialVisibility *sculptmode_copy_pmv(struct PartialVisibility *);
void sculptmode_pmv_free(struct PartialVisibility *);

View File

@@ -388,6 +388,7 @@ typedef struct SculptData
char texsep;
char averaging;
char flags;
char draw_flag;
@@ -397,6 +398,8 @@ typedef struct SculptData
/* Symmetry is separate from the other BrushData because the same
settings are always used for all brush types */
char symm;
char pad[7];
} SculptData;
typedef struct Scene {
@@ -603,6 +606,8 @@ typedef struct Scene {
#define FFMPEG_MULTIPLEX_AUDIO 1
#define FFMPEG_AUTOSPLIT_OUTPUT 2
/* SculptData.flags */
#define SCULPT_INPUT_SMOOTH 1
/* SculptData.brushtype */
#define DRAW_BRUSH 1
#define SMOOTH_BRUSH 2

View File

@@ -2920,6 +2920,10 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
PropsetData *pd= sculpt_session()->propset;
short r1=100, r2=100, r3=100;
short mouse[2];
if(sculpt_data()->flags & SCULPT_INPUT_SMOOTH)
sculpt_stroke_draw();
if(pd) {
if(pd->mode == PropsetSize) {
r1= sculptmode_brush()->size;

View File

@@ -4186,9 +4186,7 @@ void do_view3d_sculpt_inputmenu(void *arg, int event)
switch(event) {
case 0:
val= sd->averaging;
if(button(&val,1,10,"Averaging:")==0) return;
sd->averaging= val;
sd->flags ^= SCULPT_INPUT_SMOOTH;
break;
case 1:
val= sd->tablet_size;
@@ -4262,11 +4260,12 @@ uiBlock *view3d_sculpt_inputmenu(void *arg_unused)
{
uiBlock *block;
short yco= 0, menuwidth= 120;
SculptData *sd= &G.scene->sculptdata;
block= uiNewBlock(&curarea->uiblocks, "view3d_sculpt_inputmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
uiBlockSetButmFunc(block, do_view3d_sculpt_inputmenu, NULL);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Averaging", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefIconTextBut(block, BUTM, 1, ((sd->flags & SCULPT_INPUT_SMOOTH) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Smooth Stroke", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Tablet Size Adjust", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Tablet Strength Adjust", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
@@ -4287,7 +4286,7 @@ uiBlock *view3d_sculptmenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Sculpt Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBlockBut(block, view3d_sculpt_inputmenu, NULL, ICON_RIGHTARROW_THIN, "Input Devices", 0, yco-=20, 120, 19, "");
uiDefIconTextBlockBut(block, view3d_sculpt_inputmenu, NULL, ICON_RIGHTARROW_THIN, "Input Settings", 0, yco-=20, 120, 19, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ((sd->draw_flag & SCULPTDRAW_BRUSH) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Display Brush", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
uiDefIconTextBut(block, BUTM, 1, ((sd->draw_flag & SCULPTDRAW_FAST) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Partial Redraw", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");

View File

@@ -0,0 +1,280 @@
/*
* $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) 2007 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*
* Storage and manipulation of sculptmode brush strokes.
*
*/
#include "MEM_guardedalloc.h"
#include "DNA_listBase.h"
#include "BLI_blenlib.h"
#include "BIF_gl.h"
#include "BDR_sculptmode.h"
#include <math.h>
/* Temporary storage of input stroke control points */
typedef struct StrokePoint {
struct StrokePoint *next, *prev;
short x, y;
} StrokePoint;
typedef struct SculptStroke {
short (*loc)[2];
int max;
int index;
float length;
ListBase final;
StrokePoint *final_mem;
} SculptStroke;
void sculpt_stroke_new(const int max)
{
SculptSession *ss = sculpt_session();
ss->stroke = MEM_callocN(sizeof(SculptStroke), "SculptStroke");
ss->stroke->loc = MEM_callocN(sizeof(short) * 2 * max, "SculptStroke.loc");
ss->stroke->max = max;
ss->stroke->index = -1;
}
void sculpt_stroke_free()
{
SculptSession *ss = sculpt_session();
if(ss && ss->stroke) {
if(ss->stroke->loc) MEM_freeN(ss->stroke->loc);
if(ss->stroke->final_mem) MEM_freeN(ss->stroke->final_mem);
MEM_freeN(ss->stroke);
ss->stroke = NULL;
}
}
void sculpt_stroke_add_point(const short x, const short y)
{
SculptStroke *stroke = sculpt_session()->stroke;
const int next = stroke->index + 1;
if(stroke->index == -1) {
stroke->loc[0][0] = x;
stroke->loc[0][1] = y;
stroke->index = 0;
}
else if(next < stroke->max) {
const int dx = x - stroke->loc[stroke->index][0];
const int dy = y - stroke->loc[stroke->index][1];
stroke->loc[next][0] = x;
stroke->loc[next][1] = y;
stroke->length += sqrt(dx*dx + dy*dy);
stroke->index = next;
}
}
void sculpt_stroke_smooth(SculptStroke *stroke)
{
/* Apply smoothing (exclude the first and last points)*/
StrokePoint *p = stroke->final.first;
if(p && p->next && p->next->next) {
for(p = p->next->next; p && p->next && p->next->next; p = p->next) {
p->x = p->prev->prev->x*0.1 + p->prev->x*0.2 + p->x*0.4 + p->next->x*0.2 + p->next->next->x*0.1;
p->y = p->prev->prev->y*0.1 + p->prev->y*0.2 + p->y*0.4 + p->next->y*0.2 + p->next->next->y*0.1;
}
}
}
void sculpt_stroke_create_final()
{
SculptStroke *stroke = sculpt_session()->stroke;
if(stroke) {
StrokePoint *p, *pnext;
int i;
/* Copy loc into final */
if(stroke->final_mem)
MEM_freeN(stroke->final_mem);
stroke->final_mem = MEM_callocN(sizeof(StrokePoint) * (stroke->index + 1) * 2, "SculptStroke.final");
stroke->final.first = stroke->final.last = NULL;
for(i = 0; i <= stroke->index; ++i) {
p = &stroke->final_mem[i];
p->x = stroke->loc[i][0];
p->y = stroke->loc[i][1];
BLI_addtail(&stroke->final, p);
}
/* Remove shortest edges */
for(p = ((StrokePoint*)stroke->final.first)->next; p && p->next; p = pnext) {
const int dx = p->x - p->prev->x;
const int dy = p->y - p->prev->y;
const float len = sqrt(dx*dx + dy*dy);
pnext = p->next;
if(len < 10) {
BLI_remlink(&stroke->final, p);
}
}
sculpt_stroke_smooth(stroke);
/* Subdivide edges */
for(p = stroke->final.first; p && p->next; p = pnext) {
StrokePoint *np = &stroke->final_mem[i++];
pnext = p->next;
np->x = (p->x + p->next->x) / 2;
np->y = (p->y + p->next->y) / 2;
BLI_insertlink(&stroke->final, p, np);
}
sculpt_stroke_smooth(stroke);
}
}
float sculpt_stroke_seglen(StrokePoint *p1, StrokePoint *p2)
{
int dx = p2->x - p1->x;
int dy = p2->y - p1->y;
return sqrt(dx*dx + dy*dy);
}
void sculpt_stroke_apply(struct EditData *e)
{
SculptStroke *stroke = sculpt_session()->stroke;
if(stroke) {
sculpt_stroke_create_final();
if(stroke->length > 200) {
const short spacing = 2;
const int dots = stroke->length / spacing;
int i;
StrokePoint *p = stroke->final.first;
float startloc = 0;
for(i = 0; i < dots && p && p->next; ++i) {
const float dotloc = spacing * i;
short co[2];
float len = sculpt_stroke_seglen(p, p->next);
float u, v;
/* Find edge containing dot */
while(dotloc > startloc + len && p && p->next && p->next->next) {
p = p->next;
startloc += len;
len = sculpt_stroke_seglen(p, p->next);
}
if(!p || !p->next) break;
u = (dotloc - startloc) / len;
v = 1 - u;
co[0] = p->x*u + p->next->x*v;
co[1] = p->y*u + p->next->y*v;
if(startloc > 100)
break;
do_symmetrical_brush_actions(e, co, NULL);
}
/* Replace remaining values in stroke->loc with remaining stroke->final values */
stroke->index = -1;
stroke->length = 0;
for(; p; p = p->next) {
++stroke->index;
stroke->loc[stroke->index][0] = p->x;
stroke->loc[stroke->index][1] = p->y;
if(p->next) {
stroke->length += sculpt_stroke_seglen(p, p->next);
}
}
}
}
}
void sculpt_stroke_apply_all(struct EditData *e)
{
SculptStroke *stroke = sculpt_session()->stroke;
sculpt_stroke_create_final();
if(stroke) {
const short spacing = 2;
const int dots = stroke->length / spacing;
int i;
StrokePoint *p = stroke->final.first;
float startloc = 0;
for(i = 0; i < dots && p && p->next; ++i) {
const float dotloc = spacing * i;
short co[2];
float len = sculpt_stroke_seglen(p, p->next);
float u, v;
/* Find edge containing dot */
while(dotloc > startloc + len && p && p->next && p->next->next) {
p = p->next;
startloc += len;
len = sculpt_stroke_seglen(p, p->next);
}
if(!p || !p->next) break;
u = (dotloc - startloc) / len;
v = 1 - u;
co[0] = p->x*u + p->next->x*v;
co[1] = p->y*u + p->next->y*v;
do_symmetrical_brush_actions(e, co, NULL);
}
}
}
void sculpt_stroke_draw()
{
SculptStroke *stroke = sculpt_session()->stroke;
if(stroke) {
StrokePoint *p;
/* Draws the original stroke */
/*glColor3f(1, 0, 0);
glBegin(GL_LINE_STRIP);
for(i = 0; i <= stroke->index; ++i)
glVertex2s(stroke->loc[i][0], stroke->loc[i][1]);
glEnd();*/
/* Draws the smoothed stroke */
glColor3f(0, 1, 0);
glBegin(GL_LINE_STRIP);
for(p = stroke->final.first; p; p = p->next)
glVertex2s(p->x, p->y);
glEnd();
}
}

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: