2.5/Paint:
authorNicholas Bishop <nicholasbishop@gmail.com>
Wed, 19 Aug 2009 21:24:52 +0000 (21:24 +0000)
committerNicholas Bishop <nicholasbishop@gmail.com>
Wed, 19 Aug 2009 21:24:52 +0000 (21:24 +0000)
* Some initial work on a new paint abstraction, PaintStroke. For now, most of the code just pulls out stroke-related stuff from sculpt mode, next step is to integrate the other paint modes to use this. It'll enable stuff like smooth stroke for all the paint modes with less code duplication.

source/blender/editors/include/ED_view3d.h
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_stroke.c [new file with mode: 0644]
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_view3d/view3d_view.c

index 07aa44cadd85d80362dbf31f5638adbf785c195d..fd1b7e1351d40a0b690a9c6e156fec5f6c583386 100644 (file)
@@ -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);
index 40423e17fe43bb7db681357c2de374e98c1c0a8d..41764a70686f4743174fdacf10da0821e97ea844 100644 (file)
 #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 (file)
index 0000000..634b826
--- /dev/null
@@ -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;
+}
+
index 1a548708ec89cd4b3cd4c0c919a1a7acdf98b964..05faa47e0f4be559c61c129e6c437bddcc814ef6 100644 (file)
@@ -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;
 }
 
index f7f72d611dc46a690a7a5458212ff956b5032910..c01004f5b7edfb0ee880362a2c857955951a9313 100644 (file)
@@ -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;
        
index 58b7a70a12852169b7244bc7cdadba63c343e52c..ce7b6ba454da8c8804fbc53d0dd7637e4523f6d7 100644 (file)
@@ -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])