doxygen: blender/editors tagged.
[blender.git] / source / blender / editors / gpencil / gpencil_paint.c
index 3a82274e356eaacb6468796609f58ac038f85e2a..472750113b91d27db3bafd40535e55b3250d6732 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/gpencil/gpencil_paint.c
+ *  \ingroup edgpencil
+ */
+
+
 #include <stdio.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -45,6 +50,7 @@
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_gpencil_types.h"
+#include "DNA_windowmanager_types.h"
 
 #include "UI_view2d.h"
 
@@ -66,6 +72,8 @@
 /* Temporary 'Stroke' Operation data */
 typedef struct tGPsdata {
        Scene *scene;       /* current scene from context */
+       
+       wmWindow *win;          /* window where painting originated */
        ScrArea *sa;            /* area where painting originated */
        ARegion *ar;        /* region where painting originated */
        View2D *v2d;            /* needed for GP_STROKE_2DSPACE */
@@ -376,10 +384,18 @@ static short gp_stroke_addpoint (tGPsdata *p, int mval[2], float pressure)
        return GP_STROKEADD_INVALID;
 }
 
+
+/* temp struct for gp_stroke_smooth() */
+typedef struct tGpSmoothCo {
+       short x;
+       short y;
+} tGpSmoothCo;
+
 /* smooth a stroke (in buffer) before storing it */
 static void gp_stroke_smooth (tGPsdata *p)
 {
        bGPdata *gpd= p->gpd;
+       tGpSmoothCo *smoothArray, *spc;
        int i=0, cmx=gpd->sbuffer_size;
        
        /* only smooth if smoothing is enabled, and we're not doing a straight line */
@@ -390,17 +406,31 @@ static void gp_stroke_smooth (tGPsdata *p)
        if ((cmx <= 2) || (gpd->sbuffer == NULL))
                return;
        
-       /* apply weighting-average (note doing this along path sequentially does introduce slight error) */
-       for (i=0; i < gpd->sbuffer_size; i++) {
+       /* create a temporary smoothing coordinates buffer, use to store calculated values to prevent sequential error */
+       smoothArray = MEM_callocN(sizeof(tGpSmoothCo)*cmx, "gp_stroke_smooth smoothArray");
+       
+       /* first pass: calculate smoothing coordinates using weighted-averages */
+       for (i=0, spc=smoothArray; i < gpd->sbuffer_size; i++, spc++) {
+               const tGPspoint *pc= (((tGPspoint *)gpd->sbuffer) + i);
+               const tGPspoint *pb= (i-1 > 0)?(pc-1):(pc);
+               const tGPspoint *pa= (i-2 > 0)?(pc-2):(pb);
+               const tGPspoint *pd= (i+1 < cmx)?(pc+1):(pc);
+               const tGPspoint *pe= (i+2 < cmx)?(pc+2):(pd);
+               
+               spc->x= (short)(0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
+               spc->y= (short)(0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
+       }
+       
+       /* second pass: apply smoothed coordinates */
+       for (i=0, spc=smoothArray; i < gpd->sbuffer_size; i++, spc++) {
                tGPspoint *pc= (((tGPspoint *)gpd->sbuffer) + i);
-               tGPspoint *pb= (i-1 > 0)?(pc-1):(pc);
-               tGPspoint *pa= (i-2 > 0)?(pc-2):(pb);
-               tGPspoint *pd= (i+1 < cmx)?(pc+1):(pc);
-               tGPspoint *pe= (i+2 < cmx)?(pc+2):(pd);
                
-               pc->x= (short)(0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
-               pc->y= (short)(0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
+               pc->x = spc->x;
+               pc->y = spc->y;
        }
+       
+       /* free temp array */
+       MEM_freeN(smoothArray);
 }
 
 /* simplify a stroke (in buffer) before storing it 
@@ -544,18 +574,25 @@ static void gp_stroke_newfrombuffer (tGPsdata *p)
                
                /* get an array of depths, far depths are blended */
                if (gpencil_project_check(p)) {
-                       short mval[2];
+                       short mval[2], mval_prev[2]= {0};
                        int interp_depth = 0;
                        int found_depth = 0;
                        
                        depth_arr= MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
-                       
+
                        for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
                                mval[0]= ptc->x; mval[1]= ptc->y;
-                               if (view_autodist_depth(p->ar, mval, depth_margin, depth_arr+i) == 0)
+
+                               if ((view_autodist_depth(p->ar, mval, depth_margin, depth_arr+i) == 0) &&
+                                       (i && (view_autodist_depth_segment(p->ar, mval, mval_prev, depth_margin + 1, depth_arr+i) == 0))
+                               ) {
                                        interp_depth= TRUE;
-                               else
+                               }
+                               else {
                                        found_depth= TRUE;
+                               }
+
+                               VECCOPY2D(mval_prev, mval);
                        }
                        
                        if (found_depth == FALSE) {
@@ -888,15 +925,16 @@ static tGPsdata *gp_session_initpaint (bContext *C)
        /* create new context data */
        p= MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
        
-       /* pass on current scene */
+       /* pass on current scene and window */
        p->scene= CTX_data_scene(C);
+       p->win= CTX_wm_window(C);
        
        switch (curarea->spacetype) {
                /* supported views first */
                case SPACE_VIEW3D:
                {
-                       View3D *v3d= curarea->spacedata.first;
-                       RegionView3D *rv3d= ar->regiondata;
+                       // View3D *v3d= curarea->spacedata.first;
+                       // RegionView3D *rv3d= ar->regiondata;
                        
                        /* set current area 
                         *      - must verify that region data is 3D-view (and not something else)
@@ -910,12 +948,6 @@ static tGPsdata *gp_session_initpaint (bContext *C)
                                        printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable \n");
                                return p;
                        }
-                       
-                       /* for camera view set the subrect */
-                       if(rv3d->persp == RV3D_CAMOB) {
-                               view3d_calc_camera_border(p->scene, p->ar, NULL, v3d, &p->subrect_data, -1); /* negative shift */
-                               p->subrect= &p->subrect_data;
-                       }
 
 #if 0 // XXX will this sort of antiquated stuff be restored?
                        /* check that gpencil data is allowed to be drawn */
@@ -1097,9 +1129,17 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode)
                switch (p->sa->spacetype) {
                        case SPACE_VIEW3D:
                        {
+                               View3D *v3d= p->sa->spacedata.first;
                                RegionView3D *rv3d= p->ar->regiondata;
                                float rvec[3];
                                
+                               /* for camera view set the subrect */
+                               if (rv3d->persp == RV3D_CAMOB) {
+                                       view3d_calc_camera_border(p->scene, p->ar, NULL, v3d, &p->subrect_data, -1); /* negative shift */
+                                       p->subrect= &p->subrect_data;
+                               }
+                               
+                               /* get reference point for 3d space placement */
                                gp_get_3d_reference(p, rvec);
                                initgrabz(rv3d, rvec[0], rvec[1], rvec[2]);
                                
@@ -1172,6 +1212,17 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode)
 /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
 static void gp_paint_strokeend (tGPsdata *p)
 {
+       /* for surface sketching, need to set the right OpenGL context stuff so that 
+        * the conversions will project the values correctly...
+        */
+       if (gpencil_project_check(p)) {
+               View3D *v3d= p->sa->spacedata.first;
+               
+               /* need to restore the original projection settings before packing up */
+               view3d_region_operator_needs_opengl(p->win, p->ar);
+               view_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1:0);
+       }
+       
        /* check if doing eraser or not */
        if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
                /* smooth stroke before transferring? */
@@ -1247,14 +1298,6 @@ static void gpencil_draw_exit (bContext *C, wmOperator *op)
        }
        
        /* cleanup */
-       if (gpencil_project_check(p)) {
-               View3D *v3d= p->sa->spacedata.first;
-               
-               /* need to restore the original projection settings before packing up */
-               view3d_operator_needs_opengl(C);
-               view_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1:0);
-       }
-
        gp_paint_cleanup(p);
        gp_session_cleanup(p);
        
@@ -1573,7 +1616,7 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
                        if (GPENCIL_SKETCH_SESSIONS_ON(p->scene)) {
                                /* end stroke only, and then wait to resume painting soon */
                                //printf("\t\tGP - end stroke only\n");
-                               gp_paint_strokeend(p);
+                               gp_paint_cleanup(p);
                                p->status= GP_STATUS_IDLING;
                                
                                /* we've just entered idling state, so this event was processed (but no others yet) */