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