Changeset View
Changeset View
Standalone View
Standalone View
source/blender/draw/engines/gpencil/gpencil_shader_fx.c
- This file was added.
| /* | |||||
| * Copyright 2017, Blender Foundation. | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License | |||||
| * as published by the Free Software Foundation; either version 2 | |||||
| * of the License, or (at your option) any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU General Public License | |||||
| * along with this program; if not, write to the Free Software Foundation, | |||||
| * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
| * | |||||
| * Contributor(s): Antonio Vazquez | |||||
| * | |||||
| */ | |||||
| /** \file blender/draw/engines/gpencil/gpencil_shader_fx.c | |||||
| * \ingroup draw | |||||
| */ | |||||
| #include "DNA_gpencil_types.h" | |||||
| #include "DNA_shader_fx_types.h" | |||||
| #include "DNA_screen_types.h" | |||||
| #include "DNA_view3d_types.h" | |||||
| #include "DNA_camera_types.h" | |||||
| #include "BKE_gpencil.h" | |||||
| #include "BKE_shader_fx.h" | |||||
| #include "DRW_engine.h" | |||||
| #include "DRW_render.h" | |||||
| #include "BKE_camera.h" | |||||
| #include "ED_view3d.h" | |||||
| #include "ED_gpencil.h" | |||||
| #include "gpencil_engine.h" | |||||
| extern char datatoc_gpencil_fx_blur_frag_glsl[]; | |||||
| extern char datatoc_gpencil_fx_flip_frag_glsl[]; | |||||
| extern char datatoc_gpencil_fx_light_frag_glsl[]; | |||||
| extern char datatoc_gpencil_fx_pixel_frag_glsl[]; | |||||
| extern char datatoc_gpencil_fx_swirl_frag_glsl[]; | |||||
| extern char datatoc_gpencil_fx_wave_frag_glsl[]; | |||||
| /* verify if this fx is active */ | |||||
| static bool effect_is_active(Object *ob, ShaderFxData *fx, bool is_render) | |||||
| { | |||||
| if (fx == NULL) { | |||||
| return false; | |||||
| } | |||||
| bGPdata *gpd = ob->data; | |||||
| if (gpd == NULL) { | |||||
| return false; | |||||
| } | |||||
| bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd); | |||||
| if (((fx->mode & eShaderFxMode_Editmode) == 0) && (is_edit)) { | |||||
| return false; | |||||
| } | |||||
| if (((fx->mode & eShaderFxMode_Realtime) && (is_render == false)) || | |||||
| ((fx->mode & eShaderFxMode_Render) && (is_render == true))) | |||||
| { | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /* get normal of draw using one stroke of visible layer | |||||
| * /param gpd GP datablock | |||||
| * /param r_point Point on plane | |||||
| * /param r_normal Normal vector | |||||
| */ | |||||
| static bool get_normal_vector(bGPdata *gpd, float r_point[3], float r_normal[3]) | |||||
| { | |||||
| for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | |||||
| if (gpl->flag & GP_LAYER_HIDE) | |||||
| continue; | |||||
| /* get frame */ | |||||
| bGPDframe *gpf = gpl->actframe; | |||||
| if (gpf == NULL) | |||||
| continue; | |||||
| for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { | |||||
| if (gps->totpoints >= 3) { | |||||
| bGPDspoint *pt = &gps->points[0]; | |||||
| BKE_gpencil_stroke_normal(gps, r_normal); | |||||
| /* in some weird situations, the normal cannot be calculated, so try next stroke */ | |||||
| if ((r_normal[0] != 0.0f) || (r_normal[1] != 0.0f) || (r_normal[2] != 0.0f)) { | |||||
| copy_v3_v3(r_point, &pt->x); | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /* helper to get near and far depth of field values */ | |||||
| static void GPENCIL_dof_nearfar(Object *camera, float coc, float nearfar[2]) | |||||
| { | |||||
| if (camera == NULL) { | |||||
| return; | |||||
| } | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| Scene *scene = draw_ctx->scene; | |||||
| Camera *cam = (Camera *)camera->data; | |||||
| float fstop = cam->gpu_dof.fstop; | |||||
| float focus_dist = BKE_camera_object_dof_distance(camera); | |||||
| float focal_len = cam->lens; | |||||
| /* this is factor that converts to the scene scale. focal length and sensor are expressed in mm | |||||
| * unit.scale_length is how many meters per blender unit we have. We want to convert to blender units though | |||||
| * because the shader reads coordinates in world space, which is in blender units. | |||||
| * Note however that focus_distance is already in blender units and shall not be scaled here (see T48157). */ | |||||
| float scale = (scene->unit.system) ? scene->unit.scale_length : 1.0f; | |||||
| float scale_camera = 0.001f / scale; | |||||
| /* we want radius here for the aperture number */ | |||||
| float aperture_scaled = 0.5f * scale_camera * focal_len / fstop; | |||||
| float focal_len_scaled = scale_camera * focal_len; | |||||
| float hyperfocal = (focal_len_scaled * focal_len_scaled) / (aperture_scaled * coc); | |||||
| nearfar[0] = (hyperfocal * focus_dist) / (hyperfocal + focal_len); | |||||
| nearfar[1] = (hyperfocal * focus_dist) / (hyperfocal - focal_len); | |||||
| } | |||||
| /* **************** Shader Effects ***************************** */ | |||||
| /* Gaussian Blur FX | |||||
| * The effect is done using two shading groups because is faster to apply horizontal | |||||
| * and vertical in different operations. | |||||
| */ | |||||
| static void DRW_gpencil_fx_blur( | |||||
| ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, | |||||
| tGPencilObjectCache *cache) | |||||
| { | |||||
| if (fx == NULL) { | |||||
| return; | |||||
| } | |||||
| BlurShaderFxData *fxd = (BlurShaderFxData *)fx; | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| View3D *v3d = draw_ctx->v3d; | |||||
| RegionView3D *rv3d = draw_ctx->rv3d; | |||||
| DRWShadingGroup *fx_shgrp; | |||||
| stl->fx[ob_idx].fx_blur.radius[0] = fxd->radius[0]; | |||||
| stl->fx[ob_idx].fx_blur.radius[1] = fxd->radius[1]; | |||||
| stl->fx[ob_idx].fx_blur.samples = fxd->samples; | |||||
| /* init weight */ | |||||
| if (fxd->flag & FX_BLUR_DOF_MODE) { | |||||
| /* viewport and opengl render */ | |||||
| Object *camera = NULL; | |||||
| if (rv3d) { | |||||
| if (rv3d->persp == RV3D_CAMOB) { | |||||
| camera = v3d->camera; | |||||
| } | |||||
| } | |||||
| else { | |||||
| camera = stl->storage->camera; | |||||
| } | |||||
| if (camera) { | |||||
| float nearfar[2]; | |||||
| GPENCIL_dof_nearfar(camera, fxd->coc, nearfar); | |||||
| float zdepth = stl->g_data->gp_object_cache[ob_idx].zdepth; | |||||
| /* the object is on focus area */ | |||||
| if ((zdepth >= nearfar[0]) && (zdepth <= nearfar[1])) { | |||||
| stl->fx[ob_idx].fx_blur.radius[0] = 0; | |||||
| stl->fx[ob_idx].fx_blur.radius[1] = 0; | |||||
| } | |||||
| else { | |||||
| float f; | |||||
| if (zdepth < nearfar[0]) { | |||||
| f = nearfar[0] - zdepth; | |||||
| } | |||||
| else { | |||||
| f = zdepth - nearfar[1]; | |||||
| } | |||||
| stl->fx[ob_idx].fx_blur.radius[0] = f; | |||||
| stl->fx[ob_idx].fx_blur.radius[1] = f; | |||||
| CLAMP2(&stl->fx[ob_idx].fx_blur.radius[0], 0, fxd->radius[0]); | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* if not camera view, the blur is disabled */ | |||||
| stl->fx[ob_idx].fx_blur.radius[0] = 0; | |||||
| stl->fx[ob_idx].fx_blur.radius[1] = 0; | |||||
| } | |||||
| } | |||||
| struct Gwn_Batch *fxquad = DRW_cache_fullscreen_quad_get(); | |||||
| fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_blur_sh, psl->fx_blur_pass); | |||||
| DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); | |||||
| DRW_shgroup_uniform_vec2(fx_shgrp, "blur", &stl->fx[ob_idx].fx_blur.radius[0], 1); | |||||
| cache->fx_blur_sh = fx_shgrp; | |||||
| } | |||||
| /* Flip FX */ | |||||
| static void DRW_gpencil_fx_flip( | |||||
| ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, | |||||
| tGPencilObjectCache *cache) | |||||
| { | |||||
| if (fx == NULL) { | |||||
| return; | |||||
| } | |||||
| FlipShaderFxData *fxd = (FlipShaderFxData *)fx; | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| DRWShadingGroup *fx_shgrp; | |||||
| if (fxd->flag & FX_FLIP_HORIZONTAL) { | |||||
| stl->fx[ob_idx].fx_flip.flipmode[0] = 1.0f; | |||||
| } | |||||
| else { | |||||
| stl->fx[ob_idx].fx_flip.flipmode[0] = 0; | |||||
| }; | |||||
| if (fxd->flag & FX_FLIP_VERTICAL) { | |||||
| stl->fx[ob_idx].fx_flip.flipmode[1] = 1.0f; | |||||
| } | |||||
| else { | |||||
| stl->fx[ob_idx].fx_flip.flipmode[1] = 0; | |||||
| }; | |||||
| struct Gwn_Batch *fxquad = DRW_cache_fullscreen_quad_get(); | |||||
| fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_flip_sh, psl->fx_flip_pass); | |||||
| DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); | |||||
| DRW_shgroup_uniform_vec2(fx_shgrp, "mode", &stl->fx[ob_idx].fx_flip.flipmode[0], 1); | |||||
| DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1); | |||||
| cache->fx_flip_sh = fx_shgrp; | |||||
| } | |||||
| /* Light FX */ | |||||
| static void DRW_gpencil_fx_light( | |||||
| ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, | |||||
| tGPencilObjectCache *cache) | |||||
| { | |||||
| if (fx == NULL) { | |||||
| return; | |||||
| } | |||||
| Object *ob = cache->ob; | |||||
| LightShaderFxData *fxd = (LightShaderFxData *)fx; | |||||
| if (fxd->object == NULL) { | |||||
| return; | |||||
| } | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| DRWShadingGroup *fx_shgrp; | |||||
| struct Gwn_Batch *fxquad = DRW_cache_fullscreen_quad_get(); | |||||
| fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_light_sh, psl->fx_light_pass); | |||||
| DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); | |||||
| DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); | |||||
| /* location of the light using obj location as origin */ | |||||
| copy_v3_v3(stl->fx[ob_idx].fx_light.loc, &fxd->object->loc[0]); | |||||
| /* Calc distance to strokes plane | |||||
| * The w component of location is used to transfer the distance to drawing plane | |||||
| */ | |||||
| float r_point[3], r_normal[3]; | |||||
| float r_plane[4]; | |||||
| bGPdata *gpd = (bGPdata *)ob->data; | |||||
| if (!get_normal_vector(gpd, r_point, r_normal)) { | |||||
| return; | |||||
| } | |||||
| mul_mat3_m4_v3(ob->obmat, r_normal); /* only rotation component */ | |||||
| plane_from_point_normal_v3(r_plane, r_point, r_normal); | |||||
| float dt = dist_to_plane_v3(fxd->object->loc, r_plane); | |||||
| stl->fx[ob_idx].fx_light.loc[3] = dt; | |||||
| DRW_shgroup_uniform_vec4(fx_shgrp, "loc", stl->fx[ob_idx].fx_light.loc, 1); | |||||
| stl->fx[ob_idx].fx_light.energy = fxd->energy; | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "energy", &stl->fx[ob_idx].fx_light.energy, 1); | |||||
| stl->fx[ob_idx].fx_light.ambient = fxd->ambient; | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "ambient", &stl->fx[ob_idx].fx_light.ambient, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); | |||||
| cache->fx_light_sh = fx_shgrp; | |||||
| } | |||||
| /* Pixelate FX */ | |||||
| static void DRW_gpencil_fx_pixel( | |||||
| ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, | |||||
| tGPencilObjectCache *cache) | |||||
| { | |||||
| if (fx == NULL) { | |||||
| return; | |||||
| } | |||||
| Object *ob = cache->ob; | |||||
| PixelShaderFxData *fxd = (PixelShaderFxData *)fx; | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| DRWShadingGroup *fx_shgrp; | |||||
| bGPdata *gpd = (bGPdata *)ob->data; | |||||
| stl->fx[ob_idx].fx_pixel.size[0] = fxd->size[0]; | |||||
| stl->fx[ob_idx].fx_pixel.size[1] = fxd->size[1]; | |||||
| copy_v4_v4(stl->fx[ob_idx].fx_pixel.rgba, fxd->rgba); | |||||
| stl->fx[ob_idx].fx_pixel.lines = (int)fxd->flag & FX_PIXEL_USE_LINES; | |||||
| struct Gwn_Batch *fxquad = DRW_cache_fullscreen_quad_get(); | |||||
| fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_pixel_sh, psl->fx_pixel_pass); | |||||
| DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); | |||||
| DRW_shgroup_uniform_vec2(fx_shgrp, "size", &stl->fx[ob_idx].fx_pixel.size[0], 1); | |||||
| DRW_shgroup_uniform_vec4(fx_shgrp, "color", &stl->fx[ob_idx].fx_pixel.rgba[0], 1); | |||||
| DRW_shgroup_uniform_int(fx_shgrp, "uselines", &stl->fx[ob_idx].fx_pixel.lines, 1); | |||||
| copy_v3_v3(stl->fx[ob_idx].fx_pixel.loc, &ob->loc[0]); | |||||
| DRW_shgroup_uniform_vec3(fx_shgrp, "loc", stl->fx[ob_idx].fx_pixel.loc, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); | |||||
| cache->fx_pixel_sh = fx_shgrp; | |||||
| } | |||||
| /* Swirl FX */ | |||||
| static void DRW_gpencil_fx_swirl( | |||||
| ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, | |||||
| tGPencilObjectCache *cache) | |||||
| { | |||||
| if (fx == NULL) { | |||||
| return; | |||||
| } | |||||
| Object *ob = cache->ob; | |||||
| SwirlShaderFxData *fxd = (SwirlShaderFxData *)fx; | |||||
| if (fxd->object == NULL) { | |||||
| return; | |||||
| } | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| DRWShadingGroup *fx_shgrp; | |||||
| bGPdata *gpd = (bGPdata *)ob->data; | |||||
| stl->fx[ob_idx].fx_swirl.radius = fxd->radius; | |||||
| stl->fx[ob_idx].fx_swirl.angle = fxd->angle; | |||||
| stl->fx[ob_idx].fx_swirl.transparent = (int)fxd->flag & FX_SWIRL_MAKE_TRANSPARENT; | |||||
| struct Gwn_Batch *fxquad = DRW_cache_fullscreen_quad_get(); | |||||
| fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_swirl_sh, psl->fx_swirl_pass); | |||||
| DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); | |||||
| DRW_shgroup_uniform_vec2(fx_shgrp, "Viewport", DRW_viewport_size_get(), 1); | |||||
| copy_v3_v3(stl->fx[ob_idx].fx_swirl.loc, &fxd->object->loc[0]); | |||||
| DRW_shgroup_uniform_vec3(fx_shgrp, "loc", stl->fx[ob_idx].fx_swirl.loc, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "radius", &stl->fx[ob_idx].fx_swirl.radius, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "angle", &stl->fx[ob_idx].fx_swirl.angle, 1); | |||||
| DRW_shgroup_uniform_int(fx_shgrp, "transparent", &stl->fx[ob_idx].fx_swirl.transparent, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixsize", stl->storage->pixsize, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixelsize", &U.pixelsize, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "pixfactor", &gpd->pixfactor, 1); | |||||
| cache->fx_swirl_sh = fx_shgrp; | |||||
| } | |||||
| /* Wave Distorsion FX */ | |||||
| static void DRW_gpencil_fx_wave( | |||||
| ShaderFxData *fx, int ob_idx, GPENCIL_e_data *e_data, GPENCIL_Data *vedata, | |||||
| tGPencilObjectCache *cache) | |||||
| { | |||||
| if (fx == NULL) { | |||||
| return; | |||||
| } | |||||
| WaveShaderFxData *fxd = (WaveShaderFxData *)fx; | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| stl->fx[ob_idx].fx_wave.amplitude = fxd->amplitude; | |||||
| stl->fx[ob_idx].fx_wave.period = fxd->period; | |||||
| stl->fx[ob_idx].fx_wave.phase = fxd->phase; | |||||
| stl->fx[ob_idx].fx_wave.orientation = fxd->orientation; | |||||
| struct Gwn_Batch *fxquad = DRW_cache_fullscreen_quad_get(); | |||||
| DRWShadingGroup *fx_shgrp = DRW_shgroup_create(e_data->gpencil_fx_wave_sh, psl->fx_wave_pass); | |||||
| DRW_shgroup_call_add(fx_shgrp, fxquad, NULL); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeColor", &e_data->temp_color_tx_a); | |||||
| DRW_shgroup_uniform_texture_ref(fx_shgrp, "strokeDepth", &e_data->temp_depth_tx_a); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "amplitude", &stl->fx[ob_idx].fx_wave.amplitude, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "period", &stl->fx[ob_idx].fx_wave.period, 1); | |||||
| DRW_shgroup_uniform_float(fx_shgrp, "phase", &stl->fx[ob_idx].fx_wave.phase, 1); | |||||
| DRW_shgroup_uniform_int(fx_shgrp, "orientation", &stl->fx[ob_idx].fx_wave.orientation, 1); | |||||
| DRW_shgroup_uniform_vec2(fx_shgrp, "wsize", DRW_viewport_size_get(), 1); | |||||
| cache->fx_wave_sh = fx_shgrp; | |||||
| } | |||||
| /* ************************************************************** */ | |||||
| /* create all FX shaders */ | |||||
| void GPENCIL_create_fx_shaders(GPENCIL_e_data *e_data) | |||||
| { | |||||
| /* fx shaders (all in screen space) */ | |||||
| if (!e_data->gpencil_fx_blur_sh) { | |||||
| e_data->gpencil_fx_blur_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_blur_frag_glsl, NULL); | |||||
| } | |||||
| if (!e_data->gpencil_fx_flip_sh) { | |||||
| e_data->gpencil_fx_flip_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_flip_frag_glsl, NULL); | |||||
| } | |||||
| if (!e_data->gpencil_fx_light_sh) { | |||||
| e_data->gpencil_fx_light_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_light_frag_glsl, NULL); | |||||
| } | |||||
| if (!e_data->gpencil_fx_pixel_sh) { | |||||
| e_data->gpencil_fx_pixel_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_pixel_frag_glsl, NULL); | |||||
| } | |||||
| if (!e_data->gpencil_fx_swirl_sh) { | |||||
| e_data->gpencil_fx_swirl_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_swirl_frag_glsl, NULL); | |||||
| } | |||||
| if (!e_data->gpencil_fx_wave_sh) { | |||||
| e_data->gpencil_fx_wave_sh = DRW_shader_create_fullscreen(datatoc_gpencil_fx_wave_frag_glsl, NULL); | |||||
| } | |||||
| } | |||||
| /* free FX shaders */ | |||||
| void GPENCIL_delete_fx_shaders(GPENCIL_e_data *e_data) | |||||
| { | |||||
| DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_blur_sh); | |||||
| DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_flip_sh); | |||||
| DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_light_sh); | |||||
| DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_pixel_sh); | |||||
| DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_swirl_sh); | |||||
| DRW_SHADER_FREE_SAFE(e_data->gpencil_fx_wave_sh); | |||||
| } | |||||
| /* create all passes used by FX */ | |||||
| void GPENCIL_create_fx_passes(GPENCIL_PassList *psl) | |||||
| { | |||||
| DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND | | |||||
| DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; | |||||
| /* FX passes */ | |||||
| psl->fx_blur_pass = DRW_pass_create("GPencil FX Blur Pass", state); | |||||
| psl->fx_flip_pass = DRW_pass_create("GPencil FX Flip Pass", state); | |||||
| psl->fx_light_pass = DRW_pass_create("GPencil FX Light Pass", state); | |||||
| psl->fx_pixel_pass = DRW_pass_create("GPencil FX Pixel Pass", state); | |||||
| psl->fx_swirl_pass = DRW_pass_create("GPencil FX Swirl Pass", state); | |||||
| psl->fx_wave_pass = DRW_pass_create("GPencil FX Wave Pass", state); | |||||
| } | |||||
| /* prepare fx shading groups */ | |||||
| void DRW_gpencil_fx_prepare( | |||||
| struct GPENCIL_e_data *e_data, struct GPENCIL_Data *vedata, | |||||
| struct tGPencilObjectCache *cache) | |||||
| { | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| Object *ob = cache->ob; | |||||
| int ob_idx = cache->idx; | |||||
| if (ob->shader_fx.first == NULL) { | |||||
| return; | |||||
| } | |||||
| /* loop FX */ | |||||
| for (ShaderFxData *fx = ob->shader_fx.first; fx; fx = fx->next) { | |||||
| if (effect_is_active(ob, fx, stl->storage->is_render)) { | |||||
| switch (fx->type) { | |||||
| case eShaderFxType_Blur: | |||||
| DRW_gpencil_fx_blur(fx, ob_idx, e_data, vedata, cache); | |||||
| break; | |||||
| case eShaderFxType_Flip: | |||||
| DRW_gpencil_fx_flip(fx, ob_idx, e_data, vedata, cache); | |||||
| break; | |||||
| case eShaderFxType_Light: | |||||
| DRW_gpencil_fx_light(fx, ob_idx, e_data, vedata, cache); | |||||
| break; | |||||
| case eShaderFxType_Pixel: | |||||
| DRW_gpencil_fx_pixel(fx, ob_idx, e_data, vedata, cache); | |||||
| break; | |||||
| case eShaderFxType_Swirl: | |||||
| DRW_gpencil_fx_swirl(fx, ob_idx, e_data, vedata, cache); | |||||
| break; | |||||
| case eShaderFxType_Wave: | |||||
| DRW_gpencil_fx_wave(fx, ob_idx, e_data, vedata, cache); | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* helper to draw one FX pass and do ping-pong copy */ | |||||
| static void gpencil_draw_fx_pass(GPENCIL_e_data *e_data, | |||||
| DRWPass *fxpass, DRWPass *copypass, | |||||
| GPENCIL_FramebufferList *fbl, DRWShadingGroup *shgrp) | |||||
| { | |||||
| static float clearcol[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||||
| GPU_framebuffer_bind(fbl->temp_fb_b); | |||||
| GPU_framebuffer_clear_color_depth(fbl->temp_fb_b, clearcol, 1.0f); | |||||
| /* draw effect pass in temp texture (B) using as source the previous image | |||||
| * existing in the other temp texture (A) */ | |||||
| DRW_draw_pass_subset(fxpass, shgrp, shgrp); | |||||
| /* copy pass from b to a for ping-pong frame buffers */ | |||||
| e_data->input_depth_tx = e_data->temp_depth_tx_b; | |||||
| e_data->input_color_tx = e_data->temp_color_tx_b; | |||||
| GPU_framebuffer_bind(fbl->temp_fb_a); | |||||
| GPU_framebuffer_clear_color_depth(fbl->temp_fb_a, clearcol, 1.0f); | |||||
| DRW_draw_pass(copypass); | |||||
| } | |||||
| /* helper to manage gaussian blur passes */ | |||||
| static void gpencil_blur_passes(struct GPENCIL_e_data *e_data, | |||||
| struct GPENCIL_Data *vedata, | |||||
| struct tGPencilObjectCache *cache) | |||||
| { | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; | |||||
| int ob_idx = cache->idx; | |||||
| int samples = stl->fx[ob_idx].fx_blur.samples; | |||||
| float bx = stl->fx[ob_idx].fx_blur.radius[0]; | |||||
| float by = stl->fx[ob_idx].fx_blur.radius[1]; | |||||
| /* the blur is done in two steps (Hor/Ver) because is faster and | |||||
| * gets better result | |||||
| * | |||||
| * samples could be 0 and disable de blur effects because sometimes | |||||
| * is easier animate the number of samples only, instead to animate the | |||||
| * hide/unhide and the number of samples to make some effects. | |||||
| */ | |||||
| for (int b = 0; b < samples; b++) { | |||||
| /* horizontal */ | |||||
| if (bx > 0) { | |||||
| stl->fx[ob_idx].fx_blur.radius[0] = bx; | |||||
| stl->fx[ob_idx].fx_blur.radius[1] = 0; | |||||
| gpencil_draw_fx_pass(e_data, psl->fx_blur_pass, | |||||
| psl->mix_pass_noblend, | |||||
| fbl, cache->fx_blur_sh); | |||||
| } | |||||
| /* vertical */ | |||||
| if (by > 0) { | |||||
| stl->fx[ob_idx].fx_blur.radius[0] = 0; | |||||
| stl->fx[ob_idx].fx_blur.radius[1] = by; | |||||
| gpencil_draw_fx_pass(e_data, psl->fx_blur_pass, | |||||
| psl->mix_pass_noblend, | |||||
| fbl, cache->fx_blur_sh); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* apply all object fx effects */ | |||||
| void DRW_gpencil_fx_draw(struct GPENCIL_e_data *e_data, | |||||
| struct GPENCIL_Data *vedata, struct tGPencilObjectCache *cache) | |||||
| { | |||||
| GPENCIL_StorageList *stl = ((GPENCIL_Data *)vedata)->stl; | |||||
| GPENCIL_PassList *psl = ((GPENCIL_Data *)vedata)->psl; | |||||
| GPENCIL_FramebufferList *fbl = ((GPENCIL_Data *)vedata)->fbl; | |||||
| Object *ob = cache->ob; | |||||
| /* loop FX modifiers */ | |||||
| for (ShaderFxData *md = ob->shader_fx.first; md; md = md->next) { | |||||
| if (effect_is_active(ob, md, stl->storage->is_render)) { | |||||
| switch (md->type) { | |||||
| case eShaderFxType_Blur: | |||||
| if (cache->fx_blur_sh) { | |||||
| gpencil_blur_passes(e_data, vedata, cache); | |||||
| } | |||||
| break; | |||||
| case eShaderFxType_Flip: | |||||
| if (cache->fx_flip_sh) { | |||||
| gpencil_draw_fx_pass(e_data, psl->fx_flip_pass, | |||||
| psl->mix_pass_noblend, | |||||
| fbl, cache->fx_flip_sh); | |||||
| } | |||||
| break; | |||||
| case eShaderFxType_Light: | |||||
| if (cache->fx_light_sh) { | |||||
| gpencil_draw_fx_pass(e_data, psl->fx_light_pass, | |||||
| psl->mix_pass_noblend, | |||||
| fbl, cache->fx_light_sh); | |||||
| } | |||||
| break; | |||||
| case eShaderFxType_Pixel: | |||||
| if (cache->fx_pixel_sh) { | |||||
| gpencil_draw_fx_pass(e_data, psl->fx_pixel_pass, | |||||
| psl->mix_pass_noblend, | |||||
| fbl, cache->fx_pixel_sh); | |||||
| } | |||||
| break; | |||||
| case eShaderFxType_Swirl: | |||||
| if (cache->fx_swirl_sh) { | |||||
| gpencil_draw_fx_pass(e_data, psl->fx_swirl_pass, | |||||
| psl->mix_pass_noblend, | |||||
| fbl, cache->fx_swirl_sh); | |||||
| } | |||||
| break; | |||||
| case eShaderFxType_Wave: | |||||
| if (cache->fx_wave_sh) { | |||||
| gpencil_draw_fx_pass(e_data, psl->fx_wave_pass, | |||||
| psl->mix_pass_noblend, | |||||
| fbl, cache->fx_wave_sh); | |||||
| } | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||