Projection Painting, merge from branch

Additions/Features...
 - Painting onto multiple images at once.
 - Clone with an offset similar to the gimp, also an option to clone between UV layers, (not both offset and between layers atm)
 - Stencil layer, similar to The Gimp's quickmask.
 - Face mask mode - (painting onto only selected faces).
 - Texture brushes (so image and texture-node brushes too)
 - Seam bleed so you don't see gaps when painting over UV seams (new option set in the panit panel)
 - Occlusion (only point onto the first face under the paintbrush, can also be used for masking out parts of the model to paint onto) - (new option set in the paint panel)
 - Muti-threaded, each thread operates on its own bucket.
 - Support partial updates to speedup OpenGL texture refreshing.
 - Support tile based multiple undo's
 - Support float image buffers.
 - Backface culling (new option set in the paint panel)
 - All color blending modes - Add/Multiply.. etc.
 - Airbrush rate. (used to be broken) 
 - Improve the way paint is mixed when painting, so painting with 0.2 alpha will not accumulate above 0.2 alpha on the image as you paint.
 - Option to use normals to fade out strokes on the edge of a surface to avoid ugly edges. (same as Vertex Paints "Normal" option) 

Known Problems
 - Not directly related to painting but changes in selection flags are not updated on the final derived mesh.
 - Smear tool has some distortion when in perspective mode. 
 - While in perspective view any faces with 1 vert behind the viewpoint, will be completely ignored.
 - Painting can be initially slow while buckets are being initialized, a number of solutions exist.
 - Size 1 brushes don't work yet.
 - When painting onto large faces its still possible to get artifacts.
 - Spatial optimizations are needed to skip occluded faces and test pixel occlusion. (will look into using blenders BVH )
This commit is contained in:
Campbell Barton 2008-12-12 18:59:17 +00:00
commit aa40953210
15 changed files with 4058 additions and 106 deletions

@ -41,7 +41,7 @@ struct ListBase;
struct MemFile;
#define BLENDER_VERSION 248
#define BLENDER_SUBVERSION 1
#define BLENDER_SUBVERSION 2
#define BLENDER_MINVERSION 245
#define BLENDER_MINSUBVERSION 15

@ -53,6 +53,7 @@ int brush_clone_image_delete(struct Brush *brush);
/* sampling */
float brush_sample_falloff(struct Brush *brush, float dist);
float brush_sample_falloff_noalpha(struct Brush *brush, float dist);
void brush_sample_tex(struct Brush *brush, float *xy, float *rgba);
void brush_imbuf_new(struct Brush *brush, short flt, short texfalloff, int size,
struct ImBuf **imbuf);

@ -198,8 +198,12 @@ int CustomData_get_layer_index(const struct CustomData *data, int type);
int CustomData_get_named_layer_index(const struct CustomData *data, int type, char *name);
int CustomData_get_active_layer_index(const struct CustomData *data, int type);
int CustomData_get_render_layer_index(const struct CustomData *data, int type);
int CustomData_get_clone_layer_index(const struct CustomData *data, int type);
int CustomData_get_mask_layer_index(const struct CustomData *data, int type);
int CustomData_get_active_layer(const struct CustomData *data, int type);
int CustomData_get_render_layer(const struct CustomData *data, int type);
int CustomData_get_clone_layer(const struct CustomData *data, int type);
int CustomData_get_mask_layer(const struct CustomData *data, int type);
/* copies the data from source to the data element at index in the first
* layer of type
@ -227,10 +231,14 @@ void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, voi
/* sets the nth layer of type as active */
void CustomData_set_layer_active(struct CustomData *data, int type, int n);
void CustomData_set_layer_render(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone(struct CustomData *data, int type, int n);
void CustomData_set_layer_mask(struct CustomData *data, int type, int n);
/* same as above but works with an index from CustomData_get_layer_index */
void CustomData_set_layer_active_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_render_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_clone_index(struct CustomData *data, int type, int n);
void CustomData_set_layer_mask_index(struct CustomData *data, int type, int n);
/* adds flag to the layer flags */
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);

@ -328,6 +328,23 @@ float brush_sample_falloff(Brush *brush, float dist)
return 0.0f;
}
float brush_sample_falloff_noalpha(Brush *brush, float dist)
{
float outer, inner;
outer = brush->size >> 1;
inner = outer*brush->innerradius;
if (dist <= inner) {
return 1.0f;
}
else if ((dist < outer) && (inner < outer)) {
return 1.0f - sqrt((dist - inner)/(outer - inner));
}
else
return 0.0f;
}
void brush_sample_tex(Brush *brush, float *xy, float *rgba)
{
MTex *mtex= brush->mtex[brush->texact];

@ -606,7 +606,7 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
{
const LayerTypeInfo *typeInfo;
CustomDataLayer *layer, *newlayer;
int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0;
int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0;
for(i = 0; i < source->totlayer; ++i) {
layer = &source->layers[i];
@ -618,6 +618,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
number = 0;
lastactive = layer->active;
lastrender = layer->active_rnd;
lastclone = layer->active_clone;
lastmask = layer->active_mask;
lasttype = type;
}
else
@ -637,6 +639,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
if(newlayer) {
newlayer->active = lastactive;
newlayer->active_rnd = lastrender;
newlayer->active_clone = lastclone;
newlayer->active_mask = lastmask;
}
}
}
@ -736,6 +740,28 @@ int CustomData_get_render_layer_index(const CustomData *data, int type)
return -1;
}
int CustomData_get_clone_layer_index(const CustomData *data, int type)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
return i + data->layers[i].active_clone;
return -1;
}
int CustomData_get_mask_layer_index(const CustomData *data, int type)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
return i + data->layers[i].active_mask;
return -1;
}
int CustomData_get_active_layer(const CustomData *data, int type)
{
int i;
@ -758,6 +784,27 @@ int CustomData_get_render_layer(const CustomData *data, int type)
return -1;
}
int CustomData_get_clone_layer(const CustomData *data, int type)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
return data->layers[i].active_clone;
return -1;
}
int CustomData_get_mask_layer(const CustomData *data, int type)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
return data->layers[i].active_mask;
return -1;
}
void CustomData_set_layer_active(CustomData *data, int type, int n)
{
@ -777,6 +824,24 @@ void CustomData_set_layer_render(CustomData *data, int type, int n)
data->layers[i].active_rnd = n;
}
void CustomData_set_layer_clone(CustomData *data, int type, int n)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
data->layers[i].active_clone = n;
}
void CustomData_set_layer_mask(CustomData *data, int type, int n)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
data->layers[i].active_mask = n;
}
/* for using with an index from CustomData_get_active_layer_index and CustomData_get_render_layer_index */
void CustomData_set_layer_active_index(CustomData *data, int type, int n)
{
@ -796,6 +861,23 @@ void CustomData_set_layer_render_index(CustomData *data, int type, int n)
data->layers[i].active_rnd = n-i;
}
void CustomData_set_layer_clone_index(CustomData *data, int type, int n)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
data->layers[i].active_clone = n-i;
}
void CustomData_set_layer_mask_index(CustomData *data, int type, int n)
{
int i;
for(i=0; i < data->totlayer; ++i)
if(data->layers[i].type == type)
data->layers[i].active_mask = n-i;
}
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
{
@ -882,9 +964,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
if(index > 0 && data->layers[index-1].type == type) {
data->layers[index].active = data->layers[index-1].active;
data->layers[index].active_rnd = data->layers[index-1].active_rnd;
data->layers[index].active_clone = data->layers[index-1].active_clone;
data->layers[index].active_mask = data->layers[index-1].active_mask;
} else {
data->layers[index].active = 0;
data->layers[index].active_rnd = 0;
data->layers[index].active_clone = 0;
data->layers[index].active_mask = 0;
}
customData_update_offsets(data);
@ -944,6 +1030,8 @@ int CustomData_free_layer(CustomData *data, int type, int totelem, int index)
for (; i < data->totlayer && data->layers[i].type == type; i++) {
data->layers[i].active--;
data->layers[i].active_rnd--;
data->layers[i].active_clone--;
data->layers[i].active_mask--;
}
}

@ -8007,6 +8007,17 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 2)) {
Scene *sce;
/* Note, these will need to be added for painting */
for (sce= main->scene.first; sce; sce= sce->id.next) {
sce->toolsettings->imapaint.seam_bleed = 2;
sce->toolsettings->imapaint.normal_angle = 80;
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */

@ -80,6 +80,7 @@ void viewmove(int mode);
void viewmoveNDOFfly(int mode);
void viewmoveNDOF(int mode);
void view_zoom_mouseloc(float dfac, short *mouseloc);
int view_mouse_depth( float mouse_worldloc[3], short mval[2], int dist);
int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize);
void setwinmatrixview3d(int winx, int winy, struct rctf *rect);

@ -453,6 +453,8 @@ void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char la
#define B_GEN_SKELETON 2085
#define B_RETARGET_SKELETON 2086
#define B_SETTFACE_CLONE 2087
#define B_SETTFACE_MASK 2088
/* *********************** */
#define B_VGROUPBUTS 2100

@ -37,6 +37,8 @@ typedef struct CustomDataLayer {
int flag; /* general purpose flag */
int active; /* number of the active layer of this type */
int active_rnd; /* number of the layer to render*/
int active_clone; /* number of the layer to render*/
int active_mask; /* number of the layer to render*/
char pad[4];
char name[32]; /* layer name */
void *data; /* layer data */

@ -345,7 +345,9 @@ typedef struct TimeMarker {
typedef struct ImagePaintSettings {
struct Brush *brush;
short flag, tool;
int pad3;
/* for projection painting only */
short seam_bleed,normal_angle;
} ImagePaintSettings;
typedef struct ParticleBrushData {
@ -799,6 +801,15 @@ typedef struct Scene {
#define IMAGEPAINT_DRAW_TOOL 2
#define IMAGEPAINT_DRAW_TOOL_DRAWING 4
/* projection painting only */
#define IMAGEPAINT_PROJECT_DISABLE 8 /* Non projection 3D painting */
#define IMAGEPAINT_PROJECT_XRAY 16
#define IMAGEPAINT_PROJECT_BACKFACE 32
#define IMAGEPAINT_PROJECT_FLAT 64
#define IMAGEPAINT_PROJECT_LAYER_CLONE 128
#define IMAGEPAINT_PROJECT_LAYER_MASK 256
#define IMAGEPAINT_PROJECT_LAYER_MASK_INV 512
/* toolsettings->uvcalc_flag */
#define UVCALC_FILLHOLES 1
#define UVCALC_NO_ASPECT_CORRECT 2 /* would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */

@ -184,7 +184,7 @@
static float editbutweight= 1.0;
float editbutvweight= 1;
static int actmcol= 0, acttface= 0, acttface_rnd = 0, actmcol_rnd = 0;
static int actmcol= 0, acttface= 0, acttface_rnd = 0, acttface_clone = 0, acttface_mask = 0, actmcol_rnd = 0;
extern ListBase editNurb;
@ -722,10 +722,10 @@ static void delete_customdata_layer(void *data1, void *data2)
Mesh *me= (Mesh*)data1;
CustomData *data= (G.obedit)? &G.editMesh->fdata: &me->fdata;
CustomDataLayer *layer= (CustomDataLayer*)data2;
void *actlayerdata, *rndlayerdata, *layerdata=layer->data;
void *actlayerdata, *rndlayerdata, *clonelayerdata, *masklayerdata, *layerdata=layer->data;
int type= layer->type;
int index= CustomData_get_layer_index(data, type);
int i, actindex, rndindex;
int i, actindex, rndindex, cloneindex, maskindex;
/*ok, deleting a non-active layer needs to preserve the active layer indices.
to do this, we store a pointer to the .data member of both layer and the active layer,
@ -736,6 +736,8 @@ static void delete_customdata_layer(void *data1, void *data2)
layer. */
actlayerdata = data->layers[CustomData_get_active_layer_index(data, type)].data;
rndlayerdata = data->layers[CustomData_get_render_layer_index(data, type)].data;
clonelayerdata = data->layers[CustomData_get_clone_layer_index(data, type)].data;
masklayerdata = data->layers[CustomData_get_mask_layer_index(data, type)].data;
CustomData_set_layer_active(data, type, layer - &data->layers[index]);
/* Multires is handled seperately because the display data is separate
@ -787,6 +789,33 @@ static void delete_customdata_layer(void *data1, void *data2)
CustomData_set_layer_render(data, type, rndindex);
}
if (clonelayerdata != layerdata) {
/*find index. . .*/
cloneindex = CustomData_get_layer_index(data, type);
for (i=cloneindex; i<data->totlayer; i++) {
if (data->layers[i].data == clonelayerdata) {
cloneindex = i - cloneindex;
break;
}
}
/*set index. . .*/
CustomData_set_layer_clone(data, type, cloneindex);
}
if (masklayerdata != layerdata) {
/*find index. . .*/
maskindex = CustomData_get_layer_index(data, type);
for (i=maskindex; i<data->totlayer; i++) {
if (data->layers[i].data == masklayerdata) {
maskindex = i - maskindex;
break;
}
}
/*set index. . .*/
CustomData_set_layer_mask(data, type, maskindex);
}
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
@ -802,9 +831,9 @@ static void delete_customdata_layer(void *data1, void *data2)
static int customdata_buttons(
uiBlock *block, Mesh *me, CustomData *data,
int type, int *activep, int *renderp,
int setevt, int setevt_rnd, int newevt,
char *label, char *shortlabel, char *browsetip, char *browsetip_rnd,
int type, int *activep, int *renderp, int *clonep, int *maskp,
int setevt, int setevt_rnd, int setevt_clone, int setevt_mask, int newevt,
char *label, char *shortlabel, char *browsetip, char *browsetip_rnd, char *browsetip_clone, char *browsetip_mask,
char *newtip, char *deltip, int x, int y)
{
CustomDataLayer *layer;
@ -828,12 +857,27 @@ static int customdata_buttons(
layer= &data->layers[i];
if(layer->type == type) {
int xi = 0;
*activep= layer->active + 1;
*renderp= layer->active_rnd + 1;
if (clonep) *clonep= layer->active_clone + 1;
if (maskp) *maskp= layer->active_mask + 1;
uiDefIconButI(block, ROW, setevt, ICON_VIEW3D, x,y,25,19, activep, 1.0, count, 0, 0, browsetip);
uiDefIconButI(block, ROW, setevt_rnd, ICON_SCENE, x+25,y,25,19, renderp, 1.0, count, 0, 0, browsetip_rnd);
but=uiDefBut(block, TEX, setevt, "", x+50,y,145,19, layer->name, 0.0, 31.0, 0, 0, label);
if (clonep) {
uiDefIconButI(block, ROW, setevt_clone, ICON_TEXTURE, x+50,y,25,19, clonep, 1.0, count, 0, 0, browsetip_clone);
xi += 25;
}
if (maskp) {
uiDefIconButI(block, ROW, setevt_mask, ICON_PAINT, x+50+xi,y,25,19, maskp, 1.0, count, 0, 0, browsetip_mask);
xi += 25;
}
but=uiDefBut(block, TEX, setevt, "", x+50+xi,y,145-xi,19, layer->name, 0.0, 31.0, 0, 0, label);
uiButSetFunc(but, verify_customdata_name_func, data, layer);
but= uiDefIconBut(block, BUT, B_NOP, VICON_X, x+195,y,25,19, NULL, 0.0, 0.0, 0.0, 0.0, deltip);
uiButSetFunc(but, delete_customdata_layer, me, layer);
@ -902,14 +946,14 @@ static void editing_panel_mesh_type(Object *ob, Mesh *me)
uiBlockEndAlign(block);
fdata= (G.obedit)? &G.editMesh->fdata: &me->fdata;
yco= customdata_buttons(block, me, fdata, CD_MTFACE, &acttface, &acttface_rnd,
B_SETTFACE, B_SETTFACE_RND, B_NEWTFACE, "UV Texture", "UV Texture:",
"Set active UV texture", "Set rendering UV texture", "Creates a new UV texture layer",
yco= customdata_buttons(block, me, fdata, CD_MTFACE, &acttface, &acttface_rnd, (G.f & G_TEXTUREPAINT ? &acttface_clone : NULL), (G.f & G_TEXTUREPAINT ? &acttface_mask : NULL),
B_SETTFACE, B_SETTFACE_RND, B_SETTFACE_CLONE, B_SETTFACE_MASK, B_NEWTFACE, "UV Texture", "UV Texture:",
"Set active UV texture", "Set rendering UV texture", "Set the layer used for texturepaint cloning", "Set the texture paint stencil layer", "Creates a new UV texture layer",
"Removes the current UV texture layer", 190, 130);
yco= customdata_buttons(block, me, fdata, CD_MCOL, &actmcol, &actmcol_rnd,
B_SETMCOL, B_SETMCOL_RND, B_NEWMCOL, "Vertex Color", "Vertex Color:",
"Sets active vertex color layer", "Sets rendering vertex color layer", "Creates a new vertex color layer",
yco= customdata_buttons(block, me, fdata, CD_MCOL, &actmcol, &actmcol_rnd, NULL, NULL,
B_SETMCOL, B_SETMCOL_RND, B_NOP, B_NOP, B_NEWMCOL, "Vertex Color", "Vertex Color:",
"Sets active vertex color layer", "Sets rendering vertex color layer", "", "", "Creates a new vertex color layer",
"Removes the current vertex color layer", 190, yco-5);
if(yco < 0)
@ -4964,7 +5008,22 @@ void do_meshbuts(unsigned short event)
allqueue(REDRAWBUTSEDIT, 0);
}
break;
case B_SETTFACE_CLONE:
if (G.obedit || me) {
CustomData *fdata= (G.obedit)? &em->fdata: &me->fdata;
CustomData_set_layer_clone(fdata, CD_MTFACE, acttface_clone-1);
BIF_undo_push("Set Clone UV Texture");
allqueue(REDRAWBUTSEDIT, 0);
}
break;
case B_SETTFACE_MASK:
if (G.obedit || me) {
CustomData *fdata= (G.obedit)? &em->fdata: &me->fdata;
CustomData_set_layer_mask(fdata, CD_MTFACE, acttface_mask-1);
BIF_undo_push("Set Stencil UV Texture");
allqueue(REDRAWBUTSEDIT, 0);
}
break;
case B_FLIPNORM:
if(G.obedit) {
flip_editnormals();
@ -6279,20 +6338,23 @@ void brush_buttons(uiBlock *block, short sima,
ToolSettings *settings= G.scene->toolsettings;
Brush *brush= settings->imapaint.brush;
ID *id;
int yco, xco, butw;
int yco, xco, butw, but_idx;
short *menupoin = sima ? &(G.sima->menunr) : &(G.buts->menunr);
short do_project = settings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE ? 0:1;
yco= 160;
butw = sima ? 80 : 106;
uiBlockBeginAlign(block);
uiDefButS(block, ROW, evt_change, "Draw", 0, yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
uiDefButS(block, ROW, evt_change, "Soften", butw, yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
uiDefButS(block, ROW, evt_change, "Smear", butw*2, yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");
if (sima)
uiDefButS(block, ROW, evt_change, "Clone", butw*3, yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_CLONE, 0, 0, "Clone brush, use RMB to drag source image");
but_idx = 0;
uiDefButS(block, ROW, evt_change, "Draw", butw*(but_idx++),yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
if (sima || do_project==0)
uiDefButS(block, ROW, evt_change, "Soften", butw*(but_idx++), yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
uiDefButS(block, ROW, evt_change, "Smear", butw*(but_idx++), yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");
if (sima || do_project)
uiDefButS(block, ROW, evt_change, "Clone", butw*(but_idx++), yco,butw,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_CLONE, 0, 0, "Clone brush, use RMB to drag source image");
uiBlockEndAlign(block);
yco -= 30;
@ -6307,16 +6369,44 @@ void brush_buttons(uiBlock *block, short sima,
butw= 320-(xco+10);
uiDefButS(block, MENU, evt_nop, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5|Erase Alpha %x6|Add Alpha %x7", xco+10,yco,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, evt_change, "Wrap", xco+10,yco-25,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, evt_change, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
uiDefButF(block, NUM, evt_nop, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, evt_change, "Airbrush", xco+10,yco-25,butw/2,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
uiDefButF(block, NUM, evt_nop, "", xco+10 + butw/2,yco-25,butw/2,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
uiBlockEndAlign(block);
yco -= 25;
if (sima) {
uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, evt_change, "Wrap", xco+10,yco-45,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
yco -= 25;
}
else {
yco -= 25;
uiBlockBeginAlign(block);
uiDefButBitS(block, TOGN|BIT, IMAGEPAINT_PROJECT_DISABLE, B_REDR, "Project Paint", xco+10,yco-25,butw,19, &settings->imapaint.flag, 0, 0, 0, 0, "Use projection painting for improved consistency in the brush strokes");
if ((settings->imapaint.flag & IMAGEPAINT_PROJECT_DISABLE)==0) {
/* Projection Painting */
uiDefButBitS(block, TOGN|BIT, IMAGEPAINT_PROJECT_XRAY, B_NOP, "Occlude", xco+10,yco-45,butw/2,19, &settings->imapaint.flag, 0, 0, 0, 0, "Only paint onto the faces directly under the brush (slower)");
uiDefButBitS(block, TOGN|BIT, IMAGEPAINT_PROJECT_BACKFACE, B_NOP, "Cull", xco+10+butw/2,yco-45,butw/2,19, &settings->imapaint.flag, 0, 0, 0, 0, "Ignore faces pointing away from the view (faster)");
uiDefButBitS(block, TOGN|BIT, IMAGEPAINT_PROJECT_FLAT, B_NOP, "Normal", xco+10,yco-65,butw/2,19, &settings->imapaint.flag, 0, 0, 0, 0, "Paint most on faces pointing towards the view");
uiDefButS(block, NUM, B_NOP, "", xco+10 +(butw/2),yco-65,butw/2,19, &settings->imapaint.normal_angle, 10.0, 90.0, 0, 0, "Paint most on faces pointing towards the view acording to this angle");
uiDefButS(block, NUM, B_NOP, "Bleed: ", xco+10,yco-85,butw,19, &settings->imapaint.seam_bleed, 0.0, 8.0, 0, 0, "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)");
uiBlockEndAlign(block);
uiBlockBeginAlign(block);
uiDefButBitS(block, TOG|BIT, IMAGEPAINT_PROJECT_LAYER_MASK, B_NOP, "Stencil Layer", xco+10,yco-110,butw-30,19, &settings->imapaint.flag, 0, 0, 0, 0, "Set the mask layer from the UV layer buttons");
uiDefButBitS(block, TOG|BIT, IMAGEPAINT_PROJECT_LAYER_MASK_INV, B_NOP, "Inv", xco+10 + butw-30,yco-110,30,19, &settings->imapaint.flag, 0, 0, 0, 0, "Invert the mask");
uiBlockEndAlign(block);
}
uiBlockEndAlign(block);
}
uiBlockBeginAlign(block);
uiDefButF(block, COL, B_VPCOLSLI, "", 0,yco,200,19, brush->rgb, 0, 0, 0, 0, "");
uiDefButF(block, NUMSLI, evt_nop, "Opacity ", 0,yco-20,180,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");

@ -3309,7 +3309,12 @@ void drawview3dspace(ScrArea *sa, void *spacedata)
fdrawXORcirc((float)c[0], (float)c[1], (float)pset->brush[pset->brushtype].size);
}
}
if(!G.obedit && OBACT && G.f&G_TEXTUREPAINT && area_is_active_area(v3d->area) && G.scene->toolsettings->imapaint.brush){
short c[2];
getmouseco_areawin(c);
fdrawXORcirc((float)c[0], (float)c[1], (float)G.scene->toolsettings->imapaint.brush->size/2);
}
if(v3d->persp>1) drawviewborder();
if(v3d->flag2 & V3D_FLYMODE) drawviewborder_flymode();

File diff suppressed because it is too large Load Diff

@ -1307,6 +1307,14 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
}
}
}
else if (!G.obedit && OBACT && G.f&G_TEXTUREPAINT){
if(G.scene->toolsettings->imapaint.brush &&
event!=LEFTMOUSE && event!=RIGHTMOUSE && event!=MIDDLEMOUSE &&
(event==MOUSEY || event==MOUSEX) && bwin_qtest(sa->win)==0) {
allqueue(REDRAWVIEW3D, 0);
}
}
/* Handle retopo painting */
if(retopo_mesh_paint_check()) {

@ -796,12 +796,15 @@ void viewmoveNDOFfly(int mode)
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
}
int view_autodist( float mouse_worldloc[3] ) //, float *autodist )
/* Be sure to run persp(PERSP_VIEW) if this isnt set,
*
* mouse_worldloc - worldspace vector that is set
* mval - screenspace location, or from getmouseco_areawin(mval)
* dist - the size of the square to use when averaging the Z depth.
*/
int view_mouse_depth( float mouse_worldloc[3], short mval[2], int dist)
{
View3D *v3d = G.vd;
/* Zooms in on a border drawn by the user */
short mval[2];
rcti rect;
/* ZBuffer depth vars */
@ -813,13 +816,13 @@ int view_autodist( float mouse_worldloc[3] ) //, float *autodist )
getmouseco_areawin(mval);
persp(PERSP_VIEW);
/* persp(PERSP_VIEW); */
rect.xmax = mval[0] + 4;
rect.ymax = mval[1] + 4;
rect.xmax = mval[0] + dist;
rect.ymax = mval[1] + dist;
rect.xmin = mval[0] - 4;
rect.ymin = mval[1] - 4;
rect.xmin = mval[0] - dist;
rect.ymin = mval[1] - dist;
/* Get Z Depths, needed for perspective, nice for ortho */
bgl_get_mats(&mats);
@ -943,7 +946,8 @@ void viewmove(int mode)
VecMulf(obofs, -1.0f);
}
else if (U.uiflag & USER_ORBIT_ZBUF) {
if ((use_sel=view_autodist(obofs))) {
persp(PERSP_VIEW);
if ((use_sel=view_mouse_depth(obofs, mval_area, 4))) {
if (G.vd->persp==V3D_PERSP) {
float my_origin[3]; /* original G.vd->ofs */
float my_pivot[3]; /* view */
@ -974,6 +978,8 @@ void viewmove(int mode)
} else {
ofs[0] = ofs[1] = ofs[2] = 0.0f;
}
persp(PERSP_WIN);
}
else
ofs[0] = ofs[1] = ofs[2] = 0.0f;