GP: Refactor drawing engine to single VBO

This is part of T57829.

Reduce the number of batches used to only one by shader type.  This reduces GPU overhead and increase a lot the FPS. As the number of batches is small, the time to allocate and free memory was reduced in 90% or more.

Also the code has been simplified and all batch management has been removed because this is not necessary. Now, all shading groups are created after all vertex buffer data for all strokes has been created using DRW_shgroup_call_range_add().

All batch cache data has been moved to the Object runtime struct and not as before where some parts (derived data) were saved inside GPD datablock.

For particles, now the code is faster and cleaner and gets better FPS.

Thanks to Clément Foucault for his help and advices to improve speed.
This commit is contained in:
Antonio Vazquez 2018-11-20 19:26:16 +01:00
parent 140d383393
commit e63c947204
28 changed files with 933 additions and 786 deletions

View File

@ -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);

View File

@ -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). */

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;
}
else if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
valid = 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;
}
else if (cache->is_editmode) {
valid = false;
}
else if (cache->is_dirty) {
valid = false;
}
if (gpd->flag & GP_DATA_CACHE_IS_DIRTY) {
return false;
}
if (cache->is_editmode) {
return false;
}
if (cache->is_dirty) {
return 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);
}
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;
}
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);
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);
}
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);
cache->cache_size = 0;
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->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);
}

View File

@ -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);
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);
}
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
GPU_vertbuf_data_alloc(vbo, totpoints + cyclic_add + 2);
/* 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++;
}
}
/* 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);
}
return GPU_batch_create_ex(GPU_PRIM_LINE_STRIP_ADJ, vbo, NULL, GPU_BATCH_OWNS_VBO);
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(

File diff suppressed because it is too large Load Diff

View File

@ -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,27 +495,21 @@ 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);
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);
}
}
else {
DRW_gpencil_populate_multiedit(&e_data, vedata, scene, ob, cache_ob);
}
/* save end shading group */
cache_ob->end_grp = stl->storage->shgroup_id - 1;
/* FX passses */
cache_ob->has_fx = false;
@ -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);

View File

@ -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 */

View File

@ -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));

View File

@ -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) {

View File

@ -203,4 +203,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Armature = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -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,
};

View File

@ -553,4 +553,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Build = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -164,4 +164,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -353,4 +353,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Hook = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -211,4 +211,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Lattice = {
/* foreachObjectLink */ foreachObjectLink,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -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,
};

View File

@ -285,4 +285,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -143,4 +143,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Offset = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -183,4 +183,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -123,4 +123,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Simplify = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -150,4 +150,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -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,
};

View File

@ -171,4 +171,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Thick = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -187,4 +187,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Time = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -172,4 +172,5 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = {
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
/* getDuplicationFactor */ NULL,
};

View File

@ -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;