From 29f3af95272590d26f610ae828b2eeee89c82a00 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Mon, 9 Mar 2020 16:27:24 +0100 Subject: 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 --- .../draw/engines/gpencil/gpencil_cache_utils.c | 568 +++++++++++---------- 1 file changed, 306 insertions(+), 262 deletions(-) (limited to 'source/blender/draw/engines/gpencil/gpencil_cache_utils.c') 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; } + +/** \} */ -- cgit v1.2.3