GP: New Blend Layers functionality
authorAntonioya <blendergit@gmail.com>
Mon, 26 Nov 2018 17:12:39 +0000 (18:12 +0100)
committerAntonioya <blendergit@gmail.com>
Mon, 26 Nov 2018 17:12:39 +0000 (18:12 +0100)
Now it's possible define the blend mode between layers including the option to clamp the layer using underlying layers.

Also a new Simplify option has been added to disable blend layers.

14 files changed:
release/scripts/startup/bl_ui/properties_data_gpencil.py
release/scripts/startup/bl_ui/properties_grease_pencil_common.py
release/scripts/startup/bl_ui/properties_render.py
release/scripts/startup/bl_ui/space_topbar.py
source/blender/draw/CMakeLists.txt
source/blender/draw/engines/gpencil/gpencil_cache_utils.c
source/blender/draw/engines/gpencil/gpencil_draw_utils.c
source/blender/draw/engines/gpencil/gpencil_engine.c
source/blender/draw/engines/gpencil/gpencil_engine.h
source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl [new file with mode: 0644]
source/blender/makesdna/DNA_gpencil_types.h
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/intern/rna_gpencil.c
source/blender/makesrna/intern/rna_scene.c

index 949a48ed7f1a7e037a6cab1d6df635fa6d0a3904..558c3c190b612db6cea79f6a6be971cf00cbb97c 100644 (file)
@@ -135,13 +135,22 @@ class DATA_PT_gpencil_datapanel(Panel):
         col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index",
                           rows=layer_rows, reverse=True)
 
+        gpl = context.active_gpencil_layer
+        if gpl:
+            srow = col.row(align=True)
+            srow.prop(gpl, "blend_mode", text="Blend")
+
+            srow = col.row(align=True)
+            srow.prop(gpl, "opacity", text="Opacity", slider=True)
+            srow.prop(gpl, "clamp_layer", text="",
+                     icon='MOD_MASK' if gpl.clamp_layer else 'ONIONSKIN_OFF')
+
         col = row.column()
 
         sub = col.column(align=True)
         sub.operator("gpencil.layer_add", icon='ADD', text="")
         sub.operator("gpencil.layer_remove", icon='REMOVE', text="")
 
-        gpl = context.active_gpencil_layer
         if gpl:
             sub.menu("GPENCIL_MT_layer_specials", icon='DOWNARROW_HLT', text="")
 
@@ -158,10 +167,6 @@ class DATA_PT_gpencil_datapanel(Panel):
                 sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
                 sub.operator("gpencil.layer_isolate", icon='RESTRICT_VIEW_ON', text="").affect_visibility = True
 
-        row = layout.row(align=True)
-        if gpl:
-            row.prop(gpl, "opacity", text="Opacity", slider=True)
-
 
 class DATA_PT_gpencil_layer_optionpanel(LayerDataButtonsPanel, Panel):
     bl_space_type = 'PROPERTIES'
index 296e05a709d3325c64d3bc618d0b5a9af40ced60..b18254a9102189ab50fb2c86996eb77fc1dcb5d5 100644 (file)
@@ -766,7 +766,6 @@ class AnnotationDataPanel:
             layout.prop(tool_settings, "annotation_thickness", text="Thickness")
 
         if gpl:
-            # layout.prop(gpl, "opacity", text="Opacity", slider=True)
             # Full-Row - Frame Locking (and Delete Frame)
             row = layout.row(align=True)
             row.active = not gpl.lock
@@ -873,6 +872,10 @@ class GPENCIL_UL_layer(UIList):
             row.prop(gpl, "info", text="", emboss=False)
 
             row = layout.row(align=True)
+            row.prop(gpl, "clamp_layer", text="",
+                        icon='MOD_MASK' if gpl.clamp_layer else 'ONIONSKIN_OFF',
+                        emboss=False)
+
             row.prop(gpl, "lock", text="", emboss=False)
             row.prop(gpl, "hide", text="", emboss=False)
             subrow = row.row(align=True)
index 026b306b49ee5a7ee49eb9e2b73d2c93381eab45..8cfbb09ad04be1de0416aba894c8b5c1704be128 100644 (file)
@@ -650,6 +650,7 @@ class RENDER_PT_simplify_greasepencil(RenderButtonsPanel, Panel):
     def draw(self, context):
         layout = self.layout
         layout.use_property_split = True
+        layout.use_property_decorate = False
 
         rd = context.scene.render
 
@@ -659,8 +660,8 @@ class RENDER_PT_simplify_greasepencil(RenderButtonsPanel, Panel):
         col.prop(rd, "simplify_gpencil_onplay", text="Playback Only")
         col.prop(rd, "simplify_gpencil_view_modifier", text="Modifiers")
         col.prop(rd, "simplify_gpencil_shader_fx", text="ShaderFX")
+        col.prop(rd, "simplify_gpencil_blend", text="Layers Blending")
 
-        col = layout.column(align=True)
         col.prop(rd, "simplify_gpencil_view_fill")
         sub = col.column()
         sub.active = rd.simplify_gpencil_view_fill
index 4fc2b12e9509a22ba8b51f08d0fe1a7dd05b6dd3..a769268bb228d70d7f66fc4eeb3b56de307aa263 100644 (file)
@@ -516,6 +516,16 @@ class TOPBAR_PT_gpencil_layers(Panel):
         col.template_list("GPENCIL_UL_layer", "", gpd, "layers", gpd.layers, "active_index",
                           rows=layer_rows, reverse=True)
 
+        gpl = context.active_gpencil_layer
+        if gpl:
+            srow = col.row(align=True)
+            srow.prop(gpl, "blend_mode", text="Blend")
+
+            srow = col.row(align=True)
+            srow.prop(gpl, "opacity", text="Opacity", slider=True)
+            srow.prop(gpl, "clamp_layer", text="",
+                     icon='MOD_MASK' if gpl.clamp_layer else 'ONIONSKIN_OFF')
+
         col = row.column()
 
         sub = col.column(align=True)
@@ -539,10 +549,6 @@ class TOPBAR_PT_gpencil_layers(Panel):
                 sub.operator("gpencil.layer_isolate", icon='LOCKED', text="").affect_visibility = False
                 sub.operator("gpencil.layer_isolate", icon='HIDE_OFF', text="").affect_visibility = True
 
-        row = layout.row(align=True)
-        if gpl:
-            row.prop(gpl, "opacity", text="Opacity", slider=True)
-
 
 class TOPBAR_MT_editor_menus(Menu):
     bl_idname = "TOPBAR_MT_editor_menus"
index 05865ba5636a662c6e051575c9c0a4d6e4c1ce76..70dfa589cdc775f4429756ebc394a56ac31da881 100644 (file)
@@ -327,6 +327,7 @@ data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_geom.glsl SRC)
 data_to_c_simple(engines/gpencil/shaders/gpencil_stroke_frag.glsl SRC)
 data_to_c_simple(engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl SRC)
 data_to_c_simple(engines/gpencil/shaders/gpencil_simple_mix_frag.glsl SRC)
+data_to_c_simple(engines/gpencil/shaders/gpencil_blend_frag.glsl SRC)
 data_to_c_simple(engines/gpencil/shaders/gpencil_point_vert.glsl SRC)
 data_to_c_simple(engines/gpencil/shaders/gpencil_point_geom.glsl SRC)
 data_to_c_simple(engines/gpencil/shaders/gpencil_point_frag.glsl SRC)
index 15ac3f37addd7477eeba0dca1659d40ac247acd2..5478c4a60b9b08e1108c3a713a6525e206420914 100644 (file)
@@ -83,8 +83,12 @@ tGPencilObjectCache *gpencil_object_cache_add(
        cache_elem->pixfactor = cache_elem->gpd->pixfactor;
        cache_elem->shader_fx = ob_orig->shader_fx;
 
-       cache_elem->init_grp = NULL;
-       cache_elem->end_grp = NULL;
+       /* shgrp array */
+       cache_elem->tot_layers = 0;
+       int totgpl = BLI_listbase_count(&cache_elem->gpd->layers);
+       if (totgpl > 0) {
+               cache_elem->shgrp_array = MEM_callocN(sizeof(tGPencilObjectCache_shgrp) * totgpl, __func__);
+       }
 
        /* calculate zdepth from point of view */
        float zdepth = 0.0;
index c8b70953f87efa04c86c8429cc9ac2a5498ebaa0..e4d6fa582b8f70d273ae7fa5e79169fa16801d37 100644 (file)
@@ -244,13 +244,15 @@ static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, floa
 }
 
 /* recalc the internal geometry caches for fill and uvs */
-static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
+static void DRW_gpencil_recalc_geometry_caches(
+       Object *ob, bGPDlayer *gpl, MaterialGPencilStyle *gp_style, bGPDstroke *gps)
 {
        if (gps->flag & GP_STROKE_RECALC_CACHES) {
                /* Calculate triangles cache for filling area (must be done only after changes) */
                if ((gps->tot_triangles == 0) || (gps->triangles == NULL)) {
                        if ((gps->totpoints > 2) &&
-                           ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)))
+                           ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
+                               (gp_style->fill_style > 0) || (gpl->blend_mode != eGplBlendMode_Normal)))
                        {
                                DRW_gpencil_triangulate_stroke_fill(ob, gps);
                        }
@@ -559,7 +561,9 @@ static void gpencil_add_fill_vertexdata(
                /* set color using material, tint color and opacity */
                interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
                tfill[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
-               if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
+               if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
+                       (gp_style->fill_style > 0) ||
+                       (gpl->blend_mode != eGplBlendMode_Normal)) {
                        if (cache->is_dirty) {
                                const float *color;
                                if (!onion) {
@@ -581,7 +585,8 @@ static void gpencil_add_fill_vertexdata(
                                /* add to list of groups */
                                if (old_len < cache->b_fill.vbo_len) {
                                        cache->grp_cache = gpencil_group_cache_add(
-                                               cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Fill, onion,
+                                               cache->grp_cache, gpl, gpf, gps,
+                                                       eGpencilBatchGroupType_Fill, onion,
                                                cache->b_fill.vbo_len,
                                                &cache->grp_size, &cache->grp_used);
                                }
@@ -637,7 +642,8 @@ static void gpencil_add_stroke_vertexdata(
                        /* add to list of groups */
                        if (old_len < cache->b_stroke.vbo_len) {
                                cache->grp_cache = gpencil_group_cache_add(
-                                       cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Stroke, onion,
+                                       cache->grp_cache, gpl, gpf, gps,
+                                               eGpencilBatchGroupType_Stroke, onion,
                                        cache->b_stroke.vbo_len,
                                        &cache->grp_size, &cache->grp_used);
                        }
@@ -687,7 +693,8 @@ static void gpencil_add_editpoints_vertexdata(
 
                                /* add to list of groups */
                                cache->grp_cache = gpencil_group_cache_add(
-                                       cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edlin, false,
+                                       cache->grp_cache, gpl, gpf, gps,
+                                               eGpencilBatchGroupType_Edlin, false,
                                        cache->b_edlin.vbo_len,
                                        &cache->grp_size, &cache->grp_used);
                        }
@@ -699,7 +706,8 @@ static void gpencil_add_editpoints_vertexdata(
 
                                                /* add to list of groups */
                                                cache->grp_cache = gpencil_group_cache_add(
-                                                       cache->grp_cache, gpl, gpf, gps, eGpencilBatchGroupType_Edit, false,
+                                                       cache->grp_cache, gpl, gpf, gps,
+                                                               eGpencilBatchGroupType_Edit, false,
                                                        cache->b_edit.vbo_len,
                                                        &cache->grp_size, &cache->grp_used);
                                        }
@@ -771,13 +779,14 @@ static void gpencil_draw_strokes(
                /* be sure recalc all cache in source stroke to avoid recalculation when frame change
                 * and improve fps */
                if (src_gps) {
-                       DRW_gpencil_recalc_geometry_caches(ob, gp_style, src_gps);
+                       DRW_gpencil_recalc_geometry_caches(ob, gpl, gp_style, src_gps);
                }
 
                /* if the fill has any value, it's considered a fill and is not drawn if simplify fill is enabled */
                if ((stl->storage->simplify_fill) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_REMOVE_FILL_LINE)) {
                        if ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
-                           (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID))
+                           (gp_style->fill_style > GP_STYLE_FILL_STYLE_SOLID) ||
+                               (gpl->blend_mode != eGplBlendMode_Normal))
                        {
                                GP_SET_SRC_GPS(src_gps);
                                continue;
@@ -798,21 +807,28 @@ static void gpencil_draw_strokes(
                                }
                        }
 
-                       /* fill */
-                       if ((gp_style->flag & GP_STYLE_FILL_SHOW) &&
-                           (!stl->storage->simplify_fill))
+                       /* hide any blend layer */
+                       if ((!stl->storage->simplify_blend) ||
+                               (gpl->blend_mode == eGplBlendMode_Normal))
                        {
-                               gpencil_add_fill_vertexdata(
-                                       cache, ob, gpl, derived_gpf, gps,
-                                       opacity, tintcolor, false, custonion);
-                       }
-                       /* stroke */
-                       if ((gp_style->flag & GP_STYLE_STROKE_SHOW) &&
-                           (gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH))
-                       {
-                               gpencil_add_stroke_vertexdata(
-                                       cache, ob, gpl, derived_gpf, gps,
-                                       opacity, tintcolor, false, custonion);
+                               /* fill */
+                               if ((gp_style->flag & GP_STYLE_FILL_SHOW) &&
+                                       (!stl->storage->simplify_fill) &&
+                                       ((gps->flag & GP_STROKE_NOFILL) == 0))
+                               {
+                                       gpencil_add_fill_vertexdata(
+                                               cache, ob, gpl, derived_gpf, gps,
+                                               opacity, tintcolor, false, custonion);
+                               }
+                               /* stroke */
+                               if ((gp_style->flag & GP_STYLE_STROKE_SHOW) &&
+                                       ((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
+                                       (gpl->blend_mode == eGplBlendMode_Normal)))
+                               {
+                                       gpencil_add_stroke_vertexdata(
+                                               cache, ob, gpl, derived_gpf, gps,
+                                               opacity, tintcolor, false, custonion);
+                               }
                        }
                }
 
@@ -1253,12 +1269,21 @@ static void DRW_gpencil_create_batches(GpencilBatchCache *cache)
 /* create all shading groups */
 static void DRW_gpencil_shgroups_create(
         GPENCIL_e_data *e_data, void *vedata,
-        Object *ob, bGPdata *gpd,
+        Object *ob,
         GpencilBatchCache *cache, tGPencilObjectCache *cache_ob)
 {
        GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
        GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
+       bGPdata *gpd = (bGPdata *)ob->data;
+
+       GpencilBatchGroup *elm = NULL;
        DRWShadingGroup *shgrp = NULL;
+       tGPencilObjectCache_shgrp *array_elm = NULL;
+
+       bGPDlayer *gpl = NULL;
+       bGPDlayer *gpl_prev = NULL;
+       int idx = 0;
+       bool tag_first = false;
 
        int start_stroke = 0;
        int start_point = 0;
@@ -1266,12 +1291,28 @@ static void DRW_gpencil_shgroups_create(
        int start_edit = 0;
        int start_edlin = 0;
 
-       cache_ob->init_grp = NULL;
-       cache_ob->end_grp = NULL;
-
        for (int i = 0; i < cache->grp_used; i++) {
-               GpencilBatchGroup *elm = &cache->grp_cache[i];
-               bGPDlayer *gpl = elm->gpl;
+               elm = &cache->grp_cache[i];
+               array_elm = &cache_ob->shgrp_array[idx];
+
+               /* save last group when change */
+               if (gpl_prev == NULL) {
+                       gpl_prev = elm->gpl;
+                       tag_first = true;
+               }
+               else {
+                       if (elm->gpl != gpl_prev)
+                       {
+                               /* first layer is always blend Normal */
+                               array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode;
+                               array_elm->end_shgrp = shgrp;
+                               gpl_prev = elm->gpl;
+                               tag_first = true;
+                               idx++;
+                       }
+               }
+
+               gpl = elm->gpl;
                bGPDframe *gpf = elm->gpf;
                bGPDstroke *gps = elm->gps;
                MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
@@ -1365,14 +1406,22 @@ static void DRW_gpencil_shgroups_create(
                        }
                }
                /* save first group */
-               if ((shgrp != NULL) && (cache_ob->init_grp == NULL)) {
-                       cache_ob->init_grp = shgrp;
+               if ((shgrp != NULL) && (tag_first)) {
+                       array_elm = &cache_ob->shgrp_array[idx];
+                       array_elm->mode = idx == 0 ? eGplBlendMode_Normal: gpl->blend_mode;
+                       array_elm->clamp_layer = gpl->flag & GP_LAYER_USE_MASK;
+                       array_elm->blend_opacity = gpl->opacity;
+                       array_elm->init_shgrp = shgrp;
+                       cache_ob->tot_layers++;
+
+                       tag_first = false;
                }
        }
 
        /* save last group */
        if (shgrp != NULL) {
-               cache_ob->end_grp = shgrp;
+               array_elm->mode = idx == 0 ? eGplBlendMode_Normal : gpl->blend_mode;
+               array_elm->end_shgrp = shgrp;
        }
 }
 /* populate a datablock for multiedit (no onions, no modifiers) */
@@ -1425,7 +1474,7 @@ void DRW_gpencil_populate_multiedit(
 
        /* create batchs and shading groups */
        DRW_gpencil_create_batches(cache);
-       DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
+       DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
 
        cache->is_dirty = false;
 }
@@ -1465,7 +1514,7 @@ void DRW_gpencil_populate_datablock(
 
        /* if object is duplicate, only create shading groups */
        if (cache_ob->is_dup_ob) {
-               DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
+               DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
                return;
        }
 
@@ -1481,8 +1530,9 @@ void DRW_gpencil_populate_datablock(
        /* draw normal strokes */
        for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
                /* don't draw layer if hidden */
-               if (gpl->flag & GP_LAYER_HIDE)
+               if (gpl->flag & GP_LAYER_HIDE) {
                        continue;
+               }
 
                /* filter view layer to gp layers in the same view layer (for compo) */
                if ((stl->storage->is_render) && (gpl->viewlayername[0] != '\0')) {
@@ -1560,7 +1610,7 @@ void DRW_gpencil_populate_datablock(
 
        /* create batchs and shading groups */
        DRW_gpencil_create_batches(cache);
-       DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
+       DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
 
        cache->is_dirty = false;
 }
@@ -1574,9 +1624,8 @@ void DRW_gpencil_populate_particles(GPENCIL_e_data *e_data, void *vedata)
                tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
                Object *ob = cache_ob->ob;
                if (cache_ob->is_dup_ob) {
-                       bGPdata *gpd = (bGPdata *)ob->data;
                        GpencilBatchCache *cache = ob->runtime.gpencil_cache;
-                       DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob);
+                       DRW_gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
                }
        }
 }
index 7be06d501f1a6b157562c0a777f158578b76c6a6..a80ad133d09fce4710c50282c25be3219c7cf08f 100644 (file)
@@ -64,6 +64,7 @@ extern char datatoc_gpencil_paper_frag_glsl[];
 extern char datatoc_gpencil_edit_point_vert_glsl[];
 extern char datatoc_gpencil_edit_point_geom_glsl[];
 extern char datatoc_gpencil_edit_point_frag_glsl[];
+extern char datatoc_gpencil_blend_frag_glsl[];
 
 /* *********** STATIC *********** */
 static GPENCIL_e_data e_data = {NULL}; /* Engine data */
@@ -221,6 +222,11 @@ static void GPENCIL_create_shaders(void)
                e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_simple_mix_frag_glsl, NULL);
        }
 
+       /* blend */
+       if (!e_data.gpencil_blend_fullscreen_sh) {
+               e_data.gpencil_blend_fullscreen_sh = DRW_shader_create_fullscreen(datatoc_gpencil_blend_frag_glsl, NULL);
+       }
+
        /* shaders for use when drawing */
        if (!e_data.gpencil_background_sh) {
                e_data.gpencil_background_sh = DRW_shader_create_fullscreen(datatoc_gpencil_background_frag_glsl, NULL);
@@ -266,6 +272,7 @@ static void GPENCIL_engine_free(void)
        DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
        DRW_SHADER_FREE_SAFE(e_data.gpencil_fullscreen_sh);
        DRW_SHADER_FREE_SAFE(e_data.gpencil_simple_fullscreen_sh);
+       DRW_SHADER_FREE_SAFE(e_data.gpencil_blend_fullscreen_sh);
        DRW_SHADER_FREE_SAFE(e_data.gpencil_background_sh);
        DRW_SHADER_FREE_SAFE(e_data.gpencil_paper_sh);
 
@@ -371,6 +378,7 @@ void GPENCIL_cache_init(void *vedata)
                stl->storage->simplify_fill = GP_SIMPLIFY_FILL(scene, stl->storage->is_playing);
                stl->storage->simplify_modif = GP_SIMPLIFY_MODIF(scene, stl->storage->is_playing);
                stl->storage->simplify_fx = GP_SIMPLIFY_FX(scene, stl->storage->is_playing);
+               stl->storage->simplify_blend = GP_SIMPLIFY_BLEND(scene, stl->storage->is_playing);
 
                /* save pixsize */
                stl->storage->pixsize = DRW_viewport_pixelsize_get();
@@ -485,6 +493,20 @@ void GPENCIL_cache_init(void *vedata)
                        stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
                }
 
+               /* blend layers pass */
+               psl->blend_pass = DRW_pass_create(
+                       "GPencil Blend Layers Pass",
+                       DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+               DRWShadingGroup *blend_shgrp = DRW_shgroup_create(e_data.gpencil_blend_fullscreen_sh, psl->blend_pass);
+               DRW_shgroup_call_add(blend_shgrp, quad, NULL);
+               DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &e_data.temp_color_tx_a);
+               DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &e_data.temp_depth_tx_a);
+               DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &e_data.temp_color_tx_fx);
+               DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &e_data.temp_depth_tx_fx);
+               DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1);
+               DRW_shgroup_uniform_int(blend_shgrp, "clamp_layer", &stl->storage->clamp_layer, 1);
+               DRW_shgroup_uniform_float(blend_shgrp, "blend_opacity", &stl->storage->blend_opacity, 1);
+
                /* create effects passes */
                if (!stl->storage->simplify_fx) {
                        GPENCIL_create_fx_passes(psl);
@@ -639,12 +661,40 @@ static void gpencil_free_obj_runtime(GPENCIL_StorageList *stl)
                tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
                bGPdata *gpd = cache_ob->gpd;
                gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY;
+
+               /* free shgrp array */
+               cache_ob->tot_layers = 0;
+               MEM_SAFE_FREE(cache_ob->shgrp_array);
        }
 
        /* free the cache itself */
        MEM_SAFE_FREE(stl->g_data->gp_object_cache);
 }
 
+static void gpencil_draw_pass_range(
+       GPENCIL_FramebufferList *fbl, GPENCIL_StorageList *stl,
+       GPENCIL_PassList *psl, GPENCIL_TextureList *txl,
+       GPUFrameBuffer *fb,
+       DRWShadingGroup *init_shgrp, DRWShadingGroup *end_shgrp, bool multi)
+{
+       if (init_shgrp == NULL) {
+               return;
+       }
+
+       /* previews don't use AA */
+       if ((!stl->storage->is_mat_preview) && (multi)) {
+               MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+       }
+
+       DRW_draw_pass_subset(
+               psl->stroke_pass, init_shgrp, end_shgrp);
+
+       if ((!stl->storage->is_mat_preview) && (multi)) {
+               MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
+       }
+
+}
+
 /* draw scene */
 void GPENCIL_draw_scene(void *ved)
 {
@@ -657,6 +707,10 @@ void GPENCIL_draw_scene(void *ved)
        GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
 
        tGPencilObjectCache *cache_ob;
+       tGPencilObjectCache_shgrp *array_elm = NULL;
+       DRWShadingGroup *init_shgrp = NULL;
+       DRWShadingGroup *end_shgrp = NULL;
+
        const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
 
        const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -712,7 +766,7 @@ void GPENCIL_draw_scene(void *ved)
                        for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
                                cache_ob = &stl->g_data->gp_object_cache[i];
                                bGPdata *gpd = cache_ob->gpd;
-
+                               init_shgrp = NULL;
                                /* Render stroke in separated framebuffer */
                                GPU_framebuffer_bind(fbl->temp_fb_a);
                                GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
@@ -720,19 +774,67 @@ void GPENCIL_draw_scene(void *ved)
                                /* Stroke Pass:
                                 * draw only a subset that usually starts with a fill and ends with stroke
                                 */
-                               if (cache_ob->init_grp) {
-                                       /* previews don't use AA */
-                                       if (!stl->storage->is_mat_preview) {
-                                               MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
-                                       }
+                               bool use_blend = false;
+                               if (cache_ob->tot_layers > 0) {
+                                       for (int e = 0; e < cache_ob->tot_layers; e++) {
+                                               bool is_last = e == cache_ob->tot_layers - 1 ? true : false;
+                                               array_elm = &cache_ob->shgrp_array[e];
+
+                                               if (((array_elm->mode == eGplBlendMode_Normal) &&
+                                                       (!use_blend) && (!array_elm->clamp_layer)) ||
+                                                       ( e == 0))
+                                               {
+                                                       if (init_shgrp == NULL) {
+                                                               init_shgrp = array_elm->init_shgrp;
+                                                       }
+                                                       end_shgrp = array_elm->end_shgrp;
+                                               }
+                                               else {
+                                                       use_blend = true;
+                                                       /* draw pending groups */
+                                                       gpencil_draw_pass_range(
+                                                               fbl, stl, psl, txl, fbl->temp_fb_a,
+                                                               init_shgrp, end_shgrp, is_last);
+
+                                                       /* draw current group in separated texture */
+                                                       init_shgrp = array_elm->init_shgrp;
+                                                       end_shgrp = array_elm->end_shgrp;
+
+                                                       GPU_framebuffer_bind(fbl->temp_fb_fx);
+                                                       GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
+                                                       gpencil_draw_pass_range(
+                                                               fbl, stl, psl, txl, fbl->temp_fb_fx,
+                                                               init_shgrp, end_shgrp,
+                                                               is_last);
+
+                                                       /* Blend A texture and FX texture */
+                                                       GPU_framebuffer_bind(fbl->temp_fb_b);
+                                                       GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
+                                                       stl->storage->blend_mode = array_elm->mode;
+                                                       stl->storage->clamp_layer = (int)array_elm->clamp_layer;
+                                                       stl->storage->blend_opacity = array_elm->blend_opacity;
+                                                       DRW_draw_pass(psl->blend_pass);
+
+                                                       /* Copy B texture to A texture to follow loop */
+                                                       e_data.input_depth_tx = e_data.temp_depth_tx_b;
+                                                       e_data.input_color_tx = e_data.temp_color_tx_b;
+
+                                                       GPU_framebuffer_bind(fbl->temp_fb_a);
+                                                       GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f);
+                                                       DRW_draw_pass(psl->mix_pass_noblend);
+
+                                                       /* prepare next group */
+                                                       init_shgrp = NULL;
+                                               }
 
-                                       DRW_draw_pass_subset(
-                                               psl->stroke_pass, cache_ob->init_grp, cache_ob->end_grp);
-
-                                       if (!stl->storage->is_mat_preview) {
-                                               MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl);
                                        }
+                                       /* last group */
+                                       gpencil_draw_pass_range(
+                                               fbl, stl, psl, txl, fbl->temp_fb_a,
+                                               init_shgrp, end_shgrp,
+                                               true);
                                }
+
                                /* Current buffer drawing */
                                if ((!is_render) && (cache_ob->is_dup_ob == false)) {
                                        DRW_draw_pass(psl->drawing_pass);
index 0fe25ba9f0fc26ebd99bdef6f2501ec6f56243a5..b8b526cb873be4baca8536b1864414a955416467 100644 (file)
@@ -54,17 +54,23 @@ struct RenderLayer;
 #define GP_SIMPLIFY_FILL(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FILL)))
 #define GP_SIMPLIFY_MODIF(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_MODIFIER)))
 #define GP_SIMPLIFY_FX(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_FX)))
+#define GP_SIMPLIFY_BLEND(scene, playing) ((GP_SIMPLIFY_ONPLAY(playing) && (GP_SIMPLIFY(scene)) && (scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_BLEND)))
 
 #define GP_IS_CAMERAVIEW ((rv3d != NULL) && (rv3d->persp == RV3D_CAMOB && v3d->camera))
 
  /* *********** OBJECTS CACHE *********** */
+typedef struct tGPencilObjectCache_shgrp {
+       int mode;
+       bool clamp_layer;
+       float blend_opacity;
+       DRWShadingGroup *init_shgrp;
+       DRWShadingGroup *end_shgrp;
+} tGPencilObjectCache_shgrp;
 
  /* used to save gpencil object data for drawing */
 typedef struct tGPencilObjectCache {
        struct Object *ob;
        struct bGPdata *gpd;
-       DRWShadingGroup *init_grp;
-       DRWShadingGroup *end_grp;
        int idx;  /*original index, can change after sort */
 
        /* effects */
@@ -90,6 +96,11 @@ typedef struct tGPencilObjectCache {
        /* GPU data size */
        int tot_vertex;
        int tot_triangles;
+
+       /* Save shader groups by layer */
+       int tot_layers;
+       tGPencilObjectCache_shgrp *shgrp_array;
+
 } tGPencilObjectCache;
 
   /* *********** LISTS *********** */
@@ -127,10 +138,15 @@ typedef struct GPENCIL_Storage {
        int tonemapping;
        short multisamples;
 
+       int blend_mode;
+       int clamp_layer;
+       float blend_opacity;
+
        /* simplify settings*/
        bool simplify_fill;
        bool simplify_modif;
        bool simplify_fx;
+       bool simplify_blend;
 
        /* Render Matrices and data */
        float persmat[4][4], persinv[4][4];
@@ -158,6 +174,7 @@ typedef struct GPENCIL_PassList {
        struct DRWPass *background_pass;
        struct DRWPass *paper_pass;
        struct DRWPass *grid_pass;
+       struct DRWPass *blend_pass;
 
        /* effects */
        struct DRWPass *fx_shader_pass;
@@ -232,6 +249,7 @@ typedef struct GPENCIL_e_data {
        struct GPUShader *gpencil_drawing_fill_sh;
        struct GPUShader *gpencil_fullscreen_sh;
        struct GPUShader *gpencil_simple_fullscreen_sh;
+       struct GPUShader *gpencil_blend_fullscreen_sh;
        struct GPUShader *gpencil_background_sh;
        struct GPUShader *gpencil_paper_sh;
 
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
new file mode 100644 (file)
index 0000000..2ba02be
--- /dev/null
@@ -0,0 +1,130 @@
+in vec4 uvcoordsvar;
+
+out vec4 FragColor;
+
+uniform sampler2D strokeColor;
+uniform sampler2D strokeDepth;
+uniform sampler2D blendColor;
+uniform sampler2D blendDepth;
+uniform int mode;
+uniform int clamp_layer;
+uniform float blend_opacity;
+
+#define ON 1
+#define OFF 0
+
+#define MODE_NORMAL   0
+#define MODE_OVERLAY  1
+#define MODE_ADD      2
+#define MODE_SUB      3
+#define MODE_MULTIPLY 4
+#define MODE_DIVIDE   5
+
+float overlay_color(float a, float b)
+{
+       float rtn;
+               if (a < 0.5) {
+                       rtn = 2.0 * a * b;
+               }
+               else {
+                       rtn = 1.0 - 2.0 * (1.0 - a) * (1.0 - b);
+               }
+
+       return rtn;
+}
+
+vec4 get_blend_color(int mode, vec4 src_color, vec4 blend_color)
+{
+       vec4 mix_color = blend_color;
+       vec4 outcolor;
+
+    if (mix_color.a == 0) {
+               outcolor = src_color;
+       }
+       else if (mode == MODE_OVERLAY) {
+               mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
+               outcolor.r = overlay_color(src_color.r, mix_color.r);
+               outcolor.g = overlay_color(src_color.g, mix_color.g);
+               outcolor.b = overlay_color(src_color.b, mix_color.b);
+               outcolor.a = src_color.a;
+       }
+       else if (mode == MODE_ADD){
+               mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
+               outcolor = src_color + mix_color;
+               outcolor.a = src_color.a;
+       }
+       else if (mode == MODE_SUB){
+               outcolor = src_color - mix_color;
+               outcolor.a = clamp(src_color.a - (mix_color.a * blend_opacity), 0.0, 1.0);
+       }
+       else if (mode == MODE_MULTIPLY) {
+               mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
+               outcolor = src_color * mix_color;
+               outcolor.a = src_color.a;
+       }
+       else if (mode == MODE_DIVIDE) {
+               mix_color.rgb = mix_color.rgb * mix_color.a * blend_opacity;
+               outcolor = src_color / mix_color;
+               outcolor.a = src_color.a;
+       }
+       else {
+               outcolor = mix_color * blend_opacity;;
+               outcolor.a = src_color.a;
+       }
+       
+       return outcolor;
+}
+
+void main()
+{
+       vec4 outcolor;
+       ivec2 uv = ivec2(gl_FragCoord.xy);
+       vec4 stroke_color =  texelFetch(strokeColor, uv, 0).rgba;
+       float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
+       
+       vec4 mix_color =  texelFetch(blendColor, uv, 0).rgba;
+       float mix_depth = texelFetch(blendDepth, uv, 0).r;
+
+       /* premult alpha factor to remove double blend effects */
+       if (stroke_color.a > 0) {
+               stroke_color = vec4(vec3(stroke_color.rgb / stroke_color.a), stroke_color.a);
+       }
+       if (mix_color.a > 0) {
+               mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
+       }
+       
+       /* Normal mode */
+       if (mode == MODE_NORMAL) {
+               if (stroke_color.a > 0) {
+                       if (mix_color.a > 0) {
+                               FragColor = vec4(mix(stroke_color.rgb, mix_color.rgb, mix_color.a), stroke_color.a);
+                               gl_FragDepth = mix_depth;
+                       }
+                       else {
+                               FragColor = stroke_color;
+                               gl_FragDepth = stroke_depth;
+                       }
+               }
+               else {
+                       if (clamp_layer == ON) {
+                               discard;
+                       }
+                       else {
+                               FragColor = mix_color;
+                               gl_FragDepth = mix_depth;
+                       }
+               }
+               return;
+       }
+       
+       /* if not using mask, return mix color */
+       if ((stroke_color.a == 0) && (clamp_layer == OFF)) {
+               FragColor = mix_color;
+               gl_FragDepth = mix_depth;
+               return;
+       }
+
+       /* apply blend mode */
+       FragColor = get_blend_color(mode, stroke_color, mix_color);
+       gl_FragDepth = stroke_depth;
+}
index 8a1bccc69579cd3ab6804b7d26eef1f9a242ca2b..cebdc4b29b9f085cb129fdccab381dac1052d7e5 100644 (file)
@@ -269,6 +269,9 @@ typedef struct bGPDlayer {
        float opacity;          /* Opacity of the layer */
        char viewlayername[64]; /* Name of the layer used to filter render output */
 
+       int blend_mode;         /* blend modes */
+       char pad_[4];
+
        bGPDlayer_Runtime runtime;
 } bGPDlayer;
 
@@ -292,6 +295,8 @@ typedef enum eGPDlayer_Flag {
        GP_LAYER_VOLUMETRIC             = (1 << 10),
        /* Unlock color */
        GP_LAYER_UNLOCK_COLOR   = (1 << 12),
+       /* Mask Layer */
+       GP_LAYER_USE_MASK = (1 << 13),
 } eGPDlayer_Flag;
 
 /* bGPDlayer->onion_flag */
@@ -300,6 +305,16 @@ typedef enum eGPDlayer_OnionFlag {
        GP_LAYER_ONIONSKIN = (1 << 0),
 } eGPDlayer_OnionFlag;
 
+/* layer blend_mode */
+typedef enum eGPLayerBlendModes {
+       eGplBlendMode_Normal = 0,
+       eGplBlendMode_Overlay = 1,
+       eGplBlendMode_Add = 2,
+       eGplBlendMode_Subtract = 3,
+       eGplBlendMode_Multiply = 4,
+       eGplBlendMode_Divide = 5,
+} eGPLayerBlendModes;
+
 /* ***************************************** */
 /* GP Datablock */
 
index 7ab4187de1a5588ab0fa7ad2563b2fefe256b15d..e2cfd79ca9341984b4bc8ca1ba17e2922363b400 100644 (file)
@@ -2144,7 +2144,9 @@ typedef enum eGPencil_SimplifyFlags {
        /* Remove fill external line */
        SIMPLIFY_GPENCIL_REMOVE_FILL_LINE = (1 << 4),
        /* Simplify Shader FX */
-       SIMPLIFY_GPENCIL_FX               = (1 << 5)
+       SIMPLIFY_GPENCIL_FX               = (1 << 5),
+       /* Simplify layer blending */
+       SIMPLIFY_GPENCIL_BLEND            = (1 << 6),
 } eGPencil_SimplifyFlags;
 
 /* ToolSettings.gpencil_*_align - Stroke Placement mode flags */
index 8c11909d022a5b612d9793ced085fa2aa96f0b6f..d6257aa0c1b10ca176fdf7dbf1cbb0fff5200b6d 100644 (file)
@@ -78,6 +78,15 @@ const EnumPropertyItem rna_enum_gplayer_move_type_items[] = {
    {0, NULL, 0, NULL, NULL}
 };
 
+static const EnumPropertyItem rna_enum_layer_blend_modes_items[] = {
+       {eGplBlendMode_Normal, "NORMAL", 0, "Normal", "" },
+       {eGplBlendMode_Overlay, "OVERLAY", 0, "Overlay", "" },
+       {eGplBlendMode_Add, "ADD", 0, "Add", "" },
+       {eGplBlendMode_Subtract, "SUBTRACT", 0, "Subtract", "" },
+       {eGplBlendMode_Multiply, "MULTIPLY", 0, "Multiply", "" },
+       {eGplBlendMode_Divide, "DIVIDE", 0, "Divide", "" },
+       {0, NULL, 0, NULL, NULL }
+};
 #endif
 
 #ifdef RNA_RUNTIME
@@ -1159,6 +1168,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "ViewLayer",
                "Only include Layer in this View Layer render output (leave blank to include always)");
 
+       /* blend mode */
+       prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_sdna(prop, NULL, "blend_mode");
+       RNA_def_property_enum_items(prop, rna_enum_layer_blend_modes_items);
+       RNA_def_property_ui_text(prop, "Blend Mode", "Blend mode");
+       RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
        /* Flags */
        prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);
@@ -1184,6 +1200,12 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Lock Material", "Disable Material editing");
        RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 
+       prop = RNA_def_property(srna, "clamp_layer", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+       RNA_def_property_ui_text(prop, "Clamp Layer",
+               "Clamp any pixel outside underlying layers drawing");
+       RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
 
        /* exposed as layers.active */
 #if 0
index eeb48b67d282e203f920594fff1a1f229d31d919..9d943dca9ec059756d2847c58beb2c0515e8c9ef 100644 (file)
@@ -5344,6 +5344,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Simplify Shaders", "Do not apply shader fx");
        RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
 
+       prop = RNA_def_property(srna, "simplify_gpencil_blend", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "simplify_gpencil", SIMPLIFY_GPENCIL_BLEND);
+       RNA_def_property_ui_text(prop, "Layers Blending", "Do not display blend layers");
+       RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
        /* persistent data */
        prop = RNA_def_property(srna, "use_persistent_data", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "mode", R_PERSISTENT_DATA);