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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/sculpt_paint/sculpt.c')
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c282
1 files changed, 217 insertions, 65 deletions
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index b08e8ab5c2b..f7f72d611dc 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -65,6 +65,7 @@
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
+#include "BKE_sculpt.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
#include "BKE_colortools.h"
@@ -79,7 +80,6 @@
#include "ED_space_api.h"
#include "ED_util.h"
#include "ED_view3d.h"
-#include "paint_intern.h"
#include "sculpt_intern.h"
#include "RNA_access.h"
@@ -144,6 +144,7 @@ typedef struct StrokeCache {
int first_time; /* Beginning of stroke may do some things special */
+ ViewContext vc;
bglMats *mats;
short (*orig_norms)[3]; /* Copy of the mesh vertices' normals */
@@ -177,6 +178,19 @@ typedef struct ProjVert {
* Simple functions to get data from the GL
*/
+/* Uses window coordinates (x,y) and depth component z to find a point in
+ modelspace */
+static void unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
+{
+ double ux, uy, uz;
+
+ gluUnProject(x,y,z, mats->modelview, mats->projection,
+ (GLint *)mats->viewport, &ux, &uy, &uz );
+ out[0] = ux;
+ out[1] = uy;
+ out[2] = uz;
+}
+
/* Convert a point in model coordinates to 2D screen coordinates. */
static void projectf(bglMats *mats, const float v[3], float p[2])
{
@@ -533,7 +547,7 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
ActiveData *node= active_verts->first;
/* area_normal and cntr define the plane towards which vertices are squashed */
float area_normal[3];
- float cntr[3], cntr2[3], bstr = 0;
+ float cntr[3], cntr2[3], bstr;
int flip = 0;
calc_area_normal(sd, ss, area_normal, active_verts);
@@ -1041,7 +1055,47 @@ static int sculpt_mode_poll(bContext *C)
static int sculpt_poll(bContext *C)
{
- return sculpt_mode_poll(C) && paint_poll(C);
+ return sculpt_mode_poll(C) && paint_brush(&CTX_data_tool_settings(C)->sculpt->paint) &&
+ CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
+ CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
+}
+
+/*** Sculpt Cursor ***/
+static void draw_paint_cursor(bContext *C, int x, int y, void *customdata)
+{
+ Sculpt *sd= CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss= CTX_data_active_object(C)->sculpt;
+ Brush *brush = paint_brush(&sd->paint);
+
+ glColor4ub(255, 100, 100, 128);
+ 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);
+ glTranslatef((float)-x, (float)-y, 0.0f);
+
+ if(ss && ss->cache && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) {
+ ARegion *ar = CTX_wm_region(C);
+ sdrawline(x, y, (int)ss->cache->mouse[0] - ar->winrct.xmin, (int)ss->cache->mouse[1] - ar->winrct.ymin);
+ }
+
+ glDisable(GL_BLEND);
+ glDisable( GL_LINE_SMOOTH );
+}
+
+static void toggle_paint_cursor(bContext *C)
+{
+ Sculpt *s = CTX_data_scene(C)->toolsettings->sculpt;
+
+ if(s->cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), s->cursor);
+ s->cursor = NULL;
+ }
+ else {
+ s->cursor =
+ WM_paint_cursor_activate(CTX_wm_manager(C), sculpt_poll, draw_paint_cursor, NULL);
+ }
}
static void sculpt_undo_push(bContext *C, Sculpt *sd)
@@ -1071,11 +1125,8 @@ static void sculpt_undo_push(bContext *C, Sculpt *sd)
/**** Radial control ****/
static int sculpt_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
- Paint *p = paint_get_active(CTX_data_scene(C));
- Brush *brush = paint_brush(p);
-
- WM_paint_cursor_end(CTX_wm_manager(C), p->paint_cursor);
- p->paint_cursor = NULL;
+ Brush *brush = paint_brush(&CTX_data_tool_settings(C)->sculpt->paint);
+ toggle_paint_cursor(C);
brush_radial_control_invoke(op, brush, 1);
return WM_radial_control_invoke(C, op, event);
}
@@ -1084,7 +1135,7 @@ static int sculpt_radial_control_modal(bContext *C, wmOperator *op, wmEvent *eve
{
int ret = WM_radial_control_modal(C, op, event);
if(ret != OPERATOR_RUNNING_MODAL)
- paint_cursor_start(C, sculpt_poll);
+ toggle_paint_cursor(C);
return ret;
}
@@ -1118,7 +1169,7 @@ static float unproject_brush_radius(SculptSession *ss, float offset)
float brush_edge[3];
/* In anchored mode, brush size changes with mouse loc, otherwise it's fixed using the brush radius */
- view3d_unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset,
+ unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset,
ss->cache->initial_mouse[1], ss->cache->depth);
return VecLenf(ss->cache->true_location, brush_edge);
@@ -1143,7 +1194,6 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
{
StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache");
Brush *brush = paint_brush(&sd->paint);
- ViewContext *vc = paint_stroke_view_context(op->customdata);
int i;
ss->cache = cache;
@@ -1159,8 +1209,10 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
/* Truly temporary data that isn't stored in properties */
+ view3d_set_viewcontext(C, &cache->vc);
+
cache->mats = MEM_callocN(sizeof(bglMats), "sculpt bglMats");
- view3d_get_transformation(vc, vc->obact, cache->mats);
+ view3d_get_transformation(&cache->vc, cache->vc.obact, cache->mats);
sculpt_update_mesh_elements(C);
@@ -1200,7 +1252,7 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte
}
}
- view3d_unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
+ unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth);
cache->initial_radius = unproject_brush_radius(ss, brush->size);
cache->rotation = 0;
cache->first_time = 1;
@@ -1260,7 +1312,7 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR
/* Find the grab delta */
if(brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- view3d_unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
+ unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth);
if(!cache->first_time)
VecSubf(cache->grab_delta, grab_location, cache->old_grab_location);
VecCopyf(cache->old_grab_location, grab_location);
@@ -1273,6 +1325,7 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Object *ob= CTX_data_active_object(C);
ModifierData *md;
+ ViewContext vc;
float scale[3], clip_tolerance[3] = {0,0,0};
float mouse[2];
int flag = 0;
@@ -1305,12 +1358,13 @@ static void sculpt_brush_stroke_init_properties(bContext *C, wmOperator *op, wmE
RNA_float_set_array(op->ptr, "initial_mouse", mouse);
/* Initial screen depth under the mouse */
- RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y));
+ view3d_set_viewcontext(C, &vc);
+ RNA_float_set(op->ptr, "depth", read_cached_depth(&vc, event->x, event->y));
sculpt_update_cache_invariants(sd, ss, C, op);
}
-static void sculpt_brush_stroke_init(bContext *C)
+static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
@@ -1322,7 +1376,10 @@ static void sculpt_brush_stroke_init(bContext *C)
changes are made to the texture. */
sculpt_update_tex(sd, ss);
- sculpt_update_mesh_elements(C);
+ /* add modal handler */
+ WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+
+ return OPERATOR_RUNNING_MODAL;
}
static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
@@ -1378,69 +1435,157 @@ static void sculpt_flush_update(bContext *C)
ED_region_tag_redraw(ar);
}
-static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event)
+/* Returns zero if no sculpt changes should be made, non-zero otherwise */
+static int sculpt_smooth_stroke(Sculpt *s, SculptSession *ss, float output[2], wmEvent *event)
{
- ViewContext vc;
- float cur_depth;
+ Brush *brush = paint_brush(&s->paint);
- view3d_set_viewcontext(C, &vc);
- cur_depth = read_cached_depth(&vc, event->x, event->y);
-
- /* Don't start the stroke until a valid depth is found */
- if(cur_depth < 1.0 - FLT_EPSILON) {
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ output[0] = event->x;
+ output[1] = event->y;
- sculpt_brush_stroke_init_properties(C, op, event, ss);
- sculptmode_update_all_projverts(ss);
+ if(brush->flag & BRUSH_SMOOTH_STROKE && brush->sculpt_tool != SCULPT_TOOL_GRAB) {
+ StrokeCache *cache = ss->cache;
+ float u = brush->smooth_stroke_factor, v = 1.0 - u;
+ float dx = cache->mouse[0] - event->x, dy = cache->mouse[1] - event->y;
- return 1;
+ /* If the mouse is moving within the radius of the last move,
+ don't update the mouse position. This allows sharp turns. */
+ if(dx*dx + dy*dy < brush->smooth_stroke_radius * brush->smooth_stroke_radius)
+ return 0;
+
+ output[0] = event->x * v + cache->mouse[0] * u;
+ output[1] = event->y * v + cache->mouse[1] * u;
}
- else
- return 0;
+
+ return 1;
}
-static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
+/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
+int sculpt_space_stroke_enabled(Sculpt *s)
+{
+ Brush *br = paint_brush(&s->paint);
+ return (br->flag & BRUSH_SPACE) && !(br->flag & BRUSH_ANCHORED) && (br->sculpt_tool != SCULPT_TOOL_GRAB);
+}
+
+/* Put the location of the next sculpt stroke dot into the stroke RNA and apply it to the mesh */
+static void sculpt_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse[2])
{
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
-
- sculpt_update_cache_variants(sd, ss, itemptr);
+ StrokeCache *cache = ss->cache;
+ PointerRNA itemptr;
+ float cur_depth, pressure = 1;
+ float center[3];
+
+ cur_depth = read_cached_depth(&cache->vc, mouse[0], mouse[1]);
+ unproject(ss->cache->mats, center, mouse[0], mouse[1], cur_depth);
+
+ /* Tablet */
+ if(event->custom == EVT_DATA_TABLET) {
+ wmTabletData *wmtab= event->customdata;
+ if(wmtab->Active != EVT_TABLET_NONE)
+ pressure= wmtab->Pressure;
+ }
+
+ /* 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", event->shift);
+ RNA_float_set(&itemptr, "pressure", pressure);
+ sculpt_update_cache_variants(sd, ss, &itemptr);
+
sculpt_restore_mesh(sd, ss);
do_symmetrical_brush_actions(sd, ss);
+}
- /* Cleanup */
- sculpt_flush_update(C);
- sculpt_post_stroke_free(ss);
+/* For brushes with stroke spacing enabled, moves mouse in steps
+ towards the final mouse location. */
+static int sculpt_space_stroke(bContext *C, wmOperator *op, wmEvent *event, Sculpt *s, SculptSession *ss, const float final_mouse[2])
+{
+ StrokeCache *cache = ss->cache;
+ Brush *brush = paint_brush(&s->paint);
+ int cnt = 0;
+
+ if(sculpt_space_stroke_enabled(s)) {
+ float vec[2] = {final_mouse[0] - cache->mouse[0], final_mouse[1] - cache->mouse[1]};
+ float mouse[2] = {cache->mouse[0], cache->mouse[1]};
+ 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]);
+
+ if(length > FLT_EPSILON) {
+ scale = brush->spacing / length;
+ vec[0] *= scale;
+ vec[1] *= scale;
+
+ steps = (int)(length / brush->spacing);
+ for(i = 0; i < steps; ++i, ++cnt) {
+ mouse[0] += vec[0];
+ mouse[1] += vec[1];
+ sculpt_brush_stroke_add_step(C, op, event, mouse);
+ }
+ }
+ }
+
+ return cnt;
}
-static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke)
+static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ ARegion *ar = CTX_wm_region(C);
+ float cur_depth;
- /* Finished */
- if(ss->cache) {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ sculpt_update_mesh_elements(C);
+
+ if(!ss->cache) {
+ ViewContext vc;
+ view3d_set_viewcontext(C, &vc);
+ cur_depth = read_cached_depth(&vc, event->x, event->y);
- request_depth_update(paint_stroke_view_context(stroke)->rv3d);
- sculpt_cache_free(ss->cache);
- ss->cache = NULL;
- sculpt_undo_push(C, sd);
+ /* Don't start the stroke until a valid depth is found */
+ if(cur_depth < 1.0 - FLT_EPSILON) {
+ sculpt_brush_stroke_init_properties(C, op, event, ss);
+ sculptmode_update_all_projverts(ss);
+ }
+
+ ED_region_tag_redraw(ar);
}
-}
-static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- sculpt_brush_stroke_init(C);
+ if(ss->cache) {
+ float mouse[2];
- op->customdata = paint_stroke_new(C, sculpt_stroke_test_start,
- sculpt_stroke_update_step,
- sculpt_stroke_done);
+ if(sculpt_smooth_stroke(sd, ss, mouse, event)) {
+ if(sculpt_space_stroke_enabled(sd)) {
+ if(!sculpt_space_stroke(C, op, event, sd, ss, mouse))
+ ED_region_tag_redraw(ar);
+ }
+ else
+ sculpt_brush_stroke_add_step(C, op, event, mouse);
- /* add modal handler */
- WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
+ sculpt_flush_update(C);
+ sculpt_post_stroke_free(ss);
+ }
+ else
+ ED_region_tag_redraw(ar);
+ }
+
+ /* Finished */
+ if(event->type == LEFTMOUSE && event->val == 0) {
+ if(ss->cache) {
+ request_depth_update(ss->cache->vc.rv3d);
+ sculpt_cache_free(ss->cache);
+ ss->cache = NULL;
+ sculpt_undo_push(C, sd);
+ }
+
+ return OPERATOR_FINISHED;
+ }
- op->type->modal(C, op, event);
-
return OPERATOR_RUNNING_MODAL;
}
@@ -1449,14 +1594,20 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
SculptSession *ss = CTX_data_active_object(C)->sculpt;
- op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, sculpt_stroke_update_step, sculpt_stroke_done);
-
- sculpt_brush_stroke_init(C);
-
+ view3d_operator_needs_opengl(C);
sculpt_update_cache_invariants(sd, ss, C, op);
sculptmode_update_all_projverts(ss);
+ sculpt_update_tex(sd, ss);
- paint_stroke_exec(C, op);
+ RNA_BEGIN(op->ptr, itemptr, "stroke") {
+ sculpt_update_cache_variants(sd, ss, &itemptr);
+
+ sculpt_restore_mesh(sd, ss);
+ do_symmetrical_brush_actions(sd, ss);
+
+ sculpt_post_stroke_free(ss);
+ }
+ RNA_END;
sculpt_flush_update(C);
sculpt_cache_free(ss->cache);
@@ -1476,7 +1627,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
/* api callbacks */
ot->invoke= sculpt_brush_stroke_invoke;
- ot->modal= paint_stroke_modal;
+ ot->modal= sculpt_brush_stroke_modal;
ot->exec= sculpt_brush_stroke_exec;
ot->poll= sculpt_poll;
@@ -1563,9 +1714,10 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *op)
free_sculptsession(&ob->sculpt);
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
- paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
-
- paint_cursor_start(C, sculpt_poll);
+ if(!ts->sculpt->cursor)
+ toggle_paint_cursor(C);
+
+ paint_init(&ts->sculpt->paint, "Brush");
WM_event_add_notifier(C, NC_SCENE|ND_MODE, CTX_data_scene(C));
}