diff options
28 files changed, 931 insertions, 784 deletions
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 3b8df66668a..34c61083872 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -65,7 +65,6 @@ bool BKE_gpencil_free_strokes(struct bGPDframe *gpf); void BKE_gpencil_free_frames(struct bGPDlayer *gpl); void BKE_gpencil_free_layers(struct ListBase *list); bool BKE_gpencil_free_frame_runtime_data(struct bGPDframe *derived_gpf); -void BKE_gpencil_free_derived_frames(struct bGPdata *gpd); void BKE_gpencil_free(struct bGPdata *gpd, bool free_all); void BKE_gpencil_batch_cache_dirty_tag(struct bGPdata *gpd); diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index 91f368613cb..e31f61c909a 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -232,6 +232,11 @@ typedef struct GpencilModifierTypeInfo { */ void (*foreachTexLink)(struct GpencilModifierData *md, struct Object *ob, GreasePencilTexWalkFunc walk, void *userData); + + /* get the number of times the strokes are duplicated in this modifier. + * This is used to calculate the size of the GPU VBOs + */ + int (*getDuplicationFactor)(struct GpencilModifierData *md); } GpencilModifierTypeInfo; /* Initialize modifier's global data (type info and some common global storages). */ diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f2225bca3f5..98d255df080 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -211,46 +211,6 @@ void BKE_gpencil_free_layers(ListBase *list) } } -/* clear all runtime derived data */ -static void BKE_gpencil_clear_derived(bGPDlayer *gpl) -{ - if (gpl->runtime.derived_array == NULL) { - return; - } - - for (int i = 0; i < gpl->runtime.len_derived; i++) { - bGPDframe *derived_gpf = &gpl->runtime.derived_array[i]; - BKE_gpencil_free_frame_runtime_data(derived_gpf); - derived_gpf = NULL; - } - gpl->runtime.len_derived = 0; - MEM_SAFE_FREE(gpl->runtime.derived_array); -} - -/* Free all of the gp-layers temp data*/ -static void BKE_gpencil_free_layers_temp_data(ListBase *list) -{ - bGPDlayer *gpl_next; - - /* error checking */ - if (list == NULL) return; - /* delete layers */ - for (bGPDlayer *gpl = list->first; gpl; gpl = gpl_next) { - gpl_next = gpl->next; - BKE_gpencil_clear_derived(gpl); - } -} - -/* Free temp gpf derived frames */ -void BKE_gpencil_free_derived_frames(bGPdata *gpd) -{ - /* error checking */ - if (gpd == NULL) return; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - BKE_gpencil_clear_derived(gpl); - } -} - /** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ void BKE_gpencil_free(bGPdata *gpd, bool free_all) { @@ -258,9 +218,6 @@ void BKE_gpencil_free(bGPdata *gpd, bool free_all) BKE_animdata_free(&gpd->id, false); /* free layers */ - if (free_all) { - BKE_gpencil_free_layers_temp_data(&gpd->layers); - } BKE_gpencil_free_layers(&gpd->layers); /* materials */ @@ -639,8 +596,6 @@ bGPDlayer *BKE_gpencil_layer_duplicate(const bGPDlayer *gpl_src) /* make a copy of source layer */ gpl_dst = MEM_dupallocN(gpl_src); gpl_dst->prev = gpl_dst->next = NULL; - gpl_dst->runtime.derived_array = NULL; - gpl_dst->runtime.len_derived = 0; /* copy frames */ BLI_listbase_clear(&gpl_dst->frames); @@ -1031,9 +986,6 @@ void BKE_gpencil_layer_delete(bGPdata *gpd, bGPDlayer *gpl) /* free icon providing preview of icon color */ BKE_icon_delete(gpl->runtime.icon_id); - /* free derived data */ - BKE_gpencil_clear_derived(gpl); - BLI_freelinkN(&gpd->layers, gpl); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9596df58170..50bf2f79fdc 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -6612,8 +6612,6 @@ static void direct_link_gpencil(FileData *fd, bGPdata *gpd) gpl->actframe = newdataadr(fd, gpl->actframe); - gpl->runtime.derived_array = NULL; - gpl->runtime.len_derived = 0; gpl->runtime.icon_id = 0; for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 30887e3fb19..15ac3f37add 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -26,14 +26,14 @@ #include "DRW_engine.h" #include "DRW_render.h" -#include "BKE_global.h" - #include "ED_gpencil.h" #include "ED_view3d.h" #include "DNA_gpencil_types.h" #include "DNA_view3d_types.h" +#include "BKE_gpencil.h" + #include "gpencil_engine.h" #include "draw_cache_impl.h" @@ -41,63 +41,6 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -static bool gpencil_check_ob_duplicated(tGPencilObjectCache *cache_array, - int gp_cache_used, Object *ob, int *r_index) -{ - if (gp_cache_used == 0) { - return false; - } - - for (int i = 0; i < gp_cache_used; i++) { - tGPencilObjectCache *cache_elem = &cache_array[i]; - if (cache_elem->ob == ob) { - *r_index = cache_elem->data_idx; - return true; - } - } - return false; -} - -static bool gpencil_check_datablock_duplicated( - tGPencilObjectCache *cache_array, int gp_cache_used, - Object *ob, bGPdata *gpd) -{ - if (gp_cache_used == 0) { - return false; - } - - for (int i = 0; i < gp_cache_used; i++) { - tGPencilObjectCache *cache_elem = &cache_array[i]; - if ((cache_elem->ob != ob) && - (cache_elem->gpd == gpd)) - { - return true; - } - } - return false; -} - -static int gpencil_len_datablock_duplicated( - tGPencilObjectCache *cache_array, int gp_cache_used, - Object *ob, bGPdata *gpd) -{ - int tot = 0; - if (gp_cache_used == 0) { - return 0; - } - - for (int i = 0; i < gp_cache_used; i++) { - tGPencilObjectCache *cache_elem = &cache_array[i]; - if ((cache_elem->ob != ob) && - (cache_elem->gpd == gpd) && - (!cache_elem->is_dup_ob)) - { - tot++; - } - } - return tot; -} - /* add a gpencil object to cache to defer drawing */ tGPencilObjectCache *gpencil_object_cache_add( tGPencilObjectCache *cache_array, Object *ob, @@ -133,38 +76,15 @@ tGPencilObjectCache *gpencil_object_cache_add( copy_m4_m4(cache_elem->obmat, ob->obmat); cache_elem->idx = *gp_cache_used; - /* check if object is duplicated */ - cache_elem->is_dup_ob = gpencil_check_ob_duplicated( - cache_array, - *gp_cache_used, ob_orig, - &cache_elem->data_idx); - - if (!cache_elem->is_dup_ob) { - /* check if object reuse datablock */ - cache_elem->is_dup_data = gpencil_check_datablock_duplicated( - cache_array, *gp_cache_used, - ob_orig, cache_elem->gpd); - if (cache_elem->is_dup_data) { - cache_elem->data_idx = gpencil_len_datablock_duplicated( - cache_array, *gp_cache_used, - ob_orig, cache_elem->gpd); - - cache_elem->gpd->flag |= GP_DATA_CACHE_IS_DIRTY; - } - else { - cache_elem->data_idx = 0; - } - } - else { - cache_elem->is_dup_data = false; - } + /* object is duplicated (particle) */ + cache_elem->is_dup_ob = ob->base_flag & BASE_FROMDUPLI; /* save FXs */ cache_elem->pixfactor = cache_elem->gpd->pixfactor; cache_elem->shader_fx = ob_orig->shader_fx; - cache_elem->init_grp = 0; - cache_elem->end_grp = -1; + cache_elem->init_grp = NULL; + cache_elem->end_grp = NULL; /* calculate zdepth from point of view */ float zdepth = 0.0; @@ -198,6 +118,48 @@ tGPencilObjectCache *gpencil_object_cache_add( 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; + } + else { + *grp_size += GPENCIL_GROUPS_BLOCK_SIZE; + p = MEM_recallocN(cache_array, sizeof(struct GpencilBatchGroup) * *grp_size); + } + 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; +} + /* get current cache data */ static GpencilBatchCache *gpencil_batch_get_element(Object *ob) { @@ -208,51 +170,33 @@ static GpencilBatchCache *gpencil_batch_get_element(Object *ob) /* verify if cache is valid */ static bool gpencil_batch_cache_valid(GpencilBatchCache *cache, bGPdata *gpd, int cfra) { + bool valid = true; if (cache == NULL) { return false; } cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); - if (cfra != cache->cache_frame) { - return false; + valid = false; } - - if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) { - return false; + else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) { + valid = false; } - - if (cache->is_editmode) { - return false; + else if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) { + /* if onion, set as dirty always + * This reduces performance, but avoid any crash in the multiple + * overlay and multiwindow options and keep all windows working + */ + valid = false; } - - if (cache->is_dirty) { - return false; + else if (cache->is_editmode) { + valid = false; } - - return true; -} - -/* resize the cache to the number of slots */ -static void gpencil_batch_cache_resize(GpencilBatchCache *cache, int slots) -{ - cache->cache_size = slots; - cache->batch_stroke = MEM_recallocN(cache->batch_stroke, sizeof(struct Gwn_Batch *) * slots); - cache->batch_fill = MEM_recallocN(cache->batch_fill, sizeof(struct Gwn_Batch *) * slots); - cache->batch_edit = MEM_recallocN(cache->batch_edit, sizeof(struct Gwn_Batch *) * slots); - cache->batch_edlin = MEM_recallocN(cache->batch_edlin, sizeof(struct Gwn_Batch *) * slots); -} - -/* check size and increase if no free slots */ -void gpencil_batch_cache_check_free_slots(Object *ob) -{ - GpencilBatchCache *cache = gpencil_batch_get_element(ob); - - /* the memory is reallocated by chunks, not for one slot only to improve speed */ - if (cache->cache_idx >= cache->cache_size) { - cache->cache_size += GPENCIL_MIN_BATCH_SLOTS_CHUNK; - gpencil_batch_cache_resize(cache, cache->cache_size); + else if (cache->is_dirty) { + valid = false; } + + return valid; } /* cache init */ @@ -263,10 +207,6 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) GpencilBatchCache *cache = gpencil_batch_get_element(ob); - if (G.debug_value >= 664) { - printf("gpencil_batch_cache_init: %s\n", ob->id.name); - } - if (!cache) { cache = MEM_callocN(sizeof(*cache), __func__); ob_orig->runtime.gpencil_cache = cache; @@ -275,19 +215,17 @@ static GpencilBatchCache *gpencil_batch_cache_init(Object *ob, int cfra) memset(cache, 0, sizeof(*cache)); } - cache->cache_size = GPENCIL_MIN_BATCH_SLOTS_CHUNK; - cache->batch_stroke = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Stroke"); - cache->batch_fill = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Fill"); - cache->batch_edit = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edit"); - cache->batch_edlin = MEM_callocN(sizeof(struct Gwn_Batch *) * cache->cache_size, "Gpencil_Batch_Edlin"); - cache->is_editmode = GPENCIL_ANY_EDIT_MODE(gpd); - gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; - cache->cache_idx = 0; cache->is_dirty = true; + cache->cache_frame = cfra; + /* create array of derived frames equal to number of layers */ + cache->tot_layers = BLI_listbase_count(&gpd->layers); + CLAMP_MIN(cache->tot_layers, 1); + cache->derived_array = MEM_callocN(sizeof(struct bGPDframe) * cache->tot_layers, "Derived GPF"); + return cache; } @@ -298,24 +236,30 @@ static void gpencil_batch_cache_clear(GpencilBatchCache *cache) return; } - if (cache->cache_size == 0) { - return; - } - - if (cache->cache_size > 0) { - for (int i = 0; i < cache->cache_size; i++) { - GPU_BATCH_DISCARD_SAFE(cache->batch_stroke[i]); - GPU_BATCH_DISCARD_SAFE(cache->batch_fill[i]); - GPU_BATCH_DISCARD_SAFE(cache->batch_edit[i]); - GPU_BATCH_DISCARD_SAFE(cache->batch_edlin[i]); - } - MEM_SAFE_FREE(cache->batch_stroke); - MEM_SAFE_FREE(cache->batch_fill); - MEM_SAFE_FREE(cache->batch_edit); - MEM_SAFE_FREE(cache->batch_edlin); + 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); + + MEM_SAFE_FREE(cache->grp_cache); + cache->grp_size = 0; + cache->grp_used = 0; + + /* clear all frames derived data */ + for (int i = 0; i < cache->tot_layers; i++) { + bGPDframe *derived_gpf = &cache->derived_array[i]; + BKE_gpencil_free_frame_runtime_data(derived_gpf); + derived_gpf = NULL; } - - cache->cache_size = 0; + cache->tot_layers = 0; + MEM_SAFE_FREE(cache->derived_array); } /* get cache */ @@ -326,10 +270,6 @@ GpencilBatchCache *gpencil_batch_cache_get(Object *ob, int cfra) GpencilBatchCache *cache = gpencil_batch_get_element(ob); if (!gpencil_batch_cache_valid(cache, gpd, cfra)) { - if (G.debug_value >= 664) { - printf("gpencil_batch_cache: %s\n", gpd->id.name); - } - if (cache) { gpencil_batch_cache_clear(cache); } diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c index f255892de44..ec690fdd14b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c @@ -87,24 +87,33 @@ static void gpencil_set_fill_point( GPU_vertbuf_attr_set(vbo, text_id, idx, uv); } -/* create batch geometry data for points stroke shader */ -GPUBatch *DRW_gpencil_get_point_geom(bGPDstroke *gps, short thickness, const float ink[4]) +static void gpencil_vbo_ensure_size(GpencilBatchCacheElem *be, int totvertex) { - static GPUVertFormat format = { 0 }; - static uint pos_id, color_id, size_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); - size_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); + 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); } +} - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, gps->totpoints); +/* create batch geometry data for points stroke shader */ +void DRW_gpencil_get_point_geom(GpencilBatchCacheElem *be, bGPDstroke *gps, short thickness, const float ink[4]) +{ + int totvertex = gps->totpoints; + if (be->vbo == NULL) { + 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; + } + else { + gpencil_vbo_ensure_size(be, totvertex); + } /* draw stroke curve */ const bGPDspoint *pt = gps->points; - int idx = 0; float alpha; float col[4]; @@ -116,86 +125,124 @@ GPUBatch *DRW_gpencil_get_point_geom(bGPDstroke *gps, short thickness, const flo float thick = max_ff(pt->pressure * thickness, 1.0f); - GPU_vertbuf_attr_set(vbo, color_id, idx, col); - GPU_vertbuf_attr_set(vbo, size_id, idx, &thick); + 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(vbo, uvdata_id, idx, uvdata); + GPU_vertbuf_attr_set(be->vbo, be->uvdata_id, be->vbo_len, uvdata); - GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); - idx++; + GPU_vertbuf_attr_set(be->vbo, be->pos_id, be->vbo_len, &pt->x); + be->vbo_len++; } - - return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* create batch geometry data for stroke shader */ -GPUBatch *DRW_gpencil_get_stroke_geom(bGPDstroke *gps, short thickness, const float ink[4]) +void DRW_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; - 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); - } + if (be->vbo == NULL) { + 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); - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, totpoints + cyclic_add + 2); + be->vbo = GPU_vertbuf_create_with_format(&be->format); + GPU_vertbuf_data_alloc(be->vbo, be->tot_vertex); + be->vbo_len = 0; + } + else { + gpencil_vbo_ensure_size(be, totvertex); + } /* draw stroke curve */ const bGPDspoint *pt = points; - int idx = 0; 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( - vbo, &points[totpoints - 1], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); - idx++; + 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( - vbo, &points[1], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); - idx++; + 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( - vbo, pt, idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); - idx++; + 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( - vbo, &points[0], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); - idx++; + 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( - vbo, &points[1], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); - idx++; + 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( - vbo, &points[totpoints - 2], idx, - pos_id, color_id, thickness_id, uvdata_id, thickness, ink); + 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++; } +} - return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO); +/* create batch geometry data for stroke shader */ +void DRW_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_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { + DRW_gpencil_triangulate_stroke_fill(ob, gps); + ED_gpencil_calc_stroke_uv(ob, gps); + } + + BLI_assert(gps->tot_triangles >= 1); + int totvertex = gps->tot_triangles * 3; + + if (be->vbo == NULL) { + 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; + } + else { + 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 */ @@ -407,47 +454,8 @@ GPUBatch *DRW_gpencil_get_buffer_fill_geom(bGPdata *gpd) return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); } -/* create batch geometry data for stroke shader */ -GPUBatch *DRW_gpencil_get_fill_geom(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_CACHES) || (gps->tot_triangles == 0) || (gps->triangles == NULL)) { - DRW_gpencil_triangulate_stroke_fill(ob, gps); - ED_gpencil_calc_stroke_uv(ob, gps); - } - - BLI_assert(gps->tot_triangles >= 1); - - static GPUVertFormat format = { 0 }; - static uint pos_id, color_id, text_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); - text_id = GPU_vertformat_attr_add(&format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - } - - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, gps->tot_triangles * 3); - - /* Draw all triangles for filling the polygon (cache must be calculated before) */ - bGPDtriangle *stroke_triangle = gps->triangles; - int idx = 0; - for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) { - for (int j = 0; j < 3; j++) { - gpencil_set_fill_point( - vbo, idx, &gps->points[stroke_triangle->verts[j]], color, stroke_triangle->uv[j], - pos_id, color_id, text_id); - idx++; - } - } - - return GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, NULL, GPU_BATCH_OWNS_VBO); -} - /* Draw selected verts for strokes being edited */ -GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag) +void DRW_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; @@ -483,16 +491,18 @@ GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag) UI_GetThemeColor3fv(TH_GP_VERTEX, unselectColor); unselectColor[3] = alpha; - 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); - color_id = GPU_vertformat_attr_add(&format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - size_id = GPU_vertformat_attr_add(&format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } + if (be->vbo == NULL) { + 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); - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, gps->totpoints); + be->vbo = GPU_vertbuf_create_with_format(&be->format); + GPU_vertbuf_data_alloc(be->vbo, gps->totpoints); + be->vbo_len = 0; + } + else { + 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); @@ -501,7 +511,6 @@ GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag) bGPDspoint *pt = gps->points; MDeformVert *dvert = gps->dvert; - int idx = 0; float fcolor[4]; float fsize = 0; for (int i = 0; i < gps->totpoints; i++, pt++) { @@ -535,20 +544,18 @@ GPUBatch *DRW_gpencil_get_edit_geom(bGPDstroke *gps, float alpha, short dflag) } } - GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); - GPU_vertbuf_attr_set(vbo, size_id, idx, &fsize); - GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); - idx++; + 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++; } } - - return GPU_batch_create_ex(GPU_PRIM_POINTS, vbo, NULL, GPU_BATCH_OWNS_VBO); } /* Draw lines for strokes being edited */ -GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED(dflag)) +void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, bGPDstroke *gps, float alpha, short UNUSED(dflag)) { const DRWContextState *draw_ctx = DRW_context_state_get(); Object *ob = draw_ctx->obact; @@ -566,21 +573,22 @@ GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED( float linecolor[4]; copy_v4_v4(linecolor, gpd->line_color); - 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); - } + if (be->vbo == NULL) { + 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); - GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); - GPU_vertbuf_data_alloc(vbo, gps->totpoints); + be->vbo = GPU_vertbuf_create_with_format(&be->format); + GPU_vertbuf_data_alloc(be->vbo, gps->totpoints); + be->vbo_len = 0; + } + else { + gpencil_vbo_ensure_size(be, gps->totpoints); + } /* Draw all the stroke lines (selected or not) */ bGPDspoint *pt = gps->points; MDeformVert *dvert = gps->dvert; - int idx = 0; float fcolor[4]; for (int i = 0; i < gps->totpoints; i++, pt++) { /* weight paint */ @@ -600,16 +608,14 @@ GPUBatch *DRW_gpencil_get_edlin_geom(bGPDstroke *gps, float alpha, short UNUSED( } } - GPU_vertbuf_attr_set(vbo, color_id, idx, fcolor); - GPU_vertbuf_attr_set(vbo, pos_id, idx, &pt->x); - idx++; + 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++; } } - - return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO); } static void set_grid_point( diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index cba5cfccaf6..9799ab85cfb 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -65,6 +65,67 @@ #define GP_SET_SRC_GPS(src_gps) if (src_gps) src_gps = src_gps->next +/* Get number of vertex for using in GPU VBOs */ +void gpencil_calc_vertex( + GPENCIL_StorageList *stl, tGPencilObjectCache *cache_ob, + GpencilBatchCache *cache, bGPdata *gpd, + int cfra_eval) +{ + Object *ob = cache_ob->ob; + const DRWContextState *draw_ctx = DRW_context_state_get(); + bGPDframe *gpf = NULL; + + const bool time_remap = BKE_gpencil_has_time_modifiers(ob); + + cache_ob->tot_vertex = 0; + cache_ob->tot_triangles = 0; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->flag & GP_LAYER_HIDE) { + continue; + } + + /* verify time modifiers */ + if ((time_remap) && (!stl->storage->simplify_modif)) { + int remap_cfra = BKE_gpencil_time_modifier( + draw_ctx->depsgraph, draw_ctx->scene, ob, gpl, cfra_eval, + stl->storage->is_render); + gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV); + } + else { + gpf = gpl->actframe; + } + + if (gpf == NULL) { + continue; + } + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + cache_ob->tot_vertex += gps->totpoints + 3; + cache_ob->tot_triangles += gps->totpoints - 1; + } + } + + 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; + + /* some modifiers can change the number of points */ + int factor = 0; + GpencilModifierData *md; + for (md = ob->greasepencil_modifiers.first; md; md = md->next) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + /* only modifiers that change size */ + if (mti && mti->getDuplicationFactor) { + factor = mti->getDuplicationFactor(md); + + cache->b_fill.tot_vertex *= factor; + cache->b_stroke.tot_vertex *= factor; + cache->b_point.tot_vertex *= factor; + } + } +} + /* 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, @@ -182,79 +243,6 @@ static void gpencil_stroke_2d_flat(const bGPDspoint *points, int totpoints, floa *r_direction = (int)locy[2]; } -/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */ -void DRW_gpencil_triangulate_stroke_fill(Object *ob, bGPDstroke *gps) -{ - BLI_assert(gps->totpoints >= 3); - - bGPdata *gpd = (bGPdata *)ob->data; - - /* allocate memory for temporary areas */ - gps->tot_triangles = gps->totpoints - 2; - uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); - float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points"); - float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data"); - - int direction = 0; - - /* convert to 2d and triangulate */ - gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); - BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles); - - /* calc texture coordinates automatically */ - float minv[2]; - float maxv[2]; - /* first needs bounding box data */ - if (gpd->flag & GP_DATA_UV_ADAPTATIVE) { - gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv); - } - else { - ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); - ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); - } - - /* calc uv data */ - gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv); - - /* Number of triangles */ - gps->tot_triangles = gps->totpoints - 2; - /* save triangulation data in stroke cache */ - if (gps->tot_triangles > 0) { - if (gps->triangles == NULL) { - gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation"); - } - else { - gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles); - } - - for (int i = 0; i < gps->tot_triangles; i++) { - bGPDtriangle *stroke_triangle = &gps->triangles[i]; - memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); - /* copy texture coordinates */ - copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]); - copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]); - copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]); - } - } - else { - /* No triangles needed - Free anything allocated previously */ - if (gps->triangles) - MEM_freeN(gps->triangles); - - gps->triangles = NULL; - } - - /* disable recalculation flag */ - if (gps->flag & GP_STROKE_RECALC_CACHES) { - gps->flag &= ~GP_STROKE_RECALC_CACHES; - } - - /* clear memory */ - MEM_SAFE_FREE(tmp_triangles); - MEM_SAFE_FREE(points2d); - MEM_SAFE_FREE(uv); -} - /* recalc the internal geometry caches for fill and uvs */ static void DRW_gpencil_recalc_geometry_caches(Object *ob, MaterialGPencilStyle *gp_style, bGPDstroke *gps) { @@ -466,7 +454,7 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create( return grp; } -/* create shading group for volumetrics */ +/* create shading group for points */ static DRWShadingGroup *DRW_gpencil_shgroup_point_create( GPENCIL_e_data *e_data, GPENCIL_Data *vedata, DRWPass *pass, GPUShader *shader, Object *ob, bGPdata *gpd, MaterialGPencilStyle *gp_style, int id, bool onion) @@ -559,10 +547,10 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create( return grp; } -/* add fill shading group to pass */ -static void gpencil_add_fill_shgroup( - GpencilBatchCache *cache, DRWShadingGroup *fillgrp, - Object *ob, bGPDframe *gpf, bGPDstroke *gps, +/* 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_material_gpencil_settings_get(ob, gps->mat_nr + 1); @@ -586,17 +574,24 @@ static void gpencil_add_fill_shgroup( color = tfill; } } - gpencil_batch_cache_check_free_slots(ob); - cache->batch_fill[cache->cache_idx] = DRW_gpencil_get_fill_geom(ob, gps, color); + /* create vertex data */ + const int old_len = cache->b_fill.vbo_len; + DRW_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); + } } - - DRW_shgroup_call_add(fillgrp, cache->batch_fill[cache->cache_idx], gpf->runtime.viewmatrix); } } } -/* add stroke shading group to pass */ -static void gpencil_add_stroke_shgroup(GpencilBatchCache *cache, DRWShadingGroup *strokegrp, +/* 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) @@ -632,19 +627,38 @@ static void gpencil_add_stroke_shgroup(GpencilBatchCache *cache, DRWShadingGroup sthickness = gps->thickness + gpl->line_change; CLAMP_MIN(sthickness, 1); - gpencil_batch_cache_check_free_slots(ob); + if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) { - cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_stroke_geom(gps, sthickness, ink); + /* create vertex data */ + const int old_len = cache->b_stroke.vbo_len; + DRW_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 { - cache->batch_stroke[cache->cache_idx] = DRW_gpencil_get_point_geom(gps, sthickness, ink); + /* create vertex data */ + const int old_len = cache->b_point.vbo_len; + DRW_gpencil_get_point_geom(&cache->b_point, gps, sthickness, ink); + + /* 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); + } } } - DRW_shgroup_call_add(strokegrp, cache->batch_stroke[cache->cache_idx], gpf->runtime.viewmatrix); } -/* add edit points shading group to pass */ -static void gpencil_add_editpoints_shgroup( +/* add edit points vertex info */ +static void gpencil_add_editpoints_vertexdata( GPENCIL_StorageList *stl, GpencilBatchCache *cache, ToolSettings *UNUSED(ts), Object *ob, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps) { @@ -662,36 +676,31 @@ static void gpencil_add_editpoints_shgroup( } const bool is_weight_paint = (gpd) && (gpd->flag & GP_DATA_STROKE_WEIGHTMODE); - /* line of the original stroke */ if (cache->is_dirty) { - gpencil_batch_cache_check_free_slots(ob); - cache->batch_edlin[cache->cache_idx] = DRW_gpencil_get_edlin_geom(gps, edit_alpha, gpd->flag); - } - if (cache->batch_edlin[cache->cache_idx]) { - if ((obact) && (obact == ob) && - ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && - (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES)) + if ((obact == ob) && + ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) && + (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES)) { - DRW_shgroup_call_add( - stl->g_data->shgrps_edit_line, - cache->batch_edlin[cache->cache_idx], - gpf->runtime.viewmatrix); + /* line of the original stroke */ + DRW_gpencil_get_edlin_geom(&cache->b_edlin, gps, edit_alpha, gpd->flag); + + /* 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); } - } - /* 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 (cache->is_dirty) { - gpencil_batch_cache_check_free_slots(ob); - cache->batch_edit[cache->cache_idx] = DRW_gpencil_get_edit_geom(gps, edit_alpha, gpd->flag); - } - if (cache->batch_edit[cache->cache_idx]) { - if ((obact) && (obact == ob)) { - /* edit pass */ - DRW_shgroup_call_add( - stl->g_data->shgrps_edit_point, - cache->batch_edit[cache->cache_idx], - gpf->runtime.viewmatrix); + /* 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) { + DRW_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); } } } @@ -699,57 +708,6 @@ static void gpencil_add_editpoints_shgroup( } } -/* function to draw strokes for onion only */ -static void gpencil_draw_onion_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) -{ - GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; - GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - Depsgraph *depsgraph = DRW_context_state_get()->depsgraph; - - float viewmatrix[4][4]; - - /* get parent matrix and save as static data */ - ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix); - copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix); - - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); - 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; - } - - stl->shgroups[id].shgrps_fill = NULL; - if ((gps->totpoints > 1) && (gp_style->mode == GP_STYLE_MODE_LINE)) { - stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create( - e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, true); - } - else { - stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create( - e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, true); - } - - /* stroke */ - gpencil_add_stroke_shgroup( - cache, stl->shgroups[id].shgrps_stroke, ob, gpl, gpf, gps, opacity, tintcolor, true, custonion); - - stl->storage->shgroup_id++; - cache->cache_idx++; - } -} - - /* main function to draw strokes */ static void gpencil_draw_strokes( GpencilBatchCache *cache, GPENCIL_e_data *e_data, void *vedata, ToolSettings *ts, Object *ob, @@ -763,8 +721,6 @@ static void gpencil_draw_strokes( Scene *scene = draw_ctx->scene; View3D *v3d = draw_ctx->v3d; bGPDstroke *gps, *src_gps; - DRWShadingGroup *fillgrp; - DRWShadingGroup *strokegrp; float viewmatrix[4][4]; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); const bool playing = stl->storage->is_playing; @@ -810,11 +766,6 @@ static void gpencil_draw_strokes( GP_SET_SRC_GPS(src_gps); continue; } - /* limit the number of shading groups */ - if (stl->storage->shgroup_id >= GPENCIL_MAX_SHGROUPS) { - GP_SET_SRC_GPS(src_gps); - continue; - } /* be sure recalc all cache in source stroke to avoid recalculation when frame change * and improve fps */ @@ -835,38 +786,6 @@ static void gpencil_draw_strokes( if ((gpl->actframe->framenum == derived_gpf->framenum) || (!is_multiedit) || (overlay_multiedit)) { - int id = stl->storage->shgroup_id; - if (gps->totpoints > 0) { - if ((gps->totpoints > 2) && (!stl->storage->simplify_fill) && - ((gp_style->fill_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) && - ((gps->flag & GP_STROKE_NOFILL) == 0) && - (gp_style->flag & GP_STYLE_FILL_SHOW)) - { - stl->shgroups[id].shgrps_fill = DRW_gpencil_shgroup_fill_create( - e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh, - gpd, gpl, gp_style, id); - } - else { - stl->shgroups[id].shgrps_fill = NULL; - } - if ((gp_style->mode == GP_STYLE_MODE_LINE) && (gps->totpoints > 1)) { - stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_stroke_create( - e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, ob, gpd, gp_style, id, false); - } - else { - stl->shgroups[id].shgrps_stroke = DRW_gpencil_shgroup_point_create( - e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, ob, gpd, gp_style, id, false); - } - } - else { - stl->shgroups[id].shgrps_fill = NULL; - stl->shgroups[id].shgrps_stroke = NULL; - } - stl->storage->shgroup_id++; - - fillgrp = stl->shgroups[id].shgrps_fill; - strokegrp = stl->shgroups[id].shgrps_stroke; - /* copy color to temp fields to apply temporal changes in the stroke */ copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); @@ -879,17 +798,20 @@ static void gpencil_draw_strokes( } /* fill */ - if ((fillgrp) && (!stl->storage->simplify_fill)) { - gpencil_add_fill_shgroup( - cache, fillgrp, ob, derived_gpf, gps, + if ((gp_style->flag & GP_STYLE_FILL_SHOW) && + (!stl->storage->simplify_fill)) + { + gpencil_add_fill_vertexdata( + cache, ob, gpl, derived_gpf, gps, opacity, tintcolor, false, custonion); } /* stroke */ - if (strokegrp) { - const float nop = ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0) || (gp_style->stroke_rgba[3] < GPENCIL_ALPHA_OPACITY_THRESH) ? 0.0f : opacity; - gpencil_add_stroke_shgroup( - cache, strokegrp, ob, gpl, derived_gpf, gps, - nop, tintcolor, false, custonion); + if ((gp_style->flag & GP_STYLE_STROKE_SHOW) && + (gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH)) + { + gpencil_add_stroke_vertexdata( + cache, ob, gpl, derived_gpf, gps, + opacity, tintcolor, false, custonion); } } @@ -907,118 +829,11 @@ static void gpencil_draw_strokes( DRW_shgroup_uniform_vec2(stl->g_data->shgrps_edit_point, "Viewport", viewport_size, 1); } - gpencil_add_editpoints_shgroup(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps); - } - else { - gpencil_batch_cache_check_free_slots(ob); + gpencil_add_editpoints_vertexdata(stl, cache, ts, ob, gpd, gpl, derived_gpf, src_gps); } } GP_SET_SRC_GPS(src_gps); - - cache->cache_idx++; - } -} - - /* draw stroke in drawing buffer */ -void DRW_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; - Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); - 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_get_material_from_brush(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_material_gpencil_settings_get(ob, ob->actcol); - } - - /* 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 (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 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; - /* if only one point, don't need to draw buffer because the user has no time to see it */ - if (gpd->runtime.sbuffer_size > 1) { - if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) { - stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create( - e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false); - } - else { - stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create( - e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false); - } - - /* clean previous version of the batch */ - if (stl->storage->buffer_stroke) { - GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_stroke); - MEM_SAFE_FREE(e_data->batch_buffer_stroke); - stl->storage->buffer_stroke = false; - } - - /* use unit matrix because the buffer is in screen space and does not need conversion */ - if (gpd->runtime.mode == GP_STYLE_MODE_LINE) { - e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom( - gpd, lthick); - } - else { - e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom( - gpd, lthick); - } - - if (gp_style->flag & GP_STYLE_STROKE_SHOW) { - DRW_shgroup_call_add( - stl->g_data->shgrps_drawing_stroke, - e_data->batch_buffer_stroke, - stl->storage->unit_matrix); - } - - if ((gpd->runtime.sbuffer_size >= 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); - - /* clean previous version of the batch */ - if (stl->storage->buffer_fill) { - GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_fill); - MEM_SAFE_FREE(e_data->batch_buffer_fill); - stl->storage->buffer_fill = false; - } - - e_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd); - DRW_shgroup_call_add( - stl->g_data->shgrps_drawing_fill, - e_data->batch_buffer_fill, - stl->storage->unit_matrix); - stl->storage->buffer_fill = true; - } - stl->storage->buffer_stroke = true; - } - } } } @@ -1039,6 +854,44 @@ static void gpencil_get_onion_alpha(float color[4], bGPdata *gpd) CLAMP(color[3], MIN_ALPHA_VALUE, 1.0f); } +/* function to draw strokes for onion only */ +static void gpencil_draw_onion_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) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + Depsgraph *depsgraph = DRW_context_state_get()->depsgraph; + + float viewmatrix[4][4]; + + /* get parent matrix and save as static data */ + ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, viewmatrix); + copy_m4_m4(gpf->runtime.viewmatrix, viewmatrix); + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + 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, GPENCIL_e_data *e_data, void *vedata, @@ -1058,7 +911,6 @@ static void gpencil_draw_onionskins( colflag = (bool)gpd->onion_flag & GP_ONION_GHOST_PREVCOL; - /* ------------------------------- * 1) Draw Previous Frames First * ------------------------------- */ @@ -1183,9 +1035,348 @@ static void gpencil_draw_onionskins( } } +static void gpencil_copy_frame(bGPDframe *gpf, bGPDframe *derived_gpf) +{ + derived_gpf->prev = gpf->prev; + derived_gpf->next = gpf->next; + derived_gpf->framenum = gpf->framenum; + derived_gpf->flag = gpf->flag; + derived_gpf->key_type = gpf->key_type; + derived_gpf->runtime = gpf->runtime; + copy_m4_m4(derived_gpf->runtime.viewmatrix, gpf->runtime.viewmatrix); + + /* copy strokes */ + BLI_listbase_clear(&derived_gpf->strokes); + for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) { + /* make copy of source stroke */ + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src); + BLI_addtail(&derived_gpf->strokes, gps_dst); + } +} + +/* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was modified) */ +void DRW_gpencil_triangulate_stroke_fill(Object *ob, bGPDstroke *gps) +{ + BLI_assert(gps->totpoints >= 3); + + bGPdata *gpd = (bGPdata *)ob->data; + + /* allocate memory for temporary areas */ + gps->tot_triangles = gps->totpoints - 2; + uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles, "GP Stroke temp triangulation"); + float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints, "GP Stroke temp 2d points"); + float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data"); + + int direction = 0; + + /* convert to 2d and triangulate */ + gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction); + BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles); + + /* calc texture coordinates automatically */ + float minv[2]; + float maxv[2]; + /* first needs bounding box data */ + if (gpd->flag & GP_DATA_UV_ADAPTATIVE) { + gpencil_calc_2d_bounding_box(points2d, gps->totpoints, minv, maxv); + } + else { + ARRAY_SET_ITEMS(minv, -1.0f, -1.0f); + ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f); + } + + /* calc uv data */ + gpencil_calc_stroke_fill_uv(points2d, gps->totpoints, minv, maxv, uv); + + /* Number of triangles */ + gps->tot_triangles = gps->totpoints - 2; + /* save triangulation data in stroke cache */ + if (gps->tot_triangles > 0) { + if (gps->triangles == NULL) { + gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles, "GP Stroke triangulation"); + } + else { + gps->triangles = MEM_recallocN(gps->triangles, sizeof(*gps->triangles) * gps->tot_triangles); + } + + for (int i = 0; i < gps->tot_triangles; i++) { + bGPDtriangle *stroke_triangle = &gps->triangles[i]; + memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3])); + /* copy texture coordinates */ + copy_v2_v2(stroke_triangle->uv[0], uv[tmp_triangles[i][0]]); + copy_v2_v2(stroke_triangle->uv[1], uv[tmp_triangles[i][1]]); + copy_v2_v2(stroke_triangle->uv[2], uv[tmp_triangles[i][2]]); + } + } + else { + /* No triangles needed - Free anything allocated previously */ + if (gps->triangles) + MEM_freeN(gps->triangles); + + gps->triangles = NULL; + } + + /* disable recalculation flag */ + if (gps->flag & GP_STROKE_RECALC_CACHES) { + gps->flag &= ~GP_STROKE_RECALC_CACHES; + } + + /* clear memory */ + MEM_SAFE_FREE(tmp_triangles); + MEM_SAFE_FREE(points2d); + MEM_SAFE_FREE(uv); +} + +/* draw stroke in drawing buffer */ +void DRW_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; + Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); + 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_get_material_from_brush(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_material_gpencil_settings_get(ob, ob->actcol); + } + + /* 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 (ED_gpencil_session_active() && (gpd->runtime.sbuffer_size > 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; + /* if only one point, don't need to draw buffer because the user has no time to see it */ + if (gpd->runtime.sbuffer_size > 1) { + if ((gp_style) && (gp_style->mode == GP_STYLE_MODE_LINE)) { + stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_stroke_create( + e_data, vedata, psl->drawing_pass, e_data->gpencil_stroke_sh, NULL, gpd, gp_style, -1, false); + } + else { + stl->g_data->shgrps_drawing_stroke = DRW_gpencil_shgroup_point_create( + e_data, vedata, psl->drawing_pass, e_data->gpencil_point_sh, NULL, gpd, gp_style, -1, false); + } + + /* clean previous version of the batch */ + if (stl->storage->buffer_stroke) { + GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_stroke); + MEM_SAFE_FREE(e_data->batch_buffer_stroke); + stl->storage->buffer_stroke = false; + } + + /* use unit matrix because the buffer is in screen space and does not need conversion */ + if (gpd->runtime.mode == GP_STYLE_MODE_LINE) { + e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_stroke_geom( + gpd, lthick); + } + else { + e_data->batch_buffer_stroke = DRW_gpencil_get_buffer_point_geom( + gpd, lthick); + } + + if (gp_style->flag & GP_STYLE_STROKE_SHOW) { + DRW_shgroup_call_add( + stl->g_data->shgrps_drawing_stroke, + e_data->batch_buffer_stroke, + stl->storage->unit_matrix); + } + + if ((gpd->runtime.sbuffer_size >= 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); + + /* clean previous version of the batch */ + if (stl->storage->buffer_fill) { + GPU_BATCH_DISCARD_SAFE(e_data->batch_buffer_fill); + MEM_SAFE_FREE(e_data->batch_buffer_fill); + stl->storage->buffer_fill = false; + } + + e_data->batch_buffer_fill = DRW_gpencil_get_buffer_fill_geom(gpd); + DRW_shgroup_call_add( + stl->g_data->shgrps_drawing_fill, + e_data->batch_buffer_fill, + stl->storage->unit_matrix); + stl->storage->buffer_fill = true; + } + stl->storage->buffer_stroke = true; + } + } + } +} + +/* create all missing batches */ +static void DRW_gpencil_create_batches(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 DRW_gpencil_shgroups_create( + GPENCIL_e_data *e_data, void *vedata, + Object *ob, bGPdata *gpd, + GpencilBatchCache *cache, tGPencilObjectCache *cache_ob) +{ + GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; + GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; + DRWShadingGroup *shgrp = NULL; + + int start_stroke = 0; + int start_point = 0; + int start_fill = 0; + int start_edit = 0; + int start_edlin = 0; + + cache_ob->init_grp = NULL; + cache_ob->end_grp = NULL; + + for (int i = 0; i < cache->grp_used; i++) { + GpencilBatchGroup *elm = &cache->grp_cache[i]; + bGPDlayer *gpl = elm->gpl; + bGPDframe *gpf = elm->gpf; + bGPDstroke *gps = elm->gps; + MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); + + /* limit the number of shading groups */ + if (i >= GPENCIL_MAX_SHGROUPS) { + break; + } + + switch (elm->type) { + case eGpencilBatchGroupType_Stroke: + { + const int len = elm->vertex_idx - start_stroke; + + shgrp = DRW_gpencil_shgroup_stroke_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_stroke_sh, + ob, gpd, gp_style, stl->storage->shgroup_id, elm->onion); + + DRW_shgroup_call_range_add( + shgrp, cache->b_stroke.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, + 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 = DRW_gpencil_shgroup_point_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_point_sh, + ob, gpd, gp_style, stl->storage->shgroup_id, elm->onion); + + DRW_shgroup_call_range_add( + shgrp, cache->b_point.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, + 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 = DRW_gpencil_shgroup_fill_create( + e_data, vedata, psl->stroke_pass, e_data->gpencil_fill_sh, + gpd, gpl, gp_style, stl->storage->shgroup_id); + + DRW_shgroup_call_range_add( + shgrp, cache->b_fill.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, + start_fill, len); + + stl->storage->shgroup_id++; + start_fill = elm->vertex_idx; + break; + } + case eGpencilBatchGroupType_Edit: + { + const int len = elm->vertex_idx - start_edit; + /* use always the same group */ + DRW_shgroup_call_range_add( + stl->g_data->shgrps_edit_point, + cache->b_edit.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, + start_edit, len); + + start_edit = elm->vertex_idx; + break; + } + case eGpencilBatchGroupType_Edlin: + { + const int len = elm->vertex_idx - start_edlin; + /* use always the same group */ + DRW_shgroup_call_range_add( + stl->g_data->shgrps_edit_line, + cache->b_edlin.batch, + (!cache_ob->is_dup_ob) ? gpf->runtime.viewmatrix : cache_ob->obmat, + start_edlin, len); + + start_edlin = elm->vertex_idx; + break; + } + default: + { + break; + } + } + /* save first group */ + if ((shgrp != NULL) && (cache_ob->init_grp == NULL)) { + cache_ob->init_grp = shgrp; + } + } + + /* save last group */ + if (shgrp != NULL) { + cache_ob->end_grp = shgrp; + } +} /* populate a datablock for multiedit (no onions, no modifiers) */ void DRW_gpencil_populate_multiedit( - GPENCIL_e_data *e_data, void *vedata, Scene *scene, Object *ob, + GPENCIL_e_data *e_data, void *vedata, Object *ob, tGPencilObjectCache *cache_ob) { bGPdata *gpd = (bGPdata *)ob->data; @@ -1195,12 +1386,15 @@ void DRW_gpencil_populate_multiedit( const DRWContextState *draw_ctx = DRW_context_state_get(); int cfra_eval = (int)DEG_get_ctime(draw_ctx->depsgraph); GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval); + Scene *scene = draw_ctx->scene; ToolSettings *ts = scene->toolsettings; - cache->cache_idx = 0; /* check if playing animation */ bool playing = stl->storage->is_playing; + /* calc max size of VBOs */ + gpencil_calc_vertex(stl, cache_ob, cache, gpd, cfra_eval); + /* draw strokes */ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* don't draw layer if hidden */ @@ -1228,36 +1422,23 @@ void DRW_gpencil_populate_multiedit( } - cache->is_dirty = false; -} - -static void gpencil_copy_frame(bGPDframe *gpf, bGPDframe *derived_gpf) -{ - derived_gpf->prev = gpf->prev; - derived_gpf->next = gpf->next; - derived_gpf->framenum = gpf->framenum; - derived_gpf->flag = gpf->flag; - derived_gpf->key_type = gpf->key_type; - derived_gpf->runtime = gpf->runtime; + /* create batchs and shading groups */ + DRW_gpencil_create_batches(cache); + DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); - /* copy strokes */ - BLI_listbase_clear(&derived_gpf->strokes); - for (bGPDstroke *gps_src = gpf->strokes.first; gps_src; gps_src = gps_src->next) { - /* make copy of source stroke */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src); - BLI_addtail(&derived_gpf->strokes, gps_dst); - } + cache->is_dirty = false; } /* helper for populate a complete grease pencil datablock */ void DRW_gpencil_populate_datablock( GPENCIL_e_data *e_data, void *vedata, - Scene *scene, Object *ob, + 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; bGPdata *gpd_eval = (bGPdata *)ob->data; bGPdata *gpd = (bGPdata *)DEG_get_original_id(&gpd_eval->id); @@ -1273,7 +1454,6 @@ void DRW_gpencil_populate_datablock( const bool time_remap = BKE_gpencil_has_time_modifiers(ob); float opacity; - bGPDframe *p = NULL; bGPDframe *gpf = NULL; bGPDlayer *gpl_active = BKE_gpencil_layer_getactive(gpd); @@ -1281,7 +1461,15 @@ void DRW_gpencil_populate_datablock( bool playing = stl->storage->is_playing; GpencilBatchCache *cache = gpencil_batch_cache_get(ob, cfra_eval); - cache->cache_idx = 0; + + /* if object is duplicate, only create shading groups */ + if (cache_ob->is_dup_ob) { + DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); + return; + } + + /* calc max size of VBOs */ + gpencil_calc_vertex(stl, cache_ob, cache, gpd, cfra_eval); /* init general modifiers data */ if (!stl->storage->simplify_modif) { @@ -1302,16 +1490,15 @@ void DRW_gpencil_populate_datablock( } } - if ((!time_remap) || (stl->storage->simplify_modif)) { - gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV); + /* 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); } - else { - int 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); - } + gpf = BKE_gpencil_layer_getframe(gpl, remap_cfra, GP_GETFRAME_USE_PREV); if (gpf == NULL) continue; @@ -1331,24 +1518,9 @@ void DRW_gpencil_populate_datablock( opacity = opacity * v3d->overlay.gpencil_fade_layer; } - /* create derived array data or expand */ - if (cache_ob->data_idx + 1 > gpl->runtime.len_derived) { - if ((gpl->runtime.len_derived == 0) || - (gpl->runtime.derived_array == NULL)) - { - p = MEM_callocN(sizeof(struct bGPDframe), "bGPDframe array"); - gpl->runtime.len_derived = 1; - } - else { - gpl->runtime.len_derived++; - p = MEM_recallocN(gpl->runtime.derived_array, sizeof(struct bGPDframe) * gpl->runtime.len_derived); - } - gpl->runtime.derived_array = p; - - derived_gpf = &gpl->runtime.derived_array[cache_ob->data_idx]; - } - - derived_gpf = &gpl->runtime.derived_array[cache_ob->data_idx]; + /* create derived frames array data or expand */ + int derived_idx = BLI_findindex(&gpd->layers, gpl); + derived_gpf = &cache->derived_array[derived_idx]; /* if no derived frame or dirty cache, create a new one */ if ((derived_gpf == NULL) || (cache->is_dirty)) { @@ -1362,8 +1534,7 @@ void DRW_gpencil_populate_datablock( /* draw onion skins */ if (!ID_IS_LINKED(&gpd->id)) { - if ((!cache_ob->is_dup_data) && - (gpd->flag & GP_DATA_SHOW_ONIONSKINS) && + if ((gpd->flag & GP_DATA_SHOW_ONIONSKINS) && (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)) @@ -1376,18 +1547,9 @@ void DRW_gpencil_populate_datablock( } } /* draw normal strokes */ - if (!cache_ob->is_dup_ob) { - /* save batch index */ - gpl->runtime.batch_index = cache->cache_idx; - } - else { - cache->cache_idx = gpl->runtime.batch_index; - } - gpencil_draw_strokes( cache, e_data, vedata, ts, ob, gpd, gpl, gpf, derived_gpf, opacity, gpl->tintcolor, false, cache_ob); - } /* clear any lattice data */ @@ -1395,5 +1557,25 @@ void DRW_gpencil_populate_datablock( BKE_gpencil_lattice_clear(ob); } + /* create batchs and shading groups */ + DRW_gpencil_create_batches(cache); + DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); + cache->is_dirty = false; } + +void DRW_gpencil_populate_particles(GPENCIL_e_data *e_data, 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]; + Object *ob = cache_ob->ob; + if (cache_ob->is_dup_ob) { + bGPdata *gpd = (bGPdata *)ob->data; + GpencilBatchCache *cache = ob->runtime.gpencil_cache; + DRW_gpencil_shgroups_create(e_data, vedata, ob, gpd, cache, cache_ob); + } + } +} diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 52cd79e4394..7be06d501f1 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -315,9 +315,6 @@ void GPENCIL_cache_init(void *vedata) if (!stl->shgroups) { /* Alloc maximum size because count strokes is very slow and can be very complex due onion skinning. - I tried to allocate only one block and using realloc, increasing the size when read a new strokes - in cache_finish, but the realloc produce weird things on screen, so we keep as is while we found - a better solution */ stl->shgroups = MEM_mallocN(sizeof(GPENCIL_shgroup) * GPENCIL_MAX_SHGROUPS, "GPENCIL_shgroup"); } @@ -498,28 +495,22 @@ void GPENCIL_cache_init(void *vedata) static void gpencil_add_draw_data(void *vedata, Object *ob) { GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; bGPdata *gpd = (bGPdata *)ob->data; const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); int i = stl->g_data->gp_cache_used - 1; tGPencilObjectCache *cache_ob = &stl->g_data->gp_object_cache[i]; - /* save init shading group */ - cache_ob->init_grp = stl->storage->shgroup_id; - - /* fill shading groups */ - if ((!is_multiedit) || (cache_ob->is_dup_ob)) { - DRW_gpencil_populate_datablock(&e_data, vedata, scene, ob, cache_ob); - } - else { - DRW_gpencil_populate_multiedit(&e_data, vedata, scene, ob, cache_ob); + if (!cache_ob->is_dup_ob) { + /* fill shading groups */ + if (!is_multiedit) { + DRW_gpencil_populate_datablock(&e_data, vedata, ob, cache_ob); + } + else { + DRW_gpencil_populate_multiedit(&e_data, vedata, ob, cache_ob); + } } - /* save end shading group */ - cache_ob->end_grp = stl->storage->shgroup_id - 1; - /* FX passses */ cache_ob->has_fx = false; if ((!stl->storage->simplify_fx) && @@ -549,25 +540,12 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) if (ob->type == OB_GPENCIL && ob->data) { bGPdata *gpd = (bGPdata *)ob->data; - /* if onion, set as dirty always - * This reduces performance, but avoid any crash in the multiple - * overlay and multiwindow options - */ - if (gpd->flag & GP_DATA_SHOW_ONIONSKINS) { - gpd->flag |= GP_DATA_CACHE_IS_DIRTY; - } - /* 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; } - /* is edit mode only current object, not particle instances */ - if ((ob->base_flag & BASE_FROMDUPLI) && GPENCIL_ANY_EDIT_MODE(gpd)) { - return; - } - if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) { /* save gp objects for drawing later */ @@ -618,10 +596,9 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) } } -void GPENCIL_cache_finish(void *UNUSED(vedata)) +void GPENCIL_cache_finish(void *vedata) { - return; - + DRW_gpencil_populate_particles(&e_data, vedata); } /* helper function to sort inverse gpencil objects using qsort */ @@ -657,6 +634,13 @@ static void gpencil_prepare_fast_drawing( static void gpencil_free_obj_runtime(GPENCIL_StorageList *stl) { + /* 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]; + bGPdata *gpd = cache_ob->gpd; + gpd->flag &= ~GP_DATA_CACHE_IS_DIRTY; + } + /* free the cache itself */ MEM_SAFE_FREE(stl->g_data->gp_object_cache); } @@ -672,7 +656,6 @@ void GPENCIL_draw_scene(void *ved) DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); GPENCIL_TextureList *txl = ((GPENCIL_Data *)vedata)->txl; - int init_grp, end_grp; tGPencilObjectCache *cache_ob; const float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; @@ -729,33 +712,27 @@ void GPENCIL_draw_scene(void *ved) for (int i = 0; i < stl->g_data->gp_cache_used; i++) { cache_ob = &stl->g_data->gp_object_cache[i]; bGPdata *gpd = cache_ob->gpd; - init_grp = cache_ob->init_grp; - end_grp = cache_ob->end_grp; /* Render stroke in separated framebuffer */ GPU_framebuffer_bind(fbl->temp_fb_a); GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f); - /* Stroke Pass: DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH - * draw only a subset that usually start with a fill and end with stroke because the - * shading groups are created by pairs */ - if (end_grp >= init_grp) { + /* Stroke Pass: + * draw only a subset that usually starts with a fill and ends with stroke + */ + if (cache_ob->init_grp) { /* previews don't use AA */ if (!stl->storage->is_mat_preview) { MULTISAMPLE_GP_SYNC_ENABLE(stl->storage->multisamples, fbl); } DRW_draw_pass_subset( - psl->stroke_pass, - stl->shgroups[init_grp].shgrps_fill != NULL ? - stl->shgroups[init_grp].shgrps_fill : stl->shgroups[init_grp].shgrps_stroke, - stl->shgroups[end_grp].shgrps_stroke); + psl->stroke_pass, cache_ob->init_grp, cache_ob->end_grp); if (!stl->storage->is_mat_preview) { MULTISAMPLE_GP_SYNC_DISABLE(stl->storage->multisamples, fbl, fbl->temp_fb_a, txl); } } - /* Current buffer drawing */ if ((!is_render) && (cache_ob->is_dup_ob == false)) { DRW_draw_pass(psl->drawing_pass); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 8e68fdef952..0fe25ba9f0f 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -40,7 +40,10 @@ struct RenderLayer; #define GPENCIL_CACHE_BLOCK_SIZE 8 #define GPENCIL_MAX_SHGROUPS 65536 -#define GPENCIL_MIN_BATCH_SLOTS_CHUNK 16 +#define GPENCIL_GROUPS_BLOCK_SIZE 1024 + +/* 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 @@ -60,7 +63,8 @@ struct RenderLayer; typedef struct tGPencilObjectCache { struct Object *ob; struct bGPdata *gpd; - int init_grp, end_grp; + DRWShadingGroup *init_grp; + DRWShadingGroup *end_grp; int idx; /*original index, can change after sort */ /* effects */ @@ -82,8 +86,10 @@ typedef struct tGPencilObjectCache { float obmat[4][4]; float zdepth; /* z-depth value to sort gp object */ bool is_dup_ob; /* flag to tag duplicate objects */ - bool is_dup_data; /* other object uses datablock already */ - int data_idx; /* derived data index */ + + /* GPU data size */ + int tot_vertex; + int tot_triangles; } tGPencilObjectCache; /* *********** LISTS *********** */ @@ -98,8 +104,6 @@ typedef struct GPENCIL_shgroup { int fill_style; int keep_size; float obj_scale; - struct DRWShadingGroup *shgrps_fill; - struct DRWShadingGroup *shgrps_stroke; } GPENCIL_shgroup; typedef struct GPENCIL_Storage { @@ -276,24 +280,57 @@ typedef struct GPENCIL_e_data { } GPENCIL_e_data; /* Engine data */ /* GPUBatch Cache */ +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; + + /* size for VBO alloc */ + int tot_vertex; +} GpencilBatchCacheElem; + +typedef struct GpencilBatchGroup { + bGPDlayer *gpl; /* reference to original layer */ + bGPDframe *gpf; /* reference to original frame */ + 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; + typedef struct GpencilBatchCache { - /* For normal strokes, a variable number of batch can be needed depending of number of strokes. - It could use the stroke number as total size, but when activate the onion skining, the number - can change, so the size is changed dynamically. - */ - GPUBatch **batch_stroke; - GPUBatch **batch_fill; - GPUBatch **batch_edit; - GPUBatch **batch_edlin; + GpencilBatchCacheElem b_stroke; + GpencilBatchCacheElem b_point; + GpencilBatchCacheElem b_fill; + GpencilBatchCacheElem b_edit; + GpencilBatchCacheElem b_edlin; /* settings to determine if cache is invalid */ bool is_dirty; bool is_editmode; int cache_frame; - /* keep information about the size of the cache */ - int cache_size; /* total batch slots available */ - int cache_idx; /* current slot index */ + /* data with the shading groups */ + int grp_used; /* total groups in arrays */ + int grp_size; /* max size of the array */ + struct GpencilBatchGroup *grp_cache; /* array of elements */ + + int tot_layers; + struct bGPDframe *derived_array; /* runtime data created by modifiers */ } GpencilBatchCache; /* general drawing functions */ @@ -302,23 +339,24 @@ struct DRWShadingGroup *DRW_gpencil_shgroup_stroke_create( struct Object *ob, struct bGPdata *gpd, struct MaterialGPencilStyle *gp_style, int id, bool onion); void DRW_gpencil_populate_datablock( struct GPENCIL_e_data *e_data, void *vedata, - struct Scene *scene, struct Object *ob, struct tGPencilObjectCache *cache_ob); void DRW_gpencil_populate_buffer_strokes( struct GPENCIL_e_data *e_data, void *vedata, struct ToolSettings *ts, struct Object *ob); void DRW_gpencil_populate_multiedit( struct GPENCIL_e_data *e_data, void *vedata, - struct Scene *scene, struct Object *ob, struct tGPencilObjectCache *cache_ob); + struct Object *ob, struct tGPencilObjectCache *cache_ob); void DRW_gpencil_triangulate_stroke_fill(struct Object *ob, struct bGPDstroke *gps); +void DRW_gpencil_populate_particles(struct GPENCIL_e_data *e_data, void *vedata); void DRW_gpencil_multisample_ensure(struct GPENCIL_Data *vedata, int rect_w, int rect_h); /* create geometry functions */ -struct GPUBatch *DRW_gpencil_get_point_geom(struct bGPDstroke *gps, short thickness, const float ink[4]); -struct GPUBatch *DRW_gpencil_get_stroke_geom(struct bGPDstroke *gps, short thickness, const float ink[4]); -struct GPUBatch *DRW_gpencil_get_fill_geom(struct Object *ob, struct bGPDstroke *gps, const float color[4]); -struct GPUBatch *DRW_gpencil_get_edit_geom(struct bGPDstroke *gps, float alpha, short dflag); -struct GPUBatch *DRW_gpencil_get_edlin_geom(struct bGPDstroke *gps, float alpha, short dflag); +void DRW_gpencil_get_point_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, const float ink[4]); +void DRW_gpencil_get_stroke_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, short thickness, const float ink[4]); +void DRW_gpencil_get_fill_geom(struct GpencilBatchCacheElem *be, struct Object *ob, struct bGPDstroke *gps, const float color[4]); +void DRW_gpencil_get_edit_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, float alpha, short dflag); +void DRW_gpencil_get_edlin_geom(struct GpencilBatchCacheElem *be, struct bGPDstroke *gps, float alpha, short dflag); + struct GPUBatch *DRW_gpencil_get_buffer_stroke_geom(struct bGPdata *gpd, short thickness); struct GPUBatch *DRW_gpencil_get_buffer_fill_geom(struct bGPdata *gpd); struct GPUBatch *DRW_gpencil_get_buffer_point_geom(struct bGPdata *gpd, short thickness); @@ -329,8 +367,15 @@ struct tGPencilObjectCache *gpencil_object_cache_add( struct tGPencilObjectCache *cache_array, struct Object *ob, int *gp_cache_size, int *gp_cache_used); +/* 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); + /* geometry batch cache functions */ -void gpencil_batch_cache_check_free_slots(struct Object *ob); struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra); /* effects */ diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 20100354070..b7568ce20dd 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -479,8 +479,6 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op) /* make copy of layer */ bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src); gpl_dst->prev = gpl_dst->next = NULL; - gpl_dst->runtime.derived_array = NULL; - gpl_dst->runtime.len_derived = 0; BLI_addtail(&gpd_dst->layers, gpl_dst); BLI_uniquename(&gpd_dst->layers, gpl_dst, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl_dst->info)); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index db4ff053537..5078d071dd8 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -1844,7 +1844,9 @@ void ED_gpencil_calc_stroke_uv(Object *ob, bGPDstroke *gps) float factor; /* if image, use texture width */ - if ((gp_style) && (gp_style->sima)) { + if ((gp_style) && (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE) && + (gp_style->sima)) + { factor = gp_style->sima->gen_x; } else if (totlen == 0) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index 69a48a2c93b..55728ca581f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -203,4 +203,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Armature = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index 0d0ce7476b9..553d9087c3f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -315,6 +315,13 @@ static void foreachObjectLink( walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } +static int getDuplicationFactor(GpencilModifierData *md) +{ + ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md; + int t = mmd->count; + CLAMP_MIN(t, 1); + return t; +} GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* name */ "Array", @@ -338,4 +345,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Array = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index e2a257fcb43..ba814c8538a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -553,4 +553,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index 4c1418fe0e3..94c5e9ddbdf 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -164,4 +164,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index 1ec6103939a..97f260f307f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -353,4 +353,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index d9ec81b70b9..1d8f2c20b59 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -211,4 +211,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 9c3d3dc9235..7599e7e9bce 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -189,6 +189,21 @@ static void foreachObjectLink( walk(userData, ob, &mmd->object, IDWALK_CB_NOP); } +static int getDuplicationFactor(GpencilModifierData *md) +{ + MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; + int factor = 1; + /* create a duplication for each axis */ + for (int xi = 0; xi < 3; ++xi) { + if (mmd->flag & (GP_MIRROR_AXIS_X << xi)) { + factor++; + } + } + CLAMP_MIN(factor, 1); + + return factor; +} + GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* name */ "Mirror", /* structName */ "MirrorGpencilModifierData", @@ -211,4 +226,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Mirror = { /* foreachObjectLink */ foreachObjectLink, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 399ff27eafb..097b5702721 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -285,4 +285,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 43af4b94c15..2c2a5c2f994 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -143,4 +143,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index b89c3792455..7033b246e1c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -183,4 +183,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index 2d0b90e6de7..6ddf40df6c0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -123,4 +123,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index 8d93980a9d0..ece7ebc9816 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -150,4 +150,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index 38aa4159632..71881de50fc 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -97,6 +97,14 @@ static void bakeModifier( } } +static int getDuplicationFactor(GpencilModifierData *md) +{ + SubdivGpencilModifierData *mmd = (SubdivGpencilModifierData *)md; + int t = (mmd->level + 1) * (mmd->level + 1); + CLAMP_MIN(t, 2); + return t; +} + GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* name */ "Subdivision", /* structName */ "SubdivGpencilModifierData", @@ -119,4 +127,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ getDuplicationFactor, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index 8046545ef71..441cab909d3 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -171,4 +171,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c index e220d5a5e85..d90dea91af9 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c @@ -187,4 +187,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index ba3b2d84861..385296c943e 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -172,4 +172,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = { /* foreachObjectLink */ NULL, /* foreachIDLink */ NULL, /* foreachTexLink */ NULL, + /* getDuplicationFactor */ NULL, }; diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 503ad2f28d9..8a1bccc6957 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -236,10 +236,7 @@ typedef enum eGPDframe_Flag { /* Runtime temp data for bGPDlayer */ typedef struct bGPDlayer_Runtime { - struct bGPDframe *derived_array;/* runtime data created by modifiers */ int icon_id; /* id for dynamic icon used to show annotation color preview for layer */ - int batch_index; /* batch used for dupli instances */ - int len_derived; /* len of the derived array */ char pad_[4]; } bGPDlayer_Runtime; |