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
path: root/source
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2006-07-28 04:56:35 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2006-07-28 04:56:35 +0400
commitf893d950a1524d1069963dde251d48143063ad51 (patch)
tree30b8a54e5fd3bcdb059346a77337d68fdfca7180 /source
parent3d0f27c19d943f5bb9e3052b0c6a03313a16bbb0 (diff)
Image Paint:
- Code for brush spacing and timing was rewritten, making spacing more even. Example: http://users.pandora.be/blendix/brush_spacing.jpg - Instead of Stepsize for regular brushes and Flow for airbrushes, there is now Spacing for both, and Rate for airbrushes. - Airbrush now works more like it does in the Gimp now, by maintaining the spacing even if the brush moves faster than the painting rate. - Some preparations to make brushes work in texture paint mode.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/intern/brush.c3
-rw-r--r--source/blender/include/BDR_imagepaint.h4
-rw-r--r--source/blender/include/blendef.h8
-rw-r--r--source/blender/include/butspace.h5
-rw-r--r--source/blender/makesdna/DNA_brush_types.h20
-rw-r--r--source/blender/makesdna/DNA_scene_types.h8
-rw-r--r--source/blender/src/buttons_editing.c91
-rw-r--r--source/blender/src/drawimage.c31
-rw-r--r--source/blender/src/editface.c318
-rw-r--r--source/blender/src/imagepaint.c528
-rw-r--r--source/blender/src/space.c4
-rw-r--r--source/blender/src/vpaint.c21
12 files changed, 510 insertions, 531 deletions
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index ca9d1154024..383cf5b3fe8 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -54,7 +54,8 @@ Brush *add_brush(char *name)
brush->rgb[2]= 1.0f;
brush->alpha= 0.2f;
brush->size= 25;
- brush->timing= 100.0f;
+ brush->spacing= 10.0f;
+ brush->rate= 0.1f;
brush->innerradius= 0.5f;
brush->clone.alpha= 0.5;
diff --git a/source/blender/include/BDR_imagepaint.h b/source/blender/include/BDR_imagepaint.h
index 8824c63071d..9ea9c9a107a 100644
--- a/source/blender/include/BDR_imagepaint.h
+++ b/source/blender/include/BDR_imagepaint.h
@@ -34,10 +34,10 @@
#define BDR_IMAGEPAINT_H
void imagepaint_redraw_tool(void);
-void imagepaint_paint(short mousebutton);
void imagepaint_pick(short mousebutton);
-void texturepaint_paint();
+void imagepaint_paint(short mousebutton);
+void texturepaint_paint(short mousebutton);
#endif /* BDR_IMAGEPAINT_H */
diff --git a/source/blender/include/blendef.h b/source/blender/include/blendef.h
index 49873674917..fde70e4a871 100644
--- a/source/blender/include/blendef.h
+++ b/source/blender/include/blendef.h
@@ -310,16 +310,16 @@
#define B_SIMAGESAVE 364
#define B_SIMACLONEBROWSE 365
#define B_SIMACLONEDELETE 366
-#define B_SIMABRUSHCHANGE 367
#define B_SIMANOTHING 368
#define B_SIMACURVES 369
#define B_SIMARANGE 370
#define B_SIMA_USE_ALPHA 371
#define B_SIMA_SHOW_ALPHA 372
#define B_SIMA_SHOW_ZBUF 373
-#define B_BRUSHBROWSE 374
-#define B_BRUSHDELETE 375
-#define B_BRUSHLOCAL 376
+#define B_SIMABRUSHBROWSE 374
+#define B_SIMABRUSHDELETE 375
+#define B_SIMABRUSHLOCAL 376
+#define B_SIMABRUSHCHANGE 377
/* BUTS: 400 */
#define B_BUTSHOME 401
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
index a739ee9327f..adcf13b0f55 100644
--- a/source/blender/include/butspace.h
+++ b/source/blender/include/butspace.h
@@ -537,6 +537,11 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
#define B_CLR_WPAINT 2850
+#define B_BRUSHBROWSE 2851
+#define B_BRUSHDELETE 2852
+#define B_BRUSHLOCAL 2853
+#define B_BRUSHCHANGE 2854
+
/* *********************** */
#define B_RADIOBUTS 3000
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index ff578494339..8372e004fcb 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -35,23 +35,25 @@
typedef struct Brush {
ID id;
- short flag, blend;
- int size;
- float innerradius;
- float timing;
+ short flag, blend; /* general purpose flag, blend mode */
+ int size; /* brush diameter */
+ float innerradius; /* inner radius after which the falloff starts */
+ float spacing; /* spacing of paint operations */
+ float rate; /* paint operations / second (airbrush) */
- float rgb[3]; /* color */
- float alpha; /* opacity */
+ float rgb[3]; /* color */
+ float alpha; /* opacity */
struct Clone {
- struct Image *image; /* image for clone tool */
- float offset[2]; /* offset of clone image from canvas */
- float alpha; /* transparency for drawing of clone image */
+ struct Image *image; /* image for clone tool */
+ float offset[2]; /* offset of clone image from canvas */
+ float alpha; /* transparency for drawing of clone image */
} clone;
} Brush;
/* Brush.flag */
#define BRUSH_AIRBRUSH 1
+#define BRUSH_TORUS 2
/* Brush.blend */
#define BRUSH_BLEND_MIX 0
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index fe2b0cfa015..c71df7a655e 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -544,11 +544,9 @@ typedef struct Scene {
#define FFMPEG_AUTOSPLIT_OUTPUT 2
/* toolsettings->imagepaint_flag */
-#define IMAGEPAINT_TORUS 1
-#define IMAGEPAINT_DRAWING 2
-#define IMAGEPAINT_TIMED 4
-#define IMAGEPAINT_DRAW_TOOL 8
-#define IMAGEPAINT_DRAW_TOOL_DRAWING 16
+#define IMAGEPAINT_DRAWING 1
+#define IMAGEPAINT_DRAW_TOOL 2
+#define IMAGEPAINT_DRAW_TOOL_DRAWING 4
#ifdef __cplusplus
}
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
index 88ed339bd7f..31fdf5b7b06 100644
--- a/source/blender/src/buttons_editing.c
+++ b/source/blender/src/buttons_editing.c
@@ -48,6 +48,7 @@
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_camera_types.h"
#include "DNA_color_types.h"
#include "DNA_constraint_types.h"
@@ -75,6 +76,7 @@
#include "DNA_packedFile_types.h"
#include "BKE_blender.h"
+#include "BKE_brush.h"
#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
@@ -3717,6 +3719,7 @@ void do_fpaintbuts(unsigned short event)
TFace *activetf, *tf;
int a;
extern VPaint Gwp; /* from vpaint */
+ ToolSettings *settings= G.scene->toolsettings;
ob= OBACT;
if(ob==NULL) return;
@@ -3852,6 +3855,40 @@ void do_fpaintbuts(unsigned short event)
allqueue(REDRAWVIEW3D, 0);
DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
}
+ case B_BRUSHBROWSE:
+ if(G.buts->menunr==-2) {
+ activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_BRUSHBROWSE, &G.buts->menunr, do_global_buttons);
+ break;
+ }
+ else if(G.buts->menunr < 0) break;
+
+ if(brush_set_nr(&settings->imapaint.brush, G.buts->menunr)) {
+ BIF_undo_push("Browse Brush");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_BRUSHDELETE:
+ if(brush_delete(&settings->imapaint.brush)) {
+ BIF_undo_push("Unlink Brush");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_KEEPDATA:
+ brush_toggle_fake_user(settings->imapaint.brush);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case B_BRUSHLOCAL:
+ if(settings->imapaint.brush && settings->imapaint.brush->id.lib) {
+ if(okee("Make local")) {
+ make_local_brush(settings->imapaint.brush);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ break;
}
}
@@ -3918,7 +3955,7 @@ static void editing_panel_mesh_paint(void)
uiBlockEndAlign(block);
}
}
- else{
+ else { // if(G.f & G_VERTEXPAINT) {
extern VPaint Gvp; /* from vpaint */
uiBlockBeginAlign(block);
@@ -3956,10 +3993,56 @@ static void editing_panel_mesh_paint(void)
uiDefButF(block, NUM, B_DIFF, "Mul:", 1061,0,112,19, &Gvp.mul, 0.1, 50.0, 10, 0, "Set the number to multiply vertex colors with");
uiDefButF(block, NUM, B_DIFF, "Gamma:", 1174,0,102,19, &Gvp.gamma, 0.1, 5.0, 10, 0, "Change the clarity of the vertex colors");
uiBlockEndAlign(block);
-
-
}
-
+#if 0
+ else { /* texture paint */
+ ToolSettings *settings= G.scene->toolsettings;
+ Brush *brush= settings->imapaint.brush;
+ ID *id;
+ int yco, xco, butw;
+
+ yco= 160;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Draw", 0 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Soften", 80 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Smear", 160,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");
+ uiBlockEndAlign(block);
+ yco -= 30;
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (ID*)settings->imapaint.brush;
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_BRUSHBROWSE, ID_BR, 0, id, NULL, &(G.buts->menunr), 0, B_BRUSHLOCAL, B_BRUSHDELETE, 0, B_KEEPDATA);
+ uiBlockSetCol(block, TH_AUTO);
+
+ if(brush && !brush->id.lib) {
+ butw= 320-(xco+10);
+
+ uiDefButS(block, MENU, B_SIMANOTHING, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5", xco+10,yco,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
+
+ uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, B_SIMABRUSHCHANGE, "Wrap", xco+10,yco-25,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_SIMABRUSHCHANGE, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
+ uiDefButF(block, NUM, B_SIMANOTHING, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
+ uiBlockEndAlign(block);
+
+ yco -= 25;
+
+ 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");
+
+ if(brush->flag & BRUSH_AIRBRUSH)
+ uiDefButF(block, NUMSLI, B_NOP, "Flow ", 0,yco-80,200,19, &brush->spacing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush");
+ else
+ uiDefButF(block, NUMSLI, B_NOP, "Stepsize ",0,yco-80,200,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating Paint On %% of Brush diameter");
+ uiBlockEndAlign(block);
+ }
+ }
+#endif
}
static void editing_panel_mesh_texface(void)
diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c
index 94d7ddd0b23..f43943ec540 100644
--- a/source/blender/src/drawimage.c
+++ b/source/blender/src/drawimage.c
@@ -896,6 +896,7 @@ void do_imagebuts(unsigned short event)
case B_SIMABRUSHCHANGE:
allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
break;
case B_SIMACURVES:
@@ -909,33 +910,37 @@ void do_imagebuts(unsigned short event)
allqueue(REDRAWIMAGE, 0);
break;
- case B_BRUSHBROWSE:
+ case B_SIMABRUSHBROWSE:
if(G.sima->menunr==-2) {
- activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_BRUSHBROWSE, &G.sima->menunr, do_global_buttons);
+ activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_SIMABRUSHBROWSE, &G.sima->menunr, do_global_buttons);
break;
}
else if(G.sima->menunr < 0) break;
if(brush_set_nr(&settings->imapaint.brush, G.sima->menunr)) {
BIF_undo_push("Browse Brush");
+ allqueue(REDRAWBUTSEDIT, 0);
allqueue(REDRAWIMAGE, 0);
}
break;
- case B_BRUSHDELETE:
+ case B_SIMABRUSHDELETE:
if(brush_delete(&settings->imapaint.brush)) {
BIF_undo_push("Unlink Brush");
allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
}
break;
case B_KEEPDATA:
brush_toggle_fake_user(settings->imapaint.brush);
allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
break;
- case B_BRUSHLOCAL:
+ case B_SIMABRUSHLOCAL:
if(settings->imapaint.brush && settings->imapaint.brush->id.lib) {
if(okee("Make local")) {
make_local_brush(settings->imapaint.brush);
allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
}
}
break;
@@ -1020,19 +1025,21 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES
uiBlockSetCol(block, TH_BUT_SETTING2);
id= (ID*)settings->imapaint.brush;
- xco= std_libbuttons(block, 0, yco, 0, NULL, B_BRUSHBROWSE, ID_BR, 0, id, NULL, &(G.sima->menunr), 0, B_BRUSHLOCAL, B_BRUSHDELETE, 0, B_KEEPDATA);
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMABRUSHBROWSE, ID_BR, 0, id, NULL, &(G.sima->menunr), 0, B_SIMABRUSHLOCAL, B_SIMABRUSHDELETE, 0, B_KEEPDATA);
uiBlockSetCol(block, TH_AUTO);
if(brush && !brush->id.lib) {
butw= 320-(xco+10);
+ uiDefButS(block, MENU, B_SIMANOTHING, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5", xco+10,yco,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
+
+ uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, B_SIMABRUSHCHANGE, "Wrap", xco+10,yco-25,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
+
uiBlockBeginAlign(block);
- uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_SIMABRUSHCHANGE, "Airbrush", xco+10,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
- uiDefButBitS(block, TOG|BIT, IMAGEPAINT_TORUS, B_SIMABRUSHCHANGE, "Wrap", xco+10,yco-20,butw,19, &settings->imapaint.flag, 0, 0, 0, 0, "Enables torus wrapping");
+ uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_SIMABRUSHCHANGE, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
+ uiDefButF(block, NUM, B_SIMANOTHING, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
uiBlockEndAlign(block);
- uiDefButS(block, MENU, B_SIMANOTHING, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5", xco+10,yco-45,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
-
yco -= 25;
uiBlockBeginAlign(block);
@@ -1040,11 +1047,7 @@ static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PROPERTIES
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");
-
- if(brush->flag & BRUSH_AIRBRUSH)
- uiDefButF(block, NUMSLI, B_SIMANOTHING, "Flow ", 0,yco-80,200,19, &brush->timing, 1.0, 100.0, 0, 0, "Paint Flow for Air Brush");
- else
- uiDefButF(block, NUMSLI, B_SIMANOTHING, "Stepsize ",0,yco-80,200,19, &brush->timing, 1.0, 100.0, 0, 0, "Repeating Paint On %% of Brush diameter");
+ 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");
uiBlockEndAlign(block);
yco -= 110;
diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c
index 9c6e244e549..e32971b4070 100644
--- a/source/blender/src/editface.c
+++ b/source/blender/src/editface.c
@@ -55,13 +55,14 @@
#include "DNA_scene_types.h"
#include "DNA_view3d_types.h"
-#include "BKE_utildefines.h"
+#include "BKE_brush.h"
#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
-#include "BKE_texture.h"
#include "BKE_object.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
#include "BSE_view.h"
#include "BSE_edit.h"
@@ -1465,6 +1466,8 @@ void set_faceselect() /* toggle */
allqueue(REDRAWIMAGE, 0);
}
+/* Texture Paint */
+
void set_texturepaint() /* toggle */
{
Object *ob = OBACT;
@@ -1488,264 +1491,109 @@ void set_texturepaint() /* toggle */
if(G.f & G_TEXTUREPAINT)
G.f &= ~G_TEXTUREPAINT;
- else if (me)
+ else if (me) {
G.f |= G_TEXTUREPAINT;
+ brush_check_exists(&G.scene->toolsettings->imapaint.brush);
+ }
allqueue(REDRAWVIEW3D, 0);
}
-/**
- * Get the view ray through the screen point.
- * Uses the OpenGL settings of the active view port.
- * The coordinates should be given in viewport coordinates.
- * @author Maarten Gribnau
- * @param x the x-coordinate of the screen point.
- * @param y the y-coordinate of the screen point.
- * @param org origin of the view ray.
- * @param dir direction of the view ray.
- */
-static void get_pick_ray(short *xy, float org[3], float dir[3])
+/* Get the barycentric coordinates of 2d point p in 2d triangle (v1, v2, v3) */
+static void texpaint_barycentric_2d(float *v1, float *v2, float *v3, float *p, float *w)
{
- double mvmatrix[16];
- double projmatrix[16];
- GLint viewport[4];
- double px, py, pz;
- float l;
-
- /* Get the matrices needed for gluUnProject */
- glGetIntegerv(GL_VIEWPORT, viewport);
- glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
- glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
-
- /* Set up viewport so that gluUnProject will give correct values */
- viewport[0] = 0;
- viewport[1] = 0;
- /* printf("viewport = (%4d, %4d, %4d, %4d)\n", viewport[0], viewport[1], viewport[2], viewport[3]); */
- /* printf("cursor = (%4d, %4d)\n", x, y); */
-
- gluUnProject((GLdouble) xy[0], (GLdouble) xy[1], 0.0, mvmatrix, projmatrix, viewport, &px, &py, &pz);
- org[0] = (float)px; org[1] = (float)py; org[2] = (float)pz;
- /* printf("world point at z=0.0 is (%f, %f, %f)\n", org[0], org[1], org[2]); */
- gluUnProject((GLdouble) xy[0], (GLdouble) xy[1], 1.0, mvmatrix, projmatrix, viewport, &px, &py, &pz);
- /* printf("world point at z=1.0 is (%f, %f, %f)\n", px, py, pz); */
- dir[0] = ((float)px) - org[0];
- dir[1] = ((float)py) - org[1];
- dir[2] = ((float)pz) - org[2];
- l = (float)sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]);
- if (!l) return;
- l = 1. / l;
- dir[0] *= l; dir[1] *= l; dir[2] *= l;
- /* printf("ray org. is (%f, %f, %f)\n", org[0], org[1], org[2]); */
- /* printf("ray dir. is (%f, %f, %f)\n", dir[0], dir[1], dir[2]); */
-}
+ float b[2], c[2], h[2], div;
+ Vec2Subf(b, v1, v3);
+ Vec2Subf(c, v2, v3);
+ Vec2Subf(h, p, v3);
-static int triangle_ray_intersect(float tv0[3], float tv1[3], float tv2[3], float org[3], float dir[3], float uv[2])
-{
- float v1v0[3];
- float v2v0[3];
- float n[3], an[3];
- float t, d, l;
- float p[3];
- double u0, v0, u1, v1, u2, v2, uvtemp;
- unsigned int iu, iv;
-
- /* Calculate normal of the plane (cross, normalize)
- * Could really use moto here...
- */
- v1v0[0] = tv1[0] - tv0[0];
- v1v0[1] = tv1[1] - tv0[1];
- v1v0[2] = tv1[2] - tv0[2];
- v2v0[0] = tv2[0] - tv0[0];
- v2v0[1] = tv2[1] - tv0[1];
- v2v0[2] = tv2[2] - tv0[2];
- n[0] = (v1v0[1] * v2v0[2]) - (v1v0[2] * v2v0[1]);
- n[1] = (v1v0[2] * v2v0[0]) - (v1v0[0] * v2v0[2]);
- n[2] = (v1v0[0] * v2v0[1]) - (v1v0[1] * v2v0[0]);
- l = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);
- if (!l) return 0;
- l = 1. / l;
- n[0] *= l; n[1] *= l; n[2] *= l;
-
- /* Calculate intersection point */
- t = n[0]*dir[0] + n[1]*dir[1] + n[2]*dir[2];
- if (fabs(t) < 1.0e-6) return 0;
- d = -(n[0]*tv0[0] + n[1]*tv0[1] + n[2]*tv0[2]);
- t = -(((n[0]*org[0] + n[1]*org[1] + n[2]*org[2]) + d) / t);
- if (t < 0) return 0;
- p[0] = org[0] + dir[0]*t;
- p[1] = org[1] + dir[1]*t;
- p[2] = org[2] + dir[2]*t;
- /*printf("intersection at (%f, %f, %f)\n", p[0], p[1], p[2]);*/
-
- /* Calculate the largest component of the normal */
- an[0] = fabs(n[0]); an[1] = fabs(n[1]); an[2] = fabs(n[2]);
- if ((an[0] > an[1]) && (an[0] > an[2])) {
- iu = 1; iv = 2;
- }
- else if ((an[1] > an[0]) && (an[1] > an[2])) {
- iu = 2; iv = 0;
- }
- else {
- iu = 0; iv = 1;
- }
- /* printf("iu, iv = (%d, %d)\n", iu, iv); */
-
- /* Calculate (u,v) */
- u0 = p[iu] - tv0[iu];
- v0 = p[iv] - tv0[iv];
- u1 = tv1[iu] - tv0[iu];
- v1 = tv1[iv] - tv0[iv];
- u2 = tv2[iu] - tv0[iu];
- v2 = tv2[iv] - tv0[iv];
- /* printf("u0, v0, u1, v1, u2, v2 = (%f, %f, %f, %f, %f, %f)\n", u0, v0, u1, v1, u2, v2); */
-
- /* These calculations should be in double precision.
- * On windows we get inpredictable results in single precision
- */
- if (u1 == 0) {
- uvtemp = u0/u2;
- uv[1] = (float)uvtemp;
- /* if ((uv[1] >= 0.) && (uv[1] <= 1.)) { */
- uv[0] = (float)((v0 - uvtemp*v2) / v1);
- /* } */
+ div= b[0]*c[1] - b[1]*c[0];
+
+ if (div == 0.0) {
+ w[0]= w[1]= w[2]= 1.0f/3.0f;
}
else {
- uvtemp = (v0*u1 - u0*v1)/(v2*u1-u2*v1);
- uv[1] = (float)uvtemp;
- /* if ((uv[1] >= 0) && (uv[1] <= 1)) { */
- uv[0] = (float)((u0 - uvtemp*u2) / u1);
- /* } */
+ div = 1.0/div;
+ w[0] = (h[0]*c[1] - h[1]*c[0])*div;
+ w[1] = (b[0]*h[1] - b[1]*h[0])*div;
+ w[2] = 1.0 - w[0] - w[1];
}
- /* printf("uv[0], uv[1] = (%f, %f)\n", uv[0], uv[1]); */
- return ((uv[0] >= 0) && (uv[1] >= 0) && ((uv[0]+uv[1]) <= 1)) ? 2 : 1;
}
-/**
- * Returns the vertex (local) coordinates of a face.
- * No bounds checking!
- * @author Maarten Gribnau
- * @param mesh the mesh with the face.
- * @param face the face.
- * @param v1 vertex 1 coordinates.
- * @param v2 vertex 2 coordinates.
- * @param v3 vertex 3 coordinates.
- * @param v4 vertex 4 coordinates.
- * @return number of vertices of this face
- */
-static int face_get_vertex_coordinates(Mesh* mesh, TFace* face, float v1[3], float v2[3], float v3[3], float v4[3])
+/* Get 2d vertex coordinates of tface projected onto screen */
+static void texpaint_project(Object *ob, double *model, double *proj, GLint *view, float *co, float *pco)
{
- int num_vertices;
- MVert *mv;
- MFace *mf = (MFace *) (((MFace *)mesh->mface) + (face - (TFace *) mesh->tface));
-
- num_vertices = mf->v4 == 0 ? 3 : 4;
- mv = mesh->mvert + mf->v1;
- v1[0] = mv->co[0]; v1[1] = mv->co[1]; v1[2] = mv->co[2];
- mv = mesh->mvert + mf->v2;
- v2[0] = mv->co[0]; v2[1] = mv->co[1]; v2[2] = mv->co[2];
- mv = mesh->mvert + mf->v3;
- v3[0] = mv->co[0]; v3[1] = mv->co[1]; v3[2] = mv->co[2];
- if (num_vertices == 4) {
- mv = mesh->mvert + mf->v4;
- v4[0] = mv->co[0]; v4[1] = mv->co[1]; v4[2] = mv->co[2];
- }
+ float obco[3];
+ double winx, winy, winz;
+
+ VecCopyf(obco, co);
+ Mat4MulVecfl(ob->obmat, obco);
+ gluProject(obco[0], obco[1], obco[2], model, proj, view, &winx, &winy, &winz);
- return num_vertices;
+ pco[0]= (float)winx;
+ pco[1]= (float)winy;
}
-/**
- * Finds texture coordinates from face edge interpolation values.
- * @author Maarten Gribnau
- * @param face the face.
- * @param v1 vertex 1 index.
- * @param v2 vertex 2 index.
- * @param v3 vertex 3 index.
- * @param a interpolation value of edge v2-v1.
- * @param b interpolation value of edge v3-v1.
- * @param u (u,v) coordinate.
- * @param v (u,v) coordinate.
- */
-static void face_get_uv(TFace* face, int v1, int v2, int v3, float a, float b, float *uv)
+static int texpaint_projected_verts(Object *ob, Mesh *mesh, TFace *tf, float *v1, float *v2, float *v3, float *v4)
{
- float uv01[2], uv21[2];
-
- /* Pin a,b inside [0,1] range */
-#if 0
- a = (float)fmod(a, 1.);
- b = (float)fmod(b, 1.);
-#else
- if (a < 0.f) a = 0.f;
- else if (a > 1.f) a = 1.f;
- if (b < 0.f) b = 0.f;
- else if (b > 1.f) b = 1.f;
-#endif
-
- /* Convert to texture coordinates */
- uv01[0] = face->uv[v2][0] - face->uv[v1][0];
- uv01[1] = face->uv[v2][1] - face->uv[v1][1];
- uv21[0] = face->uv[v3][0] - face->uv[v1][0];
- uv21[1] = face->uv[v3][1] - face->uv[v1][1];
- uv01[0] *= a;
- uv01[1] *= a;
- uv21[0] *= b;
- uv21[1] *= b;
- uv[0] = face->uv[v1][0] + (uv01[0] + uv21[0]);
- uv[1] = face->uv[v1][1] + (uv01[1] + uv21[1]);
+ MFace *mf = mesh->mface + (tf - mesh->tface);
+ double model[16], proj[16];
+ GLint view[4];
+
+ persp(PERSP_VIEW);
+
+ /* get the need opengl matrices */
+ glGetIntegerv(GL_VIEWPORT, view);
+ glGetDoublev(GL_MODELVIEW_MATRIX, model);
+ glGetDoublev(GL_PROJECTION_MATRIX, proj);
+ view[0] = view[1] = 0;
+
+ /* project the verts */
+ texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v1)->co, v1);
+ texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v2)->co, v2);
+ texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v3)->co, v3);
+ if(mf->v4)
+ texpaint_project(ob, model, proj, view, (mesh->mvert+mf->v4)->co, v4);
+
+ return (mf->v4? 4: 3);
}
-/**
- * Get the (u,v) coordinates on a face from a point in screen coordinates.
- * The coordinates should be given in viewport coordinates.
- * @author Maarten Gribnau
- * @param object the object with the mesh
- * @param mesh the mesh with the face to be picked.
- * @param face the face to be picked.
- * @param x the x-coordinate to pick at.
- * @param y the y-coordinate to pick at.
- * @param u the u-coordinate calculated.
- * @param v the v-coordinate calculated.
- * @return intersection result:
- * 0 == no intersection, (u,v) invalid
- * 1 == intersection, (u,v) valid
- */
-int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short *xy, float *uv)
+/* compute uv coordinates of mouse in face */
+void texpaint_pick_uv(Object *ob, Mesh *mesh, TFace *tf, short *xy, float *uv)
{
- float org[3], dir[3];
- float ab[2];
- float v1[3], v2[3], v3[3], v4[3];
- int result;
- int num_verts;
-
- /* Get a view ray to intersect with the face */
- get_pick_ray(xy, org, dir);
-
- /* Convert local vertex coordinates to world */
- num_verts = face_get_vertex_coordinates(mesh, face, v1, v2, v3, v4);
- /* Convert local vertex coordinates to world */
- Mat4MulVecfl(object->obmat, v1);
- Mat4MulVecfl(object->obmat, v2);
- Mat4MulVecfl(object->obmat, v3);
- if (num_verts > 3) {
- Mat4MulVecfl(object->obmat, v4);
- }
+ float v1[2], v2[2], v3[2], v4[2], p[2], w[3];
+ int nvert;
+
+ /* compute barycentric coordinates of point in face and interpolate uv's.
+ it's ok to compute the barycentric coords on the projected positions,
+ because they are invariant under affine transform */
+ nvert= texpaint_projected_verts(ob, mesh, tf, v1, v2, v3, v4);
+
+ p[0]= xy[0];
+ p[1]= xy[1];
+
+ if (nvert == 4) {
+ texpaint_barycentric_2d(v1, v2, v4, p, w);
- /* Get (u,v) values (local face coordinates) of intersection point
- * If face is a quad, there are two triangles to check.
- */
- result = triangle_ray_intersect(v2, v1, v3, org, dir, ab);
- if ( (num_verts == 3) || ((num_verts == 4) && (result > 1)) ) {
- /* Face is a triangle or a quad with a hit on the first triangle */
- face_get_uv(face, 1, 0, 2, ab[0], ab[1], uv);
- /* printf("triangle 1, texture (u,v)=(%f, %f)\n", *u, *v); */
+ if(w[0] < 0.0f) {
+ /* if w[0] is negative, co is on the other side of the v1-v3 edge,
+ so we interpolate using the other triangle */
+ texpaint_barycentric_2d(v2, v3, v4, p, w);
+
+ uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
+ uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
+ }
+ else {
+ uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
+ uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
+ }
}
else {
- /* Face is a quad and no intersection with first triangle */
- result = triangle_ray_intersect(v4, v3, v1, org, dir, ab);
- face_get_uv(face, 3, 2, 0, ab[0], ab[1], uv);
- /* printf("triangle 2, texture (u,v)=(%f, %f)\n", *u, *v); */
+ texpaint_barycentric_2d(v1, v2, v3, p, w);
+ uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
+ uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
}
- return result > 0;
}
/* Selects all faces which have the same uv-texture as the active face
diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c
index 627d3aaf18f..a535cb855ab 100644
--- a/source/blender/src/imagepaint.c
+++ b/source/blender/src/imagepaint.c
@@ -48,6 +48,7 @@
#ifdef WIN32
#include "BLI_winstuff.h"
#endif
+#include "BLI_arithb.h"
#include "IMB_imbuf_types.h"
@@ -83,6 +84,37 @@
#include "blendef.h"
#include "mydevice.h"
+/* Structs */
+
+typedef struct ImagePaintPixmap {
+ unsigned int width, height, rowbytes, shared;
+ char *rect;
+} ImagePaintPixmap;
+
+typedef struct ImagePaintBrush {
+ ImagePaintPixmap *pixmap;
+ float rgb[3], alpha;
+ unsigned int inner_radius, outer_radius;
+ short torus;
+} ImagePaintBrush;
+
+typedef struct ImagePaintState {
+ float mousepos[2]; /* current mouse position in image pixel coordinates */
+ float lastmousepos[2]; /* last mouse position in image pixel coordinates */
+
+ float accumdistance; /* accumulated distance of brush since last paint op */
+ float lastpaintpos[2]; /* position of last paint op */
+
+ double accumtime; /* accumulated time since last paint op (airbrush) */
+ double lasttime; /* time of last update */
+
+ ImagePaintPixmap *canvas;
+ ImagePaintPixmap *clonecanvas;
+ ImagePaintBrush *brush;
+ ToolSettings *settings;
+ short firsttouch;
+} ImagePaintState;
+
/* ImagePaintPixmap */
#define IMAPAINT_FLOAT_TO_CHAR(f) ((char)(f*255))
@@ -106,11 +138,6 @@
#define IMAPAINT_RGB_COPY(a, b) { a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; }
#define IMAPAINT_RGBA_COPY(a, b) { *((int*)a)=*((int*)b); }
-typedef struct ImagePaintPixmap {
- unsigned int width, height, rowbytes, shared;
- char *rect;
-} ImagePaintPixmap;
-
static ImagePaintPixmap *imapaint_pixmap_new(unsigned int w, unsigned int h, char *rect)
{
ImagePaintPixmap *pm = MEM_callocN(sizeof(ImagePaintPixmap), "ImagePaintPixmap");
@@ -138,13 +165,6 @@ static void imapaint_pixmap_free(ImagePaintPixmap *pm)
/* ImagePaintBrush */
-typedef struct ImagePaintBrush {
- ImagePaintPixmap *pixmap;
- float rgb[3], alpha;
- unsigned int inner_radius, outer_radius;
- short torus, blend;
-} ImagePaintBrush;
-
static void imapaint_brush_pixmap_refresh(ImagePaintBrush *brush)
{
ImagePaintPixmap *pm = brush->pixmap;
@@ -242,8 +262,8 @@ static char *imapaint_pixmap_get_rgba_torus(ImagePaintPixmap *pm, unsigned int x
static void imapaint_pixmap_clip(ImagePaintPixmap *pm, ImagePaintPixmap *bpm, float *pos, unsigned int *off, unsigned int *boff, unsigned int *dim)
{
- int x = (int)(pos[0]*pm->width - bpm->width/2);
- int y = (int)(pos[1]*pm->height - bpm->height/2);
+ int x = (int)(pos[0] - bpm->width/2);
+ int y = (int)(pos[1] - bpm->height/2);
dim[0] = bpm->width;
dim[1] = bpm->height;
@@ -305,8 +325,8 @@ static void imapaint_pixmap_blend_torus(ImagePaintPixmap *pm, ImagePaintPixmap *
unsigned int x, y, out_off[2], mx, my;
char *out, *in;
- out_off[0] = (int)(pos[0]*pm->width - bpm->width/2);
- out_off[1] = (int)(pos[1]*pm->height - bpm->height/2);
+ out_off[0] = (int)(pos[0] - bpm->width/2);
+ out_off[1] = (int)(pos[1] - bpm->height/2);
for (y=0; y < bpm->height; y++) {
in = imapaint_pixmap_get_rgba(bpm, 0, y);
@@ -348,8 +368,8 @@ static void imapaint_blend_line(ImagePaintPixmap *pm, ImagePaintBrush *brush, fl
float numsteps, t, pos[2];
int step, d[2];
- d[0] = (int)((end[0] - start[0])*pm->width);
- d[1] = (int)((end[1] - start[1])*pm->height);
+ d[0] = (int)(end[0] - start[0]);
+ d[1] = (int)(end[1] - start[1]);
numsteps = sqrt(d[0]*d[0] + d[1]*d[1])/(brush->pixmap->width/4.0f);
if(numsteps < 1.0)
@@ -357,30 +377,29 @@ static void imapaint_blend_line(ImagePaintPixmap *pm, ImagePaintBrush *brush, fl
for (step=0; step < numsteps; step++) {
t = (step+1)/numsteps;
- pos[0] = start[0] + d[0]*t/pm->width;
- pos[1] = start[1] + d[1]*t/pm->height;
+ pos[0] = start[0] + d[0]*t;
+ pos[1] = start[1] + d[1]*t;
if (brush->torus)
- imapaint_pixmap_blend_torus(pm, brush->pixmap, pos, brush->blend);
+ imapaint_pixmap_blend_torus(pm, brush->pixmap, pos, BRUSH_BLEND_MIX);
else
- imapaint_pixmap_blend(pm, brush->pixmap, pos, brush->blend);
+ imapaint_pixmap_blend(pm, brush->pixmap, pos, BRUSH_BLEND_MIX);
}
}
-static void imapaint_soften_sharpen(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos, short sharpen)
+static void imapaint_lift_soften(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos, short torus)
{
ImagePaintPixmap *bpm = brush->pixmap;
unsigned int x, y, count, xi, yi, xo, yo;
unsigned int out_off[2], in_off[2], dim[2];
- float outrgb[3], finrgb[3];
- short torus= brush->torus;
+ float outrgb[3];
char *inrgb, *out;
if (torus) {
dim[0] = bpm->width;
dim[1] = bpm->width;
- in_off[0] = (int)(pos[0]*pm->width - bpm->width/2);
- in_off[1] = (int)(pos[1]*pm->height - bpm->width/2);
+ in_off[0] = (int)(pos[0] - bpm->width/2);
+ in_off[1] = (int)(pos[1] - bpm->width/2);
out_off[0] = out_off[1] = 0;
}
else {
@@ -402,8 +421,10 @@ static void imapaint_soften_sharpen(ImagePaintPixmap *pm, ImagePaintBrush *brush
/* sum and average surrounding pixels */
count = 1;
IMAPAINT_CHAR_RGB_TO_FLOAT(outrgb, inrgb);
+#if 0
if (sharpen)
IMAPAINT_FLOAT_RGB_COPY(finrgb, outrgb);
+#endif
count += imapaint_pixmap_add_if(pm, xi-1, yi-1, outrgb, torus);
count += imapaint_pixmap_add_if(pm, xi-1, yi , outrgb, torus);
@@ -420,6 +441,7 @@ static void imapaint_soften_sharpen(ImagePaintPixmap *pm, ImagePaintBrush *brush
outrgb[1] /= count;
outrgb[2] /= count;
+#if 0
if (sharpen) {
/* unsharp masking - creates ugly artifacts and is disabled
for now, needs some sort of clamping to reduce artifacts */
@@ -431,6 +453,7 @@ static void imapaint_soften_sharpen(ImagePaintPixmap *pm, ImagePaintBrush *brush
outrgb[1] = IMAPAINT_FLOAT_CLAMP(outrgb[1]);
outrgb[2] = IMAPAINT_FLOAT_CLAMP(outrgb[2]);
}
+#endif
/* write into brush buffer */
xo = out_off[0] + x;
@@ -439,11 +462,6 @@ static void imapaint_soften_sharpen(ImagePaintPixmap *pm, ImagePaintBrush *brush
IMAPAINT_FLOAT_RGB_TO_CHAR(out, outrgb);
}
}
-
- if (torus)
- imapaint_pixmap_blend_torus(pm, bpm, pos, brush->blend);
- else
- imapaint_pixmap_blend(pm, bpm, pos, brush->blend);
}
static void imapaint_lift_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos)
@@ -452,8 +470,8 @@ static void imapaint_lift_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, fl
int in_off[2], x, y;
char *out, *in;
- in_off[0] = (int)(pos[0]*pm->width - bpm->width/2);
- in_off[1] = (int)(pos[1]*pm->height - bpm->height/2);
+ in_off[0] = (int)(pos[0] - bpm->width/2);
+ in_off[1] = (int)(pos[1] - bpm->height/2);
for (y=0; y < bpm->height; y++) {
out = imapaint_pixmap_get_rgba(bpm, 0, y);
@@ -464,17 +482,6 @@ static void imapaint_lift_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, fl
}
}
-static void imapaint_smear(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *start, float *end)
-{
- float pos[2];
-
- pos[0]= 2*start[0] - end[0];
- pos[1]= 2*start[1] - end[1];
-
- imapaint_lift_smear(pm, brush, pos);
- imapaint_blend_line(pm, brush, start, end);
-}
-
static void imapaint_lift_clone(ImagePaintPixmap *pm, ImagePaintBrush *brush, float *pos)
{
ImagePaintPixmap *bpm = brush->pixmap;
@@ -484,8 +491,8 @@ static void imapaint_lift_clone(ImagePaintPixmap *pm, ImagePaintBrush *brush, fl
/* we overwrite alphas for pixels outside clone, so need to reload them */
imapaint_brush_pixmap_refresh(brush);
- in_off[0] = (int)(pos[0]*pm->width - bpm->width/2);
- in_off[1] = (int)(pos[1]*pm->height - bpm->height/2);
+ in_off[0] = (int)(pos[0] - bpm->width/2);
+ in_off[1] = (int)(pos[1] - bpm->height/2);
for (y=0; y < bpm->height; y++) {
out = imapaint_pixmap_get_rgba(bpm, 0, y);
@@ -504,96 +511,66 @@ static void imapaint_lift_clone(ImagePaintPixmap *pm, ImagePaintBrush *brush, fl
}
}
-static void imapaint_clone(ImagePaintPixmap *pm, ImagePaintPixmap *cpm, ImagePaintBrush *brush, float *start, float *off)
-{
- float pos[2];
-
- pos[0]= start[0] - off[0];
- pos[1]= start[1] - off[1];
-
- imapaint_lift_clone(cpm, brush, pos);
- imapaint_pixmap_blend(pm, brush->pixmap, start, brush->blend);
-}
-
/* 2D image paint */
-#if 0
-struct ImagePaint Gip = {
- {NULL, {0.0f, 0.0f}, 0.5f},
- {{{1.0f, 1.0f, 1.0f, 0.2f}, 25, 0.5f, 100.0f}, /* brush */
- {{1.0f, 1.0f, 1.0f, 0.1f}, 25, 0.1f, 100.0f}, /* airbrush */
- {{0.5f, 0.5f, 0.5f, 1.0f}, 25, 0.5f, 100.0f}, /* soften */
- {{1.0f, 1.0f, 1.0f, 0.1f}, 25, 0.1f, 100.0f}, /* aux1 */
- {{0.0f, 0.0f, 0.0f, 0.1f}, 25, 0.1f, 100.0f}, /* aux2 */
- {{1.0f, 1.0f, 1.0f, 0.5f}, 25, 0.1f, 20.0f}, /* smear */
- {{1.0f, 1.0f, 1.0f, 0.5f}, 25, 0.1f, 20.0f}}, /* clone */
- 0, IMAGEPAINT_BRUSH
-};
-#endif
-
-static ImagePaintBrush *imapaint_init_brush()
+static int imapaint_state_init(ImagePaintState *state, ToolSettings *settings)
{
- ToolSettings *settings= G.scene->toolsettings;
Brush *brush= settings->imapaint.brush;
if (!brush)
- return NULL;
+ return 0;
+
+ memset(state, 0, sizeof(*state));
+ state->firsttouch= 1;
+ state->lasttime= PIL_check_seconds_timer();
+ state->settings= settings;
/* initialize paint settings */
- if(brush->flag & BRUSH_AIRBRUSH)
- settings->imapaint.flag |= IMAGEPAINT_TIMED;
- else
- settings->imapaint.flag &= ~IMAGEPAINT_TIMED;
+ state->settings->imapaint.flag |= IMAGEPAINT_DRAWING;
/* create brush */
- return imapaint_brush_new(brush->size, brush->size, brush->rgb, brush->alpha, brush->innerradius);
+ state->brush= imapaint_brush_new(brush->size, brush->size, brush->rgb,
+ brush->alpha, brush->innerradius);
+
+ return 1;
}
-static void imapaint_free_brush(ImagePaintBrush *brush)
+static void imapaint_state_free(ImagePaintState *state)
{
- imapaint_brush_free(brush);
+ state->settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+
+ if(state->brush) imapaint_brush_free(state->brush);
+ if(state->canvas) imapaint_pixmap_free(state->canvas);
+ if(state->clonecanvas) imapaint_pixmap_free(state->clonecanvas);
}
-static ImagePaintPixmap *imapaint_init_canvas(ImagePaintPixmap **clonecanvas)
+static int imapaint_canvas_init(ImagePaintState *state)
{
+ Brush *brush= state->settings->imapaint.brush;
ImBuf *ibuf= NULL, *cloneibuf= NULL;
- ImagePaintPixmap *canvas;
- ToolSettings *settings= G.scene->toolsettings;
- Brush *brush= settings->imapaint.brush;
/* verify that we can paint and create canvas */
if(!G.sima->image || !G.sima->image->ibuf || !G.sima->image->ibuf->rect)
- return NULL;
+ return 0;
else if(G.sima->image->packedfile)
- return NULL;
+ return 0;
ibuf= G.sima->image->ibuf;
- canvas= imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect);
-
- if (clonecanvas) {
- /* create clone canvas */
- if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE)) {
- int w, h;
- if(!brush->clone.image || !brush->clone.image->ibuf)
- return 0;
-
- cloneibuf= brush->clone.image->ibuf;
- w = cloneibuf->x;
- h = cloneibuf->y;
- *clonecanvas= imapaint_pixmap_new(w, h, (char*)cloneibuf->rect);
- }
- else
- *clonecanvas= NULL;
- }
+ state->canvas= imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect);
- return canvas;
-}
+ /* create clone canvas */
+ if(brush && (state->settings->imapaint.tool == PAINT_TOOL_CLONE)) {
+ int w, h;
+ if(!brush->clone.image || !brush->clone.image->ibuf)
+ return 0;
-static void imapaint_free_canvas(ImagePaintPixmap *canvas, ImagePaintPixmap *clonecanvas)
-{
- imapaint_pixmap_free(canvas);
- if(clonecanvas)
- imapaint_pixmap_free(clonecanvas);
+ cloneibuf= brush->clone.image->ibuf;
+ w = cloneibuf->x;
+ h = cloneibuf->y;
+ state->clonecanvas= imapaint_pixmap_new(w, h, (char*)cloneibuf->rect);
+ }
+
+ return 1;
}
void imapaint_redraw_tool(void)
@@ -628,157 +605,189 @@ static void imapaint_compute_uvco(short *mval, float *uv)
areamouseco_to_ipoco(G.v2d, mval, &uv[0], &uv[1]);
}
-static void imapaint_paint_tool(ImagePaintBrush *brush, ImagePaintPixmap *canvas, ImagePaintPixmap *clonecanvas, float *prevuv, float *uv)
+static void imapaint_compute_imageco(ImagePaintPixmap *pm, short *mval, float *mousepos)
{
- ToolSettings *settings= G.scene->toolsettings;
- Brush *curbrush= settings->imapaint.brush;
-
- brush->torus= (settings->imapaint.flag & IMAGEPAINT_TORUS)? 1: 0;
- brush->blend= curbrush->blend;
-
- if(settings->imapaint.tool == PAINT_TOOL_SOFTEN)
- imapaint_soften_sharpen(canvas, brush, prevuv, 0);
- else if(settings->imapaint.tool == PAINT_TOOL_SMEAR)
- imapaint_smear(canvas, brush, prevuv, uv);
- else if(settings->imapaint.tool == PAINT_TOOL_CLONE)
- imapaint_clone(canvas, clonecanvas, brush, prevuv, curbrush->clone.offset);
- else if(curbrush->flag & BRUSH_AIRBRUSH)
- imapaint_blend_line(canvas, brush, uv, uv);
- else
- imapaint_blend_line(canvas, brush, prevuv, uv);
+ areamouseco_to_ipoco(G.v2d, mval, &mousepos[0], &mousepos[1]);
+ mousepos[0] *= pm->width;
+ mousepos[1] *= pm->height;
}
-void imagepaint_paint(short mousebutton)
+static void imapaint_paint_op(ImagePaintState *s, float *lastpos, float *pos)
{
- ImagePaintBrush *brush;
- ImagePaintPixmap *canvas, *clonecanvas=NULL;
- short prevmval[2], mval[2];
- double prevtime, curtime;
- float prevuv[2], uv[2];
- int paint= 0, moved= 0, firsttouch=1 ;
- ToolSettings *settings= G.scene->toolsettings;
- Brush *curbrush= settings->imapaint.brush;
-
- if (!(canvas = imapaint_init_canvas(&clonecanvas))) {
- if(G.sima->image && G.sima->image->packedfile)
- error("Painting in packed images not supported");
- return;
+ ImagePaintPixmap *canvas= s->canvas;
+ ImagePaintPixmap *clonecanvas= s->clonecanvas;
+ ImagePaintBrush *brush= s->brush;
+ short tool= s->settings->imapaint.tool;
+ short torus= s->settings->imapaint.brush->flag & BRUSH_TORUS;
+ short blend= s->settings->imapaint.brush->blend;
+ float *offset= s->settings->imapaint.brush->clone.offset;
+ float liftpos[2];
+
+ /* lift from canvas */
+ if(tool == PAINT_TOOL_SOFTEN) {
+ imapaint_lift_soften(canvas, brush, pos, torus);
}
- else if (!(brush = imapaint_init_brush())) {
- imapaint_free_canvas(canvas, clonecanvas);
- return;
+ else if(tool == PAINT_TOOL_SMEAR) {
+ imapaint_lift_smear(canvas, brush, lastpos);
}
-
- getmouseco_areawin(prevmval);
- prevtime = PIL_check_seconds_timer();
+ else if(tool == PAINT_TOOL_CLONE && clonecanvas) {
+ liftpos[0]= pos[0] - offset[0]*clonecanvas->width;
+ liftpos[1]= pos[1] - offset[1]*clonecanvas->height;
- settings->imapaint.flag |= IMAGEPAINT_DRAWING;
+ imapaint_lift_clone(clonecanvas, brush, liftpos);
+ }
- while(get_mbut() & mousebutton) {
- getmouseco_areawin(mval);
+ /* blend into canvas */
+ if (torus)
+ imapaint_pixmap_blend_torus(canvas, brush->pixmap, pos, blend);
+ else
+ imapaint_pixmap_blend(canvas, brush->pixmap, pos, blend);
+}
- if(firsttouch)
- moved= paint= 1;
- else
- moved= paint= (prevmval[0] != mval[0]) || (prevmval[1] != mval[1]);
+static void imapaint_state_do(ImagePaintState *s, short *painted)
+{
+ if (s->firsttouch) {
+ /* always paint exactly once on first touch */
+ if (s->settings->imapaint.tool != PAINT_TOOL_SMEAR)
+ imapaint_paint_op(s, s->mousepos, s->mousepos);
+
+ s->firsttouch= 0;
+ s->lastpaintpos[0]= s->mousepos[0];
+ s->lastpaintpos[1]= s->mousepos[1];
+ if (painted) *painted |= 1;
+ }
+ else {
+ Brush *brush= s->settings->imapaint.brush;
+ float startdistance, spacing, step, paintpos[2], dmousepos[2];
+ int totpaintops= 0;
- if(settings->imapaint.flag & IMAGEPAINT_TIMED) {
- /* see if need to draw because of timer */
- curtime = PIL_check_seconds_timer();
+ /* compute brush spacing adapted to brush size */
+ spacing= brush->size*brush->spacing*0.01f;
- if(((curtime - prevtime) > (5.0/curbrush->timing)) || firsttouch) {
- prevtime= curtime;
- paint= 1;
- }
- else paint= 0;
- }
- else if(paint && !firsttouch) {
- /* check if we moved enough to draw */
- float dmval[2], d, dlimit;
+ /* setup starting distance, direction vector and accumulated distance */
+ startdistance= s->accumdistance;
+ Vec2Subf(dmousepos, s->mousepos, s->lastmousepos);
+ s->accumdistance += Normalise2(dmousepos);
- dmval[0]= prevmval[0] - mval[0];
- dmval[1]= prevmval[1] - mval[1];
+ /* do paint op over unpainted distance */
+ while (s->accumdistance >= spacing) {
+ step= spacing - startdistance;
+ paintpos[0]= s->lastmousepos[0] + dmousepos[0]*step;
+ paintpos[1]= s->lastmousepos[1] + dmousepos[1]*step;
- d= sqrt(dmval[0]*dmval[0] + dmval[1]*dmval[1]);
- dlimit= curbrush->size*G.sima->zoom*curbrush->timing/200.0;
+ imapaint_paint_op(s, s->lastpaintpos, paintpos);
- if (d < dlimit)
- paint= 0;
- }
+ s->lastpaintpos[0]= paintpos[0];
+ s->lastpaintpos[1]= paintpos[1];
+ s->accumdistance -= spacing;
+ startdistance -= spacing;
+ totpaintops++;
- if(paint) {
- /* do the actual painting */
- imapaint_compute_uvco(prevmval, prevuv);
- imapaint_compute_uvco(mval, uv);
+ if (painted) *painted |= 1;
+ }
- imapaint_paint_tool(brush, canvas, clonecanvas, prevuv, uv);
+ /* do airbrush paint ops, based on the number of paint ops left over
+ from regular painting */
+ if (brush->flag & BRUSH_AIRBRUSH) {
+ double curtime= PIL_check_seconds_timer();
+ double painttime= brush->rate*totpaintops;
- prevmval[0]= mval[0];
- prevmval[1]= mval[1];
- }
- firsttouch = 0;
+ s->accumtime += curtime - s->lasttime;
+ if (s->accumtime <= painttime)
+ s->accumtime= 0.0;
+ else
+ s->accumtime -= painttime;
- if(paint)
- imapaint_redraw(0, paint);
- else if(moved && (settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL))
- imapaint_redraw(0, paint);
- }
+ while (s->accumtime >= brush->rate) {
+ if (s->settings->imapaint.tool != PAINT_TOOL_SMEAR)
+ imapaint_paint_op(s, s->mousepos, s->mousepos);
+ s->accumtime -= brush->rate;
- settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+ totpaintops++;
+ }
- imapaint_free_brush(brush);
- imapaint_free_canvas(canvas, clonecanvas);
- G.sima->image->ibuf->userflags |= IB_BITMAPDIRTY;
+ s->lasttime= curtime;
+ }
- imapaint_redraw(1, 0);
+ if ((totpaintops > 0) && painted) *painted |= 1;
+ }
}
-void imagepaint_pick(short mousebutton)
+void imagepaint_paint(short mousebutton)
{
- ToolSettings *settings= G.scene->toolsettings;
- Brush *brush= settings->imapaint.brush;
+ ImagePaintState state;
+ short prevmval[2], mval[2], painted, moved;
- if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE)) {
- if(brush->clone.image && brush->clone.image->ibuf) {
- short prevmval[2], mval[2];
- float prevuv[2], uv[2];
-
- getmouseco_areawin(prevmval);
+ /* setup data structures */
+ if (!(imapaint_state_init(&state, G.scene->toolsettings))) {
+ return;
+ }
+ else if (!imapaint_canvas_init(&state)) {
+ if(G.sima->image && G.sima->image->packedfile)
+ error("Painting in packed images not supported");
+ imapaint_state_free(&state);
+ return;
+ }
+
+ /* initialize coordinates and time */
+ getmouseco_areawin(mval);
+ imapaint_compute_imageco(state.canvas, mval, state.mousepos);
- while(get_mbut() & mousebutton) {
- getmouseco_areawin(mval);
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+ state.lastmousepos[0]= state.mousepos[0];
+ state.lastmousepos[1]= state.mousepos[1];
+ state.lasttime= PIL_check_seconds_timer();
- if((prevmval[0] != mval[0]) || (prevmval[1] != mval[1]) ) {
- /* mouse moved, so move the clone image */
- imapaint_compute_uvco(prevmval, prevuv);
- imapaint_compute_uvco(mval, uv);
+ /* start by painting once */
+ imapaint_state_do(&state, NULL);
+ imapaint_redraw(0, 1);
- brush->clone.offset[0] += uv[0] - prevuv[0];
- brush->clone.offset[1] += uv[1] - prevuv[1];
+ /* paint loop */
+ while(get_mbut() & mousebutton) {
+ getmouseco_areawin(mval);
+ moved= painted= 0;
- force_draw(0);
+ if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+ imapaint_compute_imageco(state.canvas, mval, state.mousepos);
+ moved= 1;
+ }
+ else if (!(state.settings->imapaint.brush->flag & BRUSH_AIRBRUSH))
+ continue;
- prevmval[0]= mval[0];
- prevmval[1]= mval[1];
- }
- }
+ imapaint_state_do(&state, &painted);
+
+ state.lastmousepos[0]= state.mousepos[0];
+ state.lastmousepos[1]= state.mousepos[1];
+
+ if(painted) {
+ imapaint_redraw(0, painted);
}
+ else if(moved && (state.settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL))
+ imapaint_redraw(0, painted);
}
- else if(brush) {
- extern VPaint Gvp;
- sample_vpaint();
- brush->rgb[0]= Gvp.r;
- brush->rgb[1]= Gvp.g;
- brush->rgb[2]= Gvp.b;
- }
+ /* clean up */
+ imapaint_state_free(&state);
+
+ G.sima->image->ibuf->userflags |= IB_BITMAPDIRTY;
+ imapaint_redraw(1, 0);
}
/* these will be moved */
int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect);
-int face_pick_uv(Object* object, Mesh* mesh, TFace* face, short *xy, float *uv);
+void texpaint_pick_uv(Object *ob, Mesh *mesh, TFace *tf, short *xy, float *mousepos);
-void texturepaint_paint()
+static void texpaint_compute_imageco(ImagePaintPixmap *pm, Object *ob, Mesh *mesh, TFace *tf, short *xy, float *imageco)
+{
+ texpaint_pick_uv(ob, mesh, tf, xy, imageco);
+ imageco[0] *= pm->width;
+ imageco[1] *= pm->height;
+}
+
+void texturepaint_paint(short mousebutton)
{
Object *ob;
Mesh *me;
@@ -788,34 +797,22 @@ void texturepaint_paint()
Image *img=NULL, *img_old = NULL;
ImagePaintBrush *brush;
ImagePaintPixmap *canvas = 0;
- unsigned int face_index, mousebutton;
+ unsigned int face_index;
char *warn_packed_file = 0;
float uv[2], uv_old[2];
extern VPaint Gvp;
ImBuf *ibuf= NULL;
ob = OBACT;
- if (!ob) {
- error("No active object"); return;
- }
- if (!(ob->lay & G.vd->lay)) {
- error("The active object is not in this layer"); return;
- }
+ if (!ob || !(ob->lay & G.vd->lay)) return;
me = get_mesh(ob);
- if (!me) {
- error("The active object does not have a mesh obData"); return;
- }
+ if (!me) return;
brush = imapaint_brush_new(Gvp.size, Gvp.size, &Gvp.r, Gvp.a, 0.5);
- if (!brush) {
- error("Can't create brush"); return;
- }
+ if (!brush) return;
persp(PERSP_VIEW);
- if (U.flag & USER_LMOUSESELECT) mousebutton = R_MOUSE;
- else mousebutton = L_MOUSE;
-
getmouseco_areawin(xy_old);
while (get_mbut() & mousebutton) {
getmouseco_areawin(xy);
@@ -840,7 +837,7 @@ void texturepaint_paint()
if (img != img_old) {
/* Faces have different textures. Finish drawing in the old face. */
if (face_old && canvas) {
- face_pick_uv(ob, me, face_old, xy, uv);
+ texpaint_compute_imageco(canvas, ob, me, face_old, xy, uv);
imapaint_blend_line(canvas, brush, uv_old, uv);
img_old->ibuf->userflags |= IB_BITMAPDIRTY;
/* Delete old canvas */
@@ -854,8 +851,8 @@ void texturepaint_paint()
/* MAART: skipx is not set most of the times. Make a guess. */
canvas = imapaint_pixmap_new(ibuf->x, ibuf->y, (char*)ibuf->rect);
if (canvas) {
- face_pick_uv(ob, me, face, xy_old, uv_old);
- face_pick_uv(ob, me, face, xy, uv);
+ texpaint_compute_imageco(canvas, ob, me, face, xy_old, uv_old);
+ texpaint_compute_imageco(canvas, ob, me, face, xy, uv);
imapaint_blend_line(canvas, brush, uv_old, uv);
ibuf->userflags |= IB_BITMAPDIRTY;
}
@@ -873,15 +870,15 @@ void texturepaint_paint()
if (canvas) {
/* Finish drawing in the old face. */
if (face_old) {
- face_pick_uv(ob, me, face_old, xy, uv);
+ texpaint_compute_imageco(canvas, ob, me, face_old, xy, uv);
imapaint_blend_line(canvas, brush, uv_old, uv);
img_old->ibuf->userflags |= IB_BITMAPDIRTY;
}
/* Start drawing in the new face. */
if (face) {
- face_pick_uv(ob, me, face, xy_old, uv_old);
- face_pick_uv(ob, me, face, xy, uv);
+ texpaint_compute_imageco(canvas, ob, me, face, xy_old, uv_old);
+ texpaint_compute_imageco(canvas, ob, me, face, xy, uv);
imapaint_blend_line(canvas, brush, uv_old, uv);
ibuf->userflags |= IB_BITMAPDIRTY;
}
@@ -892,7 +889,7 @@ void texturepaint_paint()
/* Same face, continue drawing */
if (face && canvas) {
/* Get the new (u,v) coordinates */
- face_pick_uv(ob, me, face, xy, uv);
+ texpaint_compute_imageco(canvas, ob, me, face, xy, uv);
imapaint_blend_line(canvas, brush, uv_old, uv);
ibuf->userflags |= IB_BITMAPDIRTY;
}
@@ -933,3 +930,38 @@ void texturepaint_paint()
allqueue(REDRAWHEADERS, 0);
}
+void imagepaint_pick(short mousebutton)
+{
+ ToolSettings *settings= G.scene->toolsettings;
+ Brush *brush= settings->imapaint.brush;
+
+ if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE)) {
+ if(brush->clone.image && brush->clone.image->ibuf) {
+ short prevmval[2], mval[2];
+ float lastmousepos[2], mousepos[2];
+
+ getmouseco_areawin(prevmval);
+
+ while(get_mbut() & mousebutton) {
+ getmouseco_areawin(mval);
+
+ if((prevmval[0] != mval[0]) || (prevmval[1] != mval[1]) ) {
+ /* mouse moved, so move the clone image */
+ imapaint_compute_uvco(prevmval, lastmousepos);
+ imapaint_compute_uvco(mval, mousepos);
+
+ brush->clone.offset[0] += mousepos[0] - lastmousepos[0];
+ brush->clone.offset[1] += mousepos[1] - lastmousepos[1];
+
+ force_draw(0);
+
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+ }
+ }
+ }
+ }
+ else if(brush)
+ sample_vpaint();
+}
+
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index 538f664663d..aa3536ec2ba 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -835,7 +835,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
Object *ob= OBACT; /* do not change! */
float *curs;
int doredraw= 0, pupval;
- unsigned short event= evt->event;
+ unsigned short event= evt->event, origevent= evt->event;
short val= evt->val;
char ascii= evt->ascii;
@@ -1011,7 +1011,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
vertex_paint();
}
else if (G.f & G_TEXTUREPAINT) {
- texturepaint_paint();
+ texturepaint_paint(origevent==LEFTMOUSE? L_MOUSE: R_MOUSE);
}
break;
case MIDDLEMOUSE:
diff --git a/source/blender/src/vpaint.c b/source/blender/src/vpaint.c
index d1b903d08c6..811486eb35a 100644
--- a/source/blender/src/vpaint.c
+++ b/source/blender/src/vpaint.c
@@ -50,6 +50,7 @@
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -534,14 +535,20 @@ void sample_vpaint() /* frontbuf */
cp = (char *)&col;
- Gvp.r= cp[0];
- Gvp.r /= 255.0;
-
- Gvp.g= cp[1];
- Gvp.g /= 255.0;
+ if(G.f & (G_VERTEXPAINT|G_WEIGHTPAINT)) {
+ Gvp.r= cp[0]/255.0f;
+ Gvp.g= cp[1]/255.0f;
+ Gvp.b= cp[2]/255.0f;
+ }
+ else {
+ Brush *brush= G.scene->toolsettings->imapaint.brush;
- Gvp.b= cp[2];
- Gvp.b /= 255.0;
+ if(brush) {
+ brush->rgb[0]= cp[0]/255.0f;
+ brush->rgb[1]= cp[1]/255.0f;
+ brush->rgb[2]= cp[2]/255.0f;
+ }
+ }
allqueue(REDRAWBUTSEDIT, 0);
addqueue(curarea->win, REDRAW, 1); /* needed for when panel is open... */