|
|
|
@@ -53,6 +53,7 @@ extern char datatoc_gpencil_gaussian_blur_frag_glsl[];
|
|
|
|
|
extern char datatoc_gpencil_wave_frag_glsl[];
|
|
|
|
|
extern char datatoc_gpencil_pixel_frag_glsl[];
|
|
|
|
|
extern char datatoc_gpencil_swirl_frag_glsl[];
|
|
|
|
|
extern char datatoc_gpencil_painting_frag_glsl[];
|
|
|
|
|
|
|
|
|
|
/* *********** STATIC *********** */
|
|
|
|
|
static GPENCIL_e_data e_data = {NULL}; /* Engine data */
|
|
|
|
@@ -95,6 +96,16 @@ static void GPENCIL_engine_init(void *vedata)
|
|
|
|
|
(int)viewport_size[0], (int)viewport_size[1],
|
|
|
|
|
vfx_color_b, ARRAY_SIZE(vfx_color_b));
|
|
|
|
|
|
|
|
|
|
/* painting framebuffer to speed up drawing process */
|
|
|
|
|
DRWFboTexture tex_painting[2] = { {
|
|
|
|
|
&e_data.painting_depth_tx, DRW_TEX_DEPTH_24, DRW_TEX_TEMP },
|
|
|
|
|
{ &e_data.painting_color_tx, DRW_TEX_RGBA_16, DRW_TEX_TEMP }
|
|
|
|
|
};
|
|
|
|
|
DRW_framebuffer_init(
|
|
|
|
|
&fbl->painting_fb, &draw_engine_gpencil_type,
|
|
|
|
|
(int)viewport_size[0], (int)viewport_size[1],
|
|
|
|
|
tex_painting, ARRAY_SIZE(tex_painting));
|
|
|
|
|
|
|
|
|
|
/* normal fill shader */
|
|
|
|
|
if (!e_data.gpencil_fill_sh) {
|
|
|
|
|
e_data.gpencil_fill_sh = DRW_shader_create(datatoc_gpencil_fill_vert_glsl, NULL,
|
|
|
|
@@ -155,6 +166,7 @@ static void GPENCIL_engine_free(void)
|
|
|
|
|
DRW_SHADER_FREE_SAFE(e_data.gpencil_vfx_wave_sh);
|
|
|
|
|
DRW_SHADER_FREE_SAFE(e_data.gpencil_vfx_pixel_sh);
|
|
|
|
|
DRW_SHADER_FREE_SAFE(e_data.gpencil_vfx_swirl_sh);
|
|
|
|
|
DRW_SHADER_FREE_SAFE(e_data.gpencil_painting_sh);
|
|
|
|
|
|
|
|
|
|
DRW_TEXTURE_FREE_SAFE(e_data.gpencil_blank_texture);
|
|
|
|
|
}
|
|
|
|
@@ -213,6 +225,9 @@ static void GPENCIL_cache_init(void *vedata)
|
|
|
|
|
if (!e_data.gpencil_vfx_swirl_sh) {
|
|
|
|
|
e_data.gpencil_vfx_swirl_sh = DRW_shader_create_fullscreen(datatoc_gpencil_swirl_frag_glsl, NULL);
|
|
|
|
|
}
|
|
|
|
|
if (!e_data.gpencil_painting_sh) {
|
|
|
|
|
e_data.gpencil_painting_sh = DRW_shader_create_fullscreen(datatoc_gpencil_painting_frag_glsl, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
/* Stroke pass */
|
|
|
|
@@ -240,6 +255,17 @@ static void GPENCIL_cache_init(void *vedata)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* detect if painting session in any datablock */
|
|
|
|
|
if (BKE_gpencil_check_drawing_sessions()) {
|
|
|
|
|
if (stl->g_data->session_flag & GP_DRW_PAINT_IDLE) {
|
|
|
|
|
stl->g_data->session_flag = GP_DRW_PAINT_DIRTY;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* if not drawing, the painting session is idle */
|
|
|
|
|
stl->g_data->session_flag = GP_DRW_PAINT_IDLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ob = draw_ctx->obact;
|
|
|
|
|
if (ob) {
|
|
|
|
|
gpd = ob->gpd;
|
|
|
|
@@ -306,6 +332,14 @@ static void GPENCIL_cache_init(void *vedata)
|
|
|
|
|
psl->vfx_pixel_pass = DRW_pass_create("GPencil VFX Pixel Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
|
|
|
|
|
|
|
|
|
|
psl->vfx_swirl_pass = DRW_pass_create("GPencil VFX Swirl Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
|
|
|
|
|
|
|
|
|
|
/* Painting session pass (used only to speedup while the user is drawing ) */
|
|
|
|
|
struct Gwn_Batch *paintquad = DRW_cache_fullscreen_quad_get();
|
|
|
|
|
psl->painting_pass = DRW_pass_create("GPencil Painting Session Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS);
|
|
|
|
|
DRWShadingGroup *painting_shgrp = DRW_shgroup_create(e_data.gpencil_painting_sh, psl->painting_pass);
|
|
|
|
|
DRW_shgroup_call_add(painting_shgrp, paintquad, NULL);
|
|
|
|
|
DRW_shgroup_uniform_buffer(painting_shgrp, "strokeColor", &e_data.painting_color_tx);
|
|
|
|
|
DRW_shgroup_uniform_buffer(painting_shgrp, "strokeDepth", &e_data.painting_depth_tx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -320,16 +354,18 @@ static void GPENCIL_cache_populate(void *vedata, Object *ob)
|
|
|
|
|
|
|
|
|
|
/* object datablock (this is not draw now) */
|
|
|
|
|
if (ob->type == OB_GPENCIL && ob->gpd) {
|
|
|
|
|
if (G.debug_value == 668) {
|
|
|
|
|
printf("GPENCIL_cache_populate: %s\n", ob->id.name);
|
|
|
|
|
}
|
|
|
|
|
/* allocate memory for saving gp objects */
|
|
|
|
|
stl->g_data->gp_object_cache = gpencil_object_cache_allocate(stl->g_data->gp_object_cache, &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used);
|
|
|
|
|
/* add for drawing later */
|
|
|
|
|
gpencil_object_cache_add(stl->g_data->gp_object_cache, ob, &stl->g_data->gp_cache_used);
|
|
|
|
|
/* generate duplicated instances using array modifiers */
|
|
|
|
|
if (!GP_SIMPLIFY_MODIF(ts, playing)) {
|
|
|
|
|
gpencil_array_modifiers(stl, ob);
|
|
|
|
|
if ((stl->g_data->session_flag & GP_DRW_PAINT_READY) == 0) {
|
|
|
|
|
if (G.debug_value == 668) {
|
|
|
|
|
printf("GPENCIL_cache_populate: %s\n", ob->id.name);
|
|
|
|
|
}
|
|
|
|
|
/* allocate memory for saving gp objects */
|
|
|
|
|
stl->g_data->gp_object_cache = gpencil_object_cache_allocate(stl->g_data->gp_object_cache, &stl->g_data->gp_cache_size, &stl->g_data->gp_cache_used);
|
|
|
|
|
/* add for drawing later */
|
|
|
|
|
gpencil_object_cache_add(stl->g_data->gp_object_cache, ob, &stl->g_data->gp_cache_used);
|
|
|
|
|
/* generate duplicated instances using array modifiers */
|
|
|
|
|
if (!GP_SIMPLIFY_MODIF(ts, playing)) {
|
|
|
|
|
gpencil_array_modifiers(stl, ob);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* draw current painting strokes */
|
|
|
|
|
DRW_gpencil_populate_buffer_strokes(vedata, ts, ob);
|
|
|
|
@@ -346,6 +382,11 @@ static void GPENCIL_cache_finish(void *vedata)
|
|
|
|
|
bool is_multiedit = false;
|
|
|
|
|
bool playing = (bool)stl->storage->playing;
|
|
|
|
|
|
|
|
|
|
/* if painting session is ready, don't need to do more */
|
|
|
|
|
if (stl->g_data->session_flag & GP_DRW_PAINT_READY) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Draw all pending objects */
|
|
|
|
|
if (stl->g_data->gp_cache_used > 0) {
|
|
|
|
|
for (int i = 0; i < stl->g_data->gp_cache_used; ++i) {
|
|
|
|
@@ -476,11 +517,6 @@ static void gpencil_vfx_passes(void *vedata, tGPencilObjectCache *cache)
|
|
|
|
|
DRW_framebuffer_clear(true, true, false, clearcol, 1.0f);
|
|
|
|
|
DRW_draw_pass(psl->vfx_copy_pass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Combine with default scene buffer always using tx_a as source texture */
|
|
|
|
|
DRW_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
/* Mix VFX Pass */
|
|
|
|
|
DRW_draw_pass(psl->mix_vfx_pass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void GPENCIL_draw_scene(void *vedata)
|
|
|
|
@@ -509,56 +545,85 @@ static void GPENCIL_draw_scene(void *vedata)
|
|
|
|
|
DRW_framebuffer_texture_attach(fbl->vfx_color_fb_b, e_data.vfx_fbcolor_depth_tx_b, 0, 0);
|
|
|
|
|
DRW_framebuffer_texture_attach(fbl->vfx_color_fb_b, e_data.vfx_fbcolor_color_tx_b, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* Draw all pending objects */
|
|
|
|
|
if (stl->g_data->gp_cache_used > 0) {
|
|
|
|
|
DRW_framebuffer_texture_attach(fbl->painting_fb, e_data.painting_depth_tx, 0, 0);
|
|
|
|
|
DRW_framebuffer_texture_attach(fbl->painting_fb, e_data.painting_color_tx, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* sort by zdepth */
|
|
|
|
|
qsort(stl->g_data->gp_object_cache, stl->g_data->gp_cache_used,
|
|
|
|
|
sizeof(tGPencilObjectCache), gpencil_object_cache_compare_zdepth);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < stl->g_data->gp_cache_used; ++i) {
|
|
|
|
|
cache = &stl->g_data->gp_object_cache[i];
|
|
|
|
|
Object *ob = cache->ob;
|
|
|
|
|
init_grp = cache->init_grp;
|
|
|
|
|
end_grp = cache->end_grp;
|
|
|
|
|
/* Render stroke in separated framebuffer */
|
|
|
|
|
DRW_framebuffer_bind(fbl->temp_color_fb);
|
|
|
|
|
DRW_framebuffer_clear(true, true, false, 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 (G.debug_value == 668) {
|
|
|
|
|
printf("GPENCIL_draw_scene: %s %d->%d\n", ob->id.name, init_grp, end_grp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (end_grp >= init_grp) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
/* Current buffer drawing */
|
|
|
|
|
if (ob->gpd->sbuffer_size > 0) {
|
|
|
|
|
DRW_draw_pass(psl->drawing_pass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* vfx modifiers passes
|
|
|
|
|
* if any vfx modifier exist, the init_vfx_wave_sh will be not NULL.
|
|
|
|
|
*/
|
|
|
|
|
if ((cache->init_vfx_wave_sh) && (cache->end_vfx_wave_sh) && (!GP_SIMPLIFY_VFX(ts, playing))) {
|
|
|
|
|
/* add vfx and combine result with default framebuffer */
|
|
|
|
|
gpencil_vfx_passes(vedata, cache);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Combine with scene buffer without more passes */
|
|
|
|
|
DRW_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
/* Mix Pass: DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS */
|
|
|
|
|
DRW_draw_pass(psl->mix_pass);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* edit points */
|
|
|
|
|
DRW_draw_pass(psl->edit_pass);
|
|
|
|
|
/* if we have a painting session, we use fast viewport drawing method */
|
|
|
|
|
if (stl->g_data->session_flag & GP_DRW_PAINT_READY) {
|
|
|
|
|
DRW_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
DRW_draw_pass(psl->painting_pass);
|
|
|
|
|
DRW_draw_pass(psl->drawing_pass);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Draw all pending objects */
|
|
|
|
|
if (stl->g_data->gp_cache_used > 0) {
|
|
|
|
|
|
|
|
|
|
/* sort by zdepth */
|
|
|
|
|
qsort(stl->g_data->gp_object_cache, stl->g_data->gp_cache_used,
|
|
|
|
|
sizeof(tGPencilObjectCache), gpencil_object_cache_compare_zdepth);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < stl->g_data->gp_cache_used; ++i) {
|
|
|
|
|
cache = &stl->g_data->gp_object_cache[i];
|
|
|
|
|
Object *ob = cache->ob;
|
|
|
|
|
init_grp = cache->init_grp;
|
|
|
|
|
end_grp = cache->end_grp;
|
|
|
|
|
/* Render stroke in separated framebuffer */
|
|
|
|
|
DRW_framebuffer_bind(fbl->temp_color_fb);
|
|
|
|
|
DRW_framebuffer_clear(true, true, false, 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 (G.debug_value == 668) {
|
|
|
|
|
printf("GPENCIL_draw_scene: %s %d->%d\n", ob->id.name, init_grp, end_grp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (end_grp >= init_grp) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
/* Current buffer drawing */
|
|
|
|
|
if (ob->gpd->sbuffer_size > 0) {
|
|
|
|
|
DRW_draw_pass(psl->drawing_pass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* vfx modifiers passes
|
|
|
|
|
* if any vfx modifier exist, the init_vfx_wave_sh will be not NULL.
|
|
|
|
|
*/
|
|
|
|
|
if ((cache->init_vfx_wave_sh) && (cache->end_vfx_wave_sh) && (!GP_SIMPLIFY_VFX(ts, playing))) {
|
|
|
|
|
/* add vfx and combine result with default framebuffer */
|
|
|
|
|
gpencil_vfx_passes(vedata, cache);
|
|
|
|
|
/* Combine with default scene buffer always using tx_a as source texture */
|
|
|
|
|
DRW_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
/* Mix VFX Pass */
|
|
|
|
|
DRW_draw_pass(psl->mix_vfx_pass);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Combine with scene buffer without more passes */
|
|
|
|
|
DRW_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
/* Mix Pass: DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS */
|
|
|
|
|
DRW_draw_pass(psl->mix_pass);
|
|
|
|
|
if (stl->g_data->session_flag & (GP_DRW_PAINT_DIRTY | GP_DRW_PAINT_FILLING)) {
|
|
|
|
|
DRW_framebuffer_bind(fbl->painting_fb);
|
|
|
|
|
/* clean only in first loop cycle */
|
|
|
|
|
if (stl->g_data->session_flag & GP_DRW_PAINT_DIRTY) {
|
|
|
|
|
DRW_framebuffer_clear(true, true, false, clearcol, 1.0f);
|
|
|
|
|
stl->g_data->session_flag = GP_DRW_PAINT_FILLING;
|
|
|
|
|
}
|
|
|
|
|
/* repeat pass to fill temp texture */
|
|
|
|
|
DRW_draw_pass(psl->mix_pass);
|
|
|
|
|
/* set default framebuffer again */
|
|
|
|
|
DRW_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* edit points */
|
|
|
|
|
DRW_draw_pass(psl->edit_pass);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* free memory */
|
|
|
|
|
/* clear temp objects created for display only */
|
|
|
|
|
for (int i = 0; i < stl->g_data->gp_cache_used; ++i) {
|
|
|
|
@@ -580,8 +645,17 @@ static void GPENCIL_draw_scene(void *vedata)
|
|
|
|
|
DRW_framebuffer_texture_detach(e_data.vfx_fbcolor_depth_tx_b);
|
|
|
|
|
DRW_framebuffer_texture_detach(e_data.vfx_fbcolor_color_tx_b);
|
|
|
|
|
|
|
|
|
|
DRW_framebuffer_texture_detach(e_data.painting_depth_tx);
|
|
|
|
|
DRW_framebuffer_texture_detach(e_data.painting_color_tx);
|
|
|
|
|
|
|
|
|
|
/* attach again default framebuffer after detach textures */
|
|
|
|
|
DRW_framebuffer_bind(dfbl->default_fb);
|
|
|
|
|
|
|
|
|
|
/* the temp texture is ready. Now we can use fast screen drawing */
|
|
|
|
|
if (stl->g_data->session_flag & GP_DRW_PAINT_FILLING) {
|
|
|
|
|
stl->g_data->session_flag = GP_DRW_PAINT_READY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const DrawEngineDataSize GPENCIL_data_size = DRW_VIEWPORT_DATA_SIZE(GPENCIL_Data);
|
|
|
|
|