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:
Diffstat (limited to 'source/blender/draw/engines/gpencil/gpencil_cache_utils.c')
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_cache_utils.c568
1 files changed, 306 insertions, 262 deletions
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;
}
+
+/** \} */