GP: Fix error drawing on Camera view for Surface/Stroke
[blender.git] / source / blender / editors / gpencil / gpencil_fill.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2017, Blender Foundation, Joshua Leung
19  * This is a new part of Blender
20  *
21  * Contributor(s): Antonio Vazquez, Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26  /** \file blender/editors/gpencil/gpencil_fill.c
27   *  \ingroup edgpencil
28   */
29
30 #include <stdio.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_utildefines.h"
35 #include "BLI_blenlib.h"
36 #include "BLI_math.h"
37 #include "BLI_stack.h"
38
39 #include "BLT_translation.h"
40
41 #include "DNA_brush_types.h"
42 #include "DNA_gpencil_types.h"
43 #include "DNA_image_types.h"
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_windowmanager_types.h"
47
48 #include "BKE_main.h"
49 #include "BKE_brush.h"
50 #include "BKE_deform.h"
51 #include "BKE_image.h"
52 #include "BKE_gpencil.h"
53 #include "BKE_material.h"
54 #include "BKE_context.h"
55 #include "BKE_screen.h"
56 #include "BKE_paint.h"
57
58 #include "ED_gpencil.h"
59 #include "ED_screen.h"
60 #include "ED_space_api.h"
61 #include "ED_view3d.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66 #include "IMB_imbuf.h"
67 #include "IMB_imbuf_types.h"
68
69 #include "GPU_immediate.h"
70 #include "GPU_draw.h"
71 #include "GPU_matrix.h"
72 #include "GPU_framebuffer.h"
73 #include "GPU_state.h"
74
75 #include "UI_interface.h"
76
77 #include "WM_api.h"
78 #include "WM_types.h"
79
80 #include "DEG_depsgraph.h"
81 #include "DEG_depsgraph_query.h"
82
83 #include "gpencil_intern.h"
84
85 #define LEAK_HORZ 0
86 #define LEAK_VERT 1
87
88
89   /* Temporary fill operation data (op->customdata) */
90 typedef struct tGPDfill {
91         bContext *C;
92         struct Main *bmain;
93         struct Depsgraph *depsgraph;
94         struct wmWindow *win;               /* window where painting originated */
95         struct Scene *scene;                /* current scene from context */
96         struct Object *ob;                  /* current active gp object */
97         struct ScrArea *sa;                 /* area where painting originated */
98         struct RegionView3D *rv3d;          /* region where painting originated */
99         struct View3D *v3d;                 /* view3 where painting originated */
100         struct ARegion *ar;                 /* region where painting originated */
101         struct bGPdata *gpd;                /* current GP datablock */
102         struct Material *mat;               /* current material */
103         struct bGPDlayer *gpl;              /* layer */
104         struct bGPDframe *gpf;              /* frame */
105
106         short flag;                         /* flags */
107         short oldkey;                       /* avoid too fast events */
108         bool on_back;                       /* send to back stroke */
109
110         int center[2];                      /* mouse fill center position */
111         int sizex;                          /* windows width */
112         int sizey;                          /* window height */
113         int lock_axis;                      /* lock to viewport axis */
114
115         short fill_leak;                    /* number of pixel to consider the leak is too small (x 2) */
116         float fill_threshold;               /* factor for transparency */
117         int fill_simplylvl;                 /* number of simplify steps */
118         int fill_draw_mode;                 /* boundary limits drawing mode */
119
120         short sbuffer_size;                 /* number of elements currently in cache */
121         void *sbuffer;                      /* temporary points */
122         float *depth_arr;                   /* depth array for reproject */
123
124         Image *ima;                         /* temp image */
125         BLI_Stack *stack;                   /* temp points data */
126         void *draw_handle_3d;               /* handle for drawing strokes while operator is running 3d stuff */
127 } tGPDfill;
128
129
130 /* draw a given stroke using same thickness and color for all points */
131 static void gp_draw_basic_stroke(
132         tGPDfill *tgpf, bGPDstroke *gps, const float diff_mat[4][4],
133         const bool cyclic, const float ink[4], const int flag, const float thershold)
134 {
135         bGPDspoint *points = gps->points;
136
137         Material *ma = tgpf->mat;
138         MaterialGPencilStyle *gp_style = ma->gp_style;
139
140         int totpoints = gps->totpoints;
141         float fpt[3];
142         float col[4];
143
144         copy_v4_v4(col, ink);
145
146         /* if cyclic needs more vertex */
147         int cyclic_add = (cyclic) ? 1 : 0;
148
149         GPUVertFormat *format = immVertexFormat();
150         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
151         uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
152
153         immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR);
154
155         /* draw stroke curve */
156         GPU_line_width(1.0f);
157         immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints + cyclic_add);
158         const bGPDspoint *pt = points;
159
160         for (int i = 0; i < totpoints; i++, pt++) {
161
162                 if (flag & GP_BRUSH_FILL_HIDE) {
163                         float alpha = gp_style->stroke_rgba[3] * pt->strength;
164                         CLAMP(alpha, 0.0f, 1.0f);
165                         col[3] = alpha <= thershold ? 0.0f : 1.0f;
166                 }
167                 else {
168                         col[3] = 1.0f;
169                 }
170                 /* set point */
171                 immAttr4fv(color, col);
172                 mul_v3_m4v3(fpt, diff_mat, &pt->x);
173                 immVertex3fv(pos, fpt);
174         }
175
176         if (cyclic && totpoints > 2) {
177                 /* draw line to first point to complete the cycle */
178                 immAttr4fv(color, col);
179                 mul_v3_m4v3(fpt, diff_mat, &points->x);
180                 immVertex3fv(pos, fpt);
181         }
182
183         immEnd();
184         immUnbindProgram();
185 }
186
187 /* loop all layers */
188 static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
189 {
190         /* duplicated: etempFlags */
191         enum {
192                 GP_DRAWFILLS_NOSTATUS = (1 << 0),   /* don't draw status info */
193                 GP_DRAWFILLS_ONLY3D = (1 << 1),   /* only draw 3d-strokes */
194         };
195
196         Object *ob = tgpf->ob;
197         bGPdata *gpd = tgpf->gpd;
198         int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
199
200         tGPDdraw tgpw;
201         tgpw.rv3d = tgpf->rv3d;
202         tgpw.depsgraph = tgpf->depsgraph;
203         tgpw.ob = ob;
204         tgpw.gpd = gpd;
205         tgpw.offsx = 0;
206         tgpw.offsy = 0;
207         tgpw.winx = tgpf->ar->winx;
208         tgpw.winy = tgpf->ar->winy;
209         tgpw.dflag = 0;
210         tgpw.disable_fill = 1;
211         tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS);
212
213         glEnable(GL_BLEND);
214
215         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
216                 /* calculate parent position */
217                 ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat);
218
219                 /* do not draw layer if hidden */
220                 if (gpl->flag & GP_LAYER_HIDE)
221                         continue;
222
223                 /* get frame to draw */
224                 bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
225                 if (gpf == NULL)
226                         continue;
227
228                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
229                         /* check if stroke can be drawn */
230                         if ((gps->points == NULL) || (gps->totpoints < 2)) {
231                                 continue;
232                         }
233                         /* check if the color is visible */
234                         MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
235                         if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) {
236                                 continue;
237                         }
238
239                         tgpw.gps = gps;
240                         tgpw.gpl = gpl;
241                         tgpw.gpf = gpf;
242                         tgpw.t_gpf = gpf;
243
244                         /* reduce thickness to avoid gaps */
245                         tgpw.lthick = gpl->line_change - 4;
246                         tgpw.opacity = 1.0;
247                         copy_v4_v4(tgpw.tintcolor, ink);
248                         tgpw.onion = true;
249                         tgpw.custonion = true;
250
251                         /* normal strokes */
252                         if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
253                             (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH))
254                         {
255                                 ED_gp_draw_fill(&tgpw);
256
257                         }
258
259                         /* 3D Lines with basic shapes and invisible lines */
260                         if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
261                             (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH))
262                         {
263                                 gp_draw_basic_stroke(
264                                         tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink,
265                                         tgpf->flag, tgpf->fill_threshold);
266                         }
267                 }
268         }
269
270         glDisable(GL_BLEND);
271 }
272
273 /* draw strokes in offscreen buffer */
274 static void gp_render_offscreen(tGPDfill *tgpf)
275 {
276         bool is_ortho = false;
277         float winmat[4][4];
278
279         if (!tgpf->gpd) {
280                 return;
281         }
282
283         char err_out[256] = "unknown";
284         GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out);
285         GPU_offscreen_bind(offscreen, true);
286         uint flag = IB_rect | IB_rectfloat;
287         ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag);
288
289         rctf viewplane;
290         float clipsta, clipend;
291
292         is_ortho = ED_view3d_viewplane_get(tgpf->depsgraph, tgpf->v3d, tgpf->rv3d, tgpf->sizex, tgpf->sizey, &viewplane, &clipsta, &clipend, NULL);
293         if (is_ortho) {
294                 orthographic_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, -clipend, clipend);
295         }
296         else {
297                 perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
298         }
299
300         /* set temporary new size */
301         int bwinx = tgpf->ar->winx;
302         int bwiny = tgpf->ar->winy;
303         rcti brect = tgpf->ar->winrct;
304
305         tgpf->ar->winx = (short)tgpf->sizex;
306         tgpf->ar->winy = (short)tgpf->sizey;
307         tgpf->ar->winrct.xmin = 0;
308         tgpf->ar->winrct.ymin = 0;
309         tgpf->ar->winrct.xmax = tgpf->sizex;
310         tgpf->ar->winrct.ymax = tgpf->sizey;
311
312         GPU_matrix_push_projection();
313         GPU_matrix_identity_set();
314         GPU_matrix_push();
315         GPU_matrix_identity_set();
316
317         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
318         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
319
320         ED_view3d_update_viewmat(
321                 tgpf->depsgraph, tgpf->scene, tgpf->v3d, tgpf->ar,
322                 NULL, winmat, NULL);
323         /* set for opengl */
324         GPU_matrix_projection_set(tgpf->rv3d->winmat);
325         GPU_matrix_set(tgpf->rv3d->viewmat);
326
327         /* draw strokes */
328         float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
329         gp_draw_datablock(tgpf, ink);
330
331         /* restore size */
332         tgpf->ar->winx = (short)bwinx;
333         tgpf->ar->winy = (short)bwiny;
334         tgpf->ar->winrct = brect;
335
336         GPU_matrix_pop_projection();
337         GPU_matrix_pop();
338
339         /* create a image to see result of template */
340         if (ibuf->rect_float) {
341                 GPU_offscreen_read_pixels(offscreen, GL_FLOAT, ibuf->rect_float);
342         }
343         else if (ibuf->rect) {
344                 GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, ibuf->rect);
345         }
346         if (ibuf->rect_float && ibuf->rect) {
347                 IMB_rect_from_float(ibuf);
348         }
349
350         tgpf->ima = BKE_image_add_from_imbuf(tgpf->bmain, ibuf, "GP_fill");
351         tgpf->ima->id.tag |= LIB_TAG_DOIT;
352
353         BKE_image_release_ibuf(tgpf->ima, ibuf, NULL);
354
355         /* switch back to window-system-provided framebuffer */
356         GPU_offscreen_unbind(offscreen, true);
357         GPU_offscreen_free(offscreen);
358 }
359
360 /* return pixel data (rgba) at index */
361 static void get_pixel(const ImBuf *ibuf, const int idx, float r_col[4])
362 {
363         if (ibuf->rect_float) {
364                 const float *frgba = &ibuf->rect_float[idx * 4];
365                 copy_v4_v4(r_col, frgba);
366         }
367         else {
368                 /* XXX: This case probably doesn't happen, as we only write to the float buffer,
369                  * but we get compiler warnings about uninitialised vars otherwise
370                  */
371                 BLI_assert(!"gpencil_fill.c - get_pixel() non-float case is used!");
372                 zero_v4(r_col);
373         }
374 }
375
376 /* set pixel data (rgba) at index */
377 static void set_pixel(ImBuf *ibuf, int idx, const float col[4])
378 {
379         //BLI_assert(idx <= ibuf->x * ibuf->y);
380         if (ibuf->rect) {
381                 uint *rrect = &ibuf->rect[idx];
382                 uchar ccol[4];
383
384                 rgba_float_to_uchar(ccol, col);
385                 *rrect = *((uint *)ccol);
386         }
387
388         if (ibuf->rect_float) {
389                 float *rrectf = &ibuf->rect_float[idx * 4];
390                 copy_v4_v4(rrectf, col);
391         }
392 }
393
394 /* check if the size of the leak is narrow to determine if the stroke is closed
395  * this is used for strokes with small gaps between them to get a full fill
396  * and do not get a full screen fill.
397  *
398  * \param ibuf: Image pixel data
399  * \param maxpixel: Maximum index
400  * \param limit: Limit of pixels to analyze
401  * \param index: Index of current pixel
402  * \param type: 0-Horizontal 1-Vertical
403  */
404 static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index, int type)
405 {
406         float rgba[4];
407         int i;
408         int pt;
409         bool t_a = false;
410         bool t_b = false;
411
412         /* Horizontal leak (check vertical pixels)
413          * X
414          * X
415          * xB7
416          * X
417          * X
418          */
419         if (type == LEAK_HORZ) {
420                 /* pixels on top */
421                 for (i = 1; i <= limit; i++) {
422                         pt = index + (ibuf->x * i);
423                         if (pt <= maxpixel) {
424                                 get_pixel(ibuf, pt, rgba);
425                                 if (rgba[0] == 1.0f) {
426                                         t_a = true;
427                                         break;
428                                 }
429                         }
430                         else {
431                                 t_a = true; /* edge of image*/
432                                 break;
433                         }
434                 }
435                 /* pixels on bottom */
436                 for (i = 1; i <= limit; i++) {
437                         pt = index - (ibuf->x * i);
438                         if (pt >= 0) {
439                                 get_pixel(ibuf, pt, rgba);
440                                 if (rgba[0] == 1.0f) {
441                                         t_b = true;
442                                         break;
443                                 }
444                         }
445                         else {
446                                 t_b = true; /* edge of image*/
447                                 break;
448                         }
449                 }
450         }
451
452         /* Vertical leak (check horizontal pixels)
453          *
454          * XXXxB7XX
455          */
456         if (type == LEAK_VERT) {
457                 /* get pixel range of the row */
458                 int row = index / ibuf->x;
459                 int lowpix = row * ibuf->x;
460                 int higpix = lowpix + ibuf->x - 1;
461
462                 /* pixels to right */
463                 for (i = 0; i < limit; i++) {
464                         pt = index - (limit - i);
465                         if (pt >= lowpix) {
466                                 get_pixel(ibuf, pt, rgba);
467                                 if (rgba[0] == 1.0f) {
468                                         t_a = true;
469                                         break;
470                                 }
471                         }
472                         else {
473                                 t_a = true; /* edge of image*/
474                                 break;
475                         }
476                 }
477                 /* pixels to left */
478                 for (i = 0; i < limit; i++) {
479                         pt = index + (limit - i);
480                         if (pt <= higpix) {
481                                 get_pixel(ibuf, pt, rgba);
482                                 if (rgba[0] == 1.0f) {
483                                         t_b = true;
484                                         break;
485                                 }
486                         }
487                         else {
488                                 t_b = true; /* edge of image */
489                                 break;
490                         }
491                 }
492         }
493         return (bool)(t_a && t_b);
494 }
495
496 /* Boundary fill inside strokes
497  * Fills the space created by a set of strokes using the stroke color as the boundary
498  * of the shape to fill.
499  *
500  * \param tgpf: Temporary fill data
501  */
502 static void gpencil_boundaryfill_area(tGPDfill *tgpf)
503 {
504         ImBuf *ibuf;
505         float rgba[4];
506         void *lock;
507         const float fill_col[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
508         ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
509         const int maxpixel = (ibuf->x * ibuf->y) - 1;
510
511         BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__);
512
513         /* calculate index of the seed point using the position of the mouse */
514         int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0];
515         if ((index >= 0) && (index < maxpixel)) {
516                 BLI_stack_push(stack, &index);
517         }
518
519         /* the fill use a stack to save the pixel list instead of the common recursive
520          * 4-contact point method.
521          * The problem with recursive calls is that for big fill areas, we can get max limit
522          * of recursive calls and STACK_OVERFLOW error.
523          *
524          * The 4-contact point analyze the pixels to the left, right, bottom and top
525          *      -----------
526          *      |    X    |
527          *      |   XoX   |
528          *      |    X    |
529          *      -----------
530          */
531         while (!BLI_stack_is_empty(stack)) {
532                 int v;
533                 BLI_stack_pop(stack, &v);
534
535                 get_pixel(ibuf, v, rgba);
536
537                 if (true) { /* Was: 'rgba' */
538                         /* check if no border(red) or already filled color(green) */
539                         if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
540                                 /* fill current pixel */
541                                 set_pixel(ibuf, v, fill_col);
542
543                                 /* add contact pixels */
544                                 /* pixel left */
545                                 if (v - 1 >= 0) {
546                                         index = v - 1;
547                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
548                                                 BLI_stack_push(stack, &index);
549                                         }
550                                 }
551                                 /* pixel right */
552                                 if (v + 1 < maxpixel) {
553                                         index = v + 1;
554                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
555                                                 BLI_stack_push(stack, &index);
556                                         }
557                                 }
558                                 /* pixel top */
559                                 if (v + tgpf->sizex < maxpixel) {
560                                         index = v + tgpf->sizex;
561                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
562                                                 BLI_stack_push(stack, &index);
563                                         }
564                                 }
565                                 /* pixel bottom */
566                                 if (v - tgpf->sizex >= 0) {
567                                         index = v - tgpf->sizex;
568                                         if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
569                                                 BLI_stack_push(stack, &index);
570                                         }
571                                 }
572                         }
573                 }
574         }
575
576         /* release ibuf */
577         if (ibuf) {
578                 BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
579         }
580
581         tgpf->ima->id.tag |= LIB_TAG_DOIT;
582         /* free temp stack data */
583         BLI_stack_free(stack);
584 }
585
586 /* clean external border of image to avoid infinite loops */
587 static void gpencil_clean_borders(tGPDfill *tgpf)
588 {
589         ImBuf *ibuf;
590         void *lock;
591         const float fill_col[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
592         ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
593         int idx;
594         int pixel = 0;
595
596         /* horizontal lines */
597         for (idx = 0; idx < ibuf->x - 1; idx++) {
598                 /* bottom line */
599                 set_pixel(ibuf, idx, fill_col);
600                 /* top line */
601                 pixel = idx + (ibuf->x * (ibuf->y - 1));
602                 set_pixel(ibuf, pixel, fill_col);
603         }
604         /* vertical lines */
605         for (idx = 0; idx < ibuf->y; idx++) {
606                 /* left line */
607                 set_pixel(ibuf, ibuf->x * idx, fill_col);
608                 /* right line */
609                 pixel = ibuf->x * idx + (ibuf->x - 1);
610                 set_pixel(ibuf, pixel, fill_col);
611         }
612
613         /* release ibuf */
614         if (ibuf) {
615                 BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
616         }
617
618         tgpf->ima->id.tag |= LIB_TAG_DOIT;
619 }
620
621 /* Get the outline points of a shape using Moore Neighborhood algorithm
622  *
623  * This is a Blender customized version of the general algorithm described
624  * in https://en.wikipedia.org/wiki/Moore_neighborhood
625  */
626 static  void gpencil_get_outline_points(tGPDfill *tgpf)
627 {
628         ImBuf *ibuf;
629         float rgba[4];
630         void *lock;
631         int v[2];
632         int boundary_co[2];
633         int start_co[2];
634         int backtracked_co[2];
635         int current_check_co[2];
636         int prev_check_co[2];
637         int backtracked_offset[1][2] = {{0, 0}};
638         // bool boundary_found = false;
639         bool start_found = false;
640         const int NEIGHBOR_COUNT = 8;
641
642         const int offset[8][2] = {
643                 {-1, -1},
644                 {0, -1},
645                 {1, -1},
646                 {1, 0},
647                 {1, 1},
648                 {0, 1},
649                 {-1, 1},
650                 {-1, 0}
651         };
652
653         tgpf->stack = BLI_stack_new(sizeof(int[2]), __func__);
654
655         ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
656         int imagesize = ibuf->x * ibuf->y;
657
658         /* find the initial point to start outline analysis */
659         for (int idx = imagesize - 1; idx != 0; idx--) {
660                 get_pixel(ibuf, idx, rgba);
661                 if (rgba[1] == 1.0f) {
662                         boundary_co[0] = idx % ibuf->x;
663                         boundary_co[1] = idx / ibuf->x;
664                         copy_v2_v2_int(start_co, boundary_co);
665                         backtracked_co[0] = (idx - 1) % ibuf->x;
666                         backtracked_co[1] = (idx - 1) / ibuf->x;
667                         backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
668                         backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
669                         copy_v2_v2_int(prev_check_co, start_co);
670
671                         BLI_stack_push(tgpf->stack, &boundary_co);
672                         start_found = true;
673                         break;
674                 }
675         }
676
677         while (start_found) {
678                 int cur_back_offset = -1;
679                 for (int i = 0; i < NEIGHBOR_COUNT; i++) {
680                         if (backtracked_offset[0][0] == offset[i][0] &&
681                             backtracked_offset[0][1] == offset[i][1])
682                         {
683                                 /* Finding the bracktracked pixel offset index */
684                                 cur_back_offset = i;
685                                 break;
686                         }
687                 }
688
689                 int loop = 0;
690                 while (loop < (NEIGHBOR_COUNT - 1) && cur_back_offset != -1) {
691                         int offset_idx = (cur_back_offset + 1) % NEIGHBOR_COUNT;
692                         current_check_co[0] = boundary_co[0] + offset[offset_idx][0];
693                         current_check_co[1] = boundary_co[1] + offset[offset_idx][1];
694
695                         int image_idx = ibuf->x * current_check_co[1] + current_check_co[0];
696                         get_pixel(ibuf, image_idx, rgba);
697
698                         /* find next boundary pixel */
699                         if (rgba[1] == 1.0f) {
700                                 copy_v2_v2_int(boundary_co, current_check_co);
701                                 copy_v2_v2_int(backtracked_co, prev_check_co);
702                                 backtracked_offset[0][0] = backtracked_co[0] - boundary_co[0];
703                                 backtracked_offset[0][1] = backtracked_co[1] - boundary_co[1];
704
705                                 BLI_stack_push(tgpf->stack, &boundary_co);
706
707                                 break;
708                         }
709                         copy_v2_v2_int(prev_check_co, current_check_co);
710                         cur_back_offset++;
711                         loop++;
712                 }
713                 /* current pixel is equal to starting pixel */
714                 if (boundary_co[0] == start_co[0] &&
715                     boundary_co[1] == start_co[1])
716                 {
717                         BLI_stack_pop(tgpf->stack, &v);
718                         // boundary_found = true;
719                         break;
720                 }
721         }
722
723         /* release ibuf */
724         if (ibuf) {
725                 BKE_image_release_ibuf(tgpf->ima, ibuf, lock);
726         }
727 }
728
729 /* get z-depth array to reproject on surface */
730 static void gpencil_get_depth_array(tGPDfill *tgpf)
731 {
732         tGPspoint *ptc;
733         ToolSettings *ts = tgpf->scene->toolsettings;
734         int totpoints = tgpf->sbuffer_size;
735         int i = 0;
736
737         if (totpoints == 0) {
738                 return;
739         }
740
741         /* for surface sketching, need to set the right OpenGL context stuff so that
742          * the conversions will project the values correctly...
743          */
744         if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) {
745                 /* need to restore the original projection settings before packing up */
746                 view3d_region_operator_needs_opengl(tgpf->win, tgpf->ar);
747                 ED_view3d_autodist_init(tgpf->depsgraph, tgpf->ar, tgpf->v3d, 0);
748
749                 /* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
750                 int depth_margin = 0;
751
752                 /* get an array of depths, far depths are blended */
753                 int mval_prev[2] = { 0 };
754                 int interp_depth = 0;
755                 int found_depth = 0;
756
757                 tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points");
758
759                 for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) {
760
761                         int mval_i[2];
762                         round_v2i_v2fl(mval_i, &ptc->x);
763
764                         if ((ED_view3d_autodist_depth(
765                                      tgpf->ar, mval_i, depth_margin, tgpf->depth_arr + i) == 0) &&
766                             (i && (ED_view3d_autodist_depth_seg(
767                                            tgpf->ar, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0)))
768                         {
769                                 interp_depth = true;
770                         }
771                         else {
772                                 found_depth = true;
773                         }
774
775                         copy_v2_v2_int(mval_prev, mval_i);
776                 }
777
778                 if (found_depth == false) {
779                         /* eeh... not much we can do.. :/, ignore depth in this case */
780                         for (i = totpoints - 1; i >= 0; i--)
781                                 tgpf->depth_arr[i] = 0.9999f;
782                 }
783                 else {
784                         if (interp_depth) {
785                                 interp_sparse_array(tgpf->depth_arr, totpoints, FLT_MAX);
786                         }
787                 }
788         }
789 }
790
791 /* create array of points using stack as source */
792 static void gpencil_points_from_stack(tGPDfill *tgpf)
793 {
794         tGPspoint *point2D;
795         int totpoints = BLI_stack_count(tgpf->stack);
796         if (totpoints == 0) {
797                 return;
798         }
799
800         tgpf->sbuffer_size = (short)totpoints;
801         tgpf->sbuffer = MEM_callocN(sizeof(tGPspoint) * totpoints, __func__);
802
803         point2D = tgpf->sbuffer;
804         while (!BLI_stack_is_empty(tgpf->stack)) {
805                 int v[2];
806                 BLI_stack_pop(tgpf->stack, &v);
807                 point2D->x = v[0];
808                 point2D->y = v[1];
809
810                 point2D->pressure = 1.0f;
811                 point2D->strength = 1.0f;
812                 point2D->time = 0.0f;
813                 point2D++;
814         }
815 }
816
817 /* create a grease pencil stroke using points in buffer */
818 static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
819 {
820         const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph);
821
822         ToolSettings *ts = tgpf->scene->toolsettings;
823         const char *align_flag = &ts->gpencil_v3d_align;
824         const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE));
825         const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) &&
826                 (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth);
827         Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
828         if (brush == NULL) {
829                 return;
830         }
831
832         bGPDspoint *pt;
833         MDeformVert *dvert = NULL;
834         tGPspoint *point2D;
835
836         if (tgpf->sbuffer_size == 0) {
837                 return;
838         }
839
840         /* get frame or create a new one */
841         tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
842
843         /* create new stroke */
844         bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
845         gps->thickness = brush->size;
846         gps->inittime = 0.0f;
847
848         /* the polygon must be closed, so enabled cyclic */
849         gps->flag |= GP_STROKE_CYCLIC;
850         gps->flag |= GP_STROKE_3DSPACE;
851
852         gps->mat_nr = BKE_gpencil_get_material_index(tgpf->ob, tgpf->mat) - 1;
853         if (gps->mat_nr < 0) {
854                 BKE_object_material_slot_add(tgpf->bmain, tgpf->ob);
855                 assign_material(tgpf->bmain, tgpf->ob, tgpf->mat, tgpf->ob->totcol, BKE_MAT_ASSIGN_USERPREF);
856                 gps->mat_nr = tgpf->ob->totcol - 1;
857         }
858
859         /* allocate memory for storage points */
860         gps->totpoints = tgpf->sbuffer_size;
861         gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_size, "gp_stroke_points");
862
863         /* initialize triangle memory to dummy data */
864         gps->tot_triangles = 0;
865         gps->triangles = NULL;
866         gps->flag |= GP_STROKE_RECALC_CACHES;
867
868         /* add stroke to frame */
869         if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) {
870                 BLI_addhead(&tgpf->gpf->strokes, gps);
871         }
872         else {
873                 BLI_addtail(&tgpf->gpf->strokes, gps);
874         }
875
876         /* add points */
877         pt = gps->points;
878         point2D = (tGPspoint *)tgpf->sbuffer;
879
880         const int def_nr = tgpf->ob->actdef - 1;
881         const bool have_weight = (bool)BLI_findlink(&tgpf->ob->defbase, def_nr);
882
883         if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
884                 BKE_gpencil_dvert_ensure(gps);
885                 dvert = gps->dvert;
886         }
887
888         for (int i = 0; i < tgpf->sbuffer_size && point2D; i++, point2D++, pt++) {
889                 /* convert screen-coordinates to 3D coordinates */
890                 gp_stroke_convertcoords_tpoint(
891                         tgpf->scene, tgpf->ar, tgpf->ob,
892                         tgpf->gpl, point2D,
893                         tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
894                         &pt->x);
895
896                 pt->pressure = 1.0f;
897                 pt->strength = 1.0f;
898                 pt->time = 0.0f;
899
900                 if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
901                         MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
902                         if (dw) {
903                                 dw->weight = ts->vgroup_weight;
904                         }
905
906                         dvert++;
907                 }
908                 else {
909                         if (dvert != NULL) {
910                                 dvert->totweight = 0;
911                                 dvert->dw = NULL;
912                                 dvert++;
913                         }
914                 }
915         }
916
917         /* smooth stroke */
918         float reduce = 0.0f;
919         float smoothfac = 1.0f;
920         for (int r = 0; r < 1; r++) {
921                 for (int i = 0; i < gps->totpoints; i++) {
922                         BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce);
923                 }
924                 reduce += 0.25f;  // reduce the factor
925         }
926
927         /* if axis locked, reproject to plane locked */
928         if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
929                 float origin[3];
930                 ED_gp_get_drawing_reference(
931                         tgpf->scene, tgpf->ob, tgpf->gpl,
932                         ts->gpencil_v3d_align, origin);
933                 ED_gp_project_stroke_to_plane(
934                         tgpf->ob, tgpf->rv3d, gps, origin,
935                         tgpf->lock_axis - 1);
936         }
937
938         /* if parented change position relative to parent object */
939         for (int a = 0; a < tgpf->sbuffer_size; a++) {
940                 pt = &gps->points[a];
941                 gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt);
942         }
943
944         /* if camera view, reproject flat to view to avoid perspective effect */
945         if (is_camera) {
946                 ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps);
947         }
948
949         /* simplify stroke */
950         for (int b = 0; b < tgpf->fill_simplylvl; b++) {
951                 BKE_gpencil_simplify_fixed(gps);
952         }
953 }
954
955 /* ----------------------- */
956 /* Drawing                 */
957 /* Helper: Draw status message while the user is running the operator */
958 static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf))
959 {
960         const char *status_str = IFACE_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back");
961         ED_workspace_status_text(C, status_str);
962 }
963
964 /* draw boundary lines to see fill limits */
965 static void gpencil_draw_boundary_lines(const bContext *UNUSED(C), tGPDfill *tgpf)
966 {
967         if (!tgpf->gpd) {
968                 return;
969         }
970         const float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f};
971         gp_draw_datablock(tgpf, ink);
972 }
973
974 /* Drawing callback for modal operator in 3d mode */
975 static void gpencil_fill_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg)
976 {
977         tGPDfill *tgpf = (tGPDfill *)arg;
978         /* draw only in the region that originated operator. This is required for multiwindow */
979         ARegion *ar = CTX_wm_region(C);
980         if (ar != tgpf->ar) {
981                 return;
982         }
983
984         gpencil_draw_boundary_lines(C, tgpf);
985 }
986
987 /* check if context is suitable for filling */
988 static bool gpencil_fill_poll(bContext *C)
989 {
990         if (ED_operator_regionactive(C)) {
991                 ScrArea *sa = CTX_wm_area(C);
992                 if (sa->spacetype == SPACE_VIEW3D) {
993                         return 1;
994                 }
995                 else {
996                         CTX_wm_operator_poll_msg_set(C, "Active region not valid for filling operator");
997                         return 0;
998                 }
999         }
1000         else {
1001                 CTX_wm_operator_poll_msg_set(C, "Active region not set");
1002                 return 0;
1003         }
1004 }
1005
1006 /* Allocate memory and initialize values */
1007 static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
1008 {
1009         tGPDfill *tgpf = MEM_callocN(sizeof(tGPDfill), "GPencil Fill Data");
1010
1011         /* define initial values */
1012         ToolSettings *ts = CTX_data_tool_settings(C);
1013         bGPdata *gpd = CTX_data_gpencil_data(C);
1014         Main *bmain = CTX_data_main(C);
1015
1016         /* set current scene and window info */
1017         tgpf->C = C;
1018         tgpf->bmain = CTX_data_main(C);
1019         tgpf->scene = CTX_data_scene(C);
1020         tgpf->ob = CTX_data_active_object(C);
1021         tgpf->sa = CTX_wm_area(C);
1022         tgpf->ar = CTX_wm_region(C);
1023         tgpf->rv3d = tgpf->ar->regiondata;
1024         tgpf->v3d = tgpf->sa->spacedata.first;
1025         tgpf->depsgraph = CTX_data_depsgraph(C);
1026         tgpf->win = CTX_wm_window(C);
1027
1028         /* set GP datablock */
1029         tgpf->gpd = gpd;
1030         tgpf->gpl = BKE_gpencil_layer_getactive(gpd);
1031         if (tgpf->gpl == NULL) {
1032                 tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true);
1033         }
1034         tgpf->lock_axis = ts->gp_sculpt.lock_axis;
1035
1036         tgpf->oldkey = -1;
1037         tgpf->sbuffer_size = 0;
1038         tgpf->sbuffer = NULL;
1039         tgpf->depth_arr = NULL;
1040
1041         /* save filling parameters */
1042         Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
1043         tgpf->flag = brush->gpencil_settings->flag;
1044         tgpf->fill_leak = brush->gpencil_settings->fill_leak;
1045         tgpf->fill_threshold = brush->gpencil_settings->fill_threshold;
1046         tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl;
1047         tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode;
1048
1049         /* get color info */
1050         Material *ma = BKE_gpencil_get_material_from_brush(brush);
1051         /* if no brush defaults, get material and color info */
1052         if ((ma == NULL) || (ma->gp_style == NULL)) {
1053                 ma = BKE_gpencil_material_ensure(bmain, tgpf->ob);
1054                 /* assign always the first material to the brush */
1055                 brush->gpencil_settings->material = give_current_material(tgpf->ob, 1);
1056         }
1057
1058         tgpf->mat = ma;
1059
1060         /* init undo */
1061         gpencil_undo_init(tgpf->gpd);
1062
1063         /* return context data for running operator */
1064         return tgpf;
1065 }
1066
1067 /* end operator */
1068 static void gpencil_fill_exit(bContext *C, wmOperator *op)
1069 {
1070         Main *bmain = CTX_data_main(C);
1071         Object *ob = CTX_data_active_object(C);
1072
1073         /* clear undo stack */
1074         gpencil_undo_finish();
1075
1076         /* restore cursor to indicate end of fill */
1077         WM_cursor_modal_restore(CTX_wm_window(C));
1078
1079         tGPDfill *tgpf = op->customdata;
1080
1081         /* don't assume that operator data exists at all */
1082         if (tgpf) {
1083                 /* clear status message area */
1084                 ED_workspace_status_text(C, NULL);
1085
1086                 MEM_SAFE_FREE(tgpf->sbuffer);
1087                 MEM_SAFE_FREE(tgpf->depth_arr);
1088
1089                 /* remove drawing handler */
1090                 if (tgpf->draw_handle_3d) {
1091                         ED_region_draw_cb_exit(tgpf->ar->type, tgpf->draw_handle_3d);
1092                 }
1093
1094                 /* delete temp image */
1095                 if (tgpf->ima) {
1096                         for (Image *ima = bmain->image.first; ima; ima = ima->id.next) {
1097                                 if (ima == tgpf->ima) {
1098                                         BLI_remlink(&bmain->image, ima);
1099                                         BKE_image_free(tgpf->ima);
1100                                         MEM_SAFE_FREE(tgpf->ima);
1101                                         break;
1102                                 }
1103                         }
1104                 }
1105
1106                 /* finally, free memory used by temp data */
1107                 MEM_freeN(tgpf);
1108         }
1109
1110         /* clear pointer */
1111         op->customdata = NULL;
1112
1113         /* drawing batch cache is dirty now */
1114         if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) {
1115                 bGPdata *gpd2 = ob->data;
1116                 DEG_id_tag_update(&gpd2->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1117                 gpd2->flag |= GP_DATA_CACHE_IS_DIRTY;
1118         }
1119
1120         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1121 }
1122
1123 static void gpencil_fill_cancel(bContext *C, wmOperator *op)
1124 {
1125         /* this is just a wrapper around exit() */
1126         gpencil_fill_exit(C, op);
1127 }
1128
1129 /* Init: Allocate memory and set init values */
1130 static int gpencil_fill_init(bContext *C, wmOperator *op)
1131 {
1132         tGPDfill *tgpf;
1133         /* cannot paint in locked layer */
1134         bGPdata *gpd = CTX_data_gpencil_data(C);
1135         bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
1136         if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) {
1137                 return 0;
1138         }
1139
1140         /* check context */
1141         tgpf = op->customdata = gp_session_init_fill(C, op);
1142         if (tgpf == NULL) {
1143                 /* something wasn't set correctly in context */
1144                 gpencil_fill_exit(C, op);
1145                 return 0;
1146         }
1147
1148         /* everything is now setup ok */
1149         return 1;
1150 }
1151
1152 /* start of interactive part of operator */
1153 static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1154 {
1155         tGPDfill *tgpf = NULL;
1156
1157         /* try to initialize context data needed */
1158         if (!gpencil_fill_init(C, op)) {
1159                 gpencil_fill_exit(C, op);
1160                 if (op->customdata)
1161                         MEM_freeN(op->customdata);
1162                 return OPERATOR_CANCELLED;
1163         }
1164         else {
1165                 tgpf = op->customdata;
1166         }
1167
1168         /* Enable custom drawing handlers to show help lines */
1169         if (tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) {
1170                 tgpf->draw_handle_3d = ED_region_draw_cb_activate(tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
1171         }
1172
1173         WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
1174
1175         gpencil_fill_status_indicators(C, tgpf);
1176
1177         DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
1178         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1179
1180         /* add a modal handler for this operator*/
1181         WM_event_add_modal_handler(C, op);
1182
1183         return OPERATOR_RUNNING_MODAL;
1184 }
1185
1186 /* events handling during interactive part of operator */
1187 static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
1188 {
1189         tGPDfill *tgpf = op->customdata;
1190
1191         int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */
1192
1193         switch (event->type) {
1194                 case ESCKEY:
1195                 case RIGHTMOUSE:
1196                         estate = OPERATOR_CANCELLED;
1197                         break;
1198                 case LEFTMOUSE:
1199                         tgpf->on_back = RNA_boolean_get(op->ptr, "on_back");
1200                         /* first time the event is not enabled to show help lines */
1201                         if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) {
1202                                 ARegion *ar = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y);
1203                                 if (ar) {
1204                                         bool in_bounds = false;
1205
1206                                         /* Perform bounds check */
1207                                         in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y);
1208
1209                                         if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) {
1210                                                 /* TODO GPXX: Verify the mouse click is right for any window size */
1211                                                 tgpf->center[0] = event->mval[0];
1212                                                 tgpf->center[1] = event->mval[1];
1213
1214                                                 /* save size */
1215                                                 tgpf->sizex = ar->winx;
1216                                                 tgpf->sizey = ar->winy;
1217
1218                                                 /* render screen to temp image */
1219                                                 gp_render_offscreen(tgpf);
1220
1221                                                 /* apply boundary fill */
1222                                                 gpencil_boundaryfill_area(tgpf);
1223
1224                                                 /* clean borders to avoid infinite loops */
1225                                                 gpencil_clean_borders(tgpf);
1226
1227                                                 /* analyze outline */
1228                                                 gpencil_get_outline_points(tgpf);
1229
1230                                                 /* create array of points from stack */
1231                                                 gpencil_points_from_stack(tgpf);
1232
1233                                                 /* create z-depth array for reproject */
1234                                                 gpencil_get_depth_array(tgpf);
1235
1236                                                 /* create stroke and reproject */
1237                                                 gpencil_stroke_from_buffer(tgpf);
1238
1239                                                 /* free temp stack data */
1240                                                 if (tgpf->stack) {
1241                                                         BLI_stack_free(tgpf->stack);
1242                                                 }
1243
1244                                                 /* push undo data */
1245                                                 gpencil_undo_push(tgpf->gpd);
1246
1247                                                 estate = OPERATOR_FINISHED;
1248                                         }
1249                                         else {
1250                                                 estate = OPERATOR_CANCELLED;
1251                                         }
1252                                 }
1253                                 else {
1254                                         estate = OPERATOR_CANCELLED;
1255                                 }
1256                         }
1257                         tgpf->oldkey = event->type;
1258                         break;
1259         }
1260         /* process last operations before exiting */
1261         switch (estate) {
1262                 case OPERATOR_FINISHED:
1263                         gpencil_fill_exit(C, op);
1264                         WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
1265                         break;
1266
1267                 case OPERATOR_CANCELLED:
1268                         gpencil_fill_exit(C, op);
1269                         break;
1270
1271                 case OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH:
1272                         break;
1273         }
1274
1275         /* return status code */
1276         return estate;
1277 }
1278
1279 void GPENCIL_OT_fill(wmOperatorType *ot)
1280 {
1281         PropertyRNA *prop;
1282
1283         /* identifiers */
1284         ot->name = "Grease Pencil Fill";
1285         ot->idname = "GPENCIL_OT_fill";
1286         ot->description = "Fill with color the shape formed by strokes";
1287
1288         /* api callbacks */
1289         ot->invoke = gpencil_fill_invoke;
1290         ot->modal = gpencil_fill_modal;
1291         ot->poll = gpencil_fill_poll;
1292         ot->cancel = gpencil_fill_cancel;
1293
1294         /* flags */
1295         ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
1296
1297         prop = RNA_def_boolean(ot->srna, "on_back", false, "Draw On Back", "Send new stroke to Back");
1298         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1299 }