Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/engines/overlay/overlay_outline.c')
-rw-r--r--source/blender/draw/engines/overlay/overlay_outline.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c
new file mode 100644
index 00000000000..a0c7f575677
--- /dev/null
+++ b/source/blender/draw/engines/overlay/overlay_outline.c
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "DNA_lightprobe_types.h"
+
+#include "UI_resources.h"
+
+#include "overlay_private.h"
+
+void OVERLAY_outline_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_TextureList *txl = vedata->txl;
+
+ if (DRW_state_is_fbo()) {
+ /* TODO only alloc if needed. */
+ /* XXX TODO GPU_R16UI can overflow, it would cause no harm
+ * (only bad colored or missing outlines) but we should
+ * use 32bits only if the scene have that many objects */
+ DRW_texture_ensure_fullscreen_2d(&txl->temp_depth_tx, GPU_DEPTH24_STENCIL8, 0);
+ DRW_texture_ensure_fullscreen_2d(&txl->outlines_id_tx, GPU_R16UI, 0);
+ GPU_framebuffer_ensure_config(
+ &fbl->outlines_prepass_fb,
+ {GPU_ATTACHMENT_TEXTURE(txl->temp_depth_tx), GPU_ATTACHMENT_TEXTURE(txl->outlines_id_tx)});
+
+ for (int i = 0; i < 2; i++) {
+ DRW_texture_ensure_fullscreen_2d(&txl->outlines_color_tx[i], GPU_RGBA8, DRW_TEX_FILTER);
+ GPU_framebuffer_ensure_config(
+ &fbl->outlines_process_fb[i],
+ {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->outlines_color_tx[i])});
+ }
+ }
+}
+
+static int shgroup_theme_id_to_outline_id(int theme_id, const int base_flag)
+{
+ if (UNLIKELY(base_flag & BASE_FROM_DUPLI)) {
+ switch (theme_id) {
+ case TH_ACTIVE:
+ case TH_SELECT:
+ return 2;
+ case TH_TRANSFORM:
+ return 0;
+ default:
+ return -1;
+ }
+ }
+
+ switch (theme_id) {
+ case TH_ACTIVE:
+ return 3;
+ case TH_SELECT:
+ return 1;
+ case TH_TRANSFORM:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_outline_or_null(OVERLAY_PrivateData *pd,
+ int theme_id,
+ const int base_flag)
+{
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, base_flag);
+ switch (outline_id) {
+ case 3: /* TH_ACTIVE */
+ return pd->outlines_active_grp;
+ case 2: /* Duplis */
+ return pd->outlines_select_dupli_grp;
+ case 1: /* TH_SELECT */
+ return pd->outlines_select_grp;
+ case 0: /* TH_TRANSFORM */
+ return pd->outlines_transform_grp;
+ default:
+ return NULL;
+ }
+}
+
+static DRWShadingGroup *shgroup_theme_id_to_probe_outline_or_null(OVERLAY_PrivateData *pd,
+ int theme_id,
+ const int base_flag)
+{
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, base_flag);
+ switch (outline_id) {
+ case 3: /* TH_ACTIVE */
+ return pd->outlines_probe_active_grp;
+ case 2: /* Duplis */
+ return pd->outlines_probe_select_dupli_grp;
+ case 1: /* TH_SELECT */
+ return pd->outlines_probe_select_grp;
+ case 0: /* TH_TRANSFORM */
+ return pd->outlines_probe_transform_grp;
+ default:
+ return NULL;
+ }
+}
+
+static DRWShadingGroup *outline_shgroup(DRWPass *pass, int outline_id, GPUShader *sh)
+{
+ DRWShadingGroup *grp = DRW_shgroup_create(sh, pass);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ return grp;
+}
+
+void OVERLAY_outline_cache_init(OVERLAY_Data *vedata)
+{
+ OVERLAY_PassList *psl = vedata->psl;
+ OVERLAY_TextureList *txl = vedata->txl;
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
+ DRWShadingGroup *grp = NULL;
+
+ const float outline_width = UI_GetThemeValuef(TH_OUTLINE_WIDTH);
+ const bool do_outline_expand = (U.pixelsize > 1.0) || (outline_width > 2.0f);
+ const bool do_large_expand = ((U.pixelsize > 1.0) && (outline_width > 2.0f)) ||
+ (outline_width > 4.0f);
+ {
+ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL;
+ DRW_PASS_CREATE(psl->outlines_prepass_ps, state | pd->clipping_state);
+
+ GPUShader *sh_grid = OVERLAY_shader_outline_prepass_grid();
+ GPUShader *sh_geom = OVERLAY_shader_outline_prepass(pd->xray_enabled_and_not_wire);
+ GPUShader *sh = OVERLAY_shader_outline_prepass(false);
+
+ pd->outlines_transform_grp = outline_shgroup(psl->outlines_prepass_ps, 0, sh_geom);
+ pd->outlines_select_grp = outline_shgroup(psl->outlines_prepass_ps, 1, sh_geom);
+ pd->outlines_select_dupli_grp = outline_shgroup(psl->outlines_prepass_ps, 2, sh_geom);
+ pd->outlines_active_grp = outline_shgroup(psl->outlines_prepass_ps, 3, sh_geom);
+
+ pd->outlines_probe_transform_grp = outline_shgroup(psl->outlines_prepass_ps, 0, sh);
+ pd->outlines_probe_select_grp = outline_shgroup(psl->outlines_prepass_ps, 1, sh);
+ pd->outlines_probe_select_dupli_grp = outline_shgroup(psl->outlines_prepass_ps, 2, sh);
+ pd->outlines_probe_active_grp = outline_shgroup(psl->outlines_prepass_ps, 3, sh);
+
+ pd->outlines_probe_grid_grp = grp = DRW_shgroup_create(sh_grid, psl->outlines_prepass_ps);
+ DRW_shgroup_uniform_block_persistent(grp, "globalsBlock", G_draw.block_ubo);
+ }
+
+ /* outlines_prepass_ps is still needed for selection of probes. */
+ if (!(pd->v3d_flag & V3D_SELECT_OUTLINE)) {
+ return;
+ }
+
+ {
+ DRW_PASS_CREATE(psl->outlines_detect_ps, DRW_STATE_WRITE_COLOR);
+ DRW_PASS_CREATE(psl->outlines_expand_ps, DRW_STATE_WRITE_COLOR);
+ DRW_PASS_CREATE(psl->outlines_bleed_ps, DRW_STATE_WRITE_COLOR);
+ DRW_PASS_CREATE(psl->outlines_resolve_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
+
+ GPUShader *sh = OVERLAY_shader_outline_detect(pd->xray_enabled_and_not_wire);
+
+ grp = DRW_shgroup_create(sh, psl->outlines_detect_ps);
+ /* Don't occlude the "outline" detection pass if in xray mode (too much flickering). */
+ DRW_shgroup_uniform_float_copy(grp, "alphaOcclu", (pd->xray_enabled) ? 1.0f : 0.35f);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineId", &txl->outlines_id_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &txl->temp_depth_tx);
+ DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth);
+ DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ if (do_outline_expand) {
+ sh = OVERLAY_shader_outline_expand(do_large_expand);
+ grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
+ DRW_shgroup_uniform_bool_copy(grp, "doExpand", true);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+
+ sh = OVERLAY_shader_outline_expand(false);
+ grp = DRW_shgroup_create(sh, psl->outlines_bleed_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[1]);
+ DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+ else {
+ sh = OVERLAY_shader_outline_expand(false);
+ grp = DRW_shgroup_create(sh, psl->outlines_expand_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &txl->outlines_color_tx[0]);
+ DRW_shgroup_uniform_bool_copy(grp, "doExpand", false);
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+
+ GPUTexture **outline_tx = &txl->outlines_color_tx[do_outline_expand ? 0 : 1];
+ sh = OVERLAY_shader_outline_resolve();
+
+ grp = DRW_shgroup_create(sh, psl->outlines_resolve_ps);
+ DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", outline_tx);
+ DRW_shgroup_uniform_vec2_copy(grp, "rcpDimensions", DRW_viewport_invert_size_get());
+ DRW_shgroup_call_procedural_triangles(grp, NULL, 1);
+ }
+}
+
+static void outline_lightprobe(OVERLAY_PrivateData *pd, Object *ob, ViewLayer *view_layer)
+{
+ DRWShadingGroup *grp;
+ LightProbe *prb = (LightProbe *)ob->data;
+ int theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL);
+
+ if (prb->type == LIGHTPROBE_TYPE_GRID) {
+ float corner[3];
+ float increment[3][3];
+ /* Update transforms */
+ float cell_dim[3], half_cell_dim[3];
+ cell_dim[0] = 2.0f / (float)(prb->grid_resolution_x);
+ cell_dim[1] = 2.0f / (float)(prb->grid_resolution_y);
+ cell_dim[2] = 2.0f / (float)(prb->grid_resolution_z);
+
+ mul_v3_v3fl(half_cell_dim, cell_dim, 0.5f);
+
+ /* First cell. */
+ copy_v3_fl(corner, -1.0f);
+ add_v3_v3(corner, half_cell_dim);
+ mul_m4_v3(ob->obmat, corner);
+
+ /* Opposite neighbor cell. */
+ copy_v3_fl3(increment[0], cell_dim[0], 0.0f, 0.0f);
+ copy_v3_fl3(increment[1], 0.0f, cell_dim[1], 0.0f);
+ copy_v3_fl3(increment[2], 0.0f, 0.0f, cell_dim[2]);
+
+ for (int i = 0; i < 3; i++) {
+ add_v3_v3(increment[i], half_cell_dim);
+ add_v3_fl(increment[i], -1.0f);
+ mul_m4_v3(ob->obmat, increment[i]);
+ sub_v3_v3(increment[i], corner);
+ }
+
+ int outline_id = shgroup_theme_id_to_outline_id(theme_id, ob->base_flag);
+ uint cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z;
+ grp = DRW_shgroup_create_sub(pd->outlines_probe_grid_grp);
+ DRW_shgroup_uniform_int_copy(grp, "outlineId", outline_id);
+ DRW_shgroup_uniform_vec3_copy(grp, "corner", corner);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_x", increment[0]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_y", increment[1]);
+ DRW_shgroup_uniform_vec3_copy(grp, "increment_z", increment[2]);
+ DRW_shgroup_uniform_ivec3_copy(grp, "grid_resolution", &prb->grid_resolution_x);
+ DRW_shgroup_call_procedural_points(grp, NULL, cell_count);
+ }
+ else if (prb->type == LIGHTPROBE_TYPE_PLANAR && (prb->flag & LIGHTPROBE_FLAG_SHOW_DATA)) {
+ grp = shgroup_theme_id_to_probe_outline_or_null(pd, theme_id, ob->base_flag);
+ DRW_shgroup_call_no_cull(grp, DRW_cache_quad_get(), ob);
+ }
+}
+
+void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata,
+ Object *ob,
+ OVERLAY_DupliData *dupli,
+ bool init_dupli)
+{
+ OVERLAY_PrivateData *pd = vedata->stl->pd;
+ const DRWContextState *draw_ctx = DRW_context_state_get();
+ struct GPUBatch *geom;
+ DRWShadingGroup *shgroup = NULL;
+
+ if (ob->type == OB_LIGHTPROBE) {
+ outline_lightprobe(pd, ob, draw_ctx->view_layer);
+ return;
+ }
+
+ if (dupli && !init_dupli) {
+ geom = dupli->outline_geom;
+ shgroup = dupli->outline_shgrp;
+ }
+ else {
+ /* This fixes only the biggest case which is a plane in ortho view. */
+ int flat_axis = 0;
+ bool is_flat_object_viewed_from_side = ((draw_ctx->rv3d->persp == RV3D_ORTHO) &&
+ DRW_object_is_flat(ob, &flat_axis) &&
+ DRW_object_axis_orthogonal_to_view(ob, flat_axis));
+
+ if (pd->xray_enabled_and_not_wire || is_flat_object_viewed_from_side) {
+ geom = DRW_cache_object_edge_detection_get(ob, NULL);
+ }
+ else {
+ geom = DRW_cache_object_surface_get(ob);
+ }
+
+ if (geom) {
+ int theme_id = DRW_object_wire_theme_get(ob, draw_ctx->view_layer, NULL);
+ shgroup = shgroup_theme_id_to_outline_or_null(pd, theme_id, ob->base_flag);
+ }
+ }
+
+ if (shgroup && geom) {
+ DRW_shgroup_call(shgroup, geom, ob);
+ }
+
+ if (init_dupli) {
+ dupli->outline_shgrp = shgroup;
+ dupli->outline_geom = geom;
+ }
+}
+
+void OVERLAY_outline_draw(OVERLAY_Data *vedata)
+{
+ OVERLAY_FramebufferList *fbl = vedata->fbl;
+ OVERLAY_PassList *psl = vedata->psl;
+ float clearcol[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ bool do_outlines = psl->outlines_prepass_ps != NULL &&
+ !DRW_pass_is_empty(psl->outlines_prepass_ps);
+
+ if (DRW_state_is_fbo() && do_outlines) {
+ DRW_stats_group_start("Outlines");
+
+ /* Render filled polygon on a separate framebuffer */
+ GPU_framebuffer_bind(fbl->outlines_prepass_fb);
+ GPU_framebuffer_clear_color_depth(fbl->outlines_prepass_fb, clearcol, 1.0f);
+ DRW_draw_pass(psl->outlines_prepass_ps);
+
+ /* Search outline pixels */
+ GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
+ DRW_draw_pass(psl->outlines_detect_ps);
+
+ /* Expand outline to form a 3px wide line */
+ GPU_framebuffer_bind(fbl->outlines_process_fb[1]);
+ DRW_draw_pass(psl->outlines_expand_ps);
+
+ /* Bleed color so the AA can do it's stuff */
+ GPU_framebuffer_bind(fbl->outlines_process_fb[0]);
+ DRW_draw_pass(psl->outlines_bleed_ps);
+
+ /* restore main framebuffer */
+ GPU_framebuffer_bind(fbl->overlay_default_fb);
+ DRW_draw_pass(psl->outlines_resolve_ps);
+
+ DRW_stats_group_end();
+ }
+ else if (DRW_state_is_select()) {
+ /* Render probes spheres/planes so we can select them. */
+ DRW_draw_pass(psl->outlines_prepass_ps);
+ }
+}