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:
authorJason Wilkins <Jason.A.Wilkins@gmail.com>2010-07-14 18:11:03 +0400
committerJason Wilkins <Jason.A.Wilkins@gmail.com>2010-07-14 18:11:03 +0400
commit5505697ac508c02b8a2e196c5a8c07431bc687cf (patch)
treea550a4718d586066017e3861d42104ef09e969bf /source
parentae1748b98470f08ed805e101b218f44c17d9b6b2 (diff)
Merge GSOC Sculpt Branch: 28499-30319
https://svn.blender.org/svnroot/bf-blender/branches/soc-2010-jwilkins See log of that branch for details.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_blender.h4
-rw-r--r--source/blender/blenkernel/BKE_brush.h10
-rw-r--r--source/blender/blenkernel/BKE_paint.h4
-rw-r--r--source/blender/blenkernel/intern/brush.c102
-rw-r--r--source/blender/blenkernel/intern/colortools.c56
-rw-r--r--source/blender/blenkernel/intern/icons.c5
-rw-r--r--source/blender/blenkernel/intern/image.c6
-rw-r--r--source/blender/blenlib/BLI_pbvh.h26
-rw-r--r--source/blender/blenlib/intern/math_geom.c77
-rw-r--r--source/blender/blenlib/intern/pbvh.c321
-rw-r--r--source/blender/blenloader/intern/readfile.c77
-rw-r--r--source/blender/editors/gpencil/gpencil_buttons.c2
-rw-r--r--source/blender/editors/include/UI_interface.h6
-rw-r--r--source/blender/editors/interface/interface_icons.c12
-rw-r--r--source/blender/editors/interface/interface_templates.c73
-rw-r--r--source/blender/editors/interface/resources.c11
-rw-r--r--source/blender/editors/sculpt_paint/SConscript10
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c78
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h7
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c93
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c816
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c6
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c3013
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h44
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c302
-rw-r--r--source/blender/editors/space_image/image_buttons.c2
-rw-r--r--source/blender/editors/space_logic/logic_window.c2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c10
-rw-r--r--source/blender/gpu/intern/gpu_draw.c1
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h139
-rw-r--r--source/blender/makesdna/DNA_color_types.h7
-rw-r--r--source/blender/makesdna/DNA_scene_types.h43
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h13
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h3
-rw-r--r--source/blender/makesrna/SConscript1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c384
-rw-r--r--source/blender/makesrna/intern/rna_image.c17
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c25
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c41
-rw-r--r--source/blender/windowmanager/SConscript4
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c4
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c99
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c24
47 files changed, 4756 insertions, 1231 deletions
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 7ac5815943a..5936805765d 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -43,9 +43,9 @@ struct bContext;
struct ReportList;
struct Scene;
struct Main;
-
+
#define BLENDER_VERSION 252
-#define BLENDER_SUBVERSION 5
+#define BLENDER_SUBVERSION 6 // XXX: this shouldn't be merged with trunk, this is so Sculpt branch can detect old files
#define BLENDER_MINVERSION 250
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index fcc636215c9..6a209167f93 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -84,5 +84,15 @@ unsigned int *brush_gen_texture_cache(struct Brush *br, int half_side);
void brush_radial_control_invoke(struct wmOperator *op, struct Brush *br, float size_weight);
int brush_radial_control_exec(struct wmOperator *op, struct Brush *br, float size_weight);
+/* unified strength and size */
+int sculpt_get_brush_size(struct Brush *brush);
+void sculpt_set_brush_size(struct Brush *brush, int size);
+int sculpt_get_lock_brush_size(struct Brush *brush);
+float sculpt_get_brush_unprojected_radius(struct Brush *brush);
+void sculpt_set_brush_unprojected_radius(struct Brush *brush, float unprojected_radius);
+float sculpt_get_brush_alpha(struct Brush *brush);
+void sculpt_set_brush_alpha(struct Brush *brush, float alpha);
+
+
#endif
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index cd412ca5a74..f9954b3d55d 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -28,6 +28,8 @@
#ifndef BKE_PAINT_H
#define BKE_PAINT_H
+#include "DNA_vec_types.h"
+
struct Brush;
struct MFace;
struct MultireModifierData;
@@ -96,6 +98,8 @@ typedef struct SculptSession {
struct GPUDrawObject *drawobject;
int modifiers_active;
+
+ rcti previous_r;
} SculptSession;
void free_sculptsession(struct Object *ob);
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 538012ccc41..c423d426e32 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -53,8 +53,7 @@
#include "BKE_main.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
-
-
+#include "BKE_icons.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -70,29 +69,59 @@ Brush *add_brush(const char *name)
brush= alloc_libblock(&G.main->brush, ID_BR, name);
- brush->rgb[0]= 1.0f;
+ /* BRUSH SCULPT TOOL SETTINGS */
+ brush->sculpt_tool = SCULPT_TOOL_DRAW; /* sculpting defaults to the draw tool for new brushes */
+ brush->size= 35; /* radius of the brush in pixels */
+ brush->alpha= 0.5f; /* brush strength/intensity probably variable should be renamed? */
+ brush->autosmooth_factor= 0.0f;
+ brush->crease_pinch_factor= 0.5f;
+ brush->sculpt_plane = SCULPT_DISP_DIR_VIEW;
+ brush->plane_offset= 0.0f; /* how far above or below the plane that is found by averaging the faces */
+ brush->plane_trim= 0.5f;
+ brush->clone.alpha= 0.5f;
+ brush->normal_weight= 0.0f;
+
+ /* BRUSH PAINT TOOL SETTINGS */
+ brush->rgb[0]= 1.0f; /* default rgb color of the brush when painting - white */
brush->rgb[1]= 1.0f;
brush->rgb[2]= 1.0f;
- brush->alpha= 0.2f;
- brush->size= 25;
- brush->spacing= 3.5f;
+
+ /* BRUSH STROKE SETTINGS */
+ brush->flag |= (BRUSH_SPACE|BRUSH_SPACE_ATTEN);
+ brush->spacing= 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
+
brush->smooth_stroke_radius= 75;
- brush->smooth_stroke_factor= 0.9;
- brush->rate= 0.1f;
+ brush->smooth_stroke_factor= 0.9f;
+
+ brush->rate= 0.1f; /* time delay between dots of paint or sculpting when doing airbrush mode */
+
brush->jitter= 0.0f;
- brush->clone.alpha= 0.5;
- brush->sculpt_tool = SCULPT_TOOL_DRAW;
- brush->flag |= BRUSH_SPACE;
- brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
-
+ /* BRUSH TEXTURE SETTINGS */
default_mtex(&brush->mtex);
+ brush->texture_sample_bias= 0; /* value to added to texture samples */
+
+ /* brush appearance */
+
+ brush->image_icon= NULL;
+
+ brush->add_col[0]= 1.00; /* add mode color is light red */
+ brush->add_col[1]= 0.39;
+ brush->add_col[2]= 0.39;
+
+ brush->sub_col[0]= 0.39; /* subtract mode color is light blue */
+ brush->sub_col[1]= 0.39;
+ brush->sub_col[2]= 1.00;
+
+ /* the default alpha falloff curve */
+ brush_curve_preset(brush, CURVE_PRESET_SMOOTH);
+
/* enable fake user by default */
brush->id.flag |= LIB_FAKEUSER;
brush_toggled_fake_user(brush);
-
- return brush;
+
+ return brush;
}
Brush *copy_brush(Brush *brush)
@@ -118,7 +147,7 @@ Brush *copy_brush(Brush *brush)
void free_brush(Brush *brush)
{
if(brush->mtex.tex) brush->mtex.tex->id.us--;
-
+
curvemapping_free(brush->curve);
}
@@ -731,11 +760,19 @@ static void brush_apply_pressure(BrushPainter *painter, Brush *brush, float pres
brush->spacing = MAX2(1.0, painter->startspacing*(1.5f-pressure));
}
-static void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos)
+void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos)
{
if(brush->jitter){
- jitterpos[0] = pos[0] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2);
- jitterpos[1] = pos[1] + ((BLI_frand()-0.5f) * brush->size * brush->jitter * 2);
+ float rand_pos[2];
+
+ // find random position within a circle of diameter 1
+ do {
+ rand_pos[0] = BLI_frand()-0.5f;
+ rand_pos[1] = BLI_frand()-0.5f;
+ } while (len_v2(rand_pos) > 0.5f);
+
+ jitterpos[0] = pos[0] + 2*rand_pos[0]*brush->size*brush->jitter;
+ jitterpos[1] = pos[1] + 2*rand_pos[1]*brush->size*brush->jitter;
}
else {
VECCOPY2D(jitterpos, pos);
@@ -887,7 +924,7 @@ int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, doubl
/* Uses the brush curve control to find a strength value between 0 and 1 */
float brush_curve_strength_clamp(Brush *br, float p, const float len)
{
- if(p >= len) p= 1.0f;
+ if(p >= len) return 0;
else p= p/len;
p= curvemapping_evaluateF(br->curve, 0, p);
@@ -899,9 +936,12 @@ float brush_curve_strength_clamp(Brush *br, float p, const float len)
* used for sculpt only */
float brush_curve_strength(Brush *br, float p, const float len)
{
- if(p >= len) p= 1.0f;
- else p= p/len;
- return curvemapping_evaluateF(br->curve, 0, p);
+ if(p >= len)
+ p= 1.0f;
+ else
+ p= p/len;
+
+ return curvemapping_evaluateF(br->curve, 0, p);
}
/* TODO: should probably be unified with BrushPainter stuff? */
@@ -915,7 +955,7 @@ unsigned int *brush_gen_texture_cache(Brush *br, int half_side)
memset(&texres, 0, sizeof(TexResult));
- if(mtex && mtex->tex) {
+ if(mtex->tex) {
float x, y, step = 2.0 / side, co[3];
texcache = MEM_callocN(sizeof(int) * side * side, "Brush texture cache");
@@ -993,9 +1033,9 @@ void brush_radial_control_invoke(wmOperator *op, Brush *br, float size_weight)
float original_value= 0;
if(mode == WM_RADIALCONTROL_SIZE)
- original_value = br->size * size_weight;
+ original_value = sculpt_get_brush_size(br) * size_weight;
else if(mode == WM_RADIALCONTROL_STRENGTH)
- original_value = br->alpha;
+ original_value = sculpt_get_brush_alpha(br);
else if(mode == WM_RADIALCONTROL_ANGLE) {
MTex *mtex = brush_active_texture(br);
if(mtex)
@@ -1013,9 +1053,15 @@ int brush_radial_control_exec(wmOperator *op, Brush *br, float size_weight)
const float conv = 0.017453293;
if(mode == WM_RADIALCONTROL_SIZE)
- br->size = new_value * size_weight;
+ if (sculpt_get_lock_brush_size(br)) {
+ float initial_value = RNA_float_get(op->ptr, "initial_value");
+ const float unprojected_radius = sculpt_get_brush_unprojected_radius(br);
+ sculpt_set_brush_unprojected_radius(br, unprojected_radius * new_value/initial_value * size_weight);
+ }
+ else
+ sculpt_set_brush_size(br, new_value * size_weight);
else if(mode == WM_RADIALCONTROL_STRENGTH)
- br->alpha = new_value;
+ sculpt_set_brush_alpha(br, new_value);
else if(mode == WM_RADIALCONTROL_ANGLE) {
MTex *mtex = brush_active_texture(br);
if(mtex)
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index c8a01b1c12f..a07c18f42f3 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -126,6 +126,9 @@ CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, floa
cumap->cm[a].curve[1].x= maxx;
cumap->cm[a].curve[1].y= maxy;
}
+
+ cumap->changed_timestamp = 0;
+
return cumap;
}
@@ -240,10 +243,12 @@ void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset)
switch(preset) {
case CURVE_PRESET_LINE: cuma->totpoint= 2; break;
- case CURVE_PRESET_SHARP: cuma->totpoint= 3; break;
+ case CURVE_PRESET_SHARP: cuma->totpoint= 4; break;
case CURVE_PRESET_SMOOTH: cuma->totpoint= 4; break;
case CURVE_PRESET_MAX: cuma->totpoint= 2; break;
- case CURVE_PRESET_MID9: cuma->totpoint= 9;
+ case CURVE_PRESET_MID9: cuma->totpoint= 9; break;
+ case CURVE_PRESET_ROUND: cuma->totpoint= 4; break;
+ case CURVE_PRESET_ROOT: cuma->totpoint= 4; break;
}
cuma->curve= MEM_callocN(cuma->totpoint*sizeof(CurveMapPoint), "curve points");
@@ -251,27 +256,29 @@ void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset)
switch(preset) {
case CURVE_PRESET_LINE:
cuma->curve[0].x= clipr->xmin;
- cuma->curve[0].y= clipr->ymin;
+ cuma->curve[0].y= clipr->ymax;
cuma->curve[0].flag= 0;
cuma->curve[1].x= clipr->xmax;
- cuma->curve[1].y= clipr->ymax;
+ cuma->curve[1].y= clipr->ymin;
cuma->curve[1].flag= 0;
break;
case CURVE_PRESET_SHARP:
cuma->curve[0].x= 0;
cuma->curve[0].y= 1;
- cuma->curve[1].x= 0.33;
- cuma->curve[1].y= 0.33;
- cuma->curve[2].x= 1;
- cuma->curve[2].y= 0;
+ cuma->curve[1].x= 0.25;
+ cuma->curve[1].y= 0.50;
+ cuma->curve[2].x= 0.75;
+ cuma->curve[2].y= 0.04;
+ cuma->curve[3].x= 1;
+ cuma->curve[3].y= 0;
break;
case CURVE_PRESET_SMOOTH:
cuma->curve[0].x= 0;
cuma->curve[0].y= 1;
cuma->curve[1].x= 0.25;
- cuma->curve[1].y= 0.92;
+ cuma->curve[1].y= 0.94;
cuma->curve[2].x= 0.75;
- cuma->curve[2].y= 0.08;
+ cuma->curve[2].y= 0.06;
cuma->curve[3].x= 1;
cuma->curve[3].y= 0;
break;
@@ -290,8 +297,29 @@ void curvemap_reset(CurveMap *cuma, rctf *clipr, int preset)
cuma->curve[i].y= 0.5;
}
}
+ break;
+ case CURVE_PRESET_ROUND:
+ cuma->curve[0].x= 0;
+ cuma->curve[0].y= 1;
+ cuma->curve[1].x= 0.5;
+ cuma->curve[1].y= 0.90;
+ cuma->curve[2].x= 0.86;
+ cuma->curve[2].y= 0.5;
+ cuma->curve[3].x= 1;
+ cuma->curve[3].y= 0;
+ break;
+ case CURVE_PRESET_ROOT:
+ cuma->curve[0].x= 0;
+ cuma->curve[0].y= 1;
+ cuma->curve[1].x= 0.25;
+ cuma->curve[1].y= 0.95;
+ cuma->curve[2].x= 0.75;
+ cuma->curve[2].y= 0.44;
+ cuma->curve[3].x= 1;
+ cuma->curve[3].y= 0;
+ break;
}
-
+
if(cuma->table) {
MEM_freeN(cuma->table);
cuma->table= NULL;
@@ -619,7 +647,9 @@ void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
float thresh= 0.01f*(clipr->xmax - clipr->xmin);
float dx= 0.0f, dy= 0.0f;
int a;
-
+
+ cumap->changed_timestamp++;
+
/* clamp with clip */
if(cumap->flag & CUMA_DO_CLIP) {
for(a=0; a<cuma->totpoint; a++) {
@@ -701,7 +731,7 @@ float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
if(cuma->table==NULL) {
curvemap_make_table(cuma, &cumap->clipr);
if(cuma->table==NULL)
- return value;
+ return 1.0f-value;
}
return curvemap_evaluateF(cuma, value);
}
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
index 29314fb4865..ad2c857be75 100644
--- a/source/blender/blenkernel/intern/icons.c
+++ b/source/blender/blenkernel/intern/icons.c
@@ -38,6 +38,7 @@
#include "DNA_material_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
+#include "DNA_brush_types.h"
#include "BLI_ghash.h"
@@ -120,6 +121,7 @@ struct PreviewImage* BKE_previewimg_create()
for (i=0; i<PREVIEW_MIPMAPS; ++i) {
prv_img->changed[i] = 1;
+ prv_img->changed_timestamp[i] = 0;
}
return prv_img;
}
@@ -202,7 +204,7 @@ PreviewImage* BKE_previewimg_get(ID *id)
Image *img = (Image*)id;
if (!img->preview) img->preview = BKE_previewimg_create();
prv_img = img->preview;
- }
+ }
return prv_img;
}
@@ -224,6 +226,7 @@ void BKE_icon_changed(int id)
int i;
for (i=0; i<PREVIEW_MIPMAPS; ++i) {
prv->changed[i] = 1;
+ prv->changed_timestamp[i]++;
}
}
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index dc78dac04dd..b66b5c60916 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -200,9 +200,9 @@ void free_image(Image *ima)
}
BKE_icon_delete(&ima->id);
ima->id.icon_id = 0;
- if (ima->preview) {
- BKE_previewimg_free(&ima->preview);
- }
+
+ BKE_previewimg_free(&ima->preview);
+
for(a=0; a<IMA_MAX_RENDER_SLOT; a++) {
if(ima->renders[a]) {
RE_FreeRenderResult(ima->renders[a]);
diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h
index 519e3ddde1d..4797aeb2364 100644
--- a/source/blender/blenlib/BLI_pbvh.h
+++ b/source/blender/blenlib/BLI_pbvh.h
@@ -36,12 +36,17 @@ struct ListBase;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
+typedef struct {
+ float (*co)[3];
+} PBVHProxyNode;
+
/* Callbacks */
/* returns 1 if the search should continue from this node, 0 otherwise */
typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data);
+typedef void (*BLI_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float* tmin);
/* Building */
@@ -70,7 +75,7 @@ void BLI_pbvh_search_gather(PBVH *bvh,
it's up to the callback to find the primitive within the leaves that is
hit first */
-void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
+void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
float ray_start[3], float ray_normal[3], int original);
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
float ray_start[3], float ray_normal[3], float *dist);
@@ -106,6 +111,8 @@ void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node,
void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
+float BLI_pbvh_node_get_tmin(PBVHNode* node);
+
/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */
void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
@@ -159,13 +166,21 @@ typedef struct PBVHVertexIter {
float *fno;
} PBVHVertexIter;
+#ifdef _MSC_VER
+#pragma warning (disable:4127) // conditional expression is constant
+#endif
+
#define BLI_pbvh_vertex_iter_begin(bvh, node, vi, mode) \
{ \
struct DMGridData **grids; \
struct MVert *verts; \
int *grid_indices, totgrid, gridsize, *vert_indices, uniq_verts, totvert; \
\
- memset(&vi, 0, sizeof(PBVHVertexIter)); \
+ vi.grid= 0; \
+ vi.no= 0; \
+ vi.fno= 0; \
+ vi.mvert= 0; \
+ vi.skip= 0; \
\
BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); \
BLI_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); \
@@ -222,6 +237,13 @@ typedef struct PBVHVertexIter {
} \
}
+void BLI_pbvh_node_get_proxies(PBVHNode* node, PBVHProxyNode** proxies, int* proxy_count);
+void BLI_pbvh_node_free_proxies(PBVHNode* node);
+PBVHProxyNode* BLI_pbvh_node_add_proxy(PBVH* bvh, PBVHNode* node);
+void BLI_pbvh_gather_proxies(PBVH* pbvh, PBVHNode*** nodes, int* totnode);
+
+//void BLI_pbvh_node_BB_reset(PBVHNode* node);
+//void BLI_pbvh_node_BB_expand(PBVHNode* node, float co[3]);
#endif /* BLI_PBVH_H */
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 0a06cd10e1e..e8fb922ce4d 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -62,6 +62,7 @@ float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const floa
n[0]= n1[1]*n2[2]-n1[2]*n2[1];
n[1]= n1[2]*n2[0]-n1[0]*n2[2];
n[2]= n1[0]*n2[1]-n1[1]*n2[0];
+
return normalize_v3(n);
}
@@ -401,16 +402,17 @@ int isect_line_tri_v3(float p1[3], float p2[3], float v0[3], float v1[3], float
sub_v3_v3v3(s, p1, v0);
- cross_v3_v3v3(q, s, e1);
- *lambda = f * dot_v3v3(e2, q);
- if ((*lambda < 0.0)||(*lambda > 1.0)) return 0;
-
u = f * dot_v3v3(s, p);
if ((u < 0.0)||(u > 1.0)) return 0;
- v = f * dot_v3v3(d, q);
+ cross_v3_v3v3(q, s, e1);
+
+ v = f * dot_v3v3(d, q);
if ((v < 0.0)||((u + v) > 1.0)) return 0;
+ *lambda = f * dot_v3v3(e2, q);
+ if ((*lambda < 0.0)||(*lambda > 1.0)) return 0;
+
if(uv) {
uv[0]= u;
uv[1]= v;
@@ -440,17 +442,18 @@ int isect_ray_tri_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2
sub_v3_v3v3(s, p1, v0);
- cross_v3_v3v3(q, s, e1);
- *lambda = f * dot_v3v3(e2, q);
- if ((*lambda < 0.0)) return 0;
-
u = f * dot_v3v3(s, p);
if ((u < 0.0)||(u > 1.0)) return 0;
+ cross_v3_v3v3(q, s, e1);
+
v = f * dot_v3v3(d, q);
if ((v < 0.0)||((u + v) > 1.0)) return 0;
- if(uv) {
+ *lambda = f * dot_v3v3(e2, q);
+ if ((*lambda < 0.0)) return 0;
+
+ if(uv) {
uv[0]= u;
uv[1]= v;
}
@@ -460,36 +463,36 @@ int isect_ray_tri_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2
int isect_ray_tri_epsilon_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float epsilon)
{
- float p[3], s[3], e1[3], e2[3], q[3];
- float a, f, u, v;
-
- sub_v3_v3v3(e1, v1, v0);
- sub_v3_v3v3(e2, v2, v0);
-
- cross_v3_v3v3(p, d, e2);
- a = dot_v3v3(e1, p);
- if (a == 0.0f) return 0;
- f = 1.0f/a;
-
- sub_v3_v3v3(s, p1, v0);
-
- cross_v3_v3v3(q, s, e1);
+ float p[3], s[3], e1[3], e2[3], q[3];
+ float a, f, u, v;
- u = f * dot_v3v3(s, p);
- if ((u < -epsilon)||(u > 1.0f+epsilon)) return 0;
-
- v = f * dot_v3v3(d, q);
- if ((v < -epsilon)||((u + v) > 1.0f+epsilon)) return 0;
+ sub_v3_v3v3(e1, v1, v0);
+ sub_v3_v3v3(e2, v2, v0);
- *lambda = f * dot_v3v3(e2, q);
- if ((*lambda < 0.0f)) return 0;
+ cross_v3_v3v3(p, d, e2);
+ a = dot_v3v3(e1, p);
+ if (a == 0.0f) return 0;
+ f = 1.0f/a;
- if(uv) {
- uv[0]= u;
- uv[1]= v;
- }
-
- return 1;
+ sub_v3_v3v3(s, p1, v0);
+
+ u = f * dot_v3v3(s, p);
+ if ((u < -epsilon)||(u > 1.0f+epsilon)) return 0;
+
+ cross_v3_v3v3(q, s, e1);
+
+ v = f * dot_v3v3(d, q);
+ if ((v < -epsilon)||((u + v) > 1.0f+epsilon)) return 0;
+
+ *lambda = f * dot_v3v3(e2, q);
+ if ((*lambda < 0.0f)) return 0;
+
+ if(uv) {
+ uv[0]= u;
+ uv[1]= v;
+ }
+
+ return 1;
}
int isect_ray_tri_threshold_v3(float p1[3], float d[3], float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float threshold)
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
index 426181e5304..7069eeea510 100644
--- a/source/blender/blenlib/intern/pbvh.c
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -92,6 +92,11 @@ struct PBVHNode {
unsigned int uniq_verts, face_verts;
char flag;
+
+ float tmin; // used for raycasting, is how close bb is to the ray point
+
+ int proxy_count;
+ PBVHProxyNode* proxies;
};
struct PBVH {
@@ -227,6 +232,17 @@ static void update_node_vb(PBVH *bvh, PBVHNode *node)
node->vb= vb;
}
+//void BLI_pbvh_node_BB_reset(PBVHNode* node)
+//{
+// BB_reset(&node->vb);
+//}
+//
+//void BLI_pbvh_node_BB_expand(PBVHNode* node, float co[3])
+//{
+// BB_expand(&node->vb, co);
+//}
+
+
/* Adapted from BLI_kdopbvh.c */
/* Returns the index of the first element on the right of the partition */
static int partition_indices(int *prim_indices, int lo, int hi, int axis,
@@ -354,10 +370,10 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
if(!G.background) {
node->draw_buffers =
GPU_build_mesh_buffers(map, bvh->verts, bvh->faces,
- node->prim_indices,
- node->totprim, node->vert_indices,
- node->uniq_verts,
- node->uniq_verts + node->face_verts);
+ node->prim_indices,
+ node->totprim, node->vert_indices,
+ node->uniq_verts,
+ node->uniq_verts + node->face_verts);
}
node->flag |= PBVH_UpdateDrawBuffers;
@@ -641,13 +657,12 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
{
PBVHNode *node;
int revisiting;
- void *search_data;
/* purpose here is to traverse tree, visiting child nodes before their
parents, this order is necessary for e.g. computing bounding boxes */
while(iter->stacksize) {
- /* pop node */
+ /* pop node */
iter->stacksize--;
node= iter->stack[iter->stacksize].node;
@@ -662,10 +677,7 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
if(revisiting)
return node;
- /* check search callback */
- search_data= iter->search_data;
-
- if(iter->scb && !iter->scb(node, search_data))
+ if(iter->scb && !iter->scb(node, iter->search_data))
continue; /* don't traverse, outside of search zone */
if(node->flag & PBVH_Leaf) {
@@ -685,6 +697,34 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter)
return NULL;
}
+static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter)
+{
+ PBVHNode *node;
+
+ while(iter->stacksize) {
+ /* pop node */
+ iter->stacksize--;
+ node= iter->stack[iter->stacksize].node;
+
+ /* on a mesh with no faces this can happen
+ * can remove this check if we know meshes have at least 1 face */
+ if(node==NULL) return NULL;
+
+ if(iter->scb && !iter->scb(node, iter->search_data)) continue; /* don't traverse, outside of search zone */
+
+ if(node->flag & PBVH_Leaf) {
+ /* immediately hit leaf node */
+ return node;
+ }
+ else {
+ pbvh_stack_push(iter, iter->bvh->nodes+node->children_offset+1, 0);
+ pbvh_stack_push(iter, iter->bvh->nodes+node->children_offset, 0);
+ }
+ }
+
+ return NULL;
+}
+
void BLI_pbvh_search_gather(PBVH *bvh,
BLI_pbvh_SearchCallback scb, void *search_data,
PBVHNode ***r_array, int *r_tot)
@@ -736,12 +776,105 @@ void BLI_pbvh_search_callback(PBVH *bvh,
pbvh_iter_begin(&iter, bvh, scb, search_data);
while((node=pbvh_iter_next(&iter)))
- if(node->flag & PBVH_Leaf)
+ if (node->flag & PBVH_Leaf)
hcb(node, hit_data);
pbvh_iter_end(&iter);
}
+typedef struct node_tree {
+ PBVHNode* data;
+
+ struct node_tree* left;
+ struct node_tree* right;
+} node_tree;
+
+static void node_tree_insert(node_tree* tree, node_tree* new_node)
+{
+ if (new_node->data->tmin < tree->data->tmin) {
+ if (tree->left) {
+ node_tree_insert(tree->left, new_node);
+ }
+ else {
+ tree->left = new_node;
+ }
+ }
+ else {
+ if (tree->right) {
+ node_tree_insert(tree->right, new_node);
+ }
+ else {
+ tree->right = new_node;
+ }
+ }
+}
+
+static void traverse_tree(node_tree* tree, BLI_pbvh_HitOccludedCallback hcb, void* hit_data, float* tmin)
+{
+ if (tree->left) traverse_tree(tree->left, hcb, hit_data, tmin);
+
+ hcb(tree->data, hit_data, tmin);
+
+ if (tree->right) traverse_tree(tree->right, hcb, hit_data, tmin);
+}
+
+static void free_tree(node_tree* tree)
+{
+ if (tree->left) {
+ free_tree(tree->left);
+ tree->left = 0;
+ }
+
+ if (tree->right) {
+ free_tree(tree->right);
+ tree->right = 0;
+ }
+
+ free(tree);
+}
+
+float BLI_pbvh_node_get_tmin(PBVHNode* node)
+{
+ return node->tmin;
+}
+
+void BLI_pbvh_search_callback_occluded(PBVH *bvh,
+ BLI_pbvh_SearchCallback scb, void *search_data,
+ BLI_pbvh_HitOccludedCallback hcb, void *hit_data)
+{
+ PBVHIter iter;
+ PBVHNode *node;
+ node_tree *tree = 0;
+
+ pbvh_iter_begin(&iter, bvh, scb, search_data);
+
+ while((node=pbvh_iter_next_occluded(&iter))) {
+ if(node->flag & PBVH_Leaf) {
+ node_tree* new_node = malloc(sizeof(node_tree));
+
+ new_node->data = node;
+
+ new_node->left = NULL;
+ new_node->right = NULL;
+
+ if (tree) {
+ node_tree_insert(tree, new_node);
+ }
+ else {
+ tree = new_node;
+ }
+ }
+ }
+
+ pbvh_iter_end(&iter);
+
+ if (tree) {
+ float tmin = FLT_MAX;
+ traverse_tree(tree, hcb, hit_data, &tmin);
+ free_tree(tree);
+ }
+}
+
static int update_search_cb(PBVHNode *node, void *data_v)
{
int flag= GET_INT_FROM_POINTER(data_v);
@@ -985,7 +1118,8 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot
GHashIterator *hiter;
GHash *map;
void *face, **faces;
- int i, tot;
+ unsigned i;
+ int tot;
map = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "pbvh_get_grid_updates gh");
@@ -1086,6 +1220,18 @@ void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max
copy_v3_v3(bb_max, node->orig_vb.bmax);
}
+void BLI_pbvh_node_get_proxies(PBVHNode* node, PBVHProxyNode** proxies, int* proxy_count)
+{
+ if (node->proxy_count > 0) {
+ if (proxies) *proxies = node->proxies;
+ if (proxy_count) *proxy_count = node->proxy_count;
+ }
+ else {
+ if (proxies) *proxies = 0;
+ if (proxy_count) *proxy_count = 0;
+ }
+}
+
/********************************* Raycast ***********************************/
typedef struct {
@@ -1100,16 +1246,13 @@ typedef struct {
static int ray_aabb_intersect(PBVHNode *node, void *data_v)
{
RaycastData *ray = data_v;
- float bb_min[3], bb_max[3], bbox[2][3];
+ float bbox[2][3];
float tmin, tmax, tymin, tymax, tzmin, tzmax;
if(ray->original)
- BLI_pbvh_node_get_original_BB(node, bb_min, bb_max);
+ BLI_pbvh_node_get_original_BB(node, bbox[0], bbox[1]);
else
- BLI_pbvh_node_get_BB(node, bb_min, bb_max);
-
- copy_v3_v3(bbox[0], bb_min);
- copy_v3_v3(bbox[1], bb_max);
+ BLI_pbvh_node_get_BB(node, bbox[0], bbox[1]);
tmin = (bbox[ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
tmax = (bbox[1-ray->sign[0]][0] - ray->start[0]) * ray->inv_dir[0];
@@ -1119,8 +1262,10 @@ static int ray_aabb_intersect(PBVHNode *node, void *data_v)
if((tmin > tymax) || (tymin > tmax))
return 0;
+
if(tymin > tmin)
tmin = tymin;
+
if(tymax < tmax)
tmax = tymax;
@@ -1129,20 +1274,20 @@ static int ray_aabb_intersect(PBVHNode *node, void *data_v)
if((tmin > tzmax) || (tzmin > tmax))
return 0;
-
- return 1;
- /* XXX: Not sure about this?
- if(tzmin > tmin)
- tmin = tzmin;
- if(tzmax < tmax)
- tmax = tzmax;
- return ((tmin < t1) && (tmax > t0));
- */
+ if(tzmin > tmin)
+ tmin = tzmin;
+ // XXX jwilkins: tmax does not need to be updated since we don't use it
+ // keeping this here for future reference
+ //if(tzmax < tmax) tmax = tzmax;
+
+ node->tmin = tmin;
+
+ return 1;
}
-void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
+void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
float ray_start[3], float ray_normal[3], int original)
{
RaycastData rcd;
@@ -1156,37 +1301,24 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitCallback cb, void *data,
rcd.sign[2] = rcd.inv_dir[2] < 0;
rcd.original = original;
- BLI_pbvh_search_callback(bvh, ray_aabb_intersect, &rcd, cb, data);
+ BLI_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
}
-/* XXX: Code largely copied from bvhutils.c, could be unified */
-/* Returns 1 if a better intersection has been found */
static int ray_face_intersection(float ray_start[3], float ray_normal[3],
float *t0, float *t1, float *t2, float *t3,
float *fdist)
{
- int hit = 0;
-
- do
- {
- float dist = FLT_MAX;
-
- if(!isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2,
- &dist, NULL, 0.1f))
- dist = FLT_MAX;
-
- if(dist >= 0 && dist < *fdist) {
- hit = 1;
- *fdist = dist;
- }
-
- t1 = t2;
- t2 = t3;
- t3 = NULL;
-
- } while(t2);
-
- return hit;
+ float dist;
+
+ if ((isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t1, t2, &dist, NULL, 0.1f) && dist < *fdist) ||
+ (t3 && isect_ray_tri_epsilon_v3(ray_start, ray_normal, t0, t2, t3, &dist, NULL, 0.1f) && dist < *fdist))
+ {
+ *fdist = dist;
+ return 1;
+ }
+ else {
+ return 0;
+ }
}
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
@@ -1399,3 +1531,86 @@ int BLI_pbvh_isDeformed(PBVH *pbvh)
{
return pbvh->deformed;
}
+/* Proxies */
+
+PBVHProxyNode* BLI_pbvh_node_add_proxy(PBVH* bvh, PBVHNode* node)
+{
+ int index, totverts;
+
+ #pragma omp critical
+ {
+
+ index = node->proxy_count;
+
+ node->proxy_count++;
+
+ if (node->proxies)
+ node->proxies= MEM_reallocN(node->proxies, node->proxy_count*sizeof(PBVHProxyNode));
+ else
+ node->proxies= MEM_mallocN(sizeof(PBVHProxyNode), "PBVHNodeProxy");
+
+ if (bvh->grids)
+ totverts = node->totprim*bvh->gridsize*bvh->gridsize;
+ else
+ totverts = node->uniq_verts;
+
+ node->proxies[index].co= MEM_callocN(sizeof(float[3])*totverts, "PBVHNodeProxy.co");
+ }
+
+ return node->proxies + index;
+}
+
+void BLI_pbvh_node_free_proxies(PBVHNode* node)
+{
+ #pragma omp critical
+ {
+ int p;
+
+ for (p= 0; p < node->proxy_count; p++) {
+ MEM_freeN(node->proxies[p].co);
+ node->proxies[p].co= 0;
+ }
+
+ MEM_freeN(node->proxies);
+ node->proxies = 0;
+
+ node->proxy_count= 0;
+ }
+}
+
+void BLI_pbvh_gather_proxies(PBVH* pbvh, PBVHNode*** r_array, int* r_tot)
+{
+ PBVHNode **array= NULL, **newarray, *node;
+ int tot= 0, space= 0;
+ int n;
+
+ for (n= 0; n < pbvh->totnode; n++) {
+ node = pbvh->nodes + n;
+
+ if(node->proxy_count > 0) {
+ if(tot == space) {
+ /* resize array if needed */
+ space= (tot == 0)? 32: space*2;
+ newarray= MEM_callocN(sizeof(PBVHNode)*space, "BLI_pbvh_gather_proxies");
+
+ if (array) {
+ memcpy(newarray, array, sizeof(PBVHNode)*tot);
+ MEM_freeN(array);
+ }
+
+ array= newarray;
+ }
+
+ array[tot]= node;
+ tot++;
+ }
+ }
+
+ if(tot == 0 && array) {
+ MEM_freeN(array);
+ array= NULL;
+ }
+
+ *r_array= array;
+ *r_tot= tot;
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index f6122161130..7b29ab2a666 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -1539,6 +1539,7 @@ static void lib_link_brush(FileData *fd, Main *main)
brush->id.flag -= LIB_NEEDLINK;
brush->mtex.tex= newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
+ brush->image_icon= newlibadr_us(fd, brush->id.lib, brush->image_icon);
brush->clone.image= newlibadr_us(fd, brush->id.lib, brush->clone.image);
}
}
@@ -10971,6 +10972,82 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
+ {
+ /* GSOC 2010 Sculpt - New settings for Brush */
+
+ Brush *brush;
+ for (brush= main->brush.first; brush; brush= brush->id.next) {
+ /* Sanity Check */
+
+ // infinite number of dabs
+ if (brush->spacing == 0)
+ brush->spacing = 10;
+
+ // will have no effect
+ if (brush->alpha == 0)
+ brush->alpha = 0.5f;
+
+ // bad radius
+ if (brush->unprojected_radius == 0)
+ brush->unprojected_radius = 0.125;
+
+ // unusable size
+ if (brush->size == 0)
+ brush->size = 35;
+
+ // can't see overlay
+ if (brush->texture_overlay_alpha == 0)
+ brush->texture_overlay_alpha = 33;
+
+ // same as draw brush
+ if (brush->crease_pinch_factor == 0)
+ brush->crease_pinch_factor = 0.5f;
+
+ // will sculpt no vertexes
+ if (brush->plane_trim == 0)
+ brush->plane_trim = 0.5f;
+
+ // same as smooth stroke off
+ if (brush->smooth_stroke_radius == 0)
+ brush->smooth_stroke_radius= 75;
+
+ // will keep cursor in one spot
+ if (brush->smooth_stroke_radius == 1)
+ brush->smooth_stroke_factor= 0.9f;
+
+ // same as dots
+ if (brush->rate == 0)
+ brush->rate = 0.1f;
+
+ /* New Settings */
+ if (main->versionfile < 252 || (main->versionfile == 252 && main->subversionfile < 6)) {
+ brush->flag |= BRUSH_SPACE_ATTEN; // explicitly enable adaptive space
+
+ // spacing was originally in pixels, convert it to percentage for new version
+ // size should not be zero due to sanity check above
+ brush->spacing = (int)(100*((float)brush->spacing) / ((float)brush->size));
+
+ if (brush->add_col[0] == 0 &&
+ brush->add_col[1] == 0 &&
+ brush->add_col[2] == 0)
+ {
+ brush->add_col[0] = 1.00;
+ brush->add_col[1] = 0.39;
+ brush->add_col[2] = 0.39;
+ }
+
+ if (brush->sub_col[0] == 0 &&
+ brush->sub_col[1] == 0 &&
+ brush->sub_col[2] == 0)
+ {
+ brush->sub_col[0] = 0.39;
+ brush->sub_col[1] = 0.39;
+ brush->sub_col[2] = 1.00;
+ }
+ }
+ }
+ }
+
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c
index 001773fc02a..17bafa3d399 100644
--- a/source/blender/editors/gpencil/gpencil_buttons.c
+++ b/source/blender/editors/gpencil/gpencil_buttons.c
@@ -243,7 +243,7 @@ static void draw_gpencil_panel (bContext *C, uiLayout *layout, bGPdata *gpd, Poi
col= uiLayoutColumn(layout, 0);
/* current Grease Pencil block */
// TODO: show some info about who owns this?
- uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_add", NULL, "GPENCIL_OT_data_unlink");
+ uiTemplateID(col, C, ctx_ptr, "grease_pencil", "GPENCIL_OT_data_add", NULL, "GPENCIL_OT_data_unlink", NULL);
/* add new layer button - can be used even when no data, since it can add a new block too */
uiItemO(col, NULL, 0, "GPENCIL_OT_layer_add");
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 93e91d02599..4b6b396483d 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -669,11 +669,11 @@ uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout);
void uiTemplateHeader(uiLayout *layout, struct bContext *C, int menus);
void uiTemplateDopeSheetFilter(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
void uiTemplateID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
- char *newop, char *openop, char *unlinkop);
+ char *newop, char *openop, char *unlinkop, char *filterop);
void uiTemplateIDBrowse(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
- char *newop, char *openop, char *unlinkop);
+ char *newop, char *openop, char *unlinkop, char *filterop);
void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
- char *newop, char *openop, char *unlinkop, int rows, int cols);
+ char *newop, char *openop, char *unlinkop, char *filterop, int rows, int cols);
void uiTemplateAnyID(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
char *proptypename, char *text);
void uiTemplatePathBuilder(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname,
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 499fe3b9767..232b6f7f317 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -46,6 +46,7 @@
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_brush_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -762,6 +763,7 @@ static void icon_create_mipmap(struct PreviewImage* prv_img, int miplevel)
prv_img->w[miplevel] = size;
prv_img->h[miplevel] = size;
prv_img->changed[miplevel] = 1;
+ prv_img->changed_timestamp[miplevel] = 0;
prv_img->rect[miplevel] = MEM_callocN(size*size*sizeof(unsigned int), "prv_rect");
}
}
@@ -976,6 +978,16 @@ int ui_id_icon_get(bContext *C, ID *id, int preview)
/* checks if not exists, or changed */
ui_id_icon_render(C, id, preview);
break;
+ case ID_BR:
+ { /* use the image in the brush as the icon */
+ /* XXX redundancy here can be reduced be rewriting this switch as an if */
+ ID* ima_id = (ID*)((Brush*)id)->image_icon;
+ id = ima_id ? ima_id : id;
+ iconid= BKE_icon_getid(id);
+ /* checks if not exists, or changed */
+ ui_id_icon_render(C, id, preview);
+ }
+ break;
default:
break;
}
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 7a5e0413f6d..cbe10496a72 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -42,6 +42,7 @@
#include "BKE_main.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
+#include "BKE_report.h"
#include "ED_screen.h"
#include "ED_render.h"
@@ -141,6 +142,8 @@ typedef struct TemplateID {
ListBase *idlb;
int prv_rows, prv_cols;
+
+ char filterop[64];
} TemplateID;
/* Search browse menu, assign */
@@ -170,15 +173,53 @@ static void id_search_cb(const bContext *C, void *arg_template, char *str, uiSea
/* ID listbase */
for(id= lb->first; id; id= id->next) {
if(!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
+ int filter_yes;
+
+ filter_yes= 0;
+
+ /* use filter */
+ if (template->filterop[0] != 0) {
+ PointerRNA ptr;
+ ReportList reports;
+ FunctionRNA *func;
+ ParameterList parms;
+
+ RNA_id_pointer_create(id, &ptr);
+
+ BKE_reports_init(&reports, RPT_PRINT);
+
+ func= RNA_struct_find_function(&ptr, template->filterop);
+
+ if (func) {
+ RNA_parameter_list_create(&parms, &ptr, func);
+
+ RNA_parameter_set_lookup(&parms, "context", &C);
+
+ if (RNA_function_call(C, &reports, &ptr, func, &parms) == 0) {
+ int* ret;
+ RNA_parameter_get_lookup(&parms, "ret", &ret);
- /* hide dot-datablocks */
- if(U.uiflag & USER_HIDE_DOT)
+ if (!(*ret)) {
+ RNA_parameter_list_free(&parms);
+ continue;
+ }
+ else {
+ filter_yes= 1;
+ }
+ }
+
+ RNA_parameter_list_free(&parms);
+ }
+ }
+
+ /* hide dot-datablocks, but only if filter does not force it visible */
+ if(!filter_yes && U.uiflag & USER_HIDE_DOT)
if ((id->name[2]=='.') && (str[0] != '.'))
continue;
if(BLI_strcasestr(id->name+2, str)) {
iconid= ui_id_icon_get((bContext*)C, id, 1);
-
+
if(!uiSearchItemAdd(items, id->name+2, id, iconid))
break;
}
@@ -340,7 +381,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
-static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop)
+static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, int flag, char *newop, char *openop, char *unlinkop, char *filterop)
{
uiBut *but;
uiBlock *block;
@@ -480,7 +521,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
uiBlockEndAlign(block);
}
-static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int flag, int prv_rows, int prv_cols)
+static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char* filterop, int flag, int prv_rows, int prv_cols)
{
TemplateID *template;
PropertyRNA *prop;
@@ -498,7 +539,12 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char
template->prop= prop;
template->prv_rows = prv_rows;
template->prv_cols = prv_cols;
-
+
+ if (filterop)
+ BLI_strncpy(template->filterop, filterop, sizeof(template->filterop));
+ else
+ template->filterop[0] = 0;
+
if(newop)
flag |= UI_ID_ADD_NEW;
if(openop)
@@ -512,26 +558,25 @@ static void ui_template_id(uiLayout *layout, bContext *C, PointerRNA *ptr, char
*/
if(template->idlb) {
uiLayoutRow(layout, 1);
- template_ID(C, layout, template, type, flag, newop, openop, unlinkop);
+ template_ID(C, layout, template, type, flag, newop, openop, unlinkop, filterop);
}
MEM_freeN(template);
-
}
-void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
+void uiTemplateID(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char *filterop)
{
- ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE, 0, 0);
+ ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, filterop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE, 0, 0);
}
-void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop)
+void uiTemplateIDBrowse(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char *filterop)
{
- ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
+ ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, filterop, UI_ID_BROWSE|UI_ID_RENAME, 0, 0);
}
-void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, int rows, int cols)
+void uiTemplateIDPreview(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propname, char *newop, char *openop, char *unlinkop, char *filterop, int rows, int cols)
{
- ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
+ ui_template_id(layout, C, ptr, propname, newop, openop, unlinkop, filterop, UI_ID_BROWSE|UI_ID_RENAME|UI_ID_DELETE|UI_ID_PREVIEWS, rows, cols);
}
/************************ ID Chooser Template ***************************/
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index cf47feb312b..bea8d3bd1f6 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1463,7 +1463,7 @@ void init_userdef_do_versions(void)
SETCOL(btheme->tv3d.lastsel_point, 0xff, 0xff, 0xff, 255);
}
}
- if (G.main->versionfile <= 252 || (G.main->versionfile == 252 && G.main->subversionfile < 5)) {
+ if (G.main->versionfile < 252 || (G.main->versionfile == 252 && G.main->subversionfile < 5)) {
bTheme *btheme;
/* interface_widgets.c */
@@ -1521,7 +1521,14 @@ void init_userdef_do_versions(void)
/* this timer uses U */
// XXX reset_autosave();
-}
+ /* GSOC Sculpt 2010 - Sanity check on Sculpt/Paint settings */
+ if (U.sculpt_paint_unified_alpha == 0)
+ U.sculpt_paint_unified_alpha = 0.5f;
+ if (U.sculpt_paint_unified_unprojected_radius == 0)
+ U.sculpt_paint_unified_unprojected_radius = 0.125f;
+ if (U.sculpt_paint_unified_size == 0)
+ U.sculpt_paint_unified_size = 35;
+}
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index 472ba361059..3d9a5144c93 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -3,6 +3,8 @@ Import ('env')
sources = env.Glob('*.c')
+defs = []
+
incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
@@ -12,7 +14,11 @@ if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
+if env['OURPLATFORM'] == 'linuxcross':
+ if env['WITH_BF_OPENMP']:
+ incs += ' ' + env['BF_OPENMP_INC']
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
- incs += ' ' + env['BF_PTHREADS_INC']
+ incs += ' ' + env['BF_PTHREADS_INC']
-env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), [], libtype=['core'], priority=[40] )
+env.BlenderLib ( 'bf_editors_sculpt_paint', sources, Split(incs), defines=defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 41908bbe388..45c0396855d 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -641,8 +641,8 @@ static int project_paint_PickColor(const ProjPaintState *ps, float pt[2], float
}
}
else {
- xi = (uv[0]*ibuf->x) + 0.5f;
- yi = (uv[1]*ibuf->y) + 0.5f;
+ xi = (int)((uv[0]*ibuf->x) + 0.5f);
+ yi = (int)((uv[1]*ibuf->y) + 0.5f);
//if (xi<0 || xi>=ibuf->x || yi<0 || yi>=ibuf->y) return 0;
@@ -1053,15 +1053,15 @@ static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const fl
* This is incorrect. Its already given radians but without it wont work.
* need to look into a fix - campbell */
if (is_quad) {
- a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * (M_PI/180.0f));
- a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * (M_PI/180.0f));
- a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * (M_PI/180.0f));
- a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * (M_PI/180.0f));
+ a1 = shell_angle_to_dist(angle_normalized_v2v2(dir4, dir1) * ((float)M_PI/180.0f));
+ a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f));
+ a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f));
+ a4 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir4) * ((float)M_PI/180.0f));
}
else {
- a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * (M_PI/180.0f));
- a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * (M_PI/180.0f));
- a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * (M_PI/180.0f));
+ a1 = shell_angle_to_dist(angle_normalized_v2v2(dir3, dir1) * ((float)M_PI/180.0f));
+ a2 = shell_angle_to_dist(angle_normalized_v2v2(dir1, dir2) * ((float)M_PI/180.0f));
+ a3 = shell_angle_to_dist(angle_normalized_v2v2(dir2, dir3) * ((float)M_PI/180.0f));
}
if (is_quad) {
@@ -1197,7 +1197,7 @@ static void screen_px_from_persp(
w[2] *= wtot_inv;
}
else {
- w[0] = w[1] = w[2] = 1.0/3.0; /* dummy values for zero area face */
+ w[0] = w[1] = w[2] = 1.0f/3.0f; /* dummy values for zero area face */
}
/* done re-weighting */
@@ -2513,11 +2513,11 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
w[0]=w[1]=w[2]= 0.0;
if (side) {
w[fidx1?fidx1-1:0] = fac;
- w[fidx2?fidx2-1:0] = 1.0-fac;
+ w[fidx2?fidx2-1:0] = 1.0f-fac;
}
else {
w[fidx1] = fac;
- w[fidx2] = 1.0-fac;
+ w[fidx2] = 1.0f-fac;
}
#endif
}
@@ -2571,11 +2571,12 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
static void project_paint_bucket_bounds(const ProjPaintState *ps, const float min[2], const float max[2], int bucketMin[2], int bucketMax[2])
{
/* divide by bucketWidth & bucketHeight so the bounds are offset in bucket grid units */
- bucketMin[0] = (int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f; /* these offsets of 0.5 and 1.5 seem odd but they are correct */
- bucketMin[1] = (int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f;
+ /* XXX: the offset of 0.5 is always truncated to zero and the offset of 1.5f is always truncated to 1, is this really correct?? - jwilkins */
+ bucketMin[0] = (int)((int)(((float)(min[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 0.5f); /* these offsets of 0.5 and 1.5 seem odd but they are correct */
+ bucketMin[1] = (int)((int)(((float)(min[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 0.5f);
- bucketMax[0] = (int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f;
- bucketMax[1] = (int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f;
+ bucketMax[0] = (int)((int)(((float)(max[0] - ps->screenMin[0]) / ps->screen_width) * ps->buckets_x) + 1.5f);
+ bucketMax[1] = (int)((int)(((float)(max[1] - ps->screenMin[1]) / ps->screen_height) * ps->buckets_y) + 1.5f);
/* incase the rect is outside the mesh 2d bounds */
CLAMP(bucketMin[0], 0, ps->buckets_x);
@@ -3029,19 +3030,19 @@ static void project_paint_begin(ProjPaintState *ps)
if(ps->source==PROJ_SRC_VIEW) {
#ifdef PROJ_DEBUG_WINCLIP
- CLAMP(ps->screenMin[0], -ps->brush->size, ps->winx + ps->brush->size);
- CLAMP(ps->screenMax[0], -ps->brush->size, ps->winx + ps->brush->size);
+ CLAMP(ps->screenMin[0], (float)(-ps->brush->size), (float)(ps->winx + ps->brush->size));
+ CLAMP(ps->screenMax[0], (float)(-ps->brush->size), (float)(ps->winx + ps->brush->size));
- CLAMP(ps->screenMin[1], -ps->brush->size, ps->winy + ps->brush->size);
- CLAMP(ps->screenMax[1], -ps->brush->size, ps->winy + ps->brush->size);
+ CLAMP(ps->screenMin[1], (float)(-ps->brush->size), (float)(ps->winy + ps->brush->size));
+ CLAMP(ps->screenMax[1], (float)(-ps->brush->size), (float)(ps->winy + ps->brush->size));
#endif
}
else { /* reprojection, use bounds */
ps->screenMin[0]= 0;
- ps->screenMax[0]= ps->winx;
+ ps->screenMax[0]= (float)(ps->winx);
ps->screenMin[1]= 0;
- ps->screenMax[1]= ps->winy;
+ ps->screenMax[1]= (float)(ps->winy);
}
/* only for convenience */
@@ -3497,7 +3498,7 @@ static int project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf
project_bucket_bounds(ps, ps->context_bucket_x, ps->context_bucket_y, bucket_bounds);
if ( (ps->source != PROJ_SRC_VIEW) ||
- project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, ps->brush->size * ps->brush->size, bucket_bounds)
+ project_bucket_isect_circle(ps->context_bucket_x, ps->context_bucket_y, mval, (float)(ps->brush->size * ps->brush->size), bucket_bounds)
) {
*bucket_index = ps->context_bucket_x + (ps->context_bucket_y * ps->buckets_x);
ps->context_bucket_x++;
@@ -3545,7 +3546,7 @@ static void blend_color_mix(unsigned char *cp, const unsigned char *cp1, const u
static void blend_color_mix_float(float *cp, const float *cp1, const float *cp2, const float fac)
{
- const float mfac= 1.0-fac;
+ const float mfac= 1.0f-fac;
cp[0]= mfac*cp1[0] + fac*cp2[0];
cp[1]= mfac*cp1[1] + fac*cp2[1];
cp[2]= mfac*cp1[2] + fac*cp2[2];
@@ -3712,7 +3713,7 @@ static void *do_projectpaint_thread(void *ph_v)
}
/* avoid a square root with every dist comparison */
- brush_size_sqared = ps->brush->size * ps->brush->size;
+ brush_size_sqared = (float)(ps->brush->size * ps->brush->size);
/* printf("brush bounds %d %d %d %d\n", bucketMin[0], bucketMin[1], bucketMax[0], bucketMax[1]); */
@@ -3771,7 +3772,7 @@ static void *do_projectpaint_thread(void *ph_v)
falloff = 1.0f - falloff;
falloff = 1.0f - (falloff * falloff);
- mask_short = projPixel->mask * (ps->brush->alpha * falloff);
+ mask_short = (unsigned short)(projPixel->mask * (ps->brush->alpha * falloff));
if (mask_short > projPixel->mask_max) {
mask = ((float)mask_short)/65535.0f;
projPixel->mask_max = mask_short;
@@ -3932,8 +3933,8 @@ static int project_paint_sub_stroke(ProjPaintState *ps, BrushPainter *painter, i
/* Use mouse coords as floats for projection painting */
float pos[2];
- pos[0] = mval_i[0];
- pos[1] = mval_i[1];
+ pos[0] = (float)(mval_i[0]);
+ pos[1] = (float)(mval_i[1]);
// we may want to use this later
// brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0);
@@ -4057,7 +4058,8 @@ static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo
{
float inrgb[3];
- if ((x >= ibuf->x) || (y >= ibuf->y)) {
+ // XXX: signed unsigned mismatch
+ if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
if (torus) imapaint_ibuf_get_set_rgb(ibuf, x, y, 1, 0, inrgb);
else return 0;
}
@@ -4611,8 +4613,8 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps)
ps->normal_angle_inner= ps->normal_angle= settings->imapaint.normal_angle;
}
- ps->normal_angle_inner *= M_PI_2 / 90;
- ps->normal_angle *= M_PI_2 / 90;
+ ps->normal_angle_inner *= (float)(M_PI_2 / 90);
+ ps->normal_angle *= (float)(M_PI_2 / 90);
ps->normal_angle_range = ps->normal_angle - ps->normal_angle_inner;
if(ps->normal_angle_range <= 0.0f)
@@ -4711,8 +4713,8 @@ static void paint_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
int mouse[2], redraw;
RNA_float_get_array(itemptr, "mouse", mousef);
- mouse[0] = mousef[0];
- mouse[1] = mousef[1];
+ mouse[0] = (int)(mousef[0]);
+ mouse[1] = (int)(mousef[1]);
time= RNA_float_get(itemptr, "time");
pressure= RNA_float_get(itemptr, "pressure");
@@ -4832,8 +4834,8 @@ static void paint_apply_event(bContext *C, wmOperator *op, wmEvent *event)
/* fill in stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
- mousef[0] = mouse[0];
- mousef[1] = mouse[1];
+ mousef[0] = (float)(mouse[0]);
+ mousef[1] = (float)(mouse[1]);
RNA_float_set_array(&itemptr, "mouse", mousef);
RNA_float_set(&itemptr, "time", (float)(time - pop->starttime));
RNA_float_set(&itemptr, "pressure", pressure);
@@ -4950,7 +4952,7 @@ static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
glColor4ub(255, 255, 255, 128);
glEnable( GL_LINE_SMOOTH );
glEnable(GL_BLEND);
- glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size*0.5f, 40);
+ glutil_draw_lined_arc(0, (float)(M_PI*2.0), brush->size*0.5f, 40);
glDisable(GL_BLEND);
glDisable( GL_LINE_SMOOTH );
@@ -4977,7 +4979,7 @@ static int paint_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *eve
ToolSettings *ts = CTX_data_scene(C)->toolsettings;
get_imapaint_zoom(C, &zoom, &zoom);
toggle_paint_cursor(C, !ts->imapaint.paintcursor);
- brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5 * zoom);
+ brush_radial_control_invoke(op, paint_brush(&ts->imapaint.paint), 0.5f * zoom);
return WM_radial_control_invoke(C, op, event);
}
@@ -4997,7 +4999,7 @@ static int paint_radial_control_exec(bContext *C, wmOperator *op)
int ret;
char str[256];
get_imapaint_zoom(C, &zoom, &zoom);
- ret = brush_radial_control_exec(op, brush, 2.0 / zoom);
+ ret = brush_radial_control_exec(op, brush, 2.0f / zoom);
WM_radial_control_string(op, str, 256);
WM_event_add_notifier(C, NC_BRUSH|NA_EDITED, brush);
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index b25eec70311..0ae7c7fac19 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -110,6 +110,13 @@ void PAINT_OT_face_select_all(struct wmOperatorType *ot);
int facemask_paint_poll(struct bContext *C);
+/* stroke operator */
+typedef enum wmBrushStrokeMode {
+ WM_BRUSHSTROKE_NORMAL,
+ WM_BRUSHSTROKE_INVERT,
+ WM_BRUSHSTROKE_SMOOTH,
+} wmBrushStrokeMode;
+
/* paint_undo.c */
typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
typedef void (*UndoFreeCb)(struct ListBase *lb);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 5470ac83370..5d52b0a3272 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -39,28 +39,25 @@
#include "sculpt_intern.h"
#include <string.h>
+//#include <stdio.h>
/* Brush operators */
static int brush_add_exec(bContext *C, wmOperator *op)
{
/*int type = RNA_enum_get(op->ptr, "type");*/
- Brush *br = NULL;
+ Paint *paint = paint_get_active(CTX_data_scene(C));
+ Brush *br = paint_brush(paint);
- br = add_brush("Brush");
+ if (br)
+ br = copy_brush(br);
+ else
+ br = add_brush("Brush");
- if(br)
- paint_brush_set(paint_get_active(CTX_data_scene(C)), br);
+ paint_brush_set(paint_get_active(CTX_data_scene(C)), br);
return OPERATOR_FINISHED;
}
-static EnumPropertyItem brush_type_items[] = {
- {OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt", ""},
- {OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""},
- {OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
- {OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
- {0, NULL, 0, NULL, NULL}};
-
void BRUSH_OT_add(wmOperatorType *ot)
{
/* identifiers */
@@ -72,9 +69,43 @@ void BRUSH_OT_add(wmOperatorType *ot)
ot->exec= brush_add_exec;
/* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ ot->flag= OPTYPE_UNDO;
+}
+
+
+static int brush_scale_size_exec(bContext *C, wmOperator *op)
+{
+ /*int type = RNA_enum_get(op->ptr, "type");*/
+ Paint *paint = paint_get_active(CTX_data_scene(C));
+ Brush *br = paint_brush(paint);
+ float factor = RNA_float_get(op->ptr, "scalar");
+
+ if (br) {
+ if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) {
+ U.sculpt_paint_unified_size *= factor;
+ }
+ else {
+ br->size *= factor;
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void BRUSH_OT_scale_size(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Scale Sculpt/Paint Brush Size";
+ ot->description= "Change brush size by a scalar";
+ ot->idname= "BRUSH_OT_scale_size";
+
+ /* api callbacks */
+ ot->exec= brush_scale_size_exec;
+
+ /* flags */
+ ot->flag= OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "type", brush_type_items, OB_MODE_VERTEX_PAINT, "Type", "Which paint mode to create the brush for.");
+ RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2);
}
static int vertex_color_set_exec(bContext *C, wmOperator *op)
@@ -108,8 +139,10 @@ void ED_operatortypes_paint(void)
{
/* brush */
WM_operatortype_append(BRUSH_OT_add);
+ WM_operatortype_append(BRUSH_OT_scale_size);
WM_operatortype_append(BRUSH_OT_curve_preset);
+
/* image */
WM_operatortype_append(PAINT_OT_texture_paint_toggle);
WM_operatortype_append(PAINT_OT_texture_paint_radial_control);
@@ -141,6 +174,7 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_face_select_all);
}
+
static void ed_keymap_paint_brush_switch(wmKeyMap *keymap, const char *path)
{
wmKeyMapItem *kmi;
@@ -180,15 +214,13 @@ static void ed_keymap_paint_brush_switch(wmKeyMap *keymap, const char *path)
static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *path)
{
wmKeyMapItem *kmi;
-
- kmi= WM_keymap_add_item(keymap, "WM_OT_context_scale_int", LEFTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", path);
- RNA_float_set(kmi->ptr, "value", 0.9);
-
- kmi= WM_keymap_add_item(keymap, "WM_OT_context_scale_int", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", path);
- RNA_float_set(kmi->ptr, "value", 10.0/9.0); // 1.1111....
-}
+
+ kmi= WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", LEFTBRACKETKEY, KM_PRESS, 0, 0);
+ RNA_float_set(kmi->ptr, "scalar", 0.9);
+
+ kmi= WM_keymap_add_item(keymap, "BRUSH_OT_scale_size", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
+ RNA_float_set(kmi->ptr, "scalar", 10.0/9.0); // 1.1111....
+}
void ED_keymap_paint(wmKeyConfig *keyconf)
{
@@ -200,12 +232,15 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
keymap= WM_keymap_find(keyconf, "Sculpt", 0, 0);
keymap->poll= sculpt_poll;
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH);
- RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_RADIALCONTROL_ANGLE);
+ RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_RADIALCONTROL_ANGLE);
- WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", WM_BRUSHSTROKE_NORMAL);
+ RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_BRUSHSTROKE_INVERT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_BRUSHSTROKE_SMOOTH);
+
+ //stroke_mode_modal_keymap(keyconf);
for(i=0; i<=5; i++)
RNA_int_set(WM_keymap_add_item(keymap, "OBJECT_OT_subdivision_set", ZEROKEY+i, KM_PRESS, KM_CTRL, 0)->ptr, "level", i);
@@ -221,7 +256,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_paint_brush_switch(keymap, "tool_settings.sculpt.active_brush_index");
ed_keymap_paint_brush_size(keymap, "tool_settings.sculpt.brush.size");
-
+
+ /* */
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", AKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.use_anchor");
@@ -254,11 +290,10 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", LKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.active_brush_name");
RNA_string_set(kmi->ptr, "value", "Layer");
-
+
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", TKEY, KM_PRESS, KM_SHIFT, 0); // was just T in 2.4x
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.active_brush_name");
RNA_string_set(kmi->ptr, "value", "Flatten");
-
/* Vertex Paint mode */
keymap= WM_keymap_find(keyconf, "Vertex Paint", 0, 0);
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 441464c5743..e373a254c3e 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -20,7 +20,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Jason Wilkins, Tom Musgrove.
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -35,6 +35,7 @@
#include "BKE_context.h"
#include "BKE_paint.h"
+#include "BKE_brush.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -49,6 +50,9 @@
#include "ED_view3d.h"
#include "paint_intern.h"
+#include "sculpt_intern.h" // XXX, for expedience in getting this working, refactor later (or this just shows that this needs unification)
+
+#include "BKE_image.h"
#include <float.h>
#include <math.h>
@@ -96,54 +100,748 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
glDisable(GL_LINE_SMOOTH);
}
-static void paint_draw_cursor(bContext *C, int x, int y, void *customdata)
+#if 0
+
+// grid texture for testing
+
+#define GRID_WIDTH 8
+#define GRID_LENGTH 8
+
+#define W (0xFFFFFFFF)
+#define G (0x00888888)
+#define E (0xE1E1E1E1)
+#define C (0xC3C3C3C3)
+#define O (0xB4B4B4B4)
+#define Q (0xA9A9A9A9)
+
+static unsigned grid_texture0[256] =
+{
+ W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,G,G,G,G,G,G,G,G,G,G,G,G,G,G,W,
+ W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,W,
+};
+
+static unsigned grid_texture1[64] =
{
- Paint *paint = paint_get_active(CTX_data_scene(C));
- Brush *brush = paint_brush(paint);
+ C,C,C,C,C,C,C,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,G,G,G,G,G,G,C,
+ C,C,C,C,C,C,C,C,
+};
+
+static unsigned grid_texture2[16] =
+{
+ O,O,O,O,
+ O,G,G,O,
+ O,G,G,O,
+ O,O,O,O,
+};
- if(!(paint->flags & PAINT_SHOW_BRUSH))
- return;
+static unsigned grid_texture3[4] =
+{
+ Q,Q,
+ Q,Q,
+};
- glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
+static unsigned grid_texture4[1] =
+{
+ Q,
+};
- glTranslatef((float)x, (float)y, 0.0f);
- glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
- glTranslatef((float)-x, (float)-y, 0.0f);
+#undef W
+#undef G
+#undef E
+#undef C
+#undef O
+#undef Q
- glDisable(GL_BLEND);
- glDisable(GL_LINE_SMOOTH);
+static void load_grid()
+{
+ static GLuint overlay_texture;
+
+ if (!overlay_texture) {
+ //GLfloat largest_supported_anisotropy;
+
+ glGenTextures(1, &overlay_texture);
+ glBindTexture(GL_TEXTURE_2D, overlay_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture0);
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGB, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture1);
+ glTexImage2D(GL_TEXTURE_2D, 2, GL_RGB, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture2);
+ glTexImage2D(GL_TEXTURE_2D, 3, GL_RGB, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture3);
+ glTexImage2D(GL_TEXTURE_2D, 4, GL_RGB, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, grid_texture4);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ //glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_supported_anisotropy);
+ //glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_supported_anisotropy);
+ }
+}
+
+#endif
+
+extern float get_tex_pixel(Brush* br, float u, float v);
+
+typedef struct Snapshot {
+ float size[3];
+ float ofs[3];
+ float rot;
+ int brush_size;
+ int winx;
+ int winy;
+ int brush_map_mode;
+ int curve_changed_timestamp;
+} Snapshot;
+
+static int same_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
+{
+ MTex* mtex = &brush->mtex;
+
+ return
+ (mtex->tex &&
+ mtex->ofs[0] == snap->ofs[0] &&
+ mtex->ofs[1] == snap->ofs[1] &&
+ mtex->ofs[2] == snap->ofs[2] &&
+ mtex->size[0] == snap->size[0] &&
+ mtex->size[1] == snap->size[1] &&
+ mtex->size[2] == snap->size[2] &&
+ mtex->rot == snap->rot) &&
+ ((mtex->brush_map_mode == MTEX_MAP_MODE_FIXED && sculpt_get_brush_size(brush) <= snap->brush_size) || (sculpt_get_brush_size(brush) == snap->brush_size)) && // make brush smaller shouldn't cause a resample
+ mtex->brush_map_mode == snap->brush_map_mode &&
+ vc->ar->winx == snap->winx &&
+ vc->ar->winy == snap->winy;
+}
+
+static void make_snap(Snapshot* snap, Brush* brush, ViewContext* vc)
+{
+ if (brush->mtex.tex) {
+ snap->brush_map_mode = brush->mtex.brush_map_mode;
+ copy_v3_v3(snap->ofs, brush->mtex.ofs);
+ copy_v3_v3(snap->size, brush->mtex.size);
+ snap->rot = brush->mtex.rot;
+ }
+ else {
+ snap->brush_map_mode = -1;
+ snap->ofs[0]= snap->ofs[0]= snap->ofs[0]= -1;
+ snap->size[0]= snap->size[0]= snap->size[0]= -1;
+ snap->rot = -1;
+ }
+
+ snap->brush_size = sculpt_get_brush_size(brush);
+ snap->winx = vc->ar->winx;
+ snap->winy = vc->ar->winy;
+}
+
+int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
+{
+ static GLuint overlay_texture = 0;
+ static int init = 0;
+ static int tex_changed_timestamp = -1;
+ static int curve_changed_timestamp = -1;
+ static Snapshot snap;
+ static int old_size = -1;
+
+ GLubyte* buffer = 0;
+
+ int size;
+ int j;
+ int refresh;
+
+ if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED && !br->mtex.tex) return 0;
+
+ refresh =
+ !overlay_texture ||
+ (br->mtex.tex &&
+ (!br->mtex.tex->preview ||
+ br->mtex.tex->preview->changed_timestamp[0] != tex_changed_timestamp)) ||
+ !br->curve ||
+ br->curve->changed_timestamp != curve_changed_timestamp ||
+ !same_snap(&snap, br, vc);
+
+ if (refresh) {
+ if (br->mtex.tex && br->mtex.tex->preview)
+ tex_changed_timestamp = br->mtex.tex->preview->changed_timestamp[0];
+
+ if (br->curve)
+ curve_changed_timestamp = br->curve->changed_timestamp;
+
+ make_snap(&snap, br, vc);
+
+ if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ int s = sculpt_get_brush_size(br);
+ int r = 1;
+
+ for (s >>= 1; s > 0; s >>= 1)
+ r++;
+
+ size = (1<<r);
+
+ if (size < 256)
+ size = 256;
+
+ if (size < old_size)
+ size = old_size;
+ }
+ else
+ size = 512;
+
+ if (old_size != size) {
+ if (overlay_texture) {
+ glDeleteTextures(1, &overlay_texture);
+ overlay_texture = 0;
+ }
+
+ init = 0;
+
+ old_size = size;
+ }
+
+ buffer = MEM_mallocN(sizeof(GLubyte)*size*size, "load_tex");
+
+ #pragma omp parallel for schedule(static) if (sd->flags & SCULPT_USE_OPENMP)
+ for (j= 0; j < size; j++) {
+ int i;
+ float y;
+ float len;
+
+ for (i= 0; i < size; i++) {
+
+ // largely duplicated from tex_strength
+
+ const float rotation = -br->mtex.rot;
+ float diameter = sculpt_get_brush_size(br);
+ int index = j*size + i;
+ float x;
+ float avg;
+
+ x = (float)i/size;
+ y = (float)j/size;
+
+ x -= 0.5f;
+ y -= 0.5f;
+
+ if (br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) {
+ x *= vc->ar->winx / diameter;
+ y *= vc->ar->winy / diameter;
+ }
+ else {
+ x *= 2;
+ y *= 2;
+ }
+
+ len = sqrtf(x*x + y*y);
+
+ if ((br->mtex.brush_map_mode == MTEX_MAP_MODE_TILED) || len <= 1) {
+ /* it is probably worth optimizing for those cases where
+ the texture is not rotated by skipping the calls to
+ atan2, sqrtf, sin, and cos. */
+ if (br->mtex.tex && (rotation > 0.001 || rotation < -0.001)) {
+ const float angle = atan2(y, x) + rotation;
+
+ x = len * cos(angle);
+ y = len * sin(angle);
+ }
+
+ x *= br->mtex.size[0];
+ y *= br->mtex.size[1];
+
+ x += br->mtex.ofs[0];
+ y += br->mtex.ofs[1];
+
+ avg = br->mtex.tex ? get_tex_pixel(br, x, y) : 1;
+
+ avg += br->texture_sample_bias;
+
+ if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED)
+ avg *= brush_curve_strength(br, len, 1); /* Falloff curve */
+
+ buffer[index] = (GLubyte)(255*avg);
+ }
+ else {
+ buffer[index] = 0;
+ }
+ }
+ }
+
+ if (!overlay_texture)
+ glGenTextures(1, &overlay_texture);
+ }
+ else {
+ size= old_size;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, overlay_texture);
+
+ if (refresh) {
+ if (!init) {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, size, size, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
+ init = 1;
+ }
+ else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_ALPHA, GL_UNSIGNED_BYTE, buffer);
+ }
+
+ if (buffer)
+ MEM_freeN(buffer);
+ }
+
+ glEnable(GL_TEXTURE_2D);
+
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ if (br->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ }
+
+ return 1;
+}
+
+/* Convert a point in model coordinates to 2D screen coordinates. */
+// XXX duplicated from sculpt.c, deal with this later.
+static void projectf(bglMats *mats, const float v[3], float p[2])
+{
+ double ux, uy, uz;
+
+ gluProject(v[0],v[1],v[2], mats->modelview, mats->projection,
+ (GLint *)mats->viewport, &ux, &uy, &uz);
+ p[0]= ux;
+ p[1]= uy;
+}
+
+static int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats)
+{
+ float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
+
+ viewvector(rv3d, location, view);
+
+ // create a vector that is not orthogonal to view
+
+ if (fabsf(view[0]) < 0.1) {
+ nonortho[0] = view[0] + 1;
+ nonortho[1] = view[1];
+ nonortho[2] = view[2];
+ }
+ else if (fabsf(view[1]) < 0.1) {
+ nonortho[0] = view[0];
+ nonortho[1] = view[1] + 1;
+ nonortho[2] = view[2];
+ }
+ else {
+ nonortho[0] = view[0];
+ nonortho[1] = view[1];
+ nonortho[2] = view[2] + 1;
+ }
+
+ // get a vector in the plane of the view
+ cross_v3_v3v3(ortho, nonortho, view);
+ normalize_v3(ortho);
+
+ // make a point on the surface of the brush tagent to the view
+ mul_v3_fl(ortho, radius);
+ add_v3_v3v3(offset, location, ortho);
+
+ // project the center of the brush, and the tagent point to the view onto the screen
+ projectf(mats, location, p1);
+ projectf(mats, offset, p2);
+
+ // the distance between these points is the size of the projected brush in pixels
+ return len_v2v2(p1, p2);
+}
+
+int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, float location[3], float modelview[16], float projection[16], int viewport[4])
+{
+ struct PaintStroke *stroke;
+ float window[2];
+ int hit;
+
+ stroke = paint_stroke_new(C, NULL, NULL, NULL, NULL);
+
+ window[0] = x + stroke->vc.ar->winrct.xmin;
+ window[1] = y + stroke->vc.ar->winrct.ymin;
+
+ memcpy(modelview, stroke->vc.rv3d->viewmat, sizeof(float[16]));
+ memcpy(projection, stroke->vc.rv3d->winmat, sizeof(float[16]));
+ memcpy(viewport, stroke->mats.viewport, sizeof(int[4]));
+
+ if (stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && sculpt_stroke_get_location(C, stroke, location, window)) {
+ *pixel_radius = project_brush_radius(stroke->vc.rv3d, sculpt_get_brush_unprojected_radius(stroke->brush), location, &stroke->mats);
+
+ if (*pixel_radius == 0)
+ *pixel_radius = sculpt_get_brush_size(stroke->brush);
+
+ mul_m4_v3(stroke->vc.obact->sculpt->ob->obmat, location);
+
+ hit = 1;
+ }
+ else {
+ Sculpt* sd = CTX_data_tool_settings(C)->sculpt;
+ Brush* brush = paint_brush(&sd->paint);
+
+ *pixel_radius = sculpt_get_brush_size(brush);
+ hit = 0;
+ }
+
+ paint_stroke_free(stroke);
+
+ return hit;
+}
+
+// XXX duplicated from sculpt.c
+float unproject_brush_radius(Object *ob, ViewContext *vc, float center[3], float offset)
+{
+ float delta[3], scale, loc[3];
+
+ mul_v3_m4v3(loc, ob->obmat, center);
+
+ initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
+ window_to_3d_delta(vc->ar, delta, offset, 0);
+
+ scale= fabsf(mat4_to_scale(ob->obmat));
+ scale= (scale == 0.0f)? 1.0f: scale;
+
+ return len_v3(delta)/scale;
+}
+
+// XXX paint cursor now does a lot of the same work that is needed during a sculpt stroke
+// problem: all this stuff was not intended to be used at this point, so things feel a
+// bit hacked. I've put lots of stuff in Brush that probably better goes in Paint
+// Functions should be refactored so that they can be used between sculpt.c and
+// paint_stroke.c clearly and optimally and the lines of communication between the
+// two modules should be more clearly defined.
+static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
+{
+ ViewContext vc;
+
+ (void)unused;
+
+ view3d_set_viewcontext(C, &vc);
+
+ if (vc.obact->sculpt) {
+ Paint *paint = paint_get_active(CTX_data_scene(C));
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Brush *brush = paint_brush(paint);
+
+ int pixel_radius, viewport[4];
+ float location[3], modelview[16], projection[16];
+
+ int hit;
+
+ int flip;
+ int sign;
+
+ float* col;
+ float alpha;
+
+ float visual_strength = sculpt_get_brush_alpha(brush)*sculpt_get_brush_alpha(brush);
+
+ const float min_alpha = 0.20f;
+ const float max_alpha = 0.80f;
+
+ {
+ const float u = 0.5f;
+ const float v = 1 - u;
+ const float r = 20;
+
+ const float dx = sd->last_x - x;
+ const float dy = sd->last_y - y;
+
+ if (dx*dx + dy*dy >= r*r) {
+ sd->last_angle = atan2(dx, dy);
+
+ sd->last_x = u*sd->last_x + v*x;
+ sd->last_y = u*sd->last_y + v*y;
+ }
+ }
+
+ if(!sculpt_get_lock_brush_size(brush) && !(paint->flags & PAINT_SHOW_BRUSH))
+ return;
+
+ hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location, modelview, projection, viewport);
+
+ if (sculpt_get_lock_brush_size(brush))
+ sculpt_set_brush_size(brush, pixel_radius);
+
+ // XXX: no way currently to know state of pen flip or invert key modifier without starting a stroke
+ flip = 1;
+
+ sign = flip * ((brush->flag & BRUSH_DIR_IN)? -1 : 1);
+
+ if (sign < 0 && ELEM4(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH))
+ col = brush->sub_col;
+ else
+ col = brush->add_col;
+
+ alpha = (paint->flags & PAINT_SHOW_BRUSH_ON_SURFACE) ? min_alpha + (visual_strength*(max_alpha-min_alpha)) : 0.50f;
+
+ if (ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_FIXED, MTEX_MAP_MODE_TILED) && brush->flag & BRUSH_TEXTURE_OVERLAY) {
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ if (load_tex(sd, brush, &vc)) {
+ glEnable(GL_BLEND);
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_ALWAYS);
+
+ glMatrixMode(GL_TEXTURE);
+ glPushMatrix();
+ glLoadIdentity();
+
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ glTranslatef(0.5f, 0.5f, 0);
+
+ if (brush->flag & BRUSH_RAKE) {
+ glRotatef(sd->last_angle*(float)(180.0/M_PI), 0, 0, 1);
+ }
+ else {
+ glRotatef(sd->special_rotation*(float)(180.0/M_PI), 0, 0, 1);
+ }
+
+ glTranslatef(-0.5f, -0.5f, 0);
+
+ if (sd->draw_pressure && (brush->flag & BRUSH_SIZE_PRESSURE)) {
+ glTranslatef(0.5f, 0.5f, 0);
+ glScalef(1.0f/sd->pressure_value, 1.0f/sd->pressure_value, 1);
+ glTranslatef(-0.5f, -0.5f, 0);
+ }
+ }
+
+ glColor4f(
+ U.sculpt_paint_overlay_col[0],
+ U.sculpt_paint_overlay_col[1],
+ U.sculpt_paint_overlay_col[2],
+ brush->texture_overlay_alpha / 100.0f);
+
+ glBegin(GL_QUADS);
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ if (sd->draw_anchored) {
+ glTexCoord2f(0, 0);
+ glVertex2f(sd->anchored_initial_mouse[0]-sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]-sd->anchored_size - vc.ar->winrct.ymin);
+
+ glTexCoord2f(1, 0);
+ glVertex2f(sd->anchored_initial_mouse[0]+sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]-sd->anchored_size - vc.ar->winrct.ymin);
+
+ glTexCoord2f(1, 1);
+ glVertex2f(sd->anchored_initial_mouse[0]+sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]+sd->anchored_size - vc.ar->winrct.ymin);
+
+ glTexCoord2f(0, 1);
+ glVertex2f(sd->anchored_initial_mouse[0]-sd->anchored_size - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1]+sd->anchored_size - vc.ar->winrct.ymin);
+ }
+ else {
+ glTexCoord2f(0, 0);
+ glVertex2f((float)x-sculpt_get_brush_size(brush), (float)y-sculpt_get_brush_size(brush));
+
+ glTexCoord2f(1, 0);
+ glVertex2f((float)x+sculpt_get_brush_size(brush), (float)y-sculpt_get_brush_size(brush));
+
+ glTexCoord2f(1, 1);
+ glVertex2f((float)x+sculpt_get_brush_size(brush), (float)y+sculpt_get_brush_size(brush));
+
+ glTexCoord2f(0, 1);
+ glVertex2f((float)x-sculpt_get_brush_size(brush), (float)y+sculpt_get_brush_size(brush));
+ }
+ }
+ else {
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 0);
+
+ glTexCoord2f(1, 0);
+ glVertex2f(viewport[2], 0);
+
+ glTexCoord2f(1, 1);
+ glVertex2f(viewport[2], viewport[3]);
+
+ glTexCoord2f(0, 1);
+ glVertex2f(0, viewport[3]);
+ }
+ glEnd();
+
+ glPopMatrix();
+ }
+
+ glPopAttrib();
+ }
+
+ if (hit) {
+ float unprojected_radius;
+
+ // XXX duplicated from brush_strength & paint_stroke_add_step, refactor later
+ //wmEvent* event = CTX_wm_window(C)->eventstate;
+
+ if (sd->draw_pressure && (brush->flag & BRUSH_ALPHA_PRESSURE))
+ visual_strength *= sd->pressure_value;
+
+ // don't show effect of strength past the soft limit
+ if (visual_strength > 1) visual_strength = 1;
+
+ if (sd->draw_anchored) {
+ unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, sd->anchored_size);
+ }
+ else {
+ if (brush->flag & BRUSH_ANCHORED)
+ unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, 8);
+ else
+ unprojected_radius = unproject_brush_radius(CTX_data_active_object(C), &vc, location, sculpt_get_brush_size(brush));
+ }
+
+ if (sd->draw_pressure && (brush->flag & BRUSH_SIZE_PRESSURE))
+ unprojected_radius *= sd->pressure_value;
+
+ if (!sculpt_get_lock_brush_size(brush))
+ sculpt_set_brush_unprojected_radius(brush, unprojected_radius);
+
+ if(!(paint->flags & PAINT_SHOW_BRUSH))
+ return;
+
+ }
+
+ glPushAttrib(
+ GL_COLOR_BUFFER_BIT|
+ GL_CURRENT_BIT|
+ GL_DEPTH_BUFFER_BIT|
+ GL_ENABLE_BIT|
+ GL_LINE_BIT|
+ GL_POLYGON_BIT|
+ GL_STENCIL_BUFFER_BIT|
+ GL_TRANSFORM_BIT|
+ GL_VIEWPORT_BIT|
+ GL_TEXTURE_BIT);
+
+ glColor4f(col[0], col[1], col[2], alpha);
+
+ glEnable(GL_BLEND);
+
+ glEnable(GL_LINE_SMOOTH);
+
+ if (sd->draw_anchored) {
+ glTranslatef(sd->anchored_initial_mouse[0] - vc.ar->winrct.xmin, sd->anchored_initial_mouse[1] - vc.ar->winrct.ymin, 0.0f);
+ glutil_draw_lined_arc(0.0, M_PI*2.0, sd->anchored_size, 40);
+ glTranslatef(-sd->anchored_initial_mouse[0] + vc.ar->winrct.xmin, -sd->anchored_initial_mouse[1] + vc.ar->winrct.xmin, 0.0f);
+ }
+ else {
+ glTranslatef((float)x, (float)y, 0.0f);
+ glutil_draw_lined_arc(0.0, M_PI*2.0, sculpt_get_brush_size(brush), 40);
+ glTranslatef(-(float)x, -(float)y, 0.0f);
+ }
+
+ glPopAttrib();
+ }
+ else {
+ Paint *paint = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(paint);
+
+ if(!(paint->flags & PAINT_SHOW_BRUSH))
+ return;
+
+ glColor4ubv(paint_get_active(CTX_data_scene(C))->paint_cursor_col);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ glTranslatef((float)x, (float)y, 0.0f);
+ glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40); // XXX: for now use the brushes size instead of potentially using the unified size because the feature has been enabled for sculpt
+ glTranslatef((float)-x, (float)-y, 0.0f);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
-static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2])
+static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2])
{
+ Paint *paint = paint_get_active(CTX_data_scene(C)); // XXX
+ Brush *brush = paint_brush(paint); // XXX
+
+ float mouse[2];
+
PointerRNA itemptr;
- float pressure = 1;
- float center[3] = {0, 0, 0};
- int flip= event->shift?1:0;
+
+ float location[3];
+
+ float pressure;
+ int pen_flip;
+
+ ViewContext vc; // XXX
+
PaintStroke *stroke = op->customdata;
- /* XXX: can remove the if statement once all modes have this */
- if(stroke->get_location)
- stroke->get_location(C, stroke, center, mouse);
+ view3d_set_viewcontext(C, &vc); // XXX
/* Tablet */
if(event->custom == EVT_DATA_TABLET) {
wmTabletData *wmtab= event->customdata;
- if(wmtab->Active != EVT_TABLET_NONE)
- pressure= wmtab->Pressure;
- if(wmtab->Active == EVT_TABLET_ERASER)
- flip = 1;
+
+ pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
+ pen_flip = (wmtab->Active == EVT_TABLET_ERASER);
+ }
+ else {
+ pressure = 1;
+ pen_flip = 0;
}
-
+
+ // XXX: temporary check for sculpt mode until things are more unified
+ if (vc.obact->sculpt) {
+ float delta[3];
+
+ brush_jitter_pos(brush, mouse_in, mouse);
+
+ // XXX: meh, this is round about because brush_jitter_pos isn't written in the best way to be reused here
+ if (brush->flag & BRUSH_JITTER_PRESSURE) {
+ sub_v3_v3v3(delta, mouse, mouse_in);
+ mul_v3_fl(delta, pressure);
+ add_v3_v3v3(mouse, mouse_in, delta);
+ }
+ }
+ else
+ copy_v3_v3(mouse, mouse_in);
+
+ /* XXX: can remove the if statement once all modes have this */
+ if(stroke->get_location)
+ stroke->get_location(C, stroke, location, mouse);
+ else
+ zero_v3(location);
+
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_float_set_array(&itemptr, "location", center);
- RNA_float_set_array(&itemptr, "mouse", mouse);
- RNA_boolean_set(&itemptr, "flip", flip);
- RNA_float_set(&itemptr, "pressure", pressure);
+
+ RNA_float_set_array(&itemptr, "location", location);
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set (&itemptr, "pen_flip", pen_flip);
+ RNA_float_set (&itemptr, "pressure", pressure);
stroke->last_mouse_position[0] = mouse[0];
stroke->last_mouse_position[1] = mouse[1];
@@ -154,10 +852,14 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *ev
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *event)
{
- output[0] = event->x;
+ output[0] = event->x;
output[1] = event->y;
- if(stroke->brush->flag & BRUSH_SMOOTH_STROKE && stroke->brush->sculpt_tool != SCULPT_TOOL_GRAB) {
+ if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) &&
+ !ELEM4(stroke->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK) &&
+ !(stroke->brush->flag & BRUSH_ANCHORED) &&
+ !(stroke->brush->flag & BRUSH_RESTORE_MESH))
+ {
float u = stroke->brush->smooth_stroke_factor, v = 1.0 - u;
float dx = stroke->last_mouse_position[0] - event->x, dy = stroke->last_mouse_position[1] - event->y;
@@ -176,7 +878,9 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *ev
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
static int paint_space_stroke_enabled(Brush *br)
{
- return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB);
+ return (br->flag & BRUSH_SPACE) &&
+ !(br->flag & BRUSH_ANCHORED) &&
+ !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK);
}
/* For brushes with stroke spacing enabled, moves mouse in steps
@@ -187,23 +891,34 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
int cnt = 0;
if(paint_space_stroke_enabled(stroke->brush)) {
- float mouse[2] = {stroke->last_mouse_position[0], stroke->last_mouse_position[1]};
- float vec[2] = {final_mouse[0] - mouse[0], final_mouse[1] - mouse[1]};
+ float mouse[2];
+ float vec[2];
float length, scale;
- int steps = 0, i;
- /* Normalize the vector between the last stroke dot and the goal */
- length = sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
+ copy_v2_v2(mouse, stroke->last_mouse_position);
+ sub_v2_v2v2(vec, final_mouse, mouse);
+
+ length = len_v2(vec);
if(length > FLT_EPSILON) {
- scale = stroke->brush->spacing / length;
- vec[0] *= scale;
- vec[1] *= scale;
+ int steps;
+ int i;
+ float pressure = 1;
+
+ // XXX duplicate code
+ if(event->custom == EVT_DATA_TABLET) {
+ wmTabletData *wmtab= event->customdata;
+ if(wmtab->Active != EVT_TABLET_NONE)
+ pressure = stroke->brush->flag & BRUSH_SIZE_PRESSURE ? wmtab->Pressure : 1;
+ }
+
+ scale = (sculpt_get_brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length;
+ mul_v2_fl(vec, scale);
+
+ steps = (int)(1.0f / scale);
- steps = (int)(length / stroke->brush->spacing);
for(i = 0; i < steps; ++i, ++cnt) {
- mouse[0] += vec[0];
- mouse[1] += vec[1];
+ add_v2_v2(mouse, vec);
paint_brush_stroke_add_step(C, op, event, mouse);
}
}
@@ -283,14 +998,25 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
//ED_region_tag_redraw(ar);
}
}
- else
+ else {
paint_brush_stroke_add_step(C, op, event, mouse);
+ }
}
else
;//ED_region_tag_redraw(ar);
}
}
+ /* we want the stroke to have the first daub at the start location instead of waiting till we have moved the space distance */
+ if(first &&
+ stroke->stroke_started &&
+ paint_space_stroke_enabled(stroke->brush) &&
+ !(stroke->brush->flag & BRUSH_ANCHORED) &&
+ !(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
+ {
+ paint_brush_stroke_add_step(C, op, event, mouse);
+ }
+
return OPERATOR_RUNNING_MODAL;
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 85fbd5954e8..21ea6cb7f75 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -216,6 +216,10 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
{CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
{CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
{CURVE_PRESET_MAX, "MAX", 0, "Max", ""},
+ {CURVE_PRESET_MID9, "MID9", 0, "Mid9", ""},
+ {CURVE_PRESET_LINE, "LINE", 0, "Line", ""},
+ {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""},
+ {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""},
{0, NULL, 0, NULL, NULL}};
ot->name= "Preset";
@@ -225,7 +229,7 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
ot->exec= brush_curve_preset_exec;
ot->poll= brush_curve_preset_poll;
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ ot->flag= OPTYPE_UNDO;
RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
}
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b53771c92ae..eee0d520747 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -22,7 +22,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): none yet.
+ * Contributor(s): Jason Wilkins, Tom Musgrove.
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -38,6 +38,8 @@
#include "BLI_ghash.h"
#include "BLI_pbvh.h"
#include "BLI_threads.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
#include "DNA_key_types.h"
#include "DNA_mesh_types.h"
@@ -73,6 +75,7 @@
#include "ED_screen.h"
#include "ED_sculpt.h"
#include "ED_view3d.h"
+#include "ED_mesh.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -81,6 +84,7 @@
#include "RE_render_ext.h"
+#include "RE_shader_ext.h"
#include "GPU_buffers.h"
@@ -88,13 +92,70 @@
#include <stdlib.h>
#include <string.h>
-/* Number of vertices to average in order to determine the flatten distance */
-#define FLATTEN_SAMPLE_SIZE 10
+#ifdef _OPENMP
+#include <omp.h>
+#endif
/* ==== FORWARD DEFINITIONS =====
*
*/
-static void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
+
+void ED_sculpt_force_update(bContext *C)
+{
+ Object *ob= CTX_data_active_object(C);
+
+ if(ob && (ob->mode & OB_MODE_SCULPT))
+ multires_force_update(ob);
+}
+
+/* Sculpt mode handles multires differently from regular meshes, but only if
+ it's the last modifier on the stack and it is not on the first level */
+struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
+{
+ ModifierData *md, *nmd;
+
+ for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
+ if(md->type == eModifierType_Multires) {
+ MultiresModifierData *mmd= (MultiresModifierData*)md;
+
+ /* Check if any of the modifiers after multires are active
+ * if not it can use the multires struct */
+ for(nmd= md->next; nmd; nmd= nmd->next)
+ if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
+ break;
+
+ if(!nmd && mmd->sculptlvl > 0)
+ return mmd;
+ }
+ }
+
+ return NULL;
+}
+
+/* Checks whether full update mode (slower) needs to be used to work with modifiers */
+int sculpt_modifiers_active(Scene *scene, Object *ob)
+{
+ ModifierData *md;
+ MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
+
+ /* check if there are any modifiers after what we are sculpting,
+ for a multires modifier with a deform modifier in front, we
+ do no need to recalculate the modifier stack. note that this
+ needs to be in sync with ccgDM_use_grid_pbvh! */
+ if(mmd)
+ md= mmd->modifier.next;
+ else
+ md= modifiers_getVirtualModifierList(ob);
+
+ /* exception for shape keys because we can edit those */
+ for(; md; md= md->next) {
+ if(modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ if(md->type != eModifierType_ShapeKey)
+ return 1;
+ }
+
+ return 0;
+}
/* ===== STRUCTS =====
*
@@ -121,10 +182,13 @@ typedef struct StrokeCache {
/* Variants */
float radius;
+ float radius_squared;
+ //float traced_location[3];
float true_location[3];
float location[3];
- float flip;
+ float pen_flip;
+ float invert;
float pressure;
float mouse[2];
float bstrength;
@@ -141,15 +205,32 @@ typedef struct StrokeCache {
Brush *brush;
float (*face_norms)[3]; /* Copy of the mesh faces' normals */
- float rotation; /* Texture rotation (radians) for anchored and rake modes */
+ float special_rotation; /* Texture rotation (radians) for anchored and rake modes */
int pixel_radius, previous_pixel_radius;
- float grab_active_location[8][3];
float grab_delta[3], grab_delta_symmetry[3];
float old_grab_location[3], orig_grab_location[3];
- int symmetry; /* Symmetry index between 0 and 7 */
- float view_normal[3], view_normal_symmetry[3];
- int last_rake[2]; /* Last location of updating rake rotation */
+
+ int symmetry; /* Symmetry index between 0 and 7 bit combo 0 is Brush only;
+ 1 is X mirror; 2 is Y mirror; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ int mirror_symmetry_pass; /* the symmetry pass we are currently on between 0 and 7*/
+ float true_view_normal[3];
+ float view_normal[3];
+ float last_area_normal[3];
+ float last_center[3];
+ int radial_symmetry_pass;
+ float symm_rot_mat[4][4];
+ float symm_rot_mat_inv[4][4];
+ float last_rake[2]; /* Last location of updating rake rotation */
int original;
+
+ float vertex_rotation;
+
+ char saved_active_brush_name[24];
+ int alt_smooth;
+
+ float plane_trim_squared;
+
+ float autosmooth_overlap;
} StrokeCache;
/* ===== OPENGL =====
@@ -224,10 +305,12 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
RegionView3D *rv3d, Object *ob)
{
PBVH *pbvh= ob->sculpt->pbvh;
- BoundBox *bb = MEM_callocN(sizeof(BoundBox), "sculpt boundbox");
+ BoundBox bb;
bglMats mats;
rcti rect;
+ memset(&bb, 0, sizeof(BoundBox));
+
view3d_get_transformation(ar, rv3d, ob, &mats);
sculpt_get_redraw_rect(ar, rv3d,ob, &rect);
@@ -246,405 +329,351 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
rect.ymax -= 2;
#endif
- view3d_calculate_clipping(bb, planes, &mats, &rect);
+ view3d_calculate_clipping(&bb, planes, &mats, &rect);
mul_m4_fl(planes, -1.0f);
- MEM_freeN(bb);
-
/* clear redraw flag from nodes */
if(pbvh)
BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
}
-/************************** Undo *************************/
-
-typedef struct SculptUndoNode {
- struct SculptUndoNode *next, *prev;
-
- char idname[MAX_ID_NAME]; /* name instead of pointer*/
- void *node; /* only during push, not valid afterwards! */
-
- float (*co)[3];
- short (*no)[3];
- int totvert;
-
- /* non-multires */
- int maxvert; /* to verify if totvert it still the same */
- int *index; /* to restore into right location */
-
- /* multires */
- int maxgrid; /* same for grid */
- int gridsize; /* same for grid */
- int totgrid; /* to restore into right location */
- int *grids; /* to restore into right location */
-
- /* layer brush */
- float *layer_disp;
+/************************ Brush Testing *******************/
- /* shape keys */
- char *shapeName[32]; /* keep size in sync with keyblock dna */
-} SculptUndoNode;
+typedef struct SculptBrushTest {
+ float radius_squared;
+ float location[3];
+ float dist;
+} SculptBrushTest;
-static void update_cb(PBVHNode *node, void *data)
+static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
{
- BLI_pbvh_node_mark_update(node);
+ test->radius_squared= ss->cache->radius_squared;
+ copy_v3_v3(test->location, ss->cache->location);
}
-/* Checks whether full update mode (slower) needs to be used to work with modifiers */
-static int sculpt_modifiers_active(Scene *scene, Object *ob)
+static int sculpt_brush_test(SculptBrushTest *test, float co[3])
{
- ModifierData *md;
- MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
+ float distsq = len_squared_v3v3(co, test->location);
- /* check if there are any modifiers after what we are sculpting,
- for a multires modifier with a deform modifier in front, we
- do no need to recalculate the modifier stack. note that this
- needs to be in sync with ccgDM_use_grid_pbvh! */
- if(mmd)
- md= mmd->modifier.next;
- else
- md= modifiers_getVirtualModifierList(ob);
-
- /* exception for shape keys because we can edit those */
- for(; md; md= md->next) {
- if(modifier_isEnabled(scene, md, eModifierMode_Realtime))
- if(md->type != eModifierType_ShapeKey)
- return 1;
+ if(distsq <= test->radius_squared) {
+ test->dist = sqrt(distsq);
+ return 1;
+ }
+ else {
+ return 0;
}
-
- return 0;
}
-static void sculpt_undo_restore(bContext *C, ListBase *lb)
+static int sculpt_brush_test_sq(SculptBrushTest *test, float co[3])
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
- SculptSession *ss = ob->sculpt;
- SculptUndoNode *unode;
- MVert *mvert;
- MultiresModifierData *mmd;
- int *index;
- int i, j, update= 0;
-
- sculpt_update_mesh_elements(scene, ob, 0);
-
- for(unode=lb->first; unode; unode=unode->next) {
- if(!(strcmp(unode->idname, ob->id.name)==0))
- continue;
+ float distsq = len_squared_v3v3(co, test->location);
- if(unode->maxvert) {
- char *shapeName= (char*)unode->shapeName;
-
- /* regular mesh restore */
- if(ss->totvert != unode->maxvert)
- continue;
+ if(distsq <= test->radius_squared) {
+ test->dist = distsq;
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
- if (ss->kb && strcmp(ss->kb->name, shapeName)) {
- /* shape key has been changed before calling undo operator */
+static int sculpt_brush_test_fast(SculptBrushTest *test, float co[3])
+{
+ return len_squared_v3v3(co, test->location) <= test->radius_squared;
+}
- Key *key= ob_get_key(ob);
- KeyBlock *kb= key_get_named_keyblock(key, shapeName);
+static int sculpt_brush_test_cube(SculptBrushTest *test, float co[3], float local[4][4])
+{
+ const static float side = 0.70710678118654752440084436210485; // sqrt(.5);
- if (kb) {
- ob->shapenr= BLI_findindex(&key->block, kb) + 1;
- ob->shapeflag|= OB_SHAPE_LOCK;
+ float local_co[3];
- sculpt_update_mesh_elements(scene, ob, 0);
- WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
- } else {
- /* key has been removed -- skip this undo node */
- continue;
- }
- }
+ mul_v3_m4v3(local_co, local, co);
- index= unode->index;
- mvert= ss->mvert;
+ local_co[0] = fabs(local_co[0]);
+ local_co[1] = fabs(local_co[1]);
+ local_co[2] = fabs(local_co[2]);
- if (ss->kb) {
- float (*vertCos)[3];
- vertCos= key_to_vertcos(ob, ss->kb);
+ if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
+ test->dist = MAX3(local_co[0], local_co[1], local_co[2]) / side;
- for(i=0; i<unode->totvert; i++)
- swap_v3_v3(vertCos[index[i]], unode->co[i]);
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
- /* propagate new coords to keyblock */
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+static float frontface(Brush *brush, float sculpt_normal[3], short no[3], float fno[3])
+{
+ if (brush->flag & BRUSH_FRONTFACE) {
+ float dot;
- /* pbvh uses it's own mvert array, so coords should be */
- /* propagated to pbvh here */
- BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ if (no) {
+ float tmp[3];
- MEM_freeN(vertCos);
- } else {
- for(i=0; i<unode->totvert; i++) {
- swap_v3_v3(mvert[index[i]].co, unode->co[i]);
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
- }
+ normal_short_to_float_v3(tmp, no);
+ dot= dot_v3v3(tmp, sculpt_normal);
}
- else if(unode->maxgrid && dm->getGridData) {
- /* multires restore */
- DMGridData **grids, *grid;
- float (*co)[3];
- int gridsize;
-
- if(dm->getNumGrids(dm) != unode->maxgrid)
- continue;
- if(dm->getGridSize(dm) != unode->gridsize)
- continue;
-
- grids= dm->getGridData(dm);
- gridsize= dm->getGridSize(dm);
-
- co = unode->co;
- for(j=0; j<unode->totgrid; j++) {
- grid= grids[unode->grids[j]];
-
- for(i=0; i<gridsize*gridsize; i++, co++)
- swap_v3_v3(grid[i].co, co[0]);
- }
+ else {
+ dot= dot_v3v3(fno, sculpt_normal);
}
- update= 1;
+ return dot > 0 ? dot : 0;
}
-
- if(update) {
- /* we update all nodes still, should be more clever, but also
- needs to work correct when exiting/entering sculpt mode and
- the nodes get recreated, though in that case it could do all */
- BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, NULL);
- BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL);
-
- if((mmd=sculpt_multires_active(scene, ob)))
- multires_mark_as_modified(ob);
-
- if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1)
- DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ else {
+ return 1;
}
}
-static void sculpt_undo_free(ListBase *lb)
+#if 0
+
+static int sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
{
- SculptUndoNode *unode;
+ if (sculpt_brush_test_fast(test, co)) {
+ float t1[3], t2[3], t3[3], dist;
- for(unode=lb->first; unode; unode=unode->next) {
- if(unode->co)
- MEM_freeN(unode->co);
- if(unode->no)
- MEM_freeN(unode->no);
- if(unode->index)
- MEM_freeN(unode->index);
- if(unode->grids)
- MEM_freeN(unode->grids);
- if(unode->layer_disp)
- MEM_freeN(unode->layer_disp);
- }
-}
+ sub_v3_v3v3(t1, location, co);
+ sub_v3_v3v3(t2, x2, location);
-static SculptUndoNode *sculpt_undo_get_node(SculptSession *ss, PBVHNode *node)
-{
- ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
- SculptUndoNode *unode;
+ cross_v3_v3v3(t3, an, t1);
- if(!lb)
- return NULL;
+ dist = len_v3(t3)/len_v3(t2);
- for(unode=lb->first; unode; unode=unode->next)
- if(unode->node == node)
- return unode;
+ test->dist = dist;
- return NULL;
+ return 1;
+ }
+
+ return 0;
}
-static SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
-{
- ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
- Object *ob= ss->ob;
- SculptUndoNode *unode;
- int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
+#endif
- /* list is manipulated by multiple threads, so we lock */
- BLI_lock_thread(LOCK_CUSTOM1);
+/* ===== Sculpting =====
+ *
+ */
+
- if((unode= sculpt_undo_get_node(ss, node))) {
- BLI_unlock_thread(LOCK_CUSTOM1);
- return unode;
- }
+static float overlapped_curve(Brush* br, float x)
+{
+ int i;
+ const int n = 100 / br->spacing;
+ const float h = br->spacing / 50.0f;
+ const float x0 = x-1;
- unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
- strcpy(unode->idname, ob->id.name);
- unode->node= node;
+ float sum;
- BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
- BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
- &maxgrid, &gridsize, NULL, NULL);
+ sum = 0;
+ for (i= 0; i < n; i++) {
+ float xx;
- unode->totvert= totvert;
- /* we will use this while sculpting, is mapalloc slow to access then? */
- unode->co= MEM_mapallocN(sizeof(float)*3*allvert, "SculptUndoNode.co");
- unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no");
- undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert);
- BLI_addtail(lb, unode);
+ xx = fabs(x0 + i*h);
- if(maxgrid) {
- /* multires */
- unode->maxgrid= maxgrid;
- unode->totgrid= totgrid;
- unode->gridsize= gridsize;
- unode->grids= MEM_mapallocN(sizeof(int)*totgrid, "SculptUndoNode.grids");
+ if (xx < 1.0f)
+ sum += brush_curve_strength(br, xx, 1);
}
- else {
- /* regular mesh */
- unode->maxvert= ss->totvert;
- unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index");
- }
-
- BLI_unlock_thread(LOCK_CUSTOM1);
- /* copy threaded, hopefully this is the performance critical part */
- {
- PBVHVertexIter vd;
+ return sum;
+}
- BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
- copy_v3_v3(unode->co[vd.i], vd.co);
- if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
- else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
- if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i];
- }
- BLI_pbvh_vertex_iter_end;
- }
+static float integrate_overlap(Brush* br)
+{
+ int i;
+ int m= 10;
+ float g = 1.0f/m;
+ float overlap;
+ float max;
- if(unode->grids)
- memcpy(unode->grids, grids, sizeof(int)*totgrid);
+ overlap= 0;
+ max= 0;
+ for(i= 0; i < m; i++) {
+ overlap = overlapped_curve(br, i*g);
- /* store active shape key */
- if(ss->kb) BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
- else unode->shapeName[0]= '\0';
+ if (overlap > max)
+ max = overlap;
+ }
- return unode;
+ return max;
}
-static void sculpt_undo_push_begin(SculptSession *ss, char *name)
+/* Uses symm to selectively flip any axis of a coordinate. */
+static void flip_coord(float out[3], float in[3], const char symm)
{
- undo_paint_push_begin(UNDO_PAINT_MESH, name,
- sculpt_undo_restore, sculpt_undo_free);
+ if(symm & SCULPT_SYMM_X)
+ out[0]= -in[0];
+ else
+ out[0]= in[0];
+ if(symm & SCULPT_SYMM_Y)
+ out[1]= -in[1];
+ else
+ out[1]= in[1];
+ if(symm & SCULPT_SYMM_Z)
+ out[2]= -in[2];
+ else
+ out[2]= in[2];
}
-static void sculpt_undo_push_end(SculptSession *ss)
+float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle)
{
- ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
- SculptUndoNode *unode;
-
- /* we don't need normals in the undo stack */
- for(unode=lb->first; unode; unode=unode->next) {
- if(unode->no) {
- MEM_freeN(unode->no);
- unode->no= NULL;
- }
+ float mirror[3];
+ float distsq;
+ float mat[4][4];
+
+ //flip_coord(mirror, cache->traced_location, symm);
+ flip_coord(mirror, cache->true_location, symm);
- if(unode->layer_disp) {
- MEM_freeN(unode->layer_disp);
- unode->layer_disp= NULL;
- }
- }
+ unit_m4(mat);
+ rotate_m4(mat, axis, angle);
- undo_paint_push_end(UNDO_PAINT_MESH);
-}
+ mul_m4_v3(mat, mirror);
-void ED_sculpt_force_update(bContext *C)
-{
- Object *ob= CTX_data_active_object(C);
+ //distsq = len_squared_v3v3(mirror, cache->traced_location);
+ distsq = len_squared_v3v3(mirror, cache->true_location);
- if(ob && (ob->mode & OB_MODE_SCULPT))
- multires_force_update(ob);
+ if (distsq <= 4*(cache->radius_squared))
+ return (2*(cache->radius) - sqrt(distsq)) / (2*(cache->radius));
+ else
+ return 0;
}
-/************************ Brush Testing *******************/
-
-typedef struct SculptBrushTest {
- float radius_squared;
- float location[3];
+static float calc_radial_symmetry_feather(Sculpt *sd, StrokeCache *cache, const char symm, const char axis)
+{
+ int i;
+ float overlap;
- float dist;
-} SculptBrushTest;
+ overlap = 0;
+ for(i = 1; i < sd->radial_symm[axis-'X']; ++i) {
+ const float angle = 2*M_PI*i/sd->radial_symm[axis-'X'];
+ overlap += calc_overlap(cache, symm, axis, angle);
+ }
-static void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test)
-{
- test->radius_squared= ss->cache->radius*ss->cache->radius;
- copy_v3_v3(test->location, ss->cache->location);
+ return overlap;
}
-static int sculpt_brush_test(SculptBrushTest *test, float co[3])
+static float calc_symmetry_feather(Sculpt *sd, StrokeCache* cache)
{
- float distsq, delta[3];
+ if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
+ float overlap;
+ int symm = cache->symmetry;
+ int i;
- sub_v3_v3v3(delta, co, test->location);
- distsq = INPR(delta, delta);
+ overlap = 0;
+ for (i = 0; i <= symm; i++) {
+ if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
- if(distsq < test->radius_squared) {
- test->dist = sqrt(distsq);
+ overlap += calc_overlap(cache, i, 0, 0);
+
+ overlap += calc_radial_symmetry_feather(sd, cache, i, 'X');
+ overlap += calc_radial_symmetry_feather(sd, cache, i, 'Y');
+ overlap += calc_radial_symmetry_feather(sd, cache, i, 'Z');
+ }
+ }
+
+ return 1/overlap;
+ }
+ else {
return 1;
}
-
- return 0;
}
-/* ===== Sculpting =====
- *
- */
-
/* Return modified brush strength. Includes the direction of the brush, positive
values pull vertices, negative values push. Uses tablet pressure and a
special multiplier found experimentally to scale the strength factor. */
-static float brush_strength(Sculpt *sd, StrokeCache *cache)
+static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, float overlap)
{
Brush *brush = paint_brush(&sd->paint);
- /* Primary strength input; square it to make lower values more sensitive */
- float alpha = brush->alpha * brush->alpha;
- float dir= brush->flag & BRUSH_DIR_IN ? -1 : 1;
- float pressure= 1;
- float flip= cache->flip ? -1:1;
+ /* Primary strength input; square it to make lower values more sensitive */
+ float alpha = sculpt_get_brush_alpha(brush)*sculpt_get_brush_alpha(brush);
+ float dir = brush->flag & BRUSH_DIR_IN ? -1 : 1;
+ float pressure = brush->flag & BRUSH_ALPHA_PRESSURE ? cache->pressure : 1;
+ float pen_flip = cache->pen_flip ? -1 : 1;
+ float invert = cache->invert ? -1 : 1;
+ float flip = dir * invert * pen_flip;
- if(brush->flag & BRUSH_ALPHA_PRESSURE)
- pressure *= cache->pressure;
-
switch(brush->sculpt_tool){
- case SCULPT_TOOL_DRAW:
- case SCULPT_TOOL_INFLATE:
- case SCULPT_TOOL_CLAY:
- case SCULPT_TOOL_FLATTEN:
- case SCULPT_TOOL_LAYER:
- return alpha * dir * pressure * flip; /*XXX: not sure why? was multiplied by G.vd->grid */;
- case SCULPT_TOOL_SMOOTH:
- return alpha * 4 * pressure;
- case SCULPT_TOOL_PINCH:
- return alpha / 2 * dir * pressure * flip;
- case SCULPT_TOOL_GRAB:
- return 1;
- default:
- return 0;
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_TUBES:
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_LAYER:
+ return alpha * flip * pressure * overlap * feather;
+
+ case SCULPT_TOOL_CREASE:
+ case SCULPT_TOOL_BLOB:
+ return alpha * flip * pressure * overlap * feather;
+
+ case SCULPT_TOOL_INFLATE:
+ if (flip > 0) {
+ return 0.250f * alpha * flip * pressure * overlap * feather;
+ }
+ else {
+ return 0.125f * alpha * flip * pressure * overlap * feather;
+ }
+
+ case SCULPT_TOOL_FILL:
+ case SCULPT_TOOL_SCRAPE:
+ case SCULPT_TOOL_FLATTEN:
+ if (flip > 0) {
+ overlap = (1+overlap) / 2;
+ return alpha * flip * pressure * overlap * feather;
+ }
+ else {
+ /* reduce strength for DEEPEN, PEAKS, and CONTRAST */
+ return 0.5f * alpha * flip * pressure * overlap * feather;
+ }
+
+ case SCULPT_TOOL_SMOOTH:
+ return alpha * pressure * feather;
+
+ case SCULPT_TOOL_PINCH:
+ if (flip > 0) {
+ return alpha * flip * pressure * overlap * feather;
+ }
+ else {
+ return 0.25f * alpha * flip * pressure * overlap * feather;
+ }
+
+ case SCULPT_TOOL_NUDGE:
+ overlap = (1+overlap) / 2;
+ return alpha * pressure * overlap * feather;
+
+ case SCULPT_TOOL_THUMB:
+ return alpha*pressure*feather;
+
+ case SCULPT_TOOL_SNAKE_HOOK:
+ return feather;
+
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_ROTATE:
+ return feather;
+
+ default:
+ return 0;
}
}
-/* Uses symm to selectively flip any axis of a coordinate. */
-static void flip_coord(float out[3], float in[3], const char symm)
+float get_tex_pixel(Brush* br, float u, float v)
{
- if(symm & SCULPT_SYMM_X)
- out[0]= -in[0];
- else
- out[0]= in[0];
- if(symm & SCULPT_SYMM_Y)
- out[1]= -in[1];
- else
- out[1]= in[1];
- if(symm & SCULPT_SYMM_Z)
- out[2]= -in[2];
- else
- out[2]= in[2];
+ TexResult texres;
+ float co[3];
+ int hasrgb;
+
+ co[0] = u;
+ co[1] = v;
+ co[2] = 0;
+
+ memset(&texres, 0, sizeof(TexResult));
+ hasrgb = multitex_ext(br->mtex.tex, co, NULL, NULL, 1, &texres);
+
+ if (hasrgb & TEX_RGB)
+ texres.tin = (0.35*texres.tr + 0.45*texres.tg + 0.2*texres.tb)*texres.ta;
+
+ return texres.tin;
}
+#if 0
+
/* Get a pixel from the texcache at (px, py) */
static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
{
@@ -655,7 +684,7 @@ static unsigned char get_texcache_pixel(const SculptSession *ss, int px, int py)
static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float v)
{
- int x, y, x2, y2;
+ unsigned x, y, x2, y2;
const int tc_max = ss->texcache_side - 1;
float urat, vrat, uopp;
@@ -682,76 +711,97 @@ static float get_texcache_pixel_bilinear(const SculptSession *ss, float u, float
get_texcache_pixel(ss, x2, y2) * urat) * vrat) / 255.0;
}
+#endif
+
/* Return a multiplier for brush strength on a particular vertex. */
static float tex_strength(SculptSession *ss, Brush *br, float *point, const float len)
{
- MTex *tex = &br->mtex;
+ MTex *mtex = &br->mtex;
float avg= 1;
- if(!tex) {
+ if(!mtex->tex) {
avg= 1;
}
- else if(tex->brush_map_mode == MTEX_MAP_MODE_3D) {
+ else if(mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
float jnk;
/* Get strength by feeding the vertex
location directly into a texture */
- externtex(tex, point, &avg,
+ externtex(mtex, point, &avg,
&jnk, &jnk, &jnk, &jnk);
}
else if(ss->texcache) {
- const float bsize= ss->cache->pixel_radius * 2;
- const float rot= tex->rot + ss->cache->rotation;
- int px, py;
- float flip[3], point_2d[2];
-
- /* If the active area is being applied for symmetry, flip it
- across the symmetry axis in order to project it. This insures
- that the brush texture will be oriented correctly. */
- copy_v3_v3(flip, point);
- flip_coord(flip, flip, ss->cache->symmetry);
- projectf(ss->cache->mats, flip, point_2d);
-
- /* For Tile and Drag modes, get the 2D screen coordinates of the
- and scale them up or down to the texture size. */
- if(tex->brush_map_mode == MTEX_MAP_MODE_TILED) {
- const int sx= (const int)tex->size[0];
- const int sy= (const int)tex->size[1];
-
- float fx= point_2d[0];
- float fy= point_2d[1];
-
- float angle= atan2(fy, fx) - rot;
- float flen= sqrtf(fx*fx + fy*fy);
-
- if(rot<0.001 && rot>-0.001) {
- px= point_2d[0];
- py= point_2d[1];
- } else {
- px= flen * cos(angle) + 2000;
- py= flen * sin(angle) + 2000;
- }
- if(sx != 1)
- px %= sx-1;
- if(sy != 1)
- py %= sy-1;
- avg= get_texcache_pixel_bilinear(ss, ss->texcache_side*px/sx, ss->texcache_side*py/sy);
- }
- else if(tex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
- float fx= (point_2d[0] - ss->cache->tex_mouse[0]) / bsize;
- float fy= (point_2d[1] - ss->cache->tex_mouse[1]) / bsize;
-
- float angle= atan2(fy, fx) - rot;
- float flen= sqrtf(fx*fx + fy*fy);
-
- fx = flen * cos(angle) + 0.5;
- fy = flen * sin(angle) + 0.5;
+ float rotation = -mtex->rot;
+ float x, y, point_2d[3];
+ float diameter;
+
+ /* if the active area is being applied for symmetry, flip it
+ across the symmetry axis and rotate it back to the orignal
+ position in order to project it. This insures that the
+ brush texture will be oriented correctly. */
+
+ flip_coord(point_2d, point, ss->cache->mirror_symmetry_pass);
+
+ if (ss->cache->radial_symmetry_pass)
+ mul_m4_v3(ss->cache->symm_rot_mat_inv, point_2d);
+
+ projectf(ss->cache->mats, point_2d, point_2d);
+
+ /* if fixed mode, keep coordinates relative to mouse */
+ if(mtex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
+ rotation += ss->cache->special_rotation;
+
+ point_2d[0] -= ss->cache->tex_mouse[0];
+ point_2d[1] -= ss->cache->tex_mouse[1];
+
+ diameter = ss->cache->pixel_radius; // use pressure adjusted size for fixed mode
+
+ x = point_2d[0];
+ y = point_2d[1];
+ }
+ else /* else (mtex->brush_map_mode == MTEX_MAP_MODE_TILED),
+ leave the coordinates relative to the screen */
+ {
+ diameter = sculpt_get_brush_size(br); // use unadjusted size for tiled mode
+
+ x = point_2d[0] - ss->cache->vc->ar->winrct.xmin;
+ y = point_2d[1] - ss->cache->vc->ar->winrct.ymin;
+ }
+
+ x /= ss->cache->vc->ar->winx;
+ y /= ss->cache->vc->ar->winy;
- avg= get_texcache_pixel_bilinear(ss, fx * ss->texcache_side, fy * ss->texcache_side);
+ if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
+ x -= 0.5f;
+ y -= 0.5f;
}
+
+ x *= ss->cache->vc->ar->winx / diameter;
+ y *= ss->cache->vc->ar->winy / diameter;
+
+ /* it is probably worth optimizing for those cases where
+ the texture is not rotated by skipping the calls to
+ atan2, sqrtf, sin, and cos. */
+ if (rotation > 0.001 || rotation < -0.001) {
+ const float angle = atan2(y, x) + rotation;
+ const float flen = sqrtf(x*x + y*y);
+
+ x = flen * cos(angle);
+ y = flen * sin(angle);
+ }
+
+ x *= br->mtex.size[0];
+ y *= br->mtex.size[1];
+
+ x += br->mtex.ofs[0];
+ y += br->mtex.ofs[1];
+
+ avg = get_tex_pixel(br, x, y);
}
- avg*= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
+ avg += br->texture_sample_bias;
+
+ avg *= brush_curve_strength(br, len, ss->cache->radius); /* Falloff curve */
return avg;
}
@@ -787,7 +837,7 @@ static int sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
sub_v3_v3v3(t, center, nearest);
- return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
+ return dot_v3v3(t, t) < data->radius_squared;
}
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags */
@@ -803,7 +853,7 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float *co, const float va
co[i]= 0.0f;
else
co[i]= val[i];
- }
+ }
}
static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], float fno[3])
@@ -815,52 +865,48 @@ static void add_norm_if(float view_vec[3], float out[3], float out_flip[3], floa
}
}
-/* For draw/layer/flatten; finds average normal for all active vertices */
-static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3], PBVHNode **nodes, int totnode)
+static void calc_area_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode)
{
- PBVH *bvh= ss->pbvh;
- StrokeCache *cache = ss->cache;
- const int view = 0; /* XXX: should probably be a flag, not number: brush_type==SCULPT_TOOL_DRAW ? sculptmode_brush()->view : 0; */
- float out[3] = {0.0f, 0.0f, 0.0f};
- float out_flip[3] = {0.0f, 0.0f, 0.0f};
- float out_dir[3];
int n;
- copy_v3_v3(out_dir, cache->view_normal_symmetry);
+ float out_flip[3] = {0.0f, 0.0f, 0.0f};
- /* threaded loop over nodes */
- //#pragma omp parallel for private(n) schedule(static)
+ zero_v3(an);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
SculptUndoNode *unode;
- float fno[3];
- float nout[3] = {0.0f, 0.0f, 0.0f};
- float nout_flip[3] = {0.0f, 0.0f, 0.0f};
-
- // XXX push instead of get for thread safety in draw
- // brush .. lame, but also not harmful really
- unode= sculpt_undo_push_node(ss, nodes[n]);
+ float private_an[3] = {0.0f, 0.0f, 0.0f};
+ float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
+
+ unode = sculpt_undo_push_node(ss, nodes[n]);
sculpt_brush_test_init(ss, &test);
if(ss->cache->original) {
- BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, unode->co[vd.i])) {
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
+ float fno[3];
+
normal_short_to_float_v3(fno, unode->no[vd.i]);
- add_norm_if(out_dir, nout, nout_flip, fno);
+ add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
}
BLI_pbvh_vertex_iter_end;
}
else {
- BLI_pbvh_vertex_iter_begin(bvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test_fast(&test, vd.co)) {
if(vd.no) {
+ float fno[3];
+
normal_short_to_float_v3(fno, vd.no);
- add_norm_if(out_dir, nout, nout_flip, fno);
+ add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
+ }
+ else {
+ add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
}
- else
- add_norm_if(out_dir, nout, nout_flip, vd.fno);
}
}
BLI_pbvh_vertex_iter_end;
@@ -868,72 +914,70 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float area_normal[3]
//#pragma omp critical
{
- /* we sum per node and add together later for threads */
- add_v3_v3(out, nout);
- add_v3_v3(out_flip, nout_flip);
+ add_v3_v3(an, private_an);
+ add_v3_v3(out_flip, private_out_flip);
}
}
- if (out[0]==0.0 && out[1]==0.0 && out[2]==0.0) {
- copy_v3_v3(out, out_flip);
- }
-
- normalize_v3(out);
+ if (is_zero_v3(an))
+ copy_v3_v3(an, out_flip);
- out[0] = out_dir[0] * view + out[0] * (10-view);
- out[1] = out_dir[1] * view + out[1] * (10-view);
- out[2] = out_dir[2] * view + out[2] * (10-view);
-
- normalize_v3(out);
- copy_v3_v3(area_normal, out);
+ normalize_v3(an);
}
-static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+/* This initializes the faces to be moved for this sculpt for draw/layer/flatten; then it
+ finds average normal for all active vertices - note that this is called once for each mirroring direction */
+static void calc_sculpt_normal(Sculpt *sd, SculptSession *ss, float an[3], PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
- float offset[3], area_normal[3];
- float bstrength= ss->cache->bstrength;
- int n;
- /* area normal */
- calc_area_normal(sd, ss, area_normal, nodes, totnode);
+ if (ss->cache->mirror_symmetry_pass == 0 &&
+ ss->cache->radial_symmetry_pass == 0 &&
+ (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
+ {
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ viewvector(ss->cache->vc->rv3d, ss->cache->vc->rv3d->twmat[3], an);
+ break;
- /* offset with as much as possible factored in already */
- offset[0]= area_normal[0]*ss->cache->radius*ss->cache->scale[0]*bstrength;
- offset[1]= area_normal[1]*ss->cache->radius*ss->cache->scale[1]*bstrength;
- offset[2]= area_normal[2]*ss->cache->radius*ss->cache->scale[2]*bstrength;
+ case SCULPT_DISP_DIR_X:
+ an[1] = 0.0;
+ an[2] = 0.0;
+ an[0] = 1.0;
+ break;
- /* threaded loop over nodes */
- //#pragma omp parallel for private(n) schedule(static)
- for(n=0; n<totnode; n++) {
- PBVHVertexIter vd;
- SculptBrushTest test;
-
- sculpt_undo_push_node(ss, nodes[n]);
- sculpt_brush_test_init(ss, &test);
+ case SCULPT_DISP_DIR_Y:
+ an[0] = 0.0;
+ an[2] = 0.0;
+ an[1] = 1.0;
+ break;
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- /* offset vertex */
- float fade = tex_strength(ss, brush, vd.co, test.dist);
- float val[3]= {vd.co[0] + offset[0]*fade,
- vd.co[1] + offset[1]*fade,
- vd.co[2] + offset[2]*fade};
+ case SCULPT_DISP_DIR_Z:
+ an[0] = 0.0;
+ an[1] = 0.0;
+ an[2] = 1.0;
+ break;
- sculpt_clip(sd, ss, vd.co, val);
- if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
+ case SCULPT_DISP_DIR_AREA:
+ calc_area_normal(sd, ss, an, nodes, totnode);
+
+ default:
+ break;
}
- BLI_pbvh_vertex_iter_end;
- BLI_pbvh_node_mark_update(nodes[n]);
+ copy_v3_v3(ss->cache->last_area_normal, an);
+ }
+ else {
+ copy_v3_v3(an, ss->cache->last_area_normal);
+ flip_coord(an, an, ss->cache->mirror_symmetry_pass);
+ mul_m4_v3(ss->cache->symm_rot_mat, an);
}
}
/* For the smooth brush, uses the neighboring vertices around vert to calculate
a smoothed location for vert. Skips corner vertices (used by only one
polygon.) */
-static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
+static void neighbor_average(SculptSession *ss, float avg[3], const unsigned vert)
{
int i, skip= -1, total=0;
IndexNode *node= ss->fmap[vert].first;
@@ -974,52 +1018,58 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
copy_v3_v3(avg, ss->mvert[vert].co);
}
-static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
+static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength)
{
Brush *brush = paint_brush(&sd->paint);
- float bstrength= ss->cache->bstrength;
PBVHVertexIter vd;
SculptBrushTest test;
+ CLAMP(bstrength, 0.0f, 1.0f);
+
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
float avg[3], val[3];
- CLAMP(fade, 0.0f, 1.0f);
-
neighbor_average(ss, avg, vd.vert_indices[vd.i]);
- val[0] = vd.co[0]+(avg[0]-vd.co[0])*fade;
- val[1] = vd.co[1]+(avg[1]-vd.co[1])*fade;
- val[2] = vd.co[2]+(avg[2]-vd.co[2])*fade;
-
- sculpt_clip(sd, ss, vd.co, val);
- if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ sub_v3_v3v3(val, avg, vd.co);
+ mul_v3_fl(val, fade);
+
+ add_v3_v3(val, vd.co);
+
+ sculpt_clip(sd, ss, vd.co, val);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
}
-static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node)
+static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength)
{
Brush *brush = paint_brush(&sd->paint);
SculptBrushTest test;
DMGridData **griddata, *data;
DMGridAdjacency *gridadj, *adj;
- float bstrength= ss->cache->bstrength;
- float co[3], (*tmpgrid)[3];
+ float (*tmpgrid)[3], (*tmprow)[3];
int v1, v2, v3, v4;
int *grid_indices, totgrid, gridsize, i, x, y;
-
+
sculpt_brush_test_init(ss, &test);
+ CLAMP(bstrength, 0.0f, 1.0f);
+
BLI_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid,
NULL, &gridsize, &griddata, &gridadj);
//#pragma omp critical
- tmpgrid= MEM_mallocN(sizeof(float)*3*gridsize*gridsize, "tmpgrid");
+ {
+ tmpgrid= MEM_mallocN(sizeof(float)*3*gridsize*gridsize, "tmpgrid");
+ tmprow= MEM_mallocN(sizeof(float)*3*gridsize, "tmprow");
+ }
for(i = 0; i < totgrid; ++i) {
data = griddata[grid_indices[i]];
@@ -1027,75 +1077,106 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
memset(tmpgrid, 0, sizeof(float)*3*gridsize*gridsize);
- /* average grid values */
- for(y = 0; y < gridsize-1; ++y) {
- for(x = 0; x < gridsize-1; ++x) {
+ for (y= 0; y < gridsize-1; y++) {
+ float tmp[3];
+
+ v1 = y*gridsize;
+ add_v3_v3v3(tmprow[0], data[v1].co, data[v1+gridsize].co);
+
+ for (x= 0; x < gridsize-1; x++) {
v1 = x + y*gridsize;
- v2 = (x + 1) + y*gridsize;
- v3 = (x + 1) + (y + 1)*gridsize;
- v4 = x + (y + 1)*gridsize;
+ v2 = v1 + 1;
+ v3 = v1 + gridsize;
+ v4 = v3 + 1;
- cent_quad_v3(co, data[v1].co, data[v2].co, data[v3].co, data[v4].co);
- mul_v3_fl(co, 0.25f);
+ add_v3_v3v3(tmprow[x+1], data[v2].co, data[v4].co);
+ add_v3_v3v3(tmp, tmprow[x+1], tmprow[x]);
- add_v3_v3(tmpgrid[v1], co);
- add_v3_v3(tmpgrid[v2], co);
- add_v3_v3(tmpgrid[v3], co);
- add_v3_v3(tmpgrid[v4], co);
+ add_v3_v3(tmpgrid[v1], tmp);
+ add_v3_v3(tmpgrid[v2], tmp);
+ add_v3_v3(tmpgrid[v3], tmp);
+ add_v3_v3(tmpgrid[v4], tmp);
}
}
/* blend with existing coordinates */
for(y = 0; y < gridsize; ++y) {
for(x = 0; x < gridsize; ++x) {
- if(x == 0 && adj->index[0] == -1) continue;
- if(x == gridsize - 1 && adj->index[2] == -1) continue;
- if(y == 0 && adj->index[3] == -1) continue;
- if(y == gridsize - 1 && adj->index[1] == -1) continue;
+ float *co;
+ float *fno;
+ int index;
- copy_v3_v3(co, data[x + y*gridsize].co);
+ if(x == 0 && adj->index[0] == -1)
+ continue;
+
+ if(x == gridsize - 1 && adj->index[2] == -1)
+ continue;
+
+ if(y == 0 && adj->index[3] == -1)
+ continue;
+
+ if(y == gridsize - 1 && adj->index[1] == -1)
+ continue;
+
+ index = x + y*gridsize;
+ co= data[index].co;
+ fno= data[index].no;
if(sculpt_brush_test(&test, co)) {
- float fade = tex_strength(ss, brush, co, test.dist)*bstrength;
- float avg[3], val[3];
+ const float fade = bstrength*tex_strength(ss, brush, co, test.dist)*frontface(brush, ss->cache->view_normal, NULL, fno);
+ float *avg, val[3];
+ float n;
+
+ avg = tmpgrid[x + y*gridsize];
+
+ n = 1/16.0f;
- copy_v3_v3(avg, tmpgrid[x + y*gridsize]);
if(x == 0 || x == gridsize - 1)
- mul_v3_fl(avg, 2.0f);
+ n *= 2;
+
if(y == 0 || y == gridsize - 1)
- mul_v3_fl(avg, 2.0f);
+ n *= 2;
+
+ mul_v3_fl(avg, n);
- CLAMP(fade, 0.0f, 1.0f);
+ sub_v3_v3v3(val, avg, co);
+ mul_v3_fl(val, fade);
- val[0] = co[0]+(avg[0]-co[0])*fade;
- val[1] = co[1]+(avg[1]-co[1])*fade;
- val[2] = co[2]+(avg[2]-co[2])*fade;
-
- sculpt_clip(sd, ss, data[x + y*gridsize].co, val);
+ add_v3_v3(val, co);
+
+ sculpt_clip(sd, ss, co, val);
}
}
}
}
//#pragma omp critical
- MEM_freeN(tmpgrid);
+ {
+ MEM_freeN(tmpgrid);
+ MEM_freeN(tmprow);
+ }
}
-static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void smooth(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float bstrength)
{
- int iteration, n;
+ const int max_iterations = 4;
+ const float fract = 1.0f/max_iterations;
+ int iteration, n, count;
+ float last;
- for(iteration = 0; iteration < 2; ++iteration) {
- //#pragma omp parallel for private(n) schedule(static)
- for(n=0; n<totnode; n++) {
- sculpt_undo_push_node(ss, nodes[n]);
+ CLAMP(bstrength, 0, 1);
- if(ss->multires)
- do_multires_smooth_brush(sd, ss, nodes[n]);
- else if(ss->fmap)
- do_mesh_smooth_brush(sd, ss, nodes[n]);
+ count = (int)(bstrength*max_iterations);
+ last = max_iterations*(bstrength - count*fract);
- BLI_pbvh_node_mark_update(nodes[n]);
+ for(iteration = 1; iteration <= count; ++iteration) {
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n=0; n<totnode; n++) {
+ if(ss->multires) {
+ do_multires_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
+ }
+ else if(ss->fmap)
+ do_mesh_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last);
}
if(ss->multires)
@@ -1103,69 +1184,378 @@ static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
}
}
-static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+static void do_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ smooth(sd, ss, nodes, totnode, ss->cache->bstrength);
+}
+
+static void do_draw_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
Brush *brush = paint_brush(&sd->paint);
+ float offset[3], area_normal[3];
float bstrength= ss->cache->bstrength;
int n;
- //#pragma omp parallel for private(n) schedule(static)
+ calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
+
+ /* offset with as much as possible factored in already */
+ mul_v3_v3fl(offset, area_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* threaded loop over nodes */
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
-
- sculpt_undo_push_node(ss, nodes[n]);
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test(&test, vd.co)) {
+ //if(sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, area_normal)) {
+ /* offset vertex */
+ float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], offset, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_crease_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ float offset[3], area_normal[3];
+ float bstrength= ss->cache->bstrength;
+ float flippedbstrength, crease_correction;
+ int n;
+
+ calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
+
+ /* offset with as much as possible factored in already */
+ mul_v3_v3fl(offset, area_normal, ss->cache->radius);
+ mul_v3_v3(offset, ss->cache->scale);
+ mul_v3_fl(offset, bstrength);
+
+ /* we divide out the squared alpha and multiply by the squared crease to give us the pinch strength */
+
+ if(sculpt_get_brush_alpha(brush) > 0.0f)
+ crease_correction = brush->crease_pinch_factor*brush->crease_pinch_factor/(sculpt_get_brush_alpha(brush)*sculpt_get_brush_alpha(brush));
+ else
+ crease_correction = brush->crease_pinch_factor*brush->crease_pinch_factor;
+
+ /* we always want crease to pinch or blob to relax even when draw is negative */
+ flippedbstrength = (bstrength < 0) ? -crease_correction*bstrength : crease_correction*bstrength;
+
+ if(brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
+
+ /* threaded loop over nodes */
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
- float val[3]= {vd.co[0]+(test.location[0]-vd.co[0])*fade,
- vd.co[1]+(test.location[1]-vd.co[1])*fade,
- vd.co[2]+(test.location[2]-vd.co[2])*fade};
+ /* offset vertex */
+ const float fade = tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
+ float val1[3];
+ float val2[3];
+
+ /* first we pinch */
+ sub_v3_v3v3(val1, test.location, vd.co);
+ //mul_v3_v3(val1, ss->cache->scale);
+ mul_v3_fl(val1, fade*flippedbstrength);
- sculpt_clip(sd, ss, vd.co, val);
- if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ /* then we draw */
+ mul_v3_v3fl(val2, offset, fade);
+
+ add_v3_v3v3(proxy[vd.i], val1, val2);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_pinch_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ int n;
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ float val[3];
+
+ sub_v3_v3v3(val, test.location, vd.co);
+ mul_v3_v3fl(proxy[vd.i], val, fade);
- BLI_pbvh_node_mark_update(nodes[n]);
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
}
}
static void do_grab_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- Brush *brush = paint_brush(&sd->paint);
+ Brush *brush= paint_brush(&sd->paint);
float bstrength= ss->cache->bstrength;
- float grab_delta[3];
+ float grab_delta[3], an[3];
int n;
-
+ float len;
+
+ if (brush->normal_weight > 0)
+ calc_sculpt_normal(sd, ss, an, nodes, totnode);
+
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
- //#pragma omp parallel for private(n) schedule(static)
+ len = len_v3(grab_delta);
+
+ if (brush->normal_weight > 0) {
+ mul_v3_fl(an, len*brush->normal_weight);
+ mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
+ add_v3_v3(grab_delta, an);
+ }
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
+ SculptUndoNode* unode;
SculptBrushTest test;
float (*origco)[3];
-
- origco= sculpt_undo_push_node(ss, nodes[n])->co;
+ short (*origno)[3];
+ float (*proxy)[3];
+
+ unode= sculpt_undo_push_node(ss, nodes[n]);
+ origco= unode->co;
+ origno= unode->no;
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, origco[vd.i])) {
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_nudge_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength = ss->cache->bstrength;
+ float grab_delta[3];
+ int n;
+ float an[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ calc_sculpt_normal(sd, ss, an, nodes, totnode);
+
+ cross_v3_v3v3(tmp, an, grab_delta);
+ cross_v3_v3v3(cono, tmp, an);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_snake_hook_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength = ss->cache->bstrength;
+ float grab_delta[3], an[3];
+ int n;
+ float len;
+
+ if (brush->normal_weight > 0)
+ calc_sculpt_normal(sd, ss, an, nodes, totnode);
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ len = len_v3(grab_delta);
+
+ if (bstrength < 0)
+ negate_v3(grab_delta);
+
+ if (brush->normal_weight > 0) {
+ mul_v3_fl(an, len*brush->normal_weight);
+ mul_v3_fl(grab_delta, 1.0f - brush->normal_weight);
+ add_v3_v3(grab_delta, an);
+ }
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, vd.co)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_thumb_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+ float bstrength = ss->cache->bstrength;
+ float grab_delta[3];
+ int n;
+ float an[3];
+ float tmp[3], cono[3];
+
+ copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+
+ calc_sculpt_normal(sd, ss, an, nodes, totnode);
+
+ cross_v3_v3v3(tmp, an, grab_delta);
+ cross_v3_v3v3(cono, tmp, an);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptUndoNode* unode;
+ SculptBrushTest test;
+ float (*origco)[3];
+ short (*origno)[3];
+ float (*proxy)[3];
+
+ unode= sculpt_undo_push_node(ss, nodes[n]);
+ origco= unode->co;
+ origno= unode->no;
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, origco[vd.i])) {
- float fade = tex_strength(ss, brush, origco[vd.i], test.dist)*bstrength;
- float add[3]= {vd.co[0]+fade*grab_delta[0],
- vd.co[1]+fade*grab_delta[1],
- vd.co[2]+fade*grab_delta[2]};
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+
+ mul_v3_v3fl(proxy[vd.i], cono, fade);
- sculpt_clip(sd, ss, vd.co, add);
- if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_rotate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush= paint_brush(&sd->paint);
+ float bstrength= ss->cache->bstrength;
+ float an[3];
+ int n;
+ float m[3][3];
+ static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
+ float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
+
+ calc_sculpt_normal(sd, ss, an, nodes, totnode);
+
+ axis_angle_to_mat3(m, an, angle);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptUndoNode* unode;
+ SculptBrushTest test;
+ float (*origco)[3];
+ short (*origno)[3];
+ float (*proxy)[3];
+
+ unode= sculpt_undo_push_node(ss, nodes[n]);
+ origco= unode->co;
+ origno= unode->no;
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test(&test, origco[vd.i])) {
+ const float fade = bstrength*tex_strength(ss, brush, origco[vd.i], test.dist)*frontface(brush, an, origno[vd.i], NULL);
+
+ mul_v3_m3v3(proxy[vd.i], m, origco[vd.i]);
+ sub_v3_v3(proxy[vd.i], origco[vd.i]);
+ mul_v3_fl(proxy[vd.i], fade);
- BLI_pbvh_node_mark_update(nodes[n]);
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
}
}
@@ -1177,63 +1567,66 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int
float lim= ss->cache->radius / 4;
int n;
- if(ss->cache->flip)
+ if(bstrength < 0)
lim = -lim;
- calc_area_normal(sd, ss, area_normal, nodes, totnode);
+ calc_sculpt_normal(sd, ss, area_normal, nodes, totnode);
- offset[0]= ss->cache->scale[0]*area_normal[0];
- offset[1]= ss->cache->scale[1]*area_normal[1];
- offset[2]= ss->cache->scale[2]*area_normal[2];
+ mul_v3_v3v3(offset, ss->cache->scale, area_normal);
- //#pragma omp parallel for private(n) schedule(static)
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
SculptUndoNode *unode;
float (*origco)[3], *layer_disp;
+ //float (*proxy)[3]; // XXX layer brush needs conversion to proxy but its more complicated
+
+ //proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
unode= sculpt_undo_push_node(ss, nodes[n]);
origco=unode->co;
if(!unode->layer_disp)
- unode->layer_disp= MEM_callocN(sizeof(float)*unode->totvert, "layer disp");
+ {
+ #pragma omp critical
+ unode->layer_disp= MEM_callocN(sizeof(float)*unode->totvert, "layer disp");
+ }
+
layer_disp= unode->layer_disp;
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
+ const float fade = bstrength*ss->cache->radius*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, area_normal, vd.no, vd.fno);
float *disp= &layer_disp[vd.i];
float val[3];
-
+
*disp+= fade;
-
+
/* Don't let the displacement go past the limit */
if((lim < 0 && *disp < lim) || (lim > 0 && *disp > lim))
*disp = lim;
-
+
+ mul_v3_v3fl(val, offset, *disp);
+
if(ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
int index= vd.vert_indices[vd.i];
/* persistent base */
- val[0] = ss->layer_co[index][0] + (*disp)*offset[0];
- val[1] = ss->layer_co[index][1] + (*disp)*offset[1];
- val[2] = ss->layer_co[index][2] + (*disp)*offset[2];
+ add_v3_v3(val, ss->layer_co[index]);
}
else {
- val[0] = origco[vd.i][0] + (*disp)*offset[0];
- val[1] = origco[vd.i][1] + (*disp)*offset[1];
- val[2] = origco[vd.i][2] + (*disp)*offset[2];
+ add_v3_v3(val, origco[vd.i]);
}
sculpt_clip(sd, ss, vd.co, val);
- if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
-
- BLI_pbvh_node_mark_update(nodes[n]);
}
}
@@ -1243,177 +1636,634 @@ static void do_inflate_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, in
float bstrength= ss->cache->bstrength;
int n;
- //#pragma omp parallel for private(n) schedule(static)
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
-
- sculpt_undo_push_node(ss, nodes[n]);
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(sculpt_brush_test(&test, vd.co)) {
- float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
- float add[3];
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, ss->cache->view_normal, vd.no, vd.fno);
+ float val[3];
- if(vd.fno) copy_v3_v3(add, vd.fno);
- else normal_short_to_float_v3(add, vd.no);
+ if(vd.fno) copy_v3_v3(val, vd.fno);
+ else normal_short_to_float_v3(val, vd.no);
- mul_v3_fl(add, fade * ss->cache->radius);
- add[0]*= ss->cache->scale[0];
- add[1]*= ss->cache->scale[1];
- add[2]*= ss->cache->scale[2];
- add_v3_v3(add, vd.co);
-
- sculpt_clip(sd, ss, vd.co, add);
- if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ mul_v3_fl(val, fade * ss->cache->radius);
+ mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
BLI_pbvh_vertex_iter_end;
-
- BLI_pbvh_node_mark_update(nodes[n]);
}
}
-static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float co[3])
+static void calc_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float fc[3])
{
- float outer_dist[FLATTEN_SAMPLE_SIZE];
- float outer_co[FLATTEN_SAMPLE_SIZE][3];
- int i, n;
-
- for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
- zero_v3(outer_co[i]);
- outer_dist[i]= -1.0f;
+ int n;
+
+ float count = 0;
+
+ zero_v3(fc);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n=0; n<totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ SculptUndoNode *unode;
+ float private_fc[3] = {0.0f, 0.0f, 0.0f};
+ int private_count = 0;
+
+ unode = sculpt_undo_push_node(ss, nodes[n]);
+ sculpt_brush_test_init(ss, &test);
+
+ if(ss->cache->original) {
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
+ add_v3_v3(private_fc, vd.co);
+ private_count++;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+ else {
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test_fast(&test, vd.co)) {
+ add_v3_v3(private_fc, vd.co);
+ private_count++;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+
+ #pragma omp critical
+ {
+ add_v3_v3(fc, private_fc);
+ count += private_count;
+ }
}
-
- //#pragma omp parallel for private(n) schedule(static)
+
+ mul_v3_fl(fc, 1.0f / count);
+}
+
+/* this calculates flatten center and area normal together,
+amortizing the memory bandwidth and loop overhead to calculate both at the same time */
+static void calc_area_normal_and_flatten_center(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+{
+ int n;
+
+ // an
+ float out_flip[3] = {0.0f, 0.0f, 0.0f};
+
+ // fc
+ float count = 0;
+
+ // an
+ zero_v3(an);
+
+ // fc
+ zero_v3(fc);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
- int j;
-
- sculpt_undo_push_node(ss, nodes[n]);
+ SculptUndoNode *unode;
+ float private_an[3] = {0.0f, 0.0f, 0.0f};
+ float private_out_flip[3] = {0.0f, 0.0f, 0.0f};
+ float private_fc[3] = {0.0f, 0.0f, 0.0f};
+ int private_count = 0;
+
+ unode = sculpt_undo_push_node(ss, nodes[n]);
sculpt_brush_test_init(ss, &test);
- BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- for(j = 0; j < FLATTEN_SAMPLE_SIZE; ++j) {
- if(test.dist > outer_dist[j]) {
- copy_v3_v3(outer_co[j], vd.co);
- outer_dist[j] = test.dist;
- break;
+ if(ss->cache->original) {
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test_fast(&test, unode->co[vd.i])) {
+ // an
+ float fno[3];
+
+ normal_short_to_float_v3(fno, unode->no[vd.i]);
+ add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
+
+ // fc
+ add_v3_v3(private_fc, vd.co);
+ private_count++;
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+ else {
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if(sculpt_brush_test_fast(&test, vd.co)) {
+ // an
+ if(vd.no) {
+ float fno[3];
+
+ normal_short_to_float_v3(fno, vd.no);
+ add_norm_if(ss->cache->view_normal, private_an, private_out_flip, fno);
}
+ else {
+ add_norm_if(ss->cache->view_normal, private_an, private_out_flip, vd.fno);
+ }
+
+ // fc
+ add_v3_v3(private_fc, vd.co);
+ private_count++;
}
}
+ BLI_pbvh_vertex_iter_end;
}
- BLI_pbvh_vertex_iter_end;
- BLI_pbvh_node_mark_update(nodes[n]);
+ #pragma omp critical
+ {
+ // an
+ add_v3_v3(an, private_an);
+ add_v3_v3(out_flip, private_out_flip);
+
+ // fc
+ add_v3_v3(fc, private_fc);
+ count += private_count;
+ }
+ }
+
+ // an
+ if (is_zero_v3(an))
+ copy_v3_v3(an, out_flip);
+
+ normalize_v3(an);
+
+ // fc
+ mul_v3_fl(fc, 1.0f / count);
+}
+
+static void calc_sculpt_plane(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, float an[3], float fc[3])
+{
+ Brush *brush = paint_brush(&sd->paint);
+
+ if (ss->cache->mirror_symmetry_pass == 0 &&
+ ss->cache->radial_symmetry_pass == 0 &&
+ (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL)))
+ {
+ switch (brush->sculpt_plane) {
+ case SCULPT_DISP_DIR_VIEW:
+ viewvector(ss->cache->vc->rv3d, ss->cache->vc->rv3d->twmat[3], an);
+ break;
+
+ case SCULPT_DISP_DIR_X:
+ an[1] = 0.0;
+ an[2] = 0.0;
+ an[0] = 1.0;
+ break;
+
+ case SCULPT_DISP_DIR_Y:
+ an[0] = 0.0;
+ an[2] = 0.0;
+ an[1] = 1.0;
+ break;
+
+ case SCULPT_DISP_DIR_Z:
+ an[0] = 0.0;
+ an[1] = 0.0;
+ an[2] = 1.0;
+ break;
+
+ case SCULPT_DISP_DIR_AREA:
+ calc_area_normal_and_flatten_center(sd, ss, nodes, totnode, an, fc);
+
+ default:
+ break;
+ }
+
+ // fc
+ /* flatten center has not been calculated yet if we are not using the area normal */
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA)
+ calc_flatten_center(sd, ss, nodes, totnode, fc);
+
+ // an
+ copy_v3_v3(ss->cache->last_area_normal, an);
+
+ // fc
+ copy_v3_v3(ss->cache->last_center, fc);
+ }
+ else {
+ // an
+ copy_v3_v3(an, ss->cache->last_area_normal);
+
+ // fc
+ copy_v3_v3(fc, ss->cache->last_center);
+
+ // an
+ flip_coord(an, an, ss->cache->mirror_symmetry_pass);
+
+ // fc
+ flip_coord(fc, fc, ss->cache->mirror_symmetry_pass);
+
+ // an
+ mul_m4_v3(ss->cache->symm_rot_mat, an);
+
+ // fc
+ mul_m4_v3(ss->cache->symm_rot_mat, fc);
}
-
- co[0] = co[1] = co[2] = 0.0f;
- for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
- if(outer_dist[i] >= 0.0f)
- add_v3_v3(co, outer_co[i]);
- mul_v3_fl(co, 1.0f / FLATTEN_SAMPLE_SIZE);
}
/* Projects a point onto a plane along the plane's normal */
static void point_plane_project(float intr[3], float co[3], float plane_normal[3], float plane_center[3])
{
- float p1[3], sub1[3], sub2[3];
+ sub_v3_v3v3(intr, co, plane_center);
+ mul_v3_v3fl(intr, plane_normal, dot_v3v3(plane_normal, intr));
+ sub_v3_v3v3(intr, co, intr);
+}
- /* Find the intersection between squash-plane and vertex (along the area normal) */
- sub_v3_v3v3(p1, co, plane_normal);
- sub_v3_v3v3(sub1, plane_center, p1);
- sub_v3_v3v3(sub2, co, p1);
- sub_v3_v3v3(intr, co, p1);
- mul_v3_fl(intr, dot_v3v3(plane_normal, sub1) / dot_v3v3(plane_normal, sub2));
- add_v3_v3(intr, p1);
+static int plane_trim(StrokeCache *cache, Brush *brush, float val[3])
+{
+ return !(brush->flag & BRUSH_PLANE_TRIM) || (dot_v3v3(val, val) <= cache->radius_squared*cache->plane_trim_squared);
}
-static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3], int flip)
+static int plane_point_side_flip(float co[3], float plane_normal[3], float plane_center[3], int flip)
{
- float delta[3];
- float d;
+ float delta[3];
+ float d;
- sub_v3_v3v3(delta, co, plane_center);
- d = dot_v3v3(plane_normal, delta);
+ sub_v3_v3v3(delta, co, plane_center);
+ d = dot_v3v3(plane_normal, delta);
- if(flip)
- d = -d;
+ if (flip) d = -d;
+
+ return d <= 0.0f;
+}
+
+static int plane_point_side(float co[3], float plane_normal[3], float plane_center[3])
+{
+ float delta[3];
+
+ sub_v3_v3v3(delta, co, plane_center);
+ return dot_v3v3(plane_normal, delta) <= 0.0f;
+}
+
+static float get_offset(Sculpt *sd, SculptSession *ss)
+{
+ Brush* brush = paint_brush(&sd->paint);
+
+ float rv = brush->plane_offset;
+
+ if (brush->flag & BRUSH_OFFSET_PRESSURE) {
+ rv *= ss->cache->pressure;
+ }
- return d <= 0.0f;
+ return rv;
}
-static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode, int clay)
+static void do_flatten_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
{
- /* area_normal and cntr define the plane towards which vertices are squashed */
Brush *brush = paint_brush(&sd->paint);
- float bstrength= ss->cache->bstrength;
- float area_normal[3];
- float cntr[3], cntr2[3] = {0}, bstr = 0;
- int n, flip = 0;
- calc_area_normal(sd, ss, area_normal, nodes, totnode);
- calc_flatten_center(sd, ss, nodes, totnode, cntr);
+ float bstrength = ss->cache->bstrength;
+ const float radius = ss->cache->radius;
+
+ float an[3];
+ float fc[3];
+
+ float offset = get_offset(sd, ss);
+
+ float displace;
+
+ int n;
+
+ float temp[3];
+
+ calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+
+ displace = radius*offset;
+
+ mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(fc, temp);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for(n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ float intr[3];
+ float val[3];
+
+ point_plane_project(intr, vd.co, an, fc);
- if(clay) {
- bstr= brush_strength(sd, ss->cache);
- /* Limit clay application to here */
- cntr2[0]=cntr[0]+area_normal[0]*bstr*ss->cache->scale[0];
- cntr2[1]=cntr[1]+area_normal[1]*bstr*ss->cache->scale[1];
- cntr2[2]=cntr[2]+area_normal[2]*bstr*ss->cache->scale[2];
- flip = bstr < 0;
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
}
+}
- //#pragma omp parallel for private(n) schedule(static)
- for(n=0; n<totnode; n++) {
+static void do_clay_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+
+ float bstrength = ss->cache->bstrength;
+ float radius = ss->cache->radius;
+ float offset = get_offset(sd, ss);
+
+ float displace;
+
+ float an[3]; // area normal
+ float fc[3]; // flatten center
+
+ int n;
+
+ float temp[3];
+ //float p[3];
+
+ int flip;
+
+ calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+
+ flip = bstrength < 0;
+
+ if (flip) {
+ bstrength = -bstrength;
+ radius = -radius;
+ }
+
+ displace = radius * (0.25f+offset);
+
+ mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(fc, temp);
+
+ //add_v3_v3v3(p, ss->cache->location, an);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
SculptBrushTest test;
-
- sculpt_undo_push_node(ss, nodes[n]);
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
sculpt_brush_test_init(ss, &test);
BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
- if(sculpt_brush_test(&test, vd.co)) {
- float intr[3], val[3];
-
- if(!clay || plane_point_side(vd.co, area_normal, cntr2, flip)) {
- const float fade = tex_strength(ss, brush, vd.co, test.dist)*bstrength;
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (plane_point_side_flip(vd.co, an, fc, flip)) {
+ //if (sculpt_brush_test_cyl(&test, vd.co, ss->cache->location, p)) {
+ float intr[3];
+ float val[3];
+
+ point_plane_project(intr, vd.co, an, fc);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_clay_tubes_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+
+ float bstrength = ss->cache->bstrength;
+ float radius = ss->cache->radius;
+ float offset = get_offset(sd, ss);
+
+ float displace;
+
+ float sn[3]; // sculpt normal
+ float an[3]; // area normal
+ float fc[3]; // flatten center
+
+ int n;
+
+ float temp[3];
+ float mat[4][4];
+ float scale[4][4];
+ float tmat[4][4];
+
+ int flip;
+
+ calc_sculpt_plane(sd, ss, nodes, totnode, sn, fc);
+
+ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL))
+ calc_area_normal(sd, ss, an, nodes, totnode);
+ else
+ copy_v3_v3(an, sn);
- /* Find the intersection between squash-plane and vertex (along the area normal) */
- point_plane_project(intr, vd.co, area_normal, cntr);
+ if (ss->cache->first_time)
+ return; // delay the first daub because grab delta is not setup
+
+ flip = bstrength < 0;
+
+ if (flip) {
+ bstrength = -bstrength;
+ radius = -radius;
+ }
+
+ displace = radius * (0.25f+offset);
+
+ mul_v3_v3v3(temp, sn, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(fc, temp);
+
+ cross_v3_v3v3(mat[0], an, ss->cache->grab_delta_symmetry); mat[0][3] = 0;
+ cross_v3_v3v3(mat[1], an, mat[0]); mat[1][3] = 0;
+ copy_v3_v3(mat[2], an); mat[2][3] = 0;
+ copy_v3_v3(mat[3], ss->cache->location); mat[3][3] = 1;
+ normalize_m4(mat);
+ scale_m4_fl(scale, ss->cache->radius);
+ mul_m4_m4m4(tmat, scale, mat);
+ invert_m4_m4(mat, tmat);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test_cube(&test, vd.co, mat)) {
+ if (plane_point_side_flip(vd.co, sn, fc, flip)) {
+ float intr[3];
+ float val[3];
+
+ point_plane_project(intr, vd.co, sn, fc);
sub_v3_v3v3(val, intr, vd.co);
- if(clay) {
- if(bstr > FLT_EPSILON)
- mul_v3_fl(val, fade / bstr);
- else
- mul_v3_fl(val, fade);
- /* Clay displacement */
- val[0]+=area_normal[0] * ss->cache->scale[0]*fade;
- val[1]+=area_normal[1] * ss->cache->scale[1]*fade;
- val[2]+=area_normal[2] * ss->cache->scale[2]*fade;
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, ss->cache->radius*test.dist)*frontface(brush, an, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
- else
- mul_v3_fl(val, fabs(fade));
+ }
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_fill_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
- add_v3_v3(val, vd.co);
+ float bstrength = ss->cache->bstrength;
+ const float radius = ss->cache->radius;
- sculpt_clip(sd, ss, vd.co, val);
- if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ float an[3];
+ float fc[3];
+ float offset = get_offset(sd, ss);
+
+ float displace;
+
+ int n;
+
+ float temp[3];
+
+ calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+
+ displace = radius*offset;
+
+ mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(fc, temp);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (plane_point_side(vd.co, an, fc)) {
+ float intr[3];
+ float val[3];
+
+ point_plane_project(intr, vd.co, an, fc);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
}
}
}
BLI_pbvh_vertex_iter_end;
+ }
+}
+
+static void do_scrape_brush(Sculpt *sd, SculptSession *ss, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = paint_brush(&sd->paint);
+
+ float bstrength = ss->cache->bstrength;
+ const float radius = ss->cache->radius;
+
+ float an[3];
+ float fc[3];
+ float offset = get_offset(sd, ss);
- BLI_pbvh_node_mark_update(nodes[n]);
+ float displace;
+
+ int n;
+
+ float temp[3];
+
+ calc_sculpt_plane(sd, ss, nodes, totnode, an, fc);
+
+ displace = -radius*offset;
+
+ mul_v3_v3v3(temp, an, ss->cache->scale);
+ mul_v3_fl(temp, displace);
+ add_v3_v3(fc, temp);
+
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ SculptBrushTest test;
+ float (*proxy)[3];
+
+ proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co;
+
+ sculpt_brush_test_init(ss, &test);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ if (sculpt_brush_test_sq(&test, vd.co)) {
+ if (!plane_point_side(vd.co, an, fc)) {
+ float intr[3];
+ float val[3];
+
+ point_plane_project(intr, vd.co, an, fc);
+
+ sub_v3_v3v3(val, intr, vd.co);
+
+ if (plane_trim(ss->cache, brush, val)) {
+ const float fade = bstrength*tex_strength(ss, brush, vd.co, sqrt(test.dist))*frontface(brush, an, vd.no, vd.fno);
+
+ mul_v3_v3fl(proxy[vd.i], val, fade);
+
+ if(vd.mvert)
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BLI_pbvh_vertex_iter_end;
}
}
-static void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
+void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
{
Mesh *me= (Mesh*)ob->data;
float (*ofs)[3]= NULL;
@@ -1475,36 +2325,27 @@ static void sculpt_update_keyblock(SculptSession *ss)
}
}
-static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
+static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush)
{
SculptSearchSphereData data;
- Brush *brush = paint_brush(&sd->paint);
- PBVHNode **nodes= NULL;
- int totnode;
+ PBVHNode **nodes = NULL;
+ int n, totnode;
+ /* Build a list of all nodes that are potentially within the brush's area of influence */
data.ss = ss;
data.sd = sd;
- data.radius_squared = ss->cache->radius * ss->cache->radius;
-
- /* Build a list of all nodes that are potentially within the brush's
- area of influence */
- if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- data.original= 1;
- BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data,
- &nodes, &totnode);
-
- if(cache->first_time)
- copy_v3_v3(ss->cache->grab_active_location[ss->cache->symmetry], ss->cache->location);
- else
- copy_v3_v3(ss->cache->location, ss->cache->grab_active_location[ss->cache->symmetry]);
- }
- else {
- BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data,
- &nodes, &totnode);
- }
+ data.radius_squared = ss->cache->radius_squared;
+ data.original = ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB, SCULPT_TOOL_LAYER);
+ BLI_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
/* Only act if some verts are inside the brush area */
- if(totnode) {
+ if (totnode) {
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n= 0; n < totnode; n++) {
+ sculpt_undo_push_node(ss, nodes[n]);
+ BLI_pbvh_node_mark_update(nodes[n]);
+ }
+
/* Apply one type of brush action */
switch(brush->sculpt_tool){
case SCULPT_TOOL_DRAW:
@@ -1513,6 +2354,12 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
case SCULPT_TOOL_SMOOTH:
do_smooth_brush(sd, ss, nodes, totnode);
break;
+ case SCULPT_TOOL_CREASE:
+ do_crease_brush(sd, ss, nodes, totnode);
+ break;
+ case SCULPT_TOOL_BLOB:
+ do_crease_brush(sd, ss, nodes, totnode);
+ break;
case SCULPT_TOOL_PINCH:
do_pinch_brush(sd, ss, nodes, totnode);
break;
@@ -1522,57 +2369,244 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, StrokeCache *cache)
case SCULPT_TOOL_GRAB:
do_grab_brush(sd, ss, nodes, totnode);
break;
+ case SCULPT_TOOL_ROTATE:
+ do_rotate_brush(sd, ss, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SNAKE_HOOK:
+ do_snake_hook_brush(sd, ss, nodes, totnode);
+ break;
+ case SCULPT_TOOL_NUDGE:
+ do_nudge_brush(sd, ss, nodes, totnode);
+ break;
+ case SCULPT_TOOL_THUMB:
+ do_thumb_brush(sd, ss, nodes, totnode);
+ break;
case SCULPT_TOOL_LAYER:
do_layer_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_FLATTEN:
- do_flatten_clay_brush(sd, ss, nodes, totnode, 0);
+ do_flatten_brush(sd, ss, nodes, totnode);
break;
case SCULPT_TOOL_CLAY:
- do_flatten_clay_brush(sd, ss, nodes, totnode, 1);
+ do_clay_brush(sd, ss, nodes, totnode);
+ break;
+ case SCULPT_TOOL_CLAY_TUBES:
+ do_clay_tubes_brush(sd, ss, nodes, totnode);
+ break;
+ case SCULPT_TOOL_FILL:
+ do_fill_brush(sd, ss, nodes, totnode);
+ break;
+ case SCULPT_TOOL_SCRAPE:
+ do_scrape_brush(sd, ss, nodes, totnode);
break;
}
+ if (brush->sculpt_tool != SCULPT_TOOL_SMOOTH && brush->autosmooth_factor > 0) {
+ if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
+ smooth(sd, ss, nodes, totnode, brush->autosmooth_factor*(1-ss->cache->pressure)*ss->cache->autosmooth_overlap);
+ }
+ else {
+ smooth(sd, ss, nodes, totnode, brush->autosmooth_factor*ss->cache->autosmooth_overlap);
+ }
+ }
+
+ /* copy the modified vertices from mesh to the active key */
+ if(ss->kb)
+ mesh_to_key(ss->ob->data, ss->kb);
+
/* optimization: we could avoid copying new coords to keyblock at each */
/* stroke step if there are no modifiers due to pbvh is used for displaying */
/* so to increase speed we'll copy new coords to keyblock when stroke is done */
if(ss->kb && ss->modifiers_active) sculpt_update_keyblock(ss);
- if(nodes)
- MEM_freeN(nodes);
+ MEM_freeN(nodes);
+ }
+}
+
+static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss)
+{
+ Brush *brush= paint_brush(&sd->paint);
+ PBVHNode** nodes;
+ int totnode;
+ int n;
+
+ BLI_pbvh_gather_proxies(ss->pbvh, &nodes, &totnode);
+
+ switch (brush->sculpt_tool) {
+ case SCULPT_TOOL_GRAB:
+ case SCULPT_TOOL_ROTATE:
+ case SCULPT_TOOL_THUMB:
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n= 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ PBVHProxyNode* proxies;
+ int proxy_count;
+ float (*origco)[3];
+
+ origco= sculpt_undo_push_node(ss, nodes[n])->co;
+
+ BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ float val[3];
+ int p;
+
+ copy_v3_v3(val, origco[vd.i]);
+
+ for (p= 0; p < proxy_count; p++)
+ add_v3_v3(val, proxies[p].co[vd.i]);
+
+ sculpt_clip(sd, ss, vd.co, val);
+ }
+ BLI_pbvh_vertex_iter_end;
+
+ BLI_pbvh_node_free_proxies(nodes[n]);
+ }
+
+ break;
+
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_TUBES:
+ case SCULPT_TOOL_CREASE:
+ case SCULPT_TOOL_BLOB:
+ case SCULPT_TOOL_FILL:
+ case SCULPT_TOOL_FLATTEN:
+ case SCULPT_TOOL_INFLATE:
+ case SCULPT_TOOL_NUDGE:
+ case SCULPT_TOOL_PINCH:
+ case SCULPT_TOOL_SCRAPE:
+ case SCULPT_TOOL_SNAKE_HOOK:
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+ for (n= 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ PBVHProxyNode* proxies;
+ int proxy_count;
+
+ BLI_pbvh_node_get_proxies(nodes[n], &proxies, &proxy_count);
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
+ float val[3];
+ int p;
+
+ copy_v3_v3(val, vd.co);
+
+ for (p= 0; p < proxy_count; p++)
+ add_v3_v3(val, proxies[p].co[vd.i]);
+
+ sculpt_clip(sd, ss, vd.co, val);
+ }
+ BLI_pbvh_vertex_iter_end;
+
+ BLI_pbvh_node_free_proxies(nodes[n]);
+
+ }
+
+ break;
+
+ case SCULPT_TOOL_SMOOTH:
+ case SCULPT_TOOL_LAYER:
+ default:
+ break;
}
+
+ if (nodes)
+ MEM_freeN(nodes);
}
+//static int max_overlap_count(Sculpt *sd)
+//{
+// int count[3];
+// int i, j;
+//
+// for (i= 0; i < 3; i++) {
+// count[i] = sd->radial_symm[i];
+//
+// for (j= 0; j < 3; j++) {
+// if (i != j && sd->flags & (SCULPT_SYMM_X<<i))
+// count[i] *= 2;
+// }
+// }
+//
+// return MAX3(count[0], count[1], count[2]);
+//}
+
/* Flip all the editdata across the axis/axes specified by symm. Used to
calculate multiple modifications to the mesh when symmetry is enabled. */
-static void calc_brushdata_symm(StrokeCache *cache, const char symm)
+static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm, const char axis, const float angle, const float feather)
{
flip_coord(cache->location, cache->true_location, symm);
- flip_coord(cache->view_normal_symmetry, cache->view_normal, symm);
flip_coord(cache->grab_delta_symmetry, cache->grab_delta, symm);
- cache->symmetry= symm;
+ flip_coord(cache->view_normal, cache->true_view_normal, symm);
+
+ // XXX This reduces the length of the grab delta if it approaches the line of symmetry
+ // XXX However, a different approach appears to be needed
+ //if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
+ // float frac = 1.0f/max_overlap_count(sd);
+ // float reduce = (feather-frac)/(1-frac);
+
+ // printf("feather: %f frac: %f reduce: %f\n", feather, frac, reduce);
+
+ // if (frac < 1)
+ // mul_v3_fl(cache->grab_delta_symmetry, reduce);
+ //}
+
+ unit_m4(cache->symm_rot_mat);
+ unit_m4(cache->symm_rot_mat_inv);
+ rotate_m4(cache->symm_rot_mat, axis, angle);
+ rotate_m4(cache->symm_rot_mat_inv, axis, -angle);
+
+ mul_m4_v3(cache->symm_rot_mat, cache->location);
+ mul_m4_v3(cache->symm_rot_mat, cache->grab_delta_symmetry);
+}
+
+static void do_radial_symmetry(Sculpt *sd, SculptSession *ss, Brush *brush, const char symm, const int axis, const float feather)
+{
+ int i;
+
+ for(i = 1; i < sd->radial_symm[axis-'X']; ++i) {
+ const float angle = 2*M_PI*i/sd->radial_symm[axis-'X'];
+ ss->cache->radial_symmetry_pass= i;
+ calc_brushdata_symm(sd, ss->cache, symm, axis, angle, feather);
+ do_brush_action(sd, ss, brush);
+ }
}
static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
{
+ Brush *brush = paint_brush(&sd->paint);
StrokeCache *cache = ss->cache;
const char symm = sd->flags & 7;
int i;
- copy_v3_v3(cache->location, cache->true_location);
- copy_v3_v3(cache->grab_delta_symmetry, cache->grab_delta);
- cache->symmetry = 0;
- cache->bstrength = brush_strength(sd, cache);
- do_brush_action(sd, ss, cache);
+ float feather = calc_symmetry_feather(sd, ss->cache);
+ float accum = integrate_overlap(brush);
+ float overlap = (brush->flag & BRUSH_SPACE_ATTEN && brush->flag & BRUSH_SPACE && !(brush->flag & BRUSH_ANCHORED)) && (brush->spacing < 100) ? 1.0f/accum : 1; // spacing is integer percentage of radius, divide by 50 to get normalized diameter
+
+ ss->cache->autosmooth_overlap = overlap;
+
+ cache->bstrength= brush_strength(sd, cache, feather, overlap);
+
+ cache->symmetry= symm;
+
+ /* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
+ for(i = 0; i <= symm; ++i) {
+ if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
+ cache->mirror_symmetry_pass= i;
+ cache->radial_symmetry_pass= 0;
- for(i = 1; i <= symm; ++i) {
- if(symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5))) {
- calc_brushdata_symm(cache, i);
- do_brush_action(sd, ss, cache);
+ calc_brushdata_symm(sd, cache, i, 0, 0, feather);
+ do_brush_action(sd, ss, brush);
+
+ do_radial_symmetry(sd, ss, brush, i, 'X', feather);
+ do_radial_symmetry(sd, ss, brush, i, 'Y', feather);
+ do_radial_symmetry(sd, ss, brush, i, 'Z', feather);
}
}
- cache->first_time = 0;
+ sculpt_combine_proxies(sd, ss);
+
+ cache->first_time= 0;
}
static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
@@ -1585,37 +2619,13 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
}
/* Need to allocate a bigger buffer for bigger brush size */
- ss->texcache_side = brush->size * 2;
+ ss->texcache_side = 2*sculpt_get_brush_size(brush);
if(!ss->texcache || ss->texcache_side > ss->texcache_actual) {
- ss->texcache = brush_gen_texture_cache(brush, brush->size);
+ ss->texcache = brush_gen_texture_cache(brush, sculpt_get_brush_size(brush));
ss->texcache_actual = ss->texcache_side;
}
}
-/* Sculpt mode handles multires differently from regular meshes, but only if
- it's the last modifier on the stack and it is not on the first level */
-struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
-{
- ModifierData *md, *nmd;
-
- for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
- if(md->type == eModifierType_Multires) {
- MultiresModifierData *mmd= (MultiresModifierData*)md;
-
- /* Check if any of the modifiers after multires are active
- * if not it can use the multires struct */
- for(nmd= md->next; nmd; nmd= nmd->next)
- if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
- break;
-
- if(!nmd && mmd->sculptlvl > 0)
- return mmd;
- }
- }
-
- return NULL;
-}
-
void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
@@ -1682,16 +2692,32 @@ static char *sculpt_tool_name(Sculpt *sd)
return "Draw Brush"; break;
case SCULPT_TOOL_SMOOTH:
return "Smooth Brush"; break;
+ case SCULPT_TOOL_CREASE:
+ return "Crease Brush"; break;
+ case SCULPT_TOOL_BLOB:
+ return "Blob Brush"; break;
case SCULPT_TOOL_PINCH:
return "Pinch Brush"; break;
case SCULPT_TOOL_INFLATE:
return "Inflate Brush"; break;
case SCULPT_TOOL_GRAB:
return "Grab Brush"; break;
+ case SCULPT_TOOL_NUDGE:
+ return "Nudge Brush"; break;
+ case SCULPT_TOOL_THUMB:
+ return "Thumb Brush"; break;
case SCULPT_TOOL_LAYER:
return "Layer Brush"; break;
case SCULPT_TOOL_FLATTEN:
- return "Flatten Brush"; break;
+ return "Flatten Brush"; break;
+ case SCULPT_TOOL_CLAY:
+ return "Clay Brush"; break;
+ case SCULPT_TOOL_CLAY_TUBES:
+ return "Clay Tubes Brush"; break;
+ case SCULPT_TOOL_FILL:
+ return "Fill Brush"; break;
+ case SCULPT_TOOL_SCRAPE:
+ return "Scrape Brush"; break;
default:
return "Sculpting"; break;
}
@@ -1769,20 +2795,119 @@ static void sculpt_cache_free(StrokeCache *cache)
MEM_freeN(cache);
}
+int sculpt_get_brush_size(Brush *brush)
+{
+ return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) ? U.sculpt_paint_unified_size : brush->size;
+}
+
+void sculpt_set_brush_size(Brush *brush, int size)
+{
+ if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE)
+ U.sculpt_paint_unified_size = size;
+ else
+ brush->size = size;
+}
+
+int sculpt_get_lock_brush_size(Brush *brush)
+{
+ return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) ? (U.sculpt_paint_settings & SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE) : (brush->flag & BRUSH_LOCK_SIZE);
+}
+
+float sculpt_get_brush_unprojected_radius(Brush *brush)
+{
+ return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE) ? U.sculpt_paint_unified_unprojected_radius : brush->unprojected_radius;
+}
+
+void sculpt_set_brush_unprojected_radius(Brush *brush, float unprojected_radius)
+{
+ if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_SIZE)
+ U.sculpt_paint_unified_unprojected_radius = unprojected_radius;
+ else
+ brush->unprojected_radius = unprojected_radius;
+}
+
+float sculpt_get_brush_alpha(Brush *brush)
+{
+ return (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_ALPHA) ? U.sculpt_paint_unified_alpha : brush->alpha;
+}
+
+void sculpt_set_brush_alpha(Brush *brush, float alpha)
+{
+ if (U.sculpt_paint_settings & SCULPT_PAINT_USE_UNIFIED_ALPHA)
+ U.sculpt_paint_unified_alpha = alpha;
+ else
+ brush->alpha = alpha;
+}
+
/* Initialize the stroke cache invariants from operator properties */
-static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bContext *C, wmOperator *op)
+static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSession *ss, wmOperator *op, wmEvent *event)
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
Brush *brush = paint_brush(&sd->paint);
ViewContext *vc = paint_stroke_view_context(op->customdata);
+ Object *ob= CTX_data_active_object(C);
+ ModifierData *md;
int i;
+ int mode;
ss->cache = cache;
- RNA_float_get_array(op->ptr, "scale", cache->scale);
- cache->flag = RNA_int_get(op->ptr, "flag");
- RNA_float_get_array(op->ptr, "clip_tolerance", cache->clip_tolerance);
- RNA_float_get_array(op->ptr, "initial_mouse", cache->initial_mouse);
+ /* Set scaling adjustment */
+ ss->cache->scale[0] = 1.0f / ob->size[0];
+ ss->cache->scale[1] = 1.0f / ob->size[1];
+ ss->cache->scale[2] = 1.0f / ob->size[2];
+
+ ss->cache->plane_trim_squared = brush->plane_trim * brush->plane_trim;
+
+ /* Initialize mirror modifier clipping */
+
+ ss->cache->flag = 0;
+
+ for(md= ob->modifiers.first; md; md= md->next) {
+ if(md->type==eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
+ const MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ /* Mark each axis that needs clipping along with its tolerance */
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ ss->cache->flag |= CLIP_X << mmd->axis;
+ if(mmd->tolerance > ss->cache->clip_tolerance[mmd->axis])
+ ss->cache->clip_tolerance[mmd->axis] = mmd->tolerance;
+ }
+ }
+ }
+
+ /* Initial mouse location */
+ if (event) {
+ ss->cache->initial_mouse[0] = event->x;
+ ss->cache->initial_mouse[1] = event->y;
+ }
+ else {
+ ss->cache->initial_mouse[0] = 0;
+ ss->cache->initial_mouse[1] = 0;
+ }
+
+ mode = RNA_int_get(op->ptr, "mode");
+ cache->invert = mode == WM_BRUSHSTROKE_INVERT;
+ cache->alt_smooth = mode == WM_BRUSHSTROKE_SMOOTH;
+
+ /* Alt-Smooth */
+ if (ss->cache->alt_smooth) {
+ Paint *p= &sd->paint;
+ Brush *br;
+ int i;
+
+ BLI_strncpy(cache->saved_active_brush_name, brush->id.name+2, sizeof(cache->saved_active_brush_name));
+
+ for(i = 0; i < p->brush_count; ++i) {
+ br = p->brushes[i];
+
+ if (strcmp(br->id.name+2, "Smooth")==0) {
+ paint_brush_set(p, br);
+ brush = br;
+ break;
+ }
+ }
+ }
copy_v2_v2(cache->mouse, cache->initial_mouse);
copy_v2_v2(cache->tex_mouse, cache->initial_mouse);
@@ -1790,11 +2915,13 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
/* Truly temporary data that isn't stored in properties */
cache->vc = vc;
+
cache->brush = brush;
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, cache->mats);
+ viewvector(cache->vc->rv3d, cache->vc->rv3d->twmat[3], cache->true_view_normal);
/* Initialize layer brush displacements and persistent coords */
if(brush->sculpt_tool == SCULPT_TOOL_LAYER) {
/* not supported yet for multires */
@@ -1820,69 +2947,143 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
cache->original = 1;
}
- if(ELEM3(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE))
+ if(ELEM7(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_TUBES))
if(!(brush->flag & BRUSH_ACCUMULATE))
cache->original = 1;
- cache->rotation = 0;
- cache->first_time = 1;
+ cache->special_rotation = (brush->flag & BRUSH_RAKE) ? sd->last_angle : 0;
+ //cache->last_rake[0] = sd->last_x;
+ //cache->last_rake[1] = sd->last_y;
+
+ cache->first_time= 1;
+
+ cache->vertex_rotation= 0;
}
/* Initialize the stroke cache variants from operator properties */
-static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
+static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, SculptSession *ss, struct PaintStroke *stroke, PointerRNA *ptr)
{
StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
-
+
int dx, dy;
- if(!(brush->flag & BRUSH_ANCHORED) || cache->first_time)
+ //RNA_float_get_array(ptr, "location", cache->traced_location);
+
+ if (cache->first_time ||
+ !((brush->flag & BRUSH_ANCHORED)||
+ (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK)||
+ (brush->sculpt_tool == SCULPT_TOOL_ROTATE))
+ )
+ {
RNA_float_get_array(ptr, "location", cache->true_location);
- cache->flip = RNA_boolean_get(ptr, "flip");
+ }
+
+ cache->pen_flip = RNA_boolean_get(ptr, "pen_flip");
RNA_float_get_array(ptr, "mouse", cache->mouse);
+
cache->pressure = RNA_float_get(ptr, "pressure");
-
+
/* Truly temporary data that isn't stored in properties */
+ sd->draw_pressure= 1;
+ sd->pressure_value= cache->pressure;
+
cache->previous_pixel_radius = cache->pixel_radius;
- cache->pixel_radius = brush->size;
+ cache->pixel_radius = sculpt_get_brush_size(brush);
- if(cache->first_time)
- cache->initial_radius = unproject_brush_radius(ss->ob, cache->vc, cache->true_location, brush->size);
+ if(cache->first_time) {
+ if (!sculpt_get_lock_brush_size(brush)) {
+ cache->initial_radius= unproject_brush_radius(ss->ob, cache->vc, cache->true_location, sculpt_get_brush_size(brush));
+ sculpt_set_brush_unprojected_radius(brush, cache->initial_radius);
+ }
+ else {
+ cache->initial_radius= sculpt_get_brush_unprojected_radius(brush);
+ }
+
+ if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
+ cache->initial_radius *= 2.0f;
+ }
- if(brush->flag & BRUSH_SIZE_PRESSURE && brush->sculpt_tool != SCULPT_TOOL_GRAB) {
+ if(brush->flag & BRUSH_SIZE_PRESSURE) {
cache->pixel_radius *= cache->pressure;
- cache->radius = cache->initial_radius * cache->pressure;
+ cache->radius= cache->initial_radius * cache->pressure;
}
else
- cache->radius = cache->initial_radius;
+ cache->radius= cache->initial_radius;
- if(!(brush->flag & BRUSH_ANCHORED))
+ cache->radius_squared = cache->radius*cache->radius;
+
+ if(!(brush->flag & BRUSH_ANCHORED || ELEM4(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE))) {
copy_v2_v2(cache->tex_mouse, cache->mouse);
+ if ( (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) &&
+ (brush->flag & BRUSH_RANDOM_ROTATION) &&
+ !(brush->flag & BRUSH_RAKE))
+ {
+ cache->special_rotation = 2*M_PI*BLI_frand();
+ }
+ }
+
if(brush->flag & BRUSH_ANCHORED) {
+ int hit = 0;
+
dx = cache->mouse[0] - cache->initial_mouse[0];
dy = cache->mouse[1] - cache->initial_mouse[1];
- cache->pixel_radius = sqrt(dx*dx + dy*dy);
- cache->radius = unproject_brush_radius(ss->ob, paint_stroke_view_context(stroke),
- cache->true_location, cache->pixel_radius);
- cache->rotation = atan2(dy, dx);
+
+ sd->anchored_size = cache->pixel_radius = sqrt(dx*dx + dy*dy);
+
+ cache->special_rotation = atan2(dx, dy) + M_PI;
+
+ if (brush->flag & BRUSH_EDGE_TO_EDGE) {
+ float d[3];
+ float halfway[3];
+ float out[3];
+
+ d[0] = dx;
+ d[1] = dy;
+ d[2] = 0;
+
+ mul_v3_v3fl(halfway, d, 0.5f);
+ add_v3_v3(halfway, cache->initial_mouse);
+
+ if (sculpt_stroke_get_location(C, stroke, out, halfway)) {
+ copy_v3_v3(sd->anchored_location, out);
+ copy_v3_v3(sd->anchored_initial_mouse, halfway);
+ copy_v2_v2(cache->tex_mouse, halfway);
+ copy_v3_v3(cache->true_location, sd->anchored_location);
+ sd->anchored_size /= 2.0f;
+ cache->pixel_radius /= 2.0f;
+ hit = 1;
+ }
+ }
+
+ if (!hit)
+ copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
+
+ cache->radius= unproject_brush_radius(ss->ob, paint_stroke_view_context(stroke), cache->true_location, cache->pixel_radius);
+ cache->radius_squared = cache->radius*cache->radius;
+
+ copy_v3_v3(sd->anchored_location, cache->true_location);
+
+ sd->draw_anchored = 1;
}
else if(brush->flag & BRUSH_RAKE) {
- int update;
-
- dx = cache->last_rake[0] - cache->mouse[0];
- dy = cache->last_rake[1] - cache->mouse[1];
+ const float u = 0.5f;
+ const float v = 1 - u;
+ const float r = 20;
- update = dx*dx + dy*dy > 100;
+ const float dx = cache->last_rake[0] - cache->mouse[0];
+ const float dy = cache->last_rake[1] - cache->mouse[1];
- /* To prevent jitter, only update the angle if the mouse has moved over 10 pixels */
- if(update && !cache->first_time)
- cache->rotation = M_PI_2 + atan2(dy, dx);
+ if (cache->first_time) {
+ copy_v3_v3(cache->last_rake, cache->mouse);
+ }
+ else if (dx*dx + dy*dy >= r*r) {
+ cache->special_rotation = atan2(dx, dy);
- if(update || cache->first_time) {
- cache->last_rake[0] = cache->mouse[0];
- cache->last_rake[1] = cache->mouse[1];
+ cache->last_rake[0] = u*cache->last_rake[0] + v*cache->mouse[0];
+ cache->last_rake[1] = u*cache->last_rake[1] + v*cache->mouse[1];
}
}
@@ -1900,16 +3101,123 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, struct P
/* compute delta to move verts by */
if(!cache->first_time) {
+ float delta[3];
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+
+ /* location stays the same for finding vertices in brush radius */
+ copy_v3_v3(cache->true_location, cache->orig_grab_location);
+
+ sd->draw_anchored = 1;
+ copy_v3_v3(sd->anchored_location, cache->true_location);
+ copy_v3_v3(sd->anchored_initial_mouse, cache->initial_mouse);
+ sd->anchored_size = cache->pixel_radius;
+ }
+ /* Find the nudge/clay tubes delta */
+ else if(brush->sculpt_tool == SCULPT_TOOL_NUDGE || brush->sculpt_tool == SCULPT_TOOL_CLAY_TUBES) {
+ float grab_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
+ cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
invert_m4_m4(imat, ss->ob->obmat);
mul_mat3_m4_v3(imat, cache->grab_delta);
}
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+ }
+ /* Find the snake hook delta */
+ else if(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) {
+ float grab_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+ else
+ add_v3_v3(cache->true_location, cache->grab_delta);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
+ cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, cache->grab_delta);
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
+
+ copy_v3_v3(cache->old_grab_location, grab_location);
+ }
+ /* Find the thumb delta */
+ else if(brush->sculpt_tool == SCULPT_TOOL_THUMB) {
+ float grab_location[3], imat[4][4];
+
+ if(cache->first_time)
+ copy_v3_v3(cache->orig_grab_location, cache->true_location);
+
+ /* compute 3d coordinate at same z from original location + mouse */
+ initgrabz(cache->vc->rv3d, cache->orig_grab_location[0],
+ cache->orig_grab_location[1], cache->orig_grab_location[2]);
+ window_to_3d_delta(cache->vc->ar, grab_location, cache->mouse[0], cache->mouse[1]);
+
+ /* compute delta to move verts by */
+ if (!cache->first_time) {
+ float delta[3];
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ss->ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ }
+ else {
+ zero_v3(cache->grab_delta);
+ }
copy_v3_v3(cache->old_grab_location, grab_location);
/* location stays the same for finding vertices in brush radius */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
+
+ sd->draw_anchored = 1;
+ copy_v3_v3(sd->anchored_location, cache->orig_grab_location);
+ copy_v3_v3(sd->anchored_initial_mouse, cache->initial_mouse);
+ sd->anchored_size = cache->pixel_radius;
+ }
+ else if(brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
+ dx = cache->mouse[0] - cache->initial_mouse[0];
+ dy = cache->mouse[1] - cache->initial_mouse[1];
+
+ cache->vertex_rotation = -atan2(dx, dy) / 4.0f;
+
+ sd->draw_anchored = 1;
+ copy_v2_v2(sd->anchored_initial_mouse, cache->initial_mouse);
+ copy_v3_v3(sd->anchored_location, cache->true_location);
+ sd->anchored_size = cache->pixel_radius;
}
+
+ sd->special_rotation = cache->special_rotation;
}
static void sculpt_stroke_modifiers_check(bContext *C, SculptSession *ss)
@@ -1930,19 +3238,23 @@ typedef struct {
int original;
} SculptRaycastData;
-void sculpt_raycast_cb(PBVHNode *node, void *data_v)
+void sculpt_raycast_cb(PBVHNode *node, void *data_v, float* tmin)
{
- SculptRaycastData *srd = data_v;
- float (*origco)[3]= NULL;
+ if (BLI_pbvh_node_get_tmin(node) < *tmin) {
+ SculptRaycastData *srd = data_v;
+ float (*origco)[3]= NULL;
- if(srd->original && srd->ss->cache) {
- /* intersect with coordinates from before we started stroke */
- SculptUndoNode *unode= sculpt_undo_get_node(srd->ss, node);
- origco= (unode)? unode->co: NULL;
- }
+ if(srd->original && srd->ss->cache) {
+ /* intersect with coordinates from before we started stroke */
+ SculptUndoNode *unode= sculpt_undo_get_node(node);
+ origco= (unode)? unode->co: NULL;
+ }
- srd->hit |= BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco,
- srd->ray_start, srd->ray_normal, &srd->dist);
+ if (BLI_pbvh_node_raycast(srd->ss->pbvh, node, origco, srd->ray_start, srd->ray_normal, &srd->dist)) {
+ srd->hit = 1;
+ *tmin = srd->dist;
+ }
+ }
}
/* Do a raycast in the tree to find the 3d brush location
@@ -1956,10 +3268,12 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou
StrokeCache *cache= ss->cache;
float ray_start[3], ray_end[3], ray_normal[3], dist;
float obimat[4][4];
- float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
- mouse[1] - vc->ar->winrct.ymin};
+ float mval[2];
SculptRaycastData srd;
+ mval[0] = mouse[0] - vc->ar->winrct.xmin;
+ mval[1] = mouse[1] - vc->ar->winrct.ymin;
+
sculpt_stroke_modifiers_check(C, ss);
viewline(vc->ar, vc->v3d, mval, ray_start, ray_end);
@@ -1987,43 +3301,6 @@ int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float ou
return srd.hit;
}
-/* Initialize stroke operator properties */
-static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmEvent *event, SculptSession *ss)
-{
- Object *ob= CTX_data_active_object(C);
- ModifierData *md;
- float scale[3], clip_tolerance[3] = {0,0,0};
- float mouse[2];
- int flag = 0;
-
- /* Set scaling adjustment */
- scale[0] = 1.0f / ob->size[0];
- scale[1] = 1.0f / ob->size[1];
- scale[2] = 1.0f / ob->size[2];
- RNA_float_set_array(op->ptr, "scale", scale);
-
- /* Initialize mirror modifier clipping */
- for(md= ob->modifiers.first; md; md= md->next) {
- if(md->type==eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
- const MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- /* Mark each axis that needs clipping along with its tolerance */
- if(mmd->flag & MOD_MIR_CLIPPING) {
- flag |= CLIP_X << mmd->axis;
- if(mmd->tolerance > clip_tolerance[mmd->axis])
- clip_tolerance[mmd->axis] = mmd->tolerance;
- }
- }
- }
- RNA_int_set(op->ptr, "flag", flag);
- RNA_float_set_array(op->ptr, "clip_tolerance", clip_tolerance);
-
- /* Initial mouse location */
- mouse[0] = event->x;
- mouse[1] = event->y;
- RNA_float_set_array(op->ptr, "initial_mouse", mouse);
-}
-
static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
{
Scene *scene= CTX_data_scene(C);
@@ -2051,22 +3328,26 @@ static int sculpt_brush_stroke_init(bContext *C, ReportList *reports)
static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
{
- StrokeCache *cache = ss->cache;
Brush *brush = paint_brush(&sd->paint);
- int i;
/* Restore the mesh before continuing with anchored stroke */
- if(brush->flag & BRUSH_ANCHORED) {
+ if((brush->flag & BRUSH_ANCHORED) ||
+ (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_SIZE_PRESSURE)) ||
+ (brush->flag & BRUSH_RESTORE_MESH))
+ {
+ StrokeCache *cache = ss->cache;
+ int i;
+
PBVHNode **nodes;
int n, totnode;
BLI_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- //#pragma omp parallel for private(n) schedule(static)
+ #pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
for(n=0; n<totnode; n++) {
SculptUndoNode *unode;
- unode= sculpt_undo_get_node(ss, nodes[n]);
+ unode= sculpt_undo_get_node(nodes[n]);
if(unode) {
PBVHVertexIter vd;
@@ -2074,8 +3355,12 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
copy_v3_v3(vd.co, unode->co[vd.i]);
if(vd.no) VECCOPY(vd.no, unode->no[vd.i])
else normal_short_to_float_v3(vd.fno, unode->no[vd.i]);
+
+ if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
BLI_pbvh_vertex_iter_end;
+
+ BLI_pbvh_node_mark_update(nodes[n]);
}
}
@@ -2096,7 +3381,6 @@ static void sculpt_flush_update(bContext *C)
SculptSession *ss = ob->sculpt;
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
- int redraw = 0;
if(mmd)
multires_mark_as_modified(ob);
@@ -2109,14 +3393,22 @@ static void sculpt_flush_update(bContext *C)
rcti r;
BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
- redraw = sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r);
- if(redraw) {
+ if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
+ //rcti tmp;
+
r.xmin += ar->winrct.xmin + 1;
r.xmax += ar->winrct.xmin - 1;
r.ymin += ar->winrct.ymin + 1;
r.ymax += ar->winrct.ymin - 1;
-
+
+ //tmp = r;
+
+ //if (!BLI_rcti_is_empty(&ss->previous_r))
+ // BLI_union_rcti(&r, &ss->previous_r);
+
+ //ss->previous_r= tmp;
+
ss->partial_redraw = 1;
ED_region_tag_redraw_partial(ar, &r);
}
@@ -2127,9 +3419,12 @@ static void sculpt_flush_update(bContext *C)
or over the background (0) */
static int over_mesh(bContext *C, struct wmOperator *op, float x, float y)
{
- float mouse[2] = {x, y}, co[3];
-
- return (int)sculpt_stroke_get_location(C, op->customdata, co, mouse);
+ float mouse[2], co[3];
+
+ mouse[0] = x;
+ mouse[1] = y;
+
+ return sculpt_stroke_get_location(C, op->customdata, co, mouse);
}
static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
@@ -2143,11 +3438,22 @@ static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op,
ED_view3d_init_mats_rv3d(ob, CTX_wm_region_view3d(C));
- sculpt_brush_stroke_init_properties(C, op, event, ss);
+ sculpt_update_cache_invariants(C, sd, ss, op, event);
- sculpt_update_cache_invariants(sd, ss, C, op);
+ sculpt_undo_push_begin(sculpt_tool_name(sd));
- sculpt_undo_push_begin(ss, sculpt_tool_name(sd));
+#ifdef _OPENMP
+ /* If using OpenMP then create a number of threads two times the
+ number of processor cores.
+ Justification: Empirically I've found that two threads per
+ processor gives higher throughput. */
+ if (sd->flags & SCULPT_USE_OPENMP) {
+ int num_procs;
+
+ num_procs = omp_get_num_procs();
+ omp_set_num_threads(2*num_procs);
+ }
+#endif
return 1;
}
@@ -2161,7 +3467,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
SculptSession *ss = CTX_data_active_object(C)->sculpt;
sculpt_stroke_modifiers_check(C, ss);
- sculpt_update_cache_variants(sd, ss, stroke, itemptr);
+ sculpt_update_cache_variants(C, sd, ss, stroke, itemptr);
sculpt_restore_mesh(sd, ss);
do_symmetrical_brush_actions(sd, ss);
@@ -2169,19 +3475,43 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
sculpt_flush_update(C);
}
-static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
+static void sculpt_stroke_done(bContext *C, struct PaintStroke *unused)
{
Object *ob= CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ (void)unused;
+
+ // reset values used to draw brush after completing the stroke
+ sd->draw_anchored= 0;
+ sd->draw_pressure= 0;
+ sd->special_rotation= 0;
/* Finished */
if(ss->cache) {
sculpt_stroke_modifiers_check(C, ss);
+ /* Alt-Smooth */
+ if (ss->cache->alt_smooth) {
+ Paint *p= &sd->paint;
+ Brush *br;
+ int i;
+
+ for(i = 0; i < p->brush_count; ++i) {
+ br = p->brushes[i];
+
+ if (strcmp(br->id.name+2, ss->cache->saved_active_brush_name)==0) {
+ paint_brush_set(p, br);
+ break;
+ }
+ }
+ }
+
sculpt_cache_free(ss->cache);
ss->cache = NULL;
- sculpt_undo_push_end(ss);
+ sculpt_undo_push_end();
BLI_pbvh_update(ss->pbvh, PBVH_UpdateOriginalBB, NULL);
@@ -2218,6 +3548,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even
/* For tablet rotation */
ignore_background_click = RNA_boolean_get(op->ptr,
"ignore_background_click");
+
if(ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
paint_stroke_free(stroke);
return OPERATOR_PASS_THROUGH;
@@ -2242,7 +3573,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
sculpt_stroke_update_step, sculpt_stroke_done);
- sculpt_update_cache_invariants(sd, ss, C, op);
+ sculpt_update_cache_invariants(C, sd, ss, op, NULL);
paint_stroke_exec(C, op);
@@ -2254,7 +3585,12 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
- ot->flag |= OPTYPE_REGISTER;
+ static EnumPropertyItem stroke_mode_items[] = {
+ { WM_BRUSHSTROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally" },
+ { WM_BRUSHSTROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke" },
+ { WM_BRUSHSTROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke" },
+ { 0 }
+ };
/* identifiers */
ot->name= "Sculpt Mode";
@@ -2265,36 +3601,32 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
ot->modal= paint_stroke_modal;
ot->exec= sculpt_brush_stroke_exec;
ot->poll= sculpt_poll;
-
+
/* flags (sculpt does own undo? (ton) */
- ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
+ ot->flag= OPTYPE_BLOCKING;
/* properties */
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
-
- /* If the object has a scaling factor, brushes also need to be scaled
- to work as expected. */
- RNA_def_float_vector(ot->srna, "scale", 3, NULL, 0.0f, FLT_MAX, "Scale", "", 0.0f, 1000.0f);
- RNA_def_int(ot->srna, "flag", 0, 0, INT_MAX, "flag", "", 0, INT_MAX);
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement,
+ "Stroke", "");
- /* For mirror modifiers */
- RNA_def_float_vector(ot->srna, "clip_tolerance", 3, NULL, 0.0f, FLT_MAX, "clip_tolerance", "", 0.0f, 1000.0f);
-
- /* The initial 2D location of the mouse */
- RNA_def_float_vector(ot->srna, "initial_mouse", 2, NULL, INT_MIN, INT_MAX, "initial_mouse", "", INT_MIN, INT_MAX);
+ RNA_def_enum(ot->srna, "mode", stroke_mode_items, WM_BRUSHSTROKE_NORMAL,
+ "Sculpt Stroke Mode",
+ "Action taken when a sculpt stroke is made");
RNA_def_boolean(ot->srna, "ignore_background_click", 0,
"Ignore Background Click",
- "Clicks on the background don't start the stroke");
+ "Clicks on the background do not start the stroke");
}
/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
-static int sculpt_set_persistent_base(bContext *C, wmOperator *op)
+static int sculpt_set_persistent_base(bContext *C, wmOperator *unused)
{
SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ (void)unused;
+
if(ss) {
if(ss->layer_co)
MEM_freeN(ss->layer_co);
@@ -2314,7 +3646,7 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
ot->exec= sculpt_set_persistent_base;
ot->poll= sculpt_mode_poll;
- ot->flag= OPTYPE_REGISTER;
+ ot->flag= 0;//OPTYPE_REGISTER;
}
/**** Toggle operator for turning sculpt mode on or off ****/
@@ -2322,18 +3654,21 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
static void sculpt_init_session(Scene *scene, Object *ob)
{
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
+ ob->sculpt->ob = ob;
sculpt_update_mesh_elements(scene, ob, 0);
}
-static int sculpt_toggle_mode(bContext *C, wmOperator *op)
+static int sculpt_toggle_mode(bContext *C, wmOperator *unused)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
- MultiresModifierData *mmd = sculpt_multires_active(scene, ob);
+ MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
int flush_recalc= 0;
+ (void)unused;
+
/* multires in sculpt mode could have different from object mode subdivision level */
flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
/* if object has got active modifiers, it's dm could be different in sculpt mode */
@@ -2359,9 +3694,13 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
/* Create persistent sculpt mode data */
- if(!ts->sculpt)
+ if(!ts->sculpt) {
ts->sculpt = MEM_callocN(sizeof(Sculpt), "sculpt mode data");
+ /* Turn on X plane mirror symmetry by default */
+ ts->sculpt->flags |= SCULPT_SYMM_X;
+ }
+
/* Create sculpt mode session data */
if(ob->sculpt)
free_sculptsession(ob);
@@ -2388,7 +3727,7 @@ static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
ot->exec= sculpt_toggle_mode;
ot->poll= ED_operator_object_active;
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ ot->flag= 0;
}
void ED_operatortypes_sculpt()
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index c7c6833b695..a46823a0b28 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -32,6 +32,9 @@
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_pbvh.h"
struct bContext;
struct Brush;
@@ -65,8 +68,49 @@ void sculpt_stroke_free(struct SculptStroke *);
void sculpt_stroke_add_point(struct SculptStroke *, const short x, const short y);
void sculpt_stroke_apply(struct Sculpt *sd, struct SculptStroke *);
void sculpt_stroke_apply_all(struct Sculpt *sd, struct SculptStroke *);
+int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]);
/* Partial Mesh Visibility */
void sculptmode_pmv(int mode);
+/* Undo */
+
+typedef struct SculptUndoNode {
+ struct SculptUndoNode *next, *prev;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
+ void *node; /* only during push, not valid afterwards! */
+
+ float (*co)[3];
+ short (*no)[3];
+ int totvert;
+
+ /* non-multires */
+ int maxvert; /* to verify if totvert it still the same */
+ int *index; /* to restore into right location */
+
+ /* multires */
+ int maxgrid; /* same for grid */
+ int gridsize; /* same for grid */
+ int totgrid; /* to restore into right location */
+ int *grids; /* to restore into right location */
+
+ /* layer brush */
+ float *layer_disp;
+
+ /* shape keys */
+ char *shapeName[32]; /* keep size in sync with keyblock dna */
+} SculptUndoNode;
+
+SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node);
+SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
+void sculpt_undo_push_begin(char *name);
+void sculpt_undo_push_end(void);
+
+struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob);
+int sculpt_modifiers_active(Scene *scene, Object *ob);
+void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
+
+void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos);
+
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
new file mode 100644
index 00000000000..303a7686a96
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -0,0 +1,302 @@
+/*
+ * $Id: sculpt.c 29425 2010-06-12 15:05:19Z jwilkins $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implements the Sculpt Mode tools
+ *
+ */
+
+#include "BLI_math.h"
+#include "BLI_ghash.h"
+#include "BLI_threads.h"
+
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_paint.h"
+#include "BKE_mesh.h"
+#include "BKE_key.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+/************************** Undo *************************/
+
+static void update_cb(PBVHNode *node, void *unused)
+{
+ (void)unused;
+ BLI_pbvh_node_mark_update(node);
+}
+
+static void sculpt_undo_restore(bContext *C, ListBase *lb)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
+ SculptSession *ss = ob->sculpt;
+ SculptUndoNode *unode;
+ MVert *mvert;
+ MultiresModifierData *mmd;
+ int *index;
+ int i, j, update= 0;
+
+ sculpt_update_mesh_elements(scene, ob, 0);
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(!(strcmp(unode->idname, ob->id.name)==0))
+ continue;
+
+ if(unode->maxvert) {
+ char *shapeName= (char*)unode->shapeName;
+
+ /* regular mesh restore */
+ if(ss->totvert != unode->maxvert)
+ continue;
+
+ if (ss->kb && strcmp(ss->kb->name, shapeName)) {
+ /* shape key has been changed before calling undo operator */
+
+ Key *key= ob_get_key(ob);
+ KeyBlock *kb= key_get_named_keyblock(key, shapeName);
+
+ if (kb) {
+ ob->shapenr= BLI_findindex(&key->block, kb) + 1;
+ ob->shapeflag|= OB_SHAPE_LOCK;
+
+ sculpt_update_mesh_elements(scene, ob, 0);
+ WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
+ } else {
+ /* key has been removed -- skip this undo node */
+ continue;
+ }
+ }
+
+ index= unode->index;
+ mvert= ss->mvert;
+
+ if (ss->kb) {
+ float (*vertCos)[3];
+ vertCos= key_to_vertcos(ob, ss->kb);
+
+ for(i=0; i<unode->totvert; i++)
+ swap_v3_v3(vertCos[index[i]], unode->co[i]);
+
+ /* propagate new coords to keyblock */
+ sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+
+ /* pbvh uses it's own mvert array, so coords should be */
+ /* propagated to pbvh here */
+ BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
+
+ MEM_freeN(vertCos);
+ } else {
+ for(i=0; i<unode->totvert; i++) {
+ swap_v3_v3(mvert[index[i]].co, unode->co[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ else if(unode->maxgrid && dm->getGridData) {
+ /* multires restore */
+ DMGridData **grids, *grid;
+ float (*co)[3];
+ int gridsize;
+
+ if(dm->getNumGrids(dm) != unode->maxgrid)
+ continue;
+ if(dm->getGridSize(dm) != unode->gridsize)
+ continue;
+
+ grids= dm->getGridData(dm);
+ gridsize= dm->getGridSize(dm);
+
+ co = unode->co;
+ for(j=0; j<unode->totgrid; j++) {
+ grid= grids[unode->grids[j]];
+
+ for(i=0; i<gridsize*gridsize; i++, co++)
+ swap_v3_v3(grid[i].co, co[0]);
+ }
+ }
+
+ update= 1;
+ }
+
+ if(update) {
+ /* we update all nodes still, should be more clever, but also
+ needs to work correct when exiting/entering sculpt mode and
+ the nodes get recreated, though in that case it could do all */
+ BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, NULL);
+ BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL);
+
+ if((mmd=sculpt_multires_active(scene, ob)))
+ multires_mark_as_modified(ob);
+
+ if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1)
+ DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+ }
+}
+
+static void sculpt_undo_free(ListBase *lb)
+{
+ SculptUndoNode *unode;
+
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(unode->co)
+ MEM_freeN(unode->co);
+ if(unode->no)
+ MEM_freeN(unode->no);
+ if(unode->index)
+ MEM_freeN(unode->index);
+ if(unode->grids)
+ MEM_freeN(unode->grids);
+ if(unode->layer_disp)
+ MEM_freeN(unode->layer_disp);
+ }
+}
+
+SculptUndoNode *sculpt_undo_get_node(PBVHNode *node)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ SculptUndoNode *unode;
+
+ if(!lb)
+ return NULL;
+
+ for(unode=lb->first; unode; unode=unode->next)
+ if(unode->node == node)
+ return unode;
+
+ return NULL;
+}
+
+SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ Object *ob= ss->ob;
+ SculptUndoNode *unode;
+ int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
+
+ /* list is manipulated by multiple threads, so we lock */
+ BLI_lock_thread(LOCK_CUSTOM1);
+
+ if((unode= sculpt_undo_get_node(node))) {
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return unode;
+ }
+
+ unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
+ strcpy(unode->idname, ob->id.name);
+ unode->node= node;
+
+ BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
+ BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
+ &maxgrid, &gridsize, NULL, NULL);
+
+ unode->totvert= totvert;
+ /* we will use this while sculpting, is mapalloc slow to access then? */
+ unode->co= MEM_mapallocN(sizeof(float)*3*allvert, "SculptUndoNode.co");
+ unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no");
+ undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert);
+ BLI_addtail(lb, unode);
+
+ if(maxgrid) {
+ /* multires */
+ unode->maxgrid= maxgrid;
+ unode->totgrid= totgrid;
+ unode->gridsize= gridsize;
+ unode->grids= MEM_mapallocN(sizeof(int)*totgrid, "SculptUndoNode.grids");
+ }
+ else {
+ /* regular mesh */
+ unode->maxvert= ss->totvert;
+ unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index");
+ }
+
+ BLI_unlock_thread(LOCK_CUSTOM1);
+
+ /* copy threaded, hopefully this is the performance critical part */
+ {
+ PBVHVertexIter vd;
+
+ BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
+ copy_v3_v3(unode->co[vd.i], vd.co);
+ if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
+ else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
+ if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i];
+ }
+ BLI_pbvh_vertex_iter_end;
+ }
+
+ if(unode->grids)
+ memcpy(unode->grids, grids, sizeof(int)*totgrid);
+
+ /* store active shape key */
+ if(ss->kb) BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
+ else unode->shapeName[0]= '\0';
+
+ return unode;
+}
+
+void sculpt_undo_push_begin(char *name)
+{
+ undo_paint_push_begin(UNDO_PAINT_MESH, name,
+ sculpt_undo_restore, sculpt_undo_free);
+}
+
+void sculpt_undo_push_end(void)
+{
+ ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
+ SculptUndoNode *unode;
+
+ /* we don't need normals in the undo stack */
+ for(unode=lb->first; unode; unode=unode->next) {
+ if(unode->no) {
+ MEM_freeN(unode->no);
+ unode->no= NULL;
+ }
+
+ if(unode->layer_disp) {
+ MEM_freeN(unode->layer_disp);
+ unode->layer_disp= NULL;
+ }
+ }
+
+ undo_paint_push_end(UNDO_PAINT_MESH);
+}
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 357aa9dacdf..f58326239ae 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -792,7 +792,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn
uiLayoutSetContextPointer(layout, "edit_image", &imaptr);
if(!compact)
- uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL, NULL);
// XXX missing: reload, pack
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 3a264cbb259..005ebfb5b88 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -4278,7 +4278,7 @@ static void draw_actuator_sound(uiLayout *layout, PointerRNA *ptr, bContext *C)
{
uiLayout *row, *col;
- uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "sound", NULL, "SOUND_OT_open", NULL, NULL);
if (!RNA_pointer_get(ptr, "sound").data)
{
uiItemL(layout, "Select a sound from the list or load a new one", 0);
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 9b7bc9a8002..81d4e8b6b01 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -237,7 +237,7 @@ static void nla_panel_animdata (const bContext *C, Panel *pa)
/* Active Action Properties ------------------------------------- */
/* action */
row= uiLayoutRow(layout, 1);
- uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/); // XXX: need to make these operators
+ uiTemplateID(row, (bContext *)C, &adt_ptr, "action", "ACTION_OT_new", NULL, NULL /*"ACTION_OT_unlink"*/, NULL); // XXX: need to make these operators
/* extrapolation */
row= uiLayoutRow(layout, 1);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 2d111b731ad..082f3f97dfd 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -81,7 +81,7 @@
void node_buts_group(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateIDBrowse(layout, C, ptr, "nodetree", NULL, NULL, "");
+ uiTemplateIDBrowse(layout, C, ptr, "nodetree", NULL, NULL, "", NULL);
}
static void node_buts_value(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -306,7 +306,7 @@ static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA
bNode *node= ptr->data;
uiLayout *col;
- uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL);
+ uiTemplateID(layout, C, ptr, "material", "MATERIAL_OT_new", NULL, NULL, NULL);
if(!node->id) return;
@@ -467,7 +467,7 @@ static void node_composit_buts_image(uiLayout *layout, bContext *C, PointerRNA *
PointerRNA imaptr;
PropertyRNA *prop;
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, NULL);
if(!node->id) return;
@@ -504,7 +504,7 @@ static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, Point
const char *layer_name;
char scene_name[19];
- uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL);
+ uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, NULL);
if(!node->id) return;
@@ -1204,7 +1204,7 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *C, PointerRNA *pt
static void node_texture_buts_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL, NULL);
}
static void node_texture_buts_output(uiLayout *layout, bContext *C, PointerRNA *ptr)
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 488eea40500..14068fe5f47 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -69,6 +69,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "gpu_buffers.h"
#include "smoke_API.h"
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 7c3641db379..76468ada523 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -130,7 +130,7 @@ typedef struct PreviewImage {
unsigned int w[2];
unsigned int h[2];
short changed[2];
- short pad0, pad1;
+ short changed_timestamp[2];
unsigned int * rect[2];
} PreviewImage;
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 14930f85e63..3b2ce6b436e 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -33,9 +33,9 @@
#include "DNA_ID.h"
#include "DNA_texture_types.h"
-#ifndef MAX_MTEX
-#define MAX_MTEX 18
-#endif
+//#ifndef MAX_MTEX // XXX Not used?
+//#define MAX_MTEX 18
+//#endif
struct CurveMapping;
struct MTex;
@@ -43,8 +43,8 @@ struct Image;
typedef struct BrushClone {
struct Image *image; /* image for clone tool */
- float offset[2]; /* offset of clone image from canvas */
- float alpha, pad; /* transparency for drawing of clone image */
+ float offset[2]; /* offset of clone image from canvas */
+ float alpha, pad; /* transparency for drawing of clone image */
} BrushClone;
typedef struct Brush {
@@ -53,50 +53,94 @@ typedef struct Brush {
struct BrushClone clone;
struct CurveMapping *curve; /* falloff curve */
struct MTex mtex;
-
- short flag, blend; /* general purpose flag, blend mode */
- int size; /* brush diameter */
- float jitter; /* jitter the position of the brush */
- float spacing; /* spacing of paint operations */
- int smooth_stroke_radius; /* turning radius (in pixels) for smooth stroke */
- float smooth_stroke_factor; /* higher values limit fast changes in the stroke direction */
- float rate; /* paint operations / second (airbrush) */
-
- float rgb[3]; /* color */
- float alpha; /* opacity */
-
- char sculpt_tool; /* active sculpt tool */
+ struct Image *image_icon;
+
+ float normal_weight;
+
+ short blend, pad; /* blend mode */
+ int size; /* brush diameter */
+ int flag; /* general purpose flag */
+ float jitter; /* jitter the position of the brush */
+ int spacing; /* spacing of paint operations */
+ int smooth_stroke_radius; /* turning radius (in pixels) for smooth stroke */
+ float smooth_stroke_factor; /* higher values limit fast changes in the stroke direction */
+ float rate; /* paint operations / second (airbrush) */
+
+ float rgb[3]; /* color */
+ float alpha; /* opacity */
+
+ int sculpt_plane; /* the direction of movement for sculpt vertices */
+
+ float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */
+
+ char sculpt_tool; /* active sculpt tool */
char vertexpaint_tool; /* active vertex/weight paint tool/blend mode */
char imagepaint_tool; /* active image paint tool */
- char pad2;
+ char pad3;
+
+ float autosmooth_factor;
+
+ float crease_pinch_factor;
+
+ float plane_trim;
+
+ float texture_sample_bias;
+ int texture_overlay_alpha;
+
+ float unprojected_radius;
+
+ float add_col[3];
+ float sub_col[3];
} Brush;
/* Brush.flag */
-#define BRUSH_AIRBRUSH 1
-#define BRUSH_TORUS 2
-#define BRUSH_ALPHA_PRESSURE 4
-#define BRUSH_SIZE_PRESSURE 8
-#define BRUSH_JITTER_PRESSURE 16 /* was BRUSH_RAD_PRESSURE */
-#define BRUSH_SPACING_PRESSURE 32
-#define BRUSH_FIXED_TEX 64
-#define BRUSH_RAKE 128
-#define BRUSH_ANCHORED 256
-#define BRUSH_DIR_IN 512
-#define BRUSH_SPACE 1024
-#define BRUSH_SMOOTH_STROKE 2048
-#define BRUSH_PERSISTENT 4096
-#define BRUSH_ACCUMULATE 8192
-#define BRUSH_LOCK_ALPHA 16384
+#define BRUSH_AIRBRUSH (1<<0)
+#define BRUSH_TORUS (1<<1)
+#define BRUSH_ALPHA_PRESSURE (1<<2)
+#define BRUSH_SIZE_PRESSURE (1<<3)
+#define BRUSH_JITTER_PRESSURE (1<<4) /* was BRUSH_RAD_PRESSURE */
+#define BRUSH_SPACING_PRESSURE (1<<5)
+#define BRUSH_FIXED_TEX (1<<6)
+#define BRUSH_RAKE (1<<7)
+#define BRUSH_ANCHORED (1<<8)
+#define BRUSH_DIR_IN (1<<9)
+#define BRUSH_SPACE (1<<10)
+#define BRUSH_SMOOTH_STROKE (1<<11)
+#define BRUSH_PERSISTENT (1<<12)
+#define BRUSH_ACCUMULATE (1<<13)
+#define BRUSH_LOCK_ALPHA (1<<14)
+#define BRUSH_ORIGINAL_NORMAL (1<<15)
+#define BRUSH_OFFSET_PRESSURE (1<<16)
+#define BRUSH_SPACE_ATTEN (1<<18)
+#define BRUSH_ADAPTIVE_SPACE (1<<19)
+#define BRUSH_LOCK_SIZE (1<<20)
+#define BRUSH_TEXTURE_OVERLAY (1<<21)
+#define BRUSH_EDGE_TO_EDGE (1<<22)
+#define BRUSH_RESTORE_MESH (1<<23)
+#define BRUSH_INVERSE_SMOOTH_PRESSURE (1<<24)
+#define BRUSH_RANDOM_ROTATION (1<<25)
+#define BRUSH_PLANE_TRIM (1<<26)
+#define BRUSH_FRONTFACE (1<<27)
/* Brush.sculpt_tool */
-#define SCULPT_TOOL_DRAW 1
-#define SCULPT_TOOL_SMOOTH 2
-#define SCULPT_TOOL_PINCH 3
-#define SCULPT_TOOL_INFLATE 4
-#define SCULPT_TOOL_GRAB 5
-#define SCULPT_TOOL_LAYER 6
-#define SCULPT_TOOL_FLATTEN 7
-#define SCULPT_TOOL_CLAY 8
+#define SCULPT_TOOL_DRAW 1
+#define SCULPT_TOOL_SMOOTH 2
+#define SCULPT_TOOL_PINCH 3
+#define SCULPT_TOOL_INFLATE 4
+#define SCULPT_TOOL_GRAB 5
+#define SCULPT_TOOL_LAYER 6
+#define SCULPT_TOOL_FLATTEN 7
+#define SCULPT_TOOL_CLAY 8
+#define SCULPT_TOOL_FILL 9
+#define SCULPT_TOOL_SCRAPE 10
+#define SCULPT_TOOL_NUDGE 11
+#define SCULPT_TOOL_THUMB 12
+#define SCULPT_TOOL_SNAKE_HOOK 13
+#define SCULPT_TOOL_ROTATE 14
+//#define SCULPT_TOOL_WAX 15 // XXX: reuse this slot later
+#define SCULPT_TOOL_CREASE 16
+#define SCULPT_TOOL_BLOB 17
+#define SCULPT_TOOL_CLAY_TUBES 18
/* ImagePaintSettings.tool */
#define PAINT_TOOL_DRAW 0
@@ -104,5 +148,16 @@ typedef struct Brush {
#define PAINT_TOOL_SMEAR 2
#define PAINT_TOOL_CLONE 3
+/* direction that the brush displaces along */
+enum {
+ SCULPT_DISP_DIR_AREA,
+ SCULPT_DISP_DIR_VIEW,
+ SCULPT_DISP_DIR_X,
+ SCULPT_DISP_DIR_Y,
+ SCULPT_DISP_DIR_Z,
+};
+
+#define MAX_BRUSH_PIXEL_RADIUS 200
+
#endif
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
index bc35d379334..83cd7979ce7 100644
--- a/source/blender/makesdna/DNA_color_types.h
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -64,7 +64,8 @@ typedef struct CurveMap {
typedef struct CurveMapping {
int flag, cur; /* cur; for buttons, to show active curve */
- int preset, pad;
+ int preset;
+ int changed_timestamp;
rctf curr, clipr; /* current rect, clip rect (is default rect too) */
@@ -87,7 +88,9 @@ typedef enum CurveMappingPreset {
CURVE_PRESET_SHARP,
CURVE_PRESET_SMOOTH,
CURVE_PRESET_MAX,
- CURVE_PRESET_MID9
+ CURVE_PRESET_MID9,
+ CURVE_PRESET_ROUND,
+ CURVE_PRESET_ROOT,
} CurveMappingPreset;
/* histogram->mode */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index a4e9deaa7d9..3ac11eabe54 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -569,12 +569,30 @@ typedef struct Sculpt {
Paint paint;
/* For rotating around a pivot point */
- float pivot[3];
+ //float pivot[3]; XXX not used?
int flags;
/* Control tablet input */
- char tablet_size, tablet_strength;
- char pad[6];
+ //char tablet_size, tablet_strength; XXX not used?
+ int radial_symm[3];
+
+ // all this below is used to communicate with the cursor drawing routine
+
+ /* record movement of mouse so that rake can start at an intuitive angle */
+ float last_x, last_y;
+ float last_angle;
+
+ int draw_anchored;
+ int anchored_size;
+ float anchored_location[3];
+ float anchored_initial_mouse[2];
+
+ int draw_pressure;
+ float pressure_value;
+
+ float special_rotation;
+
+ int pad;
} Sculpt;
typedef struct VPaint {
@@ -1105,19 +1123,22 @@ typedef struct Scene {
/* Paint.flags */
typedef enum {
- PAINT_SHOW_BRUSH = 1,
- PAINT_FAST_NAVIGATE = 2
+ PAINT_SHOW_BRUSH = (1<<0),
+ PAINT_FAST_NAVIGATE = (1<<1),
+ PAINT_SHOW_BRUSH_ON_SURFACE = (1<<2),
} PaintFlags;
/* Sculpt.flags */
/* These can eventually be moved to paint flags? */
typedef enum SculptFlags {
- SCULPT_SYMM_X = 1,
- SCULPT_SYMM_Y = 2,
- SCULPT_SYMM_Z = 4,
- SCULPT_LOCK_X = 64,
- SCULPT_LOCK_Y = 128,
- SCULPT_LOCK_Z = 256
+ SCULPT_SYMM_X = (1<<0),
+ SCULPT_SYMM_Y = (1<<1),
+ SCULPT_SYMM_Z = (1<<2),
+ SCULPT_LOCK_X = (1<<3),
+ SCULPT_LOCK_Y = (1<<4),
+ SCULPT_LOCK_Z = (1<<5),
+ SCULPT_SYMMETRY_FEATHER = (1<<6),
+ SCULPT_USE_OPENMP = (1<<7),
} SculptFlags;
/* ImagePaintSettings.flag */
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index b6e52699340..19db6316659 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -341,9 +341,10 @@ typedef struct UserDef {
short gp_settings;
short tb_leftmouse, tb_rightmouse;
struct SolidLight light[3];
+ short sculpt_paint_settings; /* user preferences for sculpt and paint */
short tw_hotspot, tw_flag, tw_handlesize, tw_size;
short textimeout,texcollectrate;
- short wmdrawmethod, wmpad;
+ short wmdrawmethod; /* removed wmpad */
int memcachelimit;
int prefetchframes;
short frameserverport;
@@ -373,6 +374,11 @@ typedef struct UserDef {
short autokey_flag; /* flags for autokeying */
struct ColorBand coba_weight; /* from texture.h */
+
+ int sculpt_paint_unified_size; /* unified radius of brush in pixels */
+ float sculpt_paint_unified_unprojected_radius;/* unified radius of brush in Blender units */
+ float sculpt_paint_unified_alpha; /* unified strength of brush */
+ float sculpt_paint_overlay_col[3];
} UserDef;
extern UserDef U; /* from blenkernel blender.c */
@@ -524,6 +530,11 @@ extern UserDef U; /* from blenkernel blender.c */
#define GP_PAINT_DOSMOOTH (1<<0)
#define GP_PAINT_DOSIMPLIFY (1<<1)
+/* sculpt_paint_settings */
+#define SCULPT_PAINT_USE_UNIFIED_SIZE (1<<0)
+#define SCULPT_PAINT_USE_UNIFIED_ALPHA (1<<1)
+#define SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE (1<<2)
+
/* color picker types */
#define USER_CP_CIRCLE 0
#define USER_CP_SQUARE_SV 1
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index ed52316990e..e6d0772f425 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -307,8 +307,7 @@ typedef struct wmOperator {
typedef enum wmRadialControlMode {
WM_RADIALCONTROL_SIZE,
WM_RADIALCONTROL_STRENGTH,
- WM_RADIALCONTROL_ANGLE
+ WM_RADIALCONTROL_ANGLE,
} wmRadialControlMode;
#endif /* DNA_WINDOWMANAGER_TYPES_H */
-
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index bd500adc8e4..1558eef713e 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -45,7 +45,6 @@ if env['WITH_BF_GAMEENGINE']:
if env['BF_UNIT_TEST']:
defs.append('UNIT_TEST')
-
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 9b824279d8d..207e4e15a72 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -52,6 +52,7 @@ INCLUDE_DIRECTORIES(
../../gpu
../../imbuf
../../render/extern/include
+ ../../../../extern/glew/include
. )
FILE(GLOB INC_FILES ../*.h ../../makesdna/*.h)
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index fff29ba8f56..6d5a06d4f81 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -30,6 +30,7 @@
#include "DNA_brush_types.h"
#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
#include "BLI_math.h"
@@ -51,6 +52,58 @@ static void rna_Brush_update(Main *bmain, Scene *scene, PointerRNA *ptr)
WM_main_add_notifier(NC_BRUSH|NA_EDITED, br);
}
+static int rna_Brush_is_sculpt_brush(Brush *me, bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int i;
+
+ for (i= 0; i < sd->paint.brush_count; i++) {
+ if (strcmp(me->id.name+2, sd->paint.brushes[i]->id.name+2) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rna_Brush_is_vpaint_brush(Brush *me, bContext *C)
+{
+ VPaint *vp = CTX_data_tool_settings(C)->vpaint;
+ int i;
+
+ for (i= 0; i < vp->paint.brush_count; i++) {
+ if (strcmp(me->id.name+2, vp->paint.brushes[i]->id.name+2) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rna_Brush_is_wpaint_brush(Brush *me, bContext *C)
+{
+ VPaint *vp = CTX_data_tool_settings(C)->wpaint;
+ int i;
+
+ for (i= 0; i < vp->paint.brush_count; i++) {
+ if (strcmp(me->id.name+2, vp->paint.brushes[i]->id.name+2) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rna_Brush_is_imapaint_brush(Brush *me, bContext *C)
+{
+ ImagePaintSettings *data = &(CTX_data_tool_settings(C)->imapaint);
+ int i;
+
+ for (i= 0; i < data->paint.brush_count; i++) {
+ if (strcmp(me->id.name+2, data->paint.brushes[i]->id.name+2) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
#else
static void rna_def_brush_texture_slot(BlenderRNA *brna)
@@ -100,14 +153,42 @@ static void rna_def_brush(BlenderRNA *brna)
static EnumPropertyItem brush_sculpt_tool_items[] = {
{SCULPT_TOOL_DRAW, "DRAW", 0, "Draw", ""},
{SCULPT_TOOL_SMOOTH, "SMOOTH", 0, "Smooth", ""},
+ {SCULPT_TOOL_CREASE, "CREASE", 0, "Crease", ""},
+ {SCULPT_TOOL_BLOB, "BLOB", 0, "Blob", ""},
{SCULPT_TOOL_PINCH, "PINCH", 0, "Pinch", ""},
{SCULPT_TOOL_INFLATE, "INFLATE", 0, "Inflate", ""},
{SCULPT_TOOL_GRAB, "GRAB", 0, "Grab", ""},
+ {SCULPT_TOOL_SNAKE_HOOK, "SNAKE_HOOK", 0, "Snake Hook", ""},
+ {SCULPT_TOOL_ROTATE, "ROTATE", 0, "Rotate", ""},
+ {SCULPT_TOOL_THUMB, "THUMB", 0, "Thumb", ""},
+ {SCULPT_TOOL_NUDGE, "NUDGE", 0, "Nudge", ""},
{SCULPT_TOOL_LAYER, "LAYER", 0, "Layer", ""},
{SCULPT_TOOL_FLATTEN, "FLATTEN", 0, "Flatten", ""},
{SCULPT_TOOL_CLAY, "CLAY", 0, "Clay", ""},
+ //{SCULPT_TOOL_CLAY_TUBES, "CLAY_TUBES", 0, "Clay Tubes", ""}, XXX: remove clay tubes from UI
+ {SCULPT_TOOL_FILL, "FILL", 0, "Fill", ""},
+ {SCULPT_TOOL_SCRAPE, "SCRAPE", 0, "Scrape", ""},
{0, NULL, 0, NULL, NULL}};
-
+
+ static EnumPropertyItem brush_stroke_method_items[] = {
+ {0, "DOTS", 0, "Dots", ""},
+ {BRUSH_RESTORE_MESH, "DRAG_DOT", 0, "Drag Dot", ""},
+ {BRUSH_SPACE, "SPACE", 0, "Space", ""},
+ {BRUSH_ANCHORED, "ANCHORED", 0, "Anchored", ""},
+ {BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem texture_angle_source_items[] = {
+ {0, "USER", 0, "User", ""},
+ {BRUSH_RAKE, "RAKE", 0, "Rake", ""},
+ {BRUSH_RANDOM_ROTATION, "RANDOM", 0, "Random", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem texture_angle_source_no_random_items[] = {
+ {0, "USER", 0, "User", ""},
+ {BRUSH_RAKE, "RAKE", 0, "Rake", ""},
+ {0, NULL, 0, NULL, NULL}};
+
static EnumPropertyItem brush_vertexpaint_tool_items[] = {
{0, "MIX", 0, "Mix", "Use mix blending mode while painting"},
{1, "ADD", 0, "Add", "Use add blending mode while painting"},
@@ -129,11 +210,76 @@ static void rna_def_brush(BlenderRNA *brna)
{0, "ADD", 0, "Add", "Add effect of brush"},
{BRUSH_DIR_IN, "SUBTRACT", 0, "Subtract", "Subtract effect of brush"},
{0, NULL, 0, NULL, NULL}};
-
+
+ static const EnumPropertyItem prop_flatten_contrast_items[]= {
+ {0, "FLATTEN", 0, "Flatten", "Add effect of brush"},
+ {BRUSH_DIR_IN, "CONTRAST", 0, "Contrast", "Subtract effect of brush"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem prop_fill_deepen_items[]= {
+ {0, "FILL", 0, "Fill", "Add effect of brush"},
+ {BRUSH_DIR_IN, "DEEPEN", 0, "Deepen", "Subtract effect of brush"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem prop_scrape_peaks_items[]= {
+ {0, "SCRAPE", 0, "Scrape", "Add effect of brush"},
+ {BRUSH_DIR_IN, "PEAKS", 0, "Peaks", "Subtract effect of brush"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem prop_pinch_magnify_items[]= {
+ {0, "PINCH", 0, "Pinch", "Add effect of brush"},
+ {BRUSH_DIR_IN, "MAGNIFY", 0, "Magnify", "Subtract effect of brush"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static const EnumPropertyItem prop_inflate_deflate_items[]= {
+ {0, "INFLATE", 0, "Inflate", "Add effect of brush"},
+ {BRUSH_DIR_IN, "DEFLATE", 0, "Deflate", "Subtract effect of brush"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem brush_sculpt_plane_items[] = {
+ {SCULPT_DISP_DIR_AREA, "AREA", 0, "Area Plane", ""},
+ {SCULPT_DISP_DIR_VIEW, "VIEW", 0, "View Plane", ""},
+ {SCULPT_DISP_DIR_X, "X", 0, "X Plane", ""},
+ {SCULPT_DISP_DIR_Y, "Y", 0, "Y Plane", ""},
+ {SCULPT_DISP_DIR_Z, "Z", 0, "Z Plane", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
srna= RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(srna, "Brush", "Brush datablock for storing brush settings for painting and sculpting");
RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
-
+
+ /* functions */
+ func= RNA_def_function(srna, "is_sculpt_brush", "rna_Brush_is_sculpt_brush");
+ RNA_def_function_ui_description(func, "Returns true if Brush can be used for sculpting");
+ parm= RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_boolean(func, "ret", 0, "", "");
+ RNA_def_function_return(func, parm);
+
+ func= RNA_def_function(srna, "is_vpaint_brush", "rna_Brush_is_vpaint_brush");
+ RNA_def_function_ui_description(func, "Returns true if Brush can be used for vertex painting");
+ parm= RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_boolean(func, "ret", 0, "", "");
+ RNA_def_function_return(func, parm);
+
+ func= RNA_def_function(srna, "is_wpaint_brush", "rna_Brush_is_wpaint_brush");
+ RNA_def_function_ui_description(func, "Returns true if Brush can be used for weight painting");
+ parm= RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_boolean(func, "ret", 0, "", "");
+ RNA_def_function_return(func, parm);
+
+ func= RNA_def_function(srna, "is_imapaint_brush", "rna_Brush_is_imapaint_brush");
+ RNA_def_function_ui_description(func, "Returns true if Brush can be used for image painting");
+ parm= RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_boolean(func, "ret", 0, "", "");
+ RNA_def_function_return(func, parm);
+
/* enums */
prop= RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_blend_items);
@@ -144,7 +290,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_enum_items(prop, brush_sculpt_tool_items);
RNA_def_property_ui_text(prop, "Sculpt Tool", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
-
+
prop= RNA_def_property(srna, "vertexpaint_tool", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, brush_vertexpaint_tool_items);
RNA_def_property_ui_text(prop, "Vertex/Weight Paint Tool", "");
@@ -158,33 +304,94 @@ static void rna_def_brush(BlenderRNA *brna)
prop= RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, prop_flip_direction_items);
- RNA_def_property_ui_text(prop, "Direction", "Mapping type to use for this image in the game engine");
+ RNA_def_property_ui_text(prop, "Direction", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "stroke_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, brush_stroke_method_items);
+ RNA_def_property_ui_text(prop, "Stroke Method", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "texture_angle_source", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, texture_angle_source_items);
+ RNA_def_property_ui_text(prop, "Texture Angle Source", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "texture_angle_source_no_random", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, texture_angle_source_no_random_items);
+ RNA_def_property_ui_text(prop, "Texture Angle Source", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "flatten_contrast", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, prop_flatten_contrast_items);
+ RNA_def_property_ui_text(prop, "Flatten/Contrast", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "inflate_deflate", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, prop_inflate_deflate_items);
+ RNA_def_property_ui_text(prop, "Inflate/Deflate", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "fill_deepen", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, prop_fill_deepen_items);
+ RNA_def_property_ui_text(prop, "Fill/Deepen", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "scrape_peaks", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, prop_scrape_peaks_items);
+ RNA_def_property_ui_text(prop, "Scrape/Peaks", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "pinch_magnify", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, prop_pinch_magnify_items);
+ RNA_def_property_ui_text(prop, "Pinch/Magnify", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "sculpt_plane", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_sculpt_plane_items);
+ RNA_def_property_ui_text(prop, "Sculpt Plane", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* number values */
- prop= RNA_def_property(srna, "size", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 1, 200);
- RNA_def_property_ui_text(prop, "Size", "Diameter of the brush");
+ prop= RNA_def_property(srna, "size", PROP_INT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS*10);
+ RNA_def_property_ui_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS, 1, 0);
+ RNA_def_property_ui_text(prop, "Size", "Radius of the brush in pixels");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 0, 0);
+ RNA_def_property_ui_text(prop, "Surface Size", "Radius of brush in Blender units");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop= RNA_def_property(srna, "jitter", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "jitter");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Jitter", "Jitter the position of the brush while painting");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- prop= RNA_def_property(srna, "spacing", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "spacing");
- RNA_def_property_range(prop, 1.0f, 100.0f);
- RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush stamps");
+ prop= RNA_def_property(srna, "spacing", PROP_INT, PROP_PERCENTAGE);
+ RNA_def_property_int_sdna(prop, NULL, "spacing");
+ RNA_def_property_range(prop, 1, 1000);
+ RNA_def_property_ui_range(prop, 1, 500, 5, 0);
+ RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush daubs as a percentage of brush diameter");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- prop= RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_NONE);
+ prop= RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_DISTANCE);
RNA_def_property_range(prop, 10, 200);
RNA_def_property_ui_text(prop, "Smooth Stroke Radius", "Minimum distance from last point before stroke continues");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- prop= RNA_def_property(srna, "smooth_stroke_factor", PROP_FLOAT, PROP_NONE);
+ prop= RNA_def_property(srna, "smooth_stroke_factor", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_range(prop, 0.5, 0.99);
RNA_def_property_ui_text(prop, "Smooth Stroke Factor", "Higher values give a smoother stroke");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -202,10 +409,56 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ prop= RNA_def_property(srna, "strength", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "alpha");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
+ RNA_def_property_ui_text(prop, "Strength", "How powerful the effect of the brush is when applied");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "plane_offset", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "plane_offset");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, -2.0f, 2.0f);
+ RNA_def_property_ui_range(prop, -0.5f, 0.5f, 0.001, 0.001);
+ RNA_def_property_ui_text(prop, "Plane Offset", "Adjusts plane on which the brush acts towards or away from the object surface");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "plane_trim", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "plane_trim");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0, 1.0f);
+ RNA_def_property_ui_text(prop, "Plane Trim", "If a vertex is further from offset plane than this then it is not affected");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "texture_sample_bias", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "texture_sample_bias");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, -1, 1);
+ RNA_def_property_ui_text(prop, "Texture Sample Bias", "Value added to texture samples");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "normal_weight", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "normal_weight");
+ RNA_def_property_float_default(prop, 0);
RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Strength", "The amount of pressure on the brush");
+ RNA_def_property_ui_text(prop, "Normal Weight", "How much grab will pull vertexes out of surface during a grab");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "crease_pinch_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "crease_pinch_factor");
+ RNA_def_property_float_default(prop, 2.0f/3.0f);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Crease Brush Pinch Factor", "How much the crease brush pinches");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "autosmooth_factor", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "autosmooth_factor");
+ RNA_def_property_float_default(prop, 0);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
+ RNA_def_property_ui_text(prop, "Autosmooth", "Amount of smoothing to automatically apply to each stroke");
RNA_def_property_update(prop, 0, "rna_Brush_update");
/* flag */
@@ -214,6 +467,11 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Airbrush", "Keep applying paint effect while holding mouse (spray)");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "use_original_normal", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ORIGINAL_NORMAL);
+ RNA_def_property_ui_text(prop, "Original Normal", "When locked keep using normal of surface where stroke was initiated");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop= RNA_def_property(srna, "use_wrap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_TORUS);
RNA_def_property_ui_text(prop, "Wrap", "Enable torus wrapping while painting");
@@ -225,6 +483,12 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Strength Pressure", "Enable tablet pressure sensitivity for strength");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "use_offset_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_OFFSET_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Plane Offset Pressure", "Enable tablet pressure sensitivity for offset");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop= RNA_def_property(srna, "use_size_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SIZE_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
@@ -243,11 +507,32 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Spacing Pressure", "Enable tablet pressure sensitivity for spacing");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "use_inverse_smooth_pressure", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERSE_SMOOTH_PRESSURE);
+ RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
+ RNA_def_property_ui_text(prop, "Inverse Smooth Pressure", "Lighter pressure causes more smoothing to be applied");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop= RNA_def_property(srna, "use_rake", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RAKE);
RNA_def_property_ui_text(prop, "Rake", "Rotate the brush texture to match the stroke direction");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "use_random_rotation", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RANDOM_ROTATION);
+ RNA_def_property_ui_text(prop, "Random Rotation", "Rotate the brush texture at random");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "use_plane_trim", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_PLANE_TRIM);
+ RNA_def_property_ui_text(prop, "Use Plane Trim", "Enable Plane Trim");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "use_frontface", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_FRONTFACE);
+ RNA_def_property_ui_text(prop, "Use Front-Face", "Brush only affects vertexes that face the viewer");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop= RNA_def_property(srna, "use_anchor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ANCHORED);
RNA_def_property_ui_text(prop, "Anchored", "Keep the brush anchored to the initial location");
@@ -273,6 +558,37 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Accumulate", "Accumulate stroke dabs on top of each other");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop= RNA_def_property(srna, "use_space_atten", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SPACE_ATTEN);
+ RNA_def_property_ui_text(prop, "Use Automatic Strength Adjustment", "Automatically adjusts strength to give consistent results for different spacings");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ /* adaptive space is not implemented yet */
+ prop= RNA_def_property(srna, "use_adaptive_space", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ADAPTIVE_SPACE);
+ RNA_def_property_ui_text(prop, "Adaptive Spacing", "Space daubs according to surface orientation instead of screen space");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "lock_brush_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_LOCK_SIZE);
+ RNA_def_property_ui_text(prop, "Use Blender Units", "When locked brush stays same size relative to object; when unlocked brush size is given in pixels");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "use_texture_overlay", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_TEXTURE_OVERLAY);
+ RNA_def_property_ui_text(prop, "Use Texture Overlay", "Show texture in viewport");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "edge_to_edge", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_EDGE_TO_EDGE);
+ RNA_def_property_ui_text(prop, "Edge-to-edge", "Drag anchor brush from edge-to-edge");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "restore_mesh", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_RESTORE_MESH);
+ RNA_def_property_ui_text(prop, "Restore Mesh", "Allows a single dot to be carefully positioned");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* not exposed in the interface yet
prop= RNA_def_property(srna, "fixed_tex", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_FIXED_TEX);
@@ -303,6 +619,31 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Texture", "");
RNA_def_property_update(prop, NC_TEXTURE, "rna_Brush_update");
+ prop= RNA_def_property(srna, "texture_overlay_alpha", PROP_INT, PROP_PERCENTAGE);
+ RNA_def_property_int_sdna(prop, NULL, "texture_overlay_alpha");
+ RNA_def_property_range(prop, 1, 100);
+ RNA_def_property_ui_text(prop, "Texture Overlay Alpha", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "add_col", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "add_col");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Add Color", "Color of cursor when adding");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "sub_col", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "sub_col");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Subract Color", "Color of cursor when subtracting");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop= RNA_def_property(srna, "image_icon", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "image_icon");
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Image Icon", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* clone tool */
prop= RNA_def_property(srna, "clone_image", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "clone.image");
@@ -357,16 +698,19 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Pressure", "Tablet pressure");
- prop= RNA_def_property(srna, "time", PROP_FLOAT, PROP_UNSIGNED);
+ prop= RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
- RNA_def_property_ui_text(prop, "Time", "");
+ RNA_def_property_ui_text(prop, "Flip", "");
- prop= RNA_def_property(srna, "flip", PROP_BOOLEAN, PROP_NONE);
+ // used in uv painting
+ prop= RNA_def_property(srna, "time", PROP_FLOAT, PROP_UNSIGNED);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
- RNA_def_property_ui_text(prop, "Flip", "");
+ RNA_def_property_ui_text(prop, "Time", "");
/* XXX: Tool (this will be for pressing a modifier key for a different brush,
e.g. switching to a Smooth brush in the middle of the stroke */
+
+ // XXX: i don't think blender currently supports the ability to properly do a remappable modifier in the middle of a stroke
}
void RNA_def_brush(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 7d8248b58ed..7144b409299 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -213,6 +213,12 @@ static int rna_Image_depth_get(PointerRNA *ptr)
return depth;
}
+static int rna_Image_is_image_icon(Image *me, bContext *C)
+{
+ const char prefix[] = ".imageicon.";
+ return strncmp(me->id.name+2, prefix, sizeof(prefix)-1) == 0;
+}
+
#else
static void rna_def_imageuser(BlenderRNA *brna)
@@ -292,6 +298,9 @@ static void rna_def_image(BlenderRNA *brna)
{IMA_STD_FIELD, "ODD", 0, "Lower First", "Lower field first"},
{0, NULL, 0, NULL, NULL}};
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
srna= RNA_def_struct(brna, "Image", "ID");
RNA_def_struct_ui_text(srna, "Image", "Image datablock referencing an external or packed image");
RNA_def_struct_ui_icon(srna, ICON_IMAGE_DATA);
@@ -333,6 +342,14 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Field Order", "Order of video fields. Select which lines are displayed first");
RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, NULL);
+ /* functions */
+ func= RNA_def_function(srna, "is_image_icon", "rna_Image_is_image_icon");
+ RNA_def_function_ui_description(func, "Returns true if Image name is prefixed with .imageicon.");
+ parm= RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm= RNA_def_boolean(func, "ret", 0, "", "");
+ RNA_def_function_return(func, parm);
+
/* booleans */
prop= RNA_def_property(srna, "fields", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_FIELDS);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 3a7e7a02837..604f7776d56 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -193,7 +193,7 @@ static void rna_Paint_active_brush_name_get(PointerRNA *ptr, char *value)
Paint *p= ptr->data;
Brush *br = paint_brush(p);
- BLI_strncpy(value, br->id.name+2, sizeof(br->id.name-2));
+ BLI_strncpy(value, br->id.name+2, sizeof(br->id.name)-2);
}
@@ -212,7 +212,7 @@ static void rna_Paint_active_brush_name_set(PointerRNA *ptr, const char *value)
for(i = 0; i < p->brush_count; ++i) {
br = p->brushes[i];
-
+
if (strcmp(br->id.name+2, value)==0) {
paint_brush_set(p, br);
return;
@@ -262,6 +262,10 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH);
RNA_def_property_ui_text(prop, "Show Brush", "");
+ prop= RNA_def_property(srna, "show_brush_on_surface", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH_ON_SURFACE);
+ RNA_def_property_ui_text(prop, "Show Brush On Surface", "");
+
prop= RNA_def_property(srna, "fast_navigate", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_FAST_NAVIGATE);
RNA_def_property_ui_text(prop, "Fast Navigate", "For multires, show low resolution while navigating the view");
@@ -274,7 +278,14 @@ static void rna_def_sculpt(BlenderRNA *brna)
srna= RNA_def_struct(brna, "Sculpt", "Paint");
RNA_def_struct_ui_text(srna, "Sculpt", "");
-
+
+ prop= RNA_def_property(srna, "radial_symm", PROP_INT, PROP_XYZ);
+ RNA_def_property_int_sdna(prop, NULL, "radial_symm");
+ RNA_def_property_int_default(prop, 1);
+ RNA_def_property_range(prop, 1, 64);
+ RNA_def_property_ui_range(prop, 0, 32, 1, 1);
+ RNA_def_property_ui_text(prop, "Radial Symmetry Count X Axis", "Number of times to copy strokes across the surface");
+
prop= RNA_def_property(srna, "symmetry_x", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMM_X);
RNA_def_property_ui_text(prop, "Symmetry X", "Mirror brush across the X axis");
@@ -298,6 +309,14 @@ static void rna_def_sculpt(BlenderRNA *brna)
prop= RNA_def_property(srna, "lock_z", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_LOCK_Z);
RNA_def_property_ui_text(prop, "Lock Z", "Disallow changes to the Z axis of vertices");
+
+ prop= RNA_def_property(srna, "use_symmetry_feather", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_SYMMETRY_FEATHER);
+ RNA_def_property_ui_text(prop, "Symmetry Feathering", "Reduce the strength of the brush where it overlaps symmetrical daubs");
+
+ prop= RNA_def_property(srna, "use_openmp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", SCULPT_USE_OPENMP);
+ RNA_def_property_ui_text(prop, "Use OpenMP", "Take advantage of multiple CPU cores to improve sculpting performance");
}
static void rna_def_vertex_paint(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 1c751433e31..b2831c4b1d3 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -274,6 +274,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block.");
RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
+ RNA_def_string(func, "filter", "", 0, "", "Function identifier to filter the ID block.");
func= RNA_def_function(srna, "template_ID_preview", "uiTemplateIDPreview");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -281,6 +282,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_string(func, "new", "", 0, "", "Operator identifier to create a new ID block.");
RNA_def_string(func, "open", "", 0, "", "Operator identifier to open a file for creating a new ID block.");
RNA_def_string(func, "unlink", "", 0, "", "Operator identifier to unlink the ID block.");
+ RNA_def_string(func, "filter", "", 0, "", "Function identifier to filter the ID block.");
RNA_def_int(func, "rows", 0, 0, INT_MAX, "Number of thumbnail preview rows to display", "", 0, INT_MAX);
RNA_def_int(func, "cols", 0, 0, INT_MAX, "Number of thumbnail preview columns to display", "", 0, INT_MAX);
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index d6aec37d6fb..a03488d3878 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -32,6 +32,7 @@
#include "DNA_curve_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_brush_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -867,7 +868,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Transform", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
-
+
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_edge(srna);
rna_def_userdef_theme_spaces_face(srna);
@@ -2194,7 +2195,43 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "gp_eraser");
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Grease Pencil Eraser Radius", "Radius of eraser 'brush'");
-
+
+ /* sculpt and paint */
+
+ prop= RNA_def_property(srna, "sculpt_paint_overlay_col", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "sculpt_paint_overlay_col");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Sculpt/Paint Overlay Color", "Color of texture overlay");
+
+ prop= RNA_def_property(srna, "sculpt_paint_use_unified_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_paint_settings", SCULPT_PAINT_USE_UNIFIED_SIZE);
+ RNA_def_property_ui_text(prop, "Sculpt/Paint Use Unified Radius", "Instead of per brush radius, the radius is shared across brushes");
+
+ prop= RNA_def_property(srna, "sculpt_paint_use_unified_strength", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_paint_settings", SCULPT_PAINT_USE_UNIFIED_ALPHA);
+ RNA_def_property_ui_text(prop, "Sculpt/Paint Use Unified Strength", "Instead of per brush strength, the strength is shared across brushes");
+
+ prop= RNA_def_property(srna, "sculpt_paint_unified_lock_brush_size", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sculpt_paint_settings", SCULPT_PAINT_UNIFIED_LOCK_BRUSH_SIZE);
+ RNA_def_property_ui_text(prop, "Sculpt/Paint Use Unified Blender Units", "When locked all brushes stay same size relative to object; when unlocked all brush sizes are given in pixels");
+
+ prop= RNA_def_property(srna, "sculpt_paint_unified_size", PROP_INT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS*10);
+ RNA_def_property_ui_range(prop, 1, MAX_BRUSH_PIXEL_RADIUS, 1, 0);
+ RNA_def_property_ui_text(prop, "Sculpt/Paint Unified Size", "Unified radius of the brush in pixels");
+
+ prop= RNA_def_property(srna, "sculpt_paint_unified_unprojected_radius", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_range(prop, 0, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0, 1, 0, 0);
+ RNA_def_property_ui_text(prop, "Sculpt/Paint Unified Surface Size", "Unified radius of brush in Blender units");
+
+ prop= RNA_def_property(srna, "sculpt_paint_unified_strength", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "sculpt_paint_unified_alpha");
+ RNA_def_property_float_default(prop, 0.5f);
+ RNA_def_property_range(prop, 0.0f, 10.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.001, 0.001);
+ RNA_def_property_ui_text(prop, "Sculpt/Paint Unified Strength", "Unified power of effect of brushes when applied");
+
/* duplication linking */
prop= RNA_def_property(srna, "duplicate_mesh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "dupflag", USER_DUP_MESH);
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index 0a86133e614..179b1ddc998 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -24,7 +24,7 @@ if env['WITH_BF_COLLADA']:
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
- incs += ' ../../../extern/binreloc/include'
+ incs += ' ../../../extern/binreloc/include'
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
incs += ' ' + env['BF_PTHREADS_INC']
@@ -35,4 +35,4 @@ if env['WITH_GHOST_COCOA']:
if env['BF_BUILDINFO']:
defs.append('NAN_BUILDINFO')
-env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defs, libtype=['core'], priority=[5] )
+env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defines=defs, libtype=['core'], priority=[5] )
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 5dbbf35796f..38322b66bbb 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -389,6 +389,7 @@ static void wm_draw_triple_free(wmWindow *win)
wmDrawTriple *triple= win->drawdata;
glDeleteTextures(triple->nx*triple->ny, triple->bind);
+
MEM_freeN(triple);
win->drawdata= NULL;
@@ -560,7 +561,8 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
else {
win->drawdata= MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
- if(!wm_triple_gen_textures(win, win->drawdata)) {
+ if(!wm_triple_gen_textures(win, win->drawdata))
+ {
wm_draw_triple_fail(C, win);
return;
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 0023ded23f0..78e1c7d87a3 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -61,6 +61,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h" /* BKE_ST_MAXNAME */
#include "BKE_utildefines.h"
+#include "BKE_brush.h" // JW
#include "BIF_gl.h"
#include "BIF_glutil.h" /* for paint cursor */
@@ -69,6 +70,7 @@
#include "ED_screen.h"
#include "ED_util.h"
+#include "ED_view3d.h" // JW
#include "RNA_access.h"
#include "RNA_define.h"
@@ -2595,19 +2597,28 @@ typedef struct wmRadialControl {
GLuint tex;
} wmRadialControl;
+extern Paint *paint_get_active(Scene *sce);
+extern struct Brush *paint_brush(struct Paint *paint);
+
static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
{
wmRadialControl *rc = (wmRadialControl*)customdata;
ARegion *ar = CTX_wm_region(C);
float r1=0.0f, r2=0.0f, r3=0.0f, angle=0.0f;
- /* Keep cursor in the original place */
- x = rc->initial_mouse[0] - ar->winrct.xmin;
- y = rc->initial_mouse[1] - ar->winrct.ymin;
+ Paint *paint = paint_get_active(CTX_data_scene(C));
+ Brush *brush = paint_brush(paint);
- glPushMatrix();
-
- glTranslatef((float)x, (float)y, 0.0f);
+ ViewContext vc;
+
+ int hit = 0;
+
+ int flip;
+ int sign;
+
+ float* col;
+
+ const float str = rc->mode == WM_RADIALCONTROL_STRENGTH ? (rc->value + 0.5) : (brush->texture_overlay_alpha / 100.0f);
if(rc->mode == WM_RADIALCONTROL_SIZE) {
r1= rc->value;
@@ -2615,29 +2626,37 @@ static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
r3= r1;
} else if(rc->mode == WM_RADIALCONTROL_STRENGTH) {
r1= (1 - rc->value) * WM_RADIAL_CONTROL_DISPLAY_SIZE;
- r2= WM_RADIAL_CONTROL_DISPLAY_SIZE;
- r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ r2= r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
} else if(rc->mode == WM_RADIALCONTROL_ANGLE) {
- r1= r2= WM_RADIAL_CONTROL_DISPLAY_SIZE;
- r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
+ r1= r2= r3= WM_RADIAL_CONTROL_DISPLAY_SIZE;
angle = rc->value;
}
- glColor4ub(255, 255, 255, 128);
- glEnable( GL_LINE_SMOOTH );
- glEnable(GL_BLEND);
+ /* Keep cursor in the original place */
+ x = rc->initial_mouse[0] - ar->winrct.xmin;
+ y = rc->initial_mouse[1] - ar->winrct.ymin;
- if(rc->mode == WM_RADIALCONTROL_ANGLE)
- fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
+ view3d_set_viewcontext(C, &vc);
- if(rc->tex) {
- const float str = rc->mode == WM_RADIALCONTROL_STRENGTH ? (rc->value + 0.5) : 1;
+ // XXX: no way currently to know state of pen flip or invert key modifier without starting a stroke
+ flip = 1;
- if(rc->mode == WM_RADIALCONTROL_ANGLE) {
- glRotatef(angle, 0, 0, 1);
- fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
- }
+ sign = flip * ((brush->flag & BRUSH_DIR_IN)? -1 : 1);
+
+ if (sign < 0 && ELEM4(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_PINCH))
+ col = brush->sub_col;
+ else
+ col = brush->add_col;
+
+ glTranslatef((float)x, (float)y, 0.0f);
+
+ glEnable(GL_BLEND);
+ if(rc->mode == WM_RADIALCONTROL_ANGLE) {
+ glRotatef(angle, 0, 0, 1);
+ }
+
+ if (rc->tex) {
glBindTexture(GL_TEXTURE_2D, rc->tex);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -2645,7 +2664,7 @@ static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
- glColor4f(0,0,0, str);
+ glColor4f(U.sculpt_paint_overlay_col[0],U.sculpt_paint_overlay_col[1],U.sculpt_paint_overlay_col[2], str);
glTexCoord2f(0,0);
glVertex2f(-r3, -r3);
glTexCoord2f(1,0);
@@ -2658,11 +2677,20 @@ static void wm_radial_control_paint(bContext *C, int x, int y, void *customdata)
glDisable(GL_TEXTURE_2D);
}
- glColor4ub(255, 255, 255, 128);
+ if(rc->mode == WM_RADIALCONTROL_ANGLE) {
+ glColor4f(col[0], col[1], col[2], 0.5f);
+ glEnable(GL_LINE_SMOOTH);
+ glRotatef(-angle, 0, 0, 1);
+ fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
+ glRotatef(angle, 0, 0, 1);
+ fdrawline(0, 0, WM_RADIAL_CONTROL_DISPLAY_SIZE, 0);
+ glDisable(GL_LINE_SMOOTH);
+ }
+
+ glColor4f(col[0], col[1], col[2], 0.5f);
glutil_draw_lined_arc(0.0, M_PI*2.0, r1, 40);
glutil_draw_lined_arc(0.0, M_PI*2.0, r2, 40);
glDisable(GL_BLEND);
- glDisable( GL_LINE_SMOOTH );
glPopMatrix();
}
@@ -2674,6 +2702,7 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
float dist;
double new_value = RNA_float_get(op->ptr, "new_value");
int ret = OPERATOR_RUNNING_MODAL;
+ float initial_value = RNA_float_get(op->ptr, "initial_value");
mode = RNA_int_get(op->ptr, "mode");
RNA_int_get_array(op->ptr, "initial_mouse", initial_mouse);
@@ -2682,6 +2711,16 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
case MOUSEMOVE:
delta[0]= initial_mouse[0] - event->x;
delta[1]= initial_mouse[1] - event->y;
+
+ //if (mode == WM_RADIALCONTROL_SIZE)
+ // delta[0]+= initial_value;
+ //else if(mode == WM_RADIALCONTROL_STRENGTH)
+ // delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * (1 - initial_value);
+ //else if(mode == WM_RADIALCONTROL_ANGLE) {
+ // delta[0]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(initial_value*M_PI/180.0f);
+ // delta[1]+= WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(initial_value*M_PI/180.0f);
+ //}
+
dist= sqrt(delta[0]*delta[0]+delta[1]*delta[1]);
if(mode == WM_RADIALCONTROL_SIZE)
@@ -2728,6 +2767,11 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(CTX_wm_region(C));
+ //if (ret != OPERATOR_RUNNING_MODAL) {
+ // wmWindow *win = CTX_wm_window(C);
+ // WM_cursor_restore(win);
+ //}
+
return ret;
}
@@ -2735,10 +2779,15 @@ int WM_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
wmRadialControl *rc = MEM_callocN(sizeof(wmRadialControl), "radial control");
+ wmWindow *win = CTX_wm_window(C);
int mode = RNA_int_get(op->ptr, "mode");
float initial_value = RNA_float_get(op->ptr, "initial_value");
+ //float initial_size = RNA_float_get(op->ptr, "initial_size");
int mouse[2] = {event->x, event->y};
+ //if (initial_size == 0)
+ // initial_size = WM_RADIAL_CONTROL_DISPLAY_SIZE;
+
if(mode == WM_RADIALCONTROL_SIZE) {
rc->max_value = 200;
mouse[0]-= initial_value;
@@ -2775,6 +2824,8 @@ int WM_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
rc->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), op->type->poll,
wm_radial_control_paint, op->customdata);
+ //WM_cursor_modal(win, CURSOR_NONE);
+
/* add modal handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index add9ac05189..4599f8ff17b 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -36,12 +36,14 @@
struct ARegion;
struct ARegionType;
struct Base;
+struct Brush;
struct bNodeTree;
struct CSG_FaceIteratorDescriptor;
struct CSG_VertexIteratorDescriptor;
struct ColorBand;
struct CurveMapping;
struct EditBone;
+struct EditFace;
struct EditMesh;
struct ID;
struct FCurve;
@@ -54,16 +56,20 @@ struct LOD_Decimation_Info;
struct MTex;
struct Main;
struct Material;
+struct MCol;
struct MenuType;
struct Mesh;
struct ModifierData;
+struct MultiresModifierData;
struct NodeBlurData;
struct Object;
+struct PBVHNode;
struct Render;
struct RenderEngine;
struct RenderLayer;
struct RenderResult;
struct ScrArea;
+struct SculptSession;
struct ShadeInput;
struct ShadeResult;
struct SpaceImage;
@@ -375,6 +381,24 @@ void smoke_get_index(void) {return;}
void smoke_step(void) {return;}
*/
+/* sculpt */
+/*
+ void ED_sculpt_force_update(struct bContext *C) {}
+struct SculptUndoNode *sculpt_undo_push_node(struct SculptSession *ss, struct PBVHNode *node) {return (struct SculptUndoNode *)NULL;}
+void sculpt_undo_push_end(void) {}
+void sculpt_undo_push_begin(char *name) {}
+struct SculptUndoNode *sculpt_undo_get_node(struct PBVHNode *node) {return (struct SculptUndoNode *) NULL;}
+struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob) {return (struct MultiresModifierData *) NULL;}
+int sculpt_modifiers_active(struct Scene *scene, struct Object *ob) {return 0;}
+*/
+int sculpt_get_brush_size(struct Brush *brush) {return 0;}
+void sculpt_set_brush_size(struct Brush *brush, int size) {}
+int sculpt_get_lock_brush_size(struct Brush *brush){ return 0;}
+float sculpt_get_brush_unprojected_radius(struct Brush *brush){return 0.0f;}
+void sculpt_set_brush_unprojected_radius(struct Brush *brush, float unprojected_radius){}
+float sculpt_get_brush_alpha(struct Brush *brush){return 0.0f;}
+void sculpt_set_brush_alpha(struct Brush *brush, float alpha){}
+
char blender_path[] = "";
/* CSG */