== 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:
@@ -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 *);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, "");
|
||||
|
||||
280
source/blender/src/sculptmode-stroke.c
Normal file
280
source/blender/src/sculptmode-stroke.c
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user