Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntonio Vazquez <blendergit@gmail.com>2020-03-09 18:27:24 +0300
committerAntonio Vazquez <blendergit@gmail.com>2020-03-09 18:27:24 +0300
commit29f3af95272590d26f610ae828b2eeee89c82a00 (patch)
treea696a58a2561c48f7ec6166e369e22081e0a64d8 /source/blender/draw/engines
parentdcb93126876879d969a30a7865700abd072066f8 (diff)
GPencil: Refactor of Draw Engine, Vertex Paint and all internal functions
This commit is a full refactor of the grease pencil modules including Draw Engine, Modifiers, VFX, depsgraph update, improvements in operators and conversion of Sculpt and Weight paint tools to real brushes. Also, a huge code cleanup has been done at all levels. Thanks to @fclem for his work and yo @pepeland and @mendio for the testing and help in the development. Differential Revision: https://developer.blender.org/D6293
Diffstat (limited to 'source/blender/draw/engines')
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_antialiasing.c169
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c568
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c1021
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_data.c502
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c2071
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c1725
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h792
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_render.c365
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader.c311
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_shader_fx.c1415
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl85
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl82
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl37
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl68
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl46
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl70
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl51
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl65
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl98
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl98
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl32
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl74
-rw-r--r--source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl44
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl64
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl21
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl12
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl157
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl593
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl17
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl14
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl17
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl53
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl19
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl234
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl16
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl126
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl31
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl11
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl9
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl126
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl142
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl66
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl15
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl110
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl264
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl63
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl5
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl354
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl76
-rw-r--r--source/blender/draw/engines/overlay/overlay_engine.c24
-rw-r--r--source/blender/draw/engines/overlay/overlay_extra.c85
-rw-r--r--source/blender/draw/engines/overlay/overlay_gpencil.c391
-rw-r--r--source/blender/draw/engines/overlay/overlay_motion_path.c4
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c158
-rw-r--r--source/blender/draw/engines/overlay/overlay_private.h19
-rw-r--r--source/blender/draw/engines/overlay/overlay_shader.c103
-rw-r--r--source/blender/draw/engines/overlay/overlay_wireframe.c6
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl35
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl14
-rw-r--r--source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl103
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl38
-rw-r--r--source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl14
-rw-r--r--source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl6
-rw-r--r--source/blender/draw/engines/workbench/workbench_render.c60
64 files changed, 5210 insertions, 8254 deletions
diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.c b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c
new file mode 100644
index 00000000000..e81073db4a5
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_antialiasing.c
@@ -0,0 +1,169 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+
+#include "DRW_render.h"
+
+#include "gpencil_engine.h"
+
+#include "smaa_textures.h"
+
+void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata)
+{
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_TextureList *txl = vedata->txl;
+ GPENCIL_PassList *psl = vedata->psl;
+ DRWShadingGroup *grp;
+
+ const float *size = DRW_viewport_size_get();
+ const float *sizeinv = DRW_viewport_invert_size_get();
+ float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]};
+
+ if (pd->simplify_antialias) {
+ /* No AA fallback. */
+ DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(2);
+ grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "blendTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
+ DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", false);
+ DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ return;
+ }
+
+ if (txl->smaa_search_tx == NULL) {
+ txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH,
+ SEARCHTEX_HEIGHT,
+ 0,
+ 2,
+ searchTexBytes,
+ GPU_R8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH,
+ AREATEX_HEIGHT,
+ 0,
+ 2,
+ areaTexBytes,
+ GPU_RG8,
+ GPU_DATA_UNSIGNED_BYTE,
+ 0,
+ false,
+ NULL);
+
+ GPU_texture_bind(txl->smaa_search_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_search_tx, true);
+ GPU_texture_unbind(txl->smaa_search_tx);
+
+ GPU_texture_bind(txl->smaa_area_tx, 0);
+ GPU_texture_filter_mode(txl->smaa_area_tx, true);
+ GPU_texture_unbind(txl->smaa_area_tx);
+ }
+
+ {
+ pd->smaa_edge_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_RG8, &draw_engine_gpencil_type);
+ pd->smaa_weight_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_RGBA8, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(pd->smaa_edge_tx),
+ });
+
+ GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb,
+ {
+ GPU_ATTACHMENT_NONE,
+ GPU_ATTACHMENT_TEXTURE(pd->smaa_weight_tx),
+ });
+ }
+
+ {
+ /* Stage 1: Edge detection. */
+ DRW_PASS_CREATE(psl->smaa_edge_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(0);
+ grp = DRW_shgroup_create(sh, psl->smaa_edge_ps);
+ DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 2: Blend Weight/Coord. */
+ DRW_PASS_CREATE(psl->smaa_weight_ps, DRW_STATE_WRITE_COLOR);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(1);
+ grp = DRW_shgroup_create(sh, psl->smaa_weight_ps);
+ DRW_shgroup_uniform_texture(grp, "edgesTex", pd->smaa_edge_tx);
+ DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx);
+ DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ {
+ /* Stage 3: Resolve. */
+ DRW_PASS_CREATE(psl->smaa_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM);
+
+ GPUShader *sh = GPENCIL_shader_antialiasing(2);
+ grp = DRW_shgroup_create(sh, psl->smaa_resolve_ps);
+ DRW_shgroup_uniform_texture(grp, "blendTex", pd->smaa_weight_tx);
+ DRW_shgroup_uniform_texture(grp, "colorTex", pd->color_tx);
+ DRW_shgroup_uniform_texture(grp, "revealTex", pd->reveal_tx);
+ DRW_shgroup_uniform_bool_copy(grp, "doAntiAliasing", true);
+ DRW_shgroup_uniform_bool_copy(grp, "onlyAlpha", pd->draw_wireframe);
+ DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics);
+
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata)
+{
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_PassList *psl = vedata->psl;
+
+ if (!pd->simplify_antialias) {
+ GPU_framebuffer_bind(fbl->smaa_edge_fb);
+ DRW_draw_pass(psl->smaa_edge_ps);
+
+ GPU_framebuffer_bind(fbl->smaa_weight_fb);
+ DRW_draw_pass(psl->smaa_weight_ps);
+ }
+
+ GPU_framebuffer_bind(pd->scene_fb);
+ DRW_draw_pass(psl->smaa_resolve_ps);
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
index 5357d6167be..743171b09fb 100644
--- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c
@@ -33,324 +33,368 @@
#include "BKE_gpencil.h"
#include "BKE_object.h"
+#include "BLI_memblock.h"
+#include "BLI_link_utils.h"
+
#include "gpencil_engine.h"
#include "draw_cache_impl.h"
#include "DEG_depsgraph.h"
-/* verify if exist a non instanced version of the object */
-static bool gpencil_has_noninstanced_object(Object *ob_instance)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const ViewLayer *view_layer = draw_ctx->view_layer;
- Object *ob = NULL;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- ob = base->object;
- if (ob->type != OB_GPENCIL) {
- continue;
- }
- /* is not duplicated and the name is equals */
- if ((ob->base_flag & BASE_FROM_DUPLI) == 0) {
- if (STREQ(ob->id.name, ob_instance->id.name)) {
- return true;
- }
- }
- }
-
- return false;
-}
+/* -------------------------------------------------------------------- */
+/** \name Object
+ * \{ */
-/* add a gpencil object to cache to defer drawing */
-tGPencilObjectCache *gpencil_object_cache_add(tGPencilObjectCache *cache_array,
- Object *ob,
- int *gp_cache_size,
- int *gp_cache_used)
+GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob)
{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- tGPencilObjectCache *cache_elem = NULL;
- RegionView3D *rv3d = draw_ctx->rv3d;
- View3D *v3d = draw_ctx->v3d;
- tGPencilObjectCache *p = NULL;
-
- /* By default a cache is created with one block with a predefined number of free slots,
- * if the size is not enough, the cache is reallocated adding a new block of free slots.
- * This is done in order to keep cache small. */
- if (*gp_cache_used + 1 > *gp_cache_size) {
- if ((*gp_cache_size == 0) || (cache_array == NULL)) {
- p = MEM_callocN(sizeof(struct tGPencilObjectCache) * GP_CACHE_BLOCK_SIZE,
- "tGPencilObjectCache");
- *gp_cache_size = GP_CACHE_BLOCK_SIZE;
- }
- else {
- *gp_cache_size += GP_CACHE_BLOCK_SIZE;
- p = MEM_recallocN(cache_array, sizeof(struct tGPencilObjectCache) * *gp_cache_size);
- }
- cache_array = p;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ GPENCIL_tObject *tgp_ob = BLI_memblock_alloc(pd->gp_object_pool);
+
+ tgp_ob->layers.first = tgp_ob->layers.last = NULL;
+ tgp_ob->vfx.first = tgp_ob->vfx.last = NULL;
+ tgp_ob->camera_z = dot_v3v3(pd->camera_z_axis, ob->obmat[3]);
+ tgp_ob->is_drawmode3d = (gpd->draw_mode == GP_DRAWMODE_3D) || pd->draw_depth_only;
+ tgp_ob->object_scale = mat4_to_scale(ob->obmat);
+
+ /* Find the normal most likely to represent the gpObject. */
+ /* TODO: This does not work quite well if you use
+ * strokes not aligned with the object axes. Maybe we could try to
+ * compute the minimum axis of all strokes. But this would be more
+ * computationaly heavy and should go into the GPData evaluation. */
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ /* Convert bbox to matrix */
+ float mat[4][4], size[3], center[3];
+ BKE_boundbox_calc_size_aabb(bbox, size);
+ BKE_boundbox_calc_center_aabb(bbox, center);
+ unit_m4(mat);
+ copy_v3_v3(mat[3], center);
+ /* Avoid division by 0.0 later. */
+ add_v3_fl(size, 1e-8f);
+ rescale_m4(mat, size);
+ /* BBox space to World. */
+ mul_m4_m4m4(mat, ob->obmat, mat);
+ if (DRW_view_is_persp_get(NULL)) {
+ /* BBox center to camera vector. */
+ sub_v3_v3v3(tgp_ob->plane_normal, pd->camera_pos, mat[3]);
}
- /* zero out all pointers */
- cache_elem = &cache_array[*gp_cache_used];
- memset(cache_elem, 0, sizeof(*cache_elem));
-
- cache_elem->ob = ob;
- cache_elem->gpd = (bGPdata *)ob->data;
- cache_elem->name = BKE_id_to_unique_string_key(&ob->id);
-
- copy_v3_v3(cache_elem->loc, ob->obmat[3]);
- copy_m4_m4(cache_elem->obmat, ob->obmat);
- cache_elem->idx = *gp_cache_used;
-
- /* object is duplicated (particle) */
- if (ob->base_flag & BASE_FROM_DUPLI) {
- /* Check if the original object is not in the viewlayer
- * and cannot be managed as dupli. This is slower, but required to keep
- * the particle drawing FPS and display instanced objects in scene
- * without the original object */
- bool has_original = gpencil_has_noninstanced_object(ob);
- cache_elem->is_dup_ob = (has_original) ? ob->base_flag & BASE_FROM_DUPLI : false;
+ else {
+ copy_v3_v3(tgp_ob->plane_normal, pd->camera_z_axis);
+ }
+ /* World to BBox space. */
+ invert_m4(mat);
+ /* Normalize the vector in BBox space. */
+ mul_mat3_m4_v3(mat, tgp_ob->plane_normal);
+ normalize_v3(tgp_ob->plane_normal);
+
+ transpose_m4(mat);
+ /* mat is now a "normal" matrix which will transform
+ * BBox space normal to world space. */
+ mul_mat3_m4_v3(mat, tgp_ob->plane_normal);
+ normalize_v3(tgp_ob->plane_normal);
+
+ /* Define a matrix that will be used to render a triangle to merge the depth of the rendered
+ * gpencil object with the rest of the scene. */
+ unit_m4(tgp_ob->plane_mat);
+ copy_v3_v3(tgp_ob->plane_mat[2], tgp_ob->plane_normal);
+ orthogonalize_m4(tgp_ob->plane_mat, 2);
+ mul_mat3_m4_v3(ob->obmat, size);
+ float radius = len_v3(size);
+ mul_m4_v3(ob->obmat, center);
+ rescale_m4(tgp_ob->plane_mat, (float[3]){radius, radius, radius});
+ copy_v3_v3(tgp_ob->plane_mat[3], center);
+
+ /* Add to corresponding list if is in front. */
+ if (ob->dtx & OB_DRAWXRAY) {
+ BLI_LINKS_APPEND(&pd->tobjects_infront, tgp_ob);
}
else {
- cache_elem->is_dup_ob = false;
+ BLI_LINKS_APPEND(&pd->tobjects, tgp_ob);
}
- cache_elem->scale = mat4_to_scale(ob->obmat);
+ return tgp_ob;
+}
- /* save FXs */
- cache_elem->pixfactor = cache_elem->gpd->pixfactor;
- cache_elem->shader_fx = ob->shader_fx;
+#define SORT_IMPL_LINKTYPE GPENCIL_tObject
- /* save wire mode (object mode is always primary option) */
- if (ob->dt == OB_WIRE) {
- cache_elem->shading_type[0] = (int)OB_WIRE;
+#define SORT_IMPL_FUNC gpencil_tobject_sort_fn_r
+#include "../../blenlib/intern/list_sort_impl.h"
+#undef SORT_IMPL_FUNC
+
+#undef SORT_IMPL_LINKTYPE
+
+static int gpencil_tobject_dist_sort(const void *a, const void *b)
+{
+ const GPENCIL_tObject *ob_a = (const GPENCIL_tObject *)a;
+ const GPENCIL_tObject *ob_b = (const GPENCIL_tObject *)b;
+ /* Reminder, camera_z is negative in front of the camera. */
+ if (ob_a->camera_z > ob_b->camera_z) {
+ return 1;
}
- else {
- if (v3d) {
- cache_elem->shading_type[0] = (int)v3d->shading.type;
- }
+ else if (ob_a->camera_z < ob_b->camera_z) {
+ return -1;
}
-
- /* 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__);
+ else {
+ return 0;
}
+}
- /* calculate zdepth from point of view */
- float zdepth = 0.0;
- if (rv3d) {
- if (rv3d->is_persp) {
- zdepth = ED_view3d_calc_zfac(rv3d, ob->obmat[3], NULL);
- }
- else {
- zdepth = -dot_v3v3(rv3d->viewinv[2], ob->obmat[3]);
+void gpencil_object_cache_sort(GPENCIL_PrivateData *pd)
+{
+ /* Sort object by distance to the camera. */
+ if (pd->tobjects.first) {
+ pd->tobjects.first = gpencil_tobject_sort_fn_r(pd->tobjects.first, gpencil_tobject_dist_sort);
+ /* Relink last pointer. */
+ while (pd->tobjects.last->next) {
+ pd->tobjects.last = pd->tobjects.last->next;
}
}
- else {
- /* In render mode, rv3d is not available, so use the distance to camera.
- * The real distance is not important, but the relative distance to the camera plane
- * in order to sort by z_depth of the objects
- */
- float vn[3] = {0.0f, 0.0f, -1.0f}; /* always face down */
- float plane_cam[4];
- struct Object *camera = draw_ctx->scene->camera;
- if (camera) {
- mul_m4_v3(camera->obmat, vn);
- normalize_v3(vn);
- plane_from_point_normal_v3(plane_cam, camera->loc, vn);
- zdepth = dist_squared_to_plane_v3(ob->obmat[3], plane_cam);
+ if (pd->tobjects_infront.first) {
+ pd->tobjects_infront.first = gpencil_tobject_sort_fn_r(pd->tobjects_infront.first,
+ gpencil_tobject_dist_sort);
+ /* Relink last pointer. */
+ while (pd->tobjects_infront.last->next) {
+ pd->tobjects_infront.last = pd->tobjects_infront.last->next;
}
}
- cache_elem->zdepth = zdepth;
- /* increase slots used in cache */
- (*gp_cache_used)++;
-
- return cache_array;
-}
-/* add a shading group to the cache to create later */
-GpencilBatchGroup *gpencil_group_cache_add(GpencilBatchGroup *cache_array,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps,
- const short type,
- const bool onion,
- const int vertex_idx,
- int *grp_size,
- int *grp_used)
-{
- GpencilBatchGroup *cache_elem = NULL;
- GpencilBatchGroup *p = NULL;
-
- /* By default a cache is created with one block with a predefined number of free slots,
- * if the size is not enough, the cache is reallocated adding a new block of free slots.
- * This is done in order to keep cache small. */
- if (*grp_used + 1 > *grp_size) {
- if ((*grp_size == 0) || (cache_array == NULL)) {
- p = MEM_callocN(sizeof(struct GpencilBatchGroup) * GPENCIL_GROUPS_BLOCK_SIZE,
- "GpencilBatchGroup");
- *grp_size = GPENCIL_GROUPS_BLOCK_SIZE;
+ /* Join both lists, adding infront. */
+ if (pd->tobjects_infront.first != NULL) {
+ if (pd->tobjects.last != NULL) {
+ pd->tobjects.last->next = pd->tobjects_infront.first;
+ pd->tobjects.last = pd->tobjects_infront.last;
}
else {
- *grp_size += GPENCIL_GROUPS_BLOCK_SIZE;
- p = MEM_recallocN(cache_array, sizeof(struct GpencilBatchGroup) * *grp_size);
+ /* Only in front objects. */
+ pd->tobjects.first = pd->tobjects_infront.first;
+ pd->tobjects.last = pd->tobjects_infront.last;
}
- cache_array = p;
}
- /* zero out all data */
- cache_elem = &cache_array[*grp_used];
- memset(cache_elem, 0, sizeof(*cache_elem));
-
- cache_elem->gpl = gpl;
- cache_elem->gpf = gpf;
- cache_elem->gps = gps;
- cache_elem->type = type;
- cache_elem->onion = onion;
- cache_elem->vertex_idx = vertex_idx;
+}
- /* increase slots used in cache */
- (*grp_used)++;
+/** \} */
- return cache_array;
-}
+/* -------------------------------------------------------------------- */
+/** \name Layer
+ * \{ */
-/* get current cache data */
-static GpencilBatchCache *gpencil_batch_get_element(Object *ob)
+static float gpencil_layer_final_opacity_get(const GPENCIL_PrivateData *pd,
+ const Object *ob,
+ const bGPDlayer *gpl)
{
- return ob->runtime.gpencil_cache;
+ const bool is_obact = ((pd->obact) && (pd->obact == ob));
+ const bool is_fade = ((pd->fade_layer_opacity > -1.0f) && (is_obact) &&
+ ((gpl->flag & GP_LAYER_ACTIVE) == 0));
+
+ /* Defines layer opacity. For active object depends of layer opacity factor, and
+ * for no active object, depends if the fade grease pencil objects option is enabled. */
+ if (!pd->is_render) {
+ if (is_obact && is_fade) {
+ return gpl->opacity * pd->fade_layer_opacity;
+ }
+ else if (!is_obact && (pd->fade_gp_object_opacity > -1.0f)) {
+ return gpl->opacity * pd->fade_gp_object_opacity;
+ }
+ }
+ return gpl->opacity;
}
-/* verify if cache is valid */
-static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra)
+static void gpencil_layer_final_tint_and_alpha_get(const GPENCIL_PrivateData *pd,
+ const bGPdata *gpd,
+ const bGPDlayer *gpl,
+ const bGPDframe *gpf,
+ float r_tint[4],
+ float *r_alpha)
{
- bool valid = true;
- if (cache == NULL) {
- return false;
- }
-
- cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
- if (cfra != cache->cache_frame) {
- valid = false;
- }
- else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
- valid = false;
- }
- else if (gpd->flag & GP_DATA_PYTHON_UPDATED) {
- gpd->flag &= ~GP_DATA_PYTHON_UPDATED;
- valid = false;
+ const bool use_onion = (gpf != NULL) && (gpf->runtime.onion_id != 0.0f);
+ if (use_onion) {
+ const bool use_onion_custom_col = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
+ const bool use_onion_fade = (gpd->onion_flag & GP_ONION_FADE) != 0;
+ const bool use_next_col = gpf->runtime.onion_id > 0.0f;
+
+ const float *onion_col_custom = (use_onion_custom_col) ?
+ (use_next_col ? gpd->gcolor_next : gpd->gcolor_prev) :
+ U.gpencil_new_layer_col;
+
+ copy_v4_fl4(r_tint, UNPACK3(onion_col_custom), 1.0f);
+
+ *r_alpha = use_onion_fade ? (1.0f / abs(gpf->runtime.onion_id)) : 0.5f;
+ *r_alpha *= gpd->onion_factor;
+ *r_alpha = (gpd->onion_factor > 0.0f) ? clamp_f(*r_alpha, 0.1f, 1.0f) :
+ clamp_f(*r_alpha, 0.01f, 1.0f);
}
- else if (cache->is_editmode) {
- valid = false;
- }
- else if (cache->is_dirty) {
- valid = false;
+ else {
+ copy_v4_v4(r_tint, gpl->tintcolor);
+ if (GPENCIL_SIMPLIFY_TINT(pd->scene)) {
+ r_tint[3] = 0.0f;
+ }
+ *r_alpha = 1.0f;
}
- return valid;
+ *r_alpha *= pd->xray_alpha;
}
-/* cache init */
-static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra)
+GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
+ const Object *ob,
+ const bGPDlayer *gpl,
+ const bGPDframe *gpf,
+ GPENCIL_tObject *tgp_ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
- GpencilBatchCache *cache = gpencil_batch_get_element(ob);
+ const bool is_in_front = (ob->dtx & OB_DRAWXRAY);
+ const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
+ const bool overide_vertcol = (pd->v3d_color_type != -1);
+ const bool is_vert_col_mode = (pd->v3d_color_type == V3D_SHADING_VERTEX_COLOR) ||
+ GPENCIL_VERTEX_MODE(gpd) || pd->is_render;
+ bool is_masked = (gpl->flag & GP_LAYER_USE_MASK) && !BLI_listbase_is_empty(&gpl->mask_layers);
+
+ float vert_col_opacity = (overide_vertcol) ? (is_vert_col_mode ? 1.0f : 0.0f) :
+ gpl->vertex_paint_opacity;
+ /* Negate thickness sign to tag that strokes are in screen space.
+ * Convert to world units (by default, 1 meter = 2000 px). */
+ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / GPENCIL_PIXEL_FACTOR);
+ float layer_opacity = gpencil_layer_final_opacity_get(pd, ob, gpl);
+ float layer_tint[4];
+ float layer_alpha;
+ gpencil_layer_final_tint_and_alpha_get(pd, gpd, gpl, gpf, layer_tint, &layer_alpha);
+
+ /* Create the new layer descriptor. */
+ GPENCIL_tLayer *tgp_layer = BLI_memblock_alloc(pd->gp_layer_pool);
+ BLI_LINKS_APPEND(&tgp_ob->layers, tgp_layer);
+ tgp_layer->layer_id = BLI_findindex(&gpd->layers, gpl);
+ tgp_layer->mask_bits = NULL;
+ tgp_layer->mask_invert_bits = NULL;
+ tgp_layer->blend_ps = NULL;
+
+ /* Masking: Go through mask list and extract valid masks in a bitmap. */
+ if (is_masked) {
+ bool valid_mask = false;
+ /* Warning: only GP_MAX_MASKBITS amount of bits.
+ * TODO(fclem) Find a better system without any limitation. */
+ tgp_layer->mask_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
+ tgp_layer->mask_invert_bits = BLI_memblock_alloc(pd->gp_maskbit_pool);
+ BLI_bitmap_set_all(tgp_layer->mask_bits, false, GP_MAX_MASKBITS);
+
+ LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
+ bGPDlayer *gpl_mask = BKE_gpencil_layer_named_get(gpd, mask->name);
+ if (gpl_mask && (gpl_mask != gpl) && ((gpl_mask->flag & GP_LAYER_HIDE) == 0) &&
+ ((mask->flag & GP_MASK_HIDE) == 0)) {
+ int index = BLI_findindex(&gpd->layers, gpl_mask);
+ if (index < GP_MAX_MASKBITS) {
+ const bool invert = (mask->flag & GP_MASK_INVERT) != 0;
+ BLI_BITMAP_SET(tgp_layer->mask_bits, index, true);
+ BLI_BITMAP_SET(tgp_layer->mask_invert_bits, index, invert);
+ valid_mask = true;
+ }
+ }
+ }
- if (!cache) {
- cache = MEM_callocN(sizeof(*cache), __func__);
- ob->runtime.gpencil_cache = cache;
- }
- else {
- memset(cache, 0, sizeof(*cache));
+ if (valid_mask) {
+ pd->use_mask_fb = true;
+ }
+ else {
+ tgp_layer->mask_bits = NULL;
+ }
+ is_masked = valid_mask;
}
- cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd);
-
- cache->is_dirty = true;
+ /* Blending: Force blending for masked layer. */
+ if (is_masked || (gpl->blend_mode != eGplBlendMode_Regular) || (layer_opacity < 1.0f)) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL;
+ switch (gpl->blend_mode) {
+ case eGplBlendMode_Regular:
+ state |= DRW_STATE_BLEND_ALPHA_PREMUL;
+ break;
+ case eGplBlendMode_Add:
+ state |= DRW_STATE_BLEND_ADD_FULL;
+ break;
+ case eGplBlendMode_Subtract:
+ state |= DRW_STATE_BLEND_SUB;
+ break;
+ case eGplBlendMode_Multiply:
+ case eGplBlendMode_Divide:
+ case eGplBlendMode_Overlay:
+ state |= DRW_STATE_BLEND_MUL;
+ break;
+ }
- cache->cache_frame = cfra;
+ if (ELEM(gpl->blend_mode, eGplBlendMode_Subtract, eGplBlendMode_Overlay)) {
+ /* For these effect to propagate, we need a signed floating point buffer. */
+ pd->use_signed_fb = true;
+ }
- return cache;
-}
+ tgp_layer->blend_ps = DRW_pass_create("GPencil Blend Layer", state);
+
+ GPUShader *sh = GPENCIL_shader_layer_blend_get();
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, tgp_layer->blend_ps);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", gpl->blend_mode);
+ DRW_shgroup_uniform_float_copy(grp, "blendOpacity", layer_opacity);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuf", &pd->color_layer_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "revealBuf", &pd->reveal_layer_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "maskBuf", (is_masked) ? &pd->mask_tx : &pd->dummy_tx);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (gpl->blend_mode == eGplBlendMode_Overlay) {
+ /* We cannot do custom blending on MultiTarget framebuffers.
+ * Workaround by doing 2 passes. */
+ grp = DRW_shgroup_create(sh, tgp_layer->blend_ps);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", 999);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
-/* clear cache */
-static void gpencil_batch_cache_clear(GpencilBatchCache *cache)
-{
- if (!cache) {
- return;
+ pd->use_layer_fb = true;
}
- GPU_BATCH_DISCARD_SAFE(cache->b_stroke.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_point.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_fill.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_edit.batch);
- GPU_BATCH_DISCARD_SAFE(cache->b_edlin.batch);
-
- MEM_SAFE_FREE(cache->b_stroke.batch);
- MEM_SAFE_FREE(cache->b_point.batch);
- MEM_SAFE_FREE(cache->b_fill.batch);
- MEM_SAFE_FREE(cache->b_edit.batch);
- MEM_SAFE_FREE(cache->b_edlin.batch);
-
- /* internal format data */
- MEM_SAFE_FREE(cache->b_stroke.format);
- MEM_SAFE_FREE(cache->b_point.format);
- MEM_SAFE_FREE(cache->b_fill.format);
- MEM_SAFE_FREE(cache->b_edit.format);
- MEM_SAFE_FREE(cache->b_edlin.format);
-
- MEM_SAFE_FREE(cache->grp_cache);
- cache->grp_size = 0;
- cache->grp_used = 0;
-}
-
-/* get cache */
-GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra)
-{
- bGPdata *gpd = (bGPdata *)ob->data;
-
- GpencilBatchCache *cache = gpencil_batch_get_element(ob);
- if (!gpencil_batch_cache_valid(cache, gpd, cfra)) {
- if (cache) {
- gpencil_batch_cache_clear(cache);
- }
- return gpencil_batch_cache_init(ob, cfra);
- }
- else {
- return cache;
+ /* Geometry pass */
+ {
+ GPUTexture *depth_tex = (is_in_front) ? pd->dummy_tx : pd->scene_depth_tx;
+ GPUTexture **mask_tex = (is_masked) ? &pd->mask_tx : &pd->dummy_tx;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_BLEND_ALPHA_PREMUL;
+ /* For 2D mode, we render all strokes with uniform depth (increasing with stroke id). */
+ state |= tgp_ob->is_drawmode3d ? DRW_STATE_DEPTH_LESS_EQUAL : DRW_STATE_DEPTH_GREATER;
+ /* Always write stencil. Only used as optimization for blending. */
+ state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
+
+ tgp_layer->geom_ps = DRW_pass_create("GPencil Layer", state);
+
+ struct GPUShader *sh = GPENCIL_shader_geometry_get();
+ DRWShadingGroup *grp = tgp_layer->base_shgrp = DRW_shgroup_create(sh, tgp_layer->geom_ps);
+
+ DRW_shgroup_uniform_texture_persistent(grp, "gpSceneDepthTexture", depth_tex);
+ DRW_shgroup_uniform_texture_ref(grp, "gpMaskTexture", mask_tex);
+ DRW_shgroup_uniform_vec3_copy(grp, "gpNormal", tgp_ob->plane_normal);
+ DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", tgp_ob->is_drawmode3d);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessScale", tgp_ob->object_scale);
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get());
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get());
+ DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
+ DRW_shgroup_uniform_float_copy(grp, "vertexColorOpacity", vert_col_opacity);
+ DRW_shgroup_uniform_vec4_copy(grp, "layerTint", layer_tint);
+ DRW_shgroup_uniform_float_copy(grp, "layerOpacity", layer_alpha);
+ DRW_shgroup_stencil_mask(grp, 0xFF);
}
-}
-/* set cache as dirty */
-void DRW_gpencil_batch_cache_dirty_tag(bGPdata *gpd)
-{
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ return tgp_layer;
}
-/* free batch cache */
-void DRW_gpencil_batch_cache_free(bGPdata *UNUSED(gpd))
+GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number)
{
- return;
-}
-
-/* wrapper to clear cache */
-void DRW_gpencil_freecache(struct Object *ob)
-{
- if ((ob) && (ob->type == OB_GPENCIL)) {
- gpencil_batch_cache_clear(ob->runtime.gpencil_cache);
- MEM_SAFE_FREE(ob->runtime.gpencil_cache);
- bGPdata *gpd = (bGPdata *)ob->data;
- if (gpd) {
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
+ if (number >= 0) {
+ GPENCIL_tLayer *layer = tgp_ob->layers.first;
+ while (layer != NULL) {
+ if (layer->layer_id == number) {
+ return layer;
+ }
+ layer = layer->next;
}
}
-
- /* clear all frames evaluated data */
- for (int i = 0; i < ob->runtime.gpencil_tot_layers; i++) {
- bGPDframe *gpf_eval = &ob->runtime.gpencil_evaluated_frames[i];
- BKE_gpencil_free_frame_runtime_data(gpf_eval);
- }
-
- ob->runtime.gpencil_tot_layers = 0;
- MEM_SAFE_FREE(ob->runtime.gpencil_evaluated_frames);
+ return NULL;
}
+
+/** \} */
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
deleted file mode 100644
index a2016b9c1e6..00000000000
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ /dev/null
@@ -1,1021 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2008, Blender Foundation
- * This is a new part of Blender
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "BLI_polyfill_2d.h"
-#include "BLI_math_color.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_gpencil_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_view3d_types.h"
-
-#include "BKE_deform.h"
-#include "BKE_gpencil.h"
-
-#include "DRW_render.h"
-
-#include "ED_gpencil.h"
-#include "ED_view3d.h"
-
-#include "UI_resources.h"
-
-#include "gpencil_engine.h"
-
-/* Helper to add stroke point to vbo */
-static void gpencil_set_stroke_point(GPUVertBuf *vbo,
- const bGPDspoint *pt,
- int idx,
- uint pos_id,
- uint color_id,
- uint thickness_id,
- uint uvdata_id,
- short thickness,
- const float ink[4])
-{
-
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- float col[4];
- ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
-
- GPU_vertbuf_attr_set(vbo, color_id, idx, col);
-
- /* transfer both values using the same shader variable */
- float uvdata[2] = {pt->uv_fac, pt->uv_rot};
- GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
-
- /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */
- float thick = max_ff(pt->pressure * thickness, 1.0f);
- GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick);
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
-}
-
-/* Helper to add buffer_stroke point to vbo */
-static void gpencil_set_buffer_stroke_point(GPUVertBuf *vbo,
- const bGPDspoint *pt,
- int idx,
- uint pos_id,
- uint color_id,
- uint thickness_id,
- uint uvdata_id,
- uint prev_pos_id,
- const float ref_pt[3],
- short thickness,
- const float ink[4])
-{
-
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- float col[4];
- ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
-
- GPU_vertbuf_attr_set(vbo, color_id, idx, col);
-
- /* transfer both values using the same shader variable */
- float uvdata[2] = {pt->uv_fac, pt->uv_rot};
- GPU_vertbuf_attr_set(vbo, uvdata_id, idx, uvdata);
-
- /* the thickness of the stroke must be affected by zoom, so a pixel scale is calculated */
- float thick = max_ff(pt->pressure * thickness, 1.0f);
- GPU_vertbuf_attr_set(vbo, thickness_id, idx, &thick);
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
- /* reference point to follow drawing path */
- GPU_vertbuf_attr_set(vbo, prev_pos_id, idx, ref_pt);
-}
-
-/* Helper to add a new fill point and texture coordinates to vertex buffer */
-static void gpencil_set_fill_point(GPUVertBuf *vbo,
- int idx,
- bGPDspoint *pt,
- const float fcolor[4],
- const float uv[2],
- uint pos_id,
- uint color_id,
- uint text_id)
-{
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x);
- GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor);
- GPU_vertbuf_attr_set(vbo, text_id, idx, uv);
-}
-
-static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex)
-{
- if (be->vbo->vertex_alloc <= be->vbo_len + totvertex) {
- uint newsize = be->vbo->vertex_alloc +
- (((totvertex / GPENCIL_VBO_BLOCK_SIZE) + 1) * GPENCIL_VBO_BLOCK_SIZE);
- GPU_vertbuf_data_resize(be->vbo, newsize);
- }
-}
-
-static void gpencil_elem_format_ensure(GpencilBatchCacheElem *be)
-{
- if (be->format == NULL) {
- be->format = MEM_callocN(sizeof(GPUVertFormat), __func__);
- }
-}
-
-/* create batch geometry data for points stroke shader */
-void gpencil_get_point_geom(GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- short thickness,
- const float ink[4],
- const int alignment_mode)
-{
- int totvertex = gps->totpoints;
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->thickness_id = GPU_vertformat_attr_add(
- be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- be->uvdata_id = GPU_vertformat_attr_add(
- be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- be->prev_pos_id = GPU_vertformat_attr_add(
- be->format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, totvertex);
-
- /* draw stroke curve */
- const bGPDspoint *pt = gps->points;
- float alpha;
- float col[4];
-
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* set point */
- alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- ARRAY_SET_ITEMS(col, ink[0], ink[1], ink[2], alpha);
-
- float thick = max_ff(pt->pressure * thickness, 1.0f);
-
- GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, col);
- GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &thick);
-
- /* transfer both values using the same shader variable */
- float uvdata[2] = {pt->uv_fac, pt->uv_rot};
- GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata);
-
- GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
-
- /* use previous point to determine stroke direction */
- bGPDspoint *pt2 = NULL;
- float fpt[3];
- if (alignment_mode != GP_STYLE_FOLLOW_PATH) {
- /* add small offset to get a vector */
- copy_v3_v3(fpt, &pt->x);
- fpt[0] += 0.00001f;
- fpt[1] += 0.00001f;
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
- }
- else {
- if (i == 0) {
- if (gps->totpoints > 1) {
- /* extrapolate a point before first point */
- pt2 = &gps->points[1];
- interp_v3_v3v3(fpt, &pt2->x, &pt->x, 1.5f);
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
- }
- else {
- /* add small offset to get a vector */
- copy_v3_v3(fpt, &pt->x);
- fpt[0] += 0.00001f;
- fpt[1] += 0.00001f;
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, fpt);
- }
- }
- else {
- pt2 = &gps->points[i - 1];
- GPU_vertbuf_attr_set(be->vbo, be->prev_pos_id, be->vbo_len, &pt2->x);
- }
- }
- be->vbo_len++;
- }
-}
-
-/* create batch geometry data for stroke shader */
-void gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- short thickness,
- const float ink[4])
-{
- bGPDspoint *points = gps->points;
- int totpoints = gps->totpoints;
- /* if cyclic needs more vertex */
- int cyclic_add = (gps->flag & GP_STROKE_CYCLIC) ? 1 : 0;
- int totvertex = totpoints + cyclic_add + 2;
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->thickness_id = GPU_vertformat_attr_add(
- be->format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- be->uvdata_id = GPU_vertformat_attr_add(
- be->format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, totvertex);
-
- /* draw stroke curve */
- const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints; i++, pt++) {
- /* first point for adjacency (not drawn) */
- if (i == 0) {
- if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
- gpencil_set_stroke_point(be->vbo,
- &points[totpoints - 1],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
- else {
- gpencil_set_stroke_point(be->vbo,
- &points[1],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
- }
- /* set point */
- gpencil_set_stroke_point(be->vbo,
- pt,
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
-
- if (gps->flag & GP_STROKE_CYCLIC && totpoints > 2) {
- /* draw line to first point to complete the cycle */
- gpencil_set_stroke_point(be->vbo,
- &points[0],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- /* now add adjacency point (not drawn) */
- gpencil_set_stroke_point(be->vbo,
- &points[1],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
- /* last adjacency point (not drawn) */
- else {
- gpencil_set_stroke_point(be->vbo,
- &points[totpoints - 2],
- be->vbo_len,
- be->pos_id,
- be->color_id,
- be->thickness_id,
- be->uvdata_id,
- thickness,
- ink);
- be->vbo_len++;
- }
-}
-
-/* create batch geometry data for stroke shader */
-void gpencil_get_fill_geom(struct GpencilBatchCacheElem *be,
- Object *ob,
- bGPDstroke *gps,
- const float color[4])
-{
- BLI_assert(gps->totpoints >= 3);
-
- /* Calculate triangles cache for filling area (must be done only after changes) */
- if ((gps->flag & GP_STROKE_RECALC_GEOMETRY) || (gps->tot_triangles == 0) ||
- (gps->triangles == NULL)) {
- BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps);
- }
-
- BLI_assert(gps->tot_triangles >= 1);
- int totvertex = gps->tot_triangles * 3;
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->uvdata_id = GPU_vertformat_attr_add(
- be->format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, totvertex);
-
- /* Draw all triangles for filling the polygon (cache must be calculated before) */
- bGPDtriangle *stroke_triangle = gps->triangles;
- for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- gpencil_set_fill_point(be->vbo,
- be->vbo_len,
- &gps->points[stroke_triangle->verts[j]],
- color,
- stroke_triangle->uv[j],
- be->pos_id,
- be->color_id,
- be->uvdata_id);
- be->vbo_len++;
- }
- }
-}
-
-/* create batch geometry data for current buffer stroke shader */
-GPUBatch *gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ARegion *region = draw_ctx->region;
- RegionView3D *rv3d = draw_ctx->rv3d;
- ToolSettings *ts = scene->toolsettings;
- Object *ob = draw_ctx->obact;
-
- tGPspoint *points = gpd->runtime.sbuffer;
- int totpoints = gpd->runtime.sbuffer_used;
- /* if cyclic needs more vertex */
- int cyclic_add = (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC) ? 1 : 0;
- int totvertex = totpoints + cyclic_add + 2;
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id, thickness_id, uvdata_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, totvertex);
-
- /* draw stroke curve */
- const tGPspoint *tpt = points;
- bGPDspoint pt, pt2, pt3;
- int idx = 0;
-
- /* get origin to reproject point */
- float origin[3];
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
-
- for (int i = 0; i < totpoints; i++, tpt++) {
- ED_gpencil_tpoint_to_point(region, origin, tpt, &pt);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
-
- /* first point for adjacency (not drawn) */
- if (i == 0) {
- if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
- ED_gpencil_tpoint_to_point(region, origin, &points[totpoints - 1], &pt2);
- gpencil_set_stroke_point(vbo,
- &pt2,
- idx,
- pos_id,
- color_id,
- thickness_id,
- uvdata_id,
- thickness,
- gpd->runtime.scolor);
- idx++;
- }
- else {
- ED_gpencil_tpoint_to_point(region, origin, &points[1], &pt2);
- gpencil_set_stroke_point(vbo,
- &pt2,
- idx,
- pos_id,
- color_id,
- thickness_id,
- uvdata_id,
- thickness,
- gpd->runtime.scolor);
- idx++;
- }
- }
-
- /* set point */
- gpencil_set_stroke_point(
- vbo, &pt, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- }
-
- /* last adjacency point (not drawn) */
- if (gpd->runtime.sbuffer_sflag & GP_STROKE_CYCLIC && totpoints > 2) {
- /* draw line to first point to complete the cycle */
- ED_gpencil_tpoint_to_point(region, origin, &points[0], &pt2);
- gpencil_set_stroke_point(
- vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- /* now add adjacency point (not drawn) */
- ED_gpencil_tpoint_to_point(region, origin, &points[1], &pt3);
- gpencil_set_stroke_point(
- vbo, &pt3, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- }
- /* last adjacency point (not drawn) */
- else {
- ED_gpencil_tpoint_to_point(region, origin, &points[totpoints - 2], &pt2);
- gpencil_set_stroke_point(
- vbo, &pt2, idx, pos_id, color_id, thickness_id, uvdata_id, thickness, gpd->runtime.scolor);
- idx++;
- }
-
- return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* create batch geometry data for current buffer point shader */
-GPUBatch *gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ARegion *region = draw_ctx->region;
- RegionView3D *rv3d = draw_ctx->rv3d;
- ToolSettings *ts = scene->toolsettings;
- Object *ob = draw_ctx->obact;
-
- tGPspoint *points = gpd->runtime.sbuffer;
- int totpoints = gpd->runtime.sbuffer_used;
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id, thickness_id, uvdata_id, prev_pos_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- thickness_id = GPU_vertformat_attr_add(&format, "thickness", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uvdata_id = GPU_vertformat_attr_add(&format, "uvdata", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- prev_pos_id = GPU_vertformat_attr_add(&format, "prev_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, totpoints);
-
- /* draw stroke curve */
- const tGPspoint *tpt = points;
- bGPDspoint pt;
- int idx = 0;
-
- /* get origin to reproject point */
- float origin[3];
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
-
- for (int i = 0; i < totpoints; i++, tpt++) {
- ED_gpencil_tpoint_to_point(region, origin, tpt, &pt);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt);
-
- /* use previous point to determine stroke direction (drawing path) */
- bGPDspoint pt2;
- float ref_pt[3];
-
- if (i == 0) {
- if (totpoints > 1) {
- /* extrapolate a point before first point */
- tGPspoint *tpt2 = &points[1];
- ED_gpencil_tpoint_to_point(region, origin, tpt2, &pt2);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
-
- interp_v3_v3v3(ref_pt, &pt2.x, &pt.x, 1.5f);
- }
- else {
- copy_v3_v3(ref_pt, &pt.x);
- }
- }
- else {
- tGPspoint *tpt2 = &points[i - 1];
- ED_gpencil_tpoint_to_point(region, origin, tpt2, &pt2);
- ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt2);
-
- copy_v3_v3(ref_pt, &pt2.x);
- }
-
- /* set point */
- gpencil_set_buffer_stroke_point(vbo,
- &pt,
- idx,
- pos_id,
- color_id,
- thickness_id,
- uvdata_id,
- prev_pos_id,
- ref_pt,
- thickness,
- gpd->runtime.scolor);
- idx++;
- }
-
- return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* create batch geometry data for current buffer control point shader */
-GPUBatch *gpencil_get_buffer_ctrlpoint_geom(bGPdata *gpd)
-{
- bGPDcontrolpoint *cps = gpd->runtime.cp_points;
- int totpoints = gpd->runtime.tot_cp_points;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
-
- if (ts->gp_sculpt.guide.use_guide) {
- totpoints++;
- }
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id, size_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, totpoints);
-
- int idx = 0;
- for (int i = 0; i < gpd->runtime.tot_cp_points; i++) {
- bGPDcontrolpoint *cp = &cps[i];
-
- GPU_vertbuf_attr_set(vbo, color_id, idx, cp->color);
-
- /* scale size */
- float size = cp->size * 0.8f;
- GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &cp->x);
- idx++;
- }
-
- if (ts->gp_sculpt.guide.use_guide) {
- float size = 10 * 0.8f;
- float color[4];
- float position[3];
- if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) {
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- copy_v3_v3(position, ts->gp_sculpt.guide.location);
- }
- else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT &&
- ts->gp_sculpt.guide.reference_object != NULL) {
- UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
- copy_v3_v3(position, ts->gp_sculpt.guide.reference_object->loc);
- }
- else {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- copy_v3_v3(position, scene->cursor.location);
- }
- GPU_vertbuf_attr_set(vbo, pos_id, idx, position);
- GPU_vertbuf_attr_set(vbo, size_id, idx, &size);
- GPU_vertbuf_attr_set(vbo, color_id, idx, color);
- }
-
- return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* create batch geometry data for current buffer fill shader */
-GPUBatch *gpencil_get_buffer_fill_geom(bGPdata *gpd)
-{
- if (gpd == NULL) {
- return NULL;
- }
-
- const tGPspoint *points = gpd->runtime.sbuffer;
- int totpoints = gpd->runtime.sbuffer_used;
- if (totpoints < 3) {
- return NULL;
- }
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ARegion *region = draw_ctx->region;
- ToolSettings *ts = scene->toolsettings;
- Object *ob = draw_ctx->obact;
-
- /* get origin to reproject point */
- float origin[3];
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
- ED_gp_get_drawing_reference(scene, ob, gpl, ts->gpencil_v3d_align, origin);
-
- int tot_triangles = totpoints - 2;
- /* allocate memory for temporary areas */
- uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * tot_triangles, __func__);
- float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * totpoints, __func__);
-
- /* Convert points to array and triangulate
- * Here a cache is not used because while drawing the information changes all the time, so the
- * cache would be recalculated constantly, so it is better to do direct calculation for each
- * function call
- */
- for (int i = 0; i < totpoints; i++) {
- const tGPspoint *pt = &points[i];
- points2d[i][0] = pt->x;
- points2d[i][1] = pt->y;
- }
- BLI_polyfill_calc(points2d, (uint)totpoints, 0, tmp_triangles);
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
-
- /* draw triangulation data */
- if (tot_triangles > 0) {
- GPU_vertbuf_data_alloc(vbo, tot_triangles * 3);
-
- const tGPspoint *tpt;
- bGPDspoint pt;
-
- int idx = 0;
- for (int i = 0; i < tot_triangles; i++) {
- for (int j = 0; j < 3; j++) {
- tpt = &points[tmp_triangles[i][j]];
- ED_gpencil_tpoint_to_point(region, origin, tpt, &pt);
- GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt.x);
- GPU_vertbuf_attr_set(vbo, color_id, idx, gpd->runtime.sfill);
- idx++;
- }
- }
- }
-
- /* clear memory */
- if (tmp_triangles) {
- MEM_freeN(tmp_triangles);
- }
- if (points2d) {
- MEM_freeN(points2d);
- }
-
- return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
-
-/* Draw selected verts for strokes being edited */
-void gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- float alpha,
- short dflag)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Object *ob = draw_ctx->obact;
- bGPdata *gpd = ob->data;
- const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- int vgindex = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, vgindex)) {
- vgindex = -1;
- }
-
- /* Get size of verts:
- * - The selected state needs to be larger than the unselected state so that
- * they stand out more.
- * - We use the theme setting for size of the unselected verts
- */
- float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
- float vsize;
- if ((int)bsize > 8) {
- vsize = 10.0f;
- bsize = 8.0f;
- }
- else {
- vsize = bsize + 2;
- }
-
- /* for now, we assume that the base color of the points is not too close to the real color */
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
-
- float unselectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor);
- unselectColor[3] = alpha;
-
- float linecolor[4];
- copy_v4_v4(linecolor, gpd->line_color);
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- be->thickness_id = GPU_vertformat_attr_add(
- be->format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, gps->totpoints);
-
- /* Draw start and end point differently if enabled stroke direction hint */
- bool show_direction_hint = (dflag & GP_DATA_SHOW_DIRECTION) && (gps->totpoints > 1);
-
- /* Draw all the stroke points (selected or not) */
- bGPDspoint *pt = gps->points;
- MDeformVert *dvert = gps->dvert;
-
- float fcolor[4];
- float fsize = 0;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* weight paint */
- if (is_weight_paint) {
- float weight = (dvert && dvert->dw && (vgindex > -1)) ?
- BKE_defvert_find_weight(dvert, vgindex) :
- 0.0f;
- float hue = 2.0f * (1.0f - weight) / 3.0f;
- hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
- selectColor[3] = 1.0f;
- copy_v4_v4(fcolor, selectColor);
- fsize = vsize;
- }
- else {
- if (show_direction_hint && i == 0) {
- /* start point in green bigger */
- ARRAY_SET_ITEMS(fcolor, 0.0f, 1.0f, 0.0f, 1.0f);
- fsize = vsize + 4;
- }
- else if (show_direction_hint && (i == gps->totpoints - 1)) {
- /* end point in red smaller */
- ARRAY_SET_ITEMS(fcolor, 1.0f, 0.0f, 0.0f, 1.0f);
- fsize = vsize + 1;
- }
- else if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
- ARRAY_SET_ITEMS(fcolor, linecolor[0], linecolor[1], linecolor[2], selectColor[3]);
- mul_v4_fl(fcolor, 0.9f);
- copy_v4_v4(fcolor, fcolor);
- fsize = vsize * 0.8f;
- }
- else if (pt->flag & GP_SPOINT_SELECT) {
- copy_v4_v4(fcolor, selectColor);
- fsize = vsize;
- }
- else {
- copy_v4_v4(fcolor, unselectColor);
- fsize = bsize;
- }
- }
-
- GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
- GPU_vertbuf_attr_set(be->vbo, be->thickness_id, be->vbo_len, &fsize);
- GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
- be->vbo_len++;
- if (gps->dvert != NULL) {
- dvert++;
- }
- }
-}
-
-/* Draw lines for strokes being edited */
-void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
- bGPDstroke *gps,
- float alpha,
- const bool hide_select)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Object *ob = draw_ctx->obact;
- bGPdata *gpd = ob->data;
- const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
-
- int vgindex = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, vgindex)) {
- vgindex = -1;
- }
-
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
- float linecolor[4];
- copy_v4_v4(linecolor, gpd->line_color);
-
- if (be->vbo == NULL) {
- gpencil_elem_format_ensure(be);
- be->pos_id = GPU_vertformat_attr_add(be->format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- be->color_id = GPU_vertformat_attr_add(be->format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
- be->vbo = GPU_vertbuf_create_with_format(be->format);
- GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex);
- be->vbo_len = 0;
- }
- gpencil_vbo_ensure_size(be, gps->totpoints);
-
- /* Draw all the stroke lines (selected or not) */
- bGPDspoint *pt = gps->points;
- MDeformVert *dvert = gps->dvert;
-
- float fcolor[4];
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* weight paint */
- if (is_weight_paint) {
- float weight = (dvert && dvert->dw && (vgindex > -1)) ?
- BKE_defvert_find_weight(dvert, vgindex) :
- 0.0f;
- float hue = 2.0f * (1.0f - weight) / 3.0f;
- hsv_to_rgb(hue, 1.0f, 1.0f, &selectColor[0], &selectColor[1], &selectColor[2]);
- selectColor[3] = 1.0f;
- copy_v4_v4(fcolor, selectColor);
- }
- else {
- if ((pt->flag & GP_SPOINT_SELECT) && (!hide_select)) {
- copy_v4_v4(fcolor, selectColor);
- }
- else {
- copy_v4_v4(fcolor, linecolor);
- }
- }
-
- GPU_vertbuf_attr_set(be->vbo, be->color_id, be->vbo_len, fcolor);
- GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x);
- be->vbo_len++;
-
- if (gps->dvert != NULL) {
- dvert++;
- }
- }
-}
-
-static void set_grid_point(GPUVertBuf *vbo,
- int idx,
- const float col_grid[4],
- uint pos_id,
- uint color_id,
- float v1,
- float v2,
- const int axis)
-{
- GPU_vertbuf_attr_set(vbo, color_id, idx, col_grid);
-
- float pos[3];
- /* Set the grid in the selected axis */
- switch (axis) {
- case GP_LOCKAXIS_X: {
- ARRAY_SET_ITEMS(pos, 0.0f, v1, v2);
- break;
- }
- case GP_LOCKAXIS_Y: {
- ARRAY_SET_ITEMS(pos, v1, 0.0f, v2);
- break;
- }
- case GP_LOCKAXIS_Z:
- default: /* view aligned */
- {
- ARRAY_SET_ITEMS(pos, v1, v2, 0.0f);
- break;
- }
- }
-
- GPU_vertbuf_attr_set(vbo, pos_id, idx, pos);
-}
-
-/* Draw grid lines */
-GPUBatch *gpencil_get_grid(Object *ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
- View3D *v3d = draw_ctx->v3d;
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool do_center = (gpd->grid.lines <= 0) ? false : true;
-
- float col_grid[4];
-
- /* verify we have something to draw and valid values */
- if (gpd->grid.scale[0] == 0.0f) {
- gpd->grid.scale[0] = 1.0f;
- }
- if (gpd->grid.scale[1] == 0.0f) {
- gpd->grid.scale[1] = 1.0f;
- }
-
- if (v3d->overlay.gpencil_grid_opacity < 0.1f) {
- v3d->overlay.gpencil_grid_opacity = 0.1f;
- }
-
- /* set color */
- copy_v3_v3(col_grid, gpd->grid.color);
- col_grid[3] = v3d->overlay.gpencil_grid_opacity;
-
- const int axis = ts->gp_sculpt.lock_axis;
-
- const char *grid_unit = NULL;
- const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
- const float grid_w = gpd->grid.scale[0] * ED_scene_grid_scale(scene, &grid_unit);
- const float grid_h = gpd->grid.scale[1] * ED_scene_grid_scale(scene, &grid_unit);
- const float space_w = (grid_w / gridlines);
- const float space_h = (grid_h / gridlines);
- const float offset[2] = {gpd->grid.offset[0], gpd->grid.offset[1]};
-
- const uint vertex_len = 2 * (gridlines * 4 + 2);
-
- static GPUVertFormat format = {0};
- static uint pos_id, color_id;
- if (format.attr_len == 0) {
- pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
- }
-
- GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
- GPU_vertbuf_data_alloc(vbo, vertex_len);
-
- int idx = 0;
-
- for (int a = 1; a <= gridlines; a++) {
- const float line_w = a * space_w;
- const float line_h = a * space_h;
-
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], -line_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], -line_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], +line_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], +line_h + offset[1], axis);
- idx++;
-
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], -grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -line_w + offset[0], +grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], -grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +line_w + offset[0], +grid_h + offset[1], axis);
- idx++;
- }
- /* center lines */
- if (do_center) {
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, -grid_w + offset[0], 0.0f + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, +grid_w + offset[0], 0.0f + offset[1], axis);
- idx++;
-
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], -grid_h + offset[1], axis);
- idx++;
- set_grid_point(
- vbo, idx, col_grid, pos_id, color_id, 0.0f + offset[0], +grid_h + offset[1], axis);
- idx++;
- }
- return GPU_batch_create_ex(GPU_PRIM_LINES, vbo, NULL, GPU_BATCH_OWNS_VBO);
-}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
new file mode 100644
index 00000000000..77baadfc83a
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c
@@ -0,0 +1,502 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_light_types.h"
+
+#include "BKE_image.h"
+
+#include "BLI_hash.h"
+#include "BLI_math_color.h"
+#include "BLI_memblock.h"
+
+#include "GPU_uniformbuffer.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "gpencil_engine.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Material
+ * \{ */
+
+static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_PrivateData *pd)
+{
+ GPENCIL_MaterialPool *matpool = BLI_memblock_alloc(pd->gp_material_pool);
+ matpool->next = NULL;
+ matpool->used_count = 0;
+ if (matpool->ubo == NULL) {
+ matpool->ubo = GPU_uniformbuffer_create(sizeof(matpool->mat_data), NULL, NULL);
+ }
+ pd->last_material_pool = matpool;
+ return matpool;
+}
+
+static struct GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_premult)
+{
+ ImBuf *ibuf;
+ ImageUser iuser = {NULL};
+ struct GPUTexture *gpu_tex = NULL;
+ void *lock;
+
+ iuser.ok = true;
+ ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
+
+ if (ibuf != NULL && ibuf->rect != NULL) {
+ gpu_tex = GPU_texture_from_blender(image, &iuser, ibuf, GL_TEXTURE_2D);
+ *r_alpha_premult = (image->alpha_mode == IMA_ALPHA_PREMUL);
+ }
+ BKE_image_release_ibuf(image, ibuf, lock);
+
+ return gpu_tex;
+}
+
+static void gpencil_uv_transform_get(const float ofs[2],
+ const float scale[2],
+ const float rotation,
+ float r_uvmat[3][2])
+{
+ /* OPTI this could use 3x2 matrices and reduce the number of operations drastically. */
+ float mat[4][4];
+ unit_m4(mat);
+ /* Offset to center. */
+ translate_m4(mat, 0.5f, 0.5f, 0.0f);
+ /* Reversed order. */
+ rescale_m4(mat, (float[3]){1.0f / scale[0], 1.0f / scale[1], 0.0});
+ rotate_m4(mat, 'Z', -rotation);
+ translate_m4(mat, ofs[0], ofs[1], 0.0f);
+ /* Convert to 3x2 */
+ copy_v2_v2(r_uvmat[0], mat[0]);
+ copy_v2_v2(r_uvmat[1], mat[1]);
+ copy_v2_v2(r_uvmat[2], mat[3]);
+}
+
+#define HSV_SATURATION 0.5
+#define HSV_VALUE 0.8
+
+static void gpencil_object_random_color_get(const Object *ob, float r_color[3])
+{
+ /* Duplicated from workbench_material.c */
+ uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
+ if (ob->id.lib) {
+ hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name);
+ }
+ float hue = BLI_hash_int_01(hash);
+ float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE};
+ hsv_to_rgb_v(hsv, r_color);
+}
+
+static void gpencil_shade_color(float color[3])
+{
+ /* This is scene refered color, not gamma corrected and not per perceptual.
+ * So we lower the threshold a bit. (1.0 / 3.0) */
+ if (color[0] + color[1] + color[2] > 1.1) {
+ add_v3_fl(color, -0.25f);
+ }
+ else {
+ add_v3_fl(color, 0.15f);
+ }
+ CLAMP3(color, 0.0f, 1.0f);
+}
+
+/* Apply all overrides from the solid viewport mode to the GPencil material. */
+static MaterialGPencilStyle *gpencil_viewport_material_overrides(GPENCIL_PrivateData *pd,
+ Object *ob,
+ int color_type,
+ MaterialGPencilStyle *gp_style)
+{
+ static MaterialGPencilStyle gp_style_tmp;
+
+ switch (color_type) {
+ case V3D_SHADING_MATERIAL_COLOR:
+ copy_v4_v4(gp_style_tmp.stroke_rgba, gp_style->stroke_rgba);
+ copy_v4_v4(gp_style_tmp.fill_rgba, gp_style->fill_rgba);
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ break;
+ case V3D_SHADING_TEXTURE_COLOR:
+ memcpy(&gp_style_tmp, gp_style, sizeof(*gp_style));
+ gp_style = &gp_style_tmp;
+ if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) {
+ copy_v4_fl(gp_style->stroke_rgba, 1.0f);
+ gp_style->mix_stroke_factor = 0.0f;
+ }
+
+ if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) {
+ copy_v4_fl(gp_style->fill_rgba, 1.0f);
+ gp_style->mix_factor = 0.0f;
+ }
+ else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) {
+ /* gp_style->fill_rgba is needed for correct gradient. */
+ gp_style->mix_factor = 0.0f;
+ }
+ break;
+ case V3D_SHADING_RANDOM_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ gpencil_object_random_color_get(ob, gp_style->fill_rgba);
+ gp_style->fill_rgba[3] = 1.0f;
+ copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba);
+ gpencil_shade_color(gp_style->stroke_rgba);
+ break;
+ case V3D_SHADING_SINGLE_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ copy_v3_v3(gp_style->fill_rgba, pd->v3d_single_color);
+ gp_style->fill_rgba[3] = 1.0f;
+ copy_v4_v4(gp_style->stroke_rgba, gp_style->fill_rgba);
+ gpencil_shade_color(gp_style->stroke_rgba);
+ break;
+ case V3D_SHADING_OBJECT_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ copy_v4_v4(gp_style->fill_rgba, ob->color);
+ copy_v4_v4(gp_style->stroke_rgba, ob->color);
+ gpencil_shade_color(gp_style->stroke_rgba);
+ break;
+ case V3D_SHADING_VERTEX_COLOR:
+ gp_style = &gp_style_tmp;
+ gp_style->stroke_style = GP_MATERIAL_STROKE_STYLE_SOLID;
+ gp_style->fill_style = GP_MATERIAL_FILL_STYLE_SOLID;
+ copy_v4_fl(gp_style->fill_rgba, 1.0f);
+ copy_v4_fl(gp_style->stroke_rgba, 1.0f);
+ break;
+ default:
+ break;
+ }
+ return gp_style;
+}
+
+/**
+ * Creates a linked list of material pool containing all materials assigned for a given object.
+ * We merge the material pools together if object does not contain a huge amount of materials.
+ * Also return an offset to the first material of the object in the ubo.
+ **/
+GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs)
+{
+ GPENCIL_MaterialPool *matpool = pd->last_material_pool;
+
+ int mat_len = max_ii(1, ob->totcol);
+
+ bool reuse_matpool = matpool && ((matpool->used_count + mat_len) <= GP_MATERIAL_BUFFER_LEN);
+
+ if (reuse_matpool) {
+ /* Share the matpool with other objects. Return offset to first material. */
+ *ofs = matpool->used_count;
+ }
+ else {
+ matpool = gpencil_material_pool_add(pd);
+ *ofs = 0;
+ }
+
+ /* Force vertex color in solid mode with vertex paint mode. Same behavior as meshes. */
+ bGPdata *gpd = (bGPdata *)ob->data;
+ int color_type = (pd->v3d_color_type != -1 && GPENCIL_VERTEX_MODE(gpd)) ?
+ V3D_SHADING_VERTEX_COLOR :
+ pd->v3d_color_type;
+
+ GPENCIL_MaterialPool *pool = matpool;
+ for (int i = 0; i < mat_len; i++) {
+ if ((i > 0) && (pool->used_count == GP_MATERIAL_BUFFER_LEN)) {
+ pool->next = gpencil_material_pool_add(pd);
+ pool = pool->next;
+ }
+ int mat_id = pool->used_count++;
+
+ gpMaterial *mat_data = &pool->mat_data[mat_id];
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, i + 1);
+
+ if (gp_style->mode == GP_MATERIAL_MODE_LINE) {
+ mat_data->flag = 0;
+ }
+ else {
+ switch (gp_style->alignment_mode) {
+ case GP_MATERIAL_FOLLOW_PATH:
+ mat_data->flag = GP_STROKE_ALIGNMENT_STROKE;
+ break;
+ case GP_MATERIAL_FOLLOW_OBJ:
+ mat_data->flag = GP_STROKE_ALIGNMENT_OBJECT;
+ break;
+ case GP_MATERIAL_FOLLOW_FIXED:
+ default:
+ mat_data->flag = GP_STROKE_ALIGNMENT_FIXED;
+ break;
+ }
+
+ if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
+ mat_data->flag |= GP_STROKE_DOTS;
+ }
+ }
+
+ if ((gp_style->mode != GP_MATERIAL_MODE_LINE) ||
+ (gp_style->flag & GP_MATERIAL_DISABLE_STENCIL)) {
+ mat_data->flag |= GP_STROKE_OVERLAP;
+ }
+
+ gp_style = gpencil_viewport_material_overrides(pd, ob, color_type, gp_style);
+
+ /* Stroke Style */
+ if ((gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE) && (gp_style->sima)) {
+ bool premul;
+ pool->tex_stroke[mat_id] = gpencil_image_texture_get(gp_style->sima, &premul);
+ mat_data->flag |= pool->tex_stroke[mat_id] ? GP_STROKE_TEXTURE_USE : 0;
+ mat_data->flag |= premul ? GP_STROKE_TEXTURE_PREMUL : 0;
+ copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba);
+ mat_data->stroke_texture_mix = 1.0f - gp_style->mix_stroke_factor;
+ mat_data->stroke_u_scale = 500.0f / gp_style->texture_pixsize;
+ }
+ else /* if (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_SOLID) */ {
+ pool->tex_stroke[mat_id] = NULL;
+ mat_data->flag &= ~GP_STROKE_TEXTURE_USE;
+ copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba);
+ mat_data->stroke_texture_mix = 0.0f;
+ }
+
+ /* Fill Style */
+ if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_TEXTURE) && (gp_style->ima)) {
+ bool use_clip = (gp_style->flag & GP_MATERIAL_TEX_CLAMP) != 0;
+ bool premul;
+ pool->tex_fill[mat_id] = gpencil_image_texture_get(gp_style->ima, &premul);
+ mat_data->flag |= pool->tex_fill[mat_id] ? GP_FILL_TEXTURE_USE : 0;
+ mat_data->flag |= premul ? GP_FILL_TEXTURE_PREMUL : 0;
+ mat_data->flag |= use_clip ? GP_FILL_TEXTURE_CLIP : 0;
+ gpencil_uv_transform_get(gp_style->texture_offset,
+ gp_style->texture_scale,
+ gp_style->texture_angle,
+ mat_data->fill_uv_transform);
+ copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
+ mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
+ }
+ else if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_GRADIENT) {
+ bool use_radial = (gp_style->gradient_type == GP_MATERIAL_GRADIENT_RADIAL);
+ pool->tex_fill[mat_id] = NULL;
+ mat_data->flag |= GP_FILL_GRADIENT_USE;
+ mat_data->flag |= use_radial ? GP_FILL_GRADIENT_RADIAL : 0;
+ gpencil_uv_transform_get(gp_style->texture_offset,
+ gp_style->texture_scale,
+ gp_style->texture_angle,
+ mat_data->fill_uv_transform);
+ copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
+ copy_v4_v4(mat_data->fill_mix_color, gp_style->mix_rgba);
+ mat_data->fill_texture_mix = 1.0f - gp_style->mix_factor;
+ if (gp_style->flag & GP_MATERIAL_FLIP_FILL) {
+ swap_v4_v4(mat_data->fill_color, mat_data->fill_mix_color);
+ }
+ }
+ else /* if (gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) */ {
+ pool->tex_fill[mat_id] = NULL;
+ copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
+ mat_data->fill_texture_mix = 0.0f;
+ }
+ }
+
+ return matpool;
+}
+
+void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
+ int mat_id,
+ GPUTexture **r_tex_stroke,
+ GPUTexture **r_tex_fill,
+ GPUUniformBuffer **r_ubo_mat)
+{
+ GPENCIL_MaterialPool *matpool = first_pool;
+ int pool_id = mat_id / GP_MATERIAL_BUFFER_LEN;
+ for (int i = 0; i < pool_id; i++) {
+ matpool = matpool->next;
+ }
+ mat_id = mat_id % GP_MATERIAL_BUFFER_LEN;
+ *r_ubo_mat = matpool->ubo;
+ if (r_tex_fill) {
+ *r_tex_fill = matpool->tex_fill[mat_id];
+ }
+ if (r_tex_stroke) {
+ *r_tex_stroke = matpool->tex_stroke[mat_id];
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lights
+ * \{ */
+
+GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd)
+{
+ GPENCIL_LightPool *lightpool = BLI_memblock_alloc(pd->gp_light_pool);
+ lightpool->light_used = 0;
+ /* Tag light list end. */
+ lightpool->light_data[0].color[0] = -1.0;
+ if (lightpool->ubo == NULL) {
+ lightpool->ubo = GPU_uniformbuffer_create(sizeof(lightpool->light_data), NULL, NULL);
+ }
+ pd->last_light_pool = lightpool;
+ return lightpool;
+}
+
+void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3])
+{
+ if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) {
+ return;
+ }
+
+ gpLight *gp_light = &lightpool->light_data[lightpool->light_used];
+ gp_light->type = GP_LIGHT_TYPE_AMBIENT;
+ copy_v3_v3(gp_light->color, color);
+ lightpool->light_used++;
+
+ if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) {
+ /* Tag light list end. */
+ gp_light[1].color[0] = -1.0f;
+ }
+}
+
+static float light_power_get(const Light *la)
+{
+ if (la->type == LA_AREA) {
+ return 1.0f / (4.0f * M_PI);
+ }
+ else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
+ return 1.0f / (4.0f * M_PI * M_PI);
+ }
+ else {
+ return 1.0f / M_PI;
+ }
+}
+
+void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob)
+{
+ Light *la = (Light *)ob->data;
+
+ if (lightpool->light_used >= GPENCIL_LIGHT_BUFFER_LEN) {
+ return;
+ }
+
+ gpLight *gp_light = &lightpool->light_data[lightpool->light_used];
+ float(*mat)[4] = (float(*)[4])gp_light->right;
+
+ if (la->type == LA_SPOT) {
+ copy_m4_m4(mat, ob->imat);
+ gp_light->type = GP_LIGHT_TYPE_SPOT;
+ gp_light->spotsize = cosf(la->spotsize * 0.5f);
+ gp_light->spotblend = (1.0f - gp_light->spotsize) * la->spotblend;
+ }
+ else if (la->type == LA_AREA) {
+ /* Simulate area lights using a spot light. */
+ normalize_m4_m4(mat, ob->obmat);
+ invert_m4(mat);
+ gp_light->type = GP_LIGHT_TYPE_SPOT;
+ gp_light->spotsize = cosf(M_PI * 0.5f);
+ gp_light->spotblend = (1.0f - gp_light->spotsize) * 1.0f;
+ }
+ else if (la->type == LA_SUN) {
+ normalize_v3_v3(gp_light->forward, ob->obmat[2]);
+ gp_light->type = GP_LIGHT_TYPE_SUN;
+ }
+ else {
+ gp_light->type = GP_LIGHT_TYPE_POINT;
+ }
+ copy_v4_v4(gp_light->position, ob->obmat[3]);
+ copy_v3_v3(gp_light->color, &la->r);
+ mul_v3_fl(gp_light->color, la->energy * light_power_get(la));
+
+ lightpool->light_used++;
+
+ if (lightpool->light_used < GPENCIL_LIGHT_BUFFER_LEN) {
+ /* Tag light list end. */
+ gp_light[1].color[0] = -1.0f;
+ }
+}
+
+/**
+ * Creates a single pool containing all lights assigned (light linked) for a given object.
+ **/
+GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *UNUSED(ob))
+{
+ GPENCIL_LightPool *lightpool = pd->last_light_pool;
+
+ if (lightpool == NULL) {
+ lightpool = gpencil_light_pool_add(pd);
+ }
+ /* TODO(fclem) Light linking. */
+ // gpencil_light_pool_populate(lightpool, ob);
+
+ return lightpool;
+}
+
+void gpencil_material_pool_free(void *storage)
+{
+ GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage;
+ DRW_UBO_FREE_SAFE(matpool->ubo);
+}
+
+void gpencil_light_pool_free(void *storage)
+{
+ GPENCIL_LightPool *lightpool = (GPENCIL_LightPool *)storage;
+ DRW_UBO_FREE_SAFE(lightpool->ubo);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Layer Data
+ * \{ */
+
+static void gpencil_view_layer_data_free(void *storage)
+{
+ GPENCIL_ViewLayerData *vldata = (GPENCIL_ViewLayerData *)storage;
+
+ BLI_memblock_destroy(vldata->gp_light_pool, gpencil_light_pool_free);
+ BLI_memblock_destroy(vldata->gp_material_pool, gpencil_material_pool_free);
+ BLI_memblock_destroy(vldata->gp_maskbit_pool, NULL);
+ BLI_memblock_destroy(vldata->gp_object_pool, NULL);
+ BLI_memblock_destroy(vldata->gp_layer_pool, NULL);
+ BLI_memblock_destroy(vldata->gp_vfx_pool, NULL);
+}
+
+GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void)
+{
+ GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure(
+ &draw_engine_gpencil_type, gpencil_view_layer_data_free);
+
+ /* NOTE(fclem) Putting this stuff in viewlayer means it is shared by all viewports.
+ * For now it is ok, but in the future, it could become a problem if we implement
+ * the caching system. */
+ if (*vldata == NULL) {
+ *vldata = MEM_callocN(sizeof(**vldata), "GPENCIL_ViewLayerData");
+
+ (*vldata)->gp_light_pool = BLI_memblock_create(sizeof(GPENCIL_LightPool));
+ (*vldata)->gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool));
+ (*vldata)->gp_maskbit_pool = BLI_memblock_create(BLI_BITMAP_SIZE(GP_MAX_MASKBITS));
+ (*vldata)->gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject));
+ (*vldata)->gp_layer_pool = BLI_memblock_create(sizeof(GPENCIL_tLayer));
+ (*vldata)->gp_vfx_pool = BLI_memblock_create(sizeof(GPENCIL_tVfx));
+ }
+
+ return *vldata;
+}
+
+/** \} */
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
deleted file mode 100644
index d44aa5764b1..00000000000
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ /dev/null
@@ -1,2071 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Copyright 2017, Blender Foundation.
- */
-
-/** \file
- * \ingroup draw
- */
-
-#include "DRW_render.h"
-
-#include "BKE_gpencil.h"
-#include "BKE_gpencil_modifier.h"
-#include "BKE_image.h"
-#include "BKE_material.h"
-#include "BKE_paint.h"
-
-#include "BLI_hash.h"
-
-#include "ED_gpencil.h"
-
-#include "DNA_gpencil_types.h"
-#include "DNA_material_types.h"
-#include "DNA_view3d_types.h"
-
-/* If builtin shaders are needed */
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-
-/* For EvaluationContext... */
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
-
-#include "IMB_imbuf_types.h"
-
-#include "gpencil_engine.h"
-
-#include "UI_resources.h"
-
-/* fill type to communicate to shader */
-#define SOLID 0
-#define GRADIENT 1
-#define RADIAL 2
-#define CHECKER 3
-#define TEXTURE 4
-#define PATTERN 5
-
-/* Verify if must fade object or not. */
-static bool gpencil_fade_object_check(GPENCIL_StorageList *stl, Object *ob)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- const bool is_overlay = (bool)((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
- (v3d->gp_flag & V3D_GP_SHOW_PAPER));
-
- if ((!is_overlay) || (ob == draw_ctx->obact) ||
- ((v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL) == 0) ||
- (v3d->overlay.gpencil_paper_opacity == 1.0f)) {
- return false;
- }
-
- const bool playing = stl->storage->is_playing;
- const bool is_render = (bool)stl->storage->is_render;
- const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
-
- return (bool)((!is_render) && (!playing) && (!is_mat_preview) && (!is_select));
-}
-
-/* Define Fade layer uniforms. */
-static void gpencil_set_fade_layer_uniforms(
- GPENCIL_StorageList *stl, DRWShadingGroup *grp, Object *ob, bGPDlayer *gpl, const bool skip)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
- const bool is_fade = (v3d) && (v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS) &&
- (draw_ctx->obact) && (draw_ctx->obact == ob) &&
- ((gpl->flag & GP_LAYER_ACTIVE) == 0);
-
- const bool playing = stl->storage->is_playing;
- const bool is_render = (bool)stl->storage->is_render;
- const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool is_select = (bool)(DRW_state_is_select() || DRW_state_is_depth());
-
- /* If drawing or not fading layer, skip. */
- if ((!overlay) || (skip) || (!is_fade) || (is_render) || (playing) || (is_mat_preview) ||
- (is_select)) {
- DRW_shgroup_uniform_int_copy(grp, "fade_layer", 0);
- return;
- }
-
- /* If layer is above active, use alpha (2) if below use mix with background (1). */
- if (stl->storage->is_ontop) {
- DRW_shgroup_uniform_int_copy(grp, "fade_layer", 2);
- }
- else {
- DRW_shgroup_uniform_int_copy(grp, "fade_layer", 1);
- }
- if (v3d) {
- DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
- DRW_shgroup_uniform_float(grp, "fade_layer_factor", &v3d->overlay.gpencil_fade_layer, 1);
- }
-}
-
-/* Define Fade object uniforms. */
-static void gpencil_set_fade_ob_uniforms(View3D *v3d, DRWShadingGroup *grp, bool status)
-{
- DRW_shgroup_uniform_bool_copy(grp, "fade_ob", status);
- if (v3d) {
- DRW_shgroup_uniform_vec3(grp, "fade_color", v3d->shading.background_color, 1);
- DRW_shgroup_uniform_float(grp, "fade_ob_factor", &v3d->overlay.gpencil_paper_opacity, 1);
- }
-}
-
-/* Get number of vertex for using in GPU VBOs */
-static void gpencil_calc_vertex(GPENCIL_StorageList *stl,
- tGPencilObjectCache *cache_ob,
- GpencilBatchCache *cache,
- bGPdata *gpd)
-{
- if ((!cache->is_dirty) || (gpd == NULL)) {
- return;
- }
-
- Object *ob = cache_ob->ob;
- const bool main_onion = stl->storage->is_main_onion;
- const bool playing = stl->storage->is_playing;
- const bool overlay = stl->storage->is_main_overlay;
- const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
- main_onion && !playing && gpencil_onion_active(gpd);
-
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
-
- /* Onion skinning. */
- const int step = gpd->gstep;
- const int mode = gpd->onion_mode;
- const short onion_keytype = gpd->onion_keytype;
-
- cache_ob->tot_vertex = 0;
- cache_ob->tot_triangles = 0;
- int idx_eval = 0;
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- bGPDframe *init_gpf = NULL;
- const bool is_onion = ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN));
- if (gpl->flag & GP_LAYER_HIDE) {
- idx_eval++;
- continue;
- }
-
- /* Relative onion mode needs to find the frame range before. */
- int frame_from = -9999;
- int frame_to = 9999;
- if ((is_onion) && (mode == GP_ONION_MODE_RELATIVE)) {
- /* 1) Found first Frame. */
- int idx = 0;
- if (gpl->actframe) {
- for (bGPDframe *gf = gpl->actframe->prev; gf; gf = gf->prev) {
- idx++;
- frame_from = gf->framenum;
- if (idx >= step) {
- break;
- }
- }
- /* 2) Found last Frame. */
- idx = 0;
- for (bGPDframe *gf = gpl->actframe->next; gf; gf = gf->next) {
- idx++;
- frame_to = gf->framenum;
- if (idx >= gpd->gstep_next) {
- break;
- }
- }
- }
- }
-
- /* If multiedit or onion skin need to count all frames of the layer. */
- if ((is_multiedit) || (is_onion)) {
- init_gpf = gpl->frames.first;
- }
- else {
- init_gpf = &ob->runtime.gpencil_evaluated_frames[idx_eval];
- }
-
- if (init_gpf == NULL) {
- continue;
- }
-
- for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (!is_onion) {
- if ((!is_multiedit) ||
- ((is_multiedit) && ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)))) {
- cache_ob->tot_vertex += gps->totpoints + 3;
- cache_ob->tot_triangles += gps->totpoints - 1;
- }
- }
- else {
- bool select = ((is_multiedit) &&
- ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)));
-
- if (!select) {
- /* Only selected frames. */
- if ((mode == GP_ONION_MODE_SELECTED) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
- continue;
- }
- /* Verify keyframe type. */
- if ((onion_keytype > -1) && (gpf->key_type != onion_keytype)) {
- continue;
- }
- /* Absolute range. */
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- if ((gpl->actframe) && (abs(gpl->actframe->framenum - gpf->framenum) > step)) {
- continue;
- }
- }
- /* Relative range. */
- if (mode == GP_ONION_MODE_RELATIVE) {
- if ((gpf->framenum < frame_from) || (gpf->framenum > frame_to)) {
- continue;
- }
- }
- }
-
- cache_ob->tot_vertex += gps->totpoints + 3;
- cache_ob->tot_triangles += gps->totpoints - 1;
- }
- }
-
- /* If not multiframe nor Onion skin, don't need follow counting. */
- if ((!is_multiedit) && (!is_onion)) {
- break;
- }
- }
- idx_eval++;
- }
-
- cache->b_fill.tot_vertex = cache_ob->tot_triangles * 3;
- cache->b_stroke.tot_vertex = cache_ob->tot_vertex;
- cache->b_point.tot_vertex = cache_ob->tot_vertex;
- cache->b_edit.tot_vertex = cache_ob->tot_vertex;
- cache->b_edlin.tot_vertex = cache_ob->tot_vertex;
-}
-
-/* Helper for doing all the checks on whether a stroke can be drawn */
-static bool gpencil_can_draw_stroke(struct MaterialGPencilStyle *gp_style,
- const bGPDstroke *gps,
- const bool onion,
- const bool is_mat_preview)
-{
- /* skip stroke if it doesn't have any valid data */
- if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
- return false;
- }
-
- /* if mat preview render always visible */
- if (is_mat_preview) {
- return true;
- }
-
- /* check if the color is visible */
- if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (onion && (gp_style->flag & GP_STYLE_COLOR_ONIONSKIN))) {
- return false;
- }
-
- /* stroke can be drawn */
- return true;
-}
-
-/* recalc the internal geometry caches for fill and uvs */
-static void gpencil_recalc_geometry_caches(Object *ob,
- bGPDlayer *gpl,
- MaterialGPencilStyle *gp_style,
- bGPDstroke *gps)
-{
- if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
- /* 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->flag & GP_STYLE_FILL_SHOW) &&
- ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0) ||
- (gpl->blend_mode != eGplBlendMode_Regular))) {
- BKE_gpencil_triangulate_stroke_fill((bGPdata *)ob->data, gps);
- }
- }
-
- /* calc uv data along the stroke */
- ED_gpencil_calc_stroke_uv(ob, gps);
-
- /* clear flag */
- gps->flag &= ~GP_STROKE_RECALC_GEOMETRY;
- }
-}
-
-static void set_wireframe_color(Object *ob,
- bGPDlayer *gpl,
- View3D *v3d,
- GPENCIL_StorageList *stl,
- MaterialGPencilStyle *gp_style,
- int id,
- const bool is_fill)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- World *world = draw_ctx->scene->world;
-
- float color[4];
- if (((gp_style->stroke_rgba[3] < GPENCIL_ALPHA_OPACITY_THRESH) ||
- (((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0))) &&
- (gp_style->fill_rgba[3] >= GPENCIL_ALPHA_OPACITY_THRESH)) {
- copy_v4_v4(color, gp_style->fill_rgba);
- }
- else {
- copy_v4_v4(color, gp_style->stroke_rgba);
- }
-
- /* wire color */
- if ((v3d) && (id > -1)) {
- const char type = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- /* if fill and wire, use background color */
- if ((is_fill) && (stl->shgroups[id].shading_type[0] == OB_WIRE)) {
- if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_THEME) {
- UI_GetThemeColor4fv(TH_BACK, stl->shgroups[id].wire_color);
- stl->shgroups[id].wire_color[3] = 1.0f;
- }
- else if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) {
- color[0] = world->horr;
- color[1] = world->horg;
- color[2] = world->horb;
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- }
- else {
- copy_v3_v3(color, v3d->shading.background_color);
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- }
- return;
- }
-
- /* strokes */
- switch (type) {
- case V3D_SHADING_SINGLE_COLOR: {
- if (stl->shgroups[id].shading_type[0] == OB_WIRE) {
- UI_GetThemeColor4fv(TH_WIRE, color);
- }
- else {
- copy_v3_v3(color, v3d->shading.single_color);
- }
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- break;
- }
- case V3D_SHADING_OBJECT_COLOR: {
- copy_v4_v4(color, ob->color);
- color[3] = 1.0f;
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- break;
- }
- case V3D_SHADING_RANDOM_COLOR: {
- uint gpl_hash = 1;
- uint ob_hash = BLI_ghashutil_strhash_p_murmur(ob->id.name);
- if (gpl) {
- gpl_hash = BLI_ghashutil_strhash_p_murmur(gpl->info);
- }
-
- float hue = BLI_hash_int_01(ob_hash * gpl_hash);
- float hsv[3] = {hue, 0.40f, 0.8f};
- float wire_col[3];
- hsv_to_rgb_v(hsv, &wire_col[0]);
-
- copy_v3_v3(stl->shgroups[id].wire_color, wire_col);
- stl->shgroups[id].wire_color[3] = 1.0f;
- break;
- }
- default: {
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- break;
- }
- }
- }
- else {
- copy_v4_v4(stl->shgroups[id].wire_color, color);
- }
-
- /* if solid, the alpha must be set to alpha */
- if (stl->shgroups[id].shading_type[0] == OB_SOLID) {
- stl->shgroups[id].wire_color[3] = 1.0f;
- }
-}
-
-/* create shading group for filling */
-static DRWShadingGroup *gpencil_shgroup_fill_create(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- DRWPass *pass,
- GPUShader *shader,
- Object *ob,
- float (*obmat)[4],
- bGPdata *gpd,
- bGPDlayer *gpl,
- MaterialGPencilStyle *gp_style,
- int id,
- const int shading_type[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- /* e_data.gpencil_fill_sh */
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
-
- DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
-
- DRW_shgroup_uniform_vec4(grp, "color2", gp_style->mix_rgba, 1);
-
- /* set style type */
- switch (gp_style->fill_style) {
- case GP_STYLE_FILL_STYLE_SOLID:
- stl->shgroups[id].fill_style = SOLID;
- break;
- case GP_STYLE_FILL_STYLE_GRADIENT:
- if (gp_style->gradient_type == GP_STYLE_GRADIENT_LINEAR) {
- stl->shgroups[id].fill_style = GRADIENT;
- }
- else {
- stl->shgroups[id].fill_style = RADIAL;
- }
- break;
- case GP_STYLE_FILL_STYLE_CHECKER:
- stl->shgroups[id].fill_style = CHECKER;
- break;
- case GP_STYLE_FILL_STYLE_TEXTURE:
- if (gp_style->flag & GP_STYLE_FILL_PATTERN) {
- stl->shgroups[id].fill_style = PATTERN;
- }
- else {
- stl->shgroups[id].fill_style = TEXTURE;
- }
- break;
- default:
- stl->shgroups[id].fill_style = GP_STYLE_FILL_STYLE_SOLID;
- break;
- }
- DRW_shgroup_uniform_int(grp, "fill_type", &stl->shgroups[id].fill_style, 1);
-
- DRW_shgroup_uniform_float(grp, "mix_factor", &gp_style->mix_factor, 1);
-
- DRW_shgroup_uniform_float(grp, "gradient_angle", &gp_style->gradient_angle, 1);
- DRW_shgroup_uniform_float(grp, "gradient_radius", &gp_style->gradient_radius, 1);
- DRW_shgroup_uniform_float(grp, "pattern_gridsize", &gp_style->pattern_gridsize, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_scale", gp_style->gradient_scale, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_shift", gp_style->gradient_shift, 1);
-
- DRW_shgroup_uniform_float(grp, "texture_angle", &gp_style->texture_angle, 1);
- DRW_shgroup_uniform_vec2(grp, "texture_scale", gp_style->texture_scale, 1);
- DRW_shgroup_uniform_vec2(grp, "texture_offset", gp_style->texture_offset, 1);
- DRW_shgroup_uniform_float(grp, "texture_opacity", &gp_style->texture_opacity, 1);
- DRW_shgroup_uniform_float(grp, "layer_opacity", &gpl->opacity, 1);
-
- stl->shgroups[id].texture_mix = gp_style->flag & GP_STYLE_FILL_TEX_MIX ? 1 : 0;
- DRW_shgroup_uniform_int(grp, "texture_mix", &stl->shgroups[id].texture_mix, 1);
-
- stl->shgroups[id].texture_flip = gp_style->flag & GP_STYLE_COLOR_FLIP_FILL ? 1 : 0;
- DRW_shgroup_uniform_int(grp, "texture_flip", &stl->shgroups[id].texture_flip, 1);
-
- stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE;
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->shgroups[id].xray_mode, 1);
- DRW_shgroup_uniform_int(grp, "drawmode", (const int *)&gpd->draw_mode, 1);
-
- /* viewport x-ray */
- stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
- DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
-
- /* shading type */
- stl->shgroups[id].shading_type[0] = GPENCIL_USE_SOLID(stl) ? (int)OB_RENDER : shading_type[0];
- if (v3d) {
- stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- }
-
- DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
-
- /* wire color */
- set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, true);
- DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
-
- /* image texture */
- if ((gp_style->flag & GP_STYLE_FILL_TEX_MIX) ||
- (gp_style->fill_style & GP_STYLE_FILL_STYLE_TEXTURE)) {
- ImBuf *ibuf;
- Image *image = gp_style->ima;
- ImageUser iuser = {NULL};
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->ima, &iuser, ibuf, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "myTexture", texture);
- DRW_shgroup_uniform_bool_copy(
- grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
-
- stl->shgroups[id].texture_clamp = gp_style->flag & GP_STYLE_COLOR_TEX_CLAMP ? 1 : 0;
- DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
-
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- }
- else {
- /* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
- stl->shgroups[id].texture_clamp = 0;
- DRW_shgroup_uniform_int(grp, "texture_clamp", &stl->shgroups[id].texture_clamp, 1);
- }
-
- return grp;
-}
-
-/* check if some onion is enabled */
-bool gpencil_onion_active(bGPdata *gpd)
-{
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
- return true;
- }
- }
- return false;
-}
-
-/* create shading group for strokes */
-DRWShadingGroup *gpencil_shgroup_stroke_create(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- DRWPass *pass,
- GPUShader *shader,
- Object *ob,
- float (*obmat)[4],
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDstroke *gps,
- MaterialGPencilStyle *gp_style,
- int id,
- bool onion,
- const float scale,
- const int shading_type[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const float *viewport_size = DRW_viewport_size_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- /* e_data.gpencil_stroke_sh */
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
-
- DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
-
- DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
-
- DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
-
- /* avoid wrong values */
- if ((gpd) && (gpd->pixfactor == 0.0f)) {
- gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- }
-
- /* object scale and depth */
- if ((ob) && (id > -1)) {
- stl->shgroups[id].obj_scale = scale;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
- stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
-
- stl->shgroups[id].stroke_style = gp_style->stroke_style;
- stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
- if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
- if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
- }
- }
- DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
-
- stl->shgroups[id].caps_mode[0] = gps->caps[0];
- stl->shgroups[id].caps_mode[1] = gps->caps[1];
- DRW_shgroup_uniform_int(grp, "caps_mode", &stl->shgroups[id].caps_mode[0], 2);
-
- stl->shgroups[id].gradient_f = gps->gradient_f;
- copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s);
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1);
-
- /* viewport x-ray */
- stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
- DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
-
- stl->shgroups[id].shading_type[0] = (GPENCIL_USE_SOLID(stl) || onion) ? (int)OB_RENDER :
- shading_type[0];
- if (v3d) {
- stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- }
- DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
-
- /* wire color */
- set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
- DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
-
- /* mix stroke factor */
- stl->shgroups[id].mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->shgroups[id].mix_stroke_factor, 1);
- }
- else {
- stl->storage->obj_scale = 1.0f;
- stl->storage->keep_size = 0;
- stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
- DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
- if (gpd) {
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
- }
- else {
- DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
- }
- const int zero[2] = {0, 0};
- DRW_shgroup_uniform_int(grp, "caps_mode", &zero[0], 2);
-
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1);
-
- /* viewport x-ray */
- DRW_shgroup_uniform_int(grp, "viewport_xray", &stl->storage->is_xray, 1);
- DRW_shgroup_uniform_int(grp, "shading_type", (const int *)&stl->storage->shade_render, 2);
-
- /* mix stroke factor */
- stl->storage->mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->storage->mix_stroke_factor, 1);
- }
-
- DRW_shgroup_uniform_vec4(grp, "colormix", gp_style->stroke_rgba, 1);
-
- if ((gpd) && (id > -1)) {
- stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE;
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->shgroups[id].xray_mode, 1);
- }
- else {
- /* for drawing always on predefined z-depth */
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
- }
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, false);
-
- /* image texture for pattern */
- if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- ImBuf *ibuf;
- Image *image = gp_style->sima;
- ImageUser iuser = {NULL};
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, ibuf, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "myTexture", texture);
- DRW_shgroup_uniform_bool_copy(
- grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
-
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- }
- else {
- /* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
- }
-
- return grp;
-}
-
-/* create shading group for points */
-static DRWShadingGroup *gpencil_shgroup_point_create(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- DRWPass *pass,
- GPUShader *shader,
- Object *ob,
- float (*obmat)[4],
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDstroke *gps,
- MaterialGPencilStyle *gp_style,
- int id,
- bool onion,
- const float scale,
- const int shading_type[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const float *viewport_size = DRW_viewport_size_get();
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
-
- /* e_data.gpencil_stroke_sh */
- DRWShadingGroup *grp = DRW_shgroup_create(shader, pass);
-
- DRW_shgroup_uniform_vec2(grp, "Viewport", viewport_size, 1);
- DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1);
-
- DRW_shgroup_uniform_mat4(grp, "gpModelMatrix", obmat);
-
- /* avoid wrong values */
- if ((gpd) && (gpd->pixfactor == 0.0f)) {
- gpd->pixfactor = GP_DEFAULT_PIX_FACTOR;
- }
-
- /* object scale and depth */
- if ((ob) && (id > -1)) {
- stl->shgroups[id].obj_scale = scale;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->shgroups[id].obj_scale, 1);
- stl->shgroups[id].keep_size = (int)((gpd) && (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS));
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->shgroups[id].keep_size, 1);
-
- stl->shgroups[id].mode = gp_style->mode;
- stl->shgroups[id].stroke_style = gp_style->stroke_style;
- stl->shgroups[id].color_type = GPENCIL_COLOR_SOLID;
- if ((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_TEXTURE;
- if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
- stl->shgroups[id].color_type = GPENCIL_COLOR_PATTERN;
- }
- }
- DRW_shgroup_uniform_int(grp, "color_type", &stl->shgroups[id].color_type, 1);
- DRW_shgroup_uniform_int(grp, "mode", &stl->shgroups[id].mode, 1);
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
-
- stl->shgroups[id].gradient_f = gps->gradient_f;
- copy_v2_v2(stl->shgroups[id].gradient_s, gps->gradient_s);
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->shgroups[id].gradient_f, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->shgroups[id].gradient_s, 1);
-
- /* viewport x-ray */
- stl->shgroups[id].is_xray = (ob->dt == OB_WIRE) ? 1 : stl->storage->is_xray;
- DRW_shgroup_uniform_int(grp, "viewport_xray", (const int *)&stl->shgroups[id].is_xray, 1);
-
- stl->shgroups[id].shading_type[0] = (GPENCIL_USE_SOLID(stl) || onion) ? (int)OB_RENDER :
- shading_type[0];
- if (v3d) {
- stl->shgroups[id].shading_type[1] = ((stl->shgroups[id].shading_type[0] == OB_WIRE) ?
- v3d->shading.wire_color_type :
- v3d->shading.color_type);
- }
- DRW_shgroup_uniform_int(grp, "shading_type", &stl->shgroups[id].shading_type[0], 2);
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, false);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, gpencil_fade_object_check(stl, ob));
-
- /* wire color */
- set_wireframe_color(ob, gpl, v3d, stl, gp_style, id, false);
- DRW_shgroup_uniform_vec4(grp, "wire_color", stl->shgroups[id].wire_color, 1);
-
- /* mix stroke factor */
- stl->shgroups[id].mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->shgroups[id].mix_stroke_factor, 1);
-
- /* lock rotation of dots and boxes */
- stl->shgroups[id].alignment_mode = gp_style->alignment_mode;
- DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->shgroups[id].alignment_mode, 1);
- }
- else {
- stl->storage->obj_scale = 1.0f;
- stl->storage->keep_size = 0;
- stl->storage->pixfactor = GP_DEFAULT_PIX_FACTOR;
- stl->storage->mode = gp_style->mode;
- DRW_shgroup_uniform_float(grp, "objscale", &stl->storage->obj_scale, 1);
- DRW_shgroup_uniform_int(grp, "keep_size", &stl->storage->keep_size, 1);
- DRW_shgroup_uniform_int(grp, "color_type", &stl->storage->color_type, 1);
- DRW_shgroup_uniform_int(grp, "mode", &stl->storage->mode, 1);
- if (gpd) {
- DRW_shgroup_uniform_float(grp, "pixfactor", &gpd->pixfactor, 1);
- }
- else {
- DRW_shgroup_uniform_float(grp, "pixfactor", &stl->storage->pixfactor, 1);
- }
-
- DRW_shgroup_uniform_float(grp, "gradient_f", &stl->storage->gradient_f, 1);
- DRW_shgroup_uniform_vec2(grp, "gradient_s", stl->storage->gradient_s, 1);
-
- /* viewport x-ray */
- DRW_shgroup_uniform_int(grp, "viewport_xray", &stl->storage->is_xray, 1);
- DRW_shgroup_uniform_int(grp, "shading_type", (const int *)&stl->storage->shade_render, 2);
-
- /* mix stroke factor */
- stl->storage->mix_stroke_factor = (gp_style->flag & GP_STYLE_STROKE_TEX_MIX) ?
- gp_style->mix_stroke_factor :
- 0.0f;
- DRW_shgroup_uniform_float(grp, "mix_stroke_factor", &stl->storage->mix_stroke_factor, 1);
-
- /* lock rotation of dots and boxes */
- DRW_shgroup_uniform_int(grp, "alignment_mode", &stl->storage->alignment_mode, 1);
- }
-
- DRW_shgroup_uniform_vec4(grp, "colormix", gp_style->stroke_rgba, 1);
-
- if ((gpd) && (id > -1)) {
- stl->shgroups[id].xray_mode = (ob->dtx & OB_DRAWXRAY) ? GP_XRAY_FRONT : GP_XRAY_3DSPACE;
- DRW_shgroup_uniform_int(grp, "xraymode", (const int *)&stl->shgroups[id].xray_mode, 1);
- }
- else {
- /* for drawing always on predefined z-depth */
- DRW_shgroup_uniform_int(grp, "xraymode", &stl->storage->xray, 1);
- }
-
- /* Fade layer uniforms. */
- gpencil_set_fade_layer_uniforms(stl, grp, ob, gpl, true);
-
- /* Fade object uniforms. */
- gpencil_set_fade_ob_uniforms(v3d, grp, false);
-
- /* image texture */
- if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && (!onion)) {
- ImBuf *ibuf;
- Image *image = gp_style->sima;
- ImageUser iuser = {NULL};
- void *lock;
-
- iuser.ok = true;
-
- ibuf = BKE_image_acquire_ibuf(image, &iuser, &lock);
-
- if (ibuf == NULL || ibuf->rect == NULL) {
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- else {
- GPUTexture *texture = GPU_texture_from_blender(gp_style->sima, &iuser, ibuf, GL_TEXTURE_2D);
- DRW_shgroup_uniform_texture(grp, "myTexture", texture);
- DRW_shgroup_uniform_bool_copy(
- grp, "myTexturePremultiplied", (image->alpha_mode == IMA_ALPHA_PREMUL));
-
- BKE_image_release_ibuf(image, ibuf, NULL);
- }
- }
- else {
- /* if no texture defined, need a blank texture to avoid errors in draw manager */
- DRW_shgroup_uniform_texture(grp, "myTexture", e_data->gpencil_blank_texture);
- }
-
- return grp;
-}
-
-/* add fill vertex info */
-static void gpencil_add_fill_vertexdata(GpencilBatchCache *cache,
- Object *ob,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps,
- float opacity,
- const float tintcolor[4],
- const bool onion,
- const bool custonion)
-{
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- if (gps->totpoints >= 3) {
- float tfill[4];
- /* 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) ||
- (gpl->blend_mode != eGplBlendMode_Regular)) {
- if (cache->is_dirty) {
- const float *color;
- if (!onion) {
- color = tfill;
- }
- else {
- if (custonion) {
- color = tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gps->runtime.tmp_fill_rgba), tintcolor[3]);
- color = tfill;
- }
- }
- /* create vertex data */
- const int old_len = cache->b_fill.vbo_len;
- gpencil_get_fill_geom(&cache->b_fill, ob, gps, color);
-
- /* 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->b_fill.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- }
- }
-}
-
-/* add stroke vertex info */
-static void gpencil_add_stroke_vertexdata(GpencilBatchCache *cache,
- Object *ob,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps,
- const float opacity,
- const float tintcolor[4],
- const bool onion,
- const bool custonion)
-{
- float tcolor[4];
- float ink[4];
- short sthickness;
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- const int alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH;
-
- /* set color using base color, tint color and opacity */
- if (cache->is_dirty) {
- if (!onion) {
- /* if special stroke, use fill color as stroke color */
- if (gps->flag & GP_STROKE_NOFILL) {
- interp_v3_v3v3(tcolor, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]);
- tcolor[3] = gps->runtime.tmp_fill_rgba[3] * opacity;
- }
- else {
- interp_v3_v3v3(tcolor, gps->runtime.tmp_stroke_rgba, tintcolor, tintcolor[3]);
- tcolor[3] = gps->runtime.tmp_stroke_rgba[3] * opacity;
- }
- copy_v4_v4(ink, tcolor);
- }
- else {
- if (custonion) {
- copy_v4_v4(ink, tintcolor);
- }
- else {
- ARRAY_SET_ITEMS(tcolor, UNPACK3(gps->runtime.tmp_stroke_rgba), opacity);
- copy_v4_v4(ink, tcolor);
- }
- }
-
- sthickness = gps->thickness + gpl->line_change;
- CLAMP_MIN(sthickness, 1);
-
- if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
- /* create vertex data */
- const int old_len = cache->b_stroke.vbo_len;
- gpencil_get_stroke_geom(&cache->b_stroke, gps, sthickness, ink);
-
- /* 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->b_stroke.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- else {
- /* create vertex data */
- const int old_len = cache->b_point.vbo_len;
- gpencil_get_point_geom(&cache->b_point, gps, sthickness, ink, alignment_mode);
-
- /* add to list of groups */
- if (old_len < cache->b_point.vbo_len) {
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Point,
- onion,
- cache->b_point.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- }
-}
-
-/* add edit points vertex info */
-static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- bGPDstroke *gps)
-{
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- ToolSettings *ts = draw_ctx->scene->toolsettings;
- const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) && (ts->gpencil_selectmode_sculpt &
- (GP_SCULPT_MASK_SELECTMODE_POINT |
- GP_SCULPT_MASK_SELECTMODE_STROKE |
- GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
-
- const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) &&
- (ts->gpencil_selectmode_sculpt &
- (GP_SCULPT_MASK_SELECTMODE_POINT |
- GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
-
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
-
- /* alpha factor for edit points/line to make them more subtle */
- float edit_alpha = v3d->vertex_opacity;
-
- if (GPENCIL_ANY_EDIT_MODE(gpd)) {
- Object *obact = DRW_context_state_get()->obact;
- if ((!obact) || (obact->type != OB_GPENCIL)) {
- return;
- }
- const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
-
- /* If Sculpt mode and the mask is disabled, the select must be hidden. */
- const bool hide_select = GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask;
-
- /* Show Edit points if:
- * Edit mode: Not in Stroke selection mode
- * Sculpt mode: Not in Stroke mask mode and any other mask mode enabled
- * Weight mode: Always
- */
- const bool show_points = (show_sculpt_points) || (is_weight_paint) ||
- (GPENCIL_EDIT_MODE(gpd) &&
- ((ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE) ||
- (gps->totpoints == 1)));
-
- if (cache->is_dirty) {
- if ((obact == ob) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
- (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) && (gps->totpoints > 1)) {
-
- /* line of the original stroke */
- gpencil_get_edlin_geom(&cache->b_edlin, gps, edit_alpha, hide_select);
-
- /* add to list of groups */
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Edlin,
- false,
- cache->b_edlin.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
-
- /* If the points are hidden return. */
- if ((!show_points) || (hide_select)) {
- return;
- }
-
- /* edit points */
- if ((gps->flag & GP_STROKE_SELECT) || (is_weight_paint)) {
- if ((gpl->flag & GP_LAYER_UNLOCK_COLOR) ||
- ((gp_style->flag & GP_STYLE_COLOR_LOCKED) == 0)) {
- if (obact == ob) {
- gpencil_get_edit_geom(&cache->b_edit, gps, edit_alpha, gpd->flag);
-
- /* add to list of groups */
- cache->grp_cache = gpencil_group_cache_add(cache->grp_cache,
- gpl,
- gpf,
- gps,
- eGpencilBatchGroupType_Edit,
- false,
- cache->b_edit.vbo_len,
- &cache->grp_size,
- &cache->grp_used);
- }
- }
- }
- }
- }
-}
-
-/* main function to draw strokes */
-static void gpencil_draw_strokes(GpencilBatchCache *cache,
- GPENCIL_e_data *e_data,
- void *vedata,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- const float opacity,
- const float tintcolor[4],
- const bool custonion,
- tGPencilObjectCache *cache_ob)
-{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- View3D *v3d = draw_ctx->v3d;
- bGPDstroke *gps;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const bool playing = stl->storage->is_playing;
- const bool is_render = (bool)stl->storage->is_render;
- const bool is_mat_preview = (bool)stl->storage->is_mat_preview;
- const bool overlay_multiedit = v3d != NULL ? !(v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) :
- true;
-
- /* Get evaluation context */
- /* NOTE: We must check if C is valid, otherwise we get crashes when trying to save files
- * (i.e. the thumbnail offscreen rendering fails)
- */
- Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
-
- /* get parent matrix and save as static data */
- if ((cache_ob != NULL) && (cache_ob->is_dup_ob)) {
- copy_m4_m4(gpf->runtime.parent_obmat, cache_ob->obmat);
- }
- else {
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, gpf->runtime.parent_obmat);
- }
-
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
-
- /* check if stroke can be drawn */
- if (gpencil_can_draw_stroke(gp_style, gps, false, is_mat_preview) == false) {
- continue;
- }
-
- /* Copy color to temp fields. */
- if ((is_multiedit) && (gp_style)) {
- copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
- }
-
- /* be sure recalc all cache in source stroke to avoid recalculation when frame change
- * and improve fps */
- gpencil_recalc_geometry_caches(
- ob, gpl, gp_style, (gps->runtime.gps_orig) ? gps->runtime.gps_orig : 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) ||
- (gpl->blend_mode != eGplBlendMode_Regular)) {
-
- continue;
- }
- }
-
- if ((gpl->actframe && (gpl->actframe->framenum == gpf->framenum)) || (!is_multiedit) ||
- (overlay_multiedit)) {
- /* hide any blend layer */
- if ((!stl->storage->simplify_blend) || (gpl->blend_mode == eGplBlendMode_Regular)) {
- /* 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, gpf, gps, opacity, tintcolor, false, custonion);
- }
- /* stroke
- * No fill strokes, must show stroke always or if the total points is lower than 3,
- * because the stroke cannot be filled and it would be invisible. */
- if (((gp_style->flag & GP_STYLE_STROKE_SHOW) || (gps->flag & GP_STROKE_NOFILL) ||
- (gps->totpoints < 3)) &&
- ((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
- (gpl->blend_mode == eGplBlendMode_Regular))) {
- /* recalc strokes uv (geometry can be changed by modifiers) */
- if (gps->flag & GP_STROKE_RECALC_GEOMETRY) {
- ED_gpencil_calc_stroke_uv(ob, gps);
- }
-
- gpencil_add_stroke_vertexdata(
- cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion);
- }
- }
- }
-
- /* edit points (only in edit mode and not play animation not render) */
- if ((draw_ctx->obact == ob) && (!playing) && (!is_render) && (!cache_ob->is_dup_ob)) {
- if ((gpl->flag & GP_LAYER_LOCKED) == 0) {
- if (!stl->g_data->shgrps_edit_line) {
- stl->g_data->shgrps_edit_line = DRW_shgroup_create(e_data->gpencil_line_sh,
- psl->edit_pass);
- DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_line, "gpModelMatrix", ob->obmat);
- }
- if (!stl->g_data->shgrps_edit_point) {
- stl->g_data->shgrps_edit_point = DRW_shgroup_create(e_data->gpencil_edit_point_sh,
- psl->edit_pass);
- const float *viewport_size = DRW_viewport_size_get();
- DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1);
- DRW_shgroup_uniform_mat4(stl->g_data->shgrps_edit_point, "gpModelMatrix", ob->obmat);
- }
-
- gpencil_add_editpoints_vertexdata(cache, ob, gpd, gpl, gpf, gps);
- }
- }
- }
-}
-
-/* get alpha factor for onion strokes */
-static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd)
-{
-#define MIN_ALPHA_VALUE 0.01f
-
- /* if fade is disabled, opacity is equal in all frames */
- if ((gpd->onion_flag & GP_ONION_FADE) == 0) {
- color[3] = gpd->onion_factor;
- }
- else {
- /* add override opacity factor */
- color[3] += gpd->onion_factor - 0.5f;
- }
-
- CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f);
-}
-
-/* function to draw strokes for onion only */
-static void gpencil_draw_onion_strokes(GpencilBatchCache *cache,
- void *vedata,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- const float opacity,
- const float tintcolor[4],
- const bool custonion)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- Depsgraph *depsgraph = DRW_context_state_get()->depsgraph;
-
- /* get parent matrix and save as static data */
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, gpf->runtime.parent_obmat);
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- if (gp_style == NULL) {
- continue;
- }
- copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba);
- copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba);
-
- int id = stl->storage->shgroup_id;
- /* check if stroke can be drawn */
- if (gpencil_can_draw_stroke(gp_style, gps, true, false) == false) {
- continue;
- }
- /* limit the number of shading groups */
- if (id >= GPENCIL_MAX_SHGROUPS) {
- continue;
- }
-
- /* stroke */
- gpencil_add_stroke_vertexdata(cache, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion);
-
- stl->storage->shgroup_id++;
- }
-}
-
-/* draw onion-skinning for a layer */
-static void gpencil_draw_onionskins(GpencilBatchCache *cache,
- void *vedata,
- Object *ob,
- bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf)
-{
-
- const float default_color[3] = {UNPACK3(U.gpencil_new_layer_col)};
- const float alpha = 1.0f;
- float color[4];
- int idx;
- float fac = 1.0f;
- int step = 0;
- bool colflag = false;
- const int mode = gpd->onion_mode;
- bGPDframe *gpf_loop = ((gpd->onion_flag & GP_ONION_LOOP) && (mode != GP_ONION_MODE_SELECTED)) ?
- gpl->frames.first :
- NULL;
- int last = gpf->framenum;
-
- colflag = (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) != 0;
- const short onion_keytype = gpd->onion_keytype;
- /* -------------------------------
- * 1) Draw Previous Frames First
- * ------------------------------- */
- step = gpd->gstep;
-
- if (gpd->onion_flag & GP_ONION_GHOST_PREVCOL) {
- copy_v3_v3(color, gpd->gcolor_prev);
- }
- else {
- copy_v3_v3(color, default_color);
- }
-
- idx = 0;
- for (bGPDframe *gf = gpf->prev; gf; gf = gf->prev) {
- /* only selected frames */
- if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
- continue;
- }
- /* verify keyframe type */
- if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) {
- continue;
- }
- /* absolute range */
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- if ((gpf->framenum - gf->framenum) > step) {
- break;
- }
- }
- /* relative range */
- if (mode == GP_ONION_MODE_RELATIVE) {
- idx++;
- if (idx > step) {
- break;
- }
- }
- /* alpha decreases with distance from curframe index */
- if (mode != GP_ONION_MODE_SELECTED) {
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(step + 1));
- }
- else {
- fac = 1.0f - ((float)idx / (float)(step + 1));
- }
- color[3] = alpha * fac * 0.66f;
- }
- else {
- idx++;
- fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
- color[3] = fac;
- }
-
- /* if loop option, save the frame to use later */
- if ((mode == GP_ONION_MODE_SELECTED) && (gpd->onion_flag & GP_ONION_LOOP)) {
- gpf_loop = gf;
- }
-
- gpencil_get_onion_alpha(color, gpd);
- gpencil_draw_onion_strokes(cache, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
- }
- /* -------------------------------
- * 2) Now draw next frames
- * ------------------------------- */
- step = gpd->gstep_next;
-
- if (gpd->onion_flag & GP_ONION_GHOST_NEXTCOL) {
- copy_v3_v3(color, gpd->gcolor_next);
- }
- else {
- copy_v3_v3(color, default_color);
- }
-
- idx = 0;
- for (bGPDframe *gf = gpf->next; gf; gf = gf->next) {
- /* only selected frames */
- if ((mode == GP_ONION_MODE_SELECTED) && ((gf->flag & GP_FRAME_SELECT) == 0)) {
- continue;
- }
- /* verify keyframe type */
- if ((onion_keytype > -1) && (gf->key_type != onion_keytype)) {
- continue;
- }
- /* absolute range */
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- if ((gf->framenum - gpf->framenum) > step) {
- break;
- }
- }
- /* relative range */
- if (mode == GP_ONION_MODE_RELATIVE) {
- idx++;
- if (idx > step) {
- break;
- }
- }
- /* alpha decreases with distance from curframe index */
- if (mode != GP_ONION_MODE_SELECTED) {
- if (mode == GP_ONION_MODE_ABSOLUTE) {
- fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(step + 1));
- }
- else {
- fac = 1.0f - ((float)idx / (float)(step + 1));
- }
- color[3] = alpha * fac * 0.66f;
- }
- else {
- idx++;
- fac = alpha - ((1.1f - (1.0f / (float)idx)) * 0.66f);
- color[3] = fac;
- }
-
- gpencil_get_onion_alpha(color, gpd);
- gpencil_draw_onion_strokes(cache, vedata, ob, gpd, gpl, gf, color[3], color, colflag);
- if (last < gf->framenum) {
- last = gf->framenum;
- }
- }
-
- /* Draw first frame in blue for loop mode */
- if ((gpd->onion_flag & GP_ONION_LOOP) && (gpf_loop != NULL)) {
- if ((last == gpf->framenum) || (gpf->next == NULL)) {
- gpencil_get_onion_alpha(color, gpd);
- gpencil_draw_onion_strokes(cache, vedata, ob, gpd, gpl, gpf_loop, color[3], color, colflag);
- }
- }
-}
-
-/* Check if stencil is required */
-static bool gpencil_is_stencil_required(MaterialGPencilStyle *gp_style)
-{
- return (bool)((gp_style->stroke_style == GP_STYLE_STROKE_STYLE_SOLID) &&
- ((gp_style->flag & GP_STYLE_DISABLE_STENCIL) == 0));
-}
-
-/* draw stroke in drawing buffer */
-void gpencil_populate_buffer_strokes(GPENCIL_e_data *e_data,
- void *vedata,
- ToolSettings *ts,
- Object *ob)
-{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- const bool is_paint_tool = (bool)((brush) && (brush->gpencil_tool == GPAINT_TOOL_DRAW));
- bGPdata *gpd_eval = ob->data;
- /* need the original to avoid cow overhead while drawing */
- bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id);
-
- MaterialGPencilStyle *gp_style = NULL;
- float obscale = mat4_to_scale(ob->obmat);
-
- /* use the brush material */
- Material *ma = BKE_gpencil_object_material_get_from_brush(ob, brush);
- if (ma != NULL) {
- gp_style = ma->gp_style;
- }
- /* this is not common, but avoid any special situations when brush could be without material */
- if (gp_style == NULL) {
- gp_style = BKE_gpencil_material_settings(ob, ob->actcol);
- }
-
- static float unit_mat[4][4] = {
- {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0}};
-
- /* drawing strokes */
- /* Check if may need to draw the active stroke cache, only if this layer is the active layer
- * that is being edited. (Stroke buffer is currently stored in gp-data)
- */
- if (gpd->runtime.sbuffer_used > 0) {
- if ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) {
- /* It should also be noted that sbuffer contains temporary point types
- * i.e. tGPspoints NOT bGPDspoints
- */
- short lthick = brush->size * obscale;
-
- /* save gradient info */
- stl->storage->gradient_f = brush->gpencil_settings->gradient_f;
- copy_v2_v2(stl->storage->gradient_s, brush->gpencil_settings->gradient_s);
- stl->storage->alignment_mode = (gp_style) ? gp_style->alignment_mode : GP_STYLE_FOLLOW_PATH;
-
- /* if only one point, don't need to draw buffer because the user has no time to see it */
- if (gpd->runtime.sbuffer_used > 1) {
- if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) {
- stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_stroke_create(
- e_data,
- vedata,
- psl->drawing_pass,
- e_data->gpencil_stroke_sh,
- NULL,
- unit_mat,
- gpd,
- NULL,
- NULL,
- gp_style,
- -1,
- false,
- 1.0f,
- (const int *)stl->storage->shade_render);
-
- if (gpencil_is_stencil_required(gp_style)) {
- DRW_shgroup_stencil_mask(stl->g_data->shgrps_drawing_stroke, 0x01);
- }
- else {
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_stroke,
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- }
- }
- else {
- stl->g_data->shgrps_drawing_stroke = gpencil_shgroup_point_create(
- e_data,
- vedata,
- psl->drawing_pass,
- e_data->gpencil_point_sh,
- NULL,
- unit_mat,
- gpd,
- NULL,
- NULL,
- gp_style,
- -1,
- false,
- 1.0f,
- (const int *)stl->storage->shade_render);
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_stroke,
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- }
-
- /* use unit matrix because the buffer is in screen space and does not need conversion */
- if (gpd->runtime.mode == GP_STYLE_MODE_LINE) {
- stl->g_data->batch_buffer_stroke = gpencil_get_buffer_stroke_geom(gpd, lthick);
- }
- else {
- stl->g_data->batch_buffer_stroke = gpencil_get_buffer_point_geom(gpd, lthick);
- }
-
- /* buffer strokes, must show stroke always */
- DRW_shgroup_call(
- stl->g_data->shgrps_drawing_stroke, stl->g_data->batch_buffer_stroke, NULL);
-
- if ((gpd->runtime.sbuffer_used >= 3) &&
- (gpd->runtime.sfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) &&
- ((gpd->runtime.sbuffer_sflag & GP_STROKE_NOFILL) == 0) &&
- ((brush->gpencil_settings->flag & GP_BRUSH_DISSABLE_LASSO) == 0) &&
- (gp_style->flag & GP_STYLE_FILL_SHOW)) {
- /* if not solid, fill is simulated with solid color */
- if (gpd->runtime.bfill_style > 0) {
- gpd->runtime.sfill[3] = 0.5f;
- }
- stl->g_data->shgrps_drawing_fill = DRW_shgroup_create(e_data->gpencil_drawing_fill_sh,
- psl->drawing_pass);
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(stl->g_data->shgrps_drawing_fill,
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- stl->g_data->batch_buffer_fill = gpencil_get_buffer_fill_geom(gpd);
- DRW_shgroup_call(stl->g_data->shgrps_drawing_fill, stl->g_data->batch_buffer_fill, NULL);
- }
- }
- }
- }
-
- /* control points for primitives and speed guide */
- const bool is_cppoint = (gpd->runtime.tot_cp_points > 0);
- const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide &&
- (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL));
- const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) &&
- ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0));
-
- if ((overlay) && (is_paint_tool) && (is_cppoint || is_speed_guide) && (is_show_gizmo) &&
- ((gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0)) {
- DRWShadingGroup *shgrp = DRW_shgroup_create(e_data->gpencil_edit_point_sh, psl->drawing_pass);
- const float *viewport_size = DRW_viewport_size_get();
- DRW_shgroup_uniform_vec2(shgrp, "Viewport", viewport_size, 1);
- DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", unit_mat);
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- stl->g_data->batch_buffer_ctrlpoint = gpencil_get_buffer_ctrlpoint_geom(gpd);
-
- DRW_shgroup_call(shgrp, stl->g_data->batch_buffer_ctrlpoint, NULL);
- }
-}
-
-/* create all missing batches */
-static void gpencil_batches_ensure(GpencilBatchCache *cache)
-{
- if ((cache->b_point.vbo) && (cache->b_point.batch == NULL)) {
- cache->b_point.batch = GPU_batch_create_ex(
- GPU_PRIM_POINTS, cache->b_point.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_stroke.vbo) && (cache->b_stroke.batch == NULL)) {
- cache->b_stroke.batch = GPU_batch_create_ex(
- GPU_PRIM_LINE_STRIP_ADJ, cache->b_stroke.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_fill.vbo) && (cache->b_fill.batch == NULL)) {
- cache->b_fill.batch = GPU_batch_create_ex(
- GPU_PRIM_TRIS, cache->b_fill.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_edit.vbo) && (cache->b_edit.batch == NULL)) {
- cache->b_edit.batch = GPU_batch_create_ex(
- GPU_PRIM_POINTS, cache->b_edit.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
- if ((cache->b_edlin.vbo) && (cache->b_edlin.batch == NULL)) {
- cache->b_edlin.batch = GPU_batch_create_ex(
- GPU_PRIM_LINE_STRIP, cache->b_edlin.vbo, NULL, GPU_BATCH_OWNS_VBO);
- }
-}
-
-/* create all shading groups */
-static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
- void *vedata,
- 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;
- DRWPass *stroke_pass = GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d;
-
- 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;
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
-
- const bool overlay = draw_ctx->v3d != NULL ?
- (bool)((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) :
- true;
- const bool screen_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true;
- const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && screen_onion &&
- overlay && gpencil_onion_active(gpd);
-
- int start_stroke = 0;
- int start_point = 0;
- int start_fill = 0;
- int start_edit = 0;
- int start_edlin = 0;
-
- uint stencil_id = 1;
- /* Flag to determine if the layer is above active layer. */
- stl->storage->is_ontop = false;
- for (int i = 0; i < cache->grp_used; i++) {
- elm = &cache->grp_cache[i];
- array_elm = &cache_ob->shgrp_array[idx];
-
- /* Limit stencil id */
- if (stencil_id > 255) {
- stencil_id = 1;
- }
-
- /* 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_Regular : gpl->blend_mode;
- array_elm->end_shgrp = shgrp;
- gpl_prev = elm->gpl;
- tag_first = true;
- idx++;
- }
- }
-
- gpl = elm->gpl;
- if ((!stl->storage->is_ontop) && (gpl->flag & GP_LAYER_ACTIVE)) {
- stl->storage->is_ontop = true;
- }
-
- bGPDframe *gpf = elm->gpf;
- bGPDstroke *gps = elm->gps;
- MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
- /* if the user switch used material from data to object,
- * the material could not be available */
- if (gp_style == NULL) {
- break;
- }
-
- /* limit the number of shading groups */
- if (i >= GPENCIL_MAX_SHGROUPS) {
- break;
- }
-
- const float scale = (!cache_ob->is_dup_ob) ? mat4_to_scale(gpf->runtime.parent_obmat) :
- cache_ob->scale;
- float(*obmat)[4] = (!cache_ob->is_dup_ob) ? gpf->runtime.parent_obmat : cache_ob->obmat;
- switch (elm->type) {
- case eGpencilBatchGroupType_Stroke: {
- const int len = elm->vertex_idx - start_stroke;
-
- shgrp = gpencil_shgroup_stroke_create(e_data,
- vedata,
- stroke_pass,
- e_data->gpencil_stroke_sh,
- ob,
- obmat,
- gpd,
- gpl,
- gps,
- gp_style,
- stl->storage->shgroup_id,
- elm->onion,
- scale,
- cache_ob->shading_type);
-
- /* set stencil mask id */
- if (gpencil_is_stencil_required(gp_style)) {
- if (stencil_id == 1) {
- /* Clear previous stencils. */
- DRW_shgroup_clear_framebuffer(shgrp, GPU_STENCIL_BIT, 0, 0, 0, 0, 0.0f, 0x0);
- }
- DRW_shgroup_stencil_mask(shgrp, stencil_id);
- stencil_id++;
- }
- else {
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- }
-
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range(shgrp, cache->b_stroke.batch, start_stroke, len);
- }
- stl->storage->shgroup_id++;
- start_stroke = elm->vertex_idx;
- break;
- }
- case eGpencilBatchGroupType_Point: {
- const int len = elm->vertex_idx - start_point;
-
- shgrp = gpencil_shgroup_point_create(e_data,
- vedata,
- stroke_pass,
- e_data->gpencil_point_sh,
- ob,
- obmat,
- gpd,
- gpl,
- gps,
- gp_style,
- stl->storage->shgroup_id,
- elm->onion,
- scale,
- cache_ob->shading_type);
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range(shgrp, cache->b_point.batch, start_point, len);
- }
- stl->storage->shgroup_id++;
- start_point = elm->vertex_idx;
- break;
- }
- case eGpencilBatchGroupType_Fill: {
- const int len = elm->vertex_idx - start_fill;
-
- shgrp = gpencil_shgroup_fill_create(e_data,
- vedata,
- stroke_pass,
- e_data->gpencil_fill_sh,
- ob,
- obmat,
- gpd,
- gpl,
- gp_style,
- stl->storage->shgroup_id,
- cache_ob->shading_type);
-
- /* Disable stencil for this type */
- DRW_shgroup_state_disable(shgrp, DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- if ((do_onion) || (elm->onion == false)) {
- DRW_shgroup_call_range(shgrp, cache->b_fill.batch, start_fill, len);
- }
- stl->storage->shgroup_id++;
- start_fill = elm->vertex_idx;
- break;
- }
- case eGpencilBatchGroupType_Edit: {
- if (stl->g_data->shgrps_edit_point) {
- const int len = elm->vertex_idx - start_edit;
-
- shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_point);
- DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
- /* use always the same group */
- DRW_shgroup_call_range(
- stl->g_data->shgrps_edit_point, cache->b_edit.batch, start_edit, len);
-
- start_edit = elm->vertex_idx;
- }
- break;
- }
- case eGpencilBatchGroupType_Edlin: {
- if (stl->g_data->shgrps_edit_line) {
- const int len = elm->vertex_idx - start_edlin;
-
- shgrp = DRW_shgroup_create_sub(stl->g_data->shgrps_edit_line);
- DRW_shgroup_uniform_mat4(shgrp, "gpModelMatrix", obmat);
- /* use always the same group */
- DRW_shgroup_call_range(
- stl->g_data->shgrps_edit_line, cache->b_edlin.batch, start_edlin, len);
-
- start_edlin = elm->vertex_idx;
- }
- break;
- }
- default: {
- break;
- }
- }
- /* save first group */
- if ((shgrp != NULL) && (tag_first)) {
- array_elm = &cache_ob->shgrp_array[idx];
- array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode;
- array_elm->mask_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) {
- array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode;
- array_elm->end_shgrp = shgrp;
- }
-}
-/* populate a datablock for multiedit (no onions, no modifiers) */
-void gpencil_populate_multiedit(GPENCIL_e_data *e_data,
- void *vedata,
- Object *ob,
- tGPencilObjectCache *cache_ob)
-{
- bGPdata *gpd = (bGPdata *)ob->data;
- bGPDframe *gpf = NULL;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
- GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
-
- /* check if playing animation */
- const bool playing = stl->storage->is_playing;
-
- /* calc max size of VBOs */
- gpencil_calc_vertex(stl, cache_ob, cache, gpd);
-
- /* draw strokes */
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* don't draw layer if hidden */
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
- const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
- const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
-
- /* list of frames to draw */
- if (!playing) {
- for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
- }
- }
- }
- else {
- gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV);
- if (gpf) {
- gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf, gpl->opacity, tintcolor, false, cache_ob);
- }
- }
- }
-
- /* create batchs and shading groups */
- gpencil_batches_ensure(cache);
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
-
- cache->is_dirty = false;
-}
-
-/* helper for populate a complete grease pencil datablock */
-void gpencil_populate_datablock(GPENCIL_e_data *e_data,
- void *vedata,
- Object *ob,
- tGPencilObjectCache *cache_ob)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const ViewLayer *view_layer = DEG_get_evaluated_view_layer(draw_ctx->depsgraph);
- Scene *scene = draw_ctx->scene;
-
- /* TODO: Review why is needed this recalc when render cycles + GP object in background.
- * We need these lines to keep running the background render, but asap we get an alternative
- * solution, we must remove it and keep all logic inside gpencil_modifier module. (antoniov)
- */
- if (ob->runtime.gpencil_tot_layers == 0) {
- BKE_gpencil_modifiers_calc(draw_ctx->depsgraph, draw_ctx->scene, ob);
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
-
- /* If render mode, instead to use view switches, test if the datablock has
- * the onion activated for render. */
- const bool render_onion = (gpd && gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
- const bool main_onion = (stl->storage->is_render) ? render_onion : stl->storage->is_main_onion;
- const bool overlay = (stl->storage->is_render) ? render_onion : stl->storage->is_main_overlay;
- const bool playing = stl->storage->is_playing;
- const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && overlay &&
- main_onion && !playing && gpencil_onion_active(gpd);
-
- View3D *v3d = draw_ctx->v3d;
- int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph);
-
- bGPDframe *gpf_eval = NULL;
- const bool time_remap = BKE_gpencil_has_time_modifiers(ob);
-
- float opacity;
- bGPDframe *gpf = NULL;
-
- GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval);
-
- /* if object is duplicate, only create shading groups */
- if (cache_ob->is_dup_ob) {
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
- return;
- }
-
- /* calc max size of VBOs */
- gpencil_calc_vertex(stl, cache_ob, cache, gpd);
-
- /* 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) {
- continue;
- }
-
- const bool is_solomode = GPENCIL_PAINT_MODE(gpd) && (!playing) && (!stl->storage->is_render) &&
- (gpl->flag & GP_LAYER_SOLO_MODE);
-
- /* filter view layer to gp layers in the same view layer (for compo) */
- if ((stl->storage->is_render) && (gpl->viewlayername[0] != '\0')) {
- if (!STREQ(view_layer->name, gpl->viewlayername)) {
- continue;
- }
- }
-
- /* remap time */
- int remap_cfra = cfra_eval;
- if ((time_remap) && (!stl->storage->simplify_modif)) {
- remap_cfra = BKE_gpencil_time_modifier(
- draw_ctx->depsgraph, scene, ob, gpl, cfra_eval, stl->storage->is_render);
- }
-
- gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV);
- if (gpf == NULL) {
- continue;
- }
-
- /* if solo mode, display only frames with keyframe in the current frame */
- if ((is_solomode) && (gpf->framenum != remap_cfra)) {
- continue;
- }
-
- opacity = gpl->opacity;
- /* if pose mode, maybe the overlay to fade geometry is enabled */
- if ((draw_ctx->obact) && (draw_ctx->object_mode == OB_MODE_POSE) &&
- (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT)) {
- opacity = opacity * v3d->overlay.xray_alpha_bone;
- }
-
- /* Get evaluated frames array data */
- int idx_eval = BLI_findindex(&gpd->layers, gpl);
- gpf_eval = &ob->runtime.gpencil_evaluated_frames[idx_eval];
-
- /* draw onion skins */
- if (!ID_IS_LINKED(&gpd->id)) {
- if ((do_onion) && (gpl->onion_flag & GP_LAYER_ONIONSKIN) &&
- ((!playing) || (gpd->onion_flag & GP_ONION_GHOST_ALWAYS)) && (!cache_ob->is_dup_ob) &&
- (gpd->id.us <= 1)) {
- if ((!stl->storage->is_render) ||
- ((stl->storage->is_render) && (gpd->onion_flag & GP_ONION_GHOST_ALWAYS))) {
- gpencil_draw_onionskins(cache, vedata, ob, gpd, gpl, gpf);
- }
- }
- }
- /* draw normal strokes */
- const float alpha = GPENCIL_SIMPLIFY_TINT(scene, playing) ? 0.0f : gpl->tintcolor[3];
- const float tintcolor[4] = {gpl->tintcolor[0], gpl->tintcolor[1], gpl->tintcolor[2], alpha};
- gpencil_draw_strokes(
- cache, e_data, vedata, ob, gpd, gpl, gpf_eval, opacity, tintcolor, false, cache_ob);
- }
-
- /* create batchs and shading groups */
- gpencil_batches_ensure(cache);
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
-
- cache->is_dirty = false;
-}
-
-void gpencil_populate_particles(GPENCIL_e_data *e_data, GHash *gh_objects, void *vedata)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-
- /* add particles */
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
- if (cache_ob->is_dup_ob) {
- /* Reassign duplicate objects because memory for particles is not available
- * and need to use the original data-block and run-time data. */
- Object *ob = (Object *)BLI_ghash_lookup(gh_objects, cache_ob->name);
- if (ob) {
- cache_ob->ob = ob;
- cache_ob->gpd = (bGPdata *)ob->data;
- GpencilBatchCache *cache = ob->runtime.gpencil_cache;
- if (cache != NULL) {
- gpencil_shgroups_create(e_data, vedata, ob, cache, cache_ob);
- }
- }
- }
- }
-}
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 96560d986a0..80afbb5c7a3 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -29,11 +29,19 @@
#include "BKE_paint.h"
#include "BKE_shader_fx.h"
+#include "BKE_camera.h"
+#include "BKE_global.h" /* for G.debug */
+
+#include "BLI_link_utils.h"
+#include "BLI_memblock.h"
+
+#include "DNA_camera_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
#include "gpencil_engine.h"
@@ -44,1129 +52,904 @@
#include "UI_resources.h"
-extern char datatoc_gpencil_fill_vert_glsl[];
-extern char datatoc_gpencil_fill_frag_glsl[];
-extern char datatoc_gpencil_stroke_vert_glsl[];
-extern char datatoc_gpencil_stroke_geom_glsl[];
-extern char datatoc_gpencil_stroke_frag_glsl[];
-extern char datatoc_gpencil_zdepth_mix_frag_glsl[];
-extern char datatoc_gpencil_simple_mix_frag_glsl[];
-extern char datatoc_gpencil_point_vert_glsl[];
-extern char datatoc_gpencil_point_geom_glsl[];
-extern char datatoc_gpencil_point_frag_glsl[];
-extern char datatoc_gpencil_background_frag_glsl[];
-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[];
-
-extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
-
-extern char datatoc_common_colormanagement_lib_glsl[];
-extern char datatoc_common_view_lib_glsl[];
-
-/* *********** STATIC *********** */
-static GPENCIL_e_data e_data = {NULL}; /* Engine data */
-
/* *********** FUNCTIONS *********** */
-/* create a multisample buffer if not present */
-void gpencil_multisample_ensure(GPENCIL_Data *vedata, int rect_w, int rect_h)
+void GPENCIL_engine_init(void *ved)
{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_StorageList *stl = vedata->stl;
+ GPENCIL_TextureList *txl = vedata->txl;
GPENCIL_FramebufferList *fbl = vedata->fbl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
-
- short samples = stl->storage->multisamples;
-
- if (samples > 0) {
- if (!fbl->multisample_fb) {
- fbl->multisample_fb = GPU_framebuffer_create();
- if (fbl->multisample_fb) {
- if (txl->multisample_color == NULL) {
- txl->multisample_color = GPU_texture_create_2d_multisample(
- rect_w, rect_h, GPU_RGBA16F, NULL, samples, NULL);
- }
- if (txl->multisample_depth == NULL) {
- txl->multisample_depth = GPU_texture_create_2d_multisample(
- rect_w, rect_h, GPU_DEPTH24_STENCIL8, NULL, samples, NULL);
- }
- GPU_framebuffer_ensure_config(&fbl->multisample_fb,
- {GPU_ATTACHMENT_TEXTURE(txl->multisample_depth),
- GPU_ATTACHMENT_TEXTURE(txl->multisample_color)});
- }
- }
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ const DRWContextState *ctx = DRW_context_state_get();
+ const View3D *v3d = ctx->v3d;
+
+ if (!stl->pd) {
+ stl->pd = MEM_callocN(sizeof(GPENCIL_PrivateData), "GPENCIL_PrivateData");
+ }
+
+ if (txl->dummy_texture == NULL) {
+ float pixels[1][4] = {{1.0f, 0.0f, 1.0f, 1.0f}};
+ txl->dummy_texture = DRW_texture_create_2d(1, 1, GPU_RGBA8, DRW_TEX_WRAP, (float *)pixels);
+ }
+
+ GPENCIL_ViewLayerData *vldata = GPENCIL_view_layer_data_ensure();
+
+ /* Resize and reset memblocks. */
+ BLI_memblock_clear(vldata->gp_light_pool, gpencil_light_pool_free);
+ BLI_memblock_clear(vldata->gp_material_pool, gpencil_material_pool_free);
+ BLI_memblock_clear(vldata->gp_object_pool, NULL);
+ BLI_memblock_clear(vldata->gp_layer_pool, NULL);
+ BLI_memblock_clear(vldata->gp_vfx_pool, NULL);
+ BLI_memblock_clear(vldata->gp_maskbit_pool, NULL);
+
+ stl->pd->gp_light_pool = vldata->gp_light_pool;
+ stl->pd->gp_material_pool = vldata->gp_material_pool;
+ stl->pd->gp_maskbit_pool = vldata->gp_maskbit_pool;
+ stl->pd->gp_object_pool = vldata->gp_object_pool;
+ stl->pd->gp_layer_pool = vldata->gp_layer_pool;
+ stl->pd->gp_vfx_pool = vldata->gp_vfx_pool;
+ stl->pd->scene = ctx->scene;
+ stl->pd->last_light_pool = NULL;
+ stl->pd->last_material_pool = NULL;
+ stl->pd->tobjects.first = NULL;
+ stl->pd->tobjects.last = NULL;
+ stl->pd->tobjects_infront.first = NULL;
+ stl->pd->tobjects_infront.last = NULL;
+ stl->pd->sbuffer_tobjects.first = NULL;
+ stl->pd->sbuffer_tobjects.last = NULL;
+ stl->pd->dummy_tx = txl->dummy_texture;
+ stl->pd->draw_depth_only = !DRW_state_is_fbo();
+ stl->pd->draw_wireframe = (v3d && v3d->shading.type == OB_WIRE) && !stl->pd->draw_depth_only;
+ stl->pd->scene_depth_tx = stl->pd->draw_depth_only ? txl->dummy_texture : dtxl->depth;
+ stl->pd->scene_fb = dfbl->default_fb;
+ stl->pd->is_render = txl->render_depth_tx || (v3d && v3d->shading.type == OB_RENDER);
+ stl->pd->is_viewport = (v3d != NULL);
+ stl->pd->global_light_pool = gpencil_light_pool_add(stl->pd);
+ stl->pd->shadeless_light_pool = gpencil_light_pool_add(stl->pd);
+ /* Small HACK: we don't want the global pool to be reused,
+ * so we set the last light pool to NULL. */
+ stl->pd->last_light_pool = NULL;
+
+ bool use_scene_lights = false;
+ bool use_scene_world = false;
+
+ if (v3d) {
+ use_scene_lights = ((v3d->shading.type == OB_MATERIAL) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS_RENDER));
+
+ use_scene_world = ((v3d->shading.type == OB_MATERIAL) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_WORLD)) ||
+ ((v3d->shading.type == OB_RENDER) &&
+ (v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER));
+
+ stl->pd->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1;
+ /* Special case: If Vertex Paint mode, use always Vertex mode. */
+ if (v3d->shading.type == OB_SOLID && ctx->obact && ctx->obact->type == OB_GPENCIL &&
+ ctx->obact->mode == OB_MODE_VERTEX_GPENCIL) {
+ stl->pd->v3d_color_type = V3D_SHADING_VERTEX_COLOR;
+ }
+
+ copy_v3_v3(stl->pd->v3d_single_color, v3d->shading.single_color);
+
+ /* For non active frame, use only lines in multiedit mode. */
+ const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
+ stl->pd->use_multiedit_lines_only = !overlays_on ||
+ (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
+
+ const bool shmode_xray_support = v3d->shading.type <= OB_SOLID;
+ stl->pd->xray_alpha = (shmode_xray_support && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f;
+ }
+ else if (stl->pd->is_render) {
+ use_scene_lights = true;
+ use_scene_world = true;
+ stl->pd->use_multiedit_lines_only = false;
+ stl->pd->xray_alpha = 1.0f;
+ stl->pd->v3d_color_type = -1;
+ }
+
+ stl->pd->use_lighting = (v3d && v3d->shading.type > OB_SOLID) || stl->pd->is_render;
+ stl->pd->use_lights = use_scene_lights;
+
+ if (txl->render_depth_tx != NULL) {
+ stl->pd->scene_depth_tx = txl->render_depth_tx;
+ stl->pd->scene_fb = fbl->render_fb;
+ }
+
+ gpencil_light_ambient_add(stl->pd->shadeless_light_pool, (float[3]){1.0f, 1.0f, 1.0f});
+
+ World *world = ctx->scene->world;
+ if (world != NULL && use_scene_world) {
+ gpencil_light_ambient_add(stl->pd->global_light_pool, &world->horr);
+ }
+ else if (v3d) {
+ float world_light[3];
+ copy_v3_fl(world_light, v3d->shading.studiolight_intensity);
+ gpencil_light_ambient_add(stl->pd->global_light_pool, world_light);
+ }
+
+ float viewmatinv[4][4];
+ DRW_view_viewmat_get(NULL, viewmatinv, true);
+ copy_v3_v3(stl->pd->camera_z_axis, viewmatinv[2]);
+ copy_v3_v3(stl->pd->camera_pos, viewmatinv[3]);
+ stl->pd->camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]);
+
+ if (ctx && ctx->rv3d && v3d) {
+ stl->pd->camera = (ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL;
+ }
+ else {
+ stl->pd->camera = NULL;
}
}
-static void GPENCIL_create_framebuffers(void *vedata)
+void GPENCIL_cache_init(void *ved)
{
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
-
- /* Go full 32bits for rendering */
- eGPUTextureFormat fb_format = DRW_state_is_image_render() ? GPU_RGBA32F : GPU_RGBA16F;
-
- if (DRW_state_is_fbo()) {
- const float *viewport_size = DRW_viewport_size_get();
- const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
-
- /* create multisample framebuffer for AA */
- if ((stl->storage->framebuffer_flag & GP_FRAMEBUFFER_MULTISAMPLE) &&
- (stl->storage->multisamples > 0)) {
- gpencil_multisample_ensure(vedata, size[0], size[1]);
- }
-
- /* Framebufers for basic object drawing */
- if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_BASIC) {
- /* temp textures for ping-pong buffers */
- stl->g_data->temp_depth_tx_a = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
- stl->g_data->temp_color_tx_a = DRW_texture_pool_query_2d(
- size[0], size[1], fb_format, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->temp_fb_a,
- {
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_depth_tx_a),
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_a),
- });
-
- stl->g_data->temp_depth_tx_b = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
- stl->g_data->temp_color_tx_b = DRW_texture_pool_query_2d(
- size[0], size[1], fb_format, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->temp_fb_b,
- {
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_depth_tx_b),
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_b),
- });
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PassList *psl = vedata->psl;
+ GPENCIL_TextureList *txl = vedata->txl;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ DRWShadingGroup *grp;
- /* used for FX effects and Layer blending */
- stl->g_data->temp_depth_tx_fx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
- stl->g_data->temp_color_tx_fx = DRW_texture_pool_query_2d(
- size[0], size[1], fb_format, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->temp_fb_fx,
- {
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_depth_tx_fx),
- GPU_ATTACHMENT_TEXTURE(stl->g_data->temp_color_tx_fx),
- });
- }
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ pd->cfra = (int)DEG_get_ctime(draw_ctx->depsgraph);
+ pd->simplify_antialias = GPENCIL_SIMPLIFY_AA(draw_ctx->scene);
+ pd->use_layer_fb = false;
+ pd->use_object_fb = false;
+ pd->use_mask_fb = false;
+ pd->use_signed_fb = false;
+
+ if (draw_ctx->v3d) {
+ const bool hide_overlay = ((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) != 0);
+ const bool show_onion = ((draw_ctx->v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) != 0);
+ const bool playing = (draw_ctx->evil_C != NULL) ?
+ ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) !=
+ NULL :
+ false;
+ pd->do_onion = show_onion && !hide_overlay && !playing;
+ /* Save simplify flags (can change while drawing, so it's better to save). */
+ Scene *scene = draw_ctx->scene;
+ pd->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing);
+ pd->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, playing) ||
+ (draw_ctx->v3d->shading.type < OB_RENDER);
+
+ /* Fade Layer. */
+ const bool is_fade_layer = ((!hide_overlay) && (!pd->is_render) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS));
+ pd->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f;
+ /* Fade GPencil Objects. */
+ const bool is_fade_object = ((!hide_overlay) && (!pd->is_render) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL));
+ pd->fade_gp_object_opacity = (is_fade_object) ? draw_ctx->v3d->overlay.gpencil_paper_opacity :
+ -1.0f;
+ pd->fade_3d_object_opacity = ((!hide_overlay) && (!pd->is_render) &&
+ (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS)) ?
+ draw_ctx->v3d->overlay.gpencil_paper_opacity :
+ -1.0f;
+ }
+ else {
+ pd->do_onion = true;
+ pd->simplify_fill = false;
+ pd->simplify_fx = false;
+ pd->fade_layer_opacity = -1.0f;
+ }
- /* background framebuffer to speed up drawing process */
- if (stl->storage->framebuffer_flag & GP_FRAMEBUFFER_DRAW) {
- if (txl->background_color_tx == NULL) {
- stl->storage->background_ready = false;
+ {
+ pd->sbuffer_stroke = NULL;
+ pd->sbuffer_gpd = NULL;
+ pd->sbuffer_layer = NULL;
+ pd->stroke_batch = NULL;
+ pd->fill_batch = NULL;
+ pd->do_fast_drawing = false;
+
+ pd->obact = draw_ctx->obact;
+ if (pd->obact && pd->obact->type == OB_GPENCIL) {
+ /* Check if active object has a temp stroke data. */
+ bGPdata *gpd = (bGPdata *)pd->obact->data;
+ if (gpd->runtime.sbuffer_used > 0) {
+ pd->sbuffer_gpd = gpd;
+ pd->sbuffer_stroke = DRW_cache_gpencil_sbuffer_stroke_data_get(pd->obact);
+ pd->sbuffer_layer = BKE_gpencil_layer_active_get(pd->sbuffer_gpd);
+ pd->do_fast_drawing = false; /* TODO option */
}
- DRW_texture_ensure_2d(
- &txl->background_depth_tx, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_FILTER);
- DRW_texture_ensure_2d(
- &txl->background_color_tx, size[0], size[1], GPU_RGBA16F, DRW_TEX_FILTER);
- GPU_framebuffer_ensure_config(&fbl->background_fb,
- {
- GPU_ATTACHMENT_TEXTURE(txl->background_depth_tx),
- GPU_ATTACHMENT_TEXTURE(txl->background_color_tx),
- });
- }
- else {
- DRW_TEXTURE_FREE_SAFE(txl->background_depth_tx);
- DRW_TEXTURE_FREE_SAFE(txl->background_color_tx);
}
}
-}
-static void GPENCIL_create_shaders(void)
-{
- /* blank texture used if no texture defined for fill shader */
- if (!e_data.gpencil_blank_texture) {
- float rect[1][1][4] = {{{0.0f}}};
- e_data.gpencil_blank_texture = DRW_texture_create_2d(
- 1, 1, GPU_RGBA8, DRW_TEX_FILTER, (float *)rect);
+ if (pd->do_fast_drawing) {
+ pd->snapshot_buffer_dirty = (txl->snapshot_color_tx == NULL);
+ const float *size = DRW_viewport_size_get();
+ DRW_texture_ensure_2d(&txl->snapshot_depth_tx, size[0], size[1], GPU_DEPTH24_STENCIL8, 0);
+ DRW_texture_ensure_2d(&txl->snapshot_color_tx, size[0], size[1], GPU_R11F_G11F_B10F, 0);
+ DRW_texture_ensure_2d(&txl->snapshot_reveal_tx, size[0], size[1], GPU_R11F_G11F_B10F, 0);
+
+ GPU_framebuffer_ensure_config(&fbl->snapshot_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->snapshot_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->snapshot_color_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->snapshot_reveal_tx),
+ });
}
- /* normal fill shader */
- if (!e_data.gpencil_fill_sh) {
- e_data.gpencil_fill_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_fill_vert_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_gpencil_fill_frag_glsl,
- NULL},
- });
+ else {
+ /* Free uneeded buffers. */
+ GPU_FRAMEBUFFER_FREE_SAFE(fbl->snapshot_fb);
+ DRW_TEXTURE_FREE_SAFE(txl->snapshot_depth_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->snapshot_color_tx);
+ DRW_TEXTURE_FREE_SAFE(txl->snapshot_reveal_tx);
}
- /* normal stroke shader using geometry to display lines (line mode) */
- if (!e_data.gpencil_stroke_sh) {
- e_data.gpencil_stroke_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_stroke_vert_glsl, NULL},
- .geom = (const char *[]){datatoc_gpencil_stroke_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_gpencil_stroke_frag_glsl,
- NULL},
- });
- }
+ {
+ DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS;
+ DRW_PASS_CREATE(psl->merge_depth_ps, state);
- /* dot/rectangle mode for normal strokes using geometry */
- if (!e_data.gpencil_point_sh) {
- e_data.gpencil_point_sh = GPU_shader_create_from_arrays({
- .vert =
- (const char *[]){datatoc_common_view_lib_glsl, datatoc_gpencil_point_vert_glsl, NULL},
- .geom = (const char *[]){datatoc_gpencil_point_geom_glsl, NULL},
- .frag = (const char *[]){datatoc_common_colormanagement_lib_glsl,
- datatoc_gpencil_point_frag_glsl,
- NULL},
- });
- }
- /* used for edit points or strokes with one point only */
- if (!e_data.gpencil_edit_point_sh) {
- e_data.gpencil_edit_point_sh = DRW_shader_create_with_lib(datatoc_gpencil_edit_point_vert_glsl,
- datatoc_gpencil_edit_point_geom_glsl,
- datatoc_gpencil_edit_point_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
+ GPUShader *sh = GPENCIL_shader_depth_merge_get();
+ grp = DRW_shgroup_create(sh, psl->merge_depth_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "depthBuf", &pd->depth_tx);
+ DRW_shgroup_uniform_bool(grp, "strokeOrder3d", &pd->is_stroke_order_3d, 1);
+ DRW_shgroup_uniform_vec4(grp, "gpModelMatrix[0]", pd->object_bound_mat[0], 4);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT;
+ DRW_PASS_CREATE(psl->mask_invert_ps, state);
- /* used for edit lines for edit modes */
- if (!e_data.gpencil_line_sh) {
- e_data.gpencil_line_sh = DRW_shader_create_with_lib(
- datatoc_gpencil_edit_point_vert_glsl,
- NULL,
- datatoc_gpu_shader_3D_smooth_color_frag_glsl,
- datatoc_common_view_lib_glsl,
- NULL);
+ GPUShader *sh = GPENCIL_shader_mask_invert_get();
+ grp = DRW_shgroup_create(sh, psl->mask_invert_ps);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- /* used to filling during drawing */
- if (!e_data.gpencil_drawing_fill_sh) {
- e_data.gpencil_drawing_fill_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
- }
+ Camera *cam = (pd->camera != NULL) ? pd->camera->data : NULL;
- /* full screen for mix zdepth*/
- if (!e_data.gpencil_fullscreen_sh) {
- e_data.gpencil_fullscreen_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_zdepth_mix_frag_glsl, NULL);
- }
- if (!e_data.gpencil_simple_fullscreen_sh) {
- e_data.gpencil_simple_fullscreen_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_simple_mix_frag_glsl, NULL);
- }
+ /* Pseudo DOF setup. */
+ if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) {
+ const float *vp_size = DRW_viewport_size_get();
+ float fstop = cam->dof.aperture_fstop;
+ float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
+ float focus_dist = BKE_camera_object_dof_distance(pd->camera);
+ float focal_len = cam->lens;
- /* blend */
- if (!e_data.gpencil_blend_fullscreen_sh) {
- e_data.gpencil_blend_fullscreen_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_blend_frag_glsl, NULL);
- }
+ const float scale_camera = 0.001f;
+ /* we want radius here for the aperture number */
+ float aperture = 0.5f * scale_camera * focal_len / fstop;
+ float focal_len_scaled = scale_camera * focal_len;
+ float sensor_scaled = scale_camera * sensor;
- /* 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);
+ if (draw_ctx->rv3d != NULL) {
+ sensor_scaled *= draw_ctx->rv3d->viewcamtexcofac[0];
+ }
+
+ pd->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled));
+ pd->dof_params[1] *= vp_size[0] / sensor_scaled;
+ pd->dof_params[0] = -focus_dist * pd->dof_params[1];
}
- if (!e_data.gpencil_paper_sh) {
- e_data.gpencil_paper_sh = DRW_shader_create_fullscreen(datatoc_gpencil_paper_frag_glsl, NULL);
+ else {
+ /* Disable DoF blur scalling. */
+ pd->camera = NULL;
}
}
-void GPENCIL_engine_init(void *vedata)
+#define DRAW_NOW 2
+
+typedef struct gpIterPopulateData {
+ Object *ob;
+ GPENCIL_tObject *tgp_ob;
+ GPENCIL_PrivateData *pd;
+ GPENCIL_MaterialPool *matpool;
+ DRWShadingGroup *grp;
+ /* Last material UBO bound. Used to avoid uneeded buffer binding. */
+ GPUUniformBuffer *ubo_mat;
+ GPUUniformBuffer *ubo_lights;
+ /* Last texture bound. */
+ GPUTexture *tex_fill;
+ GPUTexture *tex_stroke;
+ /* Offset in the material pool to the first material of this object. */
+ int mat_ofs;
+ /* Is the sbuffer call need to be issued. */
+ int do_sbuffer_call;
+ /* Indices to do correct insertion of the sbuffer stroke. */
+ int stroke_index_last;
+ int stroke_index_offset;
+ /* Infos for call batching. */
+ struct GPUBatch *geom;
+ bool instancing;
+ int vfirst, vcount;
+} gpIterPopulateData;
+
+#define DISABLE_BATCHING 0
+
+static void gpencil_drawcall_flush(gpIterPopulateData *iter)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- /* init storage */
- if (!stl->storage) {
- stl->storage = MEM_callocN(sizeof(GPENCIL_Storage), "GPENCIL_Storage");
- stl->storage->shade_render[0] = OB_RENDER;
- stl->storage->shade_render[1] = 0;
+#if !DISABLE_BATCHING
+ if (iter->geom != NULL) {
+ if (iter->instancing) {
+ DRW_shgroup_call_instance_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
+ }
+ else {
+ DRW_shgroup_call_range(iter->grp, iter->ob, iter->geom, iter->vfirst, iter->vcount);
+ }
}
+#endif
- /* Not supported anymore. */
- stl->storage->multisamples = 0;
-
- /* create shaders */
- GPENCIL_create_shaders();
- GPENCIL_create_fx_shaders(&e_data);
+ iter->geom = NULL;
+ iter->vfirst = -1;
+ iter->vcount = 0;
}
-static void GPENCIL_engine_free(void)
+/* Group drawcalls that are consecutive and with the same type. Reduces GPU driver overhead. */
+static void gp_drawcall_add(
+ gpIterPopulateData *iter, struct GPUBatch *geom, bool instancing, int v_first, int v_count)
{
- /* only free custom shaders, builtin shaders are freed in blender close */
- DRW_SHADER_FREE_SAFE(e_data.gpencil_fill_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_stroke_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_point_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_edit_point_sh);
- DRW_SHADER_FREE_SAFE(e_data.gpencil_line_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);
-
- DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
-
- /* effects */
- GPENCIL_delete_fx_shaders(&e_data);
+#if DISABLE_BATCHING
+ if (instancing) {
+ DRW_shgroup_call_instance_range(iter->grp, iter->ob, geom, v_first, v_count);
+ }
+ else {
+ DRW_shgroup_call_range(iter->grp, iter->ob, geom, v_first, v_count);
+ }
+#endif
+
+ int last = iter->vfirst + iter->vcount;
+ /* Interupt drawcall grouping if the sequence is not consecutive. */
+ if ((geom != iter->geom) || (v_first - last > 3)) {
+ gpencil_drawcall_flush(iter);
+ }
+ iter->geom = geom;
+ iter->instancing = instancing;
+ if (iter->vfirst == -1) {
+ iter->vfirst = v_first;
+ }
+ iter->vcount = v_first + v_count - iter->vfirst;
}
-/* Helper: Check if the main overlay and onion switches are enabled in any screen.
- *
- * This is required to generate the onion skin and limit the times the cache is updated because the
- * cache is generated only in the first screen and if the first screen has the onion disabled the
- * cache for onion skin is not generated. The loop adds time, but always is faster than regenerate
- * the cache all the times.
- */
-static void gpencil_check_screen_switches(const DRWContextState *draw_ctx,
- GPENCIL_StorageList *stl)
+static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ void *thunk);
+
+static void gp_sbuffer_cache_populate(gpIterPopulateData *iter)
{
- stl->storage->is_main_overlay = false;
- stl->storage->is_main_onion = false;
- /* Check if main onion switch is enabled in any screen. */
- Main *bmain = CTX_data_main(draw_ctx->evil_C);
-
- for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
- if (v3d == NULL) {
- continue;
- }
- if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
- stl->storage->is_main_overlay = true;
- }
- if (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) {
- stl->storage->is_main_onion = true;
- }
- }
- /* If found, don't need loop more. */
- if ((stl->storage->is_main_overlay) && (stl->storage->is_main_onion)) {
- return;
- }
- }
- }
+ iter->do_sbuffer_call = DRAW_NOW;
+ /* In order to draw the sbuffer stroke correctly mixed with other strokes,
+ * we need to offset the stroke index of the sbuffer stroke and the subsequent strokes.
+ * Remember, sbuffer stroke indices start from 0. So we add last index to avoid
+ * masking issues. */
+ iter->grp = DRW_shgroup_create_sub(iter->grp);
+ DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", iter->ubo_mat);
+ DRW_shgroup_uniform_float_copy(iter->grp, "strokeIndexOffset", iter->stroke_index_last);
+
+ const DRWContextState *ctx = DRW_context_state_get();
+ ToolSettings *ts = ctx->scene->toolsettings;
+ if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) {
+ /* In this case we can't do correct projection during stroke. We just disable depth test. */
+ DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx);
+ }
+
+ gpencil_stroke_cache_populate(NULL, NULL, iter->pd->sbuffer_stroke, iter);
+ gpencil_drawcall_flush(iter);
+
+ iter->stroke_index_offset = iter->pd->sbuffer_stroke->totpoints + 1;
+ iter->do_sbuffer_call = 0;
}
-void GPENCIL_cache_init(void *vedata)
+static void gpencil_layer_cache_populate(bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *UNUSED(gps),
+ void *thunk)
{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
- View3D *v3d = draw_ctx->v3d;
- Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
- const View3DCursor *cursor = &scene->cursor;
-
- /* Special handling for when active object is GP object (e.g. for draw mode) */
- Object *obact = draw_ctx->obact;
- bGPdata *obact_gpd = NULL;
- MaterialGPencilStyle *gp_style = NULL;
-
- if (obact && (obact->type == OB_GPENCIL) && (obact->data)) {
- obact_gpd = (bGPdata *)obact->data;
- /* use the brush material */
- Material *ma = BKE_gpencil_object_material_get_from_brush(obact, brush);
- if (ma != NULL) {
- gp_style = ma->gp_style;
- }
- /* this is not common, but avoid any special situations when brush could be without material */
- if (gp_style == NULL) {
- gp_style = BKE_gpencil_material_settings(obact, obact->actcol);
- }
- }
+ gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
+ GPENCIL_PrivateData *pd = iter->pd;
+ bGPdata *gpd = (bGPdata *)iter->ob->data;
- if (!stl->g_data) {
- /* Alloc transient pointers */
- stl->g_data = MEM_mallocN(sizeof(g_data), "g_data");
- stl->storage->xray = GP_XRAY_FRONT; /* used for drawing */
- stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID; /* used for drawing */
+ gpencil_drawcall_flush(iter);
+
+ if (iter->do_sbuffer_call) {
+ gp_sbuffer_cache_populate(iter);
}
- stl->storage->tonemapping = 0;
-
- stl->g_data->shgrps_edit_line = NULL;
- stl->g_data->shgrps_edit_point = NULL;
-
- /* reset textures */
- stl->g_data->batch_buffer_stroke = NULL;
- stl->g_data->batch_buffer_fill = NULL;
- stl->g_data->batch_buffer_ctrlpoint = NULL;
- stl->g_data->batch_grid = NULL;
-
- if (!stl->shgroups) {
- /* Alloc maximum size because count strokes is very slow and can be very complex due onion
- * skinning.
- */
- stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup");
+ else {
+ iter->do_sbuffer_call = !pd->do_fast_drawing && (gpd == pd->sbuffer_gpd) &&
+ (gpl == pd->sbuffer_layer) &&
+ (gpf == NULL || gpf->runtime.onion_id == 0.0f);
}
- /* init gp objects cache */
- stl->g_data->gp_cache_used = 0;
- stl->g_data->gp_cache_size = 0;
- stl->g_data->gp_object_cache = NULL;
- stl->g_data->do_instances = false;
+ GPENCIL_tLayer *tgp_layer = gpencil_layer_cache_add(pd, iter->ob, gpl, gpf, iter->tgp_ob);
- {
- /* Stroke pass 2D */
- psl->stroke_pass_2d = DRW_pass_create("GPencil Stroke Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- stl->storage->shgroup_id = 0;
- /* Stroke pass 3D */
- psl->stroke_pass_3d = DRW_pass_create("GPencil Stroke Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
- stl->storage->shgroup_id = 0;
-
- /* edit pass */
- psl->edit_pass = DRW_pass_create("GPencil Edit Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
-
- /* detect if playing animation */
- if (draw_ctx->evil_C) {
-
- bool playing = ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != NULL;
- if (playing != stl->storage->is_playing) {
- stl->storage->reset_cache = true;
- }
- stl->storage->is_playing = playing;
+ const bool use_lights = pd->use_lighting && ((gpl->flag & GP_LAYER_USE_LIGHTS) != 0) &&
+ (iter->ob->dtx & OB_USE_GPENCIL_LIGHTS);
- /* Found if main overlay and onion switches are enabled in any screen. */
- gpencil_check_screen_switches(draw_ctx, stl);
- }
- else {
- stl->storage->is_playing = false;
- stl->storage->reset_cache = false;
- stl->storage->is_main_overlay = false;
- stl->storage->is_main_onion = false;
- }
- /* save render state */
- stl->storage->is_render = DRW_state_is_scene_render();
- stl->storage->is_mat_preview = (bool)stl->storage->is_render &&
- STREQ(scene->id.name + 2, "preview");
-
- if (obact_gpd) {
- /* for some reason, when press play there is a delay in the animation flag check
- * and this produces errors. To be sure, we set cache as dirty because the frame
- * is changing.
- */
- if (stl->storage->is_playing == true) {
- obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- /* if render, set as dirty to update all data */
- else if (stl->storage->is_render == true) {
- obact_gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- }
+ iter->ubo_lights = (use_lights) ? pd->global_light_pool->ubo : pd->shadeless_light_pool->ubo;
- /* save simplify flags (can change while drawing, so it's better to save) */
- stl->storage->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, stl->storage->is_playing);
- stl->storage->simplify_modif = GPENCIL_SIMPLIFY_MODIF(scene, stl->storage->is_playing);
- stl->storage->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, stl->storage->is_playing);
- stl->storage->simplify_blend = GPENCIL_SIMPLIFY_BLEND(scene, stl->storage->is_playing);
+ gpencil_material_resources_get(iter->matpool, 0, NULL, NULL, &iter->ubo_mat);
- /* xray mode */
- if (v3d) {
- stl->storage->is_xray = XRAY_ACTIVE(v3d);
- }
- else {
- stl->storage->is_xray = 0;
- }
+ /* Iterator dependent uniforms. */
+ DRWShadingGroup *grp = iter->grp = tgp_layer->base_shgrp;
+ DRW_shgroup_uniform_block_persistent(grp, "gpLightBlock", iter->ubo_lights);
+ DRW_shgroup_uniform_block(grp, "gpMaterialBlock", iter->ubo_mat);
+ DRW_shgroup_uniform_texture(grp, "gpFillTexture", iter->tex_fill);
+ DRW_shgroup_uniform_texture(grp, "gpStrokeTexture", iter->tex_stroke);
+ DRW_shgroup_uniform_int_copy(grp, "gpMaterialOffset", iter->mat_ofs);
+ DRW_shgroup_uniform_float_copy(grp, "strokeIndexOffset", iter->stroke_index_offset);
+}
- /* save pixsize */
- stl->storage->pixsize = DRW_viewport_pixelsize_get();
- if ((!DRW_state_is_opengl_render()) && (stl->storage->is_render)) {
- stl->storage->pixsize = &stl->storage->render_pixsize;
- }
+static void gpencil_stroke_cache_populate(bGPDlayer *gpl,
+ bGPDframe *gpf,
+ bGPDstroke *gps,
+ void *thunk)
+{
+ gpIterPopulateData *iter = (gpIterPopulateData *)thunk;
- /* detect if painting session */
- if ((obact_gpd) && (obact_gpd->flag & GP_DATA_STROKE_PAINTMODE) &&
- (stl->storage->is_playing == false)) {
- /* need the original to avoid cow overhead while drawing */
- bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&obact_gpd->id);
- if (((gpd_orig->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) &&
- (gpd_orig->runtime.sbuffer_used > 0) &&
- ((gpd_orig->flag & GP_DATA_STROKE_POLYGON) == 0) && !DRW_state_is_depth() &&
- (stl->storage->background_ready == true)) {
- stl->g_data->session_flag |= GP_DRW_PAINT_PAINTING;
- }
- else {
- stl->g_data->session_flag = GP_DRW_PAINT_IDLE;
- }
- }
- else {
- /* if not drawing mode */
- stl->g_data->session_flag = GP_DRW_PAINT_HOLD;
- }
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
- if (gp_style) {
- stl->storage->stroke_style = gp_style->stroke_style;
- stl->storage->color_type = GPENCIL_COLOR_SOLID;
- if (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) {
- stl->storage->color_type = GPENCIL_COLOR_TEXTURE;
- if (gp_style->flag & GP_STYLE_STROKE_PATTERN) {
- stl->storage->color_type = GPENCIL_COLOR_PATTERN;
- }
- }
+ bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
+ bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
+ bool show_fill = (gps->tot_triangles > 0) && ((gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0) &&
+ (!iter->pd->simplify_fill) && ((gps->flag & GP_STROKE_NOFILL) == 0);
+
+ bool only_lines = gpl && gpf && gpl->actframe != gpf && iter->pd->use_multiedit_lines_only;
+
+ if (hide_material || (!show_stroke && !show_fill) || only_lines) {
+ return;
+ }
+
+ GPUUniformBuffer *ubo_mat;
+ GPUTexture *tex_stroke, *tex_fill;
+ gpencil_material_resources_get(
+ iter->matpool, iter->mat_ofs + gps->mat_nr, &tex_stroke, &tex_fill, &ubo_mat);
+
+ bool resource_changed = (iter->ubo_mat != ubo_mat) ||
+ (tex_fill && (iter->tex_fill != tex_fill)) ||
+ (tex_stroke && (iter->tex_stroke != tex_stroke));
+
+ if (resource_changed) {
+ gpencil_drawcall_flush(iter);
+
+ iter->grp = DRW_shgroup_create_sub(iter->grp);
+ if (iter->ubo_mat != ubo_mat) {
+ DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", ubo_mat);
+ iter->ubo_mat = ubo_mat;
}
- else {
- stl->storage->stroke_style = GP_STYLE_STROKE_STYLE_SOLID;
- stl->storage->color_type = GPENCIL_COLOR_SOLID;
+ if (tex_fill) {
+ DRW_shgroup_uniform_texture(iter->grp, "gpFillTexture", tex_fill);
+ iter->tex_fill = tex_fill;
}
-
- /* drawing buffer pass for drawing the stroke that is being drawing by the user. The data
- * is stored in sbuffer
- */
- psl->drawing_pass = DRW_pass_create("GPencil Drawing Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS |
- DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_NEQUAL);
-
- /* full screen pass to combine the result with default framebuffer */
- struct GPUBatch *quad = DRW_cache_fullscreen_quad_get();
- psl->mix_pass = DRW_pass_create("GPencil Mix Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
- DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.gpencil_fullscreen_sh, psl->mix_pass);
- DRW_shgroup_call(mix_shgrp, quad, NULL);
- DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeColor", &stl->g_data->input_color_tx);
- DRW_shgroup_uniform_texture_ref(mix_shgrp, "strokeDepth", &stl->g_data->input_depth_tx);
- DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
- DRW_shgroup_uniform_int(mix_shgrp, "do_select", &stl->storage->do_select_outline, 1);
- DRW_shgroup_uniform_vec4(mix_shgrp, "select_color", stl->storage->select_color, 1);
-
- /* Mix pass no blend used to copy between passes. A separated pass is required
- * because if mix_pass is used, the accumulation of blend degrade the colors.
- *
- * This pass is used too to take the snapshot used for background_pass. This image
- * will be used as the background while the user is drawing.
- */
- psl->mix_pass_noblend = DRW_pass_create("GPencil Mix Pass no blend",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS);
- DRWShadingGroup *mix_shgrp_noblend = DRW_shgroup_create(e_data.gpencil_fullscreen_sh,
- psl->mix_pass_noblend);
- DRW_shgroup_call(mix_shgrp_noblend, quad, NULL);
- DRW_shgroup_uniform_texture_ref(
- mix_shgrp_noblend, "strokeColor", &stl->g_data->input_color_tx);
- DRW_shgroup_uniform_texture_ref(
- mix_shgrp_noblend, "strokeDepth", &stl->g_data->input_depth_tx);
- DRW_shgroup_uniform_int(mix_shgrp_noblend, "tonemapping", &stl->storage->tonemapping, 1);
- DRW_shgroup_uniform_int(mix_shgrp_noblend, "do_select", &stl->storage->do_select_outline, 1);
- DRW_shgroup_uniform_vec4(mix_shgrp_noblend, "select_color", stl->storage->select_color, 1);
-
- /* Painting session pass (used only to speedup while the user is drawing )
- * This pass is used to show the snapshot of the current grease pencil strokes captured
- * when the user starts to draw (see comments above).
- * In this way, the previous strokes don't need to be redraw and the drawing process
- * is far to agile.
- */
- psl->background_pass = DRW_pass_create("GPencil Background Painting Session Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
- DRWShadingGroup *background_shgrp = DRW_shgroup_create(e_data.gpencil_background_sh,
- psl->background_pass);
- DRW_shgroup_call(background_shgrp, quad, NULL);
- DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeColor", &txl->background_color_tx);
- DRW_shgroup_uniform_texture_ref(background_shgrp, "strokeDepth", &txl->background_depth_tx);
-
- /* pass for drawing paper (only if viewport)
- * In render, the v3d is null so the paper is disabled
- * The paper is way to isolate the drawing in complex scene and to have a cleaner
- * drawing area.
- */
- if (v3d) {
- psl->paper_pass = DRW_pass_create("GPencil Paper Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
- DRWShadingGroup *paper_shgrp = DRW_shgroup_create(e_data.gpencil_paper_sh, psl->paper_pass);
- DRW_shgroup_call(paper_shgrp, quad, NULL);
- DRW_shgroup_uniform_vec3(paper_shgrp, "color", v3d->shading.background_color, 1);
- DRW_shgroup_uniform_float(paper_shgrp, "opacity", &v3d->overlay.gpencil_paper_opacity, 1);
+ if (tex_stroke) {
+ DRW_shgroup_uniform_texture(iter->grp, "gpStrokeTexture", tex_stroke);
+ iter->tex_stroke = tex_stroke;
}
- /* grid pass */
- if ((v3d) && (obact) && (obact->type == OB_GPENCIL)) {
- psl->grid_pass = DRW_pass_create("GPencil Grid Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS);
- stl->g_data->shgrps_grid = DRW_shgroup_create(e_data.gpencil_line_sh, psl->grid_pass);
-
- /* define grid orientation */
- switch (ts->gp_sculpt.lock_axis) {
- case GP_LOCKAXIS_VIEW: {
- /* align always to view */
- invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat);
- /* copy ob location */
- copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]);
- break;
- }
- case GP_LOCKAXIS_CURSOR: {
- float scale[3] = {1.0f, 1.0f, 1.0f};
- loc_eul_size_to_mat4(
- stl->storage->grid_matrix, cursor->location, cursor->rotation_euler, scale);
- break;
- }
- default: {
- copy_m4_m4(stl->storage->grid_matrix, obact->obmat);
- break;
- }
- }
+ /* TODO(fclem): This is a quick workaround but
+ * ideally we should have this as a permanent bind. */
+ const bool is_masked = iter->tgp_ob->layers.last->mask_bits != NULL;
+ GPUTexture **mask_tex = (is_masked) ? &iter->pd->mask_tx : &iter->pd->dummy_tx;
+ DRW_shgroup_uniform_texture_ref(iter->grp, "gpMaskTexture", mask_tex);
+ }
- /* Move the origin to Object or Cursor */
- if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) {
- copy_v3_v3(stl->storage->grid_matrix[3], cursor->location);
- }
- else {
- copy_v3_v3(stl->storage->grid_matrix[3], obact->obmat[3]);
- }
- DRW_shgroup_uniform_mat4(
- stl->g_data->shgrps_grid, "gpModelMatrix", stl->storage->grid_matrix);
- }
+ bool do_sbuffer = (iter->do_sbuffer_call == DRAW_NOW);
- /* blend layers pass */
- psl->blend_pass = DRW_pass_create("GPencil Blend Layers Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- 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(blend_shgrp, quad, NULL);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1);
- DRW_shgroup_uniform_int(blend_shgrp, "mask_layer", &stl->storage->mask_layer, 1);
- DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
-
- /* create effects passes */
- if (!stl->storage->simplify_fx) {
- GPENCIL_create_fx_passes(psl);
- }
+ if (show_fill) {
+ GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_fill_get(iter->ob) :
+ DRW_cache_gpencil_fills_get(iter->ob, iter->pd->cfra);
+ int vfirst = gps->runtime.fill_start * 3;
+ int vcount = gps->tot_triangles * 3;
+ gp_drawcall_add(iter, geom, false, vfirst, vcount);
}
+
+ if (show_stroke) {
+ GPUBatch *geom = do_sbuffer ? DRW_cache_gpencil_sbuffer_stroke_get(iter->ob) :
+ DRW_cache_gpencil_strokes_get(iter->ob, iter->pd->cfra);
+ /* Start one vert before to have gl_InstanceID > 0 (see shader). */
+ int vfirst = gps->runtime.stroke_start - 1;
+ /* Include "potential" cyclic vertex and start adj vertex (see shader). */
+ int vcount = gps->totpoints + 1 + 1;
+ gp_drawcall_add(iter, geom, true, vfirst, vcount);
+ }
+
+ iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1;
}
-static void gpencil_add_draw_data(void *vedata, Object *ob)
+static void gp_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- bGPdata *gpd = (bGPdata *)ob->data;
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- const DRWContextState *draw_ctx = DRW_context_state_get();
- const View3D *v3d = draw_ctx->v3d;
+ bGPdata *gpd = (bGPdata *)iter->ob->data;
+ if (gpd != iter->pd->sbuffer_gpd) {
+ return;
+ }
- int i = stl->g_data->gp_cache_used - 1;
- tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
+ GPENCIL_TextureList *txl = vedata->txl;
+ GPUTexture *depth_texture = iter->pd->scene_depth_tx;
+ GPENCIL_tObject *last_tgp_ob = iter->pd->tobjects.last;
+ /* Create another temp object that only contain the stroke. */
+ iter->tgp_ob = gpencil_object_cache_add(iter->pd, iter->ob);
+ /* Remove from the main list. */
+ iter->pd->tobjects.last = last_tgp_ob;
+ last_tgp_ob->next = NULL;
+ /* Add to sbuffer tgpobject list. */
+ BLI_LINKS_APPEND(&iter->pd->sbuffer_tobjects, iter->tgp_ob);
+ /* Remove depth test with scene (avoid self occlusion). */
+ iter->pd->scene_depth_tx = txl->dummy_texture;
- if (!cache_ob->is_dup_ob) {
- /* fill shading groups */
- if ((!is_multiedit) || (stl->storage->is_render)) {
- gpencil_populate_datablock(&e_data, vedata, ob, cache_ob);
- }
- else {
- gpencil_populate_multiedit(&e_data, vedata, ob, cache_ob);
- }
- }
+ gpencil_layer_cache_populate(
+ iter->pd->sbuffer_layer, iter->pd->sbuffer_layer->actframe, NULL, iter);
- /* FX passses */
- cache_ob->has_fx = false;
- if ((!stl->storage->simplify_fx) &&
- ((!ELEM(cache_ob->shading_type[0], OB_WIRE, OB_SOLID)) ||
- ((v3d->spacetype != SPACE_VIEW3D))) &&
- (BKE_shaderfx_has_gpencil(ob))) {
- cache_ob->has_fx = true;
- if ((!stl->storage->simplify_fx) && (!is_multiedit)) {
- gpencil_fx_prepare(&e_data, vedata, cache_ob);
- }
+ const DRWContextState *ctx = DRW_context_state_get();
+ ToolSettings *ts = ctx->scene->toolsettings;
+ if (ts->gpencil_v3d_align & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)) {
+ /* In this case we can't do correct projection during stroke. We just disable depth test. */
+ DRW_shgroup_uniform_texture(iter->grp, "gpSceneDepthTexture", iter->pd->dummy_tx);
}
+
+ iter->do_sbuffer_call = DRAW_NOW;
+ gpencil_stroke_cache_populate(NULL, NULL, iter->pd->sbuffer_stroke, iter);
+ gpencil_drawcall_flush(iter);
+
+ gpencil_vfx_cache_populate(vedata, iter->ob, iter->tgp_ob);
+
+ /* Restore state. */
+ iter->do_sbuffer_call = 0;
+ iter->pd->scene_depth_tx = depth_texture;
}
-void GPENCIL_cache_populate(void *vedata, Object *ob)
+void GPENCIL_cache_populate(void *ved, Object *ob)
{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_TextureList *txl = vedata->txl;
+
/* object must be visible */
if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) {
return;
}
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- Scene *scene = draw_ctx->scene;
- ToolSettings *ts = scene->toolsettings;
- View3D *v3d = draw_ctx->v3d;
+ if (ob->data && (ob->type == OB_GPENCIL) && (ob->dt >= OB_SOLID)) {
+ gpIterPopulateData iter = {0};
+ iter.ob = ob;
+ iter.pd = pd;
+ iter.tgp_ob = gpencil_object_cache_add(pd, ob);
+ iter.matpool = gpencil_material_pool_create(pd, ob, &iter.mat_ofs);
+ iter.tex_fill = txl->dummy_texture;
+ iter.tex_stroke = txl->dummy_texture;
- if (ob->type == OB_GPENCIL && ob->data) {
+ /* Special case for rendering onion skin. */
bGPdata *gpd = (bGPdata *)ob->data;
+ bool do_onion = (!pd->is_render) ? pd->do_onion : (gpd->onion_flag & GP_ONION_GHOST_ALWAYS);
- /* enable multisample and basic framebuffer creation */
- stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_MULTISAMPLE;
- stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_BASIC;
-
- /* when start/stop animation the cache must be set as dirty to reset all data */
- if (stl->storage->reset_cache) {
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- stl->storage->reset_cache = false;
- }
+ BKE_gpencil_visible_stroke_iter(ob,
+ gpencil_layer_cache_populate,
+ gpencil_stroke_cache_populate,
+ &iter,
+ do_onion,
+ pd->cfra);
- if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) {
- /* bound box object are not visible, only external box*/
- if (ob->dt != OB_BOUNDBOX) {
- /* save gp objects for drawing later */
- stl->g_data->gp_object_cache = gpencil_object_cache_add(stl->g_data->gp_object_cache,
- ob,
- &stl->g_data->gp_cache_size,
- &stl->g_data->gp_cache_used);
-
- /* enable instance loop */
- if (!stl->g_data->do_instances) {
- tGPencilObjectCache *cache_ob =
- &stl->g_data->gp_object_cache[stl->g_data->gp_cache_used - 1];
- stl->g_data->do_instances = cache_ob->is_dup_ob;
- }
-
- /* load drawing data */
- gpencil_add_draw_data(vedata, ob);
- }
- }
+ gpencil_drawcall_flush(&iter);
- /* draw current painting strokes
- * (only if region is equal to originated paint region)
- *
- * Need to use original data because to use the copy of data, the paint
- * operator must update depsgraph and this makes that first events of the
- * mouse are missed if the datablock is very big due the time required to
- * copy the datablock. The search of the original data is faster than a
- * full datablock copy.
- * Using the original data doesn't require a copy and the feel when drawing
- * is far better.
- */
-
- bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
- if ((draw_ctx->obact == ob) &&
- ((gpd_orig->runtime.ar == NULL) || (gpd_orig->runtime.ar == draw_ctx->region))) {
- gpencil_populate_buffer_strokes(&e_data, vedata, ts, ob);
+ if (iter.do_sbuffer_call) {
+ gp_sbuffer_cache_populate(&iter);
}
- /* grid */
- if ((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID) &&
- (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact) &&
- ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0) &&
- ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) == 0)) {
+ gpencil_vfx_cache_populate(vedata, ob, iter.tgp_ob);
- stl->g_data->batch_grid = gpencil_get_grid(ob);
- DRW_shgroup_call(stl->g_data->shgrps_grid, stl->g_data->batch_grid, NULL);
+ if (pd->do_fast_drawing) {
+ gp_sbuffer_cache_populate_fast(vedata, &iter);
}
}
+
+ if (ob->type == OB_LAMP && pd->use_lights) {
+ gpencil_light_pool_populate(pd->global_light_pool, ob);
+ }
}
-void GPENCIL_cache_finish(void *vedata)
+void GPENCIL_cache_finish(void *ved)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- tGPencilObjectCache *cache_ob = NULL;
- Object *ob = NULL;
-
- /* create data for instances */
- if (stl->g_data->do_instances) {
- GHash *gh_objects = BLI_ghash_str_new(__func__);
- /* create hash of real object (non duplicated) */
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- cache_ob = &stl->g_data->gp_object_cache[i];
- if (!cache_ob->is_dup_ob) {
- ob = cache_ob->ob;
- char *name = BKE_id_to_unique_string_key(&ob->id);
- BLI_ghash_insert(gh_objects, name, cache_ob->ob);
- }
- }
-
- /* draw particles */
- gpencil_populate_particles(&e_data, gh_objects, vedata);
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
- /* free hash */
- BLI_ghash_free(gh_objects, MEM_freeN, NULL);
+ /* Upload UBO data. */
+ BLI_memblock_iter iter;
+ BLI_memblock_iternew(pd->gp_material_pool, &iter);
+ GPENCIL_MaterialPool *pool;
+ while ((pool = (GPENCIL_MaterialPool *)BLI_memblock_iterstep(&iter))) {
+ GPU_uniformbuffer_update(pool->ubo, pool->mat_data);
}
- if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) {
- stl->storage->framebuffer_flag |= GP_FRAMEBUFFER_DRAW;
+ BLI_memblock_iternew(pd->gp_light_pool, &iter);
+ GPENCIL_LightPool *lpool;
+ while ((lpool = (GPENCIL_LightPool *)BLI_memblock_iterstep(&iter))) {
+ GPU_uniformbuffer_update(lpool->ubo, lpool->light_data);
}
- /* create framebuffers (only for normal drawing) */
- if (!DRW_state_is_select() || !DRW_state_is_depth()) {
- GPENCIL_create_framebuffers(vedata);
+ /* Sort object by decreasing Z to avoid most of alpha ordering issues. */
+ gpencil_object_cache_sort(pd);
+
+ /* Create framebuffers only if needed. */
+ if (pd->tobjects.first) {
+ eGPUTextureFormat format = pd->use_signed_fb ? GPU_RGBA16F : GPU_R11F_G11F_B10F;
+
+ const float *size = DRW_viewport_size_get();
+ pd->depth_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
+ pd->color_tx = DRW_texture_pool_query_2d(size[0], size[1], format, &draw_engine_gpencil_type);
+ pd->reveal_tx = DRW_texture_pool_query_2d(size[0], size[1], format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->gpencil_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(pd->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->color_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->reveal_tx),
+ });
+
+ if (pd->use_layer_fb) {
+ pd->color_layer_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+ pd->reveal_layer_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->layer_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(pd->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->color_layer_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->reveal_layer_tx),
+ });
+ };
+
+ if (pd->use_object_fb) {
+ pd->color_object_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+ pd->reveal_object_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->object_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(pd->depth_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->color_object_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->reveal_object_tx),
+ });
+ }
+
+ if (pd->use_mask_fb) {
+ /* We need an extra depth to not disturb the normal drawing.
+ * The color_tx is needed for framebuffer cmpleteness. */
+ GPUTexture *color_tx, *depth_tx;
+ depth_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type);
+ color_tx = DRW_texture_pool_query_2d(size[0], size[1], GPU_R8, &draw_engine_gpencil_type);
+ /* Use high quality format for render. */
+ eGPUTextureFormat mask_format = pd->is_render ? GPU_R16 : GPU_R8;
+ pd->mask_tx = DRW_texture_pool_query_2d(
+ size[0], size[1], mask_format, &draw_engine_gpencil_type);
+
+ GPU_framebuffer_ensure_config(&fbl->mask_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(depth_tx),
+ GPU_ATTACHMENT_TEXTURE(color_tx),
+ GPU_ATTACHMENT_TEXTURE(pd->mask_tx),
+ });
+ }
+
+ GPENCIL_antialiasing_init(vedata);
}
}
-/* helper function to sort inverse gpencil objects using qsort */
-static int gpencil_object_cache_compare_zdepth(const void *a1, const void *a2)
+static void GPENCIL_draw_scene_depth_only(void *ved)
{
- const tGPencilObjectCache *ps1 = a1, *ps2 = a2;
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- if (ps1->zdepth < ps2->zdepth) {
- return 1;
- }
- else if (ps1->zdepth > ps2->zdepth) {
- return -1;
+ if (DRW_state_is_fbo()) {
+ GPU_framebuffer_bind(dfbl->depth_only_fb);
}
- return 0;
-}
-
-/* prepare a texture with full viewport screenshot for fast drawing */
-static void gpencil_prepare_fast_drawing(GPENCIL_StorageList *stl,
- DefaultFramebufferList *dfbl,
- GPENCIL_FramebufferList *fbl,
- DRWPass *pass,
- const float clearcol[4])
-{
- if (stl->g_data->session_flag & (GP_DRW_PAINT_IDLE | GP_DRW_PAINT_FILLING)) {
- GPU_framebuffer_bind(fbl->background_fb);
- /* clean only in first loop cycle */
- if (stl->g_data->session_flag & GP_DRW_PAINT_IDLE) {
- GPU_framebuffer_clear_color_depth_stencil(fbl->background_fb, clearcol, 1.0f, 0x0);
- stl->g_data->session_flag = GP_DRW_PAINT_FILLING;
+ for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) {
+ for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) {
+ DRW_draw_pass(layer->geom_ps);
}
- /* repeat pass to fill temp texture */
- DRW_draw_pass(pass);
- /* set default framebuffer again */
+ }
+
+ if (DRW_state_is_fbo()) {
GPU_framebuffer_bind(dfbl->default_fb);
+ }
+
+ pd->gp_object_pool = pd->gp_layer_pool = pd->gp_vfx_pool = pd->gp_maskbit_pool = NULL;
- stl->storage->background_ready = true;
+ /* Free temp stroke buffers. */
+ if (pd->sbuffer_gpd) {
+ DRW_cache_gpencil_sbuffer_clear(pd->obact);
}
}
-void DRW_gpencil_free_runtime_data(void *ved)
+static void gpencil_draw_mask(GPENCIL_Data *vedata, GPENCIL_tObject *ob, GPENCIL_tLayer *layer)
{
- GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
+ GPENCIL_PassList *psl = vedata->psl;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ float clear_col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float clear_depth = ob->is_drawmode3d ? 1.0f : 0.0f;
+ bool inverted = false;
+ /* OPTI(fclem) we could optimize by only clearing if the new mask_bits does not contain all
+ * the masks already rendered in the buffer, and drawing only the layers not already drawn. */
+ bool cleared = false;
- /* free gpu data */
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_stroke);
- MEM_SAFE_FREE(stl->g_data->batch_buffer_stroke);
+ DRW_stats_group_start("GPencil Mask");
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_fill);
- MEM_SAFE_FREE(stl->g_data->batch_buffer_fill);
+ GPU_framebuffer_bind(fbl->mask_fb);
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_buffer_ctrlpoint);
- MEM_SAFE_FREE(stl->g_data->batch_buffer_ctrlpoint);
+ for (int i = 0; i < GP_MAX_MASKBITS; i++) {
+ if (!BLI_BITMAP_TEST(layer->mask_bits, i)) {
+ continue;
+ }
- GPU_BATCH_DISCARD_SAFE(stl->g_data->batch_grid);
- MEM_SAFE_FREE(stl->g_data->batch_grid);
+ if (BLI_BITMAP_TEST_BOOL(layer->mask_invert_bits, i) != inverted) {
+ if (cleared) {
+ DRW_draw_pass(psl->mask_invert_ps);
+ }
+ inverted = !inverted;
+ }
- if (stl->g_data->gp_object_cache == NULL) {
- return;
+ if (!cleared) {
+ cleared = true;
+ GPU_framebuffer_clear_color_depth(fbl->mask_fb, clear_col, clear_depth);
+ }
+
+ GPENCIL_tLayer *mask_layer = gpencil_layer_cache_get(ob, i);
+ BLI_assert(mask_layer);
+
+ DRW_draw_pass(mask_layer->geom_ps);
}
- /* reset all cache flags */
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i];
- if (cache_ob) {
- 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->name);
- MEM_SAFE_FREE(cache_ob->shgrp_array);
- }
+ if (!inverted) {
+ /* Blend shader expect an opacity mask not a reavealage buffer. */
+ DRW_draw_pass(psl->mask_invert_ps);
}
- /* free the cache itself */
- MEM_SAFE_FREE(stl->g_data->gp_object_cache);
+ DRW_stats_group_end();
}
-static void gpencil_draw_pass_range(GPENCIL_FramebufferList *fbl,
- GPENCIL_StorageList *stl,
- GPENCIL_PassList *psl,
- GPUFrameBuffer *fb,
- Object *ob,
- bGPdata *gpd,
- DRWShadingGroup *init_shgrp,
- DRWShadingGroup *end_shgrp,
- bool multi)
+static void GPENCIL_draw_object(GPENCIL_Data *vedata, GPENCIL_tObject *ob)
{
- if (init_shgrp == NULL) {
- return;
+ GPENCIL_PassList *psl = vedata->psl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
+
+ DRW_stats_group_start("GPencil Object");
+
+ GPUFrameBuffer *fb_object = (ob->vfx.first) ? fbl->object_fb : fbl->gpencil_fb;
+
+ GPU_framebuffer_bind(fb_object);
+ GPU_framebuffer_clear_depth_stencil(fb_object, ob->is_drawmode3d ? 1.0f : 0.0f, 0x00);
+
+ if (ob->vfx.first) {
+ GPU_framebuffer_multi_clear(fb_object, clear_cols);
}
- const bool do_antialiasing = ((!stl->storage->is_mat_preview) && (multi));
+ for (GPENCIL_tLayer *layer = ob->layers.first; layer; layer = layer->next) {
+ if (layer->mask_bits) {
+ gpencil_draw_mask(vedata, ob, layer);
+ }
+
+ if (layer->blend_ps) {
+ GPU_framebuffer_bind(fbl->layer_fb);
+ GPU_framebuffer_multi_clear(fbl->layer_fb, clear_cols);
+ }
+ else {
+ GPU_framebuffer_bind(fb_object);
+ }
+
+ DRW_draw_pass(layer->geom_ps);
- if (do_antialiasing) {
- MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+ if (layer->blend_ps) {
+ GPU_framebuffer_bind(fb_object);
+ DRW_draw_pass(layer->blend_ps);
+ }
+ }
+
+ for (GPENCIL_tVfx *vfx = ob->vfx.first; vfx; vfx = vfx->next) {
+ GPU_framebuffer_bind(*(vfx->target_fb));
+ DRW_draw_pass(vfx->vfx_ps);
}
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d : psl->stroke_pass_2d,
- init_shgrp,
- end_shgrp);
+ copy_m4_m4(pd->object_bound_mat, ob->plane_mat);
+ pd->is_stroke_order_3d = ob->is_drawmode3d;
- if (do_antialiasing) {
- MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fb, txl);
+ if (pd->scene_fb) {
+ GPU_framebuffer_bind(pd->scene_fb);
+ DRW_draw_pass(psl->merge_depth_ps);
}
+
+ DRW_stats_group_end();
}
-/* draw strokes to use for selection */
-static void drw_gpencil_select_render(GPENCIL_StorageList *stl, GPENCIL_PassList *psl)
+static void GPENCIL_fast_draw_start(GPENCIL_Data *vedata)
{
- tGPencilObjectCache *cache_ob;
- tGPencilObjectCache_shgrp *array_elm = NULL;
- DRWShadingGroup *init_shgrp = NULL;
- DRWShadingGroup *end_shgrp = NULL;
-
- /* Draw all pending objects */
- if ((stl->g_data->gp_cache_used > 0) && (stl->g_data->gp_object_cache)) {
- /* sort by zdepth */
- qsort(stl->g_data->gp_object_cache,
- stl->g_data->gp_cache_used,
- sizeof(tGPencilObjectCache),
- gpencil_object_cache_compare_zdepth);
-
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- cache_ob = &stl->g_data->gp_object_cache[i];
- if (cache_ob) {
- Object *ob = cache_ob->ob;
- bGPdata *gpd = cache_ob->gpd;
- init_shgrp = NULL;
- if (cache_ob->tot_layers > 0) {
- for (int e = 0; e < cache_ob->tot_layers; e++) {
- array_elm = &cache_ob->shgrp_array[e];
- if (init_shgrp == NULL) {
- init_shgrp = array_elm->init_shgrp;
- }
- end_shgrp = array_elm->end_shgrp;
- }
- /* draw group */
- DRW_draw_pass_subset(GPENCIL_3D_DRAWMODE(ob, gpd) ? psl->stroke_pass_3d :
- psl->stroke_pass_2d,
- init_shgrp,
- end_shgrp);
- }
- /* the cache must be dirty for next loop */
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- }
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+
+ if (!pd->snapshot_buffer_dirty) {
+ /* Copy back cached render. */
+ GPU_framebuffer_blit(fbl->snapshot_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT);
+ GPU_framebuffer_blit(fbl->snapshot_fb, 0, fbl->gpencil_fb, 0, GPU_COLOR_BIT);
+ GPU_framebuffer_blit(fbl->snapshot_fb, 1, fbl->gpencil_fb, 1, GPU_COLOR_BIT);
+ /* Bypass drawing. */
+ pd->tobjects.first = pd->tobjects.last = NULL;
}
}
-/* draw scene */
-void GPENCIL_draw_scene(void *ved)
+static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata)
{
- GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
- 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();
- View3D *v3d = draw_ctx->v3d;
- Object *obact = draw_ctx->obact;
- const bool playing = stl->storage->is_playing;
- const bool is_render = stl->storage->is_render;
- bGPdata *gpd_act = (obact) && (obact->type == OB_GPENCIL) ? (bGPdata *)obact->data : NULL;
- const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd_act);
- const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) : true;
-
- /* if the draw is for select, do a basic drawing and return */
- if (DRW_state_is_select() || DRW_state_is_depth()) {
- drw_gpencil_select_render(stl, psl);
- return;
+ if (pd->snapshot_buffer_dirty) {
+ /* Save to snapshot buffer. */
+ GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->snapshot_fb, 0, GPU_DEPTH_BIT);
+ GPU_framebuffer_blit(fbl->gpencil_fb, 0, fbl->snapshot_fb, 0, GPU_COLOR_BIT);
+ GPU_framebuffer_blit(fbl->gpencil_fb, 1, fbl->snapshot_fb, 1, GPU_COLOR_BIT);
+ pd->snapshot_buffer_dirty = false;
}
-
- /* paper pass to display a comfortable area to draw over complex scenes with geometry */
- if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
- if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_PAPER)) {
- DRW_draw_pass(psl->paper_pass);
- }
+ /* Draw the sbuffer stroke(s). */
+ for (GPENCIL_tObject *ob = pd->sbuffer_tobjects.first; ob; ob = ob->next) {
+ GPENCIL_draw_object(vedata, ob);
}
+}
- /* if we have a painting session, we use fast viewport drawing method */
- if ((!is_render) && (stl->g_data->session_flag & GP_DRW_PAINT_PAINTING)) {
- GPU_framebuffer_bind(dfbl->default_fb);
-
- if (obact->dt != OB_BOUNDBOX) {
- DRW_draw_pass(psl->background_pass);
- }
+void GPENCIL_draw_scene(void *ved)
+{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}};
- MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl);
+ /* Fade 3D objects. */
+ if ((!pd->is_render) && (pd->fade_3d_object_opacity > -1.0f)) {
+ mul_v4_fl(clear_cols[1], pd->fade_3d_object_opacity);
+ }
- DRW_draw_pass(psl->drawing_pass);
+ if (pd->draw_depth_only) {
+ GPENCIL_draw_scene_depth_only(vedata);
+ return;
+ }
- MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, dfbl->default_fb, txl);
+ if (pd->tobjects.first == NULL) {
+ return;
+ }
- /* grid pass */
- if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
- if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID)) {
- DRW_draw_pass(psl->grid_pass);
- }
- }
+ if (pd->do_fast_drawing) {
+ GPENCIL_fast_draw_start(vedata);
+ }
- /* free memory */
- DRW_gpencil_free_runtime_data(ved);
+ if (pd->tobjects.first) {
+ GPU_framebuffer_bind(fbl->gpencil_fb);
+ GPU_framebuffer_multi_clear(fbl->gpencil_fb, clear_cols);
+ }
- return;
+ for (GPENCIL_tObject *ob = pd->tobjects.first; ob; ob = ob->next) {
+ GPENCIL_draw_object(vedata, ob);
}
- if (DRW_state_is_fbo()) {
+ if (pd->do_fast_drawing) {
+ GPENCIL_fast_draw_end(vedata);
+ }
- /* Draw all pending objects */
- if (stl->g_data->gp_cache_used > 0) {
- /* sort by zdepth */
- qsort(stl->g_data->gp_object_cache,
- stl->g_data->gp_cache_used,
- sizeof(tGPencilObjectCache),
- gpencil_object_cache_compare_zdepth);
-
- for (int i = 0; i < stl->g_data->gp_cache_used; i++) {
- cache_ob = &stl->g_data->gp_object_cache[i];
- Object *ob = cache_ob->ob;
- 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_stencil(fbl->temp_fb_a, clearcol, 1.0f, 0x0);
- /* Stroke Pass:
- * draw only a subset that usually starts with a fill and ends with stroke
- */
- 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_Regular) && (!use_blend) &&
- (!array_elm->mask_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, fbl->temp_fb_a, ob, gpd, init_shgrp, end_shgrp, is_last);
-
- /* Draw current group in separated texture to blend later */
- init_shgrp = array_elm->init_shgrp;
- end_shgrp = array_elm->end_shgrp;
-
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_fx, clearcol, 1.0f, 0x0);
- gpencil_draw_pass_range(
- fbl, stl, psl, fbl->temp_fb_fx, ob, gpd, init_shgrp, end_shgrp, is_last);
-
- /* Blend A texture and FX texture */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_b, clearcol, 1.0f, 0x0);
- stl->storage->blend_mode = array_elm->mode;
- stl->storage->mask_layer = (int)array_elm->mask_layer;
- stl->storage->tonemapping = 1;
- DRW_draw_pass(psl->blend_pass);
- stl->storage->tonemapping = 0;
-
- /* Copy B texture to A texture to follow loop */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
-
- GPU_framebuffer_bind(fbl->temp_fb_a);
- GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_a, clearcol, 1.0f, 0x0);
- DRW_draw_pass(psl->mix_pass_noblend);
-
- /* prepare next group */
- init_shgrp = NULL;
- }
- }
- /* last group */
- gpencil_draw_pass_range(
- fbl, stl, psl, fbl->temp_fb_a, ob, gpd, init_shgrp, end_shgrp, true);
- }
-
- /* Current buffer drawing */
- if ((!is_render) && (cache_ob->is_dup_ob == false)) {
- DRW_draw_pass(psl->drawing_pass);
- }
- /* fx passes */
- if (cache_ob->has_fx == true) {
- stl->storage->tonemapping = 0;
- gpencil_fx_draw(&e_data, vedata, cache_ob);
- }
-
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_a;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_a;
-
- /* Combine with scene buffer */
- if ((!is_render) || (fbl->main == NULL)) {
- GPU_framebuffer_bind(dfbl->default_fb);
- }
- else {
- GPU_framebuffer_bind(fbl->main);
- }
- /* tonemapping */
- stl->storage->tonemapping = 1;
-
- /* active select flag and selection color */
- if (!is_render) {
- UI_GetThemeColorShadeAlpha4fv(
- (ob == draw_ctx->obact) ? TH_ACTIVE : TH_SELECT, 0, -40, stl->storage->select_color);
- }
- stl->storage->do_select_outline = ((overlay) && (ob->base_flag & BASE_SELECTED) &&
- (ob->mode == OB_MODE_OBJECT) && (!is_render) &&
- (!playing) && (v3d->flag & V3D_SELECT_OUTLINE));
-
- /* if active object is not object mode, disable for all objects */
- if ((stl->storage->do_select_outline) && (draw_ctx->obact) &&
- (draw_ctx->obact->mode != OB_MODE_OBJECT)) {
- stl->storage->do_select_outline = 0;
- }
-
- /* draw mix pass */
- DRW_draw_pass(psl->mix_pass);
-
- /* disable select flag */
- stl->storage->do_select_outline = 0;
-
- /* prepare for fast drawing */
- if (!is_render) {
- if (!playing) {
- gpencil_prepare_fast_drawing(stl, dfbl, fbl, psl->mix_pass_noblend, clearcol);
- }
- }
- else {
- /* if render, the cache must be dirty for next loop */
- gpd->flag |= GP_DATA_CACHE_IS_DIRTY;
- }
- }
- /* edit points */
- if ((!is_render) && (!playing) && (is_edit)) {
- DRW_draw_pass(psl->edit_pass);
- }
- }
- /* grid pass */
- if ((!is_render) && (obact) && (obact->type == OB_GPENCIL)) {
- if (((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID)) {
- DRW_draw_pass(psl->grid_pass);
- }
- }
+ if (pd->scene_fb) {
+ GPENCIL_antialiasing_draw(vedata);
}
- /* free memory */
- DRW_gpencil_free_runtime_data(ved);
- /* reset */
- if (DRW_state_is_fbo()) {
- /* attach again default framebuffer */
- if (!is_render) {
- GPU_framebuffer_bind(dfbl->default_fb);
- }
+ pd->gp_object_pool = pd->gp_layer_pool = pd->gp_vfx_pool = pd->gp_maskbit_pool = NULL;
- /* the temp texture is ready. Now we can use fast screen drawing */
- if (stl->g_data->session_flag & GP_DRW_PAINT_FILLING) {
- stl->g_data->session_flag = GP_DRW_PAINT_READY;
- }
+ /* Free temp stroke buffers. */
+ if (pd->sbuffer_gpd) {
+ DRW_cache_gpencil_sbuffer_clear(pd->obact);
}
}
+static void GPENCIL_engine_free(void)
+{
+ GPENCIL_shader_free();
+}
+
static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data);
DrawEngineType draw_engine_gpencil_type = {
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 44a30260343..4b6059f1474 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -23,6 +23,10 @@
#ifndef __GPENCIL_ENGINE_H__
#define __GPENCIL_ENGINE_H__
+#include "DNA_gpencil_types.h"
+
+#include "BLI_bitmap.h"
+
#include "GPU_batch.h"
extern DrawEngineType draw_engine_gpencil_type;
@@ -34,204 +38,201 @@ struct Object;
struct RenderEngine;
struct RenderLayer;
struct bGPDstroke;
-
+struct View3D;
+struct GpencilBatchCache;
struct GPUBatch;
struct GPUVertBuf;
struct GPUVertFormat;
-#define GPENCIL_MAX_SHGROUPS 65536
-#define GPENCIL_GROUPS_BLOCK_SIZE 1024
+/* used to convert pixel scale. */
+#define GPENCIL_PIXEL_FACTOR 2000.0f
/* used to expand VBOs. Size has a big impact in the speed */
#define GPENCIL_VBO_BLOCK_SIZE 128
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-/* *********** OBJECTS CACHE *********** */
-typedef struct tGPencilObjectCache_shgrp {
- /** type of blend (regular, add, mult, etc...) */
- int mode;
- /** flag to enable the layer clamping */
- bool mask_layer;
- /** factor to define the opacity of the 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;
- int idx; /*original index, can change after sort */
- char *name;
-
- /* effects */
- bool has_fx;
- ListBase shader_fx;
- float pixfactor;
- DRWShadingGroup *fx_wave_sh;
- DRWShadingGroup *fx_blur_sh;
- DRWShadingGroup *fx_colorize_sh;
- DRWShadingGroup *fx_pixel_sh;
- DRWShadingGroup *fx_rim_sh;
- DRWShadingGroup *fx_shadow_sh;
- DRWShadingGroup *fx_glow_sh;
- DRWShadingGroup *fx_swirl_sh;
- DRWShadingGroup *fx_flip_sh;
- DRWShadingGroup *fx_light_sh;
-
- float loc[3];
- float obmat[4][4];
- float zdepth; /* z-depth value to sort gp object */
- bool is_dup_ob; /* flag to tag duplicate objects */
- float scale;
-
- /* shading type */
- int shading_type[2];
-
- /* GPU data size */
- int tot_vertex;
- int tot_triangles;
-
- /* Save shader groups by layer */
- int tot_layers;
- tGPencilObjectCache_shgrp *shgrp_array;
-
-} tGPencilObjectCache;
+#define GP_MAX_MASKBITS 256
+
+/* UBO structure. Watch out for padding. Must match GLSL declaration. */
+typedef struct gpMaterial {
+ float stroke_color[4];
+ float fill_color[4];
+ float fill_mix_color[4];
+ float fill_uv_transform[3][2], _pad0[2];
+ float stroke_texture_mix;
+ float stroke_u_scale;
+ float fill_texture_mix;
+ int flag;
+} gpMaterial;
+
+/* gpMaterial->flag */
+/* WATCH Keep in sync with GLSL declaration. */
+#define GP_STROKE_ALIGNMENT_STROKE 1
+#define GP_STROKE_ALIGNMENT_OBJECT 2
+#define GP_STROKE_ALIGNMENT_FIXED 3
+#define GP_STROKE_ALIGNMENT 0x3
+#define GP_STROKE_OVERLAP (1 << 2)
+#define GP_STROKE_TEXTURE_USE (1 << 3)
+#define GP_STROKE_TEXTURE_STENCIL (1 << 4)
+#define GP_STROKE_TEXTURE_PREMUL (1 << 5)
+#define GP_STROKE_DOTS (1 << 6)
+#define GP_FILL_TEXTURE_USE (1 << 10)
+#define GP_FILL_TEXTURE_PREMUL (1 << 11)
+#define GP_FILL_TEXTURE_CLIP (1 << 12)
+#define GP_FILL_GRADIENT_USE (1 << 13)
+#define GP_FILL_GRADIENT_RADIAL (1 << 14)
+
+#define GPENCIL_LIGHT_BUFFER_LEN 128
+
+/* UBO structure. Watch out for padding. Must match GLSL declaration. */
+typedef struct gpLight {
+ float color[3], type;
+ float right[3], spotsize;
+ float up[3], spotblend;
+ float forward[4];
+ float position[4];
+} gpLight;
+
+/* gpLight->type */
+/* WATCH Keep in sync with GLSL declaration. */
+#define GP_LIGHT_TYPE_POINT 0.0
+#define GP_LIGHT_TYPE_SPOT 1.0
+#define GP_LIGHT_TYPE_SUN 2.0
+#define GP_LIGHT_TYPE_AMBIENT 3.0
+
+BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16)
+BLI_STATIC_ASSERT_ALIGN(gpLight, 16)
+
+/* *********** Draw Datas *********** */
+typedef struct GPENCIL_MaterialPool {
+ /* Linklist. */
+ struct GPENCIL_MaterialPool *next;
+ /* GPU representatin of materials. */
+ gpMaterial mat_data[GP_MATERIAL_BUFFER_LEN];
+ /* Matching ubo. */
+ struct GPUUniformBuffer *ubo;
+ /* Texture per material. NULL means none. */
+ struct GPUTexture *tex_fill[GP_MATERIAL_BUFFER_LEN];
+ struct GPUTexture *tex_stroke[GP_MATERIAL_BUFFER_LEN];
+ /* Number of material used in this pool. */
+ int used_count;
+} GPENCIL_MaterialPool;
+
+typedef struct GPENCIL_LightPool {
+ /* GPU representatin of materials. */
+ gpLight light_data[GPENCIL_LIGHT_BUFFER_LEN];
+ /* Matching ubo. */
+ struct GPUUniformBuffer *ubo;
+ /* Number of light in the pool. */
+ int light_used;
+} GPENCIL_LightPool;
+
+typedef struct GPENCIL_ViewLayerData {
+ /* GPENCIL_tObject */
+ struct BLI_memblock *gp_object_pool;
+ /* GPENCIL_tLayer */
+ struct BLI_memblock *gp_layer_pool;
+ /* GPENCIL_tVfx */
+ struct BLI_memblock *gp_vfx_pool;
+ /* GPENCIL_MaterialPool */
+ struct BLI_memblock *gp_material_pool;
+ /* GPENCIL_LightPool */
+ struct BLI_memblock *gp_light_pool;
+ /* BLI_bitmap */
+ struct BLI_memblock *gp_maskbit_pool;
+} GPENCIL_ViewLayerData;
+
+/* *********** GPencil *********** */
+
+typedef struct GPENCIL_tVfx {
+ /** Linklist */
+ struct GPENCIL_tVfx *next;
+ DRWPass *vfx_ps;
+ /* Framebuffer reference since it may not be allocated yet. */
+ GPUFrameBuffer **target_fb;
+} GPENCIL_tVfx;
+
+typedef struct GPENCIL_tLayer {
+ /** Linklist */
+ struct GPENCIL_tLayer *next;
+ /** Geometry pass (draw all strokes). */
+ DRWPass *geom_ps;
+ /** Blend pass to composite onto the target buffer (blends modes). NULL if not needed. */
+ DRWPass *blend_ps;
+ /** First shading group created for this layer. Contains all uniforms. */
+ DRWShadingGroup *base_shgrp;
+ /** Layer id of the mask. */
+ BLI_bitmap *mask_bits;
+ BLI_bitmap *mask_invert_bits;
+ /** Index in the layer list. Used as id for masking. */
+ int layer_id;
+} GPENCIL_tLayer;
+
+typedef struct GPENCIL_tObject {
+ /** Linklist */
+ struct GPENCIL_tObject *next;
+
+ struct {
+ GPENCIL_tLayer *first, *last;
+ } layers;
+
+ struct {
+ GPENCIL_tVfx *first, *last;
+ } vfx;
+
+ /* Distance to camera. Used for sorting. */
+ float camera_z;
+ /* Used for stroke thickness scaling. */
+ float object_scale;
+ /* Normal used for shading. Based on view angle. */
+ float plane_normal[3];
+ /* Used for drawing depth merge pass. */
+ float plane_mat[4][4];
+
+ bool is_drawmode3d;
+} GPENCIL_tObject;
/* *********** LISTS *********** */
-typedef struct GPENCIL_shgroup {
- int s_clamp;
- int stroke_style;
- int color_type;
- int mode;
- int texture_mix;
- int texture_flip;
- int texture_clamp;
- int fill_style;
- int keep_size;
- int caps_mode[2];
- float obj_scale;
- int xray_mode;
- int alignment_mode;
-
- float gradient_f;
- float gradient_s[2];
-
- float mix_stroke_factor;
-
- /* color of the wireframe */
- float wire_color[4];
- /* shading type and mode */
- int shading_type[2];
- int is_xray;
-} GPENCIL_shgroup;
-
-typedef struct GPENCIL_Storage {
- int shgroup_id; /* total elements */
- int stroke_style;
- int color_type;
- int mode;
- int xray;
- int keep_size;
- float obj_scale;
- float pixfactor;
- bool is_playing;
- bool is_render;
- bool is_mat_preview;
- bool is_main_overlay;
- bool is_main_onion;
- bool background_ready;
- int is_xray;
- bool is_ontop;
- bool reset_cache;
- const float *pixsize;
- float render_pixsize;
- int tonemapping;
- int do_select_outline;
- float select_color[4];
- short multisamples;
- float grid_matrix[4][4];
-
- short framebuffer_flag; /* flag what framebuffer need to create */
-
- int blend_mode;
- int mask_layer;
-
- /* simplify settings*/
- bool simplify_fill;
- bool simplify_modif;
- bool simplify_fx;
- bool simplify_blend;
-
- float gradient_f;
- float gradient_s[2];
- int alignment_mode;
-
- float mix_stroke_factor;
-
- /* Render Matrices and data */
- float view_vecs[2][4]; /* vec4[2] */
-
- int shade_render[2];
-
- Object *camera; /* camera pointer for render mode */
-} GPENCIL_Storage;
-
-typedef enum eGpencilFramebuffer_Flag {
- GP_FRAMEBUFFER_MULTISAMPLE = (1 << 0),
- GP_FRAMEBUFFER_BASIC = (1 << 1),
- GP_FRAMEBUFFER_DRAW = (1 << 2),
-} eGpencilFramebuffer_Flag;
-
typedef struct GPENCIL_StorageList {
- struct GPENCIL_Storage *storage;
- struct g_data *g_data;
- struct GPENCIL_shgroup *shgroups;
+ struct GPENCIL_PrivateData *pd;
} GPENCIL_StorageList;
typedef struct GPENCIL_PassList {
- struct DRWPass *stroke_pass_2d;
- struct DRWPass *stroke_pass_3d;
- struct DRWPass *edit_pass;
- struct DRWPass *drawing_pass;
- struct DRWPass *mix_pass;
- struct DRWPass *mix_pass_noblend;
- struct DRWPass *background_pass;
- struct DRWPass *paper_pass;
- struct DRWPass *grid_pass;
- struct DRWPass *blend_pass;
-
- /* effects */
- struct DRWPass *fx_shader_pass;
- struct DRWPass *fx_shader_pass_blend;
-
+ /* Composite the main GPencil buffer onto the rendered image. */
+ struct DRWPass *composite_ps;
+ /* Composite the object depth to the default depth buffer to occlude overlays. */
+ struct DRWPass *merge_depth_ps;
+ /* Invert mask buffer content. */
+ struct DRWPass *mask_invert_ps;
+ /* Anti-Aliasing. */
+ struct DRWPass *smaa_edge_ps;
+ struct DRWPass *smaa_weight_ps;
+ struct DRWPass *smaa_resolve_ps;
} GPENCIL_PassList;
typedef struct GPENCIL_FramebufferList {
- struct GPUFrameBuffer *main;
- struct GPUFrameBuffer *temp_fb_a;
- struct GPUFrameBuffer *temp_fb_b;
- struct GPUFrameBuffer *temp_fb_fx;
- struct GPUFrameBuffer *background_fb;
-
- struct GPUFrameBuffer *multisample_fb;
+ struct GPUFrameBuffer *render_fb;
+ struct GPUFrameBuffer *gpencil_fb;
+ struct GPUFrameBuffer *snapshot_fb;
+ struct GPUFrameBuffer *layer_fb;
+ struct GPUFrameBuffer *object_fb;
+ struct GPUFrameBuffer *mask_fb;
+ struct GPUFrameBuffer *smaa_edge_fb;
+ struct GPUFrameBuffer *smaa_weight_fb;
} GPENCIL_FramebufferList;
typedef struct GPENCIL_TextureList {
- struct GPUTexture *texture;
-
- /* multisample textures */
- struct GPUTexture *multisample_color;
- struct GPUTexture *multisample_depth;
-
- /* Background textures for speed-up drawing. */
- struct GPUTexture *background_depth_tx;
- struct GPUTexture *background_color_tx;
-
+ /* Dummy texture to avoid errors cause by empty sampler. */
+ struct GPUTexture *dummy_texture;
+ /* Snapshot for smoother drawing. */
+ struct GPUTexture *snapshot_depth_tx;
+ struct GPUTexture *snapshot_color_tx;
+ struct GPUTexture *snapshot_reveal_tx;
+ /* Textures used by Antialiasing. */
+ struct GPUTexture *smaa_area_tx;
+ struct GPUTexture *smaa_search_tx;
+ /* Textures used during render. Containing underlying rendered scene. */
+ struct GPUTexture *render_depth_tx;
+ struct GPUTexture *render_color_tx;
} GPENCIL_TextureList;
typedef struct GPENCIL_Data {
@@ -240,248 +241,175 @@ typedef struct GPENCIL_Data {
struct GPENCIL_TextureList *txl;
struct GPENCIL_PassList *psl;
struct GPENCIL_StorageList *stl;
-
- /* render textures */
- struct GPUTexture *render_depth_tx;
- struct GPUTexture *render_color_tx;
-
} GPENCIL_Data;
/* *********** STATIC *********** */
-typedef struct g_data {
- struct DRWShadingGroup *shgrps_edit_point;
- struct DRWShadingGroup *shgrps_edit_line;
- struct DRWShadingGroup *shgrps_drawing_stroke;
- struct DRWShadingGroup *shgrps_drawing_fill;
- struct DRWShadingGroup *shgrps_grid;
-
- int gp_cache_used; /* total objects in cache */
- int gp_cache_size; /* size of the cache */
- struct tGPencilObjectCache *gp_object_cache;
-
- /* for buffer only one batch is nedeed because the drawing is only of one stroke */
- GPUBatch *batch_buffer_stroke;
- GPUBatch *batch_buffer_fill;
- GPUBatch *batch_buffer_ctrlpoint;
-
- /* grid geometry */
- GPUBatch *batch_grid;
-
- /* runtime pointers texture */
- struct GPUTexture *input_depth_tx;
- struct GPUTexture *input_color_tx;
-
- /* working textures */
- struct GPUTexture *temp_color_tx_a;
- struct GPUTexture *temp_depth_tx_a;
-
- struct GPUTexture *temp_color_tx_b;
- struct GPUTexture *temp_depth_tx_b;
-
- struct GPUTexture *temp_color_tx_fx;
- struct GPUTexture *temp_depth_tx_fx;
-
- int session_flag;
- bool do_instances;
-
-} g_data; /* Transient data */
-
-/* flags for fast drawing support */
-typedef enum eGPsession_Flag {
- GP_DRW_PAINT_HOLD = (1 << 0),
- GP_DRW_PAINT_IDLE = (1 << 1),
- GP_DRW_PAINT_FILLING = (1 << 2),
- GP_DRW_PAINT_READY = (1 << 3),
- GP_DRW_PAINT_PAINTING = (1 << 4),
-} eGPsession_Flag;
-
-typedef struct GPENCIL_e_data {
- /* textures */
- struct GPUTexture *gpencil_blank_texture;
-
- /* general drawing shaders */
- struct GPUShader *gpencil_fill_sh;
- struct GPUShader *gpencil_stroke_sh;
- struct GPUShader *gpencil_point_sh;
- struct GPUShader *gpencil_edit_point_sh;
- struct GPUShader *gpencil_line_sh;
- 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;
-
- /* effects */
- struct GPUShader *gpencil_fx_blur_sh;
- struct GPUShader *gpencil_fx_colorize_sh;
- struct GPUShader *gpencil_fx_flip_sh;
- struct GPUShader *gpencil_fx_glow_prepare_sh;
- struct GPUShader *gpencil_fx_glow_resolve_sh;
- struct GPUShader *gpencil_fx_light_sh;
- struct GPUShader *gpencil_fx_pixel_sh;
- struct GPUShader *gpencil_fx_rim_prepare_sh;
- struct GPUShader *gpencil_fx_rim_resolve_sh;
- struct GPUShader *gpencil_fx_shadow_prepare_sh;
- struct GPUShader *gpencil_fx_shadow_resolve_sh;
- struct GPUShader *gpencil_fx_swirl_sh;
- struct GPUShader *gpencil_fx_wave_sh;
-
-} GPENCIL_e_data; /* Engine data */
-
-/* GPUBatch Cache Element */
-typedef struct GpencilBatchCacheElem {
- GPUBatch *batch;
- GPUVertBuf *vbo;
- int vbo_len;
- /* attr ids */
- GPUVertFormat *format;
- uint pos_id;
- uint color_id;
- uint thickness_id;
- uint uvdata_id;
- uint prev_pos_id;
-
- /* size for VBO alloc */
- int tot_vertex;
-} GpencilBatchCacheElem;
-
-/* Defines each batch group to define later the shgroup */
-typedef struct GpencilBatchGroup {
- struct bGPDlayer *gpl; /* reference to original layer */
- struct bGPDframe *gpf; /* reference to original frame */
- struct bGPDstroke *gps; /* reference to original stroke */
- short type; /* type of element */
- bool onion; /* the group is part of onion skin */
- int vertex_idx; /* index of vertex data */
-} GpencilBatchGroup;
-
-typedef enum GpencilBatchGroup_Type {
- eGpencilBatchGroupType_Stroke = 1,
- eGpencilBatchGroupType_Point = 2,
- eGpencilBatchGroupType_Fill = 3,
- eGpencilBatchGroupType_Edit = 4,
- eGpencilBatchGroupType_Edlin = 5,
-} GpencilBatchGroup_Type;
-
-/* Runtime data for GPU and evaluated frames after applying modifiers */
-typedef struct GpencilBatchCache {
- GpencilBatchCacheElem b_stroke;
- GpencilBatchCacheElem b_point;
- GpencilBatchCacheElem b_fill;
- GpencilBatchCacheElem b_edit;
- GpencilBatchCacheElem b_edlin;
-
- /** Cache is dirty */
- bool is_dirty;
- /** Edit mode flag */
- bool is_editmode;
- /** Last cache frame */
- int cache_frame;
-
- /** Total groups in arrays */
- int grp_used;
- /** Max size of the array */
- int grp_size;
- /** Array of cache elements */
- struct GpencilBatchGroup *grp_cache;
-} GpencilBatchCache;
-
-/* general drawing functions */
-struct DRWShadingGroup *gpencil_shgroup_stroke_create(struct GPENCIL_e_data *e_data,
- struct GPENCIL_Data *vedata,
- struct DRWPass *pass,
- struct GPUShader *shader,
- struct Object *ob,
- float (*obmat)[4],
- struct bGPdata *gpd,
- struct bGPDlayer *gpl,
- struct bGPDstroke *gps,
- struct MaterialGPencilStyle *gp_style,
- int id,
- bool onion,
- const float scale,
- const int shading_type[2]);
-void gpencil_populate_datablock(struct GPENCIL_e_data *e_data,
- void *vedata,
- struct Object *ob,
- struct tGPencilObjectCache *cache_ob);
-void gpencil_populate_buffer_strokes(struct GPENCIL_e_data *e_data,
- void *vedata,
- struct ToolSettings *ts,
- struct Object *ob);
-void gpencil_populate_multiedit(struct GPENCIL_e_data *e_data,
- void *vedata,
- struct Object *ob,
- struct tGPencilObjectCache *cache_ob);
-void gpencil_populate_particles(struct GPENCIL_e_data *e_data,
- struct GHash *gh_objects,
- void *vedata);
-
-void gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h);
-
-/* create geometry functions */
-void gpencil_get_point_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- short thickness,
- const float ink[4],
- const int follow_mode);
-void gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- short thickness,
- const float ink[4]);
-void gpencil_get_fill_geom(struct GpencilBatchCacheElem *be,
- struct Object *ob,
- struct bGPDstroke *gps,
- const float color[4]);
-void gpencil_get_edit_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- float alpha,
- short dflag);
-void gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be,
- struct bGPDstroke *gps,
- float alpha,
- const bool hide_select);
-
-struct GPUBatch *gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, short thickness);
-struct GPUBatch *gpencil_get_buffer_fill_geom(struct bGPdata *gpd);
-struct GPUBatch *gpencil_get_buffer_point_geom(struct bGPdata *gpd, short thickness);
-struct GPUBatch *gpencil_get_buffer_ctrlpoint_geom(struct bGPdata *gpd);
-struct GPUBatch *gpencil_get_grid(Object *ob);
-
-/* object cache functions */
-struct tGPencilObjectCache *gpencil_object_cache_add(struct tGPencilObjectCache *cache_array,
- struct Object *ob,
- int *gp_cache_size,
- int *gp_cache_used);
-
-bool gpencil_onion_active(struct bGPdata *gpd);
-
-/* shading groups cache functions */
-struct GpencilBatchGroup *gpencil_group_cache_add(struct GpencilBatchGroup *cache_array,
- struct bGPDlayer *gpl,
- struct bGPDframe *gpf,
- struct bGPDstroke *gps,
- const short type,
- const bool onion,
- const int vertex_idx,
- int *grp_size,
- int *grp_used);
+typedef struct GPENCIL_PrivateData {
+ /* Pointers copied from GPENCIL_ViewLayerData. */
+ struct BLI_memblock *gp_object_pool;
+ struct BLI_memblock *gp_layer_pool;
+ struct BLI_memblock *gp_vfx_pool;
+ struct BLI_memblock *gp_material_pool;
+ struct BLI_memblock *gp_light_pool;
+ struct BLI_memblock *gp_maskbit_pool;
+ /* Last used material pool. */
+ GPENCIL_MaterialPool *last_material_pool;
+ /* Last used light pool. */
+ GPENCIL_LightPool *last_light_pool;
+ /* Common lightpool containing all lights in the scene. */
+ GPENCIL_LightPool *global_light_pool;
+ /* Common lightpool containing one ambient white light. */
+ GPENCIL_LightPool *shadeless_light_pool;
+ /* Linked list of tObjects. */
+ struct {
+ GPENCIL_tObject *first, *last;
+ } tobjects, tobjects_infront;
+ /* Temp Textures (shared with other engines). */
+ GPUTexture *depth_tx;
+ GPUTexture *color_tx;
+ GPUTexture *color_layer_tx;
+ GPUTexture *color_object_tx;
+ /* Revealage is 1 - alpha */
+ GPUTexture *reveal_tx;
+ GPUTexture *reveal_layer_tx;
+ GPUTexture *reveal_object_tx;
+ /* Mask texture */
+ GPUTexture *mask_tx;
+ /* Anti-Aliasing. */
+ GPUTexture *smaa_edge_tx;
+ GPUTexture *smaa_weight_tx;
+ /* Pointer to dtxl->depth */
+ GPUTexture *scene_depth_tx;
+ GPUFrameBuffer *scene_fb;
+ /* Copy of txl->dummy_tx */
+ GPUTexture *dummy_tx;
+ /* Copy of v3d->shading.single_color. */
+ float v3d_single_color[3];
+ /* Copy of v3d->shading.color_type or -1 to ignore. */
+ int v3d_color_type;
+ /* Current frame */
+ int cfra;
+ /* If we are rendering for final render (F12). */
+ bool is_render;
+ /* If we are in viewport display (used for VFX). */
+ bool is_viewport;
+ /* True in selection and auto_depth drawing */
+ bool draw_depth_only;
+ /* Is shading set to wireframe. */
+ bool draw_wireframe;
+ /* Used by the depth merge step. */
+ int is_stroke_order_3d;
+ float object_bound_mat[4][4];
+ /* Used for computing object distance to camera. */
+ float camera_z_axis[3], camera_z_offset;
+ float camera_pos[3];
+ /* Pseudo depth of field parameter. Used to scale blur radius. */
+ float dof_params[2];
+ /* Used for DoF Setup. */
+ Object *camera;
+ /* Copy of draw_ctx->scene for convenience. */
+ struct Scene *scene;
+
+ /* Active object. */
+ Object *obact;
+ /* Object being in draw mode. */
+ struct bGPdata *sbuffer_gpd;
+ /* Layer to append the temp stroke to. */
+ struct bGPDlayer *sbuffer_layer;
+ /* Temporary stroke currently being drawn. */
+ struct bGPDstroke *sbuffer_stroke;
+ /* List of temp objects containing the stroke. */
+ struct {
+ GPENCIL_tObject *first, *last;
+ } sbuffer_tobjects;
+ /* Batches containing the temp stroke. */
+ GPUBatch *stroke_batch;
+ GPUBatch *fill_batch;
+ bool do_fast_drawing;
+ bool snapshot_buffer_dirty;
+
+ /* Display onion skinning */
+ bool do_onion;
+ /* simplify settings */
+ bool simplify_fill;
+ bool simplify_fx;
+ bool simplify_antialias;
+ /* Use scene lighting or flat shading (global setting). */
+ bool use_lighting;
+ /* Use physical lights or just ambient lighting. */
+ bool use_lights;
+ /* Do we need additional framebuffers? */
+ bool use_layer_fb;
+ bool use_object_fb;
+ bool use_mask_fb;
+ /* Some blend mode needs to add negative values.
+ * This is only supported if target texture is signed. */
+ bool use_signed_fb;
+ /* Use only lines for multiedit and not active frame. */
+ bool use_multiedit_lines_only;
+ /* Layer opacity for fading. */
+ float fade_layer_opacity;
+ /* Opacity for fading gpencil objects. */
+ float fade_gp_object_opacity;
+ /* Opacity for fading 3D objects. */
+ float fade_3d_object_opacity;
+ /* Mask opacity uniform. */
+ float mask_opacity;
+ /* Xray transparency in solid mode. */
+ float xray_alpha;
+ /* Mask invert uniform. */
+ int mask_invert;
+} GPENCIL_PrivateData;
/* geometry batch cache functions */
struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra);
-/* effects */
-void GPENCIL_create_fx_shaders(struct GPENCIL_e_data *e_data);
-void GPENCIL_delete_fx_shaders(struct GPENCIL_e_data *e_data);
-void GPENCIL_create_fx_passes(struct GPENCIL_PassList *psl);
+GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob);
+void gpencil_object_cache_sort(GPENCIL_PrivateData *pd);
-void gpencil_fx_prepare(struct GPENCIL_e_data *e_data,
- struct GPENCIL_Data *vedata,
- struct tGPencilObjectCache *cache_ob);
-void gpencil_fx_draw(struct GPENCIL_e_data *e_data,
- struct GPENCIL_Data *vedata,
- struct tGPencilObjectCache *cache_ob);
+GPENCIL_tLayer *gpencil_layer_cache_add(GPENCIL_PrivateData *pd,
+ const Object *ob,
+ const bGPDlayer *gpl,
+ const bGPDframe *gpf,
+ GPENCIL_tObject *tgp_ob);
+GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number);
+
+GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs);
+void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool,
+ int mat_id,
+ struct GPUTexture **r_tex_stroke,
+ struct GPUTexture **r_tex_fill,
+ struct GPUUniformBuffer **r_ubo_mat);
+
+void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]);
+void gpencil_light_pool_populate(GPENCIL_LightPool *matpool, Object *ob);
+GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_PrivateData *pd);
+GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_PrivateData *pd, Object *ob);
+
+/* effects */
+void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob);
+
+/* Shaders */
+struct GPUShader *GPENCIL_shader_antialiasing(int stage);
+struct GPUShader *GPENCIL_shader_geometry_get(void);
+struct GPUShader *GPENCIL_shader_composite_get(void);
+struct GPUShader *GPENCIL_shader_layer_blend_get(void);
+struct GPUShader *GPENCIL_shader_mask_invert_get(void);
+struct GPUShader *GPENCIL_shader_depth_merge_get(void);
+struct GPUShader *GPENCIL_shader_fx_blur_get(void);
+struct GPUShader *GPENCIL_shader_fx_colorize_get(void);
+struct GPUShader *GPENCIL_shader_fx_composite_get(void);
+struct GPUShader *GPENCIL_shader_fx_transform_get(void);
+struct GPUShader *GPENCIL_shader_fx_glow_get(void);
+struct GPUShader *GPENCIL_shader_fx_pixelize_get(void);
+struct GPUShader *GPENCIL_shader_fx_rim_get(void);
+struct GPUShader *GPENCIL_shader_fx_shadow_get(void);
+
+void GPENCIL_shader_free(void);
+
+/* Antialiasing */
+void GPENCIL_antialiasing_init(struct GPENCIL_Data *vedata);
+void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata);
/* main functions */
void GPENCIL_engine_init(void *vedata);
@@ -493,43 +421,17 @@ void GPENCIL_draw_scene(void *vedata);
/* render */
void GPENCIL_render_init(struct GPENCIL_Data *ved,
struct RenderEngine *engine,
- struct Depsgraph *depsgraph);
+ struct RenderLayer *render_layer,
+ const struct Depsgraph *depsgraph,
+ const rcti *rect);
void GPENCIL_render_to_image(void *vedata,
struct RenderEngine *engine,
struct RenderLayer *render_layer,
const rcti *rect);
-/* TODO: GPXX workaround function to call free memory from draw manager while draw manager support
- * scene finish callback. */
-void DRW_gpencil_free_runtime_data(void *ved);
-
-/* Use of multisample framebuffers. */
-#define MULTISAMPLE_GP_SYNC_ENABLE(lvl, fbl) \
- { \
- if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \
- DRW_stats_query_start("GP Multisample Blit"); \
- GPU_framebuffer_bind(fbl->multisample_fb); \
- GPU_framebuffer_clear_color_depth_stencil( \
- fbl->multisample_fb, (const float[4]){0.0f}, 1.0f, 0x0); \
- DRW_stats_query_end(); \
- } \
- } \
- ((void)0)
-
-#define MULTISAMPLE_GP_SYNC_DISABLE(lvl, fbl, fb, txl) \
- { \
- if ((lvl > 0) && (fbl->multisample_fb != NULL) && (DRW_state_is_fbo())) { \
- DRW_stats_query_start("GP Multisample Resolve"); \
- GPU_framebuffer_bind(fb); \
- DRW_stats_query_end(); \
- } \
- } \
- ((void)0)
-
-#define GPENCIL_3D_DRAWMODE(ob, gpd) \
- ((gpd) && (gpd->draw_mode == GP_DRAWMODE_3D) && ((ob->dtx & OB_DRAWXRAY) == 0))
-
-#define GPENCIL_USE_SOLID(stl) \
- ((stl) && ((stl->storage->is_render) || (stl->storage->is_mat_preview)))
+/* Draw Data. */
+void gpencil_light_pool_free(void *storage);
+void gpencil_material_pool_free(void *storage);
+GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void);
#endif /* __GPENCIL_ENGINE_H__ */
diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c
index 8c126310ea2..083b04c0600 100644
--- a/source/blender/draw/engines/gpencil/gpencil_render.c
+++ b/source/blender/draw/engines/gpencil/gpencil_render.c
@@ -33,66 +33,22 @@
#include "gpencil_engine.h"
-/* Get pixel size for render
- * This function uses the same calculation used for viewport, because if use
- * camera pixelsize, the result is not correct.
- */
-static float get_render_pixelsize(float persmat[4][4], int winx, int winy)
-{
- float v1[3], v2[3];
- float len_px, len_sc;
-
- v1[0] = persmat[0][0];
- v1[1] = persmat[1][0];
- v1[2] = persmat[2][0];
-
- v2[0] = persmat[0][1];
- v2[1] = persmat[1][1];
- v2[2] = persmat[2][1];
-
- len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2)));
- len_sc = (float)MAX2(winx, winy);
-
- return len_px / len_sc;
-}
-
/* init render data */
-void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph)
+void GPENCIL_render_init(GPENCIL_Data *vedata,
+ RenderEngine *engine,
+ struct RenderLayer *render_layer,
+ const Depsgraph *depsgraph,
+ const rcti *rect)
{
- GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
- GPENCIL_StorageList *stl = vedata->stl;
GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_TextureList *txl = vedata->txl;
Scene *scene = DEG_get_evaluated_scene(depsgraph);
const float *viewport_size = DRW_viewport_size_get();
const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]};
- /* In render mode the default framebuffer is not generated
- * because there is no viewport. So we need to manually create one
- * NOTE : use 32 bit format for precision in render mode.
- */
- /* create multisample framebuffer for AA */
- if (U.gpencil_multisamples > 0) {
- int rect_w = (int)viewport_size[0];
- int rect_h = (int)viewport_size[1];
- gpencil_multisample_ensure(vedata, rect_w, rect_h);
- }
-
- vedata->render_depth_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_DEPTH_COMPONENT24, &draw_engine_gpencil_type);
- vedata->render_color_tx = DRW_texture_pool_query_2d(
- size[0], size[1], GPU_RGBA32F, &draw_engine_gpencil_type);
- GPU_framebuffer_ensure_config(&fbl->main,
- {GPU_ATTACHMENT_TEXTURE(vedata->render_depth_tx),
- GPU_ATTACHMENT_TEXTURE(vedata->render_color_tx)});
-
- /* Alloc transient data. */
- if (!stl->g_data) {
- stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__);
- }
-
/* Set the pers & view matrix. */
- float winmat[4][4], viewmat[4][4], viewinv[4][4], persmat[4][4];
+ float winmat[4][4], viewmat[4][4], viewinv[4][4];
struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
float frame = BKE_scene_frame_get(scene);
@@ -105,85 +61,101 @@ void GPENCIL_render_init(GPENCIL_Data *ved, RenderEngine *engine, struct Depsgra
DRW_view_default_set(view);
DRW_view_set_active(view);
- DRW_view_persmat_get(NULL, persmat, false);
+ /* Create depth texture & color texture from render result. */
+ const char *viewname = RE_GetActiveRenderView(engine->re);
+ RenderPass *rpass_z_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
+ RenderPass *rpass_col_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
- /* calculate pixel size for render */
- stl->storage->render_pixsize = get_render_pixelsize(persmat, viewport_size[0], viewport_size[1]);
+ float *pix_z = (rpass_z_src) ? rpass_z_src->rect : NULL;
+ float *pix_col = (rpass_col_src) ? rpass_col_src->rect : NULL;
- /* INIT CACHE */
- GPENCIL_cache_init(vedata);
+ if (!pix_z || !pix_col) {
+ RE_engine_set_error_message(engine,
+ "Warning: To render grease pencil, enable Combined and Z passes.");
+ }
+
+ if (pix_z) {
+ /* Depth need to be remapped to [0..1] range. */
+ pix_z = MEM_dupallocN(pix_z);
+
+ int pix_ct = rpass_z_src->rectx * rpass_z_src->recty;
+
+ if (DRW_view_is_persp_get(view)) {
+ for (int i = 0; i < pix_ct; i++) {
+ pix_z[i] = (-winmat[3][2] / -pix_z[i]) - winmat[2][2];
+ pix_z[i] = clamp_f(pix_z[i] * 0.5f + 0.5f, 0.0f, 1.0f);
+ }
+ }
+ else {
+ /* Keep in mind, near and far distance are negatives. */
+ float near = DRW_view_near_distance_get(view);
+ float far = DRW_view_far_distance_get(view);
+ float range_inv = 1.0f / fabsf(far - near);
+ for (int i = 0; i < pix_ct; i++) {
+ pix_z[i] = (pix_z[i] + near) * range_inv;
+ pix_z[i] = clamp_f(pix_z[i], 0.0f, 1.0f);
+ }
+ }
+ }
+
+ const bool do_region = (scene->r.mode & R_BORDER) != 0;
+ const bool do_clear_z = !pix_z || do_region;
+ const bool do_clear_col = !pix_col || do_region;
+
+ /* FIXME(fclem): we have a precision loss in the depth buffer because of this reupload.
+ * Find where it comes from! */
+ txl->render_depth_tx = DRW_texture_create_2d(
+ size[0], size[1], GPU_DEPTH_COMPONENT24, 0, do_region ? NULL : pix_z);
+ txl->render_color_tx = DRW_texture_create_2d(
+ size[0], size[1], GPU_RGBA16F, 0, do_region ? NULL : pix_col);
+
+ GPU_framebuffer_ensure_config(&fbl->render_fb,
+ {
+ GPU_ATTACHMENT_TEXTURE(txl->render_depth_tx),
+ GPU_ATTACHMENT_TEXTURE(txl->render_color_tx),
+ });
+
+ if (do_clear_z || do_clear_col) {
+ /* To avoid unpredictable result, clear buffers that have not be initialized. */
+ GPU_framebuffer_bind(fbl->render_fb);
+ if (do_clear_col) {
+ float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ GPU_framebuffer_clear_color(fbl->render_fb, clear_col);
+ }
+ if (do_clear_z) {
+ GPU_framebuffer_clear_depth(fbl->render_fb, 1.0f);
+ }
+ }
+
+ if (do_region) {
+ int x = rect->xmin;
+ int y = rect->ymin;
+ int w = BLI_rcti_size_x(rect);
+ int h = BLI_rcti_size_y(rect);
+ if (pix_col) {
+ GPU_texture_update_sub(txl->render_color_tx, GPU_DATA_FLOAT, pix_col, x, y, 0, w, h, 0);
+ }
+ if (pix_z) {
+ GPU_texture_update_sub(txl->render_depth_tx, GPU_DATA_FLOAT, pix_z, x, y, 0, w, h, 0);
+ }
+ }
+
+ MEM_SAFE_FREE(pix_z);
}
/* render all objects and select only grease pencil */
static void GPENCIL_render_cache(void *vedata,
struct Object *ob,
struct RenderEngine *UNUSED(engine),
- struct Depsgraph *UNUSED(depsgraph))
+ Depsgraph *UNUSED(depsgraph))
{
- if (ob && ob->type == OB_GPENCIL) {
+ if (ob && ELEM(ob->type, OB_GPENCIL, OB_LAMP)) {
if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) {
GPENCIL_cache_populate(vedata, ob);
}
}
}
-/* TODO: Reuse Eevee code in shared module instead to duplicate here */
-static void GPENCIL_render_update_viewvecs(float invproj[4][4],
- const float winmat[4][4],
- float (*r_viewvecs)[4])
-{
- /* view vectors for the corners of the view frustum.
- * Can be used to recreate the world space position easily */
- float view_vecs[4][4] = {
- {-1.0f, -1.0f, -1.0f, 1.0f},
- {1.0f, -1.0f, -1.0f, 1.0f},
- {-1.0f, 1.0f, -1.0f, 1.0f},
- {-1.0f, -1.0f, 1.0f, 1.0f},
- };
-
- /* convert the view vectors to view space */
- const bool is_persp = (winmat[3][3] == 0.0f);
- for (int i = 0; i < 4; i++) {
- mul_project_m4_v3(invproj, view_vecs[i]);
- /* normalized trick see:
- * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */
- if (is_persp) {
- /* Divide XY by Z. */
- mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]);
- }
- }
-
- /**
- * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and
- * view_vecs[1] is the vector going from the near-bottom-left corner to
- * the far-top-right corner.
- * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner
- * when Z = 1, and top-left corner if Z = 1.
- * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed)
- * distance from the near plane to the far clip plane.
- */
- copy_v4_v4(r_viewvecs[0], view_vecs[0]);
-
- /* we need to store the differences */
- r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0];
- r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1];
- r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2];
-}
-
-/* Update view_vecs */
-static void GPENCIL_render_update_vecs(GPENCIL_Data *vedata)
-{
- GPENCIL_StorageList *stl = vedata->stl;
-
- float invproj[4][4], winmat[4][4];
- DRW_view_winmat_get(NULL, winmat, false);
- DRW_view_winmat_get(NULL, invproj, true);
-
- /* this is separated to keep function equal to Eevee for future reuse of same code */
- GPENCIL_render_update_viewvecs(invproj, winmat, stl->storage->view_vecs);
-}
-
-/* read z-depth render result */
static void GPENCIL_render_result_z(struct RenderLayer *rl,
const char *viewname,
GPENCIL_Data *vedata,
@@ -191,45 +163,52 @@ static void GPENCIL_render_result_z(struct RenderLayer *rl,
{
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
- GPENCIL_StorageList *stl = vedata->stl;
if ((view_layer->passflag & SCE_PASS_Z) != 0) {
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
- GPU_framebuffer_read_depth(vedata->fbl->main,
+ GPU_framebuffer_read_depth(vedata->fbl->render_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
BLI_rcti_size_y(rect),
rp->rect);
- bool is_persp = DRW_view_is_persp_get(NULL);
-
- GPENCIL_render_update_vecs(vedata);
-
float winmat[4][4];
DRW_view_winmat_get(NULL, winmat, false);
+ int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+
/* Convert ogl depth [0..1] to view Z [near..far] */
- for (int i = 0; i < BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect); i++) {
- if (rp->rect[i] == 1.0f) {
- rp->rect[i] = 1e10f; /* Background */
- }
- else {
- if (is_persp) {
+ if (DRW_view_is_persp_get(NULL)) {
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
}
+ }
+ }
+ else {
+ /* Keep in mind, near and far distance are negatives. */
+ float near = DRW_view_near_distance_get(NULL);
+ float far = DRW_view_far_distance_get(NULL);
+ float range = fabsf(far - near);
+
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
else {
- rp->rect[i] = -stl->storage->view_vecs[0][2] +
- rp->rect[i] * -stl->storage->view_vecs[1][2];
+ rp->rect[i] = -rp->rect[i] * range + near;
}
}
}
}
}
-/* read combined render result */
static void GPENCIL_render_result_combined(struct RenderLayer *rl,
const char *viewname,
GPENCIL_Data *vedata,
@@ -238,8 +217,8 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl,
RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname);
GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- GPU_framebuffer_bind(fbl->main);
- GPU_framebuffer_read_color(vedata->fbl->main,
+ GPU_framebuffer_bind(fbl->render_fb);
+ GPU_framebuffer_read_color(vedata->fbl->render_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
@@ -249,135 +228,31 @@ static void GPENCIL_render_result_combined(struct RenderLayer *rl,
rp->rect);
}
-/* helper to blend pixels */
-static void blend_pixel(float top_color[4], float bottom_color[4], float dst_color[4])
-{
- float alpha = top_color[3];
-
- /* use blend: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA */
- dst_color[0] = (top_color[0] * alpha) + (bottom_color[0] * (1.0f - alpha));
- dst_color[1] = (top_color[1] * alpha) + (bottom_color[1] * (1.0f - alpha));
- dst_color[2] = (top_color[2] * alpha) + (bottom_color[2] * (1.0f - alpha));
-}
-
-/* render grease pencil to image */
-void GPENCIL_render_to_image(void *vedata,
+void GPENCIL_render_to_image(void *ved,
RenderEngine *engine,
struct RenderLayer *render_layer,
const rcti *rect)
{
+ GPENCIL_Data *vedata = (GPENCIL_Data *)ved;
const char *viewname = RE_GetActiveRenderView(engine->re);
const DRWContextState *draw_ctx = DRW_context_state_get();
- int imgsize = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
-
- /* save previous render data */
- RenderPass *rpass_color_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
- RenderPass *rpass_depth_src = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
- float *src_rect_color_data = NULL;
- float *src_rect_depth_data = NULL;
- if ((rpass_color_src) && (rpass_depth_src) && (rpass_color_src->rect) &&
- (rpass_depth_src->rect)) {
- src_rect_color_data = MEM_dupallocN(rpass_color_src->rect);
- src_rect_depth_data = MEM_dupallocN(rpass_depth_src->rect);
- }
- else {
- /* TODO: put this message in a better place */
- printf("Warning: To render grease pencil, enable Combined and Z passes.\n");
- }
+ Depsgraph *depsgraph = draw_ctx->depsgraph;
+ GPENCIL_render_init(vedata, engine, render_layer, depsgraph, rect);
GPENCIL_engine_init(vedata);
- GPENCIL_render_init(vedata, engine, draw_ctx->depsgraph);
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- Object *camera = DEG_get_evaluated_object(draw_ctx->depsgraph, RE_GetCamera(engine->re));
- stl->storage->camera = camera; /* save current camera */
-
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- if (fbl->main) {
- GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx, 0, 0);
- GPU_framebuffer_texture_attach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx, 0, 0);
- /* clean first time the buffer */
- float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- GPU_framebuffer_bind(fbl->main);
- GPU_framebuffer_clear_color_depth(fbl->main, clearcol, 1.0f);
- }
-
- /* loop all objects and draw */
- DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, GPENCIL_render_cache);
+ vedata->stl->pd->camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re));
+ /* Loop over all objects and create draw structure. */
+ GPENCIL_cache_init(vedata);
+ DRW_render_object_iter(vedata, engine, depsgraph, GPENCIL_render_cache);
GPENCIL_cache_finish(vedata);
DRW_render_instance_buffer_finish();
+ /* Render the gpencil object and merge the result to the underlying render. */
GPENCIL_draw_scene(vedata);
- /* combined data */
GPENCIL_render_result_combined(render_layer, viewname, vedata, rect);
- /* z-depth data */
GPENCIL_render_result_z(render_layer, viewname, vedata, rect);
-
- /* detach textures */
- if (fbl->main) {
- GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_depth_tx);
- GPU_framebuffer_texture_detach(fbl->main, ((GPENCIL_Data *)vedata)->render_color_tx);
- }
-
- /* merge previous render image with new GP image */
- if (src_rect_color_data) {
- RenderPass *rpass_color_gp = RE_pass_find_by_name(
- render_layer, RE_PASSNAME_COMBINED, viewname);
- RenderPass *rpass_depth_gp = RE_pass_find_by_name(render_layer, RE_PASSNAME_Z, viewname);
- float *gp_rect_color_data = rpass_color_gp->rect;
- float *gp_rect_depth_data = rpass_depth_gp->rect;
- float *gp_pixel_rgba;
- float *gp_pixel_depth;
- float *src_pixel_rgba;
- float *src_pixel_depth;
-
- for (int i = 0; i < imgsize; i++) {
- gp_pixel_rgba = &gp_rect_color_data[i * 4];
- gp_pixel_depth = &gp_rect_depth_data[i];
-
- src_pixel_rgba = &src_rect_color_data[i * 4];
- src_pixel_depth = &src_rect_depth_data[i];
-
- /* check grease pencil render transparency */
- if (gp_pixel_rgba[3] > 0.0f) {
- if (src_pixel_rgba[3] > 0.0f) {
- /* check z-depth */
- if (gp_pixel_depth[0] > src_pixel_depth[0]) {
- /* copy source z-depth */
- gp_pixel_depth[0] = src_pixel_depth[0];
- /* blend object on top */
- if (src_pixel_rgba[3] < 1.0f) {
- blend_pixel(src_pixel_rgba, gp_pixel_rgba, gp_pixel_rgba);
- }
- else {
- copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
- }
- }
- else {
- /* blend gp render */
- if (gp_pixel_rgba[3] < 1.0f) {
- /* premult alpha factor to remove double blend effects */
- mul_v3_fl(gp_pixel_rgba, 1.0f / gp_pixel_rgba[3]);
-
- blend_pixel(gp_pixel_rgba, src_pixel_rgba, gp_pixel_rgba);
-
- gp_pixel_rgba[3] = gp_pixel_rgba[3] > src_pixel_rgba[3] ? gp_pixel_rgba[3] :
- src_pixel_rgba[3];
- }
- }
- }
- }
- else {
- copy_v4_v4(gp_pixel_rgba, src_pixel_rgba);
- gp_pixel_depth[0] = src_pixel_depth[0];
- }
- }
-
- /* free memory */
- MEM_SAFE_FREE(src_rect_color_data);
- MEM_SAFE_FREE(src_rect_depth_data);
- }
}
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader.c b/source/blender/draw/engines/gpencil/gpencil_shader.c
new file mode 100644
index 00000000000..8c7ba42a70e
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_shader.c
@@ -0,0 +1,311 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw
+ */
+#include "DRW_render.h"
+
+#include "gpencil_engine.h"
+
+extern char datatoc_gpencil_common_lib_glsl[];
+extern char datatoc_gpencil_frag_glsl[];
+extern char datatoc_gpencil_vert_glsl[];
+extern char datatoc_gpencil_antialiasing_frag_glsl[];
+extern char datatoc_gpencil_antialiasing_vert_glsl[];
+extern char datatoc_gpencil_layer_blend_frag_glsl[];
+extern char datatoc_gpencil_mask_invert_frag_glsl[];
+extern char datatoc_gpencil_depth_merge_frag_glsl[];
+extern char datatoc_gpencil_depth_merge_vert_glsl[];
+extern char datatoc_gpencil_vfx_frag_glsl[];
+
+extern char datatoc_common_colormanagement_lib_glsl[];
+extern char datatoc_common_fullscreen_vert_glsl[];
+extern char datatoc_common_smaa_lib_glsl[];
+extern char datatoc_common_view_lib_glsl[];
+
+static struct {
+ /* SMAA antialiasing */
+ GPUShader *antialiasing_sh[3];
+ /* GPencil Object rendering */
+ GPUShader *gpencil_sh;
+ /* Final Compositing over rendered background. */
+ GPUShader *composite_sh;
+ /* All layer blend types in one shader! */
+ GPUShader *layer_blend_sh;
+ /* Merge the final object depth to the depth buffer. */
+ GPUShader *depth_merge_sh;
+ /* Invert the content of the mask buffer. */
+ GPUShader *mask_invert_sh;
+ /* Effects. */
+ GPUShader *fx_composite_sh;
+ GPUShader *fx_colorize_sh;
+ GPUShader *fx_blur_sh;
+ GPUShader *fx_glow_sh;
+ GPUShader *fx_pixel_sh;
+ GPUShader *fx_rim_sh;
+ GPUShader *fx_shadow_sh;
+ GPUShader *fx_transform_sh;
+ /* general drawing shaders */
+ GPUShader *gpencil_fill_sh;
+ GPUShader *gpencil_stroke_sh;
+ GPUShader *gpencil_point_sh;
+ GPUShader *gpencil_edit_point_sh;
+ GPUShader *gpencil_line_sh;
+ GPUShader *gpencil_drawing_fill_sh;
+ GPUShader *gpencil_fullscreen_sh;
+ GPUShader *gpencil_simple_fullscreen_sh;
+ GPUShader *gpencil_blend_fullscreen_sh;
+ GPUShader *gpencil_background_sh;
+ GPUShader *gpencil_paper_sh;
+} g_shaders = {{NULL}};
+
+void GPENCIL_shader_free(void)
+{
+ GPUShader **sh_data_as_array = (GPUShader **)&g_shaders;
+ for (int i = 0; i < (sizeof(g_shaders) / sizeof(GPUShader *)); i++) {
+ DRW_SHADER_FREE_SAFE(sh_data_as_array[i]);
+ }
+}
+
+GPUShader *GPENCIL_shader_antialiasing(int stage)
+{
+ BLI_assert(stage < 3);
+
+ if (!g_shaders.antialiasing_sh[stage]) {
+ char stage_define[32];
+ BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage);
+
+ g_shaders.antialiasing_sh[stage] = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 1\n",
+ "#define SMAA_INCLUDE_PS 0\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_gpencil_antialiasing_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ "#define SMAA_INCLUDE_VS 0\n",
+ "#define SMAA_INCLUDE_PS 1\n",
+ "uniform vec4 viewportMetrics;\n",
+ datatoc_common_smaa_lib_glsl,
+ datatoc_gpencil_antialiasing_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define SMAA_GLSL_3\n",
+ "#define SMAA_RT_METRICS viewportMetrics\n",
+ "#define SMAA_PRESET_HIGH\n",
+ "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 0.0)\n",
+ "#define SMAA_NO_DISCARD\n",
+ stage_define,
+ NULL,
+ },
+ });
+ }
+ return g_shaders.antialiasing_sh[stage];
+}
+
+GPUShader *GPENCIL_shader_geometry_get(void)
+{
+ if (!g_shaders.gpencil_sh) {
+ g_shaders.gpencil_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_view_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_common_colormanagement_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define GP_MATERIAL_BUFFER_LEN " STRINGIFY(GP_MATERIAL_BUFFER_LEN) "\n",
+ "#define GPENCIL_LIGHT_BUFFER_LEN " STRINGIFY(GPENCIL_LIGHT_BUFFER_LEN) "\n",
+ "#define UNIFORM_RESOURCE_ID\n",
+ NULL,
+ },
+ });
+ }
+ return g_shaders.gpencil_sh;
+}
+
+GPUShader *GPENCIL_shader_layer_blend_get(void)
+{
+ if (!g_shaders.layer_blend_sh) {
+ g_shaders.layer_blend_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_layer_blend_frag_glsl,
+ NULL,
+ },
+ });
+ }
+ return g_shaders.layer_blend_sh;
+}
+
+GPUShader *GPENCIL_shader_mask_invert_get(void)
+{
+ if (!g_shaders.mask_invert_sh) {
+ g_shaders.mask_invert_sh = DRW_shader_create_fullscreen(datatoc_gpencil_mask_invert_frag_glsl,
+ NULL);
+ }
+ return g_shaders.mask_invert_sh;
+}
+
+GPUShader *GPENCIL_shader_depth_merge_get(void)
+{
+ if (!g_shaders.depth_merge_sh) {
+ g_shaders.depth_merge_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_view_lib_glsl,
+ datatoc_gpencil_depth_merge_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_depth_merge_frag_glsl,
+ NULL,
+ },
+ });
+ }
+ return g_shaders.depth_merge_sh;
+}
+
+/* ------- FX Shaders --------- */
+
+GPUShader *GPENCIL_shader_fx_blur_get(void)
+{
+ if (!g_shaders.fx_blur_sh) {
+ g_shaders.fx_blur_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define BLUR\n");
+ }
+ return g_shaders.fx_blur_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_colorize_get(void)
+{
+ if (!g_shaders.fx_colorize_sh) {
+ g_shaders.fx_colorize_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define COLORIZE\n");
+ }
+ return g_shaders.fx_colorize_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_composite_get(void)
+{
+ if (!g_shaders.fx_composite_sh) {
+ g_shaders.fx_composite_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define COMPOSITE\n");
+ }
+ return g_shaders.fx_composite_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_glow_get(void)
+{
+ if (!g_shaders.fx_glow_sh) {
+ g_shaders.fx_glow_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_vfx_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define GLOW\n",
+ NULL,
+ },
+ });
+ }
+ return g_shaders.fx_glow_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_pixelize_get(void)
+{
+ if (!g_shaders.fx_pixel_sh) {
+ g_shaders.fx_pixel_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define PIXELIZE\n");
+ }
+ return g_shaders.fx_pixel_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_rim_get(void)
+{
+ if (!g_shaders.fx_rim_sh) {
+ g_shaders.fx_rim_sh = GPU_shader_create_from_arrays({
+ .vert =
+ (const char *[]){
+ datatoc_common_fullscreen_vert_glsl,
+ NULL,
+ },
+ .frag =
+ (const char *[]){
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpencil_vfx_frag_glsl,
+ NULL,
+ },
+ .defs =
+ (const char *[]){
+ "#define RIM\n",
+ NULL,
+ },
+ });
+ }
+ return g_shaders.fx_rim_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_shadow_get(void)
+{
+ if (!g_shaders.fx_shadow_sh) {
+ g_shaders.fx_shadow_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define SHADOW\n");
+ }
+ return g_shaders.fx_shadow_sh;
+}
+
+GPUShader *GPENCIL_shader_fx_transform_get(void)
+{
+ if (!g_shaders.fx_transform_sh) {
+ g_shaders.fx_transform_sh = DRW_shader_create_fullscreen(datatoc_gpencil_vfx_frag_glsl,
+ "#define TRANSFORM\n");
+ }
+ return g_shaders.fx_transform_sh;
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
index f6a62e0d472..9467efcd18c 100644
--- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
+++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c
@@ -26,28 +26,17 @@
#include "BKE_gpencil.h"
+#include "BLI_link_utils.h"
+#include "BLI_memblock.h"
+
#include "DRW_render.h"
#include "BKE_camera.h"
#include "gpencil_engine.h"
-extern char datatoc_gpencil_fx_blur_frag_glsl[];
-extern char datatoc_gpencil_fx_colorize_frag_glsl[];
-extern char datatoc_gpencil_fx_flip_frag_glsl[];
-extern char datatoc_gpencil_fx_light_frag_glsl[];
-extern char datatoc_gpencil_fx_pixel_frag_glsl[];
-extern char datatoc_gpencil_fx_rim_prepare_frag_glsl[];
-extern char datatoc_gpencil_fx_rim_resolve_frag_glsl[];
-extern char datatoc_gpencil_fx_shadow_prepare_frag_glsl[];
-extern char datatoc_gpencil_fx_shadow_resolve_frag_glsl[];
-extern char datatoc_gpencil_fx_glow_prepare_frag_glsl[];
-extern char datatoc_gpencil_fx_glow_resolve_frag_glsl[];
-extern char datatoc_gpencil_fx_swirl_frag_glsl[];
-extern char datatoc_gpencil_fx_wave_frag_glsl[];
-
/* verify if this fx is active */
-static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_render)
+static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_viewport)
{
if (fx == NULL) {
return false;
@@ -58,1007 +47,613 @@ static bool effect_is_active(bGPdata *gpd, ShaderFxData *fx, bool is_render)
}
bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
- if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit) && (!is_render)) {
+ if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit) && (is_viewport)) {
return false;
}
- if (((fx->mode & eShaderFxMode_Realtime) && (is_render == false)) ||
- ((fx->mode & eShaderFxMode_Render) && (is_render == true))) {
+ if (((fx->mode & eShaderFxMode_Realtime) && (is_viewport == true)) ||
+ ((fx->mode & eShaderFxMode_Render) && (is_viewport == false))) {
return true;
}
return false;
}
-/**
- * Get normal of draw using one stroke of visible layer
- * \param gpd: GP datablock
- * \param r_point: Point on plane
- * \param r_normal: Normal vector
- */
-static bool get_normal_vector(bGPdata *gpd, float r_point[3], float r_normal[3])
+typedef struct gpIterVfxData {
+ GPENCIL_PrivateData *pd;
+ GPENCIL_tObject *tgp_ob;
+ GPUFrameBuffer **target_fb;
+ GPUFrameBuffer **source_fb;
+ GPUTexture **target_color_tx;
+ GPUTexture **source_color_tx;
+ GPUTexture **target_reveal_tx;
+ GPUTexture **source_reveal_tx;
+} gpIterVfxData;
+
+static DRWShadingGroup *gpencil_vfx_pass_create(const char *name,
+ DRWState state,
+ gpIterVfxData *iter,
+ GPUShader *sh)
{
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
+ DRWPass *pass = DRW_pass_create(name, state);
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_texture_ref(grp, "colorBuf", iter->source_color_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "revealBuf", iter->source_reveal_tx);
- /* get frame */
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (gps->totpoints >= 3) {
- bGPDspoint *pt = &gps->points[0];
- BKE_gpencil_stroke_normal(gps, r_normal);
- /* in some weird situations, the normal cannot be calculated, so try next stroke */
- if ((r_normal[0] != 0.0f) || (r_normal[1] != 0.0f) || (r_normal[2] != 0.0f)) {
- copy_v3_v3(r_point, &pt->x);
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-/* helper to get near and far depth of field values */
-static void GPENCIL_dof_nearfar(Object *camera, float coc, float nearfar[2])
-{
- if (camera == NULL) {
- return;
- }
- Camera *cam = camera->data;
+ GPENCIL_tVfx *tgp_vfx = BLI_memblock_alloc(iter->pd->gp_vfx_pool);
+ tgp_vfx->target_fb = iter->target_fb;
+ tgp_vfx->vfx_ps = pass;
- float fstop = cam->dof.aperture_fstop;
- float focus_dist = BKE_camera_object_dof_distance(camera);
- float focal_len = cam->lens;
+ SWAP(GPUFrameBuffer **, iter->target_fb, iter->source_fb);
+ SWAP(GPUTexture **, iter->target_color_tx, iter->source_color_tx);
+ SWAP(GPUTexture **, iter->target_reveal_tx, iter->source_reveal_tx);
- const float scale_camera = 0.001f;
- /* we want radius here for the aperture number */
- float aperture_scaled = 0.5f * scale_camera * focal_len / fstop;
- float focal_len_scaled = scale_camera * focal_len;
+ BLI_LINKS_APPEND(&iter->tgp_ob->vfx, tgp_vfx);
- float hyperfocal = (focal_len_scaled * focal_len_scaled) / (aperture_scaled * coc);
- nearfar[0] = (hyperfocal * focus_dist) / (hyperfocal + focal_len);
- nearfar[1] = (hyperfocal * focus_dist) / (hyperfocal - focal_len);
+ return grp;
}
-/* **************** Shader Effects ***************************** */
-
-/* Gaussian Blur FX
- * The effect is done using two shading groups because is faster to apply horizontal
- * and vertical in different operations.
- */
-static void gpencil_fx_blur(ShaderFxData *fx,
- int ob_idx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
+ if (fx->radius[0] == 0.0f && fx->radius[1] == 0.0f) {
return;
}
- BlurShaderFxData *fxd = (BlurShaderFxData *)fx;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- const DRWContextState *draw_ctx = DRW_context_state_get();
- View3D *v3d = draw_ctx->v3d;
- RegionView3D *rv3d = draw_ctx->rv3d;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- fxd->blur[0] = fxd->radius[0];
- fxd->blur[1] = fxd->radius[1];
-
- /* init weight */
- if (fxd->flag & FX_BLUR_DOF_MODE) {
- /* viewport and opengl render */
- Object *camera = NULL;
- if (rv3d) {
- if (rv3d->persp == RV3D_CAMOB) {
- camera = v3d->camera;
- }
- }
- else {
- camera = stl->storage->camera;
- }
-
- if (camera) {
- float nearfar[2];
- GPENCIL_dof_nearfar(camera, fxd->coc, nearfar);
- float zdepth = stl->g_data->gp_object_cache[ob_idx].zdepth;
- /* the object is on focus area */
- if ((zdepth >= nearfar[0]) && (zdepth <= nearfar[1])) {
- fxd->blur[0] = 0;
- fxd->blur[1] = 0;
- }
- else {
- float f;
- if (zdepth < nearfar[0]) {
- f = nearfar[0] - zdepth;
- }
- else {
- f = zdepth - nearfar[1];
- }
- fxd->blur[0] = f;
- fxd->blur[1] = f;
- CLAMP2(&fxd->blur[0], 0, fxd->radius[0]);
- }
- }
- else {
- /* if not camera view, the blur is disabled */
- fxd->blur[0] = 0;
- fxd->blur[1] = 0;
- }
- }
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
+ DRWShadingGroup *grp;
+ const float s = sin(fx->rotation);
+ const float c = cos(fx->rotation);
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-}
+ float winmat[4][4], persmat[4][4];
+ float blur_size[2] = {fx->radius[0], fx->radius[1]};
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
-/* Colorize FX */
-static void gpencil_fx_colorize(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
-{
- if (fx == NULL) {
- return;
+ if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) {
+ /* Compute circle of confusion size. */
+ float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1];
+ copy_v2_fl(blur_size, fabsf(coc));
+ }
+ else {
+ /* Modify by distance to camera and object scale. */
+ DRW_view_winmat_get(NULL, winmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = world_pixel_scale * scale * winmat[1][1] * vp_size[1] / w;
+ mul_v2_fl(blur_size, distance_factor);
+ }
+
+ GPUShader *sh = GPENCIL_shader_fx_blur_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ if (blur_size[0] > 0.0f) {
+ grp = gpencil_vfx_pass_create("Fx Blur H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){blur_size[0] * c, blur_size[0] * s});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0])));
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ if (blur_size[1] > 0.0f) {
+ grp = gpencil_vfx_pass_create("Fx Blur V", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){-blur_size[1] * s, blur_size[1] * c});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1])));
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_colorize_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec4(fx_shgrp, "low_color", &fxd->low_color[0], 1);
- DRW_shgroup_uniform_vec4(fx_shgrp, "high_color", &fxd->high_color[0], 1);
- DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "factor", &fxd->factor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
}
-/* Flip FX */
-static void gpencil_fx_flip(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+static void gpencil_vfx_colorize(ColorizeShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- FlipShaderFxData *fxd = (FlipShaderFxData *)fx;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- fxd->flipmode = 100;
- /* the number works as bit flag */
- if (fxd->flag & FX_FLIP_HORIZONTAL) {
- fxd->flipmode += 10;
- }
- if (fxd->flag & FX_FLIP_VERTICAL) {
- fxd->flipmode += 1;
- }
+ DRWShadingGroup *grp;
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_flip_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_int(fx_shgrp, "flipmode", &fxd->flipmode, 1);
+ GPUShader *sh = GPENCIL_shader_fx_colorize_get();
- DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Colorize", state, iter, sh);
+ DRW_shgroup_uniform_vec3_copy(grp, "lowColor", fx->low_color);
+ DRW_shgroup_uniform_vec3_copy(grp, "highColor", fx->high_color);
+ DRW_shgroup_uniform_float_copy(grp, "factor", fx->factor);
+ DRW_shgroup_uniform_int_copy(grp, "mode", fx->mode);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Light FX */
-static void gpencil_fx_light(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_flip(FlipShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- LightShaderFxData *fxd = (LightShaderFxData *)fx;
-
- if (fxd->object == NULL) {
- return;
- }
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_light_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
-
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
-
- /* location of the light using obj location as origin */
- copy_v3_v3(fxd->loc, fxd->object->obmat[3]);
-
- /* Calc distance to strokes plane
- * The w component of location is used to transfer the distance to drawing plane
- */
- float r_point[3], r_normal[3];
- float r_plane[4];
- bGPdata *gpd = cache->gpd;
- if (!get_normal_vector(gpd, r_point, r_normal)) {
- return;
- }
- mul_mat3_m4_v3(cache->obmat, r_normal); /* only rotation component */
- plane_from_point_normal_v3(r_plane, r_point, r_normal);
- float dt = dist_to_plane_v3(fxd->object->obmat[3], r_plane);
- fxd->loc[3] = dt; /* use last element to save it */
+ DRWShadingGroup *grp;
- DRW_shgroup_uniform_vec4(fx_shgrp, "loc", &fxd->loc[0], 1);
+ float axis_flip[2];
+ axis_flip[0] = (fx->flag & FX_FLIP_HORIZONTAL) ? -1.0f : 1.0f;
+ axis_flip[1] = (fx->flag & FX_FLIP_VERTICAL) ? -1.0f : 1.0f;
- DRW_shgroup_uniform_float(fx_shgrp, "energy", &fxd->energy, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "ambient", &fxd->ambient, 1);
+ GPUShader *sh = GPENCIL_shader_fx_transform_get();
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", axis_flip);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", (float[2]){0.0f, 0.0f});
+ DRW_shgroup_uniform_float_copy(grp, "swirlRadius", 0.0f);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Pixelate FX */
-static void gpencil_fx_pixel(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
+ DRWShadingGroup *grp;
+
+ float winmat[4][4], persmat[4][4];
+ float offset[2] = {fx->offset[0], fx->offset[1]};
+ float blur_size[2] = {fx->blur[0], fx->blur[1]};
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
+
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
+
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
+ mul_v2_fl(offset, distance_factor);
+ mul_v2_v2(offset, vp_size_inv);
+ mul_v2_fl(blur_size, distance_factor);
+
+ GPUShader *sh = GPENCIL_shader_fx_rim_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Rim H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", (float[2]){blur_size[0] * vp_size_inv[0], 0.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", offset);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0])));
+ DRW_shgroup_uniform_vec3_copy(grp, "maskColor", fx->mask_rgb);
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ switch (fx->mode) {
+ case eShaderFxRimMode_Normal:
+ state |= DRW_STATE_BLEND_ALPHA_PREMUL;
+ break;
+ case eShaderFxRimMode_Add:
+ state |= DRW_STATE_BLEND_ADD_FULL;
+ break;
+ case eShaderFxRimMode_Subtract:
+ state |= DRW_STATE_BLEND_SUB;
+ break;
+ case eShaderFxRimMode_Multiply:
+ case eShaderFxRimMode_Divide:
+ case eShaderFxRimMode_Overlay:
+ state |= DRW_STATE_BLEND_MUL;
+ break;
+ }
+
+ zero_v2(offset);
+
+ grp = gpencil_vfx_pass_create("Fx Rim V", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", (float[2]){0.0f, blur_size[1] * vp_size_inv[1]});
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", offset);
+ DRW_shgroup_uniform_vec3_copy(grp, "rimColor", fx->rim_rgb);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1])));
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", fx->mode);
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (fx->mode == eShaderFxRimMode_Overlay) {
+ /* We cannot do custom blending on MultiTarget framebuffers.
+ * Workaround by doing 2 passes. */
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", 999);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- fxd->size[2] = (int)fxd->flag & FX_PIXEL_USE_LINES;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_pixel_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_int(fx_shgrp, "size", &fxd->size[0], 3);
- DRW_shgroup_uniform_vec4(fx_shgrp, "color", &fxd->rgba[0], 1);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
}
-/* Rim FX */
-static void gpencil_fx_rim(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
+ DRWShadingGroup *grp;
+
+ float persmat[4][4], winmat[4][4], ob_center[3], pixsize_uniform[2];
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
+ float pixel_size[2] = {fx->size[0], fx->size[1]};
+ mul_v2_v2(pixel_size, vp_size_inv);
+
+ /* Fixed pixelisation center from object center. */
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
+ mul_v3_m4v3(ob_center, persmat, ob->obmat[3]);
+ mul_v3_fl(ob_center, 1.0f / w);
+
+ /* Convert to uvs. */
+ mul_v2_fl(ob_center, 0.5f);
+ add_v2_fl(ob_center, 0.5f);
+
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ mul_v2_fl(pixel_size, (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w);
+
+ /* Center to texel */
+ madd_v2_v2fl(ob_center, pixel_size, -0.5f);
+
+ GPUShader *sh = GPENCIL_shader_fx_pixelize_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+
+ /* Only if pixelated effect is bigger than 1px. */
+ if (pixel_size[0] > vp_size_inv[0]) {
+ copy_v2_fl2(pixsize_uniform, pixel_size[0], vp_size_inv[1]);
+ grp = gpencil_vfx_pass_create("Fx Pixelize X", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform);
+ DRW_shgroup_uniform_vec2_copy(grp, "targetPixelOffset", ob_center);
+ DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){pixel_size[0], 0.0f});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[0] / vp_size_inv[0] > 3.0) ? 2 : 1);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+
+ if (pixel_size[1] > vp_size_inv[1]) {
+ copy_v2_fl2(pixsize_uniform, vp_size_inv[0], pixel_size[1]);
+ grp = gpencil_vfx_pass_create("Fx Pixelize Y", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "targetPixelSize", pixsize_uniform);
+ DRW_shgroup_uniform_vec2_copy(grp, "accumOffset", (float[2]){0.0f, pixel_size[1]});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", (pixel_size[1] / vp_size_inv[1] > 3.0) ? 2 : 1);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
- RimShaderFxData *fxd = (RimShaderFxData *)fx;
- bGPdata *gpd = cache->gpd;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- /* prepare pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_prepare_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
-
- DRW_shgroup_uniform_int(fx_shgrp, "offset", &fxd->offset[0], 2);
- DRW_shgroup_uniform_vec3(fx_shgrp, "rim_color", &fxd->rim_rgb[0], 1);
- DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-
- /* blur pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh_b = fx_shgrp;
-
- /* resolve pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_rim_resolve_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeRim", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_vec3(fx_shgrp, "mask_color", &fxd->mask_rgb[0], 1);
- DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
-
- fxd->runtime.fx_sh_c = fx_shgrp;
}
-/* Shadow FX */
-static void gpencil_fx_shadow(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
- if ((!fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) {
- fxd->runtime.fx_sh = NULL;
- fxd->runtime.fx_sh_b = NULL;
- fxd->runtime.fx_sh_c = NULL;
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- /* prepare pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_shadow_prepare_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
-
- DRW_shgroup_uniform_int(fx_shgrp, "offset", &fxd->offset[0], 2);
- DRW_shgroup_uniform_float(fx_shgrp, "scale", &fxd->scale[0], 2);
- DRW_shgroup_uniform_float(fx_shgrp, "rotation", &fxd->rotation, 1);
- DRW_shgroup_uniform_vec4(fx_shgrp, "shadow_color", &fxd->shadow_rgba[0], 1);
-
- if ((fxd->object) && (fxd->flag & FX_SHADOW_USE_OBJECT)) {
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->object->obmat[3], 1);
- }
- else {
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- }
-
- if (fxd->flag & FX_SHADOW_USE_WAVE) {
- DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1);
+ DRWShadingGroup *grp;
+
+ const bool use_obj_pivot = (fx->flag & FX_SHADOW_USE_OBJECT) != 0;
+ const bool use_wave = (fx->flag & FX_SHADOW_USE_WAVE) != 0;
+
+ float uv_mat[4][4], winmat[4][4], persmat[4][4], rot_center[3];
+ float wave_ofs[3], wave_dir[3], wave_phase, blur_dir[2], tmp[2];
+ float offset[2] = {fx->offset[0], fx->offset[1]};
+ float blur_size[2] = {fx->blur[0], fx->blur[1]};
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
+ const float ratio = vp_size_inv[1] / vp_size_inv[0];
+
+ copy_v3_v3(rot_center, (use_obj_pivot && fx->object) ? fx->object->obmat[3] : ob->obmat[3]);
+
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, rot_center));
+ mul_v3_m4v3(rot_center, persmat, rot_center);
+ mul_v3_fl(rot_center, 1.0f / w);
+
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
+ mul_v2_fl(offset, distance_factor);
+ mul_v2_v2(offset, vp_size_inv);
+ mul_v2_fl(blur_size, distance_factor);
+
+ rot_center[0] = rot_center[0] * 0.5f + 0.5f;
+ rot_center[1] = rot_center[1] * 0.5f + 0.5f;
+
+ /* UV transform matrix. (loc, rot, scale) Sent to shader as 2x3 matrix. */
+ unit_m4(uv_mat);
+ translate_m4(uv_mat, rot_center[0], rot_center[1], 0.0f);
+ rescale_m4(uv_mat, (float[3]){1.0f / fx->scale[0], 1.0f / fx->scale[1], 1.0f});
+ translate_m4(uv_mat, -offset[0], -offset[1], 0.0f);
+ rescale_m4(uv_mat, (float[3]){1.0f / ratio, 1.0f, 1.0f});
+ rotate_m4(uv_mat, 'Z', fx->rotation);
+ rescale_m4(uv_mat, (float[3]){ratio, 1.0f, 1.0f});
+ translate_m4(uv_mat, -rot_center[0], -rot_center[1], 0.0f);
+
+ if (use_wave) {
+ float dir[2];
+ if (fx->orientation == 0) {
+ /* Horizontal */
+ copy_v2_fl2(dir, 1.0f, 0.0f);
+ }
+ else {
+ /* Vertical */
+ copy_v2_fl2(dir, 0.0f, 1.0f);
+ }
+ /* This is applied after rotation. Counter the rotation to keep aligned with global axis. */
+ rotate_v2_v2fl(wave_dir, dir, fx->rotation);
+ /* Rotate 90°. */
+ copy_v2_v2(wave_ofs, wave_dir);
+ SWAP(float, wave_ofs[0], wave_ofs[1]);
+ wave_ofs[1] *= -1.0f;
+ /* Keep world space scalling and aspect ratio. */
+ mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
+ mul_v2_v2(wave_dir, vp_size);
+ mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
+ mul_v2_v2(wave_ofs, vp_size_inv);
+ /* Phase start at shadow center. */
+ wave_phase = fx->phase - dot_v2v2(rot_center, wave_dir);
}
else {
- DRW_shgroup_uniform_int_copy(fx_shgrp, "orientation", -1);
- }
- DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "period", &fxd->period, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "phase", &fxd->phase, 1);
-
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-
- /* blur pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh_b = fx_shgrp;
-
- /* resolve pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_shadow_resolve_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "shadowDepth", &stl->g_data->temp_depth_tx_fx);
-
- fxd->runtime.fx_sh_c = fx_shgrp;
+ zero_v2(wave_dir);
+ zero_v2(wave_ofs);
+ wave_phase = 0.0f;
+ }
+
+ GPUShader *sh = GPENCIL_shader_fx_shadow_get();
+
+ copy_v2_fl2(blur_dir, blur_size[0] * vp_size_inv[0], 0.0f);
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Shadow H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", blur_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveDir", wave_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs);
+ DRW_shgroup_uniform_float_copy(grp, "wavePhase", wave_phase);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotX", uv_mat[0]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotY", uv_mat[1]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", uv_mat[3]);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[0])));
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ unit_m4(uv_mat);
+ zero_v2(wave_ofs);
+
+ /* We reseted the uv_mat so we need to accound for the rotation in the */
+ copy_v2_fl2(tmp, 0.0f, blur_size[1]);
+ rotate_v2_v2fl(blur_dir, tmp, -fx->rotation);
+ mul_v2_v2(blur_dir, vp_size_inv);
+
+ state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL;
+ grp = gpencil_vfx_pass_create("Fx Shadow V", state, iter, sh);
+ DRW_shgroup_uniform_vec4_copy(grp, "shadowColor", fx->shadow_rgba);
+ DRW_shgroup_uniform_vec2_copy(grp, "blurDir", blur_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotX", uv_mat[0]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvRotY", uv_mat[1]);
+ DRW_shgroup_uniform_vec2_copy(grp, "uvOffset", uv_mat[3]);
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, blur_size[1])));
+ DRW_shgroup_uniform_bool_copy(grp, "isFirstPass", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Glow FX */
-static void gpencil_fx_glow(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
+static void gpencil_vfx_glow(GlowShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
- return;
- }
- GlowShaderFxData *fxd = (GlowShaderFxData *)fx;
- bGPdata *gpd = cache->gpd;
- copy_v3_v3(fxd->runtime.loc, cache->loc);
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
-
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- /* prepare pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_glow_prepare_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "glow_color", &fxd->glow_color[0], 1);
- DRW_shgroup_uniform_vec3(fx_shgrp, "select_color", &fxd->select_color[0], 1);
- DRW_shgroup_uniform_int(fx_shgrp, "mode", &fxd->mode, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "threshold", &fxd->threshold, 1);
-
- fxd->runtime.fx_sh = fx_shgrp;
-
- /* blur pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_fx);
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
- DRW_shgroup_uniform_int(fx_shgrp, "blur", &fxd->blur[0], 2);
-
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->runtime.loc, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
-
- fxd->runtime.fx_sh_b = fx_shgrp;
-
- /* resolve pass */
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_glow_resolve_sh, psl->fx_shader_pass_blend);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowColor", &stl->g_data->temp_color_tx_fx);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "glowDepth", &stl->g_data->temp_depth_tx_fx);
-
- /* reuse field */
- DRW_shgroup_uniform_int(fx_shgrp, "alpha_mode", &fxd->blur[1], 1);
-
- fxd->runtime.fx_sh_c = fx_shgrp;
-}
+ const bool use_glow_under = (fx->flag & FX_GLOW_USE_ALPHA) != 0;
+ DRWShadingGroup *grp;
+ const float s = sin(fx->rotation);
+ const float c = cos(fx->rotation);
-/* Swirl FX */
-static void gpencil_fx_swirl(ShaderFxData *fx,
- GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache)
-{
- if (fx == NULL) {
- return;
- }
- SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
- if (fxd->object == NULL) {
- return;
- }
+ GPUShader *sh = GPENCIL_shader_fx_glow_get();
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- DRWShadingGroup *fx_shgrp;
- bGPdata *gpd = cache->gpd;
+ float ref_col[3];
- fxd->transparent = (int)fxd->flag & FX_SWIRL_MAKE_TRANSPARENT;
+ if (fx->mode == eShaderFxGlowMode_Luminance) {
+ ref_col[0] = fx->threshold;
+ ref_col[1] = -1.0f;
+ ref_col[2] = -1.0f;
+ }
+ else {
+ copy_v3_v3(ref_col, fx->select_color);
+ }
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Glow H", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){fx->blur[0] * c, fx->blur[0] * s});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, fx->blur[0])));
+ DRW_shgroup_uniform_vec3_copy(grp, "threshold", ref_col);
+ DRW_shgroup_uniform_vec4_copy(grp, "glowColor", fx->glow_color);
+ DRW_shgroup_uniform_bool_copy(grp, "glowUnder", use_glow_under);
+ DRW_shgroup_uniform_bool_copy(grp, "firstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ state = DRW_STATE_WRITE_COLOR;
+ /* Blending: Force blending. */
+ switch (fx->blend_mode) {
+ case eGplBlendMode_Regular:
+ state |= DRW_STATE_BLEND_ALPHA_PREMUL;
+ break;
+ case eGplBlendMode_Add:
+ state |= DRW_STATE_BLEND_ADD_FULL;
+ break;
+ case eGplBlendMode_Subtract:
+ state |= DRW_STATE_BLEND_SUB;
+ break;
+ case eGplBlendMode_Multiply:
+ case eGplBlendMode_Divide:
+ state |= DRW_STATE_BLEND_MUL;
+ break;
+ }
+
+ /* Small Hack: We ask for RGBA16F buffer if using use_glow_under to store original
+ * revealage in alpha channel. */
+ if (fx->blend_mode == eGplBlendMode_Subtract || use_glow_under) {
+ /* For this effect to propagate, we need a signed floating point buffer. */
+ iter->pd->use_signed_fb = true;
+ }
+
+ grp = gpencil_vfx_pass_create("Fx Glow V", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "offset", (float[2]){-fx->blur[1] * s, fx->blur[1] * c});
+ DRW_shgroup_uniform_int_copy(grp, "sampCount", max_ii(1, min_ii(fx->samples, fx->blur[0])));
+ DRW_shgroup_uniform_vec3_copy(grp, "threshold", (float[3]){-1.0f, -1.0f, -1.0f});
+ DRW_shgroup_uniform_vec4_copy(grp, "glowColor", (float[4]){1.0f, 1.0f, 1.0f, fx->glow_color[3]});
+ DRW_shgroup_uniform_bool_copy(grp, "firstPass", false);
+ DRW_shgroup_uniform_int_copy(grp, "blendMode", fx->blend_mode);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+}
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
- fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_swirl_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
+static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *iter)
+{
+ DRWShadingGroup *grp;
- DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1);
+ float winmat[4][4], persmat[4][4], wave_center[3];
+ float wave_ofs[3], wave_dir[3], wave_phase;
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
+ const float *vp_size_inv = DRW_viewport_invert_size_get();
- DRW_shgroup_uniform_vec3(fx_shgrp, "loc", fxd->object->obmat[3], 1);
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3]));
+ mul_v3_m4v3(wave_center, persmat, ob->obmat[3]);
+ mul_v3_fl(wave_center, 1.0f / w);
- DRW_shgroup_uniform_int(fx_shgrp, "radius", &fxd->radius, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "angle", &fxd->angle, 1);
- DRW_shgroup_uniform_int(fx_shgrp, "transparent", &fxd->transparent, 1);
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(ob->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
- DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1);
+ wave_center[0] = wave_center[0] * 0.5f + 0.5f;
+ wave_center[1] = wave_center[1] * 0.5f + 0.5f;
- fxd->runtime.fx_sh = fx_shgrp;
+ if (fx->orientation == 0) {
+ /* Horizontal */
+ copy_v2_fl2(wave_dir, 1.0f, 0.0f);
+ }
+ else {
+ /* Vertical */
+ copy_v2_fl2(wave_dir, 0.0f, 1.0f);
+ }
+ /* Rotate 90°. */
+ copy_v2_v2(wave_ofs, wave_dir);
+ SWAP(float, wave_ofs[0], wave_ofs[1]);
+ wave_ofs[1] *= -1.0f;
+ /* Keep world space scalling and aspect ratio. */
+ mul_v2_fl(wave_dir, 1.0f / (max_ff(1e-8f, fx->period) * distance_factor));
+ mul_v2_v2(wave_dir, vp_size);
+ mul_v2_fl(wave_ofs, fx->amplitude * distance_factor);
+ mul_v2_v2(wave_ofs, vp_size_inv);
+ /* Phase start at shadow center. */
+ wave_phase = fx->phase - dot_v2v2(wave_center, wave_dir);
+
+ GPUShader *sh = GPENCIL_shader_fx_transform_get();
+
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Wave", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", (float[2]){1.0f, 1.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "waveDir", wave_dir);
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", wave_ofs);
+ DRW_shgroup_uniform_float_copy(grp, "wavePhase", wave_phase);
+ DRW_shgroup_uniform_float_copy(grp, "swirlRadius", 0.0f);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* Wave Distortion FX */
-static void gpencil_fx_wave(ShaderFxData *fx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata)
+static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object *UNUSED(ob), gpIterVfxData *iter)
{
- if (fx == NULL) {
+ DRWShadingGroup *grp;
+
+ if (fx->object == NULL) {
return;
}
- WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPUBatch *fxquad = DRW_cache_fullscreen_quad_get();
-
- DRWShadingGroup *fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_wave_sh, psl->fx_shader_pass);
- DRW_shgroup_call(fx_shgrp, fxquad, NULL);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &stl->g_data->temp_color_tx_a);
- DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &stl->g_data->temp_depth_tx_a);
- DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &fxd->amplitude, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "period", &fxd->period, 1);
- DRW_shgroup_uniform_float(fx_shgrp, "phase", &fxd->phase, 1);
- DRW_shgroup_uniform_int(fx_shgrp, "orientation", &fxd->orientation, 1);
- DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1);
+ float winmat[4][4], persmat[4][4], swirl_center[3];
+ DRW_view_winmat_get(NULL, winmat, false);
+ DRW_view_persmat_get(NULL, persmat, false);
+ const float *vp_size = DRW_viewport_size_get();
- fxd->runtime.fx_sh = fx_shgrp;
-}
-
-/* ************************************************************** */
+ copy_v3_v3(swirl_center, fx->object->obmat[3]);
-/* create all FX shaders */
-void GPENCIL_create_fx_shaders(GPENCIL_e_data *e_data)
-{
- /* fx shaders (all in screen space) */
- if (!e_data->gpencil_fx_blur_sh) {
- e_data->gpencil_fx_blur_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_blur_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_colorize_sh) {
- e_data->gpencil_fx_colorize_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_colorize_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_flip_sh) {
- e_data->gpencil_fx_flip_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_flip_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_light_sh) {
- e_data->gpencil_fx_light_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_light_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_pixel_sh) {
- e_data->gpencil_fx_pixel_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_pixel_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_rim_prepare_sh) {
- e_data->gpencil_fx_rim_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_rim_prepare_frag_glsl, NULL);
+ const float w = fabsf(mul_project_m4_v3_zfac(persmat, swirl_center));
+ mul_v3_m4v3(swirl_center, persmat, swirl_center);
+ mul_v3_fl(swirl_center, 1.0f / w);
- e_data->gpencil_fx_rim_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_rim_resolve_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_shadow_prepare_sh) {
- e_data->gpencil_fx_shadow_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_shadow_prepare_frag_glsl, NULL);
+ /* Modify by distance to camera and object scale. */
+ float world_pixel_scale = 1.0f / GPENCIL_PIXEL_FACTOR;
+ float scale = mat4_to_scale(fx->object->obmat);
+ float distance_factor = (world_pixel_scale * scale * winmat[1][1] * vp_size[1]) / w;
- e_data->gpencil_fx_shadow_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_shadow_resolve_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_glow_prepare_sh) {
- e_data->gpencil_fx_glow_prepare_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_glow_prepare_frag_glsl, NULL);
+ mul_v2_fl(swirl_center, 0.5f);
+ add_v2_fl(swirl_center, 0.5f);
+ mul_v2_v2(swirl_center, vp_size);
- e_data->gpencil_fx_glow_resolve_sh = DRW_shader_create_fullscreen(
- datatoc_gpencil_fx_glow_resolve_frag_glsl, NULL);
- }
- if (!e_data->gpencil_fx_swirl_sh) {
- e_data->gpencil_fx_swirl_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_swirl_frag_glsl,
- NULL);
- }
- if (!e_data->gpencil_fx_wave_sh) {
- e_data->gpencil_fx_wave_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_wave_frag_glsl,
- NULL);
+ float radius = fx->radius * distance_factor;
+ if (radius < 1.0f) {
+ return;
}
-}
-/* free FX shaders */
-void GPENCIL_delete_fx_shaders(GPENCIL_e_data *e_data)
-{
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_blur_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_colorize_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_flip_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_light_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_pixel_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_rim_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_shadow_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_shadow_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_prepare_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_glow_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_swirl_sh);
- DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_wave_sh);
-}
+ GPUShader *sh = GPENCIL_shader_fx_transform_get();
-/* create all passes used by FX */
-void GPENCIL_create_fx_passes(GPENCIL_PassList *psl)
-{
- psl->fx_shader_pass = DRW_pass_create("GPencil Shader FX Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH |
- DRW_STATE_DEPTH_LESS);
- psl->fx_shader_pass_blend = DRW_pass_create("GPencil Shader FX Pass",
- DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA |
- DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
+ DRWState state = DRW_STATE_WRITE_COLOR;
+ grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh);
+ DRW_shgroup_uniform_vec2_copy(grp, "axisFlip", (float[2]){1.0f, 1.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "waveOffset", (float[2]){0.0f, 0.0f});
+ DRW_shgroup_uniform_vec2_copy(grp, "swirlCenter", swirl_center);
+ DRW_shgroup_uniform_float_copy(grp, "swirlAngle", fx->angle);
+ DRW_shgroup_uniform_float_copy(grp, "swirlRadius", radius);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
}
-/* prepare fx shading groups */
-void gpencil_fx_prepare(GPENCIL_e_data *e_data,
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache_ob)
+void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, Object *ob, GPENCIL_tObject *tgp_ob)
{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- const bool wiremode = (bool)(cache_ob->shading_type[0] == OB_WIRE);
-
- int ob_idx = cache_ob->idx;
-
- if ((wiremode) || (cache_ob->shader_fx.first == NULL)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ GPENCIL_FramebufferList *fbl = vedata->fbl;
+ GPENCIL_PrivateData *pd = vedata->stl->pd;
+ /* If simplify enabled, nothing more to do. */
+ if (pd->simplify_fx) {
return;
}
- /* loop FX */
- for (ShaderFxData *fx = cache_ob->shader_fx.first; fx; fx = fx->next) {
- if (effect_is_active(cache_ob->gpd, fx, stl->storage->is_render)) {
+
+ /* These may not be allocated yet, use adress of future pointer. */
+ gpIterVfxData iter = {
+ .pd = pd,
+ .tgp_ob = tgp_ob,
+ .target_fb = &fbl->layer_fb,
+ .source_fb = &fbl->object_fb,
+ .target_color_tx = &pd->color_layer_tx,
+ .source_color_tx = &pd->color_object_tx,
+ .target_reveal_tx = &pd->reveal_layer_tx,
+ .source_reveal_tx = &pd->reveal_object_tx,
+ };
+
+ LISTBASE_FOREACH (ShaderFxData *, fx, &ob->shader_fx) {
+ if (effect_is_active(gpd, fx, pd->is_viewport)) {
switch (fx->type) {
case eShaderFxType_Blur:
- gpencil_fx_blur(fx, ob_idx, e_data, vedata, cache_ob);
+ gpencil_vfx_blur((BlurShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Colorize:
- gpencil_fx_colorize(fx, e_data, vedata);
+ gpencil_vfx_colorize((ColorizeShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Flip:
- gpencil_fx_flip(fx, e_data, vedata);
- break;
- case eShaderFxType_Light:
- gpencil_fx_light(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_flip((FlipShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Pixel:
- gpencil_fx_pixel(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_pixelize((PixelShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Rim:
- gpencil_fx_rim(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_rim((RimShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Shadow:
- gpencil_fx_shadow(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_shadow((ShadowShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Glow:
- gpencil_fx_glow(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_glow((GlowShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Swirl:
- gpencil_fx_swirl(fx, e_data, vedata, cache_ob);
+ gpencil_vfx_swirl((SwirlShaderFxData *)fx, ob, &iter);
break;
case eShaderFxType_Wave:
- gpencil_fx_wave(fx, e_data, vedata);
+ gpencil_vfx_wave((WaveShaderFxData *)fx, ob, &iter);
break;
default:
break;
}
}
}
-}
-
-/* helper to draw one FX pass and do ping-pong copy */
-static void gpencil_draw_fx_pass(GPENCIL_Data *vedata, DRWShadingGroup *shgrp, bool blend)
-{
- if (shgrp == NULL) {
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
-
- const float clearcol[4] = {0.0f};
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
-
- /* draw effect pass in temp texture (B) using as source the previous image
- * existing in the other temp texture (A) */
- if (!blend) {
- DRW_draw_pass_subset(psl->fx_shader_pass, shgrp, shgrp);
- }
- else {
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, shgrp, shgrp);
- }
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_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);
-}
-
-/* helper to manage gaussian blur passes */
-static void draw_gpencil_blur_passes(GPENCIL_Data *vedata, BlurShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh == NULL) {
- return;
- }
-
- DRWShadingGroup *shgrp = fxd->runtime.fx_sh;
- int samples = fxd->samples;
-
- float bx = fxd->blur[0];
- float by = fxd->blur[1];
-
- /* the blur is done in two steps (Hor/Ver) because is faster and
- * gets better result
- *
- * samples could be 0 and disable de blur effects because sometimes
- * is easier animate the number of samples only, instead to animate the
- * hide/unhide and the number of samples to make some effects.
- */
- for (int b = 0; b < samples; b++) {
- /* horizontal */
- if (bx > 0) {
- fxd->blur[0] = bx;
- fxd->blur[1] = 0;
- gpencil_draw_fx_pass(vedata, shgrp, true);
- }
- /* vertical */
- if (by > 0) {
- fxd->blur[0] = 0;
- fxd->blur[1] = by;
- gpencil_draw_fx_pass(vedata, shgrp, true);
- }
- }
-}
-
-/* blur intermediate pass */
-static void draw_gpencil_midpass_blur(GPENCIL_Data *vedata, ShaderFxData_Runtime *runtime)
-{
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- const float clearcol[4] = {0.0f};
-
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, runtime->fx_sh_b, runtime->fx_sh_b);
-
- /* copy pass from b for ping-pong frame buffers */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass(psl->mix_pass_noblend);
-}
-
-/* do blur of mid passes */
-static void draw_gpencil_do_blur(
- GPENCIL_Data *vedata, ShaderFxData_Runtime *runtime, int samples, int bx, int by, int blur[2])
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_data->temp_color_tx_b;
+ if (tgp_ob->vfx.first != NULL) {
+ /* We need an extra pass to combine result to main buffer. */
+ iter.target_fb = &fbl->gpencil_fb;
- if ((samples > 0) && ((bx > 0) || (by > 0))) {
- for (int x = 0; x < samples; x++) {
+ GPUShader *sh = GPENCIL_shader_fx_composite_get();
- /* horizontal */
- blur[0] = bx;
- blur[1] = 0;
- draw_gpencil_midpass_blur(vedata, runtime);
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL;
+ DRWShadingGroup *grp = gpencil_vfx_pass_create("GPencil Object Compose", state, &iter, sh);
+ DRW_shgroup_uniform_int_copy(grp, "isFirstPass", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
- /* Vertical */
- blur[0] = 0;
- blur[1] = by;
- draw_gpencil_midpass_blur(vedata, runtime);
-
- blur[0] = bx;
- blur[1] = by;
- }
- }
-}
-
-/* helper to draw RIM passes */
-static void draw_gpencil_rim_passes(GPENCIL_Data *vedata, RimShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh_b == NULL) {
- return;
- }
+ /* We cannot do custom blending on MultiTarget framebuffers.
+ * Workaround by doing 2 passes. */
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_state_disable(grp, DRW_STATE_BLEND_MUL);
+ DRW_shgroup_state_enable(grp, DRW_STATE_BLEND_ADD_FULL);
+ DRW_shgroup_uniform_int_copy(grp, "isFirstPass", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
-
- const float clearcol[4] = {0.0f};
-
- /* prepare mask */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh);
-
- /* blur rim */
- draw_gpencil_do_blur(
- vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[1], &fxd->blur[0]);
-
- /* resolve */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_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);
-}
-
-/* helper to draw SHADOW passes */
-static void draw_gpencil_shadow_passes(GPENCIL_Data *vedata, ShadowShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh_b == NULL) {
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
- const float clearcol[4] = {0.0f};
-
- /* prepare shadow */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh);
-
- /* blur shadow */
- draw_gpencil_do_blur(
- vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[1], &fxd->blur[0]);
-
- /* resolve */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_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);
-}
-
-/* helper to draw GLOW passes */
-static void draw_gpencil_glow_passes(GPENCIL_Data *vedata, GlowShaderFxData *fxd)
-{
- if (fxd->runtime.fx_sh_b == NULL) {
- return;
- }
-
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
- GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl;
- GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl;
-
- const float clearcol[4] = {0.0f};
-
- /* prepare glow */
- GPU_framebuffer_bind(fbl->temp_fb_fx);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_fx, clearcol, 1.0f);
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh, fxd->runtime.fx_sh);
-
- /* blur glow */
- draw_gpencil_do_blur(
- vedata, &fxd->runtime, fxd->samples, fxd->blur[0], fxd->blur[0], &fxd->blur[0]);
-
- /* resolve */
- GPU_framebuffer_bind(fbl->temp_fb_b);
- GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f);
-
- /* reuses blur field to keep alpha mode */
- fxd->blur[1] = (fxd->flag & FX_GLOW_USE_ALPHA) ? 1 : 0;
-
- DRW_draw_pass_subset(psl->fx_shader_pass_blend, fxd->runtime.fx_sh_c, fxd->runtime.fx_sh_c);
-
- /* copy pass from b to a for ping-pong frame buffers */
- stl->g_data->input_depth_tx = stl->g_data->temp_depth_tx_b;
- stl->g_data->input_color_tx = stl->g_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);
-}
-
-/* apply all object fx effects */
-void gpencil_fx_draw(GPENCIL_e_data *UNUSED(e_data),
- GPENCIL_Data *vedata,
- tGPencilObjectCache *cache_ob)
-{
- GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl;
-
- /* loop FX modifiers */
- for (ShaderFxData *fx = cache_ob->shader_fx.first; fx; fx = fx->next) {
- if (effect_is_active(cache_ob->gpd, fx, stl->storage->is_render)) {
- switch (fx->type) {
-
- case eShaderFxType_Blur: {
- BlurShaderFxData *fxd = (BlurShaderFxData *)fx;
- draw_gpencil_blur_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Colorize: {
- ColorizeShaderFxData *fxd = (ColorizeShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Flip: {
- FlipShaderFxData *fxd = (FlipShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Light: {
- LightShaderFxData *fxd = (LightShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Pixel: {
- PixelShaderFxData *fxd = (PixelShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Rim: {
- RimShaderFxData *fxd = (RimShaderFxData *)fx;
- draw_gpencil_rim_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Shadow: {
- ShadowShaderFxData *fxd = (ShadowShaderFxData *)fx;
- draw_gpencil_shadow_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Glow: {
- GlowShaderFxData *fxd = (GlowShaderFxData *)fx;
- draw_gpencil_glow_passes(vedata, fxd);
- break;
- }
- case eShaderFxType_Swirl: {
- SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- case eShaderFxType_Wave: {
- WaveShaderFxData *fxd = (WaveShaderFxData *)fx;
- gpencil_draw_fx_pass(vedata, fxd->runtime.fx_sh, false);
- break;
- }
- default:
- break;
- }
- }
+ pd->use_object_fb = true;
+ pd->use_layer_fb = true;
}
}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl
deleted file mode 100644
index 0f64f54c67b..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_blur_frag.glsl
+++ /dev/null
@@ -1,85 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-
-uniform int blur[2];
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 noffset = vec2(blur[0], blur[1]);
-
-out vec4 FragColor;
-
-float get_zdepth(ivec2 poxy)
-{
- /* if outside viewport set as infinite depth */
- if ((poxy.x < 0) || (poxy.x > Viewport.x)) {
- return 1.0f;
- }
- if ((poxy.y < 0) || (poxy.y > Viewport.y)) {
- return 1.0f;
- }
-
- float zdepth = texelFetch(strokeDepth, poxy, 0).r;
- return zdepth;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) :
- (noffset[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) :
- (noffset[1] / defaultpixsize);
-
- /* round to avoid shift when add more samples */
- dx = floor(dx) + 1.0;
- dy = floor(dy) + 1.0;
-
- /* apply blurring, using a 9-tap filter with predefined gaussian weights */
- /* depth (get the value of the surrounding pixels) */
- float outdepth = get_zdepth(ivec2(uv.x, uv.y));
- for (int x = -1; x < 2; x++) {
- for (int y = -1; y < 2; y++) {
- float depth = get_zdepth(ivec2(uv.x + x * dx, uv.y + y * dy));
- if (depth < outdepth) {
- outdepth = depth;
- break;
- }
- }
- }
- gl_FragDepth = outdepth;
-
- /* color */
- vec4 outcolor = vec4(0.0);
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416;
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 0.0 * dx, uv.y + 1.0 * dy), 0) * 0.118318;
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 1.0 * dy), 0) * 0.0947416;
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318;
-
- outcolor += texelFetch(strokeColor, ivec2(uv.x, uv.y), 0) * 0.147761;
-
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y + 0.0 * dy), 0) * 0.118318;
- outcolor += texelFetch(strokeColor, ivec2(uv.x - 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416;
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 0.0 * dx, uv.y - 1.0 * dy), 0) * 0.118318;
- outcolor += texelFetch(strokeColor, ivec2(uv.x + 1.0 * dx, uv.y - 1.0 * dy), 0) * 0.0947416;
-
- FragColor = clamp(outcolor, 0, 1.0);
-
- /* discar extreme values */
- if (outcolor.a < 0.02f) {
- discard;
- }
- if ((outdepth <= 0.000001) || (outdepth >= 0.999999)) {
- discard;
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl
deleted file mode 100644
index 52f42d30d06..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_colorize_frag.glsl
+++ /dev/null
@@ -1,82 +0,0 @@
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform vec4 low_color;
-uniform vec4 high_color;
-uniform int mode;
-uniform float factor;
-
-out vec4 FragColor;
-
-#define MODE_GRAYSCALE 0
-#define MODE_SEPIA 1
-#define MODE_DUOTONE 2
-#define MODE_CUSTOM 3
-#define MODE_TRANSPARENT 4
-
-float get_luminance(vec4 color)
-{
- float lum = (color.r * 0.2126) + (color.g * 0.7152) + (color.b * 0.723);
- return lum;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- vec4 src_pixel = texelFetch(strokeColor, uv.xy, 0);
- float luminance = get_luminance(src_pixel);
- vec4 outcolor;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
-
- switch (mode) {
- case MODE_GRAYSCALE: {
- outcolor = vec4(luminance, luminance, luminance, src_pixel.a);
- break;
- }
- case MODE_SEPIA: {
- float Red = (src_pixel.r * 0.393) + (src_pixel.g * 0.769) + (src_pixel.b * 0.189);
- float Green = (src_pixel.r * 0.349) + (src_pixel.g * 0.686) + (src_pixel.b * 0.168);
- float Blue = (src_pixel.r * 0.272) + (src_pixel.g * 0.534) + (src_pixel.b * 0.131);
- outcolor = vec4(Red, Green, Blue, src_pixel.a);
- break;
- }
- case MODE_DUOTONE: {
- if (luminance <= factor) {
- outcolor = low_color;
- }
- else {
- outcolor = high_color;
- }
- break;
- }
- case MODE_CUSTOM: {
- /* if below umbral, force custom color */
- if (luminance <= factor) {
- outcolor = low_color;
- }
- else {
- outcolor = vec4(luminance * low_color.r,
- luminance * low_color.b,
- luminance * low_color.b,
- src_pixel.a);
- }
- break;
- }
- case MODE_TRANSPARENT: {
- outcolor = vec4(src_pixel.rgb, src_pixel.a * factor);
- break;
- }
- default: {
- outcolor = src_pixel;
- }
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl
deleted file mode 100644
index 2cd77007b36..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_flip_frag.glsl
+++ /dev/null
@@ -1,37 +0,0 @@
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 wsize;
-uniform int flipmode;
-
-void main()
-{
- vec2 mode = vec2(0, 0);
- /* horz. */
- if (flipmode >= 110) {
- mode[0] = 1;
- }
- /* vert. */
- if ((flipmode == 101) || (flipmode == 111)) {
- mode[1] = 1;
- }
-
- vec2 uv = vec2(gl_FragCoord.xy);
- float stroke_depth;
- vec4 outcolor;
-
- if (mode[0] > 0) {
- uv.x = wsize.x - uv.x;
- }
- if (mode[1] > 0) {
- uv.y = wsize.y - uv.y;
- }
-
- ivec2 iuv = ivec2(uv.x, uv.y);
- stroke_depth = texelFetch(strokeDepth, iuv, 0).r;
- outcolor = texelFetch(strokeColor, iuv, 0);
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl
deleted file mode 100644
index 676b9b05db9..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_prepare_frag.glsl
+++ /dev/null
@@ -1,68 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-/* ******************************************************************* */
-/* create glow mask */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform vec3 glow_color;
-uniform vec3 select_color;
-uniform float threshold;
-uniform int mode;
-
-out vec4 FragColor;
-
-#define MODE_LUMINANCE 0
-#define MODE_COLOR 1
-
-/* calc luminance */
-float luma(vec3 color)
-{
- /* the color is linear, so do not apply tonemapping */
- return (color.r + color.g + color.b) / 3.0;
-}
-
-bool check_color(vec3 color_a, vec3 color_b)
-{
- /* need round the number to avoid precision errors */
- if ((floor(color_a.r * 100) == floor(color_b.r * 100)) &&
- (floor(color_a.g * 100) == floor(color_b.g * 100)) &&
- (floor(color_a.b * 100) == floor(color_b.b * 100))) {
- return true;
- }
-
- return false;
-}
-
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r;
- vec4 src_pixel = texelFetch(strokeColor, ivec2(uv.xy), 0);
- vec4 outcolor;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
-
- if (mode == MODE_LUMINANCE) {
- if (luma(src_pixel.rgb) < threshold) {
- discard;
- }
- }
- else if (mode == MODE_COLOR) {
- if (!check_color(src_pixel.rgb, select_color.rgb)) {
- discard;
- }
- }
- else {
- discard;
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = vec4(glow_color.rgb, 1.0);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl
deleted file mode 100644
index e2aceb9eefe..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_glow_resolve_frag.glsl
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ******************************************************************* */
-/* Resolve GLOW pass */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D glowColor;
-uniform sampler2D glowDepth;
-uniform int alpha_mode;
-
-out vec4 FragColor;
-
-void main()
-{
- vec4 outcolor;
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- vec4 src_pixel = texelFetch(strokeColor, uv.xy, 0);
- vec4 glow_pixel = texelFetch(glowColor, uv.xy, 0);
- float glow_depth = texelFetch(glowDepth, uv.xy, 0).r;
-
- if (alpha_mode == 0) {
- outcolor = src_pixel + glow_pixel;
- }
- else {
- if ((src_pixel.a < 0.1) || (glow_pixel.a < 0.1)) {
- outcolor = src_pixel + glow_pixel;
- }
- else {
- outcolor = src_pixel;
- }
- }
-
- if (src_pixel.a < glow_pixel.a) {
- gl_FragDepth = glow_depth;
- }
- else {
- gl_FragDepth = stroke_depth;
- }
-
- if (outcolor.a < 0.001) {
- discard;
- }
-
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
deleted file mode 100644
index a5c321c20c1..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_light_frag.glsl
+++ /dev/null
@@ -1,70 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-uniform vec4 loc;
-uniform float energy;
-uniform float ambient;
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-out vec4 FragColor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-#define height loc.w
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- /* need to calculate ndc because this is not done by vertex shader */
- vec3 ndc = vec3(vertex).xyz / vertex.w;
-
- vec2 sc;
- sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
- sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
-
- return sc;
-}
-
-void main()
-{
- float stroke_depth;
- vec4 objcolor;
-
- vec4 light_loc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
- vec2 light2d = toScreenSpace(light_loc);
-
- /* calc pixel scale */
- float pxscale = (ProjectionMatrix[3][3] == 0.0) ? (10.0 / (light_loc.z * defaultpixsize)) :
- (10.0 / defaultpixsize);
- pxscale = max(pxscale, 0.000001);
-
- /* the height over plane is received in the w component of the loc
- * and needs a factor to adapt to pixels
- */
- float peak = height * 10.0 * pxscale;
- vec3 light3d = vec3(light2d.x, light2d.y, peak);
-
- vec2 uv = vec2(gl_FragCoord.xy);
- vec3 frag_loc = vec3(uv.x, uv.y, 0);
- vec3 norm = vec3(0, 0, 1.0); /* always z-up */
-
- ivec2 iuv = ivec2(uv.x, uv.y);
- stroke_depth = texelFetch(strokeDepth, iuv, 0).r;
- objcolor = texelFetch(strokeColor, iuv, 0);
-
- /* diffuse light */
- vec3 lightdir = normalize(light3d - frag_loc);
- float diff = max(dot(norm, lightdir), 0.0);
- float dist = length(light3d - frag_loc) / pxscale;
- float factor = diff * ((energy * 100.0) / (dist * dist));
-
- vec3 result = factor * max(ambient, 0.1) * vec3(objcolor);
-
- gl_FragDepth = stroke_depth;
- FragColor = vec4(result.r, result.g, result.b, objcolor.a);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl
deleted file mode 100644
index 46b3c4286b4..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_pixel_frag.glsl
+++ /dev/null
@@ -1,51 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform int size[3];
-uniform vec4 color;
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-out vec4 FragColor;
-
-int uselines = size[2];
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 nsize = max(vec2(size[0], size[1]), 3.0);
-
-/* This pixelation shader is a modified version of original Geeks3d.com code */
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (nsize[0] / (nloc.z * defaultpixsize)) :
- (nsize[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (nsize[1] / (nloc.z * defaultpixsize)) :
- (nsize[1] / defaultpixsize);
-
- dx = max(abs(dx), 3.0);
- dy = max(abs(dy), 3.0);
-
- vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));
-
- float stroke_depth = texelFetch(strokeDepth, ivec2(coord), 0).r;
- vec4 outcolor = texelFetch(strokeColor, ivec2(coord), 0);
-
- if (uselines == 1) {
- float difx = uv.x - (floor(uv.x / nsize[0]) * nsize[0]);
- if ((difx == 0.5) && (outcolor.a > 0)) {
- outcolor = color;
- }
- float dify = uv.y - (floor(uv.y / nsize[1]) * nsize[1]);
- if ((dify == 0.5) && (outcolor.a > 0)) {
- outcolor = color;
- }
- }
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl
deleted file mode 100644
index 2a17e573978..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_prepare_frag.glsl
+++ /dev/null
@@ -1,65 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-/* ******************************************************************* */
-/* create rim and mask */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-
-uniform int offset[2];
-uniform vec3 rim_color;
-uniform vec3 mask_color;
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 noffset = vec2(offset[0], offset[1]);
-
-out vec4 FragColor;
-
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) :
- (noffset[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) :
- (noffset[1] / defaultpixsize);
-
- float stroke_depth = texelFetch(strokeDepth, ivec2(uv.xy), 0).r;
- vec4 src_pixel = texelFetch(strokeColor, ivec2(uv.xy), 0);
- vec4 offset_pixel = texelFetch(strokeColor, ivec2(uv.x - dx, uv.y - dy), 0);
- vec4 outcolor;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
- /* check inside viewport */
- else if ((uv.x - dx < 0) || (uv.x - dx > Viewport[0])) {
- discard;
- }
- else if ((uv.y - dy < 0) || (uv.y - dy > Viewport[1])) {
- discard;
- }
- /* pixel is equal to mask color, keep */
- else if (src_pixel.rgb == mask_color.rgb) {
- discard;
- }
- else {
- if ((src_pixel.a > 0) && (offset_pixel.a > 0)) {
- discard;
- }
- else {
- outcolor = vec4(rim_color, 1.0);
- }
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl
deleted file mode 100644
index fa010baa32f..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_rim_resolve_frag.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-/* ******************************************************************* */
-/* Resolve RIM pass and add blur if needed */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D strokeRim;
-
-uniform vec3 mask_color;
-uniform int mode;
-
-out vec4 FragColor;
-
-#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 mix_color)
-{
- vec4 outcolor;
- if (mode == MODE_NORMAL) {
- outcolor = mix_color;
- }
- else if (mode == MODE_OVERLAY) {
- 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);
- }
- else if (mode == MODE_ADD) {
- outcolor = src_color + mix_color;
- }
- else if (mode == MODE_SUB) {
- outcolor = src_color - mix_color;
- }
- else if (mode == MODE_MULTIPLY) {
- outcolor = src_color * mix_color;
- }
- else if (mode == MODE_DIVIDE) {
- outcolor = src_color / mix_color;
- }
- else {
- outcolor = mix_color;
- }
-
- /* use always the alpha of source color */
-
- outcolor.a = src_color.a;
- /* use alpha to calculate the weight of the mixed color */
- outcolor = mix(src_color, outcolor, mix_color.a);
-
- return outcolor;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- vec4 src_pixel = texelFetch(strokeColor, uv.xy, 0);
- vec4 rim_pixel = texelFetch(strokeRim, uv.xy, 0);
-
- vec4 outcolor = src_pixel;
-
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
- /* pixel is equal to mask color, keep */
- else if (src_pixel.rgb == mask_color.rgb) {
- outcolor = src_pixel;
- }
- else {
- if (rim_pixel.a == 0.0f) {
- outcolor = src_pixel;
- }
- else {
- outcolor = get_blend_color(mode, src_pixel, rim_pixel);
- }
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl
deleted file mode 100644
index d2e20feae18..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_prepare_frag.glsl
+++ /dev/null
@@ -1,98 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-/* ******************************************************************* */
-/* create shadow */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform vec2 Viewport;
-
-uniform int offset[2];
-uniform float scale[2];
-uniform float rotation;
-uniform vec4 shadow_color;
-
-uniform float amplitude;
-uniform float period;
-uniform float phase;
-uniform int orientation;
-
-uniform vec3 loc;
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-#define M_PI 3.1415926535897932384626433832795
-
-#define HORIZONTAL 0
-#define VERTICAL 1
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-vec2 noffset = vec2(offset[0], offset[1]);
-float cosv = cos(rotation);
-float sinv = sin(rotation);
-
-out vec4 FragColor;
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- /* need to calculate ndc because this is not done by vertex shader */
- vec3 ndc = vec3(vertex).xyz / vertex.w;
-
- vec2 sc;
- sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
- sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
-
- return sc;
-}
-
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- vec4 nloc = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
- vec2 loc2d = toScreenSpace(nloc);
-
- float dx = (ProjectionMatrix[3][3] == 0.0) ? (noffset[0] / (nloc.z * defaultpixsize)) :
- (noffset[0] / defaultpixsize);
- float dy = (ProjectionMatrix[3][3] == 0.0) ? (noffset[1] / (nloc.z * defaultpixsize)) :
- (noffset[1] / defaultpixsize);
-
- /* move point to new coords system */
- vec2 tpos = vec2(uv.x, uv.y) - loc2d;
-
- /* rotation */
- if (rotation != 0) {
- vec2 rotpoint = vec2((tpos.x * cosv) - (tpos.y * sinv), (tpos.x * sinv) + (tpos.y * cosv));
- tpos = rotpoint;
- }
-
- /* apply offset */
- tpos = vec2(tpos.x - dx, tpos.y - dy);
-
- /* apply scale */
- tpos.x *= 1.0 / scale[0];
- tpos.y *= 1.0 / scale[1];
-
- /* back to original coords system */
- vec2 texpos = tpos + loc2d;
-
- /* wave */
- if (orientation == HORIZONTAL) {
- float pval = (uv.x * M_PI) / Viewport[0];
- texpos.y += amplitude * sin((period * pval) + phase);
- }
- else if (orientation == VERTICAL) {
- float pval = (uv.y * M_PI) / Viewport[1];
- texpos.x += amplitude * sin((period * pval) + phase);
- }
-
- vec4 src_pixel = texelFetch(strokeColor, ivec2(texpos.x, texpos.y), 0);
- /* is transparent */
- if (src_pixel.a == 0.0f) {
- discard;
- }
-
- gl_FragDepth = texelFetch(strokeDepth, ivec2(texpos.x, texpos.y), 0).r;
- FragColor = shadow_color;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl
deleted file mode 100644
index 3ef11008adf..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_shadow_resolve_frag.glsl
+++ /dev/null
@@ -1,32 +0,0 @@
-/* ******************************************************************* */
-/* Resolve Shadow pass */
-/* ******************************************************************* */
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D shadowColor;
-uniform sampler2D shadowDepth;
-
-out vec4 FragColor;
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- float stroke_depth = texelFetch(strokeDepth, uv.xy, 0).r;
- float shadow_depth = texelFetch(shadowDepth, uv.xy, 0).r;
- vec4 stroke_pixel = texelFetch(strokeColor, uv.xy, 0);
- vec4 shadow_pixel = texelFetch(shadowColor, uv.xy, 0);
-
- /* copy original pixel */
- vec4 outcolor = stroke_pixel;
- float outdepth = stroke_depth;
-
- /* if stroke is not on top, copy shadow */
- if ((stroke_pixel.a <= 0.2) && (shadow_pixel.a > 0.0)) {
- outcolor = shadow_pixel;
- outdepth = shadow_depth;
- }
-
- gl_FragDepth = outdepth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
deleted file mode 100644
index 01d4fe40195..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_swirl_frag.glsl
+++ /dev/null
@@ -1,74 +0,0 @@
-uniform mat4 ProjectionMatrix;
-uniform mat4 ViewMatrix;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform vec2 Viewport;
-uniform vec3 loc;
-uniform int radius;
-uniform float angle;
-uniform int transparent;
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform float pixfactor;
-
-out vec4 FragColor;
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- /* need to calculate ndc because this is not done by vertex shader */
- vec3 ndc = vec3(vertex).xyz / vertex.w;
-
- vec2 sc;
- sc.x = ((ndc.x + 1.0) / 2.0) * Viewport.x;
- sc.y = ((ndc.y + 1.0) / 2.0) * Viewport.y;
-
- return sc;
-}
-
-/* This swirl shader is a modified version of original Geeks3d.com code */
-void main()
-{
- vec2 uv = vec2(gl_FragCoord.xy);
- float stroke_depth;
- vec4 outcolor;
-
- vec4 center3d = ProjectionMatrix * ViewMatrix * vec4(loc.xyz, 1.0);
- vec2 center = toScreenSpace(center3d);
- vec2 tc = uv - center;
-
- float dist = length(tc);
- float locpixsize = abs((loc.z * defaultpixsize));
- if (locpixsize == 0) {
- locpixsize = 1;
- }
- float pxradius = (ProjectionMatrix[3][3] == 0.0) ? (radius / locpixsize) :
- (radius / defaultpixsize);
- pxradius = max(pxradius, 1);
-
- if (dist <= pxradius) {
- float percent = (pxradius - dist) / pxradius;
- float theta = percent * percent * angle * 8.0;
- float s = sin(theta);
- float c = cos(theta);
- tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
- tc += center;
-
- stroke_depth = texelFetch(strokeDepth, ivec2(tc), 0).r;
- outcolor = texelFetch(strokeColor, ivec2(tc), 0);
- }
- else {
- if (transparent == 1) {
- discard;
- }
- stroke_depth = texelFetch(strokeDepth, ivec2(uv), 0).r;
- outcolor = texelFetch(strokeColor, ivec2(uv), 0);
- }
-
- gl_FragDepth = stroke_depth;
- FragColor = outcolor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl b/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl
deleted file mode 100644
index 0a5df9f6d77..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/fx/gpencil_fx_wave_frag.glsl
+++ /dev/null
@@ -1,44 +0,0 @@
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-uniform float amplitude;
-uniform float period;
-uniform float phase;
-uniform int orientation;
-uniform vec2 wsize;
-
-#define M_PI 3.1415926535897932384626433832795
-
-#define HORIZONTAL 0
-#define VERTICAL 1
-
-void main()
-{
- vec4 outcolor;
- ivec2 uv = ivec2(gl_FragCoord.xy);
- float stroke_depth;
-
- float value;
- if (orientation == HORIZONTAL) {
- float pval = (uv.x * M_PI) / wsize[0];
- value = amplitude * sin((period * pval) + phase);
- outcolor = texelFetch(strokeColor, ivec2(uv.x, uv.y + value), 0);
- stroke_depth = texelFetch(strokeDepth, ivec2(uv.x, uv.y + value), 0).r;
- }
- else {
- float pval = (uv.y * M_PI) / wsize[1];
- value = amplitude * sin((period * pval) + phase);
- outcolor = texelFetch(strokeColor, ivec2(uv.x + value, uv.y), 0);
- stroke_depth = texelFetch(strokeDepth, ivec2(uv.x + value, uv.y), 0).r;
- }
-
- FragColor = outcolor;
- gl_FragDepth = stroke_depth;
-
- if (outcolor.a < 0.02f) {
- discard;
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
new file mode 100644
index 00000000000..b512b54e392
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_frag.glsl
@@ -0,0 +1,64 @@
+
+uniform sampler2D edgesTex;
+uniform sampler2D areaTex;
+uniform sampler2D searchTex;
+uniform sampler2D blendTex;
+uniform sampler2D colorTex;
+uniform sampler2D revealTex;
+uniform bool onlyAlpha;
+uniform bool doAntiAliasing;
+
+in vec2 uvs;
+in vec2 pixcoord;
+in vec4 offset[3];
+
+#if SMAA_STAGE == 0
+out vec2 fragColor;
+#elif SMAA_STAGE == 1
+out vec4 fragColor;
+#elif SMAA_STAGE == 2
+/* Reminder: Blending func is fragRevealage * DST + fragColor .*/
+layout(location = 0, index = 0) out vec4 outColor;
+layout(location = 0, index = 1) out vec4 outReveal;
+#endif
+
+void main()
+{
+#if SMAA_STAGE == 0
+ /* Detect edges in color and revealage buffer. */
+ fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex);
+ fragColor = max(fragColor, SMAALumaEdgeDetectionPS(uvs, offset, revealTex));
+ /* Discard if there is no edge. */
+ if (dot(fragColor, float2(1.0, 1.0)) == 0.0) {
+ discard;
+ }
+
+#elif SMAA_STAGE == 1
+ fragColor = SMAABlendingWeightCalculationPS(
+ uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0));
+
+#elif SMAA_STAGE == 2
+ /* Resolve both buffers. */
+ if (doAntiAliasing) {
+ outColor = SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex);
+ outReveal = SMAANeighborhoodBlendingPS(uvs, offset[0], revealTex, blendTex);
+ }
+ else {
+ outColor = texture(colorTex, uvs);
+ outReveal = texture(revealTex, uvs);
+ }
+
+ /* Revealage, how much light passes through. */
+ /* Average for alpha channel. */
+ outReveal.a = clamp(dot(outReveal.rgb, vec3(0.333334)), 0.0, 1.0);
+ /* Color buf is already premultiplied. Just add it to the color. */
+ /* Add the alpha. */
+ outColor.a = 1.0 - outReveal.a;
+
+ if (onlyAlpha) {
+ /* Special case in wireframe xray mode. */
+ outColor = vec4(0.0);
+ outReveal.rgb = outReveal.aaa;
+ }
+#endif
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
new file mode 100644
index 00000000000..07734d19972
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_antialiasing_vert.glsl
@@ -0,0 +1,21 @@
+
+out vec2 uvs;
+out vec2 pixcoord;
+out vec4 offset[3];
+
+void main()
+{
+ int v = gl_VertexID % 3;
+ float x = -1.0 + float((v & 1) << 2);
+ float y = -1.0 + float((v & 2) << 1);
+ gl_Position = vec4(x, y, 1.0, 1.0);
+ uvs = (gl_Position.xy + 1.0) * 0.5;
+
+#if SMAA_STAGE == 0
+ SMAAEdgeDetectionVS(uvs, offset);
+#elif SMAA_STAGE == 1
+ SMAABlendingWeightCalculationVS(uvs, pixcoord, offset);
+#elif SMAA_STAGE == 2
+ SMAANeighborhoodBlendingVS(uvs, offset[0]);
+#endif
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
deleted file mode 100644
index 18803bfa3fa..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_background_frag.glsl
+++ /dev/null
@@ -1,12 +0,0 @@
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
-
- gl_FragDepth = texelFetch(strokeDepth, uv, 0).r;
- FragColor = texelFetch(strokeColor, uv, 0);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
deleted file mode 100644
index 85dee4390a5..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
+++ /dev/null
@@ -1,157 +0,0 @@
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform sampler2D blendColor;
-uniform sampler2D blendDepth;
-uniform int mode;
-uniform int mask_layer;
-uniform int tonemapping;
-
-#define ON 1
-#define OFF 0
-
-#define MODE_REGULAR 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 mix_color)
-{
- vec4 outcolor;
-
- if (mix_color.a == 0) {
- return src_color;
- }
-
- switch (mode) {
- case MODE_REGULAR: {
- /* premult */
- src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a);
- mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
-
- outcolor = vec4(mix(src_color.rgb, mix_color.rgb, mix_color.a), src_color.a);
- break;
- }
- case MODE_OVERLAY: {
- src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a);
- mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
-
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- 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;
- break;
- }
- case MODE_ADD: {
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color + mix_color;
- outcolor.a = src_color.a;
- break;
- }
- case MODE_SUB: {
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color - mix_color;
- outcolor.a = clamp(src_color.a - mix_color.a, 0.0, 1.0);
- break;
- }
- case MODE_MULTIPLY: {
- src_color = vec4(vec3(src_color.rgb / src_color.a), src_color.a);
- mix_color = vec4(vec3(mix_color.rgb / mix_color.a), mix_color.a);
-
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color * mix_color;
- outcolor.a = src_color.a;
- break;
- }
- case MODE_DIVIDE: {
- mix_color.rgb = mix(src_color.rgb, mix_color.rgb, mix_color.a);
- outcolor = src_color / mix_color;
- outcolor.a = src_color.a;
- break;
- }
- default: {
- outcolor = mix_color;
- outcolor.a = src_color.a;
- break;
- }
- }
- return clamp(outcolor, 0.0, 1.0);
-}
-
-float linearrgb_to_srgb(float c)
-{
- if (c < 0.0031308) {
- return (c < 0.0) ? 0.0 : c * 12.92;
- }
- else {
- return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
- }
-}
-
-vec4 tone(vec4 stroke_color)
-{
- if (tonemapping == 1) {
- vec4 color = vec4(0, 0, 0, stroke_color.a);
- color.r = linearrgb_to_srgb(stroke_color.r);
- color.g = linearrgb_to_srgb(stroke_color.g);
- color.b = linearrgb_to_srgb(stroke_color.b);
- return color;
- }
- else {
- return stroke_color;
- }
-}
-
-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;
-
- if (stroke_color.a > 0) {
- if (mix_color.a > 0) {
- /* apply blend mode */
- FragColor = get_blend_color(mode, stroke_color, mix_color);
- }
- else {
- FragColor = stroke_color;
- }
- gl_FragDepth = min(stroke_depth, mix_depth);
- }
- else {
- if (mask_layer == ON) {
- discard;
- }
- else {
- /* if not using mask, return mix color */
- FragColor = mix_color;
- gl_FragDepth = mix_depth;
- }
- }
-
- /* apply tone mapping */
- FragColor = tone(FragColor);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
new file mode 100644
index 00000000000..8774b633467
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
@@ -0,0 +1,593 @@
+
+/* Must match C declaration. */
+struct gpMaterial {
+ vec4 stroke_color;
+ vec4 fill_color;
+ vec4 fill_mix_color;
+ vec4 fill_uv_rot_scale;
+ vec4 fill_uv_offset;
+ /* Put float/int at the end to avoid padding error */
+ float stroke_texture_mix;
+ float stroke_u_scale;
+ float fill_texture_mix;
+ int flag;
+ /* Please ensure 16 byte alignment (multiple of vec4). */
+};
+
+/* flag */
+#define GP_STROKE_ALIGNMENT_STROKE 1
+#define GP_STROKE_ALIGNMENT_OBJECT 2
+#define GP_STROKE_ALIGNMENT_FIXED 3
+#define GP_STROKE_ALIGNMENT 0x3
+#define GP_STROKE_OVERLAP (1 << 2)
+#define GP_STROKE_TEXTURE_USE (1 << 3)
+#define GP_STROKE_TEXTURE_STENCIL (1 << 4)
+#define GP_STROKE_TEXTURE_PREMUL (1 << 5)
+#define GP_STROKE_DOTS (1 << 6)
+#define GP_FILL_TEXTURE_USE (1 << 10)
+#define GP_FILL_TEXTURE_PREMUL (1 << 11)
+#define GP_FILL_TEXTURE_CLIP (1 << 12)
+#define GP_FILL_GRADIENT_USE (1 << 13)
+#define GP_FILL_GRADIENT_RADIAL (1 << 14)
+/* High bits are used to pass material ID to fragment shader. */
+#define GP_MATID_SHIFT 16
+
+/* Multiline defines can crash blender with certain GPU drivers. */
+/* clang-format off */
+#define GP_FILL_FLAGS (GP_FILL_TEXTURE_USE | GP_FILL_TEXTURE_PREMUL | GP_FILL_TEXTURE_CLIP | GP_FILL_GRADIENT_USE | GP_FILL_GRADIENT_RADIAL)
+/* clang-format on */
+
+#define GP_FLAG_TEST(flag, val) (((flag) & (val)) != 0)
+
+/* Must match C declaration. */
+struct gpLight {
+ vec4 color_type;
+ vec4 right;
+ vec4 up;
+ vec4 forward;
+ vec4 position;
+ /* Please ensure 16 byte alignment (multiple of vec4). */
+};
+
+#define spot_size right.w
+#define spot_blend up.w
+
+#define GP_LIGHT_TYPE_POINT 0.0
+#define GP_LIGHT_TYPE_SPOT 1.0
+#define GP_LIGHT_TYPE_SUN 2.0
+#define GP_LIGHT_TYPE_AMBIENT 3.0
+
+#ifdef GP_MATERIAL_BUFFER_LEN
+
+layout(std140) uniform gpMaterialBlock
+{
+ gpMaterial materials[GP_MATERIAL_BUFFER_LEN];
+};
+
+#endif
+
+#ifdef GPENCIL_LIGHT_BUFFER_LEN
+
+layout(std140) uniform gpLightBlock
+{
+ gpLight lights[GPENCIL_LIGHT_BUFFER_LEN];
+};
+
+#endif
+
+/* Must match eGPLayerBlendModes */
+#define MODE_REGULAR 0
+#define MODE_OVERLAY 1
+#define MODE_ADD 2
+#define MODE_SUB 3
+#define MODE_MULTIPLY 4
+#define MODE_DIVIDE 5
+#define MODE_OVERLAY_SECOND_PASS 999
+
+void blend_mode_output(
+ int blend_mode, vec4 color, float opacity, out vec4 frag_color, out vec4 frag_revealage)
+{
+ switch (blend_mode) {
+ case MODE_REGULAR:
+ /* Reminder: Blending func is premult alpha blend (dst.rgba * (1 - src.a) + src.rgb).*/
+ color *= opacity;
+ frag_color = color;
+ frag_revealage = vec4(0.0, 0.0, 0.0, color.a);
+ break;
+ case MODE_MULTIPLY:
+ /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/
+ color.a *= opacity;
+ frag_revealage = frag_color = (1.0 - color.a) + color.a * color;
+ break;
+ case MODE_DIVIDE:
+ /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/
+ color.a *= opacity;
+ frag_revealage = frag_color = clamp(1.0 / max(vec4(1e-6), 1.0 - color * color.a), 0.0, 1e18);
+ break;
+ case MODE_OVERLAY:
+ /* Reminder: Blending func is multiply blend (dst.rgba * src.rgba).*/
+ /**
+ * We need to separate the overlay equation into 2 term (one mul and one add).
+ * This is the standard overlay equation (per channel):
+ * rtn = (src < 0.5) ? (2.0 * src * dst) : (1.0 - 2.0 * (1.0 - src) * (1.0 - dst));
+ * We rewrite the second branch like this:
+ * rtn = 1 - 2 * (1 - src) * (1 - dst);
+ * rtn = 1 - 2 (1 - dst + src * dst - src);
+ * rtn = 1 - 2 (1 - dst * (1 - src) - src);
+ * rtn = 1 - 2 + dst * (2 - 2 * src) + 2 * src;
+ * rtn = (- 1 + 2 * src) + dst * (2 - 2 * src);
+ **/
+ color = mix(vec4(0.5), color, color.a * opacity);
+ vec4 s = step(-0.5, -color);
+ frag_revealage = frag_color = 2.0 * s + 2.0 * color * (1.0 - s * 2.0);
+ break;
+ case MODE_OVERLAY_SECOND_PASS:
+ /* Reminder: Blending func is additive blend (dst.rgba + src.rgba).*/
+ color = mix(vec4(0.5), color, color.a * opacity);
+ frag_revealage = frag_color = (-1.0 + 2.0 * color) * step(-0.5, -color);
+ break;
+ case MODE_SUB:
+ case MODE_ADD:
+ /* Reminder: Blending func is additive / subtractive blend (dst.rgba +/- src.rgba).*/
+ frag_color = color * color.a * opacity;
+ frag_revealage = vec4(0.0);
+ break;
+ }
+}
+
+#ifdef GPU_VERTEX_SHADER
+# define IN_OUT out
+#else
+# define IN_OUT in
+#endif
+
+/* Shader interface. */
+IN_OUT vec4 finalColorMul;
+IN_OUT vec4 finalColorAdd;
+IN_OUT vec3 finalPos;
+IN_OUT vec2 finalUvs;
+noperspective IN_OUT float strokeThickness;
+noperspective IN_OUT float strokeHardeness;
+flat IN_OUT vec2 strokeAspect;
+flat IN_OUT vec2 strokePt1;
+flat IN_OUT vec2 strokePt2;
+flat IN_OUT int matFlag;
+flat IN_OUT float depth;
+
+#ifdef GPU_FRAGMENT_SHADER
+
+# define linearstep(p0, p1, v) (clamp(((v) - (p0)) / abs((p1) - (p0)), 0.0, 1.0))
+
+float stroke_round_cap_mask(vec2 p1, vec2 p2, vec2 aspect, float thickness, float hardfac)
+{
+ /* We create our own uv space to avoid issues with triangulation and linear
+ * interpolation artifacts. */
+ vec2 line = p2.xy - p1.xy;
+ vec2 pos = gl_FragCoord.xy - p1.xy;
+ float line_len = length(line);
+ float half_line_len = line_len * 0.5;
+ /* Normalize */
+ line = (line_len > 0.0) ? (line / line_len) : vec2(1.0, 0.0);
+ /* Create a uv space that englobe the whole segment into a capsule. */
+ vec2 uv_end;
+ uv_end.x = max(abs(dot(line, pos) - half_line_len) - half_line_len, 0.0);
+ uv_end.y = dot(vec2(-line.y, line.x), pos);
+ /* Divide by stroke radius. */
+ uv_end /= thickness;
+ uv_end *= aspect;
+
+ float dist = clamp(1.0 - length(uv_end) * 2.0, 0.0, 1.0);
+ if (hardfac > 0.999) {
+ return step(1e-8, dist);
+ }
+ else {
+ /* Modulate the falloff profile */
+ float hardness = 1.0 - hardfac;
+ dist = pow(dist, mix(0.01, 10.0, hardness));
+ return smoothstep(0.0, 1.0, dist);
+ }
+}
+
+#endif
+
+uniform vec2 sizeViewport;
+uniform vec2 sizeViewportInv;
+
+/* Per Object */
+uniform bool strokeOrder3d;
+uniform int gpMaterialOffset;
+uniform float thicknessScale;
+uniform float thicknessWorldScale;
+#define thicknessIsScreenSpace (thicknessWorldScale < 0.0)
+#define MATERIAL(m) materials[m + gpMaterialOffset]
+
+#ifdef GPU_VERTEX_SHADER
+
+/* Per Layer */
+uniform float thicknessOffset;
+uniform float vertexColorOpacity;
+uniform vec4 layerTint;
+uniform float layerOpacity; /* Used for onion skin. */
+uniform float strokeIndexOffset = 0.0;
+
+/* All of these attribs are quad loaded the same way
+ * as GL_LINES_ADJACENCY would feed a geometry shader:
+ * - ma reference the previous adjacency point.
+ * - ma1 reference the current line first point.
+ * - ma2 reference the current line second point.
+ * - ma3 reference the next adjacency point.
+ * Note that we are rendering quad instances and not using any index buffer (except for fills).
+ */
+in vec4 ma;
+in vec4 ma1;
+in vec4 ma2;
+in vec4 ma3;
+# define strength1 ma1.y
+# define strength2 ma2.y
+# define stroke_id1 ma1.z
+# define point_id1 ma1.w
+/* Position contains thickness in 4th component. */
+in vec4 pos; /* Prev adj vert */
+in vec4 pos1; /* Current edge */
+in vec4 pos2; /* Current edge */
+in vec4 pos3; /* Next adj vert */
+# define thickness1 pos1.w
+# define thickness2 pos2.w
+/* xy is UV for fills, z is U of stroke, w is cosine of UV angle with sign of sine. */
+in vec4 uv1;
+in vec4 uv2;
+
+in vec4 col1;
+in vec4 col2;
+
+in vec4 fcol1;
+
+/* hard.x is aspect. */
+in vec2 hard1;
+in vec2 hard2;
+# define aspect1 hard1.x
+# define aspect2 hard2.x
+
+void discard_vert()
+{
+ /* We set the vertex at the camera origin to generate 0 fragments. */
+ gl_Position = vec4(0.0, 0.0, -3e36, 0.0);
+}
+
+vec2 project_to_screenspace(vec4 v)
+{
+ return ((v.xy / v.w) * 0.5 + 0.5) * sizeViewport;
+}
+
+vec2 rotate_90deg(vec2 v)
+{
+ /* Counter Clock-Wise. */
+ return vec2(-v.y, v.x);
+}
+
+mat4 model_matrix_get()
+{
+ return ModelMatrix;
+}
+
+vec3 transform_point(mat4 m, vec3 v)
+{
+ return (m * vec4(v, 1.0)).xyz;
+}
+
+vec2 safe_normalize(vec2 v)
+{
+ float len_sqr = dot(v, v);
+ if (len_sqr > 0.0) {
+ return v / sqrt(len_sqr);
+ }
+ else {
+ return vec2(1.0, 0.0);
+ }
+}
+
+vec2 safe_normalize_len(vec2 v, out float len)
+{
+ len = sqrt(dot(v, v));
+ if (len > 0.0) {
+ return v / len;
+ }
+ else {
+ return vec2(1.0, 0.0);
+ }
+}
+
+float stroke_thickness_modulate(float thickness)
+{
+ /* Modify stroke thickness by object and layer factors.-*/
+ thickness *= thicknessScale;
+ thickness += thicknessOffset;
+ thickness = max(1.0, thickness);
+
+ if (thicknessIsScreenSpace) {
+ /* Multiply offset by view Z so that offset is constant in screenspace.
+ * (e.i: does not change with the distance to camera) */
+ thickness *= gl_Position.w;
+ }
+ else {
+ /* World space point size. */
+ thickness *= thicknessWorldScale * ProjectionMatrix[1][1] * sizeViewport.y;
+ }
+ return thickness;
+}
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+void color_output(vec4 stroke_col, vec4 vert_col, float vert_strength, float mix_tex)
+{
+ /* Mix stroke with other colors. */
+ vec4 mixed_col = stroke_col;
+ mixed_col.rgb = mix(mixed_col.rgb, vert_col.rgb, vert_col.a * vertexColorOpacity);
+ mixed_col.rgb = mix(mixed_col.rgb, layerTint.rgb, layerTint.a);
+ mixed_col.a *= vert_strength * layerOpacity;
+ /**
+ * This is what the fragment shader looks like.
+ * out = col * finalColorMul + col.a * finalColorAdd.
+ * finalColorMul is how much of the texture color to keep.
+ * finalColorAdd is how much of the mixed color to add.
+ * Note that we never add alpha. This is to keep the texture act as a stencil.
+ * We do however, modulate the alpha (reduce it).
+ **/
+ /* We add the mixed color. This is 100% mix (no texture visible). */
+ finalColorMul = vec4(mixed_col.aaa, mixed_col.a);
+ finalColorAdd = vec4(mixed_col.rgb * mixed_col.a, 0.0);
+ /* Then we blend according to the texture mix factor.
+ * Note that we keep the alpha modulation. */
+ finalColorMul.rgb *= mix_tex;
+ finalColorAdd.rgb *= 1.0 - mix_tex;
+}
+# endif
+
+void stroke_vertex()
+{
+ int m = int(ma1.x);
+ bool is_dot = false;
+ bool is_squares = false;
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+ if (m != -1.0) {
+ is_dot = GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_ALIGNMENT);
+ is_squares = !GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_DOTS);
+ }
+# endif
+
+ /* Special Case. Stroke with single vert are rendered as dots. Do not discard them. */
+ if (!is_dot && ma.x == -1.0 && ma2.x == -1.0) {
+ is_dot = true;
+ is_squares = false;
+ }
+
+ /* Enpoints, we discard the vertices. */
+ if (ma1.x == -1.0 || (!is_dot && ma2.x == -1.0)) {
+ discard_vert();
+ return;
+ }
+
+ mat4 model_mat = model_matrix_get();
+
+ /* Avoid using a vertex attrib for quad positioning. */
+ float x = float(gl_VertexID & 1) * 2.0 - 1.0; /* [-1..1] */
+ float y = float(gl_VertexID & 2) - 1.0; /* [-1..1] */
+
+ bool use_curr = is_dot || (x == -1.0);
+
+ vec3 wpos_adj = transform_point(model_mat, (use_curr) ? pos.xyz : pos3.xyz);
+ vec3 wpos1 = transform_point(model_mat, pos1.xyz);
+ vec3 wpos2 = transform_point(model_mat, pos2.xyz);
+
+ vec4 ndc_adj = point_world_to_ndc(wpos_adj);
+ vec4 ndc1 = point_world_to_ndc(wpos1);
+ vec4 ndc2 = point_world_to_ndc(wpos2);
+
+ gl_Position = (use_curr) ? ndc1 : ndc2;
+ finalPos = (use_curr) ? wpos1 : wpos2;
+
+ vec2 ss_adj = project_to_screenspace(ndc_adj);
+ vec2 ss1 = project_to_screenspace(ndc1);
+ vec2 ss2 = project_to_screenspace(ndc2);
+ /* Screenspace Lines tangents. */
+ float line_len;
+ vec2 line = safe_normalize_len(ss2 - ss1, line_len);
+ vec2 line_adj = safe_normalize((use_curr) ? (ss1 - ss_adj) : (ss_adj - ss2));
+
+ float thickness = abs((use_curr) ? thickness1 : thickness2);
+ thickness = stroke_thickness_modulate(thickness);
+
+ finalUvs = vec2(x, y) * 0.5 + 0.5;
+ strokeHardeness = (use_curr) ? hard1.y : hard2.y;
+
+ if (is_dot) {
+# ifdef GP_MATERIAL_BUFFER_LEN
+ int alignement = MATERIAL(m).flag & GP_STROKE_ALIGNMENT;
+# endif
+
+ vec2 x_axis;
+# ifdef GP_MATERIAL_BUFFER_LEN
+ if (alignement == GP_STROKE_ALIGNMENT_STROKE) {
+ x_axis = (ma2.x == -1.0) ? line_adj : line;
+ }
+ else if (alignement == GP_STROKE_ALIGNMENT_FIXED) {
+ /* Default for no-material drawing. */
+ x_axis = vec2(1.0, 0.0);
+ }
+ else
+# endif
+ { /* GP_STROKE_ALIGNMENT_OBJECT */
+ vec4 ndc_x = point_world_to_ndc(wpos1 + model_mat[0].xyz);
+ vec2 ss_x = project_to_screenspace(ndc_x);
+ x_axis = safe_normalize(ss_x - ss1);
+ }
+
+ /* Rotation: Encoded as Cos + Sin sign. */
+ float rot_sin = sqrt(1.0 - uv1.w * uv1.w) * sign(uv1.w);
+ float rot_cos = abs(uv1.w);
+ x_axis = mat2(rot_cos, -rot_sin, rot_sin, rot_cos) * x_axis;
+
+ vec2 y_axis = rotate_90deg(x_axis);
+
+ strokeAspect.x = aspect1;
+
+ if (strokeAspect.x > 1.0) {
+ strokeAspect.y = strokeAspect.x;
+ strokeAspect.x = 1.0;
+ }
+ else {
+ strokeAspect.x = 1.0 / strokeAspect.x;
+ strokeAspect.y = 1.0;
+ }
+
+ x /= strokeAspect.x;
+ y /= strokeAspect.y;
+
+ gl_Position.xy += (x * x_axis + y * y_axis) * sizeViewportInv.xy * thickness;
+
+ strokePt1 = ss1;
+ strokePt2 = ss1 + x_axis * 0.5;
+ strokeThickness = (is_squares) ? 1e18 : (thickness / gl_Position.w);
+ }
+ else {
+ bool is_stroke_start = (ma.x == -1.0 && x == -1.0);
+ bool is_stroke_end = (ma3.x == -1.0 && x == 1.0);
+
+ /* Mitter tangent vector. */
+ vec2 miter_tan = safe_normalize(line_adj + line);
+ float miter_dot = dot(miter_tan, line_adj);
+ /* Break corners after a certain angle to avoid really thick corners. */
+ const float miter_limit = 0.5; /* cos(60°) */
+ bool miter_break = (miter_dot < miter_limit) || is_stroke_start || is_stroke_end;
+ miter_tan = (miter_break) ? line : (miter_tan / miter_dot);
+
+ vec2 miter = rotate_90deg(miter_tan);
+
+ strokePt1.xy = ss1;
+ strokePt2.xy = ss2;
+ strokeThickness = thickness / gl_Position.w;
+ strokeAspect = vec2(1.0);
+
+ vec2 screen_ofs = miter * y;
+
+ /* Reminder: we packed the cap flag into the sign of stength and thickness sign. */
+ if ((is_stroke_start && strength1 > 0.0) || (is_stroke_end && thickness1 > 0.0) ||
+ miter_break) {
+ screen_ofs += line * x;
+ }
+
+ gl_Position.xy += screen_ofs * sizeViewportInv.xy * thickness;
+
+ finalUvs.x = (use_curr) ? uv1.z : uv2.z;
+# ifdef GP_MATERIAL_BUFFER_LEN
+ finalUvs.x *= MATERIAL(m).stroke_u_scale;
+# endif
+ }
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+ vec4 vert_col = (use_curr) ? col1 : col2;
+ float vert_strength = abs((use_curr) ? strength1 : strength2);
+ vec4 stroke_col = MATERIAL(m).stroke_color;
+ float mix_tex = MATERIAL(m).stroke_texture_mix;
+
+ color_output(stroke_col, vert_col, vert_strength, mix_tex);
+
+ matFlag = MATERIAL(m).flag & ~GP_FILL_FLAGS;
+# endif
+
+ if (strokeOrder3d) {
+ /* Use the fragment depth (see fragment shader). */
+ depth = -1.0;
+ }
+# ifdef GP_MATERIAL_BUFFER_LEN
+ else if (GP_FLAG_TEST(MATERIAL(m).flag, GP_STROKE_OVERLAP)) {
+ /* Use the index of the point as depth.
+ * This means the stroke can overlap itself. */
+ depth = (point_id1 + strokeIndexOffset + 1.0) * 0.0000002;
+ }
+# endif
+ else {
+ /* Use the index of first point of the stroke as depth.
+ * We render using a greater depth test this means the stroke
+ * cannot overlap itself.
+ * We offset by one so that the fill can be overlapped by its stroke.
+ * The offset is ok since we pad the strokes data because of adjacency infos. */
+ depth = (stroke_id1 + strokeIndexOffset + 1.0) * 0.0000002;
+ }
+}
+
+void fill_vertex()
+{
+ mat4 model_mat = model_matrix_get();
+
+ vec3 wpos = transform_point(model_mat, pos1.xyz);
+ gl_Position = point_world_to_ndc(wpos);
+ finalPos = wpos;
+
+# ifdef GP_MATERIAL_BUFFER_LEN
+ int m = int(ma1.x);
+
+ vec4 fill_col = MATERIAL(m).fill_color;
+ float mix_tex = MATERIAL(m).fill_texture_mix;
+
+ /* Special case: We don't modulate alpha in gradient mode. */
+ if (GP_FLAG_TEST(MATERIAL(m).flag, GP_FILL_GRADIENT_USE)) {
+ fill_col.a = 1.0;
+ }
+
+ /* Decode fill opacity. */
+ vec4 fcol_decode = vec4(fcol1.rgb, floor(fcol1.a / 10.0));
+ float fill_opacity = fcol1.a - (fcol_decode.a * 10);
+ fcol_decode.a /= 10000.0f;
+
+ /* Apply opacity. */
+ fill_col.a *= fill_opacity;
+ /* If factor is > 1 force opacity. */
+ if (fill_opacity > 1.0) {
+ fill_col.a += fill_opacity - 1.0f;
+ }
+
+ fill_col.a = clamp(fill_col.a, 0.0, 1.0);
+
+ color_output(fill_col, fcol_decode, 1.0, mix_tex);
+
+ matFlag = MATERIAL(m).flag & GP_FILL_FLAGS;
+ matFlag |= m << GP_MATID_SHIFT;
+
+ vec2 loc = MATERIAL(m).fill_uv_offset.xy;
+ mat2x2 rot_scale = mat2x2(MATERIAL(m).fill_uv_rot_scale.xy, MATERIAL(m).fill_uv_rot_scale.zw);
+ finalUvs = rot_scale * uv1.xy + loc;
+# endif
+
+ strokeThickness = 1e18;
+ strokeAspect = vec2(1.0);
+ strokePt1 = strokePt2 = vec2(0.0);
+
+ if (strokeOrder3d) {
+ /* Use the fragment depth (see fragment shader). */
+ depth = -1.0;
+ /* We still offset the fills a little to avoid overlaps */
+ gl_Position.z += 0.000002;
+ }
+ else {
+ /* Use the index of first point of the stroke as depth. */
+ depth = (stroke_id1 + strokeIndexOffset) * 0.0000002;
+ }
+}
+
+void gpencil_vertex()
+{
+ /* Trick to detect if a drawcall is stroke or fill.
+ * This does mean that we need to draw an empty stroke segment before starting
+ * to draw the real stroke segments. */
+ bool is_fill = (gl_InstanceID == 0);
+
+ if (!is_fill) {
+ stroke_vertex();
+ }
+ else {
+ fill_vertex();
+ }
+}
+
+#endif
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
new file mode 100644
index 00000000000..71597197bd8
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_frag.glsl
@@ -0,0 +1,17 @@
+
+uniform sampler2D depthBuf;
+uniform float strokeDepth2d;
+uniform bool strokeOrder3d;
+
+noperspective in vec4 uvcoordsvar;
+
+void main()
+{
+ float depth = textureLod(depthBuf, uvcoordsvar.xy, 0).r;
+ if (strokeOrder3d) {
+ gl_FragDepth = depth;
+ }
+ else {
+ gl_FragDepth = (depth != 0.0) ? gl_FragCoord.z : 1.0;
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
new file mode 100644
index 00000000000..1e5a900f486
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_depth_merge_vert.glsl
@@ -0,0 +1,14 @@
+
+uniform vec4 gpModelMatrix[4];
+
+noperspective out vec4 uvcoordsvar;
+
+void main()
+{
+ mat4 model_matrix = mat4(gpModelMatrix[0], gpModelMatrix[1], gpModelMatrix[2], gpModelMatrix[3]);
+ int v = gl_VertexID % 3;
+ float x = -1.0 + float((v & 1) << 2);
+ float y = -1.0 + float((v & 2) << 1);
+ gl_Position = ViewProjectionMatrix * (model_matrix * vec4(x, y, 0.0, 1.0));
+ uvcoordsvar = vec4((gl_Position.xy / gl_Position.w + 1.0) * 0.5, 0.0, 0.0);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
deleted file mode 100644
index 6a2a4f68dc9..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_frag.glsl
+++ /dev/null
@@ -1,17 +0,0 @@
-in vec4 mColor;
-in vec2 mTexCoord;
-out vec4 fragColor;
-
-void main()
-{
- vec2 centered = mTexCoord - vec2(0.5);
- float dist_squared = dot(centered, centered);
- const float rad_squared = 0.25;
-
- // round point with jaggy edges
- if (dist_squared > rad_squared) {
- discard;
- }
-
- fragColor = mColor;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl
deleted file mode 100644
index e0634a7d1a7..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_geom.glsl
+++ /dev/null
@@ -1,53 +0,0 @@
-uniform vec2 Viewport;
-
-layout(points) in;
-layout(triangle_strip, max_vertices = 4) out;
-
-in vec4 finalColor[1];
-in float finalThickness[1];
-
-out vec4 mColor;
-out vec2 mTexCoord;
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- return vec2(vertex.xy / vertex.w) * Viewport;
-}
-
-/* get zdepth value */
-float getZdepth(vec4 point)
-{
- return min(-0.05, (point.z / point.w));
-}
-
-void main(void)
-{
- vec4 P0 = gl_in[0].gl_Position;
- vec2 sp0 = toScreenSpace(P0);
-
- float size = finalThickness[0];
-
- /* generate the triangle strip */
- mTexCoord = vec2(0, 1);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x - size, sp0.y + size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x - size, sp0.y - size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(1, 1);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x + size, sp0.y + size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(1, 0);
- mColor = finalColor[0];
- gl_Position = vec4(vec2(sp0.x + size, sp0.y - size) / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
deleted file mode 100644
index 57908f3251b..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_edit_point_vert.glsl
+++ /dev/null
@@ -1,19 +0,0 @@
-
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in float size;
-
-out vec4 finalColor;
-out float finalThickness;
-
-void main()
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalColor = color;
- finalThickness = size;
-
- /* Dirty fix waiting for new GPencil engine. */
- finalColor.rgb = pow(finalColor.rgb, vec3(2.2));
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
deleted file mode 100644
index 8285541e0b4..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_frag.glsl
+++ /dev/null
@@ -1,234 +0,0 @@
-uniform vec4 color2;
-uniform int fill_type;
-uniform float mix_factor;
-
-uniform float gradient_angle;
-uniform float gradient_radius;
-uniform float pattern_gridsize;
-uniform vec2 gradient_scale;
-uniform vec2 gradient_shift;
-
-uniform float texture_angle;
-uniform vec2 texture_scale;
-uniform vec2 texture_offset;
-uniform int texture_mix;
-uniform int texture_flip;
-uniform float texture_opacity;
-uniform int xraymode;
-uniform int drawmode;
-uniform float layer_opacity;
-
-uniform sampler2D myTexture;
-uniform bool myTexturePremultiplied;
-uniform int texture_clamp;
-
-uniform int viewport_xray;
-uniform int shading_type[2];
-uniform vec4 wire_color;
-
-uniform int fade_layer;
-uniform float fade_layer_factor;
-uniform bool fade_ob;
-uniform vec3 fade_color;
-uniform float fade_ob_factor;
-
-/* keep this list synchronized with list in gpencil_draw_utils.c */
-#define SOLID 0
-#define GRADIENT 1
-#define RADIAL 2
-#define CHECKER 3
-#define TEXTURE 4
-#define PATTERN 5
-
-#define GP_XRAY_FRONT 0
-#define GP_XRAY_3DSPACE 1
-
-#define GP_DRAWMODE_2D 0
-#define GP_DRAWMODE_3D 1
-
-#define OB_WIRE 2
-#define OB_SOLID 3
-
-#define V3D_SHADING_MATERIAL_COLOR 0
-#define V3D_SHADING_TEXTURE_COLOR 3
-#define V3D_SHADING_VERTEX_COLOR 5
-
-in vec4 finalColor;
-in vec2 texCoord_interp;
-out vec4 fragColor;
-#define texture2D texture
-
-void set_color(in vec4 color,
- in vec4 color2,
- in vec4 tcolor,
- in float mixv,
- in float factor,
- in int tmix,
- in int flip,
- out vec4 ocolor)
-{
- /* full color A */
- if (mixv == 1.0) {
- if (tmix == 1) {
- ocolor = (flip == 0) ? color : tcolor;
- }
- else {
- ocolor = (flip == 0) ? color : color2;
- }
- }
- /* full color B */
- else if (mixv == 0.0) {
- if (tmix == 1) {
- ocolor = (flip == 0) ? tcolor : color;
- }
- else {
- ocolor = (flip == 0) ? color2 : color;
- }
- }
- /* mix of colors */
- else {
- if (tmix == 1) {
- ocolor = (flip == 0) ? mix(color, tcolor, factor) : mix(tcolor, color, factor);
- }
- else {
- ocolor = (flip == 0) ? mix(color, color2, factor) : mix(color2, color, factor);
- }
- }
- ocolor.a *= layer_opacity;
-}
-
-void main()
-{
- vec2 t_center = vec2(0.5, 0.5);
- mat2 matrot_tex = mat2(
- cos(texture_angle), -sin(texture_angle), sin(texture_angle), cos(texture_angle));
- vec2 rot_tex = (matrot_tex * (texCoord_interp - t_center)) + t_center + texture_offset;
- vec4 tmp_color;
- tmp_color = (texture_clamp == 0) ?
- texture_read_as_srgb(
- myTexture, myTexturePremultiplied, rot_tex * texture_scale) :
- texture_read_as_srgb(
- myTexture, myTexturePremultiplied, clamp(rot_tex * texture_scale, 0.0, 1.0));
- vec4 text_color = vec4(tmp_color[0], tmp_color[1], tmp_color[2], tmp_color[3] * texture_opacity);
- vec4 checker_color;
-
- /* wireframe with x-ray discard */
- if ((viewport_xray == 1) && (shading_type[0] == OB_WIRE)) {
- discard;
- }
-
- /* solid fill */
- if (fill_type == SOLID) {
- fragColor = finalColor;
- }
- else {
- vec2 center = vec2(0.5, 0.5) + gradient_shift;
- mat2 matrot = mat2(
- cos(gradient_angle), -sin(gradient_angle), sin(gradient_angle), cos(gradient_angle));
- vec2 rot = (((matrot * (texCoord_interp - center)) + center) * gradient_scale) +
- gradient_shift;
- /* gradient */
- if (fill_type == GRADIENT) {
- set_color(finalColor,
- color2,
- text_color,
- mix_factor,
- rot.x - mix_factor + 0.5,
- texture_mix,
- texture_flip,
- fragColor);
- }
- /* radial gradient */
- if (fill_type == RADIAL) {
- float in_rad = gradient_radius * mix_factor;
- float ex_rad = gradient_radius - in_rad;
- float intensity = 0;
- float distance = length((center - texCoord_interp) * gradient_scale);
- if (distance > gradient_radius) {
- discard;
- }
- if (distance > in_rad) {
- intensity = clamp(((distance - in_rad) / ex_rad), 0.0, 1.0);
- }
- set_color(finalColor,
- color2,
- text_color,
- mix_factor,
- intensity,
- texture_mix,
- texture_flip,
- fragColor);
- }
- /* Checkerboard */
- if (fill_type == CHECKER) {
- vec2 pos = rot / pattern_gridsize;
- if ((fract(pos.x) < 0.5 && fract(pos.y) < 0.5) ||
- (fract(pos.x) > 0.5 && fract(pos.y) > 0.5)) {
- checker_color = (texture_flip == 0) ? finalColor : color2;
- }
- else {
- checker_color = (texture_flip == 0) ? color2 : finalColor;
- }
- /* mix with texture */
- fragColor = (texture_mix == 1) ? mix(checker_color, text_color, mix_factor) : checker_color;
- fragColor.a *= layer_opacity;
- }
- /* texture */
- if (fill_type == TEXTURE) {
- fragColor = (texture_mix == 1) ? mix(text_color, finalColor, mix_factor) : text_color;
- fragColor.a *= layer_opacity;
- }
- /* pattern */
- if (fill_type == PATTERN) {
- fragColor = finalColor;
- fragColor.a = min(text_color.a, finalColor.a) * layer_opacity;
- }
- }
-
- /* set zdepth */
- if (xraymode == GP_XRAY_FRONT) {
- gl_FragDepth = min(-0.05, (gl_FragCoord.z / gl_FragCoord.w));
- }
- else if (xraymode == GP_XRAY_3DSPACE) {
- /* if 3D mode, move slightly the fill to avoid z-fighting between stroke and fill on same
- * stroke */
- if (drawmode == GP_DRAWMODE_3D) {
- gl_FragDepth = gl_FragCoord.z * 1.0001;
- }
- else {
- gl_FragDepth = gl_FragCoord.z;
- }
- }
- else {
- gl_FragDepth = 0.000001;
- }
-
- /* if wireframe override colors */
- if (shading_type[0] == OB_WIRE) {
- fragColor = wire_color;
- }
-
- /* for solid override color */
- if (shading_type[0] == OB_SOLID) {
- if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
- (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
- fragColor = wire_color;
- }
- if (viewport_xray == 1) {
- fragColor.a *= 0.5;
- }
- }
- /* Apply paper opacity */
- if (fade_layer == 1) {
- /* Layer is below, mix with background. */
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
- }
- else if (fade_layer == 2) {
- /* Layer is above, change opacity. */
- fragColor.a *= fade_layer_factor;
- }
- else if (fade_ob == true) {
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
deleted file mode 100644
index 263dc570423..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_fill_vert.glsl
+++ /dev/null
@@ -1,16 +0,0 @@
-
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in vec2 texCoord;
-
-out vec4 finalColor;
-out vec2 texCoord_interp;
-
-void main(void)
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalColor = color;
- texCoord_interp = texCoord;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
new file mode 100644
index 00000000000..8c2032f834a
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_frag.glsl
@@ -0,0 +1,126 @@
+
+uniform sampler2D gpFillTexture;
+uniform sampler2D gpStrokeTexture;
+uniform sampler2D gpSceneDepthTexture;
+uniform sampler2D gpMaskTexture;
+uniform vec3 gpNormal;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 revealColor;
+
+float length_squared(vec2 v)
+{
+ return dot(v, v);
+}
+float length_squared(vec3 v)
+{
+ return dot(v, v);
+}
+
+vec3 gpencil_lighting(void)
+{
+ vec3 light_accum = vec3(0.0);
+ for (int i = 0; i < GPENCIL_LIGHT_BUFFER_LEN; i++) {
+ if (lights[i].color_type.x == -1.0) {
+ break;
+ }
+ vec3 L = lights[i].position.xyz - finalPos;
+ float vis = 1.0;
+ /* Spot Attenuation. */
+ if (lights[i].color_type.w == GP_LIGHT_TYPE_SPOT) {
+ mat3 rot_scale = mat3(lights[i].right.xyz, lights[i].up.xyz, lights[i].forward.xyz);
+ vec3 local_L = rot_scale * L;
+ local_L /= abs(local_L.z);
+ float ellipse = inversesqrt(length_squared(local_L));
+ vis *= smoothstep(0.0, 1.0, (ellipse - lights[i].spot_size) / lights[i].spot_blend);
+ /* Also mask +Z cone. */
+ vis *= step(0.0, local_L.z);
+ }
+ /* Inverse square decay. Skip for suns. */
+ float L_len_sqr = length_squared(L);
+ if (lights[i].color_type.w < GP_LIGHT_TYPE_SUN) {
+ vis /= L_len_sqr;
+ }
+ else {
+ L = lights[i].forward.xyz;
+ L_len_sqr = 1.0;
+ }
+ /* Lambertian falloff */
+ if (lights[i].color_type.w != GP_LIGHT_TYPE_AMBIENT) {
+ L /= sqrt(L_len_sqr);
+ vis *= clamp(dot(gpNormal, L), 0.0, 1.0);
+ }
+ light_accum += vis * lights[i].color_type.rgb;
+ }
+ /* Clamp to avoid NaNs. */
+ return clamp(light_accum, 0.0, 1e10);
+}
+
+void main()
+{
+ vec4 col;
+ if (GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_USE)) {
+ bool premul = GP_FLAG_TEST(matFlag, GP_STROKE_TEXTURE_PREMUL);
+ col = texture_read_as_linearrgb(gpStrokeTexture, premul, finalUvs);
+ }
+ else if (GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_USE)) {
+ bool use_clip = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_CLIP);
+ vec2 uvs = (use_clip) ? clamp(finalUvs, 0.0, 1.0) : finalUvs;
+ bool premul = GP_FLAG_TEST(matFlag, GP_FILL_TEXTURE_PREMUL);
+ col = texture_read_as_linearrgb(gpFillTexture, premul, uvs);
+ }
+ else if (GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_USE)) {
+ bool radial = GP_FLAG_TEST(matFlag, GP_FILL_GRADIENT_RADIAL);
+ float fac = clamp(radial ? length(finalUvs * 2.0 - 1.0) : finalUvs.x, 0.0, 1.0);
+ int matid = matFlag >> GP_MATID_SHIFT;
+ col = mix(MATERIAL(matid).fill_color, MATERIAL(matid).fill_mix_color, fac);
+ }
+ else /* SOLID */ {
+ col = vec4(1.0);
+ }
+ col.rgb *= col.a;
+
+ /* Composite all other colors on top of texture color.
+ * Everything is premult by col.a to have the stencil effect. */
+ fragColor = col * finalColorMul + col.a * finalColorAdd;
+
+ fragColor.rgb *= gpencil_lighting();
+
+ fragColor *= stroke_round_cap_mask(
+ strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness);
+
+ /* For compatibility with colored alpha buffer.
+ * Note that we are limited to mono-chromatic alpha blending here
+ * because of the blend equation and the limit of 1 color target
+ * when using custom color blending. */
+ revealColor = vec4(0.0, 0.0, 0.0, fragColor.a);
+
+ if (fragColor.a < 0.001) {
+ discard;
+ }
+
+ /* Manual depth test */
+ vec2 uvs = gl_FragCoord.xy / vec2(textureSize(gpSceneDepthTexture, 0).xy);
+ float scene_depth = texture(gpSceneDepthTexture, uvs).r;
+ if (gl_FragCoord.z > scene_depth) {
+ discard;
+ }
+
+ /* FIXME(fclem) Grrr. This is bad for performance but it's the easiest way to not get
+ * depth written where the mask obliterate the layer. */
+ float mask = texture(gpMaskTexture, uvs).r;
+ if (mask < 0.001) {
+ discard;
+ }
+
+ /* We override the fragment depth using the fragment shader to ensure a constant value.
+ * This has a cost as the depth test cannot happen early.
+ * We could do this in the vertex shader but then perspective interpolation of uvs and
+ * fragment clipping gets really complicated. */
+ if (depth >= 0.0) {
+ gl_FragDepth = depth;
+ }
+ else {
+ gl_FragDepth = gl_FragCoord.z;
+ }
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
new file mode 100644
index 00000000000..6fbc7f47dac
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_layer_blend_frag.glsl
@@ -0,0 +1,31 @@
+
+uniform sampler2D colorBuf;
+uniform sampler2D revealBuf;
+uniform sampler2D maskBuf;
+uniform int blendMode;
+uniform float blendOpacity;
+
+in vec4 uvcoordsvar;
+
+/* Reminder: This is considered SRC color in blend equations.
+ * Same operation on all buffers. */
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 fragRevealage;
+
+void main()
+{
+ vec4 color;
+
+ /* Remember, this is associated alpha (aka. premult). */
+ color.rgb = textureLod(colorBuf, uvcoordsvar.xy, 0).rgb;
+ /* Stroke only render mono-chromatic revealage. We convert to alpha. */
+ color.a = 1.0 - textureLod(revealBuf, uvcoordsvar.xy, 0).r;
+
+ float mask = textureLod(maskBuf, uvcoordsvar.xy, 0).r;
+ mask *= blendOpacity;
+
+ fragColor = vec4(1.0, 0.0, 1.0, 1.0);
+ fragRevealage = vec4(1.0, 0.0, 1.0, 1.0);
+
+ blend_mode_output(blendMode, color, mask, fragColor, fragRevealage);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
new file mode 100644
index 00000000000..b21b4147087
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_mask_invert_frag.glsl
@@ -0,0 +1,11 @@
+
+in vec4 uvcoordsvar;
+
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 fragRevealage;
+
+void main()
+{
+ /* Blend mode does the inversion. */
+ fragRevealage = fragColor = vec4(1.0);
+}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
deleted file mode 100644
index 1d1cd6349dc..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_paper_frag.glsl
+++ /dev/null
@@ -1,9 +0,0 @@
-uniform vec3 color;
-uniform float opacity;
-
-out vec4 FragColor;
-
-void main()
-{
- FragColor = vec4(color, 1.0 - opacity);
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
deleted file mode 100644
index d79b8fb4d8a..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_frag.glsl
+++ /dev/null
@@ -1,126 +0,0 @@
-uniform int color_type;
-uniform int mode;
-uniform sampler2D myTexture;
-uniform bool myTexturePremultiplied;
-
-uniform float gradient_f;
-uniform vec2 gradient_s;
-
-uniform vec4 colormix;
-uniform float mix_stroke_factor;
-uniform int shading_type[2];
-
-in vec4 mColor;
-in vec2 mTexCoord;
-out vec4 fragColor;
-
-uniform int fade_layer;
-uniform float fade_layer_factor;
-uniform bool fade_ob;
-uniform vec3 fade_color;
-uniform float fade_ob_factor;
-
-#define texture2D texture
-
-#define GPENCIL_MODE_LINE 0
-#define GPENCIL_MODE_DOTS 1
-#define GPENCIL_MODE_BOX 2
-
-/* keep this list synchronized with list in gpencil_engine.h */
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-#define OB_SOLID 3
-#define V3D_SHADING_TEXTURE_COLOR 3
-
-bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR);
-
-/* Function to check the point inside ellipse */
-float check_ellipse_point(vec2 pt, vec2 radius)
-{
- float p = (pow(pt.x, 2) / pow(radius.x, 2)) + (pow(pt.y, 2) / pow(radius.y, 2));
-
- return p;
-}
-
-/* Function to check the point inside box */
-vec2 check_box_point(vec2 pt, vec2 radius)
-{
- vec2 rtn;
- rtn.x = abs(pt.x) / radius.x;
- rtn.y = abs(pt.y) / radius.y;
-
- return rtn;
-}
-
-void main()
-{
- vec2 centered = mTexCoord - vec2(0.5);
- float ellip = check_ellipse_point(centered, vec2(gradient_s / 2.0));
- vec2 box;
-
- if (mode != GPENCIL_MODE_BOX) {
- if (ellip > 1.0) {
- discard;
- }
- }
- else {
- box = check_box_point(centered, vec2(gradient_s / 2.0));
- if ((box.x > 1.0) || (box.y > 1.0)) {
- discard;
- }
- }
-
- /* Solid */
- if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) {
- fragColor = mColor;
- }
- /* texture */
- if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) {
- vec4 text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord);
- if (mix_stroke_factor > 0.0) {
- fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor);
- fragColor.a = text_color.a;
- }
- else {
- fragColor = text_color;
- }
-
- /* mult both alpha factor to use strength factor with texture */
- fragColor.a = min(fragColor.a * mColor.a, fragColor.a);
- }
- /* pattern */
- if ((color_type == GPENCIL_COLOR_PATTERN) && (!no_texture)) {
- vec4 text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord);
- fragColor = mColor;
- /* mult both alpha factor to use strength factor with color alpha limit */
- fragColor.a = min(text_color.a * mColor.a, mColor.a);
- }
-
- if (gradient_f < 1.0) {
- float dist = length(centered) * 2.0;
- float decay = dist * (1.0 - gradient_f) * fragColor.a;
- fragColor.a = clamp(fragColor.a - decay, 0.0, 1.0);
- if (mode == GPENCIL_MODE_DOTS) {
- fragColor.a = fragColor.a * (1.0 - ellip);
- }
- }
-
- if (fragColor.a < 0.0035) {
- discard;
- }
-
- /* Apply paper opacity */
- if (fade_layer == 1) {
- /* Layer is below, mix with background. */
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
- }
- else if (fade_layer == 2) {
- /* Layer is above, change opacity. */
- fragColor.a *= fade_layer_factor;
- }
- else if (fade_ob == true) {
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
deleted file mode 100644
index a2f4c1f9b15..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_geom.glsl
+++ /dev/null
@@ -1,142 +0,0 @@
-uniform vec2 Viewport;
-uniform int xraymode;
-uniform int alignment_mode;
-
-layout(points) in;
-layout(triangle_strip, max_vertices = 4) out;
-
-in vec4 finalColor[1];
-in float finalThickness[1];
-in vec2 finaluvdata[1];
-in vec4 finalprev_pos[1];
-
-out vec4 mColor;
-out vec2 mTexCoord;
-
-#define GP_XRAY_FRONT 0
-#define GP_XRAY_3DSPACE 1
-
-#define M_PI 3.14159265358979323846 /* pi */
-#define M_2PI 6.28318530717958647692 /* 2*pi */
-#define FALSE 0
-
-/* keep this definition equals to GP_STYLE_FOLLOW_FIXED value */
-#define FIXED 2
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- return vec2(vertex.xy / vertex.w) * Viewport;
-}
-
-/* get zdepth value */
-float getZdepth(vec4 point)
-{
- if (xraymode == GP_XRAY_FRONT) {
- return min(-0.05, (point.z / point.w));
- }
- if (xraymode == GP_XRAY_3DSPACE) {
- return (point.z / point.w);
- }
-
- /* in front by default */
- return 0.000001;
-}
-
-vec2 rotateUV(vec2 uv, float angle)
-{
- /* translate center of rotation to the center of texture */
- vec2 new_uv = uv - vec2(0.5f, 0.5f);
- vec2 rot_uv;
- rot_uv.x = new_uv.x * cos(angle) - new_uv.y * sin(angle);
- rot_uv.y = new_uv.y * cos(angle) + new_uv.x * sin(angle);
- return rot_uv + vec2(0.5f, 0.5f);
-}
-
-vec2 rotatePoint(vec2 center, vec2 point, float angle)
-{
- /* translate center of rotation to the center */
- vec2 new_point = point - center;
- vec2 rot_point;
- rot_point.x = new_point.x * cos(angle) - new_point.y * sin(angle);
- rot_point.y = new_point.y * cos(angle) + new_point.x * sin(angle);
- return rot_point + center;
-}
-
-/* Calculate angle of the stroke using previous point as reference.
- * The angle is calculated using the x axis (1, 0) as 0 degrees */
-float getAngle(vec2 pt0, vec2 pt1)
-{
- /* do not rotate one point only (no reference to rotate) */
- if (pt0 == pt1) {
- return 0.0;
- }
-
- if (alignment_mode == FIXED) {
- return 0.0;
- }
-
- /* default horizontal line (x-axis) in screen space */
- vec2 v0 = vec2(1.0, 0.0);
-
- /* vector of direction */
- vec2 vn = vec2(normalize(pt1 - pt0));
-
- /* angle signed (function ported from angle_signed_v2v2) */
- float perp_dot = (v0[1] * vn[0]) - (v0[0] * vn[1]);
- float angle = atan(perp_dot, dot(v0, vn));
-
- /* get full circle rotation */
- if (angle > 0.0) {
- angle = M_PI + (M_PI - angle);
- }
- else {
- angle *= -1.0;
- }
-
- return angle;
-}
-
-void main(void)
-{
- /* receive points */
- vec4 P0 = gl_in[0].gl_Position;
- vec2 sp0 = toScreenSpace(P0);
-
- vec4 P1 = finalprev_pos[0];
- vec2 sp1 = toScreenSpace(P1);
- vec2 point;
-
- float size = finalThickness[0];
- vec2 center = vec2(sp0.x, sp0.y);
-
- /* get angle of stroke to rotate texture */
- float angle = getAngle(sp0, sp1);
-
- /* generate the triangle strip */
- mTexCoord = rotateUV(vec2(0, 1), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x - size, sp0.y + size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = rotateUV(vec2(0, 0), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x - size, sp0.y - size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = rotateUV(vec2(1, 1), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x + size, sp0.y + size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- mTexCoord = rotateUV(vec2(1, 0), finaluvdata[0].y);
- mColor = finalColor[0];
- point = rotatePoint(center, vec2(sp0.x + size, sp0.y - size), angle);
- gl_Position = vec4(point / Viewport, getZdepth(P0), 1.0);
- EmitVertex();
-
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
deleted file mode 100644
index 33d7d714231..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_point_vert.glsl
+++ /dev/null
@@ -1,66 +0,0 @@
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform int keep_size;
-uniform float objscale;
-uniform float pixfactor;
-uniform int viewport_xray;
-uniform int shading_type[2];
-uniform vec4 wire_color;
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in float thickness;
-in vec2 uvdata;
-in vec3 prev_pos;
-
-out vec4 finalColor;
-out float finalThickness;
-out vec2 finaluvdata;
-out vec4 finalprev_pos;
-
-#define TRUE 1
-
-#define OB_WIRE 2
-#define OB_SOLID 3
-
-#define V3D_SHADING_MATERIAL_COLOR 0
-#define V3D_SHADING_TEXTURE_COLOR 3
-#define V3D_SHADING_VERTEX_COLOR 5
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-void main()
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalprev_pos = point_world_to_ndc((gpModelMatrix * vec4(prev_pos, 1.0)).xyz);
- finalColor = color;
-
- if (keep_size == TRUE) {
- finalThickness = thickness;
- }
- else {
- float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) :
- (thickness / defaultpixsize);
- finalThickness = max(size * objscale, 0.5); /* set a minimum size */
- }
-
- /* for wireframe override size and color */
- if (shading_type[0] == OB_WIRE) {
- finalThickness = 2.0;
- finalColor = wire_color;
- }
- /* for solid override color */
- if (shading_type[0] == OB_SOLID) {
- if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
- (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
- finalColor = wire_color;
- }
- if (viewport_xray == 1) {
- finalColor.a *= 0.5;
- }
- }
-
- finaluvdata = uvdata;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl
deleted file mode 100644
index 2f4429a858f..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_simple_mix_frag.glsl
+++ /dev/null
@@ -1,15 +0,0 @@
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
- float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
- vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
-
- FragColor = stroke_color;
- gl_FragDepth = stroke_depth;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
deleted file mode 100644
index 0f1665b73c2..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_frag.glsl
+++ /dev/null
@@ -1,110 +0,0 @@
-uniform int color_type;
-uniform sampler2D myTexture;
-uniform bool myTexturePremultiplied;
-
-uniform float gradient_f;
-
-uniform vec4 colormix;
-uniform float mix_stroke_factor;
-uniform int shading_type[2];
-
-uniform int fade_layer;
-uniform float fade_layer_factor;
-uniform bool fade_ob;
-uniform vec3 fade_color;
-uniform float fade_ob_factor;
-
-in vec4 mColor;
-in vec2 mTexCoord;
-in vec2 uvfac;
-
-out vec4 fragColor;
-
-#define texture2D texture
-
-/* keep this list synchronized with list in gpencil_engine.h */
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-#define ENDCAP 1.0
-
-#define OB_SOLID 3
-#define V3D_SHADING_TEXTURE_COLOR 3
-
-bool no_texture = (shading_type[0] == OB_SOLID) && (shading_type[1] != V3D_SHADING_TEXTURE_COLOR);
-
-void main()
-{
-
- vec4 tColor = vec4(mColor);
- /* if uvfac[1] == 1, then encap */
- if (uvfac[1] == ENDCAP) {
- vec2 center = vec2(uvfac[0], 0.5);
- float dist = length(mTexCoord - center);
- if (dist > 0.50) {
- discard;
- }
- }
-
- if ((color_type == GPENCIL_COLOR_SOLID) || (no_texture)) {
- fragColor = tColor;
- }
-
- /* texture for endcaps */
- vec4 text_color;
- if (uvfac[1] == ENDCAP) {
- text_color = texture_read_as_srgb(
- myTexture, myTexturePremultiplied, vec2(mTexCoord.x, mTexCoord.y));
- }
- else {
- text_color = texture_read_as_srgb(myTexture, myTexturePremultiplied, mTexCoord);
- }
-
- /* texture */
- if ((color_type == GPENCIL_COLOR_TEXTURE) && (!no_texture)) {
- if (mix_stroke_factor > 0.0) {
- fragColor.rgb = mix(text_color.rgb, colormix.rgb, mix_stroke_factor);
- fragColor.a = text_color.a;
- }
- else {
- fragColor = text_color;
- }
-
- /* mult both alpha factor to use strength factor */
- fragColor.a = min(fragColor.a * tColor.a, fragColor.a);
- }
- /* pattern */
- if ((color_type == GPENCIL_COLOR_PATTERN) && (!no_texture)) {
- fragColor = tColor;
- /* mult both alpha factor to use strength factor with color alpha limit */
- fragColor.a = min(text_color.a * tColor.a, tColor.a);
- }
-
- /* gradient */
- /* keep this disabled while the line glitch bug exists
- if (gradient_f < 1.0) {
- float d = abs(mTexCoord.y - 0.5) * (1.1 - gradient_f);
- float alpha = 1.0 - clamp((fragColor.a - (d * 2.0)), 0.03, 1.0);
- fragColor.a = smoothstep(fragColor.a, 0.0, alpha);
-
- }
- */
-
- if (fragColor.a < 0.0035) {
- discard;
- }
-
- /* Apply paper opacity */
- if (fade_layer == 1) {
- /* Layer is below, mix with background. */
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_layer_factor);
- }
- else if (fade_layer == 2) {
- /* Layer is above, change opacity. */
- fragColor.a *= fade_layer_factor;
- }
- else if (fade_ob == true) {
- fragColor.rgb = mix(fade_color.rgb, fragColor.rgb, fade_ob_factor);
- }
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
deleted file mode 100644
index 3300514dd13..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_geom.glsl
+++ /dev/null
@@ -1,264 +0,0 @@
-uniform vec2 Viewport;
-uniform int xraymode;
-uniform int color_type;
-uniform int caps_mode[2];
-
-layout(lines_adjacency) in;
-layout(triangle_strip, max_vertices = 13) out;
-
-in vec4 finalColor[4];
-in float finalThickness[4];
-in vec2 finaluvdata[4];
-
-out vec4 mColor;
-out vec2 mTexCoord;
-out vec2 uvfac;
-
-#define GP_XRAY_FRONT 0
-#define GP_XRAY_3DSPACE 1
-
-/* keep this list synchronized with list in gpencil_engine.h */
-#define GPENCIL_COLOR_SOLID 0
-#define GPENCIL_COLOR_TEXTURE 1
-#define GPENCIL_COLOR_PATTERN 2
-
-#define GPENCIL_FLATCAP 1
-
-/* project 3d point to 2d on screen space */
-vec2 toScreenSpace(vec4 vertex)
-{
- return vec2(vertex.xy / vertex.w) * Viewport;
-}
-
-/* get zdepth value */
-float getZdepth(vec4 point)
-{
- if (xraymode == GP_XRAY_FRONT) {
- return min(-0.05, (point.z / point.w));
- }
- if (xraymode == GP_XRAY_3DSPACE) {
- return (point.z / point.w);
- }
-
- /* in front by default */
- return 0.000001;
-}
-
-/* check equality but with a small tolerance */
-bool is_equal(vec4 p1, vec4 p2)
-{
- float limit = 0.0001;
- float x = abs(p1.x - p2.x);
- float y = abs(p1.y - p2.y);
- float z = abs(p1.z - p2.z);
-
- if ((x < limit) && (y < limit) && (z < limit)) {
- return true;
- }
-
- return false;
-}
-
-void main(void)
-{
- float MiterLimit = 0.75;
- uvfac = vec2(0.0, 0.0);
-
- /* receive 4 points */
- vec4 P0 = gl_in[0].gl_Position;
- vec4 P1 = gl_in[1].gl_Position;
- vec4 P2 = gl_in[2].gl_Position;
- vec4 P3 = gl_in[3].gl_Position;
-
- /* get the four vertices passed to the shader */
- vec2 sp0 = toScreenSpace(P0); // start of previous segment
- vec2 sp1 = toScreenSpace(P1); // end of previous segment, start of current segment
- vec2 sp2 = toScreenSpace(P2); // end of current segment, start of next segment
- vec2 sp3 = toScreenSpace(P3); // end of next segment
-
- /* culling outside viewport */
- vec2 area = Viewport * 4.0;
- if (sp1.x < -area.x || sp1.x > area.x) {
- return;
- }
- if (sp1.y < -area.y || sp1.y > area.y) {
- return;
- }
- if (sp2.x < -area.x || sp2.x > area.x) {
- return;
- }
- if (sp2.y < -area.y || sp2.y > area.y) {
- return;
- }
-
- /* culling behind camera */
- if (P1.w < 0 || P2.w < 0) {
- return;
- }
-
- /* determine the direction of each of the 3 segments (previous, current, next) */
- vec2 v0 = normalize(sp1 - sp0);
- vec2 v1 = normalize(sp2 - sp1);
- vec2 v2 = normalize(sp3 - sp2);
-
- /* determine the normal of each of the 3 segments (previous, current, next) */
- vec2 n0 = vec2(-v0.y, v0.x);
- vec2 n1 = vec2(-v1.y, v1.x);
- vec2 n2 = vec2(-v2.y, v2.x);
-
- /* determine miter lines by averaging the normals of the 2 segments */
- vec2 miter_a = normalize(n0 + n1); // miter at start of current segment
- vec2 miter_b = normalize(n1 + n2); // miter at end of current segment
-
- /* determine the length of the miter by projecting it onto normal and then inverse it */
- float an1 = dot(miter_a, n1);
- float bn1 = dot(miter_b, n2);
- if (an1 == 0) {
- an1 = 1;
- }
- if (bn1 == 0) {
- bn1 = 1;
- }
- float length_a = finalThickness[1] / an1;
- float length_b = finalThickness[2] / bn1;
- if (length_a <= 0.0) {
- length_a = 0.01;
- }
- if (length_b <= 0.0) {
- length_b = 0.01;
- }
-
- /* prevent excessively long miters at sharp corners */
- if (dot(v0, v1) < -MiterLimit) {
- miter_a = n1;
- length_a = finalThickness[1];
-
- /* close the gap */
- if (dot(v0, n1) > 0) {
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- EndPrimitive();
- }
- else {
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n1) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 1);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - finalThickness[1] * n0) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0, 0.5);
- mColor = finalColor[1];
- gl_Position = vec4(sp1 / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- EndPrimitive();
- }
- }
-
- if (dot(v1, v2) < -MiterLimit) {
- miter_b = n1;
- length_b = finalThickness[2];
- }
-
- /* generate the start endcap */
- if ((caps_mode[0] != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
- vec4 cap_color = finalColor[1];
-
- mTexCoord = vec2(2.0, 0.5);
- mColor = cap_color;
- vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0;
- uvfac = vec2(0.0, 1.0);
- gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0.0, -0.5);
- mColor = cap_color;
- uvfac = vec2(0.0, 1.0);
- gl_Position = vec4((sp1 - (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(0.0, 1.5);
- mColor = cap_color;
- uvfac = vec2(0.0, 1.0);
- gl_Position = vec4((sp1 + (length_a * 2.0) * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
- }
-
- float y_a = 0.0;
- float y_b = 1.0;
-
- /* invert uv (vertical) */
- if (finaluvdata[2].x > 1.0) {
- if ((finaluvdata[1].y != 0.0) && (finaluvdata[2].y != 0.0)) {
- float d = ceil(finaluvdata[2].x) - 1.0;
- if (floor(d / 2.0) == (d / 2.0)) {
- y_a = 1.0;
- y_b = 0.0;
- }
- }
- }
- /* generate the triangle strip */
- uvfac = vec2(0.0, 0.0);
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 0) : vec2(finaluvdata[1].x, y_a);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 + length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(0, 1) : vec2(finaluvdata[1].x, y_b);
- mColor = finalColor[1];
- gl_Position = vec4((sp1 - length_a * miter_a) / Viewport, getZdepth(P1), 1.0);
- EmitVertex();
-
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 0) : vec2(finaluvdata[2].x, y_a);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 + length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- mTexCoord = (color_type == GPENCIL_COLOR_SOLID) ? vec2(1, 1) : vec2(finaluvdata[2].x, y_b);
- mColor = finalColor[2];
- gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- /* generate the end endcap */
- if ((caps_mode[1] != GPENCIL_FLATCAP) && is_equal(P1, P3) && (finaluvdata[2].x > 0)) {
- vec4 cap_color = finalColor[2];
-
- mTexCoord = vec2(finaluvdata[2].x, 1.5);
- mColor = cap_color;
- uvfac = vec2(finaluvdata[2].x, 1.0);
- gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(finaluvdata[2].x, -0.5);
- mColor = cap_color;
- uvfac = vec2(finaluvdata[2].x, 1.0);
- gl_Position = vec4((sp2 - (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
-
- mTexCoord = vec2(finaluvdata[2].x + 2, 0.5);
- mColor = cap_color;
- uvfac = vec2(finaluvdata[2].x, 1.0);
- vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0;
- gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0);
- EmitVertex();
- }
-
- EndPrimitive();
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
deleted file mode 100644
index 8df08f0bf68..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_stroke_vert.glsl
+++ /dev/null
@@ -1,63 +0,0 @@
-
-uniform float pixsize; /* rv3d->pixsize */
-uniform int keep_size;
-uniform float objscale;
-uniform float pixfactor;
-uniform int viewport_xray;
-uniform int shading_type[2];
-uniform vec4 wire_color;
-uniform mat4 gpModelMatrix;
-
-in vec3 pos;
-in vec4 color;
-in float thickness;
-in vec2 uvdata;
-
-out vec4 finalColor;
-out float finalThickness;
-out vec2 finaluvdata;
-
-#define TRUE 1
-
-#define OB_WIRE 2
-#define OB_SOLID 3
-
-#define V3D_SHADING_MATERIAL_COLOR 0
-#define V3D_SHADING_TEXTURE_COLOR 3
-#define V3D_SHADING_VERTEX_COLOR 5
-
-float defaultpixsize = pixsize * (1000.0 / pixfactor);
-
-void main(void)
-{
- gl_Position = point_world_to_ndc((gpModelMatrix * vec4(pos, 1.0)).xyz);
- finalColor = color;
-
- if (keep_size == TRUE) {
- finalThickness = thickness;
- }
- else {
- float size = (ProjectionMatrix[3][3] == 0.0) ? (thickness / (gl_Position.z * defaultpixsize)) :
- (thickness / defaultpixsize);
- finalThickness = max(size * objscale, 1.0);
- }
-
- /* for wireframe override size and color */
- if (shading_type[0] == OB_WIRE) {
- finalThickness = 1.0;
- finalColor = wire_color;
- }
- /* for solid override color */
- if (shading_type[0] == OB_SOLID) {
- if ((shading_type[1] != V3D_SHADING_MATERIAL_COLOR) &&
- (shading_type[1] != V3D_SHADING_TEXTURE_COLOR) &&
- (shading_type[1] != V3D_SHADING_VERTEX_COLOR)) {
- finalColor = wire_color;
- }
- if (viewport_xray == 1) {
- finalColor.a *= 0.5;
- }
- }
-
- finaluvdata = uvdata;
-}
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
new file mode 100644
index 00000000000..c6cfee5ef2d
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl
@@ -0,0 +1,5 @@
+
+void main()
+{
+ gpencil_vertex();
+} \ No newline at end of file
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
new file mode 100644
index 00000000000..503248558ad
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_vfx_frag.glsl
@@ -0,0 +1,354 @@
+
+uniform sampler2D colorBuf;
+uniform sampler2D revealBuf;
+
+in vec4 uvcoordsvar;
+
+/* Reminder: This is considered SRC color in blend equations.
+ * Same operation on all buffers. */
+layout(location = 0) out vec4 fragColor;
+layout(location = 1) out vec4 fragRevealage;
+
+float gaussian_weight(float x)
+{
+ return exp(-x * x / (2.0 * 0.35 * 0.35));
+}
+
+#if defined(COMPOSITE)
+
+uniform bool isFirstPass;
+
+void main()
+{
+ if (isFirstPass) {
+ /* Blend mode is multiply. */
+ fragColor.rgb = fragRevealage.rgb = texture(revealBuf, uvcoordsvar.xy).rgb;
+ fragColor.a = fragRevealage.a = 1.0;
+ }
+ else {
+ /* Blend mode is additive. */
+ fragRevealage = vec4(0.0);
+ fragColor.rgb = texture(colorBuf, uvcoordsvar.xy).rgb;
+ fragColor.a = 0.0;
+ }
+}
+
+#elif defined(COLORIZE)
+
+uniform vec3 lowColor;
+uniform vec3 highColor;
+uniform float factor;
+uniform int mode;
+
+const mat3 sepia_mat = mat3(
+ vec3(0.393, 0.349, 0.272), vec3(0.769, 0.686, 0.534), vec3(0.189, 0.168, 0.131));
+
+# define MODE_GRAYSCALE 0
+# define MODE_SEPIA 1
+# define MODE_DUOTONE 2
+# define MODE_CUSTOM 3
+# define MODE_TRANSPARENT 4
+
+void main()
+{
+ fragColor = texture(colorBuf, uvcoordsvar.xy);
+ fragRevealage = texture(revealBuf, uvcoordsvar.xy);
+
+ float luma = dot(fragColor.rgb, vec3(0.2126, 0.7152, 0.723));
+
+ /* No blending. */
+ switch (mode) {
+ case MODE_GRAYSCALE:
+ fragColor.rgb = mix(fragColor.rgb, vec3(luma), factor);
+ break;
+ case MODE_SEPIA:
+ fragColor.rgb = mix(fragColor.rgb, sepia_mat * fragColor.rgb, factor);
+ break;
+ case MODE_DUOTONE:
+ fragColor.rgb = luma * ((luma <= factor) ? lowColor : highColor);
+ break;
+ case MODE_CUSTOM:
+ fragColor.rgb = mix(fragColor.rgb, luma * lowColor, factor);
+ break;
+ case MODE_TRANSPARENT:
+ default:
+ fragColor.rgb *= factor;
+ fragRevealage.rgb = mix(vec3(1.0), fragRevealage.rgb, factor);
+ break;
+ }
+}
+
+#elif defined(BLUR)
+
+uniform vec2 offset;
+uniform int sampCount;
+
+void main()
+{
+ vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy);
+ vec2 ofs = offset * pixel_size;
+
+ fragColor = vec4(0.0);
+ fragRevealage = vec4(0.0);
+
+ /* No blending. */
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = uvcoordsvar.xy + ofs * x;
+ fragColor.rgb += texture(colorBuf, uv).rgb * weight;
+ fragRevealage.rgb += texture(revealBuf, uv).rgb * weight;
+ }
+
+ fragColor /= weight_accum;
+ fragRevealage /= weight_accum;
+}
+
+#elif defined(TRANSFORM)
+
+uniform vec2 axisFlip = vec2(1.0);
+uniform vec2 waveDir = vec2(0.0);
+uniform vec2 waveOffset = vec2(0.0);
+uniform float wavePhase = 0.0;
+uniform vec2 swirlCenter = vec2(0.0);
+uniform float swirlAngle = 0.0;
+uniform float swirlRadius = 0.0;
+
+void main()
+{
+ vec2 uv = (uvcoordsvar.xy - 0.5) * axisFlip + 0.5;
+
+ /* Wave deform. */
+ float wave_time = dot(uv, waveDir.xy);
+ uv += sin(wave_time + wavePhase) * waveOffset;
+ /* Swirl deform. */
+ if (swirlRadius > 0.0) {
+ vec2 tex_size = vec2(textureSize(colorBuf, 0).xy);
+ vec2 pix_coord = uv * tex_size - swirlCenter;
+ float dist = length(pix_coord);
+ float percent = clamp((swirlRadius - dist) / swirlRadius, 0.0, 1.0);
+ float theta = percent * percent * swirlAngle;
+ float s = sin(theta);
+ float c = cos(theta);
+ mat2 rot = mat2(vec2(c, -s), vec2(s, c));
+ uv = (rot * pix_coord + swirlCenter) / tex_size;
+ }
+
+ fragColor = texture(colorBuf, uv);
+ fragRevealage = texture(revealBuf, uv);
+}
+
+#elif defined(GLOW)
+
+uniform vec4 glowColor;
+uniform vec2 offset;
+uniform int sampCount;
+uniform vec3 threshold;
+uniform bool firstPass;
+uniform bool glowUnder;
+uniform int blendMode;
+
+void main()
+{
+ vec2 pixel_size = 1.0 / vec2(textureSize(revealBuf, 0).xy);
+ vec2 ofs = offset * pixel_size;
+
+ fragColor = vec4(0.0);
+ fragRevealage = vec4(0.0);
+
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = uvcoordsvar.xy + ofs * x;
+ vec3 col = texture(colorBuf, uv).rgb;
+ vec3 rev = texture(revealBuf, uv).rgb;
+ if (threshold.x > -1.0) {
+ if (threshold.y > -1.0) {
+ if (all(lessThan(abs(col - threshold), vec3(0.05)))) {
+ weight = 0.0;
+ }
+ }
+ else {
+ if (dot(col, vec3(1.0 / 3.0)) < threshold.x) {
+ weight = 0.0;
+ }
+ }
+ }
+ fragColor.rgb += col * weight;
+ fragRevealage.rgb += (1.0 - rev) * weight;
+ }
+
+ if (weight_accum > 0.0) {
+ fragColor *= glowColor.rgbb / weight_accum;
+ fragRevealage = fragRevealage / weight_accum;
+ }
+ fragRevealage = 1.0 - fragRevealage;
+
+ if (glowUnder) {
+ if (firstPass) {
+ /* In first pass we copy the revealage buffer in the alpha channel.
+ * This let us do the alpha under in second pass. */
+ vec3 original_revealage = texture(revealBuf, uvcoordsvar.xy).rgb;
+ fragRevealage.a = clamp(dot(original_revealage.rgb, vec3(0.333334)), 0.0, 1.0);
+ }
+ else {
+ /* Recover original revealage. */
+ fragRevealage.a = texture(revealBuf, uvcoordsvar.xy).a;
+ }
+ }
+
+ if (!firstPass) {
+ fragColor.a = clamp(1.0 - dot(fragRevealage.rgb, vec3(0.333334)), 0.0, 1.0);
+ fragRevealage.a *= glowColor.a;
+ blend_mode_output(blendMode, fragColor, fragRevealage.a, fragColor, fragRevealage);
+ }
+}
+
+#elif defined(RIM)
+
+uniform vec2 blurDir;
+uniform vec2 uvOffset;
+uniform vec3 rimColor;
+uniform vec3 maskColor;
+uniform int sampCount;
+uniform int blendMode;
+uniform bool isFirstPass;
+
+void main()
+{
+ /* Blur revealage buffer. */
+ fragRevealage = vec4(0.0);
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = uvcoordsvar.xy + blurDir * x + uvOffset;
+ vec3 col = texture(revealBuf, uv).rgb;
+ if (any(not(equal(vec2(0.0), floor(uv))))) {
+ col = vec3(0.0);
+ }
+ fragRevealage.rgb += col * weight;
+ }
+ fragRevealage /= weight_accum;
+
+ if (isFirstPass) {
+ /* In first pass we copy the reveal buffer. This let us do alpha masking in second pass. */
+ fragColor = texture(revealBuf, uvcoordsvar.xy);
+ /* Also add the masked color to the reveal buffer. */
+ vec3 col = texture(colorBuf, uvcoordsvar.xy).rgb;
+ if (all(lessThan(abs(col - maskColor), vec3(0.05)))) {
+ fragColor = vec4(1.0);
+ }
+ }
+ else {
+ /* Premult by foreground alpha (alpha mask). */
+ float mask = 1.0 - clamp(dot(vec3(0.333334), texture(colorBuf, uvcoordsvar.xy).rgb), 0.0, 1.0);
+
+ /* fragRevealage is blurred shadow. */
+ float rim = clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0);
+
+ vec4 color = vec4(rimColor, 1.0);
+
+ blend_mode_output(blendMode, color, rim * mask, fragColor, fragRevealage);
+ }
+}
+
+#elif defined(SHADOW)
+
+uniform vec4 shadowColor;
+uniform vec2 uvRotX;
+uniform vec2 uvRotY;
+uniform vec2 uvOffset;
+uniform vec2 blurDir;
+uniform vec2 waveDir;
+uniform vec2 waveOffset;
+uniform float wavePhase;
+uniform int sampCount;
+uniform bool isFirstPass;
+
+vec2 compute_uvs(float x)
+{
+ vec2 uv = uvcoordsvar.xy;
+ /* Tranform UV (loc, rot, scale) */
+ uv = uv.x * uvRotX + uv.y * uvRotY + uvOffset;
+ uv += blurDir * x;
+ /* Wave deform. */
+ float wave_time = dot(uv, waveDir.xy);
+ uv += sin(wave_time + wavePhase) * waveOffset;
+ return uv;
+}
+
+void main()
+{
+ /* Blur revealage buffer. */
+ fragRevealage = vec4(0.0);
+ float weight_accum = 0.0;
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount);
+ float weight = gaussian_weight(x);
+ weight_accum += weight;
+ vec2 uv = compute_uvs(x);
+ vec3 col = texture(revealBuf, uv).rgb;
+ if (any(not(equal(vec2(0.0), floor(uv))))) {
+ col = vec3(1.0);
+ }
+ fragRevealage.rgb += col * weight;
+ }
+ fragRevealage /= weight_accum;
+
+ /* No blending in first pass, alpha over premult in second pass. */
+ if (isFirstPass) {
+ /* In first pass we copy the reveal buffer. This let us do alpha under in second pass. */
+ fragColor = texture(revealBuf, uvcoordsvar.xy);
+ }
+ else {
+ /* fragRevealage is blurred shadow. */
+ float shadow_fac = 1.0 - clamp(dot(vec3(0.333334), fragRevealage.rgb), 0.0, 1.0);
+ /* Premult by foreground revealage (alpha under). */
+ vec3 original_revealage = texture(colorBuf, uvcoordsvar.xy).rgb;
+ shadow_fac *= clamp(dot(vec3(0.333334), original_revealage), 0.0, 1.0);
+ /* Modulate by opacity */
+ shadow_fac *= shadowColor.a;
+ /* Apply shadow color. */
+ fragColor.rgb = mix(vec3(0.0), shadowColor.rgb, shadow_fac);
+ /* Alpha over (mask behind the shadow). */
+ fragColor.a = shadow_fac;
+
+ fragRevealage.rgb = original_revealage * (1.0 - shadow_fac);
+ /* Replace the whole revealage buffer. */
+ fragRevealage.a = 1.0;
+ }
+}
+
+#elif defined(PIXELIZE)
+
+uniform vec2 targetPixelSize;
+uniform vec2 targetPixelOffset;
+uniform vec2 accumOffset;
+uniform int sampCount;
+
+void main()
+{
+ vec2 pixel = floor((uvcoordsvar.xy - targetPixelOffset) / targetPixelSize);
+ vec2 uv = (pixel + 0.5) * targetPixelSize + targetPixelOffset;
+
+ fragColor = vec4(0.0);
+ fragRevealage = vec4(0.0);
+
+ for (int i = -sampCount; i <= sampCount; i++) {
+ float x = float(i) / float(sampCount + 1);
+ vec2 uv_ofs = uv + accumOffset * 0.5 * x;
+ fragColor += texture(colorBuf, uv_ofs);
+ fragRevealage += texture(revealBuf, uv_ofs);
+ }
+
+ fragColor /= float(sampCount) * 2.0 + 1.0;
+ fragRevealage /= float(sampCount) * 2.0 + 1.0;
+}
+
+#endif
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl
deleted file mode 100644
index 926b11e4083..00000000000
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_zdepth_mix_frag.glsl
+++ /dev/null
@@ -1,76 +0,0 @@
-in vec4 uvcoordsvar;
-
-out vec4 FragColor;
-
-uniform sampler2D strokeColor;
-uniform sampler2D strokeDepth;
-uniform int tonemapping;
-uniform vec4 select_color;
-uniform int do_select;
-
-float srgb_to_linearrgb(float c)
-{
- if (c < 0.04045) {
- return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
- }
- else {
- return pow((c + 0.055) * (1.0 / 1.055), 2.4);
- }
-}
-
-float linearrgb_to_srgb(float c)
-{
- if (c < 0.0031308) {
- return (c < 0.0) ? 0.0 : c * 12.92;
- }
- else {
- return 1.055 * pow(c, 1.0 / 2.4) - 0.055;
- }
-}
-
-bool check_borders(ivec2 uv, int size)
-{
- for (int x = -size; x <= size; x++) {
- for (int y = -size; y <= size; y++) {
- vec4 stroke_color = texelFetch(strokeColor, ivec2(uv.x + x, uv.y + y), 0).rgba;
- if (stroke_color.a > 0) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-void main()
-{
- ivec2 uv = ivec2(gl_FragCoord.xy);
- float stroke_depth = texelFetch(strokeDepth, uv, 0).r;
- vec4 stroke_color = texelFetch(strokeColor, uv, 0).rgba;
-
- /* 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);
- }
-
- /* apply color correction for render only */
- if (tonemapping == 1) {
- stroke_color.r = srgb_to_linearrgb(stroke_color.r);
- stroke_color.g = srgb_to_linearrgb(stroke_color.g);
- stroke_color.b = srgb_to_linearrgb(stroke_color.b);
- }
-
- FragColor = clamp(stroke_color, 0.0, 1.0);
- gl_FragDepth = clamp(stroke_depth, 0.0, 1.0);
-
- if (do_select == 1) {
- if (stroke_color.a == 0) {
- if (check_borders(uv, 2)) {
- FragColor = select_color;
- gl_FragDepth = 0.000001;
- /* Dirty fix waiting for new GPencil engine. */
- FragColor.rgb = pow(FragColor.rgb, vec3(2.2));
- }
- }
- }
-}
diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c
index a8d2c4c6cf0..cfa0fa9eb1a 100644
--- a/source/blender/draw/engines/overlay/overlay_engine.c
+++ b/source/blender/draw/engines/overlay/overlay_engine.c
@@ -25,6 +25,8 @@
#include "DRW_engine.h"
#include "DRW_render.h"
+#include "DEG_depsgraph_query.h"
+
#include "ED_view3d.h"
#include "BKE_object.h"
@@ -79,6 +81,7 @@ static void OVERLAY_engine_init(void *vedata)
pd->xray_enabled = XRAY_ACTIVE(v3d);
pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE;
pd->clear_in_front = (v3d->shading.type != OB_SOLID);
+ pd->cfra = DEG_get_ctime(draw_ctx->depsgraph);
OVERLAY_antialiasing_init(vedata);
@@ -133,11 +136,14 @@ static void OVERLAY_cache_init(void *vedata)
case CTX_MODE_SCULPT:
OVERLAY_sculpt_cache_init(vedata);
break;
- case CTX_MODE_OBJECT:
- case CTX_MODE_PAINT_GPENCIL:
case CTX_MODE_EDIT_GPENCIL:
+ case CTX_MODE_PAINT_GPENCIL:
case CTX_MODE_SCULPT_GPENCIL:
+ case CTX_MODE_VERTEX_GPENCIL:
case CTX_MODE_WEIGHT_GPENCIL:
+ OVERLAY_edit_gpencil_cache_init(vedata);
+ break;
+ case CTX_MODE_OBJECT:
break;
default:
BLI_assert(!"Draw mode invalid");
@@ -148,6 +154,7 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_background_cache_init(vedata);
OVERLAY_extra_cache_init(vedata);
OVERLAY_facing_cache_init(vedata);
+ OVERLAY_gpencil_cache_init(vedata);
OVERLAY_grid_cache_init(vedata);
OVERLAY_image_cache_init(vedata);
OVERLAY_metaball_cache_init(vedata);
@@ -216,8 +223,9 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob)
const bool in_paint_mode = (ob == draw_ctx->obact) &&
(draw_ctx->object_mode & OB_MODE_ALL_PAINT);
const bool in_sculpt_mode = (ob == draw_ctx->obact) && (ob->sculpt != NULL);
- const bool has_surface = ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT);
- const bool draw_surface = !((ob->dt < OB_WIRE) || (!renderable && (ob->dt != OB_WIRE)));
+ const bool has_surface = ELEM(
+ ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL, OB_FONT, OB_GPENCIL);
+ const bool draw_surface = (ob->dt >= OB_WIRE) && (renderable || (ob->dt == OB_WIRE));
const bool draw_facing = draw_surface && (pd->overlay.flag & V3D_OVERLAY_FACE_ORIENTATION);
const bool draw_bones = (pd->overlay.flag & V3D_OVERLAY_HIDE_BONES) == 0;
const bool draw_wires = draw_surface && has_surface &&
@@ -429,6 +437,7 @@ static void OVERLAY_draw_scene(void *vedata)
OVERLAY_armature_draw(vedata);
OVERLAY_particle_draw(vedata);
OVERLAY_metaball_draw(vedata);
+ OVERLAY_gpencil_draw(vedata);
OVERLAY_extra_draw(vedata);
if (DRW_state_is_fbo()) {
@@ -491,6 +500,13 @@ static void OVERLAY_draw_scene(void *vedata)
case CTX_MODE_SCULPT:
OVERLAY_sculpt_draw(vedata);
break;
+ case CTX_MODE_EDIT_GPENCIL:
+ case CTX_MODE_PAINT_GPENCIL:
+ case CTX_MODE_SCULPT_GPENCIL:
+ case CTX_MODE_VERTEX_GPENCIL:
+ case CTX_MODE_WEIGHT_GPENCIL:
+ OVERLAY_edit_gpencil_draw(vedata);
+ break;
default:
break;
}
diff --git a/source/blender/draw/engines/overlay/overlay_extra.c b/source/blender/draw/engines/overlay/overlay_extra.c
index b40e95d538c..49f266291da 100644
--- a/source/blender/draw/engines/overlay/overlay_extra.c
+++ b/source/blender/draw/engines/overlay/overlay_extra.c
@@ -38,7 +38,7 @@
#include "DNA_camera_types.h"
#include "DNA_constraint_types.h"
-#include "DNA_gpencil_types.h"
+#include "DNA_curve_types.h"
#include "DNA_lightprobe_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meta_types.h"
@@ -1331,89 +1331,6 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name GPencil.
- * \{ */
-
-static void OVERLAY_gpencil_color_names(Object *ob)
-{
- if (ob->mode != OB_MODE_EDIT_GPENCIL) {
- return;
- }
-
- bGPdata *gpd = (bGPdata *)ob->data;
- if (gpd == NULL) {
- return;
- }
-
- const DRWContextState *draw_ctx = DRW_context_state_get();
- ViewLayer *view_layer = draw_ctx->view_layer;
- int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
- uchar color[4];
- /* Color Management: Exception here as texts are drawn in sRGB space directly. */
- UI_GetThemeColor3ubv(theme_id, color);
- color[3] = 255;
- struct DRWTextStore *dt = DRW_text_cache_ensure();
-
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- if (gpl->flag & GP_LAYER_HIDE) {
- continue;
- }
- bGPDframe *gpf = gpl->actframe;
- if (gpf == NULL) {
- continue;
- }
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
- if (ma == NULL) {
- continue;
- }
-
- MaterialGPencilStyle *gp_style = ma->gp_style;
- /* skip stroke if it doesn't have any valid data */
- if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
- continue;
- }
- /* check if the color is visible */
- if (gp_style->flag & GP_STYLE_COLOR_HIDE) {
- continue;
- }
-
- /* only if selected */
- if (gps->flag & GP_STROKE_SELECT) {
- float fpt[3];
- for (int i = 0; i < gps->totpoints; i++) {
- bGPDspoint *pt = &gps->points[i];
- if (pt->flag & GP_SPOINT_SELECT) {
- mul_v3_m4v3(fpt, ob->obmat, &pt->x);
- DRW_text_cache_add(dt,
- fpt,
- ma->id.name + 2,
- strlen(ma->id.name + 2),
- 10,
- 0,
- DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
- color);
- break;
- }
- }
- }
- }
- }
-}
-
-void OVERLAY_gpencil_cache_populate(OVERLAY_Data *UNUSED(vedata), Object *ob)
-{
- /* don't show object extras in set's */
- if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
- if ((ob->dtx & OB_DRAWNAME) && DRW_state_show_text()) {
- OVERLAY_gpencil_color_names(ob);
- }
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Volumetric / Smoke sim
* \{ */
diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.c b/source/blender/draw/engines/overlay/overlay_gpencil.c
new file mode 100644
index 00000000000..c96c448c63b
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_gpencil.c
@@ -0,0 +1,391 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2020, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BKE_gpencil.h"
+
+#include "UI_resources.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "ED_view3d.h"
+
+#include "overlay_private.h"
+
+#include "draw_common.h"
+#include "draw_manager_text.h"
+
+void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ /* Default: Display nothing. */
+ pd->edit_gpencil_points_grp = NULL;
+ pd->edit_gpencil_wires_grp = NULL;
+ psl->edit_gpencil_ps = NULL;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+
+ if (gpd == NULL || ob->type != OB_GPENCIL) {
+ return;
+ }
+
+ /* For sculpt show only if mask mode, and only points if not stroke mode. */
+ const bool use_sculpt_mask = (GPENCIL_SCULPT_MODE(gpd) &&
+ GPENCIL_ANY_SCULPT_MASK(ts->gpencil_selectmode_sculpt));
+ const bool show_sculpt_points = (GPENCIL_SCULPT_MODE(gpd) &&
+ (ts->gpencil_selectmode_sculpt &
+ (GP_SCULPT_MASK_SELECTMODE_POINT |
+ GP_SCULPT_MASK_SELECTMODE_SEGMENT)));
+
+ /* For vertex paint show only if mask mode, and only points if not stroke mode. */
+ bool use_vertex_mask = (GPENCIL_VERTEX_MODE(gpd) &&
+ GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex));
+ const bool show_vertex_points = (GPENCIL_VERTEX_MODE(gpd) &&
+ (ts->gpencil_selectmode_vertex &
+ (GP_VERTEX_MASK_SELECTMODE_POINT |
+ GP_VERTEX_MASK_SELECTMODE_SEGMENT)));
+
+ /* If Sculpt or Vertex mode and the mask is disabled, the select must be hidden. */
+ const bool hide_select = ((GPENCIL_SCULPT_MODE(gpd) && !use_sculpt_mask) ||
+ (GPENCIL_VERTEX_MODE(gpd) && !use_vertex_mask));
+
+ const bool do_multiedit = GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool show_multi_edit_lines = (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0;
+
+ const bool show_lines = (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) || show_multi_edit_lines;
+
+ const bool hide_lines = !GPENCIL_EDIT_MODE(gpd) && !GPENCIL_WEIGHT_MODE(gpd) &&
+ !use_sculpt_mask && !use_vertex_mask && !show_lines;
+
+ /* Special case when vertex paint and multiedit lines. */
+ if (do_multiedit && show_multi_edit_lines && GPENCIL_VERTEX_MODE(gpd)) {
+ use_vertex_mask = true;
+ }
+
+ const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE);
+
+ /* Show Edit points if:
+ * Edit mode: Not in Stroke selection mode
+ * Sculpt mode: If use Mask and not Stroke mode
+ * Weight mode: Always
+ * Vertex mode: If use Mask and not Stroke mode
+ */
+ const bool show_points = show_sculpt_points || is_weight_paint || show_vertex_points ||
+ (GPENCIL_EDIT_MODE(gpd) &&
+ (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
+
+ if ((!GPENCIL_VERTEX_MODE(gpd) && !GPENCIL_PAINT_MODE(gpd)) || use_vertex_mask) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
+ DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->edit_gpencil_ps, state | pd->clipping_state);
+
+ if (show_lines && !hide_lines) {
+ sh = OVERLAY_shader_edit_gpencil_wire();
+ pd->edit_gpencil_wires_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", show_multi_edit_lines);
+ DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint);
+ DRW_shgroup_uniform_bool_copy(grp, "hideSelect", hide_select);
+ DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+ }
+
+ if (show_points && !hide_select) {
+ sh = OVERLAY_shader_edit_gpencil_point();
+ pd->edit_gpencil_points_grp = grp = DRW_shgroup_create(sh, psl->edit_gpencil_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_bool_copy(grp, "doMultiframe", do_multiedit);
+ DRW_shgroup_uniform_bool_copy(grp, "doWeightColor", is_weight_paint);
+ DRW_shgroup_uniform_float_copy(grp, "gpEditOpacity", v3d->vertex_opacity);
+ DRW_shgroup_uniform_texture(grp, "weightTex", G_draw.weight_ramp);
+ }
+ }
+
+ /* control points for primitives and speed guide */
+ const bool is_cppoint = (gpd->runtime.tot_cp_points > 0);
+ const bool is_speed_guide = (ts->gp_sculpt.guide.use_guide &&
+ (draw_ctx->object_mode == OB_MODE_PAINT_GPENCIL));
+ const bool is_show_gizmo = (((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0) &&
+ ((v3d->gizmo_flag & V3D_GIZMO_HIDE_TOOL) == 0));
+
+ if ((is_cppoint || is_speed_guide) && (is_show_gizmo)) {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->edit_gpencil_gizmos_ps, state);
+
+ sh = OVERLAY_shader_edit_gpencil_guide_point();
+ grp = DRW_shgroup_create(sh, psl->edit_gpencil_gizmos_ps);
+
+ if (gpd->runtime.cp_points != NULL) {
+ for (int i = 0; i < gpd->runtime.tot_cp_points; i++) {
+ bGPDcontrolpoint *cp = &gpd->runtime.cp_points[i];
+ grp = DRW_shgroup_create_sub(grp);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", &cp->x);
+ DRW_shgroup_uniform_float_copy(grp, "pSize", cp->size * 0.8f * G_draw.block.sizePixel);
+ DRW_shgroup_uniform_vec4_copy(grp, "pColor", cp->color);
+ DRW_shgroup_call_procedural_points(grp, NULL, 1);
+ }
+ }
+
+ if (ts->gp_sculpt.guide.use_guide) {
+ float color[4];
+ if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_CUSTOM) {
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.location);
+ }
+ else if (ts->gp_sculpt.guide.reference_point == GP_GUIDE_REF_OBJECT &&
+ ts->gp_sculpt.guide.reference_object != NULL) {
+ UI_GetThemeColor4fv(TH_GIZMO_SECONDARY, color);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", ts->gp_sculpt.guide.reference_object->loc);
+ }
+ else {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ DRW_shgroup_uniform_vec3_copy(grp, "pPosition", scene->cursor.location);
+ }
+ DRW_shgroup_uniform_vec4_copy(grp, "pColor", color);
+ DRW_shgroup_uniform_float_copy(grp, "pSize", 8.0f * G_draw.block.sizePixel);
+ DRW_shgroup_call_procedural_points(grp, NULL, 1);
+ }
+ }
+}
+
+void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ struct GPUShader *sh;
+ DRWShadingGroup *grp;
+
+ /* Default: Display nothing. */
+ psl->gpencil_canvas_ps = NULL;
+
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+ Object *ob = draw_ctx->obact;
+ bGPdata *gpd = ob ? (bGPdata *)ob->data : NULL;
+ Scene *scene = draw_ctx->scene;
+ ToolSettings *ts = scene->toolsettings;
+ const View3DCursor *cursor = &scene->cursor;
+
+ if (gpd == NULL || ob->type != OB_GPENCIL) {
+ return;
+ }
+
+ const bool show_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
+ const bool show_grid = (v3d->gp_flag & V3D_GP_SHOW_GRID) != 0;
+
+ if (show_grid && show_overlays) {
+ const char *grid_unit = NULL;
+ float mat[4][4];
+ float col_grid[4];
+ float size[2];
+
+ /* set color */
+ copy_v3_v3(col_grid, gpd->grid.color);
+ col_grid[3] = max_ff(v3d->overlay.gpencil_grid_opacity, 0.01f);
+
+ copy_m4_m4(mat, ob->obmat);
+
+ float viewinv[4][4];
+ /* Set the grid in the selected axis */
+ switch (ts->gp_sculpt.lock_axis) {
+ case GP_LOCKAXIS_X:
+ swap_v4_v4(mat[0], mat[2]);
+ break;
+ case GP_LOCKAXIS_Y:
+ swap_v4_v4(mat[1], mat[2]);
+ break;
+ case GP_LOCKAXIS_Z:
+ /* Default. */
+ break;
+ case GP_LOCKAXIS_CURSOR:
+ loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, (float[3]){1, 1, 1});
+ break;
+ case GP_LOCKAXIS_VIEW:
+ /* view aligned */
+ DRW_view_viewmat_get(NULL, viewinv, true);
+ copy_v3_v3(mat[0], viewinv[0]);
+ copy_v3_v3(mat[1], viewinv[1]);
+ break;
+ }
+
+ translate_m4(mat, gpd->grid.offset[0], gpd->grid.offset[1], 0.0f);
+ mul_v2_v2fl(size, gpd->grid.scale, 2.0f * ED_scene_grid_scale(scene, &grid_unit));
+ rescale_m4(mat, (float[3]){size[0], size[1], 0.0f});
+
+ const int gridlines = (gpd->grid.lines <= 0) ? 1 : gpd->grid.lines;
+ int line_ct = gridlines * 4 + 2;
+
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_ALPHA;
+ DRW_PASS_CREATE(psl->gpencil_canvas_ps, state);
+
+ sh = OVERLAY_shader_gpencil_canvas();
+ grp = DRW_shgroup_create(sh, psl->gpencil_canvas_ps);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_uniform_vec4_copy(grp, "color", col_grid);
+ DRW_shgroup_uniform_vec3_copy(grp, "xAxis", mat[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "yAxis", mat[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "origin", mat[3]);
+ DRW_shgroup_uniform_int_copy(grp, "halfLineCount", line_ct / 2);
+ DRW_shgroup_call_procedural_lines(grp, NULL, line_ct);
+ }
+}
+
+static void OVERLAY_edit_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ bGPdata *gpd = (bGPdata *)ob->data;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ if (pd->edit_gpencil_wires_grp) {
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_wires_grp);
+ DRW_shgroup_uniform_vec4_copy(grp, "gpEditColor", gpd->line_color);
+
+ struct GPUBatch *geom = DRW_cache_gpencil_edit_lines_get(ob, pd->cfra);
+ DRW_shgroup_call_no_cull(pd->edit_gpencil_wires_grp, geom, ob);
+ }
+
+ if (pd->edit_gpencil_points_grp) {
+ const bool show_direction = (v3d->gp_flag & V3D_GP_SHOW_STROKE_DIRECTION) != 0;
+
+ DRWShadingGroup *grp = DRW_shgroup_create_sub(pd->edit_gpencil_points_grp);
+ DRW_shgroup_uniform_float_copy(grp, "doStrokeEndpoints", show_direction);
+
+ struct GPUBatch *geom = DRW_cache_gpencil_edit_points_get(ob, pd->cfra);
+ DRW_shgroup_call_no_cull(grp, geom, ob);
+ }
+}
+
+static void overlay_gpencil_draw_stroke_color_name(bGPDlayer *UNUSED(gpl),
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ void *thunk)
+{
+ Object *ob = (Object *)thunk;
+ Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
+ if (ma == NULL) {
+ return;
+ }
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ /* skip stroke if it doesn't have any valid data */
+ if ((gps->points == NULL) || (gps->totpoints < 1) || (gp_style == NULL)) {
+ return;
+ }
+ /* check if the color is visible */
+ if (gp_style->flag & GP_MATERIAL_HIDE) {
+ return;
+ }
+ /* only if selected */
+ if (gps->flag & GP_STROKE_SELECT) {
+ for (int i = 0; i < gps->totpoints; i++) {
+ bGPDspoint *pt = &gps->points[i];
+ /* Draw name at the first selected point. */
+ if (pt->flag & GP_SPOINT_SELECT) {
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+ uchar color[4];
+ UI_GetThemeColor4ubv(theme_id, color);
+
+ float fpt[3];
+ mul_v3_m4v3(fpt, ob->obmat, &pt->x);
+
+ struct DRWTextStore *dt = DRW_text_cache_ensure();
+ DRW_text_cache_add(dt,
+ fpt,
+ ma->id.name + 2,
+ strlen(ma->id.name + 2),
+ 10,
+ 0,
+ DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_STRING_PTR,
+ color);
+ break;
+ }
+ }
+ }
+}
+
+static void OVERLAY_gpencil_color_names(Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ int cfra = DEG_get_ctime(draw_ctx->depsgraph);
+
+ BKE_gpencil_visible_stroke_iter(
+ ob, NULL, overlay_gpencil_draw_stroke_color_name, ob, false, cfra);
+}
+
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ View3D *v3d = draw_ctx->v3d;
+
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd == NULL) {
+ return;
+ }
+
+ if (GPENCIL_ANY_MODE(gpd)) {
+ OVERLAY_edit_gpencil_cache_populate(vedata, ob);
+ }
+
+ /* don't show object extras in set's */
+ if ((ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) == 0) {
+ if ((v3d->gp_flag & V3D_GP_SHOW_MATERIAL_NAME) && (ob->mode == OB_MODE_EDIT_GPENCIL) &&
+ DRW_state_show_text()) {
+ OVERLAY_gpencil_color_names(ob);
+ }
+ }
+}
+
+void OVERLAY_gpencil_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->gpencil_canvas_ps) {
+ DRW_draw_pass(psl->gpencil_canvas_ps);
+ }
+}
+
+void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+
+ if (psl->edit_gpencil_gizmos_ps) {
+ DRW_draw_pass(psl->edit_gpencil_gizmos_ps);
+ }
+
+ if (psl->edit_gpencil_ps) {
+ DRW_draw_pass(psl->edit_gpencil_ps);
+ }
+}
diff --git a/source/blender/draw/engines/overlay/overlay_motion_path.c b/source/blender/draw/engines/overlay/overlay_motion_path.c
index 555e0084c49..29eb4fd12a4 100644
--- a/source/blender/draw/engines/overlay/overlay_motion_path.c
+++ b/source/blender/draw/engines/overlay/overlay_motion_path.c
@@ -155,7 +155,7 @@ static void motion_path_cache(OVERLAY_Data *vedata,
DRW_shgroup_uniform_bool_copy(grp, "selected", selected);
DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
/* Only draw the required range. */
- DRW_shgroup_call_range(grp, mpath_batch_line_get(mpath), start_index, len);
+ DRW_shgroup_call_range(grp, NULL, mpath_batch_line_get(mpath), start_index, len);
}
/* Draw points. */
@@ -167,7 +167,7 @@ static void motion_path_cache(OVERLAY_Data *vedata,
DRW_shgroup_uniform_bool_copy(grp, "showKeyFrames", show_keyframes);
DRW_shgroup_uniform_vec3_copy(grp, "customColor", color);
/* Only draw the required range. */
- DRW_shgroup_call_range(grp, mpath_batch_points_get(mpath), start_index, len);
+ DRW_shgroup_call_range(grp, NULL, mpath_batch_points_get(mpath), start_index, len);
}
/* Draw frame numbers at each frame-step value. */
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
index 63738b3c214..e77a0a143a9 100644
--- a/source/blender/draw/engines/overlay/overlay_outline.c
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -23,13 +23,67 @@
#include "DRW_render.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
-#include "DNA_lightprobe_types.h"
+#include "BKE_object.h"
+
+#include "DNA_gpencil_types.h"
#include "UI_resources.h"
#include "overlay_private.h"
+/* Returns the normal plane in ndc space. */
+static void gpencil_depth_plane(Object *ob, float r_plane[4])
+{
+ /* TODO put that into private data. */
+ float viewinv[4][4];
+ DRW_view_viewmat_get(NULL, viewinv, true);
+ float *camera_z_axis = viewinv[2];
+ float *camera_pos = viewinv[3];
+
+ /* Find the normal most likely to represent the gpObject. */
+ /* TODO: This does not work quite well if you use
+ * strokes not aligned with the object axes. Maybe we could try to
+ * compute the minimum axis of all strokes. But this would be more
+ * computationaly heavy and should go into the GPData evaluation. */
+ BoundBox *bbox = BKE_object_boundbox_get(ob);
+ /* Convert bbox to matrix */
+ float mat[4][4], size[3], center[3];
+ BKE_boundbox_calc_size_aabb(bbox, size);
+ BKE_boundbox_calc_center_aabb(bbox, center);
+ unit_m4(mat);
+ copy_v3_v3(mat[3], center);
+ /* Avoid division by 0.0 later. */
+ add_v3_fl(size, 1e-8f);
+ rescale_m4(mat, size);
+ /* BBox space to World. */
+ mul_m4_m4m4(mat, ob->obmat, mat);
+ /* BBox center in world space. */
+ copy_v3_v3(center, mat[3]);
+ /* View Vector. */
+ if (DRW_view_is_persp_get(NULL)) {
+ /* BBox center to camera vector. */
+ sub_v3_v3v3(r_plane, camera_pos, mat[3]);
+ }
+ else {
+ copy_v3_v3(r_plane, camera_z_axis);
+ }
+ /* World to BBox space. */
+ invert_m4(mat);
+ /* Normalize the vector in BBox space. */
+ mul_mat3_m4_v3(mat, r_plane);
+ normalize_v3(r_plane);
+
+ transpose_m4(mat);
+ /* mat is now a "normal" matrix which will transform
+ * BBox space normal to world space. */
+ mul_mat3_m4_v3(mat, r_plane);
+ normalize_v3(r_plane);
+
+ plane_from_point_normal_v3(r_plane, center, r_plane);
+}
+
void OVERLAY_outline_init(OVERLAY_Data *vedata)
{
OVERLAY_FramebufferList *fbl = vedata->fbl;
@@ -79,6 +133,11 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
pd->outlines_grp = grp = DRW_shgroup_create(sh_geom, psl->outlines_prepass_ps);
DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
+
+ GPUShader *sh_gpencil = OVERLAY_shader_outline_prepass_gpencil();
+
+ pd->outlines_gpencil_grp = grp = DRW_shgroup_create(sh_gpencil, psl->outlines_prepass_ps);
+ DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0);
}
/* outlines_prepass_ps is still needed for selection of probes. */
@@ -107,6 +166,98 @@ void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
}
}
+typedef struct iterData {
+ Object *ob;
+ DRWShadingGroup *stroke_grp;
+ DRWShadingGroup *fill_grp;
+ int cfra;
+ float plane[4];
+} iterData;
+
+static void gp_layer_cache_populate(bGPDlayer *gpl,
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *UNUSED(gps),
+ void *thunk)
+{
+ iterData *iter = (iterData *)thunk;
+ bGPdata *gpd = (bGPdata *)iter->ob->data;
+
+ const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
+ const bool is_stroke_order_3d = (gpd->draw_mode == GP_DRAWMODE_3D);
+
+ float object_scale = mat4_to_scale(iter->ob->obmat);
+ /* Negate thickness sign to tag that strokes are in screen space.
+ * Convert to world units (by default, 1 meter = 2000 px). */
+ float thickness_scale = (is_screenspace) ? -1.0f : (gpd->pixfactor / 2000.0f);
+
+ DRWShadingGroup *grp = iter->stroke_grp = DRW_shgroup_create_sub(iter->stroke_grp);
+ DRW_shgroup_uniform_bool_copy(grp, "strokeOrder3d", is_stroke_order_3d);
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewportInv", DRW_viewport_invert_size_get());
+ DRW_shgroup_uniform_vec2_copy(grp, "sizeViewport", DRW_viewport_size_get());
+ DRW_shgroup_uniform_float_copy(grp, "thicknessScale", object_scale);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessOffset", (float)gpl->line_change);
+ DRW_shgroup_uniform_float_copy(grp, "thicknessWorldScale", thickness_scale);
+ DRW_shgroup_uniform_vec4_copy(grp, "gpDepthPlane", iter->plane);
+}
+
+static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
+ bGPDframe *UNUSED(gpf),
+ bGPDstroke *gps,
+ void *thunk)
+{
+ iterData *iter = (iterData *)thunk;
+
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(iter->ob, gps->mat_nr + 1);
+
+ bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
+ bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
+ // TODO: What about simplify Fill?
+ bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
+
+ if (hide_material) {
+ return;
+ }
+
+ if (show_fill) {
+ struct GPUBatch *geom = DRW_cache_gpencil_fills_get(iter->ob, iter->cfra);
+ int vfirst = gps->runtime.fill_start * 3;
+ int vcount = gps->tot_triangles * 3;
+ DRW_shgroup_call_range(iter->fill_grp, iter->ob, geom, vfirst, vcount);
+ }
+
+ if (show_stroke) {
+ struct GPUBatch *geom = DRW_cache_gpencil_strokes_get(iter->ob, iter->cfra);
+ /* Start one vert before to have gl_InstanceID > 0 (see shader). */
+ int vfirst = gps->runtime.stroke_start - 1;
+ /* Include "potential" cyclic vertex and start adj vertex (see shader). */
+ int vcount = gps->totpoints + 1 + 1;
+ DRW_shgroup_call_instance_range(iter->stroke_grp, iter->ob, geom, vfirst, vcount);
+ }
+}
+
+static void OVERLAY_outline_gpencil(OVERLAY_PrivateData *pd, Object *ob)
+{
+ /* No outlines in edit mode. */
+ bGPdata *gpd = (bGPdata *)ob->data;
+ if (gpd && GPENCIL_ANY_MODE(gpd)) {
+ return;
+ }
+
+ iterData iter = {
+ .ob = ob,
+ .stroke_grp = pd->outlines_gpencil_grp,
+ .fill_grp = DRW_shgroup_create_sub(pd->outlines_gpencil_grp),
+ .cfra = pd->cfra,
+ };
+
+ if (gpd->draw_mode == GP_DRAWMODE_2D) {
+ gpencil_depth_plane(ob, iter.plane);
+ }
+
+ BKE_gpencil_visible_stroke_iter(
+ ob, gp_layer_cache_populate, gp_stroke_cache_populate, &iter, false, pd->cfra);
+}
+
void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
Object *ob,
OVERLAY_DupliData *dupli,
@@ -123,6 +274,11 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
return;
}
+ if (ob->type == OB_GPENCIL) {
+ OVERLAY_outline_gpencil(pd, ob);
+ return;
+ }
+
if (dupli && !init_dupli) {
geom = dupli->outline_geom;
shgroup = dupli->outline_shgrp;
diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h
index 185df723301..167a8e940df 100644
--- a/source/blender/draw/engines/overlay/overlay_private.h
+++ b/source/blender/draw/engines/overlay/overlay_private.h
@@ -60,6 +60,8 @@ typedef struct OVERLAY_PassList {
DRWPass *clipping_frustum_ps;
DRWPass *edit_curve_wire_ps[2];
DRWPass *edit_curve_handle_ps;
+ DRWPass *edit_gpencil_ps;
+ DRWPass *edit_gpencil_gizmos_ps;
DRWPass *edit_lattice_ps;
DRWPass *edit_mesh_depth_ps[2];
DRWPass *edit_mesh_verts_ps[2];
@@ -76,6 +78,7 @@ typedef struct OVERLAY_PassList {
DRWPass *extra_blend_ps;
DRWPass *extra_centers_ps;
DRWPass *extra_grid_ps;
+ DRWPass *gpencil_canvas_ps;
DRWPass *facing_ps;
DRWPass *grid_ps;
DRWPass *image_background_ps;
@@ -219,6 +222,8 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *edit_curve_points_grp;
DRWShadingGroup *edit_lattice_points_grp;
DRWShadingGroup *edit_lattice_wires_grp;
+ DRWShadingGroup *edit_gpencil_points_grp;
+ DRWShadingGroup *edit_gpencil_wires_grp;
DRWShadingGroup *edit_mesh_depth_grp[2];
DRWShadingGroup *edit_mesh_faces_grp[2];
DRWShadingGroup *edit_mesh_faces_cage_grp[2];
@@ -238,6 +243,7 @@ typedef struct OVERLAY_PrivateData {
DRWShadingGroup *motion_path_lines_grp;
DRWShadingGroup *motion_path_points_grp;
DRWShadingGroup *outlines_grp;
+ DRWShadingGroup *outlines_gpencil_grp;
DRWShadingGroup *paint_surf_grp;
DRWShadingGroup *paint_wire_grp;
DRWShadingGroup *paint_wire_selected_grp;
@@ -277,6 +283,7 @@ typedef struct OVERLAY_PrivateData {
float xray_opacity;
short v3d_flag; /* TODO move to View3DOverlay */
short v3d_gridflag; /* TODO move to View3DOverlay */
+ int cfra;
DRWState clipping_state;
OVERLAY_ShadingData shdata;
@@ -419,6 +426,12 @@ void OVERLAY_edit_curve_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_edit_surf_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_edit_curve_draw(OVERLAY_Data *vedata);
+void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata);
+void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
+void OVERLAY_gpencil_draw(OVERLAY_Data *vedata);
+void OVERLAY_edit_gpencil_draw(OVERLAY_Data *vedata);
+
void OVERLAY_edit_lattice_cache_init(OVERLAY_Data *vedata);
void OVERLAY_edit_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_lattice_cache_populate(OVERLAY_Data *vedata, Object *ob);
@@ -446,7 +459,6 @@ void OVERLAY_extra_centers_draw(OVERLAY_Data *vedata);
void OVERLAY_camera_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_empty_cache_populate(OVERLAY_Data *vedata, Object *ob);
-void OVERLAY_gpencil_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_light_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_lightprobe_cache_populate(OVERLAY_Data *vedata, Object *ob);
void OVERLAY_speaker_cache_populate(OVERLAY_Data *vedata, Object *ob);
@@ -547,6 +559,9 @@ GPUShader *OVERLAY_shader_depth_only(void);
GPUShader *OVERLAY_shader_edit_curve_handle(void);
GPUShader *OVERLAY_shader_edit_curve_point(void);
GPUShader *OVERLAY_shader_edit_curve_wire(void);
+GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void);
+GPUShader *OVERLAY_shader_edit_gpencil_point(void);
+GPUShader *OVERLAY_shader_edit_gpencil_wire(void);
GPUShader *OVERLAY_shader_edit_lattice_point(void);
GPUShader *OVERLAY_shader_edit_lattice_wire(void);
GPUShader *OVERLAY_shader_edit_mesh_analysis(void);
@@ -564,12 +579,14 @@ GPUShader *OVERLAY_shader_extra_wire(bool use_object);
GPUShader *OVERLAY_shader_extra_loose_point(void);
GPUShader *OVERLAY_shader_extra_point(void);
GPUShader *OVERLAY_shader_facing(void);
+GPUShader *OVERLAY_shader_gpencil_canvas(void);
GPUShader *OVERLAY_shader_grid(void);
GPUShader *OVERLAY_shader_image(void);
GPUShader *OVERLAY_shader_motion_path_line(void);
GPUShader *OVERLAY_shader_motion_path_vert(void);
GPUShader *OVERLAY_shader_uniform_color(void);
GPUShader *OVERLAY_shader_outline_prepass(bool use_wire);
+GPUShader *OVERLAY_shader_outline_prepass_gpencil(void);
GPUShader *OVERLAY_shader_extra_grid(void);
GPUShader *OVERLAY_shader_outline_detect(void);
GPUShader *OVERLAY_shader_paint_face(void);
diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c
index d33ef239198..86d5f58957e 100644
--- a/source/blender/draw/engines/overlay/overlay_shader.c
+++ b/source/blender/draw/engines/overlay/overlay_shader.c
@@ -54,6 +54,9 @@ extern char datatoc_edit_curve_handle_geom_glsl[];
extern char datatoc_edit_curve_handle_vert_glsl[];
extern char datatoc_edit_curve_point_vert_glsl[];
extern char datatoc_edit_curve_wire_vert_glsl[];
+extern char datatoc_edit_gpencil_canvas_vert_glsl[];
+extern char datatoc_edit_gpencil_guide_vert_glsl[];
+extern char datatoc_edit_gpencil_vert_glsl[];
extern char datatoc_edit_lattice_point_vert_glsl[];
extern char datatoc_edit_lattice_wire_vert_glsl[];
extern char datatoc_edit_mesh_common_lib_glsl[];
@@ -113,6 +116,8 @@ extern char datatoc_gpu_shader_flat_color_frag_glsl[];
extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[];
extern char datatoc_gpu_shader_common_obinfos_lib_glsl[];
+extern char datatoc_gpencil_common_lib_glsl[];
+
extern char datatoc_common_colormanagement_lib_glsl[];
extern char datatoc_common_fullscreen_vert_glsl[];
extern char datatoc_common_fxaa_lib_glsl[];
@@ -138,6 +143,9 @@ typedef struct OVERLAY_Shaders {
GPUShader *edit_curve_handle;
GPUShader *edit_curve_point;
GPUShader *edit_curve_wire;
+ GPUShader *edit_gpencil_guide_point;
+ GPUShader *edit_gpencil_point;
+ GPUShader *edit_gpencil_wire;
GPUShader *edit_lattice_point;
GPUShader *edit_lattice_wire;
GPUShader *edit_mesh_vert;
@@ -159,11 +167,13 @@ typedef struct OVERLAY_Shaders {
GPUShader *extra_lightprobe_grid;
GPUShader *extra_loose_point;
GPUShader *facing;
+ GPUShader *gpencil_canvas;
GPUShader *grid;
GPUShader *image;
GPUShader *motion_path_line;
GPUShader *motion_path_vert;
GPUShader *outline_prepass;
+ GPUShader *outline_prepass_gpencil;
GPUShader *outline_prepass_wire;
GPUShader *outline_detect;
GPUShader *paint_face;
@@ -557,6 +567,58 @@ GPUShader *OVERLAY_shader_edit_curve_wire(void)
return sh_data->edit_curve_wire;
}
+GPUShader *OVERLAY_shader_edit_gpencil_guide_point(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->edit_gpencil_guide_point) {
+ sh_data->edit_gpencil_guide_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_guide_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ });
+ }
+ return sh_data->edit_gpencil_guide_point;
+}
+
+GPUShader *OVERLAY_shader_edit_gpencil_point(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_gpencil_point) {
+ sh_data->edit_gpencil_point = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_point_varying_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, "#define USE_POINTS\n", NULL},
+ });
+ }
+ return sh_data->edit_gpencil_point;
+}
+
+GPUShader *OVERLAY_shader_edit_gpencil_wire(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->edit_gpencil_wire) {
+ sh_data->edit_gpencil_wire = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_gpu_shader_3D_smooth_color_frag_glsl, NULL},
+ .defs = (const char *[]){sh_cfg->def, NULL},
+ });
+ }
+ return sh_data->edit_gpencil_wire;
+}
+
GPUShader *OVERLAY_shader_edit_lattice_point(void)
{
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -883,6 +945,21 @@ GPUShader *OVERLAY_shader_facing(void)
return sh_data->facing;
}
+GPUShader *OVERLAY_shader_gpencil_canvas(void)
+{
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
+ if (!sh_data->gpencil_canvas) {
+ sh_data->gpencil_canvas = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){datatoc_common_globals_lib_glsl,
+ datatoc_common_view_lib_glsl,
+ datatoc_edit_gpencil_canvas_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl, datatoc_extra_frag_glsl, NULL},
+ });
+ }
+ return sh_data->gpencil_canvas;
+}
+
GPUShader *OVERLAY_shader_grid(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
@@ -998,6 +1075,32 @@ GPUShader *OVERLAY_shader_outline_prepass(bool use_wire)
return use_wire ? sh_data->outline_prepass_wire : sh_data->outline_prepass;
}
+GPUShader *OVERLAY_shader_outline_prepass_gpencil(void)
+{
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg];
+ OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg];
+ if (!sh_data->outline_prepass_gpencil) {
+ sh_data->outline_prepass_gpencil = GPU_shader_create_from_arrays({
+ .vert = (const char *[]){sh_cfg->lib,
+ datatoc_common_view_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_gpu_shader_common_obinfos_lib_glsl,
+ datatoc_outline_prepass_vert_glsl,
+ NULL},
+ .frag = (const char *[]){datatoc_common_view_lib_glsl,
+ datatoc_gpencil_common_lib_glsl,
+ datatoc_outline_prepass_frag_glsl,
+ NULL},
+ .defs = (const char *[]){sh_cfg->def,
+ "#define USE_GPENCIL\n",
+ "#define UNIFORM_RESOURCE_ID\n",
+ NULL},
+ });
+ }
+ return sh_data->outline_prepass_gpencil;
+}
+
GPUShader *OVERLAY_shader_outline_detect(void)
{
OVERLAY_Shaders *sh_data = &e_data.sh_data[0];
diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c
index 5dbdc71dae1..4df9faace18 100644
--- a/source/blender/draw/engines/overlay/overlay_wireframe.c
+++ b/source/blender/draw/engines/overlay/overlay_wireframe.c
@@ -201,7 +201,11 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata,
shgrp = pd->wires_grp[is_xray][use_coloring];
}
- if (use_sculpt_pbvh) {
+ if (ob->type == OB_GPENCIL) {
+ /* TODO (fclem) Make GPencil objects have correct boundbox. */
+ DRW_shgroup_call_no_cull(shgrp, geom, ob);
+ }
+ else if (use_sculpt_pbvh) {
DRW_shgroup_call_sculpt(shgrp, ob, true, false, false);
}
else {
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
new file mode 100644
index 00000000000..5aa7fe78e4e
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_canvas_vert.glsl
@@ -0,0 +1,35 @@
+
+uniform vec4 color;
+uniform vec3 xAxis;
+uniform vec3 yAxis;
+uniform vec3 origin;
+uniform int halfLineCount;
+
+flat out vec4 finalColor;
+flat out vec2 edgeStart;
+noperspective out vec2 edgePos;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec2 pos;
+ pos.x = float(gl_VertexID % 2);
+ pos.y = float(gl_VertexID / 2) / float(halfLineCount - 1);
+
+ if (pos.y > 1.0) {
+ pos.xy = pos.yx;
+ pos.x -= 1.0 + 1.0 / float(halfLineCount - 1);
+ }
+
+ pos -= 0.5;
+
+ vec3 world_pos = xAxis * pos.x + yAxis * pos.y + origin;
+
+ gl_Position = point_world_to_ndc(world_pos);
+
+ finalColor = color;
+
+ /* Convert to screen position [0..sizeVp]. */
+ edgePos = edgeStart = ((gl_Position.xy / gl_Position.w) * 0.5 + 0.5) * sizeViewport.xy;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl
new file mode 100644
index 00000000000..ef68b0f4e6f
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_guide_vert.glsl
@@ -0,0 +1,14 @@
+uniform vec4 pColor;
+uniform float pSize;
+uniform vec3 pPosition;
+
+out vec4 finalColor;
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ gl_Position = point_world_to_ndc(pPosition);
+ finalColor = pColor;
+ gl_PointSize = pSize;
+}
diff --git a/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
new file mode 100644
index 00000000000..cb03ad44615
--- /dev/null
+++ b/source/blender/draw/engines/overlay/shaders/edit_gpencil_vert.glsl
@@ -0,0 +1,103 @@
+
+uniform float normalSize;
+uniform bool doMultiframe;
+uniform bool doStrokeEndpoints;
+uniform bool hideSelect;
+uniform bool doWeightColor;
+uniform float gpEditOpacity;
+uniform vec4 gpEditColor;
+uniform sampler1D weightTex;
+
+in vec3 pos;
+in float ma;
+in uint vflag;
+in float weight;
+
+out vec4 finalColor;
+
+void discard_vert()
+{
+ /* We set the vertex at the camera origin to generate 0 fragments. */
+ gl_Position = vec4(0.0, 0.0, -3e36, 0.0);
+}
+
+#define GP_EDIT_POINT_SELECTED (1u << 0u)
+#define GP_EDIT_STROKE_SELECTED (1u << 1u)
+#define GP_EDIT_MULTIFRAME (1u << 2u)
+#define GP_EDIT_STROKE_START (1u << 3u)
+#define GP_EDIT_STROKE_END (1u << 4u)
+
+#ifdef USE_POINTS
+# define colorUnselect colorGpencilVertex
+# define colorSelect colorGpencilVertexSelect
+#else
+# define colorUnselect gpEditColor
+# define colorSelect (hideSelect ? colorUnselect : colorGpencilVertexSelect)
+#endif
+
+vec3 weight_to_rgb(float t)
+{
+ if (t < 0.0) {
+ /* No weight */
+ return colorUnselect.rgb;
+ }
+ else if (t > 1.0) {
+ /* Error color */
+ return vec3(1.0, 0.0, 1.0);
+ }
+ else {
+ return texture(weightTex, t).rgb;
+ }
+}
+
+void main()
+{
+ GPU_INTEL_VERTEX_SHADER_WORKAROUND
+
+ vec3 world_pos = point_object_to_world(pos);
+ gl_Position = point_world_to_ndc(world_pos);
+
+ bool is_multiframe = (vflag & GP_EDIT_MULTIFRAME) != 0u;
+ bool is_stroke_sel = (vflag & GP_EDIT_STROKE_SELECTED) != 0u;
+ bool is_point_sel = (vflag & GP_EDIT_POINT_SELECTED) != 0u;
+
+ if (doWeightColor) {
+ finalColor.rgb = weight_to_rgb(weight);
+ finalColor.a = gpEditOpacity;
+ }
+ else {
+ finalColor = (is_point_sel) ? colorSelect : colorUnselect;
+ finalColor.a *= gpEditOpacity;
+ }
+
+#ifdef USE_POINTS
+ gl_PointSize = sizeVertex * 2.0;
+
+ if (doStrokeEndpoints && !doWeightColor) {
+ bool is_stroke_start = (vflag & GP_EDIT_STROKE_START) != 0u;
+ bool is_stroke_end = (vflag & GP_EDIT_STROKE_END) != 0u;
+
+ if (is_stroke_start) {
+ gl_PointSize *= 2.0;
+ finalColor.rgb = vec3(0.0, 1.0, 0.0);
+ }
+ else if (is_stroke_end) {
+ gl_PointSize *= 1.5;
+ finalColor.rgb = vec3(1.0, 0.0, 0.0);
+ }
+ }
+
+ if ((!is_stroke_sel && !doWeightColor) || (!doMultiframe && is_multiframe)) {
+ discard_vert();
+ }
+#endif
+
+ /* Discard unwanted padding vertices. */
+ if (ma == -1.0 || (is_multiframe && !doMultiframe)) {
+ discard_vert();
+ }
+
+#ifdef USE_WORLD_CLIP_PLANES
+ world_clip_planes_calc_clip_distance(world_pos);
+#endif
+}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
index f6e3724eb51..85f79e94263 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_frag.glsl
@@ -1,10 +1,46 @@
+uniform vec4 gpDepthPlane;
+
flat in uint objectId;
/* using uint because 16bit uint can contain more ids than int. */
out uint outId;
+vec3 ray_plane_intersection(vec3 ray_ori, vec3 ray_dir, vec4 plane)
+{
+ float d = dot(plane.xyz, ray_dir);
+ vec3 plane_co = plane.xyz * (-plane.w / dot(plane.xyz, plane.xyz));
+ vec3 h = ray_ori - plane_co;
+ float lambda = -dot(plane.xyz, h) / ((abs(d) < 1e-8) ? 1e-8 : d);
+ return ray_ori + ray_dir * lambda;
+}
+
void main()
{
- outId = objectId;
+#ifdef USE_GPENCIL
+ if (stroke_round_cap_mask(strokePt1, strokePt2, strokeAspect, strokeThickness, strokeHardeness) <
+ 0.001) {
+ discard;
+ }
+
+ if (depth != -1.0) {
+ /* Stroke order 2D. */
+ bool is_persp = ProjectionMatrix[3][3] == 0.0;
+ vec2 uvs = vec2(gl_FragCoord.xy) * sizeViewportInv;
+ vec3 pos_ndc = vec3(uvs, gl_FragCoord.z) * 2.0 - 1.0;
+ vec4 pos_world = ViewProjectionMatrixInverse * vec4(pos_ndc, 1.0);
+ vec3 pos = pos_world.xyz / pos_world.w;
+
+ vec3 ray_ori = pos;
+ vec3 ray_dir = (is_persp) ? (ViewMatrixInverse[3].xyz - pos) : ViewMatrixInverse[2].xyz;
+ vec3 isect = ray_plane_intersection(ray_ori, ray_dir, gpDepthPlane);
+ vec4 ndc = point_world_to_ndc(isect);
+ gl_FragDepth = (ndc.z / ndc.w) * 0.5 + 0.5;
+ }
+ else {
+ gl_FragDepth = gl_FragCoord.z;
+ }
+#endif
+
+ outId = uint(objectId);
}
diff --git a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
index 984e55b0c46..a2021759196 100644
--- a/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/outline_prepass_vert.glsl
@@ -1,7 +1,9 @@
uniform bool isTransform;
+#ifndef USE_GPENCIL
in vec3 pos;
+#endif
#ifdef USE_GEOM
out vec3 vPos;
@@ -47,11 +49,19 @@ uint outline_colorid_get(void)
void main()
{
+#ifdef USE_GPENCIL
+ gpencil_vertex();
+# ifdef USE_WORLD_CLIP_PLANES
+ vec3 world_pos = point_object_to_world(pos1.xyz);
+# endif
+
+#else
vec3 world_pos = point_object_to_world(pos);
-#ifdef USE_GEOM
+ gl_Position = point_world_to_ndc(world_pos);
+# ifdef USE_GEOM
vPos = point_world_to_view(world_pos);
+# endif
#endif
- gl_Position = point_world_to_ndc(world_pos);
/* Small bias to always be on top of the geom. */
gl_Position.z -= 1e-3;
diff --git a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
index 31ac9a2b181..1abac302cda 100644
--- a/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
+++ b/source/blender/draw/engines/overlay/shaders/wireframe_vert.glsl
@@ -101,8 +101,10 @@ void wire_object_color_get(out vec3 rim_col, out vec3 wire_col)
void main()
{
+ bool no_attrib = all(equal(nor, vec3(0)));
+ vec3 wnor = no_attrib ? ViewMatrixInverse[2].xyz : normalize(normal_object_to_world(nor));
+
vec3 wpos = point_object_to_world(pos);
- vec3 wnor = normalize(normal_object_to_world(nor));
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
vec3 V = (is_persp) ? normalize(ViewMatrixInverse[3].xyz - wpos) : ViewMatrixInverse[2].xyz;
@@ -147,7 +149,7 @@ void main()
#endif
/* Cull flat edges below threshold. */
- if (get_edge_sharpness(wd) < 0.0) {
+ if (!no_attrib && (get_edge_sharpness(wd) < 0.0)) {
edgeStart = vec2(-1.0);
}
diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c
index c8f74120113..6e005e7ccaf 100644
--- a/source/blender/draw/engines/workbench/workbench_render.c
+++ b/source/blender/draw/engines/workbench/workbench_render.c
@@ -117,6 +117,60 @@ static bool workbench_render_framebuffers_init(void)
return ok;
}
+static void workbench_render_result_z(struct RenderLayer *rl,
+ const char *viewname,
+ const rcti *rect)
+{
+ DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ ViewLayer *view_layer = draw_ctx->view_layer;
+
+ if ((view_layer->passflag & SCE_PASS_Z) != 0) {
+ RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname);
+
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_read_depth(dfbl->default_fb,
+ rect->xmin,
+ rect->ymin,
+ BLI_rcti_size_x(rect),
+ BLI_rcti_size_y(rect),
+ rp->rect);
+
+ float winmat[4][4];
+ DRW_view_winmat_get(NULL, winmat, false);
+
+ int pix_ct = BLI_rcti_size_x(rect) * BLI_rcti_size_y(rect);
+
+ /* Convert ogl depth [0..1] to view Z [near..far] */
+ if (DRW_view_is_persp_get(NULL)) {
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
+ rp->rect[i] = rp->rect[i] * 2.0f - 1.0f;
+ rp->rect[i] = winmat[3][2] / (rp->rect[i] + winmat[2][2]);
+ }
+ }
+ }
+ else {
+ /* Keep in mind, near and far distance are negatives. */
+ float near = DRW_view_near_distance_get(NULL);
+ float far = DRW_view_far_distance_get(NULL);
+ float range = fabsf(far - near);
+
+ for (int i = 0; i < pix_ct; i++) {
+ if (rp->rect[i] == 1.0f) {
+ rp->rect[i] = 1e10f; /* Background */
+ }
+ else {
+ rp->rect[i] = -rp->rect[i] * range + near;
+ }
+ }
+ }
+ }
+}
+
static void workbench_render_framebuffers_finish(void)
{
}
@@ -195,8 +249,8 @@ void workbench_render(WORKBENCH_Data *data,
const char *viewname = RE_GetActiveRenderView(engine->re);
RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname);
- GPU_framebuffer_bind(dfbl->color_only_fb);
- GPU_framebuffer_read_color(dfbl->color_only_fb,
+ GPU_framebuffer_bind(dfbl->default_fb);
+ GPU_framebuffer_read_color(dfbl->default_fb,
rect->xmin,
rect->ymin,
BLI_rcti_size_x(rect),
@@ -205,6 +259,8 @@ void workbench_render(WORKBENCH_Data *data,
0,
rp->rect);
+ workbench_render_result_z(render_layer, viewname, rect);
+
workbench_render_framebuffers_finish();
}