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