diff options
-rw-r--r-- | source/blender/editors/include/ED_view3d.h | 1 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_intern.h | 15 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_stroke.c | 224 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_vertex.c | 175 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/sculpt.c | 209 | ||||
-rw-r--r-- | source/blender/editors/space_view3d/view3d_view.c | 13 |
6 files changed, 391 insertions, 246 deletions
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 07aa44cadd8..fd1b7e1351d 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -70,6 +70,7 @@ float *give_cursor(struct Scene *scene, struct View3D *v3d); void initgrabz(struct RegionView3D *rv3d, float x, float y, float z); void window_to_3d(struct ARegion *ar, float *vec, short mx, short my); void window_to_3d_delta(struct ARegion *ar, float *vec, short mx, short my); +void view3d_unproject(struct bglMats *mats, float out[3], const short x, const short y, const float z); /* Depth buffer */ float read_cached_depth(struct ViewContext *vc, int x, int y); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 40423e17fe4..41764a70686 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -29,13 +29,28 @@ #ifndef ED_PAINT_INTERN_H #define ED_PAINT_INTERN_H +struct bContext; struct Scene; struct Object; struct Mesh; +struct PaintStroke; +struct PointerRNA; struct ViewContext; +struct wmEvent; +struct wmOperator; struct wmOperatorType; struct ARegion; +/* paint_stroke.c */ +typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event); +typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr); +typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke); + +struct PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start, + StrokeUpdateStep update_step, StrokeDone done); +int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event); +struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke); + /* paint_vertex.c */ void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_weight_paint_radial_control(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c new file mode 100644 index 00000000000..634b82674b5 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -0,0 +1,224 @@ +/* + * ***** 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2009 by Nicholas Bishop + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" + +#include "RNA_access.h" + +#include "BKE_context.h" +#include "BKE_paint.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "BLI_arithb.h" + +#include "BIF_glutil.h" + +#include "ED_screen.h" +#include "ED_view3d.h" + +#include "paint_intern.h" + +#include <float.h> +#include <math.h> + +typedef struct PaintStroke { + /* Cached values */ + ViewContext vc; + bglMats mats; + Brush *brush; + + float last_mouse_position[2]; + + /* Set whether any stroke step has yet occured + e.g. in sculpt mode, stroke doesn't start until cursor + passes over the mesh */ + int stroke_started; + + StrokeTestStart test_start; + StrokeUpdateStep update_step; + StrokeDone done; +} PaintStroke; + +/* 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]) +{ + PointerRNA itemptr; + float cur_depth, pressure = 1; + float center[3]; + PaintStroke *stroke = op->customdata; + + cur_depth = read_cached_depth(&stroke->vc, mouse[0], mouse[1]); + view3d_unproject(&stroke->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); + + stroke->last_mouse_position[0] = mouse[0]; + stroke->last_mouse_position[1] = mouse[1]; + + stroke->update_step(C, stroke, &itemptr); +} + +/* 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[1] = event->y; + + if(stroke->brush->flag & BRUSH_SMOOTH_STROKE && stroke->brush->sculpt_tool != SCULPT_TOOL_GRAB) { + 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; + + /* 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 < stroke->brush->smooth_stroke_radius * stroke->brush->smooth_stroke_radius) + return 0; + + output[0] = event->x * v + stroke->last_mouse_position[0] * u; + output[1] = event->y * v + stroke->last_mouse_position[1] * u; + } + + return 1; +} + +/* 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); +} + +/* For brushes with stroke spacing enabled, moves mouse in steps + towards the final mouse location. */ +static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const float final_mouse[2]) +{ + PaintStroke *stroke = op->customdata; + 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 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 = stroke->brush->spacing / length; + vec[0] *= scale; + vec[1] *= scale; + + steps = (int)(length / stroke->brush->spacing); + for(i = 0; i < steps; ++i, ++cnt) { + mouse[0] += vec[0]; + mouse[1] += vec[1]; + paint_brush_stroke_add_step(C, op, event, mouse); + } + } + } + + return cnt; +} + +/**** Public API ****/ + +PaintStroke *paint_stroke_new(bContext *C, StrokeTestStart test_start, + StrokeUpdateStep update_step, StrokeDone done) +{ + PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke"); + + stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C))); + view3d_set_viewcontext(C, &stroke->vc); + view3d_get_transformation(&stroke->vc, stroke->vc.obact, &stroke->mats); + + stroke->test_start = test_start; + stroke->update_step = update_step; + stroke->done = done; + + return stroke; +} + +int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + PaintStroke *stroke = op->customdata; + float mouse[2]; + + if(!stroke->stroke_started) { + stroke->last_mouse_position[0] = event->x; + stroke->last_mouse_position[1] = event->y; + stroke->stroke_started = stroke->test_start(C, op, event); + ED_region_tag_redraw(ar); + } + + if(stroke->stroke_started) { + if(paint_smooth_stroke(stroke, mouse, event)) { + if(paint_space_stroke_enabled(stroke->brush)) { + if(!paint_space_stroke(C, op, event, mouse)) + ED_region_tag_redraw(ar); + } + else + paint_brush_stroke_add_step(C, op, event, mouse); + } + else + ED_region_tag_redraw(ar); + } + + /* TODO: fix hardcoded event here */ + if(event->type == LEFTMOUSE && event->val == 0) { + stroke->done(C, stroke); + MEM_freeN(stroke); + return OPERATOR_FINISHED; + } + else + return OPERATOR_RUNNING_MODAL; +} + +ViewContext *paint_stroke_view_context(PaintStroke *stroke) +{ + return &stroke->vc; +} + diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 1a548708ec8..05faa47e0f4 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1709,122 +1709,123 @@ static void vpaint_exit(bContext *C, wmOperator *op) op->customdata= NULL; } -static int vpaint_modal(bContext *C, wmOperator *op, wmEvent *event) +static void vpaint_dot(bContext *C, struct VPaintData *vpd, wmEvent *event) { ToolSettings *ts= CTX_data_tool_settings(C); VPaint *vp= ts->vpaint; Brush *brush = paint_brush(&vp->paint); - - switch(event->type) { - case LEFTMOUSE: - if(event->val==0) { /* release */ - vpaint_exit(C, op); - return OPERATOR_FINISHED; - } - /* pass on, first press gets painted too */ - - case MOUSEMOVE: - { - struct VPaintData *vpd= op->customdata; - ViewContext *vc= &vpd->vc; - Object *ob= vc->obact; - Mesh *me= ob->data; - float mat[4][4]; - int *indexar= vpd->indexar; - int totindex, index; - short mval[2]; + ViewContext *vc= &vpd->vc; + Object *ob= vc->obact; + Mesh *me= ob->data; + float mat[4][4]; + int *indexar= vpd->indexar; + int totindex, index; + short mval[2]; - view3d_operator_needs_opengl(C); + view3d_operator_needs_opengl(C); - /* load projection matrix */ - wmMultMatrix(ob->obmat); - wmGetSingleMatrix(mat); - wmLoadMatrix(vc->rv3d->viewmat); + /* load projection matrix */ + wmMultMatrix(ob->obmat); + wmGetSingleMatrix(mat); + wmLoadMatrix(vc->rv3d->viewmat); - mval[0]= event->x - vc->ar->winrct.xmin; - mval[1]= event->y - vc->ar->winrct.ymin; + mval[0]= event->x - vc->ar->winrct.xmin; + mval[1]= event->y - vc->ar->winrct.ymin; - /* which faces are involved */ - if(vp->flag & VP_AREA) { - totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush->size); - } - else { - indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); - if(indexar[0]) totindex= 1; - else totindex= 0; - } + /* which faces are involved */ + if(vp->flag & VP_AREA) { + totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush->size); + } + else { + indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); + if(indexar[0]) totindex= 1; + else totindex= 0; + } - MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); + MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); - if(vp->flag & VP_COLINDEX) { - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + if(vp->flag & VP_COLINDEX) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - if(mface->mat_nr!=ob->actcol-1) { - indexar[index]= 0; - } - } + if(mface->mat_nr!=ob->actcol-1) { + indexar[index]= 0; } - } - if((G.f & G_FACESELECT) && me->mface) { - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + } + } + } + if((G.f & G_FACESELECT) && me->mface) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - if((mface->flag & ME_FACE_SEL)==0) - indexar[index]= 0; - } - } - } + if((mface->flag & ME_FACE_SEL)==0) + indexar[index]= 0; + } + } + } - for(index=0; index<totindex; index++) { + for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); - unsigned int *mcol= ( (unsigned int *)me->mcol) + 4*(indexar[index]-1); - unsigned int *mcolorig= ( (unsigned int *)vp->vpaint_prev) + 4*(indexar[index]-1); - int alpha; + if(indexar[index] && indexar[index]<=me->totface) { + MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + unsigned int *mcol= ( (unsigned int *)me->mcol) + 4*(indexar[index]-1); + unsigned int *mcolorig= ( (unsigned int *)vp->vpaint_prev) + 4*(indexar[index]-1); + int alpha; - if(vp->mode==VP_BLUR) { - unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128); - if(mface->v4) { - unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128); - vpd->paintcol= mcol_blend( fcol1, fcol2, 128); - } - else { - vpd->paintcol= mcol_blend( mcol[2], fcol1, 170); - } + if(vp->mode==VP_BLUR) { + unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128); + if(mface->v4) { + unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128); + vpd->paintcol= mcol_blend( fcol1, fcol2, 128); + } + else { + vpd->paintcol= mcol_blend( mcol[2], fcol1, 170); + } - } + } - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v1, mval); - if(alpha) vpaint_blend(vp, mcol, mcolorig, vpd->paintcol, alpha); + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v1, mval); + if(alpha) vpaint_blend(vp, mcol, mcolorig, vpd->paintcol, alpha); - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v2, mval); - if(alpha) vpaint_blend(vp, mcol+1, mcolorig+1, vpd->paintcol, alpha); + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v2, mval); + if(alpha) vpaint_blend(vp, mcol+1, mcolorig+1, vpd->paintcol, alpha); - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v3, mval); - if(alpha) vpaint_blend(vp, mcol+2, mcolorig+2, vpd->paintcol, alpha); + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v3, mval); + if(alpha) vpaint_blend(vp, mcol+2, mcolorig+2, vpd->paintcol, alpha); - if(mface->v4) { - alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v4, mval); - if(alpha) vpaint_blend(vp, mcol+3, mcolorig+3, vpd->paintcol, alpha); - } - } + if(mface->v4) { + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*mface->v4, mval); + if(alpha) vpaint_blend(vp, mcol+3, mcolorig+3, vpd->paintcol, alpha); } + } + } - MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); + MTC_Mat4SwapMat4(vc->rv3d->persmat, mat); - do_shared_vertexcol(me); + do_shared_vertexcol(me); - ED_region_tag_redraw(vc->ar); + ED_region_tag_redraw(vc->ar); - DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA); + DAG_object_flush_update(vc->scene, ob, OB_RECALC_DATA); +} + +static int vpaint_modal(bContext *C, wmOperator *op, wmEvent *event) +{ + switch(event->type) { + case LEFTMOUSE: + if(event->val==0) { /* release */ + vpaint_exit(C, op); + return OPERATOR_FINISHED; } + /* pass on, first press gets painted too */ + + case MOUSEMOVE: + vpaint_dot(C, op->customdata, event); break; } - + return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index f7f72d611dc..c01004f5b7e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -80,6 +80,7 @@ #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,7 +145,6 @@ 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 */ @@ -178,19 +178,6 @@ 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]) { @@ -547,7 +534,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; + float cntr[3], cntr2[3], bstr = 0; int flip = 0; calc_area_normal(sd, ss, area_normal, active_verts); @@ -1169,7 +1156,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 */ - unproject(ss->cache->mats, brush_edge, ss->cache->initial_mouse[0] + offset, + view3d_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); @@ -1194,6 +1181,7 @@ 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; @@ -1209,10 +1197,8 @@ 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(&cache->vc, cache->vc.obact, cache->mats); + view3d_get_transformation(vc, vc->obact, cache->mats); sculpt_update_mesh_elements(C); @@ -1252,7 +1238,7 @@ static void sculpt_update_cache_invariants(Sculpt *sd, SculptSession *ss, bConte } } - unproject(cache->mats, cache->true_location, cache->initial_mouse[0], cache->initial_mouse[1], cache->depth); + view3d_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; @@ -1312,7 +1298,7 @@ static void sculpt_update_cache_variants(Sculpt *sd, SculptSession *ss, PointerR /* Find the grab delta */ if(brush->sculpt_tool == SCULPT_TOOL_GRAB) { - unproject(cache->mats, grab_location, cache->mouse[0], cache->mouse[1], cache->depth); + view3d_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); @@ -1325,7 +1311,6 @@ 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; @@ -1358,13 +1343,12 @@ 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 */ - view3d_set_viewcontext(C, &vc); - RNA_float_set(op->ptr, "depth", read_cached_depth(&vc, event->x, event->y)); + RNA_float_set(op->ptr, "depth", read_cached_depth(paint_stroke_view_context(op->customdata), event->x, event->y)); sculpt_update_cache_invariants(sd, ss, C, op); } -static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) +static void sculpt_brush_stroke_init(bContext *C) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; @@ -1376,10 +1360,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *even changes are made to the texture. */ sculpt_update_tex(sd, ss); - /* add modal handler */ - WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); - - return OPERATOR_RUNNING_MODAL; + sculpt_update_mesh_elements(C); } static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) @@ -1435,157 +1416,67 @@ static void sculpt_flush_update(bContext *C) ED_region_tag_redraw(ar); } -/* 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) +static int sculpt_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *event) { - Brush *brush = paint_brush(&s->paint); - - output[0] = event->x; - output[1] = event->y; + ViewContext vc; + float cur_depth; - 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; + 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; - /* 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; + sculpt_brush_stroke_init_properties(C, op, event, ss); + sculptmode_update_all_projverts(ss); - output[0] = event->x * v + cache->mouse[0] * u; - output[1] = event->y * v + cache->mouse[1] * u; + return 1; } - - return 1; -} - -/* 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); + else + return 0; } -/* 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]) +static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; SculptSession *ss = CTX_data_active_object(C)->sculpt; - 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_update_cache_variants(sd, ss, itemptr); sculpt_restore_mesh(sd, ss); do_symmetrical_brush_actions(sd, 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; + /* Cleanup */ + sculpt_flush_update(C); // XXX: during exec, shouldn't do this every time + sculpt_post_stroke_free(ss); } -static int sculpt_brush_stroke_modal(bContext *C, wmOperator *op, wmEvent *event) +static void sculpt_stroke_done(bContext *C, struct PaintStroke *stroke) { - 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; - - 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); - - /* 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); - } + /* Finished */ if(ss->cache) { - float mouse[2]; - - 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); + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - sculpt_flush_update(C); - sculpt_post_stroke_free(ss); - } - else - ED_region_tag_redraw(ar); + request_depth_update(paint_stroke_view_context(stroke)->rv3d); + sculpt_cache_free(ss->cache); + ss->cache = NULL; + sculpt_undo_push(C, sd); } +} - /* 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); - } +static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + sculpt_brush_stroke_init(C); - return OPERATOR_FINISHED; - } + op->customdata = paint_stroke_new(C, sculpt_stroke_test_start, + sculpt_stroke_update_step, + sculpt_stroke_done); + /* add modal handler */ + WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op); + return OPERATOR_RUNNING_MODAL; } @@ -1594,10 +1485,10 @@ 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; - view3d_operator_needs_opengl(C); + sculpt_brush_stroke_init(C); + sculpt_update_cache_invariants(sd, ss, C, op); sculptmode_update_all_projverts(ss); - sculpt_update_tex(sd, ss); RNA_BEGIN(op->ptr, itemptr, "stroke") { sculpt_update_cache_variants(sd, ss, &itemptr); @@ -1627,7 +1518,7 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) /* api callbacks */ ot->invoke= sculpt_brush_stroke_invoke; - ot->modal= sculpt_brush_stroke_modal; + ot->modal= paint_stroke_modal; ot->exec= sculpt_brush_stroke_exec; ot->poll= sculpt_poll; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 58b7a70a128..ce7b6ba454d 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -63,6 +63,7 @@ #include "RE_pipeline.h" // make_stars #include "BIF_gl.h" +#include "BIF_glutil.h" #include "WM_api.h" #include "WM_types.h" @@ -543,6 +544,18 @@ void view3d_get_object_project_mat(RegionView3D *rv3d, Object *ob, float pmat[4] Mat4MulMat4(pmat, vmat, rv3d->winmat); } +/* Uses window coordinates (x,y) and depth component z to find a point in + modelspace */ +void view3d_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; +} /* use above call to get projecting mat */ void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4]) |