~ubuntu-branches/ubuntu/trusty/blender/trusty

« back to all changes in this revision

Viewing changes to source/blender/editors/gpencil/gpencil_paint.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-03-06 12:08:47 UTC
  • mfrom: (1.5.1) (14.1.8 experimental)
  • Revision ID: package-import@ubuntu.com-20130306120847-frjfaryb2zrotwcg
Tags: 2.66a-1ubuntu1
* Resynchronize with Debian (LP: #1076930, #1089256, #1052743, #999024,
  #1122888, #1147084)
* debian/control:
  - Lower build-depends on libavcodec-dev since we're not
    doing the libav9 transition in Ubuntu yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
 *  \ingroup edgpencil
28
28
 */
29
29
 
30
 
 
31
30
#include <stdio.h>
32
31
#include <stddef.h>
33
32
#include <stdlib.h>
40
39
#include "BLI_math.h"
41
40
#include "BLI_utildefines.h"
42
41
 
 
42
#include "BLF_translation.h"
 
43
 
 
44
#include "PIL_time.h"
 
45
 
43
46
#include "BKE_gpencil.h"
44
47
#include "BKE_context.h"
45
48
#include "BKE_global.h"
46
49
#include "BKE_report.h"
 
50
#include "BKE_tracking.h"
47
51
 
48
52
#include "DNA_object_types.h"
49
53
#include "DNA_scene_types.h"
55
59
#include "ED_gpencil.h"
56
60
#include "ED_screen.h"
57
61
#include "ED_view3d.h"
 
62
#include "ED_clip.h"
 
63
 
 
64
#include "BIF_gl.h"
 
65
#include "BIF_glutil.h"
58
66
 
59
67
#include "RNA_access.h"
60
 
 
61
68
#include "RNA_define.h"
 
69
 
62
70
#include "WM_api.h"
63
71
#include "WM_types.h"
64
72
 
71
79
typedef struct tGPsdata {
72
80
        Scene *scene;       /* current scene from context */
73
81
        
74
 
        wmWindow *win;          /* window where painting originated */
75
 
        ScrArea *sa;            /* area where painting originated */
 
82
        wmWindow *win;      /* window where painting originated */
 
83
        ScrArea *sa;        /* area where painting originated */
76
84
        ARegion *ar;        /* region where painting originated */
77
 
        View2D *v2d;            /* needed for GP_STROKE_2DSPACE */
78
 
        rctf *subrect;          /* for using the camera rect within the 3d view */
 
85
        View2D *v2d;        /* needed for GP_STROKE_2DSPACE */
 
86
        rctf *subrect;      /* for using the camera rect within the 3d view */
79
87
        rctf subrect_data;
80
88
        
81
 
        
82
 
#if 0 // XXX review this 2d image stuff...
83
 
        ImBuf *ibuf;            /* needed for GP_STROKE_2DIMAGE */
84
 
        struct IBufViewSettings {
85
 
                int offsx, offsy;                       /* offsets */
86
 
                int sizex, sizey;                       /* dimensions to use as scale-factor */
87
 
        } im2d_settings;        /* needed for GP_STROKE_2DIMAGE */
88
 
#endif
89
 
        
90
 
        PointerRNA ownerPtr;/* pointer to owner of gp-datablock */
91
 
        bGPdata *gpd;           /* gp-datablock layer comes from */
92
 
        bGPDlayer *gpl;         /* layer we're working on */
93
 
        bGPDframe *gpf;         /* frame we're working on */
94
 
        
95
 
        short status;           /* current status of painting */
96
 
        short paintmode;        /* mode for painting */
97
 
        
98
 
        int mval[2];            /* current mouse-position */
99
 
        int mvalo[2];           /* previous recorded mouse-position */
100
 
        
101
 
        float pressure;         /* current stylus pressure */
102
 
        float opressure;        /* previous stylus pressure */
103
 
        
104
 
        short radius;           /* radius of influence for eraser */
105
 
        short flags;            /* flags that can get set during runtime */
 
89
        PointerRNA ownerPtr; /* pointer to owner of gp-datablock */
 
90
        bGPdata *gpd;       /* gp-datablock layer comes from */
 
91
        bGPDlayer *gpl;     /* layer we're working on */
 
92
        bGPDframe *gpf;     /* frame we're working on */
 
93
 
 
94
        short status;       /* current status of painting */
 
95
        short paintmode;    /* mode for painting */
 
96
        
 
97
        int mval[2];        /* current mouse-position */
 
98
        int mvalo[2];       /* previous recorded mouse-position */
 
99
        
 
100
        float pressure;     /* current stylus pressure */
 
101
        float opressure;    /* previous stylus pressure */
 
102
        
 
103
        short radius;       /* radius of influence for eraser */
 
104
        short flags;        /* flags that can get set during runtime */
 
105
        
 
106
        /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
 
107
         * float (and its 7 digits precision) is definitively not enough here!
 
108
         * double, with its 15 digits precision, ensures us millisecond precision for a few centuries at least.
 
109
         */
 
110
        double inittime;    /* Used when converting to path */
 
111
        double curtime;     /* Used when converting to path */
 
112
        double ocurtime;    /* Used when converting to path */
106
113
 
107
114
        float imat[4][4];   /* inverted transformation matrix applying when converting coords from screen-space
108
115
                             * to region space */
109
 
 
110
 
        float custom_color[4]; /* custom color for (?) */
 
116
        
 
117
        float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
 
118
        
 
119
        void *erasercursor; /* radial cursor data for drawing eraser */
111
120
} tGPsdata;
112
121
 
113
122
/* values for tGPsdata->status */
114
123
enum {
115
 
        GP_STATUS_IDLING = 0,   /* stroke isn't in progress yet */
116
 
        GP_STATUS_PAINTING,             /* a stroke is in progress */
117
 
        GP_STATUS_ERROR,                /* something wasn't correctly set up */
118
 
        GP_STATUS_DONE                  /* painting done */
 
124
        GP_STATUS_IDLING = 0,   /* stroke isn't in progress yet */
 
125
        GP_STATUS_PAINTING,     /* a stroke is in progress */
 
126
        GP_STATUS_ERROR,        /* something wasn't correctly set up */
 
127
        GP_STATUS_DONE          /* painting done */
119
128
};
120
129
 
121
130
/* Return flags for adding points to stroke buffer */
122
131
enum {
123
 
        GP_STROKEADD_INVALID    = -2,           /* error occurred - insufficient info to do so */
124
 
        GP_STROKEADD_OVERFLOW   = -1,           /* error occurred - cannot fit any more points */
125
 
        GP_STROKEADD_NORMAL,                            /* point was successfully added */
126
 
        GP_STROKEADD_FULL                                       /* cannot add any more points to buffer */
 
132
        GP_STROKEADD_INVALID    = -2,       /* error occurred - insufficient info to do so */
 
133
        GP_STROKEADD_OVERFLOW   = -1,       /* error occurred - cannot fit any more points */
 
134
        GP_STROKEADD_NORMAL,                /* point was successfully added */
 
135
        GP_STROKEADD_FULL                   /* cannot add any more points to buffer */
127
136
};
128
137
 
129
138
/* Runtime flags */
130
139
enum {
131
 
        GP_PAINTFLAG_FIRSTRUN           = (1<<0),       /* operator just started */
132
 
        GP_PAINTFLAG_STROKEADDED        = (1<<1)        /* stroke was already added during draw session */
 
140
        GP_PAINTFLAG_FIRSTRUN       = (1 << 0),    /* operator just started */
 
141
        GP_PAINTFLAG_STROKEADDED    = (1 << 1)
133
142
};
134
143
 
135
144
/* ------ */
136
145
 
137
146
/* maximum sizes of gp-session buffer */
138
 
#define GP_STROKE_BUFFER_MAX    5000
 
147
#define GP_STROKE_BUFFER_MAX    5000
139
148
 
140
149
/* Macros for accessing sensitivity thresholds... */
141
 
        /* minimum number of pixels mouse should move before new point created */
142
 
#define MIN_MANHATTEN_PX        (U.gp_manhattendist)
143
 
        /* minimum length of new segment before new point can be added */
144
 
#define MIN_EUCLIDEAN_PX        (U.gp_euclideandist)
 
150
/* minimum number of pixels mouse should move before new point created */
 
151
#define MIN_MANHATTEN_PX    (U.gp_manhattendist)
 
152
/* minimum length of new segment before new point can be added */
 
153
#define MIN_EUCLIDEAN_PX    (U.gp_euclideandist)
 
154
 
 
155
static int gp_stroke_added_check(tGPsdata *p)
 
156
{
 
157
        return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
 
158
}
 
159
 
 
160
static void gp_stroke_added_enable(tGPsdata *p)
 
161
{
 
162
        BLI_assert(p->gpf->strokes.last != NULL);
 
163
        p->flags |= GP_PAINTFLAG_STROKEADDED;
 
164
}
145
165
 
146
166
/* ------ */
147
167
/* Forward defines for some functions... */
152
172
/* Context Wrangling... */
153
173
 
154
174
/* check if context is suitable for drawing */
155
 
static int gpencil_draw_poll (bContext *C)
 
175
static int gpencil_draw_poll(bContext *C)
156
176
{
157
177
        if (ED_operator_regionactive(C)) {
158
178
                /* check if current context can support GPencil data */
175
195
}
176
196
 
177
197
/* check if projecting strokes into 3d-geometry in the 3D-View */
178
 
static int gpencil_project_check (tGPsdata *p)
 
198
static int gpencil_project_check(tGPsdata *p)
179
199
{
180
 
        bGPdata *gpd= p->gpd;
 
200
        bGPdata *gpd = p->gpd;
181
201
        return ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) && (p->gpd->flag & (GP_DATA_DEPTH_VIEW | GP_DATA_DEPTH_STROKE)));
182
202
}
183
203
 
187
207
/* Utilities --------------------------------- */
188
208
 
189
209
/* get the reference point for stroke-point conversions */
190
 
static void gp_get_3d_reference (tGPsdata *p, float vec[3])
 
210
static void gp_get_3d_reference(tGPsdata *p, float vec[3])
191
211
{
192
 
        View3D *v3d= p->sa->spacedata.first;
193
 
        float *fp= give_cursor(p->scene, v3d);
 
212
        View3D *v3d = p->sa->spacedata.first;
 
213
        const float *fp = give_cursor(p->scene, v3d);
194
214
        
195
215
        /* the reference point used depends on the owner... */
196
 
#if 0 // XXX: disabled for now, since we can't draw relative to the owner yet
 
216
#if 0 /* XXX: disabled for now, since we can't draw relative to the owner yet */
197
217
        if (p->ownerPtr.type == &RNA_Object) {
198
 
                Object *ob= (Object *)p->ownerPtr.data;
 
218
                Object *ob = (Object *)p->ownerPtr.data;
199
219
                
200
220
                /* active Object 
201
 
                 *      - use relative distance of 3D-cursor from object center 
 
221
                 *  - use relative distance of 3D-cursor from object center
202
222
                 */
203
223
                sub_v3_v3v3(vec, fp, ob->loc);
204
224
        }
205
225
        else
206
 
#endif  
 
226
#endif
207
227
        {
208
228
                /* use 3D-cursor */
209
229
                copy_v3_v3(vec, fp);
213
233
/* Stroke Editing ---------------------------- */
214
234
 
215
235
/* check if the current mouse position is suitable for adding a new point */
216
 
static short gp_stroke_filtermval (tGPsdata *p, const int mval[2], int pmval[2])
 
236
static short gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2])
217
237
{
218
 
        int dx= abs(mval[0] - pmval[0]);
219
 
        int dy= abs(mval[1] - pmval[1]);
 
238
        int dx = abs(mval[0] - pmval[0]);
 
239
        int dy = abs(mval[1] - pmval[1]);
220
240
        
221
241
        /* if buffer is empty, just let this go through (i.e. so that dots will work) */
222
242
        if (p->gpd->sbuffer_size == 0)
232
252
         *      - prevents points being added too densely
233
253
         *      - distance here doesn't use sqrt to prevent slowness... we should still be safe from overflows though
234
254
         */
235
 
        else if ((dx*dx + dy*dy) > MIN_EUCLIDEAN_PX*MIN_EUCLIDEAN_PX)
 
255
        else if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX)
236
256
                return 1;
237
257
        
238
258
        /* mouse 'didn't move' */
241
261
}
242
262
 
243
263
/* convert screen-coordinates to buffer-coordinates */
244
 
// XXX this method needs a total overhaul!
245
 
static void gp_stroke_convertcoords (tGPsdata *p, const int mval[2], float out[3], float *depth)
 
264
/* XXX this method needs a total overhaul! */
 
265
static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth)
246
266
{
247
 
        bGPdata *gpd= p->gpd;
 
267
        bGPdata *gpd = p->gpd;
248
268
        
249
269
        /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
250
270
        if (gpd->sbuffer_sflag & GP_STROKE_3DSPACE) {
257
277
                        int mval_prj[2];
258
278
                        float rvec[3], dvec[3];
259
279
                        float mval_f[2];
260
 
 
 
280
                        
261
281
                        /* Current method just converts each point in screen-coordinates to
262
282
                         * 3D-coordinates using the 3D-cursor as reference. In general, this
263
283
                         * works OK, but it could of course be improved.
270
290
                        gp_get_3d_reference(p, rvec);
271
291
                        
272
292
                        /* method taken from editview.c - mouse_cursor() */
273
 
                        project_int_noclip(p->ar, rvec, mval_prj);
274
 
 
275
 
                        VECSUB2D(mval_f, mval_prj, mval);
276
 
                        ED_view3d_win_to_delta(p->ar, mval_f, dvec);
277
 
                        sub_v3_v3v3(out, rvec, dvec);
 
293
                        /* TODO, use ED_view3d_project_float_global */
 
294
                        if (ED_view3d_project_int_global(p->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
 
295
                                VECSUB2D(mval_f, mval_prj, mval);
 
296
                                ED_view3d_win_to_delta(p->ar, mval_f, dvec);
 
297
                                sub_v3_v3v3(out, rvec, dvec);
 
298
                        }
 
299
                        else {
 
300
                                zero_v3(out);
 
301
                        }
278
302
                }
279
303
        }
280
304
        
284
308
                mul_v3_m4v3(out, p->imat, out);
285
309
        }
286
310
        
287
 
#if 0
288
 
        /* 2d - on image 'canvas' (assume that p->v2d is set) */
289
 
        else if (gpd->sbuffer_sflag & GP_STROKE_2DIMAGE) {
290
 
                int sizex, sizey, offsx, offsy;
291
 
                
292
 
                /* get stored settings 
293
 
                 *      - assume that these have been set already (there are checks that set sane 'defaults' just in case)
294
 
                 */
295
 
                sizex= p->im2d_settings.sizex;
296
 
                sizey= p->im2d_settings.sizey;
297
 
                offsx= p->im2d_settings.offsx;
298
 
                offsy= p->im2d_settings.offsy;
299
 
                
300
 
                /* calculate new points */
301
 
                out[0]= (float)(mval[0] - offsx) / (float)sizex;
302
 
                out[1]= (float)(mval[1] - offsy) / (float)sizey;
303
 
        }
304
 
#endif
305
 
        
306
311
        /* 2d - relative to screen (viewport area) */
307
312
        else {
308
313
                if (p->subrect == NULL) { /* normal 3D view */
310
315
                        out[1] = (float)(mval[1]) / (float)(p->ar->winy) * 100;
311
316
                }
312
317
                else { /* camera view, use subrect */
313
 
                        out[0]= ((mval[0] - p->subrect->xmin) / ((p->subrect->xmax - p->subrect->xmin))) * 100;
314
 
                        out[1]= ((mval[1] - p->subrect->ymin) / ((p->subrect->ymax - p->subrect->ymin))) * 100;
 
318
                        out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
 
319
                        out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
315
320
                }
316
321
        }
317
322
}
318
323
 
319
324
/* add current stroke-point to buffer (returns whether point was successfully added) */
320
 
static short gp_stroke_addpoint (tGPsdata *p, const int mval[2], float pressure)
 
325
static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, double curtime)
321
326
{
322
 
        bGPdata *gpd= p->gpd;
 
327
        bGPdata *gpd = p->gpd;
323
328
        tGPspoint *pt;
324
 
        
 
329
 
325
330
        /* check painting mode */
326
331
        if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
327
332
                /* straight lines only - i.e. only store start and end point in buffer */
328
333
                if (gpd->sbuffer_size == 0) {
329
334
                        /* first point in buffer (start point) */
330
 
                        pt= (tGPspoint *)(gpd->sbuffer);
 
335
                        pt = (tGPspoint *)(gpd->sbuffer);
331
336
                        
332
337
                        /* store settings */
333
338
                        copy_v2_v2_int(&pt->x, mval);
334
 
                        pt->pressure= pressure;
 
339
                        pt->pressure = pressure;
 
340
                        pt->time = (float)(curtime - p->inittime);
335
341
                        
336
342
                        /* increment buffer size */
337
343
                        gpd->sbuffer_size++;
340
346
                        /* normally, we just reset the endpoint to the latest value 
341
347
                         *      - assume that pointers for this are always valid...
342
348
                         */
343
 
                        pt= ((tGPspoint *)(gpd->sbuffer) + 1);
 
349
                        pt = ((tGPspoint *)(gpd->sbuffer) + 1);
344
350
                        
345
351
                        /* store settings */
346
352
                        copy_v2_v2_int(&pt->x, mval);
347
 
                        pt->pressure= pressure;
 
353
                        pt->pressure = pressure;
 
354
                        pt->time = (float)(curtime - p->inittime);
348
355
                        
349
356
                        /* if this is just the second point we've added, increment the buffer size
350
357
                         * so that it will be drawn properly...
351
358
                         * otherwise, just leave it alone, otherwise we get problems
352
359
                         */
353
360
                        if (gpd->sbuffer_size != 2)
354
 
                                gpd->sbuffer_size= 2;
 
361
                                gpd->sbuffer_size = 2;
355
362
                }
356
363
                
357
364
                /* can keep carrying on this way :) */
363
370
                        return GP_STROKEADD_OVERFLOW;
364
371
                
365
372
                /* get pointer to destination point */
366
 
                pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
 
373
                pt = ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
367
374
                
368
375
                /* store settings */
369
376
                copy_v2_v2_int(&pt->x, mval);
370
 
                pt->pressure= pressure;
 
377
                pt->pressure = pressure;
 
378
                pt->time = (float)(curtime - p->inittime);
371
379
                
372
380
                /* increment counters */
373
381
                gpd->sbuffer_size++;
380
388
        }
381
389
        else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
382
390
                /* get pointer to destination point */
383
 
                pt= (tGPspoint *)(gpd->sbuffer);
384
 
 
 
391
                pt = (tGPspoint *)(gpd->sbuffer);
 
392
                
385
393
                /* store settings */
386
394
                copy_v2_v2_int(&pt->x, mval);
387
 
                pt->pressure= pressure;
388
 
 
 
395
                pt->pressure = pressure;
 
396
                pt->time = (float)(curtime - p->inittime);
 
397
                
389
398
                /* if there's stroke for this poly line session add (or replace last) point
390
399
                 * to stroke. This allows to draw lines more interactively (see new segment
391
 
                 * during mouse slide, i.e.) 
 
400
                 * during mouse slide, e.g.)
392
401
                 */
393
 
                if (p->flags & GP_PAINTFLAG_STROKEADDED) {
394
 
                        bGPDstroke *gps= p->gpf->strokes.last;
 
402
                if (gp_stroke_added_check(p)) {
 
403
                        bGPDstroke *gps = p->gpf->strokes.last;
395
404
                        bGPDspoint *pts;
396
 
 
 
405
                        
397
406
                        /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
398
407
                        if (gpd->sbuffer_size == 0) {
399
 
                                gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint)*(gps->totpoints+1));
 
408
                                gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
400
409
                                gps->totpoints++;
401
410
                        }
402
 
 
403
 
                        pts = &gps->points[gps->totpoints-1];
404
 
 
405
 
                        /* special case for poly lines: normally, depth is needed only when creating new stroke from buffer,
406
 
                         * but poly lines are converting to stroke instantly, so initialize depth buffer before converting coordinates 
 
411
                        
 
412
                        pts = &gps->points[gps->totpoints - 1];
 
413
                        
 
414
                        /* special case for poly lines: normally,
 
415
                         * depth is needed only when creating new stroke from buffer,
 
416
                         * but poly lines are converting to stroke instantly,
 
417
                         * so initialize depth buffer before converting coordinates
407
418
                         */
408
419
                        if (gpencil_project_check(p)) {
409
 
                                View3D *v3d= p->sa->spacedata.first;
410
 
 
 
420
                                View3D *v3d = p->sa->spacedata.first;
 
421
                                
411
422
                                view3d_region_operator_needs_opengl(p->win, p->ar);
412
 
                                ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1:0);
 
423
                                ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
413
424
                        }
414
 
 
 
425
                        
415
426
                        /* convert screen-coordinates to appropriate coordinates (and store them) */
416
427
                        gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL);
417
 
 
418
 
                        /* copy pressure */
419
 
                        pts->pressure= pt->pressure;
 
428
                        
 
429
                        /* copy pressure and time */
 
430
                        pts->pressure = pt->pressure;
 
431
                        pts->time = pt->time;
420
432
                }
421
 
 
 
433
                
422
434
                /* increment counters */
423
435
                if (gpd->sbuffer_size == 0)
424
436
                        gpd->sbuffer_size++;
425
 
 
 
437
                
426
438
                return GP_STROKEADD_NORMAL;
427
439
        }
428
440
        
430
442
        return GP_STROKEADD_INVALID;
431
443
}
432
444
 
433
 
 
434
 
/* temp struct for gp_stroke_smooth() */
435
 
typedef struct tGpSmoothCo {
436
 
        int x;
437
 
        int y;
438
 
} tGpSmoothCo;
439
 
 
440
445
/* smooth a stroke (in buffer) before storing it */
441
 
static void gp_stroke_smooth (tGPsdata *p)
 
446
static void gp_stroke_smooth(tGPsdata *p)
442
447
{
443
 
        bGPdata *gpd= p->gpd;
444
 
        tGpSmoothCo *smoothArray, *spc;
445
 
        int i=0, cmx=gpd->sbuffer_size;
 
448
        bGPdata *gpd = p->gpd;
 
449
        tGPspoint *spt, tmp_spt[3];
 
450
        int i = 0, cmx = gpd->sbuffer_size;
446
451
        
447
452
        /* only smooth if smoothing is enabled, and we're not doing a straight line */
448
453
        if (!(U.gp_settings & GP_PAINT_DOSMOOTH) || ELEM(p->paintmode, GP_PAINTMODE_DRAW_STRAIGHT, GP_PAINTMODE_DRAW_POLY))
452
457
        if ((cmx <= 2) || (gpd->sbuffer == NULL))
453
458
                return;
454
459
        
455
 
        /* create a temporary smoothing coordinates buffer, use to store calculated values to prevent sequential error */
456
 
        smoothArray = MEM_callocN(sizeof(tGpSmoothCo)*cmx, "gp_stroke_smooth smoothArray");
457
 
        
458
 
        /* first pass: calculate smoothing coordinates using weighted-averages */
459
 
        for (i=0, spc=smoothArray; i < gpd->sbuffer_size; i++, spc++) {
460
 
                const tGPspoint *pc= (((tGPspoint *)gpd->sbuffer) + i);
461
 
                const tGPspoint *pb= (i-1 > 0)?(pc-1):(pc);
462
 
                const tGPspoint *pa= (i-2 > 0)?(pc-2):(pb);
463
 
                const tGPspoint *pd= (i+1 < cmx)?(pc+1):(pc);
464
 
                const tGPspoint *pe= (i+2 < cmx)?(pc+2):(pd);
465
 
                
466
 
                spc->x= (int)(0.1*pa->x + 0.2*pb->x + 0.4*pc->x + 0.2*pd->x + 0.1*pe->x);
467
 
                spc->y= (int)(0.1*pa->y + 0.2*pb->y + 0.4*pc->y + 0.2*pd->y + 0.1*pe->y);
468
 
        }
469
 
        
470
 
        /* second pass: apply smoothed coordinates */
471
 
        for (i=0, spc=smoothArray; i < gpd->sbuffer_size; i++, spc++) {
472
 
                tGPspoint *pc= (((tGPspoint *)gpd->sbuffer) + i);
473
 
 
474
 
                copy_v2_v2_int(&pc->x, &spc->x);
475
 
        }
476
 
        
477
 
        /* free temp array */
478
 
        MEM_freeN(smoothArray);
 
460
        /* Calculate smoothing coordinates using weighted-averages 
 
461
         * WARNING: we do NOT smooth first and last points (to avoid shrinkage)
 
462
         */
 
463
        spt = (tGPspoint *)gpd->sbuffer;
 
464
        
 
465
        /* This (tmp_spt) small array stores the last two points' original coordinates, 
 
466
         * as we don't want to use already averaged ones! It is used as a cyclic buffer...
 
467
         */
 
468
        tmp_spt[0] = *spt;
 
469
        for (i = 1, spt++; i < cmx - 1; i++, spt++) {
 
470
                const tGPspoint *pc = spt;
 
471
                const tGPspoint *pb = &tmp_spt[(i - 1) % 3];
 
472
                const tGPspoint *pa = (i - 1 > 0) ? (&tmp_spt[(i - 2) % 3]) : (pb);
 
473
                const tGPspoint *pd = pc + 1;
 
474
                const tGPspoint *pe = (i + 2 < cmx) ? (pc + 2) : (pd);
 
475
                
 
476
                /* Store current point's original state for the two next points! */
 
477
                tmp_spt[i % 3] = *spt;
 
478
                
 
479
                spt->x = (int)(0.1 * pa->x + 0.2 * pb->x + 0.4 * pc->x + 0.2 * pd->x + 0.1 * pe->x);
 
480
                spt->y = (int)(0.1 * pa->y + 0.2 * pb->y + 0.4 * pc->y + 0.2 * pd->y + 0.1 * pe->y);
 
481
        }
479
482
}
480
483
 
481
484
/* simplify a stroke (in buffer) before storing it 
482
485
 *      - applies a reverse Chaikin filter
483
486
 *      - code adapted from etch-a-ton branch (editarmature_sketch.c)
484
487
 */
485
 
static void gp_stroke_simplify (tGPsdata *p)
 
488
static void gp_stroke_simplify(tGPsdata *p)
486
489
{
487
 
        bGPdata *gpd= p->gpd;
488
 
        tGPspoint *old_points= (tGPspoint *)gpd->sbuffer;
489
 
        short num_points= gpd->sbuffer_size;
490
 
        short flag= gpd->sbuffer_sflag;
 
490
        bGPdata *gpd = p->gpd;
 
491
        tGPspoint *old_points = (tGPspoint *)gpd->sbuffer;
 
492
        short num_points = gpd->sbuffer_size;
 
493
        short flag = gpd->sbuffer_sflag;
491
494
        short i, j;
492
495
        
493
496
        /* only simplify if simplification is enabled, and we're not doing a straight line */
497
500
        /* don't simplify if less than 4 points in buffer */
498
501
        if ((num_points <= 4) || (old_points == NULL))
499
502
                return;
500
 
                
 
503
        
501
504
        /* clear buffer (but don't free mem yet) so that we can write to it 
502
505
         *      - firstly set sbuffer to NULL, so a new one is allocated
503
506
         *      - secondly, reset flag after, as it gets cleared auto
504
507
         */
505
 
        gpd->sbuffer= NULL;
 
508
        gpd->sbuffer = NULL;
506
509
        gp_session_validatebuffer(p);
507
510
        gpd->sbuffer_sflag = flag;
508
511
        
514
517
                co[0] += (float)(old_points[offs].x * sfac); \
515
518
                co[1] += (float)(old_points[offs].y * sfac); \
516
519
                pressure += old_points[offs].pressure * sfac; \
517
 
        }
 
520
                time += old_points[offs].time * sfac; \
 
521
        } (void)0
518
522
        
 
523
        /* XXX Here too, do not lose start and end points! */
 
524
        gp_stroke_addpoint(p, &old_points->x, old_points->pressure, p->inittime + (double)old_points->time);
519
525
        for (i = 0, j = 0; i < num_points; i++) {
520
526
                if (i - j == 3) {
521
 
                        float co[2], pressure;
 
527
                        float co[2], pressure, time;
522
528
                        int mco[2];
523
529
                        
524
530
                        /* initialize values */
525
 
                        co[0]= 0;
526
 
                        co[1]= 0;
527
 
                        pressure = 0;
 
531
                        co[0] = 0.0f;
 
532
                        co[1] = 0.0f;
 
533
                        pressure = 0.0f;
 
534
                        time = 0.0f;
528
535
                        
529
536
                        /* using macro, calculate new point */
530
537
                        GP_SIMPLIFY_AVPOINT(j, -0.25f);
531
 
                        GP_SIMPLIFY_AVPOINT(j+1, 0.75f);
532
 
                        GP_SIMPLIFY_AVPOINT(j+2, 0.75f);
533
 
                        GP_SIMPLIFY_AVPOINT(j+3, -0.25f);
 
538
                        GP_SIMPLIFY_AVPOINT(j + 1, 0.75f);
 
539
                        GP_SIMPLIFY_AVPOINT(j + 2, 0.75f);
 
540
                        GP_SIMPLIFY_AVPOINT(j + 3, -0.25f);
534
541
                        
535
542
                        /* set values for adding */
536
 
                        mco[0]= (int)co[0];
537
 
                        mco[1]= (int)co[1];
 
543
                        mco[0] = (int)co[0];
 
544
                        mco[1] = (int)co[1];
538
545
                        
539
546
                        /* ignore return values on this... assume to be ok for now */
540
 
                        gp_stroke_addpoint(p, mco, pressure);
 
547
                        gp_stroke_addpoint(p, mco, pressure, p->inittime + (double)time);
541
548
                        
542
549
                        j += 2;
543
550
                }
544
 
        } 
 
551
        }
 
552
        gp_stroke_addpoint(p, &old_points[num_points - 1].x, old_points[num_points - 1].pressure,
 
553
                           p->inittime + (double)old_points[num_points - 1].time);
545
554
        
546
555
        /* free old buffer */
547
556
        MEM_freeN(old_points);
549
558
 
550
559
 
551
560
/* make a new stroke from the buffer data */
552
 
static void gp_stroke_newfrombuffer (tGPsdata *p)
 
561
static void gp_stroke_newfrombuffer(tGPsdata *p)
553
562
{
554
 
        bGPdata *gpd= p->gpd;
 
563
        bGPdata *gpd = p->gpd;
555
564
        bGPDstroke *gps;
556
565
        bGPDspoint *pt;
557
566
        tGPspoint *ptc;
563
572
         *      - drawing straight-lines only requires the endpoints
564
573
         */
565
574
        if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT)
566
 
                totelem = (gpd->sbuffer_size >= 2) ? 2: gpd->sbuffer_size;
 
575
                totelem = (gpd->sbuffer_size >= 2) ? 2 : gpd->sbuffer_size;
567
576
        else
568
577
                totelem = gpd->sbuffer_size;
569
578
        
576
585
        
577
586
        /* special case for poly line -- for already added stroke during session
578
587
         * coordinates are getting added to stroke immediately to allow more
579
 
         * interactive behavior */
 
588
         * interactive behavior
 
589
         */
580
590
        if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
581
 
                if (p->flags & GP_PAINTFLAG_STROKEADDED)
 
591
                if (gp_stroke_added_check(p)) {
582
592
                        return;
 
593
                }
583
594
        }
584
 
 
 
595
        
585
596
        /* allocate memory for a new stroke */
586
 
        gps= MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
 
597
        gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
587
598
        
588
599
        /* copy appropriate settings for stroke */
589
 
        gps->totpoints= totelem;
590
 
        gps->thickness= p->gpl->thickness;
591
 
        gps->flag= gpd->sbuffer_sflag;
 
600
        gps->totpoints = totelem;
 
601
        gps->thickness = p->gpl->thickness;
 
602
        gps->flag = gpd->sbuffer_sflag;
 
603
        gps->inittime = p->inittime;
592
604
        
593
605
        /* allocate enough memory for a continuous array for storage points */
594
 
        gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
595
 
 
 
606
        gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
 
607
        
596
608
        /* set pointer to first non-initialized point */
597
 
        pt= gps->points + (gps->totpoints - totelem);
598
 
 
 
609
        pt = gps->points + (gps->totpoints - totelem);
 
610
        
599
611
        /* copy points from the buffer to the stroke */
600
612
        if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
601
613
                /* straight lines only -> only endpoints */
602
614
                {
603
615
                        /* first point */
604
 
                        ptc= gpd->sbuffer;
 
616
                        ptc = gpd->sbuffer;
605
617
                        
606
618
                        /* convert screen-coordinates to appropriate coordinates (and store them) */
607
619
                        gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
608
620
                        
609
 
                        /* copy pressure */
610
 
                        pt->pressure= ptc->pressure;
 
621
                        /* copy pressure and time */
 
622
                        pt->pressure = ptc->pressure;
 
623
                        pt->time = ptc->time;
611
624
                        
612
625
                        pt++;
613
626
                }
614
627
                        
615
628
                if (totelem == 2) {
616
629
                        /* last point if applicable */
617
 
                        ptc= ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
 
630
                        ptc = ((tGPspoint *)gpd->sbuffer) + (gpd->sbuffer_size - 1);
618
631
                        
619
632
                        /* convert screen-coordinates to appropriate coordinates (and store them) */
620
633
                        gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
621
634
                        
622
 
                        /* copy pressure */
623
 
                        pt->pressure= ptc->pressure;
 
635
                        /* copy pressure and time */
 
636
                        pt->pressure = ptc->pressure;
 
637
                        pt->time = ptc->time;
624
638
                }
625
639
        }
626
640
        else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
627
641
                /* first point */
628
 
                ptc= gpd->sbuffer;
629
 
 
 
642
                ptc = gpd->sbuffer;
 
643
                
630
644
                /* convert screen-coordinates to appropriate coordinates (and store them) */
631
645
                gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
632
 
 
633
 
                /* copy pressure */
634
 
                pt->pressure= ptc->pressure;
 
646
                
 
647
                /* copy pressure and time */
 
648
                pt->pressure = ptc->pressure;
 
649
                pt->time = ptc->time;
635
650
        }
636
651
        else {
637
 
                float *depth_arr= NULL;
 
652
                float *depth_arr = NULL;
638
653
                
639
654
                /* get an array of depths, far depths are blended */
640
655
                if (gpencil_project_check(p)) {
641
 
                        int mval[2], mval_prev[2]= {0};
 
656
                        int mval[2], mval_prev[2] = {0};
642
657
                        int interp_depth = 0;
643
658
                        int found_depth = 0;
644
659
                        
645
 
                        depth_arr= MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
646
 
 
647
 
                        for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
 
660
                        depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
 
661
                        
 
662
                        for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
648
663
                                copy_v2_v2_int(mval, &ptc->x);
649
 
 
650
 
                                if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr+i) == 0) &&
651
 
                                        (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr+i) == 0))
652
 
                                ) {
653
 
                                        interp_depth= TRUE;
 
664
                                
 
665
                                if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) &&
 
666
                                    (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0)))
 
667
                                {
 
668
                                        interp_depth = TRUE;
654
669
                                }
655
670
                                else {
656
 
                                        found_depth= TRUE;
 
671
                                        found_depth = TRUE;
657
672
                                }
658
 
 
 
673
                                
659
674
                                copy_v2_v2_int(mval_prev, mval);
660
675
                        }
661
676
                        
662
677
                        if (found_depth == FALSE) {
663
678
                                /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */
664
 
                                for (i=gpd->sbuffer_size-1; i >= 0; i--)
 
679
                                for (i = gpd->sbuffer_size - 1; i >= 0; i--)
665
680
                                        depth_arr[i] = 0.9999f;
666
681
                        }
667
682
                        else {
670
685
                                        int first_valid = 0;
671
686
                                        int last_valid = 0;
672
687
                                        
673
 
                                        for (i=0; i < gpd->sbuffer_size; i++) {
 
688
                                        for (i = 0; i < gpd->sbuffer_size; i++) {
674
689
                                                if (depth_arr[i] != FLT_MAX)
675
690
                                                        break;
676
691
                                        }
677
 
                                        first_valid= i;
 
692
                                        first_valid = i;
678
693
                                        
679
 
                                        for (i=gpd->sbuffer_size-1; i >= 0; i--) {
 
694
                                        for (i = gpd->sbuffer_size - 1; i >= 0; i--) {
680
695
                                                if (depth_arr[i] != FLT_MAX)
681
696
                                                        break;
682
697
                                        }
683
 
                                        last_valid= i;
 
698
                                        last_valid = i;
684
699
                                        
685
700
                                        /* invalidate non-endpoints, so only blend between first and last */
686
 
                                        for (i=first_valid+1; i < last_valid; i++)
687
 
                                                depth_arr[i]= FLT_MAX;
 
701
                                        for (i = first_valid + 1; i < last_valid; i++)
 
702
                                                depth_arr[i] = FLT_MAX;
688
703
                                        
689
 
                                        interp_depth= TRUE;
 
704
                                        interp_depth = TRUE;
690
705
                                }
691
706
                                
692
707
                                if (interp_depth) {
696
711
                }
697
712
                
698
713
                
699
 
                pt= gps->points;
 
714
                pt = gps->points;
700
715
                
701
716
                /* convert all points (normal behavior) */
702
 
                for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
 
717
                for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) {
703
718
                        /* convert screen-coordinates to appropriate coordinates (and store them) */
704
 
                        gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr+i:NULL);
 
719
                        gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL);
705
720
                        
706
 
                        /* copy pressure */
707
 
                        pt->pressure= ptc->pressure;
 
721
                        /* copy pressure and time */
 
722
                        pt->pressure = ptc->pressure;
 
723
                        pt->time = ptc->time;
708
724
                }
709
725
                
710
726
                if (depth_arr)
711
727
                        MEM_freeN(depth_arr);
712
728
        }
713
729
        
714
 
        p->flags |= GP_PAINTFLAG_STROKEADDED;
715
 
 
716
730
        /* add stroke to frame */
717
731
        BLI_addtail(&p->gpf->strokes, gps);
 
732
        gp_stroke_added_enable(p);
718
733
}
719
734
 
720
735
/* --- 'Eraser' for 'Paint' Tool ------ */
721
736
 
722
737
/* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
723
 
static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
 
738
static short gp_stroke_eraser_splitdel(bGPDframe *gpf, bGPDstroke *gps, int i)
724
739
{
725
 
        bGPDspoint *pt_tmp= gps->points;
 
740
        bGPDspoint *pt_tmp = gps->points;
726
741
        bGPDstroke *gsn = NULL;
727
 
 
 
742
        
728
743
        /* if stroke only had two points, get rid of stroke */
729
744
        if (gps->totpoints == 2) {
730
745
                /* free stroke points, then stroke */
734
749
                /* nothing left in stroke, so stop */
735
750
                return 1;
736
751
        }
737
 
 
 
752
        
738
753
        /* if last segment, just remove segment from the stroke */
739
754
        else if (i == gps->totpoints - 2) {
740
755
                /* allocate new points array, and assign most of the old stroke there */
741
756
                gps->totpoints--;
742
 
                gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
743
 
                memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
 
757
                gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
 
758
                memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * gps->totpoints);
744
759
                
745
760
                /* free temp buffer */
746
761
                MEM_freeN(pt_tmp);
748
763
                /* nothing left in stroke, so stop */
749
764
                return 1;
750
765
        }
751
 
 
 
766
        
752
767
        /* if first segment, just remove segment from the stroke */
753
768
        else if (i == 0) {
754
769
                /* allocate new points array, and assign most of the old stroke there */
755
770
                gps->totpoints--;
756
 
                gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
757
 
                memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
 
771
                gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
 
772
                memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint) * gps->totpoints);
 
773
                
 
774
                /* We must adjust timings!
 
775
                 * Each point's timing data is a delta from stroke's inittime, so as we erase the first
 
776
                 * point of the stroke, we have to offset this inittime and all remaining points' delta values.
 
777
                 * This way we get a new stroke with exactly the same timing as if user had started drawing from
 
778
                 * the second point...
 
779
                 */
 
780
                {
 
781
                        bGPDspoint *pts;
 
782
                        float delta = pt_tmp[1].time;
 
783
                        int j;
 
784
                        
 
785
                        gps->inittime += (double)delta;
 
786
                        
 
787
                        pts = gps->points;
 
788
                        for (j = 0; j < gps->totpoints; j++, pts++) {
 
789
                                pts->time -= delta;
 
790
                        }
 
791
                }
758
792
                
759
793
                /* free temp buffer */
760
794
                MEM_freeN(pt_tmp);
762
796
                /* no break here, as there might still be stuff to remove in this stroke */
763
797
                return 0;
764
798
        }
765
 
 
 
799
        
766
800
        /* segment occurs in 'middle' of stroke, so split */
767
801
        else {
768
802
                /* duplicate stroke, and assign 'later' data to that stroke */
769
 
                gsn= MEM_dupallocN(gps);
770
 
                gsn->prev= gsn->next= NULL;
 
803
                gsn = MEM_dupallocN(gps);
 
804
                gsn->prev = gsn->next = NULL;
771
805
                BLI_insertlinkafter(&gpf->strokes, gps, gsn);
772
806
                
773
 
                gsn->totpoints= gps->totpoints - i;
774
 
                gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
775
 
                memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
 
807
                gsn->totpoints = gps->totpoints - i;
 
808
                gsn->points = MEM_callocN(sizeof(bGPDspoint) * gsn->totpoints, "gp_stroke_points");
 
809
                memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint) * gsn->totpoints);
 
810
                
 
811
                /* We must adjust timings of this new stroke!
 
812
                 * Each point's timing data is a delta from stroke's inittime, so as we erase the first
 
813
                 * point of the stroke, we have to offset this inittime and all remaing points' delta values.
 
814
                 * This way we get a new stroke with exactly the same timing as if user had started drawing from
 
815
                 * the second point...
 
816
                 */
 
817
                {
 
818
                        bGPDspoint *pts;
 
819
                        float delta = pt_tmp[i].time;
 
820
                        int j;
 
821
                        
 
822
                        gsn->inittime += (double)delta;
 
823
                        
 
824
                        pts = gsn->points;
 
825
                        for (j = 0; j < gsn->totpoints; j++, pts++) {
 
826
                                pts->time -= delta;
 
827
                        }
 
828
                }
776
829
                
777
830
                /* adjust existing stroke  */
778
 
                gps->totpoints= i;
779
 
                gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
780
 
                memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
 
831
                gps->totpoints = i;
 
832
                gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
 
833
                memcpy(gps->points, pt_tmp, sizeof(bGPDspoint) * i);
781
834
                
782
835
                /* free temp buffer */
783
836
                MEM_freeN(pt_tmp);
788
841
}
789
842
 
790
843
/* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
791
 
static short gp_stroke_eraser_strokeinside (int mval[], int UNUSED(mvalo[]), short rad, short x0, short y0, short x1, short y1)
 
844
static short gp_stroke_eraser_strokeinside(const int mval[], const int UNUSED(mvalo[]),
 
845
                                           int rad, int x0, int y0, int x1, int y1)
792
846
{
793
847
        /* simple within-radius check for now */
794
 
        if (edge_inside_circle(mval[0], mval[1], rad, x0, y0, x1, y1))
795
 
                return 1;
 
848
        const float mval_fl[2]     = {mval[0], mval[1]};
 
849
        const float screen_co_a[2] = {x0, y0};
 
850
        const float screen_co_b[2] = {x1, y1};
 
851
        
 
852
        if (edge_inside_circle(mval_fl, rad, screen_co_a, screen_co_b)) {
 
853
                return TRUE;
 
854
        }
796
855
        
797
856
        /* not inside */
798
 
        return 0;
 
857
        return FALSE;
799
858
800
859
 
 
860
static void gp_point_to_xy(ARegion *ar, View2D *v2d, rctf *subrect, bGPDstroke *gps, bGPDspoint *pt,
 
861
                           int *r_x, int *r_y)
 
862
{
 
863
        int xyval[2];
 
864
 
 
865
        if (gps->flag & GP_STROKE_3DSPACE) {
 
866
                if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
 
867
                        *r_x = xyval[0];
 
868
                        *r_y = xyval[1];
 
869
                }
 
870
                else {
 
871
                        *r_x = V2D_IS_CLIPPED;
 
872
                        *r_y = V2D_IS_CLIPPED;
 
873
                }
 
874
        }
 
875
        else if (gps->flag & GP_STROKE_2DSPACE) {
 
876
                UI_view2d_view_to_region(v2d, pt->x, pt->y, r_x, r_y);
 
877
        }
 
878
        else {
 
879
                if (subrect == NULL) { /* normal 3D view */
 
880
                        *r_x = (int)(pt->x / 100 * ar->winx);
 
881
                        *r_y = (int)(pt->y / 100 * ar->winy);
 
882
                }
 
883
                else { /* camera view, use subrect */
 
884
                        *r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
 
885
                        *r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
 
886
                }
 
887
        }
 
888
}
 
889
 
 
890
 
801
891
/* eraser tool - evaluation per stroke */
802
 
// TODO: this could really do with some optimization (KD-Tree/BVH?)
803
 
static void gp_stroke_eraser_dostroke (tGPsdata *p, int mval[], int mvalo[], short rad, rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
 
892
/* TODO: this could really do with some optimization (KD-Tree/BVH?) */
 
893
static void gp_stroke_eraser_dostroke(tGPsdata *p,
 
894
                                      const int mval[], const int mvalo[],
 
895
                                      short rad, const rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
804
896
{
805
897
        bGPDspoint *pt1, *pt2;
806
 
        int x0=0, y0=0, x1=0, y1=0;
807
 
        int xyval[2];
 
898
        int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
808
899
        int i;
809
900
        
810
901
        if (gps->totpoints == 0) {
814
905
                BLI_freelinkN(&gpf->strokes, gps);
815
906
        }
816
907
        else if (gps->totpoints == 1) {
817
 
                /* get coordinates */
818
 
                if (gps->flag & GP_STROKE_3DSPACE) {
819
 
                        project_int(p->ar, &gps->points->x, xyval);
820
 
                        x0= xyval[0];
821
 
                        y0= xyval[1];
822
 
                }
823
 
                else if (gps->flag & GP_STROKE_2DSPACE) {                       
824
 
                        UI_view2d_view_to_region(p->v2d, gps->points->x, gps->points->y, &x0, &y0);
825
 
                }
826
 
#if 0
827
 
                else if (gps->flag & GP_STROKE_2DIMAGE) {                       
828
 
                        int offsx, offsy, sizex, sizey;
829
 
                        
830
 
                        /* get stored settings */
831
 
                        sizex= p->im2d_settings.sizex;
832
 
                        sizey= p->im2d_settings.sizey;
833
 
                        offsx= p->im2d_settings.offsx;
834
 
                        offsy= p->im2d_settings.offsy;
835
 
                        
836
 
                        /* calculate new points */
837
 
                        x0= (int)((gps->points->x * sizex) + offsx);
838
 
                        y0= (int)((gps->points->y * sizey) + offsy);
839
 
                }
840
 
#endif
841
 
                else {
842
 
                        if (p->subrect == NULL) { /* normal 3D view */
843
 
                                x0= (int)(gps->points->x / 100 * p->ar->winx);
844
 
                                y0= (int)(gps->points->y / 100 * p->ar->winy);
845
 
                        }
846
 
                        else { /* camera view, use subrect */
847
 
                                x0= (int)((gps->points->x / 100) * (p->subrect->xmax - p->subrect->xmin)) + p->subrect->xmin;
848
 
                                y0= (int)((gps->points->y / 100) * (p->subrect->ymax - p->subrect->ymin)) + p->subrect->ymin;
849
 
                        }
850
 
                }
 
908
                gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, gps->points, &x0, &y0);
851
909
                
852
910
                /* do boundbox check first */
853
 
                if (BLI_in_rcti(rect, x0, y0)) {
 
911
                if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
854
912
                        /* only check if point is inside */
855
 
                        if ( ((x0-mval[0])*(x0-mval[0]) + (y0-mval[1])*(y0-mval[1])) <= rad*rad ) {
 
913
                        if (((x0 - mval[0]) * (x0 - mval[0]) + (y0 - mval[1]) * (y0 - mval[1])) <= rad * rad) {
856
914
                                /* free stroke */
857
915
                                MEM_freeN(gps->points);
858
916
                                BLI_freelinkN(&gpf->strokes, gps);
859
917
                        }
860
918
                }
861
919
        }
862
 
        else {  
 
920
        else {
863
921
                /* loop over the points in the stroke, checking for intersections 
864
 
                 *      - an intersection will require the stroke to be split
 
922
                 *  - an intersection will require the stroke to be split
865
923
                 */
866
 
                for (i=0; (i+1) < gps->totpoints; i++) {
 
924
                for (i = 0; (i + 1) < gps->totpoints; i++) {
867
925
                        /* get points to work with */
868
 
                        pt1= gps->points + i;
869
 
                        pt2= gps->points + i + 1;
 
926
                        pt1 = gps->points + i;
 
927
                        pt2 = gps->points + i + 1;
870
928
                        
871
 
                        /* get coordinates */
872
 
                        if (gps->flag & GP_STROKE_3DSPACE) {
873
 
                                project_int(p->ar, &pt1->x, xyval);
874
 
                                x0= xyval[0];
875
 
                                y0= xyval[1];
876
 
                                
877
 
                                project_int(p->ar, &pt2->x, xyval);
878
 
                                x1= xyval[0];
879
 
                                y1= xyval[1];
880
 
                        }
881
 
                        else if (gps->flag & GP_STROKE_2DSPACE) {
882
 
                                UI_view2d_view_to_region(p->v2d, pt1->x, pt1->y, &x0, &y0);
883
 
                                
884
 
                                UI_view2d_view_to_region(p->v2d, pt2->x, pt2->y, &x1, &y1);
885
 
                        }
886
 
#if 0
887
 
                        else if (gps->flag & GP_STROKE_2DIMAGE) {
888
 
                                int offsx, offsy, sizex, sizey;
889
 
                                
890
 
                                /* get stored settings */
891
 
                                sizex= p->im2d_settings.sizex;
892
 
                                sizey= p->im2d_settings.sizey;
893
 
                                offsx= p->im2d_settings.offsx;
894
 
                                offsy= p->im2d_settings.offsy;
895
 
                                
896
 
                                /* calculate new points */
897
 
                                x0= (int)((pt1->x * sizex) + offsx);
898
 
                                y0= (int)((pt1->y * sizey) + offsy);
899
 
                                
900
 
                                x1= (int)((pt2->x * sizex) + offsx);
901
 
                                y1= (int)((pt2->y * sizey) + offsy);
902
 
                        }
903
 
#endif
904
 
                        else {
905
 
                                if (p->subrect == NULL) { /* normal 3D view */
906
 
                                        x0= (int)(pt1->x / 100 * p->ar->winx);
907
 
                                        y0= (int)(pt1->y / 100 * p->ar->winy);
908
 
                                        x1= (int)(pt2->x / 100 * p->ar->winx);
909
 
                                        y1= (int)(pt2->y / 100 * p->ar->winy);
910
 
                                }
911
 
                                else { /* camera view, use subrect */ 
912
 
                                        x0= (int)((pt1->x / 100) * (p->subrect->xmax - p->subrect->xmin)) + p->subrect->xmin;
913
 
                                        y0= (int)((pt1->y / 100) * (p->subrect->ymax - p->subrect->ymin)) + p->subrect->ymin;
914
 
                                        x1= (int)((pt2->x / 100) * (p->subrect->xmax - p->subrect->xmin)) + p->subrect->xmin;
915
 
                                        y1= (int)((pt2->y / 100) * (p->subrect->ymax - p->subrect->ymin)) + p->subrect->ymin;
916
 
                                }
917
 
                        }
 
929
                        gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, pt1, &x0, &y0);
 
930
                        gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, pt2, &x1, &y1);
918
931
                        
919
932
                        /* check that point segment of the boundbox of the eraser stroke */
920
 
                        if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) {
 
933
                        if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
 
934
                            ((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) {
921
935
                                /* check if point segment of stroke had anything to do with
922
936
                                 * eraser region  (either within stroke painted, or on its lines)
923
 
                                 *      - this assumes that linewidth is irrelevant
 
937
                                 *  - this assumes that linewidth is irrelevant
924
938
                                 */
925
939
                                if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
926
940
                                        /* if function returns true, break this loop (as no more point to check) */
933
947
}
934
948
 
935
949
/* erase strokes which fall under the eraser strokes */
936
 
static void gp_stroke_doeraser (tGPsdata *p)
 
950
static void gp_stroke_doeraser(tGPsdata *p)
937
951
{
938
 
        bGPDframe *gpf= p->gpf;
 
952
        bGPDframe *gpf = p->gpf;
939
953
        bGPDstroke *gps, *gpn;
940
954
        rcti rect;
941
955
        
946
960
        rect.ymax = p->mval[1] + p->radius;
947
961
        
948
962
        /* loop over strokes, checking segments for intersections */
949
 
        for (gps= gpf->strokes.first; gps; gps= gpn) {
950
 
                gpn= gps->next;
 
963
        for (gps = gpf->strokes.first; gps; gps = gpn) {
 
964
                gpn = gps->next;
951
965
                gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps);
952
966
        }
953
967
}
956
970
/* Sketching Operator */
957
971
 
958
972
/* clear the session buffers (call this before AND after a paint operation) */
959
 
static void gp_session_validatebuffer (tGPsdata *p)
 
973
static void gp_session_validatebuffer(tGPsdata *p)
960
974
{
961
 
        bGPdata *gpd= p->gpd;
 
975
        bGPdata *gpd = p->gpd;
962
976
        
963
977
        /* clear memory of buffer (or allocate it if starting a new session) */
964
978
        if (gpd->sbuffer) {
965
 
                //printf("\t\tGP - reset sbuffer\n");
966
 
                memset(gpd->sbuffer, 0, sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX);
 
979
                /* printf("\t\tGP - reset sbuffer\n"); */
 
980
                memset(gpd->sbuffer, 0, sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX);
967
981
        }
968
982
        else {
969
 
                //printf("\t\tGP - allocate sbuffer\n");
970
 
                gpd->sbuffer= MEM_callocN(sizeof(tGPspoint)*GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
 
983
                /* printf("\t\tGP - allocate sbuffer\n"); */
 
984
                gpd->sbuffer = MEM_callocN(sizeof(tGPspoint) * GP_STROKE_BUFFER_MAX, "gp_session_strokebuffer");
971
985
        }
972
986
        
973
987
        /* reset indices */
974
988
        gpd->sbuffer_size = 0;
975
989
        
976
990
        /* reset flags */
977
 
        gpd->sbuffer_sflag= 0;
 
991
        gpd->sbuffer_sflag = 0;
 
992
 
 
993
        /* reset inittime */
 
994
        p->inittime = 0.0;
978
995
}
979
996
 
980
997
/* (re)init new painting data */
981
 
static int gp_session_initdata (bContext *C, tGPsdata *p)
 
998
static int gp_session_initdata(bContext *C, tGPsdata *p)
982
999
{
983
1000
        bGPdata **gpd_ptr = NULL;
984
 
        ScrArea *curarea= CTX_wm_area(C);
985
 
        ARegion *ar= CTX_wm_region(C);
 
1001
        ScrArea *curarea = CTX_wm_area(C);
 
1002
        ARegion *ar = CTX_wm_region(C);
986
1003
        
987
1004
        /* make sure the active view (at the starting time) is a 3d-view */
988
1005
        if (curarea == NULL) {
989
 
                p->status= GP_STATUS_ERROR;
 
1006
                p->status = GP_STATUS_ERROR;
990
1007
                if (G.debug & G_DEBUG)
991
1008
                        printf("Error: No active view for painting\n");
992
1009
                return 0;
993
1010
        }
994
1011
        
995
1012
        /* pass on current scene and window */
996
 
        p->scene= CTX_data_scene(C);
997
 
        p->win= CTX_wm_window(C);
 
1013
        p->scene = CTX_data_scene(C);
 
1014
        p->win = CTX_wm_window(C);
998
1015
 
999
1016
        unit_m4(p->imat);
1000
1017
        
1002
1019
                /* supported views first */
1003
1020
                case SPACE_VIEW3D:
1004
1021
                {
1005
 
                        // View3D *v3d= curarea->spacedata.first;
1006
 
                        // RegionView3D *rv3d= ar->regiondata;
 
1022
                        /* View3D *v3d = curarea->spacedata.first; */
 
1023
                        /* RegionView3D *rv3d = ar->regiondata; */
1007
1024
                        
1008
1025
                        /* set current area 
1009
1026
                         *      - must verify that region data is 3D-view (and not something else)
1010
1027
                         */
1011
 
                        p->sa= curarea;
1012
 
                        p->ar= ar;
 
1028
                        p->sa = curarea;
 
1029
                        p->ar = ar;
1013
1030
                        
1014
1031
                        if (ar->regiondata == NULL) {
1015
 
                                p->status= GP_STATUS_ERROR;
 
1032
                                p->status = GP_STATUS_ERROR;
1016
1033
                                if (G.debug & G_DEBUG)
1017
1034
                                        printf("Error: 3D-View active region doesn't have any region data, so cannot be drawable\n");
1018
1035
                                return 0;
1019
1036
                        }
1020
 
 
1021
 
#if 0 // XXX will this sort of antiquated stuff be restored?
1022
 
                        /* check that gpencil data is allowed to be drawn */
1023
 
                        if ((v3d->flag2 & V3D_DISPGP)==0) {
1024
 
                                p->status= GP_STATUS_ERROR;
1025
 
                                if (G.debug & G_DEBUG)
1026
 
                                        printf("Error: In active view, Grease Pencil not shown\n");
1027
 
                                return 0;
1028
 
                        }
1029
 
#endif
1030
1037
                }
1031
 
                        break;
1032
 
 
 
1038
                break;
 
1039
                
1033
1040
                case SPACE_NODE:
1034
1041
                {
1035
 
                        //SpaceNode *snode= curarea->spacedata.first;
 
1042
                        /* SpaceNode *snode = curarea->spacedata.first; */
1036
1043
                        
1037
1044
                        /* set current area */
1038
 
                        p->sa= curarea;
1039
 
                        p->ar= ar;
1040
 
                        p->v2d= &ar->v2d;
1041
 
                        
1042
 
#if 0 // XXX will this sort of antiquated stuff be restored?
1043
 
                        /* check that gpencil data is allowed to be drawn */
1044
 
                        if ((snode->flag & SNODE_DISPGP)==0) {
1045
 
                                p->status= GP_STATUS_ERROR;
1046
 
                                if (G.debug & G_DEBUG)
1047
 
                                        printf("Error: In active view, Grease Pencil not shown\n");
1048
 
                                return 0;
1049
 
                        }
1050
 
#endif
 
1045
                        p->sa = curarea;
 
1046
                        p->ar = ar;
 
1047
                        p->v2d = &ar->v2d;
1051
1048
                }
1052
 
                        break;
1053
 
#if 0 // XXX these other spaces will come over time...
 
1049
                break;
1054
1050
                case SPACE_SEQ:
1055
1051
                {
1056
 
                        SpaceSeq *sseq= curarea->spacedata.first;
 
1052
                        SpaceSeq *sseq = curarea->spacedata.first;
1057
1053
                        
1058
1054
                        /* set current area */
1059
 
                        p->sa= curarea;
1060
 
                        p->ar= ar;
1061
 
                        p->v2d= &ar->v2d;
 
1055
                        p->sa = curarea;
 
1056
                        p->ar = ar;
 
1057
                        p->v2d = &ar->v2d;
1062
1058
                        
1063
1059
                        /* check that gpencil data is allowed to be drawn */
1064
1060
                        if (sseq->mainb == SEQ_DRAW_SEQUENCE) {
1065
 
                                p->status= GP_STATUS_ERROR;
 
1061
                                p->status = GP_STATUS_ERROR;
1066
1062
                                if (G.debug & G_DEBUG)
1067
1063
                                        printf("Error: In active view (sequencer), active mode doesn't support Grease Pencil\n");
1068
1064
                                return 0;
1069
1065
                        }
1070
 
                        if ((sseq->flag & SEQ_DRAW_GPENCIL)==0) {
1071
 
                                p->status= GP_STATUS_ERROR;
1072
 
                                if (G.debug & G_DEBUG)
1073
 
                                        printf("Error: In active view, Grease Pencil not shown\n");
1074
 
                                return 0;
1075
 
                        }
1076
1066
                }
1077
 
                        break;  
1078
 
#endif
 
1067
                break;
1079
1068
                case SPACE_IMAGE:
1080
1069
                {
1081
 
                        //SpaceImage *sima= curarea->spacedata.first;
 
1070
                        /* SpaceImage *sima = curarea->spacedata.first; */
1082
1071
                        
1083
1072
                        /* set the current area */
1084
 
                        p->sa= curarea;
1085
 
                        p->ar= ar;
1086
 
                        p->v2d= &ar->v2d;
1087
 
                        //p->ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1088
 
                        
1089
 
#if 0 // XXX disabled for now
1090
 
                        /* check that gpencil data is allowed to be drawn */
1091
 
                        if ((sima->flag & SI_DISPGP)==0) {
1092
 
                                p->status= GP_STATUS_ERROR;
1093
 
                                if (G.debug & G_DEBUG)
1094
 
                                        printf("Error: In active view, Grease Pencil not shown\n");
1095
 
                                return 0;
1096
 
                        }
1097
 
#endif
 
1073
                        p->sa = curarea;
 
1074
                        p->ar = ar;
 
1075
                        p->v2d = &ar->v2d;
1098
1076
                }
1099
 
                        break;
 
1077
                break;
1100
1078
                case SPACE_CLIP:
1101
1079
                {
1102
 
                        SpaceClip *sc= curarea->spacedata.first;
1103
 
 
 
1080
                        SpaceClip *sc = curarea->spacedata.first;
 
1081
                        
1104
1082
                        /* set the current area */
1105
 
                        p->sa= curarea;
1106
 
                        p->ar= ar;
1107
 
                        p->v2d= &ar->v2d;
1108
 
                        //p->ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
1109
 
 
 
1083
                        p->sa = curarea;
 
1084
                        p->ar = ar;
 
1085
                        p->v2d = &ar->v2d;
 
1086
                        
1110
1087
                        invert_m4_m4(p->imat, sc->unistabmat);
1111
 
 
 
1088
                        
1112
1089
                        /* custom color for new layer */
1113
 
                        p->custom_color[0]= 1.0f;
1114
 
                        p->custom_color[1]= 0.0f;
1115
 
                        p->custom_color[2]= 0.5f;
1116
 
                        p->custom_color[3]= 0.9f;
 
1090
                        p->custom_color[0] = 1.0f;
 
1091
                        p->custom_color[1] = 0.0f;
 
1092
                        p->custom_color[2] = 0.5f;
 
1093
                        p->custom_color[3] = 0.9f;
 
1094
                        
 
1095
                        if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
 
1096
                                MovieClip *clip = ED_space_clip_get_clip(sc);
 
1097
                                int framenr = ED_space_clip_get_clip_frame_number(sc);
 
1098
                                MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
 
1099
                                MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, framenr);
 
1100
                                
 
1101
                                p->imat[3][0] -= marker->pos[0];
 
1102
                                p->imat[3][1] -= marker->pos[1];
 
1103
                        }
1117
1104
                }
1118
 
                        break;
1119
 
 
 
1105
                break;
 
1106
                
1120
1107
                /* unsupported views */
1121
1108
                default:
1122
1109
                {
1123
 
                        p->status= GP_STATUS_ERROR;
 
1110
                        p->status = GP_STATUS_ERROR;
1124
1111
                        if (G.debug & G_DEBUG)
1125
1112
                                printf("Error: Active view not appropriate for Grease Pencil drawing\n");
1126
1113
                        return 0;
1127
1114
                }
1128
 
                        break;
 
1115
                break;
1129
1116
        }
1130
1117
        
1131
1118
        /* get gp-data */
1132
 
        gpd_ptr= gpencil_data_get_pointers(C, &p->ownerPtr);
 
1119
        gpd_ptr = gpencil_data_get_pointers(C, &p->ownerPtr);
1133
1120
        if (gpd_ptr == NULL) {
1134
 
                p->status= GP_STATUS_ERROR;
 
1121
                p->status = GP_STATUS_ERROR;
1135
1122
                if (G.debug & G_DEBUG)
1136
1123
                        printf("Error: Current context doesn't allow for any Grease Pencil data\n");
1137
1124
                return 0;
1139
1126
        else {
1140
1127
                /* if no existing GPencil block exists, add one */
1141
1128
                if (*gpd_ptr == NULL)
1142
 
                        *gpd_ptr= gpencil_data_addnew("GPencil");
1143
 
                p->gpd= *gpd_ptr;
 
1129
                        *gpd_ptr = gpencil_data_addnew("GPencil");
 
1130
                p->gpd = *gpd_ptr;
1144
1131
        }
1145
1132
        
1146
 
        if (ED_gpencil_session_active()==0) {
 
1133
        if (ED_gpencil_session_active() == 0) {
1147
1134
                /* initialize undo stack,
1148
 
                 * also, existing undo stack would make buffer drawn */
 
1135
                 * also, existing undo stack would make buffer drawn
 
1136
                 */
1149
1137
                gpencil_undo_init(p->gpd);
1150
1138
        }
1151
1139
        
1152
1140
        /* clear out buffer (stored in gp-data), in case something contaminated it */
1153
1141
        gp_session_validatebuffer(p);
1154
1142
        
1155
 
#if 0
1156
 
        /* set 'default' im2d_settings just in case something that uses this doesn't set it */
1157
 
        p->im2d_settings.sizex= 1;
1158
 
        p->im2d_settings.sizey= 1;
1159
 
#endif
1160
 
 
1161
1143
        return 1;
1162
1144
}
1163
1145
 
1164
1146
/* init new painting session */
1165
 
static tGPsdata *gp_session_initpaint (bContext *C)
 
1147
static tGPsdata *gp_session_initpaint(bContext *C)
1166
1148
{
1167
1149
        tGPsdata *p = NULL;
1168
1150
 
1169
1151
        /* create new context data */
1170
 
        p= MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
 
1152
        p = MEM_callocN(sizeof(tGPsdata), "GPencil Drawing Data");
1171
1153
 
1172
1154
        gp_session_initdata(C, p);
1173
1155
        
1176
1158
}
1177
1159
 
1178
1160
/* cleanup after a painting session */
1179
 
static void gp_session_cleanup (tGPsdata *p)
 
1161
static void gp_session_cleanup(tGPsdata *p)
1180
1162
{
1181
 
        bGPdata *gpd= (p) ? p->gpd : NULL;
 
1163
        bGPdata *gpd = (p) ? p->gpd : NULL;
1182
1164
        
1183
1165
        /* error checking */
1184
1166
        if (gpd == NULL)
1186
1168
        
1187
1169
        /* free stroke buffer */
1188
1170
        if (gpd->sbuffer) {
1189
 
                //printf("\t\tGP - free sbuffer\n");
 
1171
                /* printf("\t\tGP - free sbuffer\n"); */
1190
1172
                MEM_freeN(gpd->sbuffer);
1191
 
                gpd->sbuffer= NULL;
 
1173
                gpd->sbuffer = NULL;
1192
1174
        }
1193
1175
        
1194
1176
        /* clear flags */
1195
 
        gpd->sbuffer_size= 0;
1196
 
        gpd->sbuffer_sflag= 0;
 
1177
        gpd->sbuffer_size = 0;
 
1178
        gpd->sbuffer_sflag = 0;
 
1179
        p->inittime = 0.0;
1197
1180
}
1198
1181
 
1199
1182
/* init new stroke */
1200
 
static void gp_paint_initstroke (tGPsdata *p, short paintmode)
 
1183
static void gp_paint_initstroke(tGPsdata *p, short paintmode)
1201
1184
{       
1202
1185
        /* get active layer (or add a new one if non-existent) */
1203
 
        p->gpl= gpencil_layer_getactive(p->gpd);
 
1186
        p->gpl = gpencil_layer_getactive(p->gpd);
1204
1187
        if (p->gpl == NULL) {
1205
 
                p->gpl= gpencil_layer_addnew(p->gpd);
1206
 
 
 
1188
                p->gpl = gpencil_layer_addnew(p->gpd, "GP_Layer", 1);
 
1189
                
1207
1190
                if (p->custom_color[3])
1208
1191
                        copy_v3_v3(p->gpl->color, p->custom_color);
1209
1192
        }
1210
1193
        if (p->gpl->flag & GP_LAYER_LOCKED) {
1211
 
                p->status= GP_STATUS_ERROR;
 
1194
                p->status = GP_STATUS_ERROR;
1212
1195
                if (G.debug & G_DEBUG)
1213
1196
                        printf("Error: Cannot paint on locked layer\n");
1214
1197
                return;
1215
1198
        }
1216
1199
                
1217
1200
        /* get active frame (add a new one if not matching frame) */
1218
 
        p->gpf= gpencil_layer_getframe(p->gpl, p->scene->r.cfra, 1);
 
1201
        p->gpf = gpencil_layer_getframe(p->gpl, p->scene->r.cfra, 1);
1219
1202
        if (p->gpf == NULL) {
1220
 
                p->status= GP_STATUS_ERROR;
 
1203
                p->status = GP_STATUS_ERROR;
1221
1204
                if (G.debug & G_DEBUG)
1222
1205
                        printf("Error: No frame created (gpencil_paint_init)\n");
1223
1206
                return;
1226
1209
                p->gpf->flag |= GP_FRAME_PAINT;
1227
1210
        
1228
1211
        /* set 'eraser' for this stroke if using eraser */
1229
 
        p->paintmode= paintmode;
 
1212
        p->paintmode = paintmode;
1230
1213
        if (p->paintmode == GP_PAINTMODE_ERASER)
1231
1214
                p->gpd->sbuffer_sflag |= GP_STROKE_ERASER;
1232
1215
                
1237
1220
        /* when drawing in the camera view, in 2D space, set the subrect */
1238
1221
        if (!(p->gpd->flag & GP_DATA_VIEWALIGN)) {
1239
1222
                if (p->sa->spacetype == SPACE_VIEW3D) {
1240
 
                        View3D *v3d= p->sa->spacedata.first;
1241
 
                        RegionView3D *rv3d= p->ar->regiondata;
1242
 
 
 
1223
                        View3D *v3d = p->sa->spacedata.first;
 
1224
                        RegionView3D *rv3d = p->ar->regiondata;
 
1225
                        
1243
1226
                        /* for camera view set the subrect */
1244
1227
                        if (rv3d->persp == RV3D_CAMOB) {
1245
1228
                                ED_view3d_calc_camera_border(p->scene, p->ar, v3d, rv3d, &p->subrect_data, TRUE); /* no shift */
1246
 
                                p->subrect= &p->subrect_data;
 
1229
                                p->subrect = &p->subrect_data;
1247
1230
                        }
1248
1231
                }
1249
1232
        }
1253
1236
                switch (p->sa->spacetype) {
1254
1237
                        case SPACE_VIEW3D:
1255
1238
                        {
1256
 
                                RegionView3D *rv3d= p->ar->regiondata;
 
1239
                                RegionView3D *rv3d = p->ar->regiondata;
1257
1240
                                float rvec[3];
1258
1241
                                
1259
1242
                                /* get reference point for 3d space placement */
1262
1245
                                
1263
1246
                                p->gpd->sbuffer_sflag |= GP_STROKE_3DSPACE;
1264
1247
                        }
1265
 
                                break;
 
1248
                        break;
1266
1249
                        
1267
1250
                        case SPACE_NODE:
1268
1251
                        {
1269
1252
                                p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1270
1253
                        }
1271
 
                                break;
1272
 
#if 0 // XXX other spacetypes to be restored in due course
 
1254
                        break;
 
1255
                        
1273
1256
                        case SPACE_SEQ:
1274
1257
                        {
1275
 
                                SpaceSeq *sseq= (SpaceSeq *)p->sa->spacedata.first;
1276
 
                                int rectx, recty;
1277
 
                                float zoom, zoomx, zoomy;
1278
 
                                
1279
 
                                /* set draw 2d-stroke flag */
1280
 
                                p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
1281
 
                                
1282
 
                                /* calculate zoom factor */
1283
 
                                zoom= (float)(SEQ_ZOOM_FAC(sseq->zoom));
1284
 
                                if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
1285
 
                                        zoomx = zoom * (p->scene->r.xasp / p->scene->r.yasp);
1286
 
                                        zoomy = zoom;
1287
 
                                } 
1288
 
                                else
1289
 
                                        zoomx = zoomy = zoom;
1290
 
                                
1291
 
                                /* calculate rect size to use to calculate the size of the drawing area
1292
 
                                 *      - We use the size of the output image not the size of the ibuf being shown
1293
 
                                 *        as it is too messy getting the ibuf (and could be too slow). This should be
1294
 
                                 *        a reasonable for most cases anyway.
1295
 
                                 */
1296
 
                                rectx= (p->scene->r.size * p->scene->r.xsch) / 100;
1297
 
                                recty= (p->scene->r.size * p->scene->r.ysch) / 100; 
1298
 
                                
1299
 
                                /* set offset and scale values for opertations to use */
1300
 
                                p->im2d_settings.sizex= (int)(zoomx * rectx);
1301
 
                                p->im2d_settings.sizey= (int)(zoomy * recty);
1302
 
                                p->im2d_settings.offsx= (int)((p->sa->winx-p->im2d_settings.sizex)/2 + sseq->xof);
1303
 
                                p->im2d_settings.offsy= (int)((p->sa->winy-p->im2d_settings.sizey)/2 + sseq->yof);
 
1258
                                p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1304
1259
                        }
1305
 
                                break;
1306
 
#endif
 
1260
                        break;
 
1261
                        
1307
1262
                        case SPACE_IMAGE:
1308
1263
                        {
1309
 
                                SpaceImage *sima= (SpaceImage *)p->sa->spacedata.first;
 
1264
                                SpaceImage *sima = (SpaceImage *)p->sa->spacedata.first;
1310
1265
                                
1311
1266
                                /* only set these flags if the image editor doesn't have an image active,
1312
1267
                                 * otherwise user will be confused by strokes not appearing after they're drawn
1317
1272
                                        /* make strokes be drawn in screen space */
1318
1273
                                        p->gpd->sbuffer_sflag &= ~GP_STROKE_2DSPACE;
1319
1274
                                        p->gpd->flag &= ~GP_DATA_VIEWALIGN;
1320
 
                                }       
 
1275
                                }
1321
1276
                                else
1322
1277
                                        p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1323
1278
                        }
1324
 
                                break;
 
1279
                        break;
1325
1280
                                
1326
1281
                        case SPACE_CLIP:
1327
1282
                        {
1328
1283
                                p->gpd->sbuffer_sflag |= GP_STROKE_2DSPACE;
1329
1284
                        }
1330
 
                                break;
 
1285
                        break;
1331
1286
                }
1332
1287
        }
1333
1288
}
1334
1289
 
1335
1290
/* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
1336
 
static void gp_paint_strokeend (tGPsdata *p)
 
1291
static void gp_paint_strokeend(tGPsdata *p)
1337
1292
{
1338
1293
        /* for surface sketching, need to set the right OpenGL context stuff so that 
1339
1294
         * the conversions will project the values correctly...
1340
1295
         */
1341
1296
        if (gpencil_project_check(p)) {
1342
 
                View3D *v3d= p->sa->spacedata.first;
 
1297
                View3D *v3d = p->sa->spacedata.first;
1343
1298
                
1344
1299
                /* need to restore the original projection settings before packing up */
1345
1300
                view3d_region_operator_needs_opengl(p->win, p->ar);
1346
 
                ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1:0);
 
1301
                ED_view3d_autodist_init(p->scene, p->ar, v3d, (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 1 : 0);
1347
1302
        }
1348
1303
        
1349
1304
        /* check if doing eraser or not */
1363
1318
}
1364
1319
 
1365
1320
/* finish off stroke painting operation */
1366
 
static void gp_paint_cleanup (tGPsdata *p)
 
1321
static void gp_paint_cleanup(tGPsdata *p)
1367
1322
{
1368
1323
        /* p->gpd==NULL happens when stroke failed to initialize,
1369
 
         * for example. when GP is hidden in current space (sergey) */
 
1324
         * for example when GP is hidden in current space (sergey)
 
1325
         */
1370
1326
        if (p->gpd) {
1371
1327
                /* finish off a stroke */
1372
1328
                gp_paint_strokeend(p);
1379
1335
 
1380
1336
/* ------------------------------- */
1381
1337
 
1382
 
static void gpencil_draw_exit (bContext *C, wmOperator *op)
1383
 
{
1384
 
        tGPsdata *p= op->customdata;
 
1338
/* Helper callback for drawing the cursor itself */
 
1339
static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
 
1340
{
 
1341
        tGPsdata *p = (tGPsdata *)p_ptr;
 
1342
        
 
1343
        if (p->paintmode == GP_PAINTMODE_ERASER) {
 
1344
                glPushMatrix();
 
1345
                
 
1346
                glTranslatef((float)x, (float)y, 0.0f);
 
1347
                
 
1348
                glColor4ub(255, 255, 255, 128);
 
1349
                
 
1350
                glEnable(GL_LINE_SMOOTH);
 
1351
                glEnable(GL_BLEND);
 
1352
                
 
1353
                glutil_draw_lined_arc(0.0, M_PI * 2.0, p->radius, 40);
 
1354
                
 
1355
                glDisable(GL_BLEND);
 
1356
                glDisable(GL_LINE_SMOOTH);
 
1357
                
 
1358
                glPopMatrix();
 
1359
        }
 
1360
}
 
1361
 
 
1362
/* Turn brush cursor in 3D view on/off */
 
1363
static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
 
1364
{
 
1365
        if (p->erasercursor && !enable) {
 
1366
                /* clear cursor */
 
1367
                WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
 
1368
                p->erasercursor = NULL;
 
1369
        }
 
1370
        else if (enable) {
 
1371
                /* enable cursor */
 
1372
                p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C), 
 
1373
                                                           NULL, /* XXX */
 
1374
                                                           gpencil_draw_eraser, p);
 
1375
        }
 
1376
}
 
1377
 
 
1378
/* ------------------------------- */
 
1379
 
 
1380
 
 
1381
static void gpencil_draw_exit(bContext *C, wmOperator *op)
 
1382
{
 
1383
        tGPsdata *p = op->customdata;
1385
1384
        
1386
1385
        /* clear undo stack */
1387
1386
        gpencil_undo_finish();
1393
1392
        if (p) {
1394
1393
                /* check size of buffer before cleanup, to determine if anything happened here */
1395
1394
                if (p->paintmode == GP_PAINTMODE_ERASER) {
1396
 
                        // TODO clear radial cursor thing
1397
 
                        // XXX draw_sel_circle(NULL, p.mvalo, 0, p.radius, 0);
 
1395
                        /* turn off radial brush cursor */
 
1396
                        gpencil_draw_toggle_eraser_cursor(C, p, FALSE);
 
1397
                        
 
1398
                        /* if successful, store the new eraser size to be used again next time */
 
1399
                        if (p->status == GP_STATUS_DONE)
 
1400
                                U.gp_eraser = p->radius;
1398
1401
                }
1399
1402
                
1400
1403
                /* cleanup */
1402
1405
                gp_session_cleanup(p);
1403
1406
                
1404
1407
                /* finally, free the temp data */
1405
 
                MEM_freeN(p);   
 
1408
                MEM_freeN(p);
1406
1409
        }
1407
1410
        
1408
 
        op->customdata= NULL;
 
1411
        op->customdata = NULL;
1409
1412
}
1410
1413
 
1411
 
static int gpencil_draw_cancel (bContext *C, wmOperator *op)
 
1414
static int gpencil_draw_cancel(bContext *C, wmOperator *op)
1412
1415
{
1413
1416
        /* this is just a wrapper around exit() */
1414
1417
        gpencil_draw_exit(C, op);
1418
1421
/* ------------------------------- */
1419
1422
 
1420
1423
 
1421
 
static int gpencil_draw_init (bContext *C, wmOperator *op)
 
1424
static int gpencil_draw_init(bContext *C, wmOperator *op)
1422
1425
{
1423
1426
        tGPsdata *p;
1424
 
        int paintmode= RNA_enum_get(op->ptr, "mode");
 
1427
        int paintmode = RNA_enum_get(op->ptr, "mode");
1425
1428
        
1426
1429
        /* check context */
1427
 
        p= op->customdata= gp_session_initpaint(C);
 
1430
        p = op->customdata = gp_session_initpaint(C);
1428
1431
        if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
1429
1432
                /* something wasn't set correctly in context */
1430
1433
                gpencil_draw_exit(C, op);
1439
1442
        }
1440
1443
        
1441
1444
        /* radius for eraser circle is defined in userprefs now */
1442
 
        p->radius= U.gp_eraser;
 
1445
        p->radius = U.gp_eraser;
1443
1446
        
1444
1447
        /* everything is now setup ok */
1445
1448
        return 1;
1446
1449
}
1447
1450
 
 
1451
 
1448
1452
/* ------------------------------- */
1449
1453
 
1450
1454
/* update UI indicators of status, including cursor and header prints */
1451
 
static void gpencil_draw_status_indicators (tGPsdata *p)
 
1455
static void gpencil_draw_status_indicators(tGPsdata *p)
1452
1456
{
1453
1457
        /* header prints */
1454
1458
        switch (p->status) {
1455
1459
                case GP_STATUS_PAINTING:
1456
1460
                        /* only print this for paint-sessions, otherwise it gets annoying */
1457
1461
                        if (GPENCIL_SKETCH_SESSIONS_ON(p->scene))
1458
 
                                ED_area_headerprint(p->sa, "Grease Pencil: Drawing/erasing stroke... Release to end stroke");
 
1462
                                ED_area_headerprint(p->sa, IFACE_("Grease Pencil: Drawing/erasing stroke... Release to end stroke"));
1459
1463
                        break;
1460
1464
                
1461
1465
                case GP_STATUS_IDLING:
1462
1466
                        /* print status info */
1463
1467
                        switch (p->paintmode) {
1464
1468
                                case GP_PAINTMODE_ERASER:
1465
 
                                        ED_area_headerprint(p->sa, "Grease Pencil Erase Session: Hold and drag LMB or RMB to erase | ESC/Enter to end");
 
1469
                                        ED_area_headerprint(p->sa, IFACE_("Grease Pencil Erase Session: Hold and drag LMB or RMB to erase |"
 
1470
                                                                          " ESC/Enter to end"));
1466
1471
                                        break;
1467
1472
                                case GP_PAINTMODE_DRAW_STRAIGHT:
1468
 
                                        ED_area_headerprint(p->sa, "Grease Pencil Line Session: Hold and drag LMB to draw | ESC/Enter to end");
 
1473
                                        ED_area_headerprint(p->sa, IFACE_("Grease Pencil Line Session: Hold and drag LMB to draw | "
 
1474
                                                                          "ESC/Enter to end"));
1469
1475
                                        break;
1470
1476
                                case GP_PAINTMODE_DRAW:
1471
 
                                        ED_area_headerprint(p->sa, "Grease Pencil Freehand Session: Hold and drag LMB to draw | ESC/Enter to end");
 
1477
                                        ED_area_headerprint(p->sa, IFACE_("Grease Pencil Freehand Session: Hold and drag LMB to draw | "
 
1478
                                                                          "ESC/Enter to end"));
1472
1479
                                        break;
1473
1480
                                        
1474
1481
                                default: /* unhandled future cases */
1475
 
                                        ED_area_headerprint(p->sa, "Grease Pencil Session: ESC/Enter to end");
 
1482
                                        ED_area_headerprint(p->sa, IFACE_("Grease Pencil Session: ESC/Enter to end"));
1476
1483
                                        break;
1477
1484
                        }
1478
1485
                        break;
1488
1495
/* ------------------------------- */
1489
1496
 
1490
1497
/* create a new stroke point at the point indicated by the painting context */
1491
 
static void gpencil_draw_apply (wmOperator *op, tGPsdata *p)
 
1498
static void gpencil_draw_apply(wmOperator *op, tGPsdata *p)
1492
1499
{
1493
1500
        /* handle drawing/erasing -> test for erasing first */
1494
1501
        if (p->paintmode == GP_PAINTMODE_ERASER) {
1496
1503
                gp_stroke_doeraser(p);
1497
1504
                
1498
1505
                /* store used values */
1499
 
                p->mvalo[0]= p->mval[0];
1500
 
                p->mvalo[1]= p->mval[1];
1501
 
                p->opressure= p->pressure;
 
1506
                p->mvalo[0] = p->mval[0];
 
1507
                p->mvalo[1] = p->mval[1];
 
1508
                p->opressure = p->pressure;
1502
1509
        }
1503
1510
        /* only add current point to buffer if mouse moved (even though we got an event, it might be just noise) */
1504
1511
        else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
1505
1512
                /* try to add point */
1506
 
                short ok= gp_stroke_addpoint(p, p->mval, p->pressure);
 
1513
                short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
1507
1514
                
1508
1515
                /* handle errors while adding point */
1509
1516
                if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
1510
1517
                        /* finish off old stroke */
1511
1518
                        gp_paint_strokeend(p);
 
1519
                        /* And start a new one!!! Else, projection errors! */
 
1520
                        gp_paint_initstroke(p, p->paintmode);
1512
1521
                        
1513
1522
                        /* start a new stroke, starting from previous point */
1514
 
                        gp_stroke_addpoint(p, p->mvalo, p->opressure);
1515
 
                        gp_stroke_addpoint(p, p->mval, p->pressure);
 
1523
                        /* XXX Must manually reset inittime... */
 
1524
                        /* XXX We only need to reuse previous point if overflow! */
 
1525
                        if (ok == GP_STROKEADD_OVERFLOW) {
 
1526
                                p->inittime = p->ocurtime;
 
1527
                                gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
 
1528
                        }
 
1529
                        else {
 
1530
                                p->inittime = p->curtime;
 
1531
                        }
 
1532
                        gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
1516
1533
                }
1517
1534
                else if (ok == GP_STROKEADD_INVALID) {
1518
1535
                        /* the painting operation cannot continue... */
1525
1542
                }
1526
1543
                
1527
1544
                /* store used values */
1528
 
                p->mvalo[0]= p->mval[0];
1529
 
                p->mvalo[1]= p->mval[1];
1530
 
                p->opressure= p->pressure;
 
1545
                p->mvalo[0] = p->mval[0];
 
1546
                p->mvalo[1] = p->mval[1];
 
1547
                p->opressure = p->pressure;
 
1548
                p->ocurtime = p->curtime;
1531
1549
        }
1532
1550
}
1533
1551
 
1534
1552
/* handle draw event */
1535
 
static void gpencil_draw_apply_event (wmOperator *op, wmEvent *event)
 
1553
static void gpencil_draw_apply_event(wmOperator *op, wmEvent *event)
1536
1554
{
1537
 
        tGPsdata *p= op->customdata;
 
1555
        tGPsdata *p = op->customdata;
1538
1556
        PointerRNA itemptr;
1539
1557
        float mousef[2];
1540
 
        int tablet=0;
1541
 
 
1542
 
        /* convert from window-space to area-space mouse coordintes */
1543
 
        // NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding...
1544
 
        p->mval[0]= event->mval[0] + 1;
1545
 
        p->mval[1]= event->mval[1] + 1;
1546
 
 
 
1558
        int tablet = 0;
 
1559
        
 
1560
        /* convert from window-space to area-space mouse coordinates
 
1561
         * NOTE: float to ints conversions, +1 factor is probably used to ensure a bit more accurate rounding...
 
1562
         */
 
1563
        p->mval[0] = event->mval[0] + 1;
 
1564
        p->mval[1] = event->mval[1] + 1;
 
1565
        p->curtime = PIL_check_seconds_timer();
 
1566
        
1547
1567
        /* handle pressure sensitivity (which is supplied by tablets) */
1548
 
        if (event->custom == EVT_DATA_TABLET) {
1549
 
                wmTabletData *wmtab= event->customdata;
1550
 
                
1551
 
                tablet= (wmtab->Active != EVT_TABLET_NONE);
1552
 
                p->pressure= wmtab->Pressure;
1553
 
                
1554
 
                //if (wmtab->Active == EVT_TABLET_ERASER)
1555
 
                        // TODO... this should get caught by the keymaps which call drawing in the first place
 
1568
        if (event->tablet_data) {
 
1569
                wmTabletData *wmtab = event->tablet_data;
 
1570
                
 
1571
                tablet = (wmtab->Active != EVT_TABLET_NONE);
 
1572
                p->pressure = wmtab->Pressure;
 
1573
                
 
1574
                /* if (wmtab->Active == EVT_TABLET_ERASER) */
 
1575
                /* TODO... this should get caught by the keymaps which call drawing in the first place */
1556
1576
        }
1557
1577
        else
1558
 
                p->pressure= 1.0f;
 
1578
                p->pressure = 1.0f;
1559
1579
        
1560
1580
        /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
1561
1581
        RNA_collection_add(op->ptr, "stroke", &itemptr);
1562
1582
        
1563
 
        mousef[0]= p->mval[0];
1564
 
        mousef[1]= p->mval[1];
 
1583
        mousef[0] = p->mval[0];
 
1584
        mousef[1] = p->mval[1];
1565
1585
        RNA_float_set_array(&itemptr, "mouse", mousef);
1566
1586
        RNA_float_set(&itemptr, "pressure", p->pressure);
1567
1587
        RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN));
1570
1590
        if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
1571
1591
                p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
1572
1592
                
1573
 
                p->mvalo[0]= p->mval[0];
1574
 
                p->mvalo[1]= p->mval[1];
1575
 
                p->opressure= p->pressure;
 
1593
                p->mvalo[0] = p->mval[0];
 
1594
                p->mvalo[1] = p->mval[1];
 
1595
                p->opressure = p->pressure;
 
1596
                p->inittime = p->ocurtime = p->curtime;
1576
1597
                
1577
1598
                /* special exception here for too high pressure values on first touch in
1578
 
                 *  windows for some tablets, then we just skip first touch ..  
 
1599
                 *  windows for some tablets, then we just skip first touch...
1579
1600
                 */
1580
1601
                if (tablet && (p->pressure >= 0.99f))
1581
1602
                        return;
1582
1603
        }
1583
1604
        
 
1605
        RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
 
1606
        
1584
1607
        /* apply the current latest drawing point */
1585
1608
        gpencil_draw_apply(op, p);
1586
1609
        
1591
1614
/* ------------------------------- */
1592
1615
 
1593
1616
/* operator 'redo' (i.e. after changing some properties, but also for repeat last) */
1594
 
static int gpencil_draw_exec (bContext *C, wmOperator *op)
 
1617
static int gpencil_draw_exec(bContext *C, wmOperator *op)
1595
1618
{
1596
1619
        tGPsdata *p = NULL;
1597
1620
        
1598
 
        //printf("GPencil - Starting Re-Drawing\n");
 
1621
        /* printf("GPencil - Starting Re-Drawing\n"); */
1599
1622
        
1600
1623
        /* try to initialize context data needed while drawing */
1601
1624
        if (!gpencil_draw_init(C, op)) {
1602
1625
                if (op->customdata) MEM_freeN(op->customdata);
1603
 
                //printf("\tGP - no valid data\n");
 
1626
                /* printf("\tGP - no valid data\n"); */
1604
1627
                return OPERATOR_CANCELLED;
1605
1628
        }
1606
1629
        else
1607
 
                p= op->customdata;
 
1630
                p = op->customdata;
1608
1631
        
1609
 
        //printf("\tGP - Start redrawing stroke\n");
 
1632
        /* printf("\tGP - Start redrawing stroke\n"); */
1610
1633
        
1611
1634
        /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
1612
1635
         * setting the relevant values in context at each step, then applying
1613
1636
         */
1614
 
        RNA_BEGIN(op->ptr, itemptr, "stroke") {
 
1637
        RNA_BEGIN(op->ptr, itemptr, "stroke")
 
1638
        {
1615
1639
                float mousef[2];
1616
1640
                
1617
 
                //printf("\t\tGP - stroke elem\n");
 
1641
                /* printf("\t\tGP - stroke elem\n"); */
1618
1642
                
1619
1643
                /* get relevant data for this point from stroke */
1620
1644
                RNA_float_get_array(&itemptr, "mouse", mousef);
1621
1645
                p->mval[0] = (int)mousef[0];
1622
1646
                p->mval[1] = (int)mousef[1];
1623
 
                p->pressure= RNA_float_get(&itemptr, "pressure");
 
1647
                p->pressure = RNA_float_get(&itemptr, "pressure");
 
1648
                p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
1624
1649
                
1625
1650
                if (RNA_boolean_get(&itemptr, "is_start")) {
1626
1651
                        /* if first-run flag isn't set already (i.e. not true first stroke),
1627
1652
                         * then we must terminate the previous one first before continuing
1628
1653
                         */
1629
1654
                        if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
1630
 
                                // TODO: both of these ops can set error-status, but we probably don't need to worry
 
1655
                                /* TODO: both of these ops can set error-status, but we probably don't need to worry */
1631
1656
                                gp_paint_strokeend(p);
1632
1657
                                gp_paint_initstroke(p, p->paintmode);
1633
1658
                        }
1637
1662
                if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
1638
1663
                        p->flags &= ~GP_PAINTFLAG_FIRSTRUN;
1639
1664
                        
1640
 
                        p->mvalo[0]= p->mval[0];
1641
 
                        p->mvalo[1]= p->mval[1];
1642
 
                        p->opressure= p->pressure;
 
1665
                        p->mvalo[0] = p->mval[0];
 
1666
                        p->mvalo[1] = p->mval[1];
 
1667
                        p->opressure = p->pressure;
 
1668
                        p->ocurtime = p->curtime;
1643
1669
                }
1644
1670
                
1645
1671
                /* apply this data as necessary now (as per usual) */
1647
1673
        }
1648
1674
        RNA_END;
1649
1675
        
1650
 
        //printf("\tGP - done\n");
 
1676
        /* printf("\tGP - done\n"); */
1651
1677
        
1652
1678
        /* cleanup */
1653
1679
        gpencil_draw_exit(C, op);
1654
1680
        
1655
1681
        /* refreshes */
1656
 
        WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work  
 
1682
        WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1657
1683
        
1658
1684
        /* done */
1659
1685
        return OPERATOR_FINISHED;
1662
1688
/* ------------------------------- */
1663
1689
 
1664
1690
/* start of interactive drawing part of operator */
1665
 
static int gpencil_draw_invoke (bContext *C, wmOperator *op, wmEvent *event)
 
1691
static int gpencil_draw_invoke(bContext *C, wmOperator *op, wmEvent *event)
1666
1692
{
1667
1693
        tGPsdata *p = NULL;
1668
 
        wmWindow *win= CTX_wm_window(C);
 
1694
        wmWindow *win = CTX_wm_window(C);
1669
1695
        
1670
1696
        if (G.debug & G_DEBUG)
1671
1697
                printf("GPencil - Starting Drawing\n");
1679
1705
                return OPERATOR_CANCELLED;
1680
1706
        }
1681
1707
        else
1682
 
                p= op->customdata;
1683
 
        
1684
 
        // TODO: set any additional settings that we can take from the events?
1685
 
        // TODO? if tablet is erasing, force eraser to be on?
1686
 
        
1687
 
        // TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway...
1688
 
        
 
1708
                p = op->customdata;
 
1709
 
 
1710
        /* TODO: set any additional settings that we can take from the events?
 
1711
         * TODO? if tablet is erasing, force eraser to be on? */
 
1712
 
 
1713
        /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
 
1714
 
1689
1715
        /* if eraser is on, draw radial aid */
1690
1716
        if (p->paintmode == GP_PAINTMODE_ERASER) {
1691
 
                // TODO: this involves mucking around with radial control, so we leave this for now..
 
1717
                gpencil_draw_toggle_eraser_cursor(C, p, TRUE);
1692
1718
        }
1693
1719
        
1694
1720
        /* set cursor */
1695
1721
        if (p->paintmode == GP_PAINTMODE_ERASER)
1696
 
                WM_cursor_modal(win, BC_CROSSCURSOR); // XXX need a better cursor
 
1722
                WM_cursor_modal(win, BC_CROSSCURSOR);  /* XXX need a better cursor */
1697
1723
        else
1698
1724
                WM_cursor_modal(win, BC_PAINTBRUSHCURSOR);
1699
1725
        
1701
1727
         * painting should start immediately. Otherwise, this was called from a toolbar, in which
1702
1728
         * case we should wait for the mouse to be clicked.
1703
1729
         */
1704
 
        if (event->type) {
 
1730
        if (event->val == KM_PRESS) {
1705
1731
                /* hotkey invoked - start drawing */
1706
 
                //printf("\tGP - set first spot\n");
1707
 
                p->status= GP_STATUS_PAINTING;
 
1732
                /* printf("\tGP - set first spot\n"); */
 
1733
                p->status = GP_STATUS_PAINTING;
1708
1734
                
1709
1735
                /* handle the initial drawing - i.e. for just doing a simple dot */
1710
1736
                gpencil_draw_apply_event(op, event);
1711
1737
        }
1712
1738
        else {
1713
1739
                /* toolbar invoked - don't start drawing yet... */
1714
 
                //printf("\tGP - hotkey invoked... waiting for click-drag\n");
 
1740
                /* printf("\tGP - hotkey invoked... waiting for click-drag\n"); */
1715
1741
        }
1716
1742
        
1717
 
        WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL, NULL);
 
1743
        WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1718
1744
        /* add a modal handler for this operator, so that we can then draw continuous strokes */
1719
1745
        WM_event_add_modal_handler(C, op);
1720
1746
        return OPERATOR_RUNNING_MODAL;
1721
1747
}
1722
1748
 
1723
1749
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
1724
 
static int gpencil_area_exists(bContext *C, ScrArea *satest)
 
1750
static int gpencil_area_exists(bContext *C, ScrArea *sa_test)
1725
1751
{
1726
 
        bScreen *sc= CTX_wm_screen(C);
1727
 
        ScrArea *sa;
1728
 
        
1729
 
        for (sa= sc->areabase.first; sa; sa= sa->next) {
1730
 
                if (sa==satest)
1731
 
                        return 1;
1732
 
        }
1733
 
        
1734
 
        return 0;
 
1752
        bScreen *sc = CTX_wm_screen(C);
 
1753
        return (BLI_findindex(&sc->areabase, sa_test) != -1);
1735
1754
}
1736
1755
 
1737
1756
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
1738
1757
{
1739
 
        tGPsdata *p= op->customdata;
1740
 
 
 
1758
        tGPsdata *p = op->customdata;
 
1759
        
1741
1760
        /* we must check that we're still within the area that we're set up to work from
1742
1761
         * otherwise we could crash (see bug #20586)
1743
1762
         */
1744
1763
        if (CTX_wm_area(C) != p->sa) {
1745
1764
                printf("\t\t\tGP - wrong area execution abort!\n");
1746
 
                p->status= GP_STATUS_ERROR;
 
1765
                p->status = GP_STATUS_ERROR;
1747
1766
        }
1748
 
 
1749
 
        //printf("\t\tGP - start stroke\n");
1750
 
 
 
1767
        
 
1768
        /* printf("\t\tGP - start stroke\n"); */
 
1769
        
1751
1770
        /* we may need to set up paint env again if we're resuming */
1752
 
        // XXX: watch it with the paintmode! in future, it'd be nice to allow changing paint-mode when in sketching-sessions
1753
 
        // XXX: with tablet events, we may event want to check for eraser here, for nicer tablet support
1754
 
 
 
1771
        /* XXX: watch it with the paintmode! in future,
 
1772
         *      it'd be nice to allow changing paint-mode when in sketching-sessions */
 
1773
        /* XXX: with tablet events, we may event want to check for eraser here, for nicer tablet support */
 
1774
        
1755
1775
        if (gp_session_initdata(C, p))
1756
1776
                gp_paint_initstroke(p, p->paintmode);
1757
 
 
 
1777
        
1758
1778
        if (p->status != GP_STATUS_ERROR)
1759
 
                p->status= GP_STATUS_PAINTING;
1760
 
 
 
1779
                p->status = GP_STATUS_PAINTING;
 
1780
        
1761
1781
        return op->customdata;
1762
1782
}
1763
1783
 
1764
1784
static void gpencil_stroke_end(wmOperator *op)
1765
1785
{
1766
 
        tGPsdata *p= op->customdata;
 
1786
        tGPsdata *p = op->customdata;
1767
1787
 
1768
1788
        gp_paint_cleanup(p);
1769
1789
 
1771
1791
 
1772
1792
        gp_session_cleanup(p);
1773
1793
 
1774
 
        p->status= GP_STATUS_IDLING;
 
1794
        p->status = GP_STATUS_IDLING;
1775
1795
 
1776
 
        p->gpd= NULL;
1777
 
        p->gpl= NULL;
1778
 
        p->gpf= NULL;
 
1796
        p->gpd = NULL;
 
1797
        p->gpl = NULL;
 
1798
        p->gpf = NULL;
1779
1799
}
1780
1800
 
1781
1801
/* events handling during interactive drawing part of operator */
1782
 
static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
 
1802
static int gpencil_draw_modal(bContext *C, wmOperator *op, wmEvent *event)
1783
1803
{
1784
 
        tGPsdata *p= op->customdata;
1785
 
        int estate = OPERATOR_PASS_THROUGH; /* default exit state - not handled, so let others have a share of the pie */
 
1804
        tGPsdata *p = op->customdata;
 
1805
        int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */
1786
1806
        
1787
 
        // if (event->type == NDOF_MOTION)
1788
 
        //      return OPERATOR_PASS_THROUGH;
1789
 
        // -------------------------------
1790
 
        // [mce] Not quite what I was looking
1791
 
        // for, but a good start! GP continues to
1792
 
        // draw on the screen while the 3D mouse
1793
 
        // moves the viewpoint. Problem is that
1794
 
        // the stroke is converted to 3D only after
1795
 
        // it is finished. This approach should work
1796
 
        // better in tools that immediately apply
1797
 
        // in 3D space.
 
1807
        /* if (event->type == NDOF_MOTION)
 
1808
         *    return OPERATOR_PASS_THROUGH;
 
1809
         * -------------------------------
 
1810
         * [mce] Not quite what I was looking
 
1811
         * for, but a good start! GP continues to
 
1812
         * draw on the screen while the 3D mouse
 
1813
         * moves the viewpoint. Problem is that
 
1814
         * the stroke is converted to 3D only after
 
1815
         * it is finished. This approach should work
 
1816
         * better in tools that immediately apply
 
1817
         * in 3D space.
 
1818
         */
1798
1819
 
 
1820
        /* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
 
1821
        if (ISKEYBOARD(event->type)) {
 
1822
                if (ELEM4(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) {
 
1823
                        /* allow some keys - for frame changing: [#33412] */
 
1824
                }
 
1825
                else {
 
1826
                        estate = OPERATOR_RUNNING_MODAL;
 
1827
                }
 
1828
        }
 
1829
        
1799
1830
        //printf("\tGP - handle modal event...\n");
1800
1831
        
1801
 
        /* exit painting mode (and/or end current stroke) */
 
1832
        /* exit painting mode (and/or end current stroke) 
 
1833
         * NOTE: cannot do RIGHTMOUSE (as is standard for cancelling) as that would break polyline [#32647] 
 
1834
         */
1802
1835
        if (ELEM4(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
1803
1836
                /* exit() ends the current stroke before cleaning up */
1804
 
                //printf("\t\tGP - end of paint op + end of stroke\n");
1805
 
                p->status= GP_STATUS_DONE;
 
1837
                /* printf("\t\tGP - end of paint op + end of stroke\n"); */
 
1838
                p->status = GP_STATUS_DONE;
1806
1839
                estate = OPERATOR_FINISHED;
1807
1840
        }
1808
1841
        
1809
 
        /* toggle painting mode upon mouse-button movement */
 
1842
        /* toggle painting mode upon mouse-button movement 
 
1843
         *  - LEFTMOUSE  = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
 
1844
         *  - RIGHTMOUSE = polyline (hotkey) / eraser (all)
 
1845
         *    (Disabling RIGHTMOUSE case here results in bugs like [#32647])
 
1846
         */
1810
1847
        if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE)) {
1811
1848
                /* if painting, end stroke */
1812
1849
                if (p->status == GP_STATUS_PAINTING) {
1813
 
                        int sketch= 0;
 
1850
                        int sketch = 0;
 
1851
                        
1814
1852
                        /* basically, this should be mouse-button up = end stroke 
1815
1853
                         * BUT what happens next depends on whether we 'painting sessions' is enabled
1816
1854
                         */
1817
1855
                        sketch |= GPENCIL_SKETCH_SESSIONS_ON(p->scene);
1818
1856
                        /* polyline drawing is also 'sketching' -- all knots should be added during one session */
1819
 
                        sketch |= p->paintmode == GP_PAINTMODE_DRAW_POLY;
1820
 
 
 
1857
                        sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
 
1858
                        
1821
1859
                        if (sketch) {
1822
1860
                                /* end stroke only, and then wait to resume painting soon */
1823
 
                                //printf("\t\tGP - end stroke only\n");
 
1861
                                /* printf("\t\tGP - end stroke only\n"); */
1824
1862
                                gpencil_stroke_end(op);
1825
1863
                                
1826
1864
                                /* we've just entered idling state, so this event was processed (but no others yet) */
1827
1865
                                estate = OPERATOR_RUNNING_MODAL;
1828
 
 
 
1866
                                
1829
1867
                                /* stroke could be smoothed, send notifier to refresh screen */
1830
 
                                WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL);
 
1868
                                WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1831
1869
                        }
1832
1870
                        else {
1833
 
                                //printf("\t\tGP - end of stroke + op\n");
1834
 
                                p->status= GP_STATUS_DONE;
 
1871
                                /* printf("\t\tGP - end of stroke + op\n"); */
 
1872
                                p->status = GP_STATUS_DONE;
1835
1873
                                estate = OPERATOR_FINISHED;
1836
1874
                        }
1837
1875
                }
1838
1876
                else if (event->val == KM_PRESS) {
1839
1877
                        /* not painting, so start stroke (this should be mouse-button down) */
1840
 
                        p= gpencil_stroke_begin(C, op);
1841
 
 
 
1878
                        p = gpencil_stroke_begin(C, op);
 
1879
                        
1842
1880
                        if (p->status == GP_STATUS_ERROR) {
1843
1881
                                estate = OPERATOR_CANCELLED;
1844
1882
                        }
1845
 
                } 
 
1883
                }
1846
1884
                else {
1847
1885
                        p->status = GP_STATUS_IDLING;
1848
1886
                }
1853
1891
                /* handle painting mouse-movements? */
1854
1892
                if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
1855
1893
                        /* handle drawing event */
1856
 
                        //printf("\t\tGP - add point\n");
 
1894
                        /* printf("\t\tGP - add point\n"); */
1857
1895
                        gpencil_draw_apply_event(op, event);
1858
1896
                        
1859
1897
                        /* finish painting operation if anything went wrong just now */
1863
1901
                        }
1864
1902
                        else {
1865
1903
                                /* event handled, so just tag as running modal */
1866
 
                                //printf("\t\t\t\tGP - add point handled!\n");
 
1904
                                /* printf("\t\t\t\tGP - add point handled!\n"); */
1867
1905
                                estate = OPERATOR_RUNNING_MODAL;
1868
1906
                        }
1869
1907
                }
 
1908
                /* eraser size */
 
1909
                else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
 
1910
                         ELEM4(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
 
1911
                {
 
1912
                        /* just resize the brush (local version)
 
1913
                         * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
 
1914
                         */
 
1915
                        /* printf("\t\tGP - resize eraser\n"); */
 
1916
                        switch (event->type) {
 
1917
                                case WHEELUPMOUSE: /* larger */
 
1918
                                case PADPLUSKEY:
 
1919
                                        p->radius += 5;
 
1920
                                        break;
 
1921
                                        
 
1922
                                case WHEELDOWNMOUSE: /* smaller */
 
1923
                                case PADMINUS:
 
1924
                                        p->radius -= 5;
 
1925
                                        
 
1926
                                        if (p->radius < 0) 
 
1927
                                                p->radius = 0;
 
1928
                                        break;
 
1929
                        }
 
1930
                        
 
1931
                        /* force refresh */
 
1932
                        ED_region_tag_redraw(p->ar); /* just active area for now, since doing whole screen is too slow */
 
1933
                        
 
1934
                        /* event handled, so just tag as running modal */
 
1935
                        estate = OPERATOR_RUNNING_MODAL;
 
1936
                }
1870
1937
                /* there shouldn't be any other events, but just in case there are, let's swallow them 
1871
 
                 * (i.e. to prevent problems with with undo)
 
1938
                 * (i.e. to prevent problems with undo)
1872
1939
                 */
1873
1940
                else {
1874
1941
                        /* swallow event to save ourselves trouble */
1877
1944
        }
1878
1945
        
1879
1946
        /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
1880
 
        if (0==gpencil_area_exists(C, p->sa))
1881
 
                estate= OPERATOR_CANCELLED;
 
1947
        if (0 == gpencil_area_exists(C, p->sa))
 
1948
                estate = OPERATOR_CANCELLED;
1882
1949
        else
1883
1950
                /* update status indicators - cursor, header, etc. */
1884
1951
                gpencil_draw_status_indicators(p);
1888
1955
                case OPERATOR_FINISHED:
1889
1956
                        /* one last flush before we're done */
1890
1957
                        gpencil_draw_exit(C, op);
1891
 
                        WM_event_add_notifier(C, NC_SCREEN|ND_GPENCIL|NA_EDITED, NULL); // XXX need a nicer one that will work
 
1958
                        WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1892
1959
                        break;
1893
1960
                        
1894
1961
                case OPERATOR_CANCELLED:
1895
1962
                        gpencil_draw_exit(C, op);
1896
1963
                        break;
1897
 
 
1898
 
                case OPERATOR_RUNNING_MODAL|OPERATOR_PASS_THROUGH:
 
1964
                
 
1965
                case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
1899
1966
                        /* event doesn't need to be handled */
1900
 
                        //printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n", event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE);
 
1967
#if 0
 
1968
                        printf("unhandled event -> %d (mmb? = %d | mmv? = %d)\n",
 
1969
                               event->type, event->type == MIDDLEMOUSE, event->type==MOUSEMOVE);
 
1970
#endif
1901
1971
                        break;
1902
1972
        }
1903
1973
        
1908
1978
/* ------------------------------- */
1909
1979
 
1910
1980
static EnumPropertyItem prop_gpencil_drawmodes[] = {
1911
 
        {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", ""},
1912
 
        {GP_PAINTMODE_DRAW_STRAIGHT, "DRAW_STRAIGHT", 0, "Draw Straight Lines", ""},
1913
 
        {GP_PAINTMODE_DRAW_POLY, "DRAW_POLY", 0, "Draw Poly Line", ""},
1914
 
        {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", ""},
 
1981
        {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
 
1982
        {GP_PAINTMODE_DRAW_STRAIGHT, "DRAW_STRAIGHT", 0, "Draw Straight Lines", "Draw straight line segment(s)"},
 
1983
        {GP_PAINTMODE_DRAW_POLY, "DRAW_POLY", 0, "Draw Poly Line", "Click to place endpoints of straight line segments (connected)"},
 
1984
        {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Grease Pencil strokes"},
1915
1985
        {0, NULL, 0, NULL, NULL}
1916
1986
};
1917
1987
 
1918
 
void GPENCIL_OT_draw (wmOperatorType *ot)
 
1988
void GPENCIL_OT_draw(wmOperatorType *ot)
1919
1989
{
1920
1990
        /* identifiers */
1921
1991
        ot->name = "Grease Pencil Draw";
1930
2000
        ot->poll = gpencil_draw_poll;
1931
2001
        
1932
2002
        /* flags */
1933
 
        ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
 
2003
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1934
2004
        
1935
2005
        /* settings for drawing */
1936
 
        RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
 
2006
        ot->prop = RNA_def_enum(ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
1937
2007
        
1938
2008
        RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
1939
2009
}