Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/brush.c')
-rw-r--r--source/blender/blenkernel/intern/brush.c688
1 files changed, 563 insertions, 125 deletions
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 4b8c3a2a0f4..71a43994363 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -35,6 +35,7 @@
#include "DNA_brush_types.h"
#include "DNA_color_types.h"
#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
#include "DNA_windowmanager_types.h"
#include "WM_types.h"
@@ -53,8 +54,7 @@
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
-
-
+#include "BKE_icons.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -62,6 +62,58 @@
#include "RE_render_ext.h" /* externtex */
#include "RE_shader_ext.h"
+static void brush_set_defaults(Brush *brush)
+{
+ brush->blend = 0;
+ brush->flag = 0;
+
+ brush->ob_mode = (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT);
+
+ /* BRUSH SCULPT TOOL SETTINGS */
+ brush->size= 35; /* radius of the brush in pixels */
+ brush->alpha= 0.5f; /* brush strength/intensity probably variable should be renamed? */
+ brush->autosmooth_factor= 0.0f;
+ brush->crease_pinch_factor= 0.5f;
+ brush->sculpt_plane = SCULPT_DISP_DIR_AREA;
+ brush->plane_offset= 0.0f; /* how far above or below the plane that is found by averaging the faces */
+ brush->plane_trim= 0.5f;
+ brush->clone.alpha= 0.5f;
+ brush->normal_weight= 0.0f;
+ brush->flag |= BRUSH_ALPHA_PRESSURE;
+
+ /* BRUSH PAINT TOOL SETTINGS */
+ brush->rgb[0]= 1.0f; /* default rgb color of the brush when painting - white */
+ brush->rgb[1]= 1.0f;
+ brush->rgb[2]= 1.0f;
+
+ /* BRUSH STROKE SETTINGS */
+ brush->flag |= (BRUSH_SPACE|BRUSH_SPACE_ATTEN);
+ brush->spacing= 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
+
+ brush->smooth_stroke_radius= 75;
+ brush->smooth_stroke_factor= 0.9f;
+
+ brush->rate= 0.1f; /* time delay between dots of paint or sculpting when doing airbrush mode */
+
+ brush->jitter= 0.0f;
+
+ /* BRUSH TEXTURE SETTINGS */
+ default_mtex(&brush->mtex);
+
+ brush->texture_sample_bias= 0; /* value to added to texture samples */
+ brush->texture_overlay_alpha= 33;
+
+ /* brush appearance */
+
+ brush->add_col[0]= 1.00; /* add mode color is light red */
+ brush->add_col[1]= 0.39;
+ brush->add_col[2]= 0.39;
+
+ brush->sub_col[0]= 0.39; /* subtract mode color is light blue */
+ brush->sub_col[1]= 0.39;
+ brush->sub_col[2]= 1.00;
+}
+
/* Datablock add/copy/free/make_local */
Brush *add_brush(const char *name)
@@ -70,29 +122,17 @@ Brush *add_brush(const char *name)
brush= alloc_libblock(&G.main->brush, ID_BR, name);
- brush->rgb[0]= 1.0f;
- brush->rgb[1]= 1.0f;
- brush->rgb[2]= 1.0f;
- brush->alpha= 0.2f;
- brush->size= 25;
- brush->spacing= 7.5f;
- brush->smooth_stroke_radius= 75;
- brush->smooth_stroke_factor= 0.9;
- brush->rate= 0.1f;
- brush->jitter= 0.0f;
- brush->clone.alpha= 0.5;
- brush->sculpt_tool = SCULPT_TOOL_DRAW;
- brush->flag |= BRUSH_SPACE;
+ /* enable fake user by default */
+ brush->id.flag |= LIB_FAKEUSER;
+ brush_set_defaults(brush);
+
+ brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
+
+ /* the default alpha falloff curve */
brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
-
- default_mtex(&brush->mtex);
- /* enable fake user by default */
- brush->id.flag |= LIB_FAKEUSER;
- brush_toggled_fake_user(brush);
-
- return brush;
+ return brush;
}
Brush *copy_brush(Brush *brush)
@@ -101,14 +141,18 @@ Brush *copy_brush(Brush *brush)
brushn= copy_libblock(brush);
- if(brush->mtex.tex) id_us_plus((ID*)brush->mtex.tex);
-
+ if (brush->mtex.tex)
+ id_us_plus((ID*)brush->mtex.tex);
+
+ if (brush->icon_imbuf)
+ brushn->icon_imbuf= IMB_dupImBuf(brush->icon_imbuf);
+
brushn->curve= curvemapping_copy(brush->curve);
/* enable fake user by default */
if (!(brushn->id.flag & LIB_FAKEUSER)) {
brushn->id.flag |= LIB_FAKEUSER;
- brush_toggled_fake_user(brushn);
+ brushn->id.us++;
}
return brushn;
@@ -117,8 +161,14 @@ Brush *copy_brush(Brush *brush)
/* not brush itself */
void free_brush(Brush *brush)
{
- if(brush->mtex.tex) brush->mtex.tex->id.us--;
-
+ if (brush->mtex.tex)
+ brush->mtex.tex->id.us--;
+
+ if (brush->icon_imbuf)
+ IMB_freeImBuf(brush->icon_imbuf);
+
+ BKE_previewimg_free(&(brush->preview));
+
curvemapping_free(brush->curve);
}
@@ -147,7 +197,7 @@ void make_local_brush(Brush *brush)
if(scene->id.lib) lib= 1;
else local= 1;
}
-
+
if(local && lib==0) {
brush->id.lib= 0;
brush->id.flag= LIB_LOCAL;
@@ -156,7 +206,7 @@ void make_local_brush(Brush *brush)
/* enable fake user by default */
if (!(brush->id.flag & LIB_FAKEUSER)) {
brush->id.flag |= LIB_FAKEUSER;
- brush_toggled_fake_user(brush);
+ brush->id.us++;
}
}
else if(local && lib) {
@@ -174,55 +224,176 @@ void make_local_brush(Brush *brush)
}
}
-/* Library Operations */
-
-int brush_set_nr(Brush **current_brush, int nr, const char *name)
+void brush_debug_print_state(Brush *br)
{
- ID *idtest, *id;
+ Brush def;
+
+ /* create a fake brush and set it to the defaults */
+ memset(&def, 0, sizeof(Brush));
+ brush_set_defaults(&def);
- id= (ID*)(*current_brush);
- idtest= (ID*)BLI_findlink(&G.main->brush, nr-1);
+#define BR_TEST(field, t) \
+ if(br->field != def.field) \
+ printf("br->" #field " = %" #t ";\n", br->field)
+
+#define BR_TEST_FLAG(_f) \
+ if((br->flag & _f) && !(def.flag & _f)) \
+ printf("br->flag |= " #_f ";\n"); \
+ else if(!(br->flag & _f) && (def.flag & _f)) \
+ printf("br->flag &= ~" #_f ";\n")
- if(idtest==0) { /* new brush */
- if(id) idtest= (ID *)copy_brush((Brush *)id);
- else idtest= (ID *)add_brush(name);
- idtest->us--;
- }
- if(idtest!=id) {
- brush_delete(current_brush);
- *current_brush= (Brush *)idtest;
- id_us_plus(idtest);
-
- return 1;
- }
-
- return 0;
-}
-int brush_delete(Brush **current_brush)
-{
- if (*current_brush) {
- (*current_brush)->id.us--;
- *current_brush= NULL;
-
- return 1;
- }
-
- return 0;
+ /* print out any non-default brush state */
+ BR_TEST(normal_weight, f);
+
+ BR_TEST(blend, d);
+ BR_TEST(size, d);
+
+ /* br->flag */
+ BR_TEST_FLAG(BRUSH_AIRBRUSH);
+ BR_TEST_FLAG(BRUSH_TORUS);
+ BR_TEST_FLAG(BRUSH_ALPHA_PRESSURE);
+ BR_TEST_FLAG(BRUSH_SIZE_PRESSURE);
+ BR_TEST_FLAG(BRUSH_JITTER_PRESSURE);
+ BR_TEST_FLAG(BRUSH_SPACING_PRESSURE);
+ BR_TEST_FLAG(BRUSH_FIXED_TEX);
+ BR_TEST_FLAG(BRUSH_RAKE);
+ BR_TEST_FLAG(BRUSH_ANCHORED);
+ BR_TEST_FLAG(BRUSH_DIR_IN);
+ BR_TEST_FLAG(BRUSH_SPACE);
+ BR_TEST_FLAG(BRUSH_SMOOTH_STROKE);
+ BR_TEST_FLAG(BRUSH_PERSISTENT);
+ BR_TEST_FLAG(BRUSH_ACCUMULATE);
+ BR_TEST_FLAG(BRUSH_LOCK_ALPHA);
+ BR_TEST_FLAG(BRUSH_ORIGINAL_NORMAL);
+ BR_TEST_FLAG(BRUSH_OFFSET_PRESSURE);
+ BR_TEST_FLAG(BRUSH_SPACE_ATTEN);
+ BR_TEST_FLAG(BRUSH_ADAPTIVE_SPACE);
+ BR_TEST_FLAG(BRUSH_LOCK_SIZE);
+ BR_TEST_FLAG(BRUSH_TEXTURE_OVERLAY);
+ BR_TEST_FLAG(BRUSH_EDGE_TO_EDGE);
+ BR_TEST_FLAG(BRUSH_RESTORE_MESH);
+ BR_TEST_FLAG(BRUSH_INVERSE_SMOOTH_PRESSURE);
+ BR_TEST_FLAG(BRUSH_RANDOM_ROTATION);
+ BR_TEST_FLAG(BRUSH_PLANE_TRIM);
+ BR_TEST_FLAG(BRUSH_FRONTFACE);
+ BR_TEST_FLAG(BRUSH_CUSTOM_ICON);
+
+ BR_TEST(jitter, f);
+ BR_TEST(spacing, d);
+ BR_TEST(smooth_stroke_radius, d);
+ BR_TEST(smooth_stroke_factor, f);
+ BR_TEST(rate, f);
+
+ BR_TEST(alpha, f);
+
+ BR_TEST(sculpt_plane, d);
+
+ BR_TEST(plane_offset, f);
+
+ BR_TEST(autosmooth_factor, f);
+
+ BR_TEST(crease_pinch_factor, f);
+
+ BR_TEST(plane_trim, f);
+
+ BR_TEST(texture_sample_bias, f);
+ BR_TEST(texture_overlay_alpha, d);
+
+ BR_TEST(add_col[0], f);
+ BR_TEST(add_col[1], f);
+ BR_TEST(add_col[2], f);
+ BR_TEST(sub_col[0], f);
+ BR_TEST(sub_col[1], f);
+ BR_TEST(sub_col[2], f);
+
+ printf("\n");
+
+#undef BR_TEST
+#undef BR_TEST_FLAG
}
-void brush_toggled_fake_user(Brush *brush)
+void brush_reset_sculpt(Brush *br)
{
- ID *id= (ID*)brush;
- if(id) {
- if(id->flag & LIB_FAKEUSER) {
- id_us_plus(id);
- } else {
- id->us--;
- }
+ /* enable this to see any non-default
+ settings used by a brush:
+
+ brush_debug_print_state(br);
+ */
+
+ brush_set_defaults(br);
+ brush_curve_preset(br, CURVE_PRESET_SMOOTH);
+
+ switch(br->sculpt_tool) {
+ case SCULPT_TOOL_CLAY:
+ br->flag |= BRUSH_FRONTFACE;
+ break;
+ case SCULPT_TOOL_CREASE:
+ br->flag |= BRUSH_DIR_IN;
+ br->alpha = 0.25;
+ break;
+ case SCULPT_TOOL_FILL:
+ br->add_col[1] = 1;
+ br->sub_col[0] = 0.25;
+ br->sub_col[1] = 1;
+ break;
+ case SCULPT_TOOL_FLATTEN:
+ br->add_col[1] = 1;
+ br->sub_col[0] = 0.25;
+ br->sub_col[1] = 1;
+ break;
+ case SCULPT_TOOL_INFLATE:
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ br->sub_col[0] = 0.250000;
+ br->sub_col[1] = 0.250000;
+ br->sub_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_NUDGE:
+ br->add_col[0] = 0.250000;
+ br->add_col[1] = 1.000000;
+ br->add_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_PINCH:
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ br->sub_col[0] = 0.250000;
+ br->sub_col[1] = 0.250000;
+ br->sub_col[2] = 0.250000;
+ break;
+ case SCULPT_TOOL_SCRAPE:
+ br->add_col[1] = 1.000000;
+ br->sub_col[0] = 0.250000;
+ br->sub_col[1] = 1.000000;
+ break;
+ case SCULPT_TOOL_ROTATE:
+ break;
+ case SCULPT_TOOL_SMOOTH:
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->spacing = 5;
+ br->add_col[0] = 0.750000;
+ br->add_col[1] = 0.750000;
+ br->add_col[2] = 0.750000;
+ break;
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ case SCULPT_TOOL_THUMB:
+ br->size = 75;
+ br->flag &= ~BRUSH_ALPHA_PRESSURE;
+ br->flag &= ~BRUSH_SPACE;
+ br->flag &= ~BRUSH_SPACE_ATTEN;
+ br->add_col[0] = 0.250000;
+ br->add_col[1] = 1.000000;
+ br->add_col[2] = 0.250000;
+ break;
+ default:
+ break;
}
}
+/* Library Operations */
void brush_curve_preset(Brush *b, /*CurveMappingPreset*/int preset)
{
CurveMap *cm = NULL;
@@ -234,7 +405,7 @@ void brush_curve_preset(Brush *b, /*CurveMappingPreset*/int preset)
cm->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
b->curve->preset = preset;
- curvemap_reset(cm, &b->curve->clipr, b->curve->preset);
+ curvemap_reset(cm, &b->curve->clipr, b->curve->preset, CURVEMAP_SLOPE_NEGATIVE);
curvemapping_changed(b->curve, 0);
}
@@ -306,12 +477,6 @@ int brush_clone_image_delete(Brush *brush)
return 0;
}
-void brush_check_exists(Brush **brush, const char *name)
-{
- if(*brush==NULL)
- brush_set_nr(brush, 1, name);
-}
-
/* Brush Sampling */
void brush_sample_tex(Brush *brush, float *xy, float *rgba)
{
@@ -320,9 +485,10 @@ void brush_sample_tex(Brush *brush, float *xy, float *rgba)
if (mtex && mtex->tex) {
float co[3], tin, tr, tg, tb, ta;
int hasrgb;
-
- co[0]= xy[0]/(brush->size >> 1);
- co[1]= xy[1]/(brush->size >> 1);
+ const int radius= brush_size(brush);
+
+ co[0]= xy[0]/radius;
+ co[1]= xy[1]/radius;
co[2]= 0.0f;
hasrgb= externtex(mtex, co, &tin, &tr, &tg, &tb, &ta);
@@ -345,23 +511,24 @@ void brush_sample_tex(Brush *brush, float *xy, float *rgba)
}
-void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **outbuf)
+void brush_imbuf_new(Brush *brush, short flt, short texfall, int bufsize, ImBuf **outbuf)
{
ImBuf *ibuf;
float xy[2], dist, rgba[4], *dstf;
int x, y, rowbytes, xoff, yoff, imbflag;
- int maxsize = brush->size >> 1;
+ const int radius= brush_size(brush);
char *dst, crgb[3];
+ const float alpha= brush_alpha(brush);
imbflag= (flt)? IB_rectfloat: IB_rect;
- xoff = -size/2.0f + 0.5f;
- yoff = -size/2.0f + 0.5f;
- rowbytes= size*4;
+ xoff = -bufsize/2.0f + 0.5f;
+ yoff = -bufsize/2.0f + 0.5f;
+ rowbytes= bufsize*4;
if (*outbuf)
ibuf= *outbuf;
else
- ibuf= IMB_allocImBuf(size, size, 32, imbflag, 0);
+ ibuf= IMB_allocImBuf(bufsize, bufsize, 32, imbflag, 0);
if (flt) {
for (y=0; y < ibuf->y; y++) {
@@ -375,7 +542,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o
dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
VECCOPY(dstf, brush->rgb);
- dstf[3]= brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize);
+ dstf[3]= alpha*brush_curve_strength_clamp(brush, dist, radius);
}
else if (texfall == 1) {
brush_sample_tex(brush, xy, dstf);
@@ -388,7 +555,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o
dstf[0] = rgba[0]*brush->rgb[0];
dstf[1] = rgba[1]*brush->rgb[1];
dstf[2] = rgba[2]*brush->rgb[2];
- dstf[3] = rgba[3]*brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize);
+ dstf[3] = rgba[3]*alpha*brush_curve_strength_clamp(brush, dist, radius);
}
}
}
@@ -411,7 +578,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o
dst[0]= crgb[0];
dst[1]= crgb[1];
dst[2]= crgb[2];
- dst[3]= FTOCHAR(brush->alpha*brush_curve_strength(brush, dist, maxsize));
+ dst[3]= FTOCHAR(alpha*brush_curve_strength(brush, dist, radius));
}
else if (texfall == 1) {
brush_sample_tex(brush, xy, rgba);
@@ -427,7 +594,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o
dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]);
dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]);
dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]);
- dst[3] = FTOCHAR(rgba[3]*brush->alpha*brush_curve_strength_clamp(brush, dist, maxsize));
+ dst[3] = FTOCHAR(rgba[3]*alpha*brush_curve_strength_clamp(brush, dist, radius));
}
}
}
@@ -441,7 +608,7 @@ void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **o
typedef struct BrushPainterCache {
short enabled;
- int size; /* size override, if 0 uses brush->size */
+ int size; /* size override, if 0 uses 2*brush_size(brush) */
short flt; /* need float imbuf? */
short texonly; /* no alpha, color or fallof, only texture in imbuf */
@@ -486,8 +653,8 @@ BrushPainter *brush_painter_new(Brush *brush)
painter->firsttouch= 1;
painter->cache.lastsize= -1; /* force ibuf create in refresh */
- painter->startsize = brush->size;
- painter->startalpha = brush->alpha;
+ painter->startsize = brush_size(brush);
+ painter->startalpha = brush_alpha(brush);
painter->startjitter = brush->jitter;
painter->startspacing = brush->spacing;
@@ -520,8 +687,8 @@ void brush_painter_free(BrushPainter *painter)
{
Brush *brush = painter->brush;
- brush->size = painter->startsize;
- brush->alpha = painter->startalpha;
+ brush_set_size(brush, painter->startsize);
+ brush_set_alpha(brush, painter->startalpha);
brush->jitter = painter->startjitter;
brush->spacing = painter->startspacing;
@@ -538,9 +705,10 @@ static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, i
float *bf, *mf, *tf, *otf=NULL, xoff, yoff, xy[2], rgba[4];
char *b, *m, *t, *ot= NULL;
int dotexold, origx= x, origy= y;
+ const int radius= brush_size(brush);
- xoff = -brush->size/2.0f + 0.5f;
- yoff = -brush->size/2.0f + 0.5f;
+ xoff = -radius + 0.5f;
+ yoff = -radius + 0.5f;
xoff += (int)pos[0] - (int)painter->startpaintpos[0];
yoff += (int)pos[1] - (int)painter->startpaintpos[1];
@@ -622,14 +790,15 @@ static void brush_painter_fixed_tex_partial_update(BrushPainter *painter, float
BrushPainterCache *cache= &painter->cache;
ImBuf *oldtexibuf, *ibuf;
int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+ const int diameter= 2*brush_size(brush);
imbflag= (cache->flt)? IB_rectfloat: IB_rect;
if (!cache->ibuf)
- cache->ibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0);
+ cache->ibuf= IMB_allocImBuf(diameter, diameter, 32, imbflag, 0);
ibuf= cache->ibuf;
oldtexibuf= cache->texibuf;
- cache->texibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0);
+ cache->texibuf= IMB_allocImBuf(diameter, diameter, 32, imbflag, 0);
if (oldtexibuf) {
srcx= srcy= 0;
@@ -676,9 +845,13 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos)
MTex *mtex= &brush->mtex;
int size;
short flt;
+ const int diameter= 2*brush_size(brush);
+ const float alpha= brush_alpha(brush);
- if ((brush->size != cache->lastsize) || (brush->alpha != cache->lastalpha)
- || (brush->jitter != cache->lastjitter)) {
+ if (diameter != cache->lastsize ||
+ alpha != cache->lastalpha ||
+ brush->jitter != cache->lastjitter)
+ {
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
cache->ibuf= NULL;
@@ -689,7 +862,7 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos)
}
flt= cache->flt;
- size= (cache->size)? cache->size: brush->size;
+ size= (cache->size)? cache->size: diameter;
if (!(mtex && mtex->tex) || (mtex->tex->type==0)) {
brush_imbuf_new(brush, flt, 0, size, &cache->ibuf);
@@ -701,8 +874,8 @@ static void brush_painter_refresh_cache(BrushPainter *painter, float *pos)
else
brush_imbuf_new(brush, flt, 2, size, &cache->ibuf);
- cache->lastsize= brush->size;
- cache->lastalpha= brush->alpha;
+ cache->lastsize= diameter;
+ cache->lastalpha= alpha;
cache->lastjitter= brush->jitter;
}
else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) {
@@ -721,21 +894,31 @@ void brush_painter_break_stroke(BrushPainter *painter)
static void brush_apply_pressure(BrushPainter *painter, Brush *brush, float pressure)
{
- if (brush->flag & BRUSH_ALPHA_PRESSURE)
- brush->alpha = MAX2(0.0, painter->startalpha*pressure);
- if (brush->flag & BRUSH_SIZE_PRESSURE)
- brush->size = MAX2(1.0, painter->startsize*pressure);
+ if (brush_use_alpha_pressure(brush))
+ brush_set_alpha(brush, MAX2(0.0, painter->startalpha*pressure));
+ if (brush_use_size_pressure(brush))
+ brush_set_size(brush, MAX2(1.0, painter->startsize*pressure));
if (brush->flag & BRUSH_JITTER_PRESSURE)
brush->jitter = MAX2(0.0, painter->startjitter*pressure);
if (brush->flag & BRUSH_SPACING_PRESSURE)
brush->spacing = MAX2(1.0, painter->startspacing*(1.5f-pressure));
}
-static void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos)
+void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos)
{
if(brush->jitter){
- jitterpos[0] = pos[0] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2);
- jitterpos[1] = pos[1] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2);
+ float rand_pos[2];
+ const int radius= brush_size(brush);
+ const int diameter= 2*radius;
+
+ // find random position within a circle of diameter 1
+ do {
+ rand_pos[0] = BLI_frand()-0.5f;
+ rand_pos[1] = BLI_frand()-0.5f;
+ } while (len_v2(rand_pos) > 0.5f);
+
+ jitterpos[0] = pos[0] + 2*rand_pos[0]*diameter*brush->jitter;
+ jitterpos[1] = pos[1] + 2*rand_pos[1]*diameter*brush->jitter;
}
else {
VECCOPY2D(jitterpos, pos);
@@ -774,7 +957,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
double starttime, curtime= time;
/* compute brush spacing adapted to brush size */
- spacing= brush->rate; //brush->size*brush->spacing*0.01f;
+ spacing= brush->rate; //radius*brush->spacing*0.01f;
/* setup starting time, direction vector and accumulated time */
starttime= painter->accumtime;
@@ -805,11 +988,12 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
else {
float startdistance, spacing, step, paintpos[2], dmousepos[2], finalpos[2];
float t, len, press;
+ const int radius= brush_size(brush);
- /* compute brush spacing adapted to brush size, spacing may depend
+ /* compute brush spacing adapted to brush radius, spacing may depend
on pressure, so update it */
brush_apply_pressure(painter, brush, painter->lastpressure);
- spacing= MAX2(1.0f, brush->size)*brush->spacing*0.01f;
+ spacing= MAX2(1.0f, radius)*brush->spacing*0.01f;
/* setup starting distance, direction vector and accumulated distance */
startdistance= painter->accumdistance;
@@ -826,7 +1010,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
t = step/len;
press= (1.0f-t)*painter->lastpressure + t*pressure;
brush_apply_pressure(painter, brush, press);
- spacing= MAX2(1.0f, brush->size)*brush->spacing*0.01f;
+ spacing= MAX2(1.0f, radius)*brush->spacing*0.01f;
brush_jitter_pos(brush, paintpos, finalpos);
@@ -876,8 +1060,8 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
painter->lastmousepos[1]= pos[1];
painter->lastpressure= pressure;
- brush->alpha = painter->startalpha;
- brush->size = painter->startsize;
+ brush_set_alpha(brush, painter->startalpha);
+ brush_set_size(brush, painter->startsize);
brush->jitter = painter->startjitter;
brush->spacing = painter->startspacing;
@@ -887,7 +1071,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
/* Uses the brush curve control to find a strength value between 0 and 1 */
float brush_curve_strength_clamp(Brush *br, float p, const float len)
{
- if(p >= len) p= 1.0f;
+ if(p >= len) return 0;
else p= p/len;
p= curvemapping_evaluateF(br->curve, 0, p);
@@ -899,9 +1083,12 @@ float brush_curve_strength_clamp(Brush *br, float p, const float len)
* used for sculpt only */
float brush_curve_strength(Brush *br, float p, const float len)
{
- if(p >= len) p= 1.0f;
- else p= p/len;
- return curvemapping_evaluateF(br->curve, 0, p);
+ if(p >= len)
+ p= 1.0f;
+ else
+ p= p/len;
+
+ return curvemapping_evaluateF(br->curve, 0, p);
}
/* TODO: should probably be unified with BrushPainter stuff? */
@@ -915,7 +1102,7 @@ unsigned int *brush_gen_texture_cache(Brush *br, int half_side)
memset(&texres, 0, sizeof(TexResult));
- if(mtex && mtex->tex) {
+ if(mtex->tex) {
float x, y, step = 2.0 / side, co[3];
texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
@@ -930,7 +1117,7 @@ unsigned int *brush_gen_texture_cache(Brush *br, int half_side)
co[2]= 0.0f;
/* This is copied from displace modifier code */
- hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 1, &texres);
+ hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 0, &texres);
/* if the texture gave an RGB value, we assume it didn't give a valid
* intensity, so calculate one (formula from do_material_tex).
@@ -993,9 +1180,9 @@ void brush_radial_control_invoke(wmOperator *op, Brush *br, float size_weight)
float original_value= 0;
if(mode == WM_RADIALCONTROL_SIZE)
- original_value = br->size * size_weight;
+ original_value = brush_size(br) * size_weight;
else if(mode == WM_RADIALCONTROL_STRENGTH)
- original_value = br->alpha;
+ original_value = brush_alpha(br);
else if(mode == WM_RADIALCONTROL_ANGLE) {
MTex *mtex = brush_active_texture(br);
if(mtex)
@@ -1013,9 +1200,15 @@ int brush_radial_control_exec(wmOperator *op, Brush *br, float size_weight)
const float conv = 0.017453293;
if(mode == WM_RADIALCONTROL_SIZE)
- br->size = new_value * size_weight;
+ if (brush_use_locked_size(br)) {
+ float initial_value = RNA_float_get(op->ptr, "initial_value");
+ const float unprojected_radius = brush_unprojected_radius(br);
+ brush_set_unprojected_radius(br, unprojected_radius * new_value/initial_value * size_weight);
+ }
+ else
+ brush_set_size(br, new_value * size_weight);
else if(mode == WM_RADIALCONTROL_STRENGTH)
- br->alpha = new_value;
+ brush_set_alpha(br, new_value);
else if(mode == WM_RADIALCONTROL_ANGLE) {
MTex *mtex = brush_active_texture(br);
if(mtex)
@@ -1024,3 +1217,248 @@ int brush_radial_control_exec(wmOperator *op, Brush *br, float size_weight)
return OPERATOR_FINISHED;
}
+
+/* Unified Size and Strength */
+
+static void set_unified_settings(Brush *brush, short flag, int value)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ if (value)
+ sce->toolsettings->sculpt_paint_settings |= flag;
+ else
+ sce->toolsettings->sculpt_paint_settings &= ~flag;
+ }
+ }
+}
+
+static short unified_settings(Brush *brush)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ return sce->toolsettings->sculpt_paint_settings;
+ }
+ }
+
+ return 0;
+}
+
+static void set_unified_size(Brush *brush, int value)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ sce->toolsettings->sculpt_paint_unified_size= value;
+ }
+ }
+}
+
+static int unified_size(Brush *brush)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ return sce->toolsettings->sculpt_paint_unified_size;
+ }
+ }
+
+ return 35; // XXX magic number
+}
+
+static void set_unified_alpha(Brush *brush, float value)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ sce->toolsettings->sculpt_paint_unified_alpha= value;
+ }
+ }
+}
+
+static float unified_alpha(Brush *brush)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ return sce->toolsettings->sculpt_paint_unified_alpha;
+ }
+ }
+
+ return 0.5f; // XXX magic number
+}
+
+static void set_unified_unprojected_radius(Brush *brush, float value)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ sce->toolsettings->sculpt_paint_unified_unprojected_radius= value;
+ }
+ }
+}
+
+static float unified_unprojected_radius(Brush *brush)
+{
+ Scene *sce;
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings &&
+ ELEM4(brush,
+ paint_brush(&(sce->toolsettings->imapaint.paint)),
+ paint_brush(&(sce->toolsettings->vpaint->paint)),
+ paint_brush(&(sce->toolsettings->wpaint->paint)),
+ paint_brush(&(sce->toolsettings->sculpt->paint))))
+ {
+ return sce->toolsettings->sculpt_paint_unified_unprojected_radius;
+ }
+ }
+
+ return 0.125f; // XXX magic number
+}
+void brush_set_size(Brush *brush, int size)
+{
+ if (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE)
+ set_unified_size(brush, size);
+ else
+ brush->size= size;
+
+ //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
+}
+
+int brush_size(Brush *brush)
+{
+ return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? unified_size(brush) : brush->size;
+}
+
+void brush_set_use_locked_size(Brush *brush, int value)
+{
+ if (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) {
+ set_unified_settings(brush, SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE, value);
+ }
+ else {
+ if (value)
+ brush->flag |= BRUSH_LOCK_SIZE;
+ else
+ brush->flag &= ~BRUSH_LOCK_SIZE;
+ }
+
+ //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
+}
+
+int brush_use_locked_size(Brush *brush)
+{
+ return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? (unified_settings(brush) & SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE) : (brush->flag & BRUSH_LOCK_SIZE);
+}
+
+void brush_set_use_size_pressure(Brush *brush, int value)
+{
+ if (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) {
+ set_unified_settings(brush, SCULPT_PAINT_UNIFIED_SIZE_PRESSURE, value);
+ }
+ else {
+ if (value)
+ brush->flag |= BRUSH_SIZE_PRESSURE;
+ else
+ brush->flag &= ~BRUSH_SIZE_PRESSURE;
+ }
+
+ //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
+}
+
+int brush_use_size_pressure(Brush *brush)
+{
+ return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? (unified_settings(brush) & SCULPT_PAINT_UNIFIED_SIZE_PRESSURE) : (brush->flag & BRUSH_SIZE_PRESSURE);
+}
+
+void brush_set_use_alpha_pressure(Brush *brush, int value)
+{
+ if (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_ALPHA) {
+ set_unified_settings(brush, SCULPT_PAINT_UNIFIED_ALPHA_PRESSURE, value);
+ }
+ else {
+ if (value)
+ brush->flag |= BRUSH_ALPHA_PRESSURE;
+ else
+ brush->flag &= ~BRUSH_ALPHA_PRESSURE;
+ }
+
+ //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
+}
+
+int brush_use_alpha_pressure(Brush *brush)
+{
+ return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_ALPHA) ? (unified_settings(brush) & SCULPT_PAINT_UNIFIED_ALPHA_PRESSURE) : (brush->flag & BRUSH_ALPHA_PRESSURE);
+}
+
+void brush_set_unprojected_radius(Brush *brush, float unprojected_radius)
+{
+ if (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE)
+ set_unified_unprojected_radius(brush, unprojected_radius);
+ else
+ brush->unprojected_radius= unprojected_radius;
+
+ //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
+}
+
+float brush_unprojected_radius(Brush *brush)
+{
+ return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_SIZE) ? unified_unprojected_radius(brush) : brush->unprojected_radius;
+}
+
+void brush_set_alpha(Brush *brush, float alpha)
+{
+ if (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_ALPHA)
+ set_unified_alpha(brush, alpha);
+ else
+ brush->alpha= alpha;
+
+ //WM_main_add_notifier(NC_BRUSH|NA_EDITED, brush);
+}
+
+float brush_alpha(Brush *brush)
+{
+ return (unified_settings(brush) & SCULPT_PAINT_USE_UNIFIED_ALPHA) ? unified_alpha(brush) : brush->alpha;
+}