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:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2006-09-24 23:29:25 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2006-09-24 23:29:25 +0400
commitef7200741beaf9df968e8e8e7ef6cfed5a51ccb3 (patch)
tree3dac4fed58960e9a857a7d1382661ea6eb771c51
parent7f7f35d1ca75885eec6c062f9af00e4d0f39dbd0 (diff)
Basic pressure sensitivity support in imagepaint, for opacity, size,
falloff and spacing. Click the button labeled "P" next to the sliders. Works best for opacity, other options can give poor quality strokes in some cases. Also performance needs to be improved. Remember, works only on X11 and Mac, no Windows support for tablets yet.
-rw-r--r--source/blender/blenkernel/BKE_brush.h2
-rw-r--r--source/blender/blenkernel/intern/brush.c66
-rw-r--r--source/blender/makesdna/DNA_brush_types.h10
-rw-r--r--source/blender/src/buttons_editing.c12
-rw-r--r--source/blender/src/drawimage.c12
-rw-r--r--source/blender/src/imagepaint.c49
-rw-r--r--source/blender/src/vpaint.c3
7 files changed, 111 insertions, 43 deletions
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 52f86ef9c41..2c0034ad234 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -69,7 +69,7 @@ BrushPainter *brush_painter_new(struct Brush *brush);
void brush_painter_require_imbuf(BrushPainter *painter, short flt,
short texonly, int size);
int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos,
- double time, void *user);
+ double time, float pressure, void *user);
void brush_painter_break_stroke(BrushPainter *painter);
void brush_painter_free(BrushPainter *painter);
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 5ade66e4566..36e8c2137cc 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -299,6 +299,13 @@ void brush_check_exists(Brush **brush)
/* Brush Sampling */
+/*static float taylor_approx_cos(float f)
+{
+ f = f*f;
+ f = 1.0f - f/2.0f + f*f/24.0f;
+ return f;
+}*/
+
float brush_sample_falloff(Brush *brush, float dist)
{
float a, outer, inner;
@@ -310,10 +317,12 @@ float brush_sample_falloff(Brush *brush, float dist)
return brush->alpha;
}
else if ((dist < outer) && (inner < outer)) {
- /* formula used by sculpt:
- 0.5f * (cos(3*(dist - inner)/(outer - inner)) + 1); */
a = sqrt((dist - inner)/(outer - inner));
return (1 - a)*brush->alpha;
+
+ /* formula used by sculpt, with taylor approx
+ a = 0.5f*(taylor_approx_cos(3.0f*(dist - inner)/(outer - inner)) + 1.0f);
+ return a*brush->alpha; */
}
else
return 0.0f;
@@ -470,6 +479,8 @@ struct BrushPainter {
double accumtime; /* accumulated time since last paint op (airbrush) */
double lasttime; /* time of last update */
+ float lastpressure;
+
short firsttouch; /* first paint op */
float startsize;
@@ -720,24 +731,37 @@ void brush_painter_break_stroke(BrushPainter *painter)
painter->firsttouch= 1;
}
-int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, void *user)
+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->flag & BRUSH_RAD_PRESSURE)
+ brush->innerradius = MAX2(0.0, painter->startinnerradius*pressure);
+ if (brush->flag & BRUSH_SPACING_PRESSURE)
+ brush->spacing = MAX2(1.0, painter->startspacing*(1.5f-pressure));
+}
+
+int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user)
{
Brush *brush= painter->brush;
int totpaintops= 0;
+ if (pressure == 0.0f)
+ pressure = 1.0f; /* zero pressure == not using tablet */
+
if (painter->firsttouch) {
/* paint exactly once on first touch */
painter->startpaintpos[0]= pos[0];
painter->startpaintpos[1]= pos[1];
+ brush_apply_pressure(painter, brush, pressure);
if (painter->cache.enabled)
brush_painter_refresh_cache(painter, pos);
totpaintops += func(user, painter->cache.ibuf, pos, pos);
- painter->lastpaintpos[0]= pos[0];
- painter->lastpaintpos[1]= pos[1];
painter->lasttime= time;
-
painter->firsttouch= 0;
}
#if 0
@@ -760,8 +784,10 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step;
paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step;
- if (painter->cache.enabled) brush_painter_refresh_cache(painter);
- totpaintops += func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos);
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter);
+ totpaintops += func(user, painter->cache.ibuf,
+ painter->lastpaintpos, paintpos);
painter->lastpaintpos[0]= paintpos[0];
painter->lastpaintpos[1]= paintpos[1];
@@ -774,15 +800,18 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
#endif
else {
float startdistance, spacing, step, paintpos[2], dmousepos[2];
- float brushsize = MAX2(1.0, brush->size);
+ float t, len, press;
- /* compute brush spacing adapted to brush size */
- spacing= brushsize*brush->spacing*0.01f;
+ /* compute brush spacing adapted to brush size, spacing may depend
+ on pressure, so update it */
+ brush_apply_pressure(painter, brush, painter->lastpressure);
+ spacing= MAX2(1.0, brush->size)*brush->spacing*0.01f;
/* setup starting distance, direction vector and accumulated distance */
startdistance= painter->accumdistance;
Vec2Subf(dmousepos, pos, painter->lastmousepos);
- painter->accumdistance += Normalise2(dmousepos);
+ len= Normalise2(dmousepos);
+ painter->accumdistance += len;
/* do paint op over unpainted distance */
while (painter->accumdistance >= spacing) {
@@ -790,8 +819,14 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step;
paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step;
+ t = step/len;
+ press= (1.0-t)*painter->lastpressure + t*pressure;
+ brush_apply_pressure(painter, brush, press);
+ spacing= MAX2(1.0, brush->size)*brush->spacing*0.01f;
+
if (painter->cache.enabled)
brush_painter_refresh_cache(painter, paintpos);
+
totpaintops +=
func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos);
@@ -815,6 +850,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
painter->accumtime -= painttime;
while (painter->accumtime >= brush->rate) {
+ brush_apply_pressure(painter, brush, pressure);
if (painter->cache.enabled)
brush_painter_refresh_cache(painter, paintpos);
totpaintops +=
@@ -828,6 +864,12 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
painter->lastmousepos[0]= pos[0];
painter->lastmousepos[1]= pos[1];
+ painter->lastpressure= pressure;
+
+ brush->alpha = painter->startalpha;
+ brush->size = painter->startsize;
+ brush->innerradius = painter->startinnerradius;
+ brush->spacing = painter->startspacing;
return totpaintops;
}
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 41df45a3d9f..40347c9834f 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -64,9 +64,13 @@ typedef struct Brush {
} Brush;
/* Brush.flag */
-#define BRUSH_AIRBRUSH 1
-#define BRUSH_TORUS 2
-#define BRUSH_FIXED_TEX 4
+#define BRUSH_AIRBRUSH 1
+#define BRUSH_TORUS 2
+#define BRUSH_ALPHA_PRESSURE 4
+#define BRUSH_SIZE_PRESSURE 8
+#define BRUSH_RAD_PRESSURE 16
+#define BRUSH_SPACING_PRESSURE 32
+#define BRUSH_FIXED_TEX 64
/* Brush.blend */
#define BRUSH_BLEND_MIX 0
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index d33a0528fa8..3e03b3deaba 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -4274,10 +4274,14 @@ static void editing_panel_mesh_paint(void)
uiBlockBeginAlign(block);
uiDefButF(block, COL, B_VPCOLSLI, "", 0,yco,200,19, brush->rgb, 0, 0, 0, 0, "");
- uiDefButF(block, NUMSLI, B_NOP, "Opacity ", 0,yco-20,200,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
- uiDefButI(block, NUMSLI, B_NOP, "Size ", 0,yco-40,200,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
- uiDefButF(block, NUMSLI, B_NOP, "Falloff ", 0,yco-60,200,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
- uiDefButF(block, NUMSLI, B_NOP, "Spacing ",0,yco-80,200,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter");
+ uiDefButF(block, NUMSLI, B_NOP, "Opacity ", 0,yco-20,180,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_ALPHA_PRESSURE, B_NOP, "P", 180,yco-20,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButI(block, NUMSLI, B_NOP, "Size ", 0,yco-40,180,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SIZE_PRESSURE, B_NOP, "P", 180,yco-40,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_NOP, "Falloff ", 0,yco-60,180,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_RAD_PRESSURE, B_NOP, "P", 180,yco-60,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_NOP, "Spacing ",0,yco-80,180,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SPACING_PRESSURE, B_NOP, "P", 180,yco-80,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
uiBlockEndAlign(block);
yco -= 110;
diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c
index be60509852f..3958f0d0c3a 100644
--- a/source/blender/src/drawimage.c
+++ b/source/blender/src/drawimage.c
@@ -1075,10 +1075,14 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES
uiBlockBeginAlign(block);
uiDefButF(block, COL, B_VPCOLSLI, "", 0,yco,200,19, brush->rgb, 0, 0, 0, 0, "");
- uiDefButF(block, NUMSLI, B_SIMANOTHING, "Opacity ", 0,yco-20,200,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
- uiDefButI(block, NUMSLI, B_SIMANOTHING, "Size ", 0,yco-40,200,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
- uiDefButF(block, NUMSLI, B_SIMANOTHING, "Falloff ", 0,yco-60,200,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
- uiDefButF(block, NUMSLI, B_SIMANOTHING, "Spacing ",0,yco-80,200,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter");
+ uiDefButF(block, NUMSLI, B_SIMANOTHING, "Opacity ", 0,yco-20,180,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_ALPHA_PRESSURE, B_SIMANOTHING, "P", 180,yco-20,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButI(block, NUMSLI, B_SIMANOTHING, "Size ", 0,yco-40,180,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SIZE_PRESSURE, B_SIMANOTHING, "P", 180,yco-40,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_SIMANOTHING, "Falloff ", 0,yco-60,180,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_RAD_PRESSURE, B_SIMANOTHING, "P", 180,yco-60,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_SIMANOTHING, "Spacing ",0,yco-80,180,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SPACING_PRESSURE, B_SIMANOTHING, "P", 180,yco-80,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
uiBlockEndAlign(block);
yco -= 110;
diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c
index dc7db64836a..64a61f0acf0 100644
--- a/source/blender/src/imagepaint.c
+++ b/source/blender/src/imagepaint.c
@@ -2,8 +2,7 @@
* $Id$
* imagepaint.c
*
- * Functions to edit the "2D UV/Image "
- * and handle user events sent to it.
+ * Functions to paint images in 2D and 3D.
*
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
*
@@ -82,6 +81,8 @@
#include "BDR_imagepaint.h"
#include "BDR_vpaint.h"
+#include "GHOST_Types.h"
+
#include "blendef.h"
#include "mydevice.h"
@@ -517,7 +518,7 @@ static void imapaint_canvas_free(ImagePaintState *s)
imb_freerectfloatImBuf(s->clonecanvas);
}
-static int imapaint_do_paint(ImagePaintState *s, BrushPainter *painter, Image *image, short texpaint, float *uv, double time, int update)
+static int imapaint_do_paint(ImagePaintState *s, BrushPainter *painter, Image *image, short texpaint, float *uv, double time, int update, float pressure)
{
float pos[2];
@@ -526,7 +527,7 @@ static int imapaint_do_paint(ImagePaintState *s, BrushPainter *painter, Image *i
brush_painter_require_imbuf(painter, ((image->ibuf->rect_float)? 1: 0), 0, 0);
- if (brush_painter_paint(painter, imapaint_paint_op, pos, time, s)) {
+ if (brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s)) {
if (update)
imapaint_image_update(image, texpaint);
return 1;
@@ -534,7 +535,7 @@ static int imapaint_do_paint(ImagePaintState *s, BrushPainter *painter, Image *i
else return 0;
}
-static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpaint, short *prevmval, short *mval, double time)
+static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpaint, short *prevmval, short *mval, double time, float pressure)
{
Image *newimage = NULL;
float fwuv[2], bkuv[2], newuv[2];
@@ -564,7 +565,8 @@ static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpain
if (breakstroke) {
texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
- redraw |= imapaint_do_paint(s, painter, s->image, texpaint, fwuv, time, 1);
+ redraw |= imapaint_do_paint(s, painter, s->image, texpaint, fwuv,
+ time, 1, pressure);
imapaint_clear_partial_redraw();
brush_painter_break_stroke(painter);
}
@@ -577,8 +579,10 @@ static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpain
/* paint in new image */
if (newimage) {
if (breakstroke)
- redraw|= imapaint_do_paint(s, painter, newimage, texpaint, bkuv, time, 0);
- redraw|= imapaint_do_paint(s, painter, newimage, texpaint, newuv, time, 1);
+ redraw|= imapaint_do_paint(s, painter, newimage, texpaint,
+ bkuv, time, 0, pressure);
+ redraw|= imapaint_do_paint(s, painter, newimage, texpaint, newuv,
+ time, 1, pressure);
}
/* update state */
@@ -589,7 +593,8 @@ static void imapaint_do(ImagePaintState *s, BrushPainter *painter, short texpain
}
else {
imapaint_compute_uvco(mval, newuv);
- redraw |= imapaint_do_paint(s, painter, s->image, texpaint, newuv, time, 1);
+ redraw |= imapaint_do_paint(s, painter, s->image, texpaint, newuv,
+ time, 1, pressure);
}
if (redraw) {
@@ -605,6 +610,8 @@ void imagepaint_paint(short mousebutton, short texpaint)
ToolSettings *settings= G.scene->toolsettings;
short prevmval[2], mval[2];
double time;
+ float pressure;
+ const GHOST_TabletData *td;
/* initialize state */
memset(&s, 0, sizeof(s));
@@ -641,30 +648,36 @@ void imagepaint_paint(short mousebutton, short texpaint)
painter= brush_painter_new(s.brush);
getmouseco_areawin(mval);
+ td= get_tablet_data();
+ pressure= (td)? td->Pressure: 1.0f;
time= PIL_check_seconds_timer();
prevmval[0]= mval[0];
prevmval[1]= mval[1];
- imapaint_do(&s, painter, texpaint, prevmval, mval, time);
-
- //get_tablet_data();
+ imapaint_do(&s, painter, texpaint, prevmval, mval, time, pressure);
/* paint loop */
- while(get_mbut() & mousebutton) {
+ do {
getmouseco_areawin(mval);
+ if(td) {
+ td= get_tablet_data();
+ pressure= (td)? td->Pressure: 1.0f;
+ }
time= PIL_check_seconds_timer();
if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
- imapaint_do(&s, painter, texpaint, prevmval, mval, time);
+ imapaint_do(&s, painter, texpaint, prevmval, mval, time, pressure);
prevmval[0]= mval[0];
prevmval[1]= mval[1];
- //s.brush->size = MAX2(1, MIN2(200, s.brush->size*0.9));
}
else if (s.brush->flag & BRUSH_AIRBRUSH)
- imapaint_do(&s, painter, texpaint, prevmval, mval, time);
+ imapaint_do(&s, painter, texpaint, prevmval, mval, time, pressure);
else
BIF_wait_for_statechange();
- }
+
+ /* do mouse checking at the end, so don't check twice, and potentially
+ miss a short tap */
+ } while(get_mbut() & mousebutton);
/* clean up */
settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
@@ -679,8 +692,6 @@ void imagepaint_paint(short mousebutton, short texpaint)
persp(PERSP_WIN);
}
-
- /* todo: BIF_undo_push("Image paint"); */
}
void imagepaint_pick(short mousebutton)
diff --git a/source/blender/src/vpaint.c b/source/blender/src/vpaint.c
index 380763834ac..cf4c5e9b9fc 100644
--- a/source/blender/src/vpaint.c
+++ b/source/blender/src/vpaint.c
@@ -547,6 +547,9 @@ void sample_vpaint() /* frontbuf */
brush->rgb[0]= cp[0]/255.0f;
brush->rgb[1]= cp[1]/255.0f;
brush->rgb[2]= cp[2]/255.0f;
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
}
}