diff options
Diffstat (limited to 'source/blender/draw/engines/overlay')
18 files changed, 1113 insertions, 15 deletions
diff --git a/source/blender/draw/engines/overlay/overlay_background.c b/source/blender/draw/engines/overlay/overlay_background.c index f52ae691a35..cb09d916a0f 100644 --- a/source/blender/draw/engines/overlay/overlay_background.c +++ b/source/blender/draw/engines/overlay/overlay_background.c @@ -31,6 +31,7 @@ #define BG_GRADIENT 1 #define BG_CHECKER 2 #define BG_RADIAL 3 +#define BG_SOLID_CHECKER 4 void OVERLAY_background_cache_init(OVERLAY_Data *vedata) { @@ -40,7 +41,7 @@ void OVERLAY_background_cache_init(OVERLAY_Data *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene = draw_ctx->scene; const RegionView3D *rv3d = draw_ctx->rv3d; - const BoundBox *bb = rv3d->clipbb; + const BoundBox *bb = rv3d ? rv3d->clipbb : NULL; const View3D *v3d = draw_ctx->v3d; bool draw_clipping_bounds = (pd->clipping_state != 0); @@ -50,9 +51,11 @@ void OVERLAY_background_cache_init(OVERLAY_Data *vedata) if (DRW_state_is_opengl_render() && !DRW_state_draw_background()) { background_type = BG_SOLID; - zero_v3(color_override); color_override[3] = 1.0f; } + else if (pd->is_image_editor) { + background_type = BG_SOLID_CHECKER; + } else if (!DRW_state_draw_background()) { background_type = BG_CHECKER; } diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.c b/source/blender/draw/engines/overlay/overlay_edit_uv.c new file mode 100644 index 00000000000..109db6433e0 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_edit_uv.c @@ -0,0 +1,394 @@ +/* + * 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 "draw_cache_impl.h" +#include "draw_manager_text.h" + +#include "BKE_image.h" + +#include "DNA_mesh_types.h" + +#include "ED_image.h" + +#include "GPU_batch.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "overlay_private.h" + +typedef struct OVERLAY_StretchingAreaTotals { + void *next, *prev; + float *total_area; + float *total_area_uv; +} OVERLAY_StretchingAreaTotals; + +static OVERLAY_UVLineStyle edit_uv_line_style_from_space_image(const SpaceImage *sima) +{ + const bool is_uv_editor = sima->mode == SI_MODE_UV; + if (is_uv_editor) { + switch (sima->dt_uv) { + case SI_UVDT_OUTLINE: + return OVERLAY_UV_LINE_STYLE_OUTLINE; + case SI_UVDT_BLACK: + return OVERLAY_UV_LINE_STYLE_BLACK; + case SI_UVDT_WHITE: + return OVERLAY_UV_LINE_STYLE_WHITE; + case SI_UVDT_DASH: + return OVERLAY_UV_LINE_STYLE_DASH; + default: + return OVERLAY_UV_LINE_STYLE_BLACK; + } + } + else { + return OVERLAY_UV_LINE_STYLE_SHADOW; + } +} + +/* -------------------------------------------------------------------- */ +/** \name Internal API + * \{ */ + +void OVERLAY_edit_uv_init(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + const DRWContextState *draw_ctx = DRW_context_state_get(); + SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + const Scene *scene = draw_ctx->scene; + const ToolSettings *ts = scene->toolsettings; + + Image *image = sima->image; + /* By design no image is an image type. This so editor shows UV's by default. */ + const bool is_image_type = + (image == NULL) || ELEM(image->type, IMA_TYPE_IMAGE, IMA_TYPE_MULTILAYER, IMA_TYPE_UV_TEST); + const bool is_uv_editor = sima->mode == SI_MODE_UV; + const bool has_edit_object = (draw_ctx->object_edit) != NULL; + const bool is_paint_mode = sima->mode == SI_MODE_PAINT; + const bool is_view_mode = sima->mode == SI_MODE_VIEW; + const bool is_edit_mode = draw_ctx->object_mode == OB_MODE_EDIT; + const bool do_uv_overlay = is_image_type && is_uv_editor && has_edit_object; + const bool show_modified_uvs = sima->flag & SI_DRAWSHADOW; + const bool is_tiled_image = image && (image->source == IMA_SRC_TILED); + const bool do_faces = ((sima->flag & SI_NO_DRAWFACES) == 0); + const bool do_face_dots = (ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode & SCE_SELECT_FACE) != 0 : + (ts->uv_selectmode == UV_SELECT_FACE); + const bool do_uvstretching_overlay = is_image_type && is_uv_editor && is_edit_mode && + ((sima->flag & SI_DRAW_STRETCH) != 0); + pd->edit_uv.do_faces = do_faces && !do_uvstretching_overlay; + pd->edit_uv.do_face_dots = do_faces && do_face_dots; + + pd->edit_uv.do_uv_overlay = do_uv_overlay; + pd->edit_uv.do_uv_shadow_overlay = + is_image_type && + ((is_paint_mode && + ((draw_ctx->object_mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != 0)) || + (is_view_mode && ((draw_ctx->object_mode & (OB_MODE_TEXTURE_PAINT)) != 0)) || + (do_uv_overlay && (show_modified_uvs))); + pd->edit_uv.do_uv_stretching_overlay = do_uvstretching_overlay; + pd->edit_uv.uv_opacity = sima->uv_opacity; + pd->edit_uv.do_tiled_image_overlay = is_image_type && is_tiled_image; + + pd->edit_uv.dash_length = 4.0f * UI_DPI_FAC; + pd->edit_uv.line_style = edit_uv_line_style_from_space_image(sima); + pd->edit_uv.do_smooth_wire = ((U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) > 0); + + pd->edit_uv.draw_type = sima->dt_uvstretch; + BLI_listbase_clear(&pd->edit_uv.totals); + pd->edit_uv.total_area_ratio = 0.0f; + pd->edit_uv.total_area_ratio_inv = 0.0f; + + ED_space_image_get_uv_aspect(sima, &pd->edit_uv.aspect[0], &pd->edit_uv.aspect[1]); +} + +void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->edit_uv.do_uv_overlay || pd->edit_uv.do_uv_shadow_overlay) { + /* uv edges */ + { + DRW_PASS_CREATE(psl->edit_uv_edges_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA); + GPUShader *sh = OVERLAY_shader_edit_uv_edges_get(); + if (pd->edit_uv.do_uv_shadow_overlay) { + pd->edit_uv_shadow_edges_grp = DRW_shgroup_create(sh, psl->edit_uv_edges_ps); + DRW_shgroup_uniform_block(pd->edit_uv_shadow_edges_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_int_copy( + pd->edit_uv_shadow_edges_grp, "lineStyle", OVERLAY_UV_LINE_STYLE_SHADOW); + DRW_shgroup_uniform_float_copy( + pd->edit_uv_shadow_edges_grp, "alpha", pd->edit_uv.uv_opacity); + DRW_shgroup_uniform_float( + pd->edit_uv_shadow_edges_grp, "dashLength", &pd->edit_uv.dash_length, 1); + DRW_shgroup_uniform_bool( + pd->edit_uv_shadow_edges_grp, "doSmoothWire", &pd->edit_uv.do_smooth_wire, 1); + } + + if (pd->edit_uv.do_uv_overlay) { + pd->edit_uv_edges_grp = DRW_shgroup_create(sh, psl->edit_uv_edges_ps); + DRW_shgroup_uniform_block(pd->edit_uv_edges_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_int_copy(pd->edit_uv_edges_grp, "lineStyle", pd->edit_uv.line_style); + DRW_shgroup_uniform_float_copy(pd->edit_uv_edges_grp, "alpha", pd->edit_uv.uv_opacity); + DRW_shgroup_uniform_float( + pd->edit_uv_edges_grp, "dashLength", &pd->edit_uv.dash_length, 1); + DRW_shgroup_uniform_bool( + pd->edit_uv_edges_grp, "doSmoothWire", &pd->edit_uv.do_smooth_wire, 1); + } + } + } + + if (pd->edit_uv.do_uv_overlay) { + /* uv verts */ + { + DRW_PASS_CREATE(psl->edit_uv_verts_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + DRW_STATE_BLEND_ALPHA); + GPUShader *sh = OVERLAY_shader_edit_uv_verts_get(); + pd->edit_uv_verts_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); + + const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE); + + DRW_shgroup_uniform_block(pd->edit_uv_verts_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy( + pd->edit_uv_verts_grp, "pointSize", (point_size + 1.5f) * M_SQRT2); + DRW_shgroup_uniform_float_copy(pd->edit_uv_verts_grp, "outlineWidth", 0.75f); + } + + /* uv faces */ + if (pd->edit_uv.do_faces) { + DRW_PASS_CREATE(psl->edit_uv_faces_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA); + GPUShader *sh = OVERLAY_shader_edit_uv_face_get(); + pd->edit_uv_faces_grp = DRW_shgroup_create(sh, psl->edit_uv_faces_ps); + DRW_shgroup_uniform_block(pd->edit_uv_faces_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float(pd->edit_uv_faces_grp, "uvOpacity", &pd->edit_uv.uv_opacity, 1); + } + + /* uv face dots */ + if (pd->edit_uv.do_face_dots) { + const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE); + GPUShader *sh = OVERLAY_shader_edit_uv_face_dots_get(); + pd->edit_uv_face_dots_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); + DRW_shgroup_uniform_block(pd->edit_uv_face_dots_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float_copy(pd->edit_uv_face_dots_grp, "pointSize", point_size); + } + } + + /* uv stretching */ + if (pd->edit_uv.do_uv_stretching_overlay) { + DRW_PASS_CREATE(psl->edit_uv_stretching_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA); + if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) { + GPUShader *sh = OVERLAY_shader_edit_uv_stretching_angle_get(); + pd->edit_uv_stretching_grp = DRW_shgroup_create(sh, psl->edit_uv_stretching_ps); + DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_vec2_copy(pd->edit_uv_stretching_grp, "aspect", pd->edit_uv.aspect); + } + else /* SI_UVDT_STRETCH_AREA */ { + GPUShader *sh = OVERLAY_shader_edit_uv_stretching_area_get(); + pd->edit_uv_stretching_grp = DRW_shgroup_create(sh, psl->edit_uv_stretching_ps); + DRW_shgroup_uniform_block(pd->edit_uv_stretching_grp, "globalsBlock", G_draw.block_ubo); + DRW_shgroup_uniform_float( + pd->edit_uv_stretching_grp, "totalAreaRatio", &pd->edit_uv.total_area_ratio, 1); + DRW_shgroup_uniform_float( + pd->edit_uv_stretching_grp, "totalAreaRatioInv", &pd->edit_uv.total_area_ratio_inv, 1); + } + } + + if (pd->edit_uv.do_tiled_image_overlay) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + Image *image = sima->image; + GPUBatch *geom = DRW_cache_quad_wires_get(); + float obmat[4][4]; + unit_m4(obmat); + + DRW_PASS_CREATE(psl->edit_uv_tiled_image_borders_ps, + DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); + GPUShader *sh = OVERLAY_shader_edit_uv_tiled_image_borders_get(); + + float theme_color[4], selected_color[4]; + UI_GetThemeColorShade4fv(TH_BACK, 60, theme_color); + UI_GetThemeColor4fv(TH_FACE_SELECT, selected_color); + srgb_to_linearrgb_v4(theme_color, theme_color); + srgb_to_linearrgb_v4(selected_color, selected_color); + + DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps); + DRW_shgroup_uniform_vec4_copy(grp, "color", theme_color); + DRW_shgroup_uniform_vec3_copy(grp, "offset", (float[3]){0.0f, 0.0f, 0.0f}); + + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + const int tile_x = ((tile->tile_number - 1001) % 10); + const int tile_y = ((tile->tile_number - 1001) / 10); + obmat[3][1] = (float)tile_y; + obmat[3][0] = (float)tile_x; + DRW_shgroup_call_obmat(grp, geom, obmat); + } + + /* Active tile border */ + ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index); + obmat[3][0] = (float)((active_tile->tile_number - 1001) % 10); + obmat[3][1] = (float)((active_tile->tile_number - 1001) / 10); + grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps); + DRW_shgroup_uniform_vec4_copy(grp, "color", selected_color); + DRW_shgroup_call_obmat(grp, geom, obmat); + + struct DRWTextStore *dt = DRW_text_cache_ensure(); + uchar color[4]; + /* Color Management: Exception here as texts are drawn in sRGB space directly. */ + UI_GetThemeColorShade4ubv(TH_BACK, 60, color); + char text[16]; + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + BLI_snprintf(text, 5, "%d", tile->tile_number); + float tile_location[3] = { + ((tile->tile_number - 1001) % 10), ((tile->tile_number - 1001) / 10), 0.0f}; + DRW_text_cache_add(dt, + tile_location, + text, + strlen(text), + 10, + 10, + DRW_TEXT_CACHE_GLOBALSPACE | DRW_TEXT_CACHE_ASCII, + color); + } + } +} + +void OVERLAY_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + GPUBatch *geom; + const bool is_edit_object = DRW_object_is_in_edit_mode(ob); + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool draw_shadows = (draw_ctx->object_mode != OB_MODE_OBJECT) && + (ob->mode == draw_ctx->object_mode); + if (is_edit_object) { + if (pd->edit_uv.do_uv_overlay) { + geom = DRW_mesh_batch_cache_get_edituv_edges(ob->data); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_edges_grp, geom, NULL); + } + geom = DRW_mesh_batch_cache_get_edituv_verts(ob->data); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_verts_grp, geom, NULL); + } + if (pd->edit_uv.do_faces) { + geom = DRW_mesh_batch_cache_get_edituv_faces(ob->data); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_faces_grp, geom, NULL); + } + } + if (pd->edit_uv.do_face_dots) { + geom = DRW_mesh_batch_cache_get_edituv_facedots(ob->data); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_face_dots_grp, geom, NULL); + } + } + } + + if (pd->edit_uv.do_uv_stretching_overlay) { + Mesh *me = ob->data; + + if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_ANGLE) { + geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(me); + } + else /* SI_UVDT_STRETCH_AREA */ { + OVERLAY_StretchingAreaTotals *totals = MEM_mallocN(sizeof(OVERLAY_StretchingAreaTotals), + __func__); + BLI_addtail(&pd->edit_uv.totals, totals); + geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_area( + me, &totals->total_area, &totals->total_area_uv); + } + + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_stretching_grp, geom, NULL); + } + } + } + + if (draw_shadows) { + if (pd->edit_uv.do_uv_shadow_overlay) { + geom = DRW_mesh_batch_cache_get_uv_edges(ob->data); + if (geom) { + DRW_shgroup_call_obmat(pd->edit_uv_shadow_edges_grp, geom, NULL); + } + } + } +} + +static void edit_uv_stretching_update_ratios(OVERLAY_Data *vedata) +{ + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->edit_uv.draw_type == SI_UVDT_STRETCH_AREA) { + float total_area = 0.0f; + float total_area_uv = 0.0f; + + LISTBASE_FOREACH (OVERLAY_StretchingAreaTotals *, totals, &pd->edit_uv.totals) { + total_area += *totals->total_area; + total_area_uv += *totals->total_area_uv; + } + + if (total_area > FLT_EPSILON && total_area_uv > FLT_EPSILON) { + pd->edit_uv.total_area_ratio = total_area / total_area_uv; + pd->edit_uv.total_area_ratio_inv = total_area_uv / total_area; + } + } + BLI_freelistN(&pd->edit_uv.totals); +} + +void OVERLAY_edit_uv_draw(OVERLAY_Data *vedata) +{ + OVERLAY_PassList *psl = vedata->psl; + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + + if (pd->edit_uv.do_tiled_image_overlay) { + DRW_draw_pass(psl->edit_uv_tiled_image_borders_ps); + } + + if (pd->edit_uv.do_uv_stretching_overlay) { + edit_uv_stretching_update_ratios(vedata); + DRW_draw_pass(psl->edit_uv_stretching_ps); + } + if (pd->edit_uv.do_uv_overlay) { + if (pd->edit_uv.do_faces) { + DRW_draw_pass(psl->edit_uv_faces_ps); + } + DRW_draw_pass(psl->edit_uv_edges_ps); + + DRW_draw_pass(psl->edit_uv_verts_ps); + } + else if (pd->edit_uv.do_uv_shadow_overlay) { + DRW_draw_pass(psl->edit_uv_edges_ps); + } +} + +/* \{ */ diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 1312408498a..9cdd371ec4e 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -29,9 +29,13 @@ #include "ED_view3d.h" +#include "UI_interface.h" + #include "BKE_object.h" #include "BKE_paint.h" +#include "DNA_space_types.h" + #include "overlay_engine.h" #include "overlay_private.h" @@ -48,6 +52,10 @@ static void OVERLAY_engine_init(void *vedata) const View3D *v3d = draw_ctx->v3d; const Scene *scene = draw_ctx->scene; const ToolSettings *ts = scene->toolsettings; + const SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + BLI_assert(v3d || sima); + + OVERLAY_shader_library_ensure(); if (!stl->pd) { /* Alloc transient pointers */ @@ -55,6 +63,14 @@ static void OVERLAY_engine_init(void *vedata) } OVERLAY_PrivateData *pd = stl->pd; + pd->is_image_editor = sima != NULL; + + if (pd->is_image_editor) { + pd->clipping_state = 0; + OVERLAY_grid_init(data); + OVERLAY_edit_uv_init(data); + return; + } pd->hide_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) != 0; pd->ctx_mode = CTX_data_mode_enum_ex( @@ -122,6 +138,13 @@ static void OVERLAY_cache_init(void *vedata) OVERLAY_StorageList *stl = data->stl; OVERLAY_PrivateData *pd = stl->pd; + if (pd->is_image_editor) { + OVERLAY_background_cache_init(vedata); + OVERLAY_grid_cache_init(vedata); + OVERLAY_edit_uv_cache_init(vedata); + return; + } + switch (pd->ctx_mode) { case CTX_MODE_EDIT_MESH: OVERLAY_edit_mesh_cache_init(vedata); @@ -240,6 +263,14 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) { OVERLAY_Data *data = vedata; OVERLAY_PrivateData *pd = data->stl->pd; + + if (pd->is_image_editor) { + if (ob->type == OB_MESH) { + OVERLAY_edit_uv_cache_populate(vedata, ob); + } + return; + } + const DRWContextState *draw_ctx = DRW_context_state_get(); const bool is_select = DRW_state_is_select(); const bool renderable = DRW_object_is_renderable(ob); @@ -414,6 +445,12 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) static void OVERLAY_cache_finish(void *vedata) { + OVERLAY_Data *data = vedata; + OVERLAY_PrivateData *pd = data->stl->pd; + if (pd->is_image_editor) { + return; + } + /* TODO(fclem) Only do this when really needed. */ { /* HACK we allocate the in front depth here to avoid the overhead when if is not needed. */ @@ -445,6 +482,16 @@ static void OVERLAY_draw_scene(void *vedata) GPU_framebuffer_clear_color(dfbl->overlay_only_fb, clear_col); } + if (pd->is_image_editor) { + OVERLAY_background_draw(data); + OVERLAY_grid_draw(data); + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(dfbl->overlay_fb); + } + OVERLAY_edit_uv_draw(data); + return; + } + OVERLAY_image_background_draw(vedata); OVERLAY_background_draw(vedata); diff --git a/source/blender/draw/engines/overlay/overlay_grid.c b/source/blender/draw/engines/overlay/overlay_grid.c index e3079870d8f..7445dfc2e3d 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.c +++ b/source/blender/draw/engines/overlay/overlay_grid.c @@ -26,6 +26,7 @@ #include "DEG_depsgraph_query.h" +#include "ED_image.h" #include "ED_view3d.h" #include "overlay_private.h" @@ -42,14 +43,31 @@ enum { CLIP_ZNEG = (1 << 8), GRID_BACK = (1 << 9), GRID_CAMERA = (1 << 10), + PLANE_IMAGE = (1 << 11), }; void OVERLAY_grid_init(OVERLAY_Data *vedata) { OVERLAY_PrivateData *pd = vedata->stl->pd; OVERLAY_ShadingData *shd = &pd->shdata; - const DRWContextState *draw_ctx = DRW_context_state_get(); + + shd->grid_flag = 0; + shd->zneg_flag = 0; + shd->zpos_flag = 0; + shd->grid_line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f; + + if (pd->is_image_editor) { + SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; + shd->grid_flag = ED_space_image_has_buffer(sima) ? 0 : PLANE_IMAGE | SHOW_GRID; + shd->grid_distance = 1.0f; + shd->grid_mesh_size = 1.0f; + for (int step = 0; step < 8; step++) { + shd->grid_steps[step] = powf(4, step) * (1.0f / 16.0f); + } + return; + } + View3D *v3d = draw_ctx->v3d; Scene *scene = draw_ctx->scene; RegionView3D *rv3d = draw_ctx->rv3d; @@ -60,10 +78,6 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata) const bool show_floor = (pd->v3d_gridflag & V3D_SHOW_FLOOR) != 0; const bool show_ortho_grid = (pd->v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0; - shd->grid_flag = 0; - shd->zneg_flag = 0; - shd->zpos_flag = 0; - if (pd->hide_overlays || !(pd->v3d_gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z | V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID))) { return; @@ -163,14 +177,16 @@ void OVERLAY_grid_init(OVERLAY_Data *vedata) } shd->grid_distance = dist / 2.0f; - shd->grid_line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f; ED_view3d_grid_steps(scene, v3d, rv3d, shd->grid_steps); } void OVERLAY_grid_cache_init(OVERLAY_Data *vedata) { - OVERLAY_ShadingData *shd = &vedata->stl->pd->shdata; + OVERLAY_StorageList *stl = vedata->stl; + OVERLAY_PrivateData *pd = stl->pd; + OVERLAY_ShadingData *shd = &pd->shdata; + OVERLAY_PassList *psl = vedata->psl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); @@ -182,12 +198,29 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *vedata) DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->grid_ps, state); - - GPUShader *sh = OVERLAY_shader_grid(); + DRWShadingGroup *grp; + GPUShader *sh; struct GPUBatch *geom = DRW_cache_grid_get(); + if (pd->is_image_editor) { + /* add quad background */ + sh = OVERLAY_shader_grid_image(); + grp = DRW_shgroup_create(sh, psl->grid_ps); + DRW_shgroup_call(grp, DRW_cache_quad_get(), NULL); + float color_back[4]; + interp_v4_v4v4(color_back, G_draw.block.colorBackground, G_draw.block.colorGrid, 0.5); + DRW_shgroup_uniform_vec4_copy(grp, "color", color_back); + + /* add wire border */ + grp = DRW_shgroup_create(sh, psl->grid_ps); + DRW_shgroup_call(grp, DRW_cache_quad_wires_get(), NULL); + DRW_shgroup_uniform_vec4_copy(grp, "color", G_draw.block.colorGrid); + } + + sh = OVERLAY_shader_grid(); + /* Create 3 quads to render ordered transparency Z axis */ - DRWShadingGroup *grp = DRW_shgroup_create(sh, psl->grid_ps); + grp = DRW_shgroup_create(sh, psl->grid_ps); DRW_shgroup_uniform_int(grp, "gridFlag", &shd->zneg_flag, 1); DRW_shgroup_uniform_vec3(grp, "planeAxes", shd->zplane_axes, 1); DRW_shgroup_uniform_float(grp, "gridDistance", &shd->grid_distance, 1); diff --git a/source/blender/draw/engines/overlay/overlay_private.h b/source/blender/draw/engines/overlay/overlay_private.h index 86c1f077571..c1d29cf7450 100644 --- a/source/blender/draw/engines/overlay/overlay_private.h +++ b/source/blender/draw/engines/overlay/overlay_private.h @@ -34,6 +34,9 @@ extern "C" { # define USE_GEOM_SHADER_WORKAROUND 0 #endif +/* Needed for eSpaceImage_UVDT_Stretch */ +#include "DNA_space_types.h" + typedef struct OVERLAY_FramebufferList { struct GPUFrameBuffer *overlay_default_fb; struct GPUFrameBuffer *overlay_line_fb; @@ -55,6 +58,14 @@ typedef struct OVERLAY_TextureList { #define NOT_IN_FRONT 0 #define IN_FRONT 1 +typedef enum OVERLAY_UVLineStyle { + OVERLAY_UV_LINE_STYLE_OUTLINE = 0, + OVERLAY_UV_LINE_STYLE_DASH = 1, + OVERLAY_UV_LINE_STYLE_BLACK = 2, + OVERLAY_UV_LINE_STYLE_WHITE = 3, + OVERLAY_UV_LINE_STYLE_SHADOW = 4, +} OVERLAY_UVLineStyle; + typedef struct OVERLAY_PassList { DRWPass *antialiasing_ps; DRWPass *armature_ps[2]; @@ -79,6 +90,11 @@ typedef struct OVERLAY_PassList { DRWPass *edit_text_overlay_ps; DRWPass *edit_text_darken_ps; DRWPass *edit_text_wire_ps[2]; + DRWPass *edit_uv_edges_ps; + DRWPass *edit_uv_verts_ps; + DRWPass *edit_uv_faces_ps; + DRWPass *edit_uv_stretching_ps; + DRWPass *edit_uv_tiled_image_borders_ps; DRWPass *extra_ps[2]; DRWPass *extra_blend_ps; DRWPass *extra_centers_ps; @@ -247,6 +263,12 @@ typedef struct OVERLAY_PrivateData { DRWShadingGroup *edit_particle_point_grp; DRWShadingGroup *edit_text_overlay_grp; DRWShadingGroup *edit_text_wire_grp[2]; + DRWShadingGroup *edit_uv_verts_grp; + DRWShadingGroup *edit_uv_edges_grp; + DRWShadingGroup *edit_uv_shadow_edges_grp; + DRWShadingGroup *edit_uv_faces_grp; + DRWShadingGroup *edit_uv_face_dots_grp; + DRWShadingGroup *edit_uv_stretching_grp; DRWShadingGroup *extra_grid_grp; DRWShadingGroup *facing_grp[2]; DRWShadingGroup *motion_path_lines_grp; @@ -289,6 +311,7 @@ typedef struct OVERLAY_PrivateData { View3DOverlay overlay; enum eContextObjectMode ctx_mode; + bool is_image_editor; bool clear_in_front; bool use_in_front; bool wireframe_mode; @@ -328,6 +351,29 @@ typedef struct OVERLAY_PrivateData { int select_mode; } edit_particle; struct { + bool do_uv_overlay; + bool do_uv_shadow_overlay; + bool do_uv_stretching_overlay; + bool do_tiled_image_overlay; + + bool do_faces; + bool do_face_dots; + + float uv_opacity; + /* edge drawing */ + OVERLAY_UVLineStyle line_style; + float dash_length; + int do_smooth_wire; + + /* stretching overlay */ + float aspect[2]; + eSpaceImage_UVDT_Stretch draw_type; + ListBase totals; + float total_area_ratio; + float total_area_ratio_inv; + + } edit_uv; + struct { bool transparent; bool show_relations; bool do_pose_xray; @@ -475,6 +521,11 @@ void OVERLAY_edit_particle_cache_init(OVERLAY_Data *vedata); void OVERLAY_edit_particle_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_edit_particle_draw(OVERLAY_Data *vedata); +void OVERLAY_edit_uv_init(OVERLAY_Data *vedata); +void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata); +void OVERLAY_edit_uv_cache_populate(OVERLAY_Data *vedata, Object *ob); +void OVERLAY_edit_uv_draw(OVERLAY_Data *vedata); + void OVERLAY_extra_cache_init(OVERLAY_Data *vedata); void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob); void OVERLAY_extra_blend_draw(OVERLAY_Data *vedata); @@ -573,6 +624,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, void OVERLAY_wireframe_draw(OVERLAY_Data *vedata); void OVERLAY_wireframe_in_front_draw(OVERLAY_Data *vedata); +void OVERLAY_shader_library_ensure(void); GPUShader *OVERLAY_shader_antialiasing(void); GPUShader *OVERLAY_shader_armature_degrees_of_freedom_wire(void); GPUShader *OVERLAY_shader_armature_degrees_of_freedom_solid(void); @@ -602,6 +654,13 @@ GPUShader *OVERLAY_shader_edit_mesh_skin_root(void); GPUShader *OVERLAY_shader_edit_mesh_vert(void); GPUShader *OVERLAY_shader_edit_particle_strand(void); GPUShader *OVERLAY_shader_edit_particle_point(void); +GPUShader *OVERLAY_shader_edit_uv_edges_get(void); +GPUShader *OVERLAY_shader_edit_uv_face_get(void); +GPUShader *OVERLAY_shader_edit_uv_face_dots_get(void); +GPUShader *OVERLAY_shader_edit_uv_verts_get(void); +GPUShader *OVERLAY_shader_edit_uv_stretching_area_get(void); +GPUShader *OVERLAY_shader_edit_uv_stretching_angle_get(void); +GPUShader *OVERLAY_shader_edit_uv_tiled_image_borders_get(void); GPUShader *OVERLAY_shader_extra(bool is_select); GPUShader *OVERLAY_shader_extra_groundline(void); GPUShader *OVERLAY_shader_extra_wire(bool use_object, bool is_select); @@ -610,6 +669,7 @@ GPUShader *OVERLAY_shader_extra_point(void); GPUShader *OVERLAY_shader_facing(void); GPUShader *OVERLAY_shader_gpencil_canvas(void); GPUShader *OVERLAY_shader_grid(void); +GPUShader *OVERLAY_shader_grid_image(void); GPUShader *OVERLAY_shader_image(void); GPUShader *OVERLAY_shader_motion_path_line(void); GPUShader *OVERLAY_shader_motion_path_vert(void); diff --git a/source/blender/draw/engines/overlay/overlay_shader.c b/source/blender/draw/engines/overlay/overlay_shader.c index e3cb052890b..4530d6e8adf 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.c +++ b/source/blender/draw/engines/overlay/overlay_shader.c @@ -70,6 +70,15 @@ extern char datatoc_edit_mesh_analysis_vert_glsl[]; extern char datatoc_edit_mesh_analysis_frag_glsl[]; extern char datatoc_edit_particle_strand_vert_glsl[]; extern char datatoc_edit_particle_point_vert_glsl[]; +extern char datatoc_edit_uv_verts_vert_glsl[]; +extern char datatoc_edit_uv_verts_frag_glsl[]; +extern char datatoc_edit_uv_edges_vert_glsl[]; +extern char datatoc_edit_uv_edges_geom_glsl[]; +extern char datatoc_edit_uv_edges_frag_glsl[]; +extern char datatoc_edit_uv_faces_vert_glsl[]; +extern char datatoc_edit_uv_face_dots_vert_glsl[]; +extern char datatoc_edit_uv_stretching_vert_glsl[]; +extern char datatoc_edit_uv_tiled_image_borders_vert_glsl[]; extern char datatoc_extra_frag_glsl[]; extern char datatoc_extra_vert_glsl[]; extern char datatoc_extra_groundline_vert_glsl[]; @@ -113,6 +122,7 @@ extern char datatoc_xray_fade_frag_glsl[]; extern char datatoc_gpu_shader_depth_only_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_frag_glsl[]; extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; extern char datatoc_gpu_shader_flat_color_frag_glsl[]; extern char datatoc_gpu_shader_point_varying_color_varying_outline_aa_frag_glsl[]; @@ -120,6 +130,7 @@ extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; extern char datatoc_gpencil_common_lib_glsl[]; +extern char datatoc_common_overlay_lib_glsl[]; extern char datatoc_common_colormanagement_lib_glsl[]; extern char datatoc_common_fullscreen_vert_glsl[]; extern char datatoc_common_fxaa_lib_glsl[]; @@ -164,6 +175,13 @@ typedef struct OVERLAY_Shaders { GPUShader *edit_mesh_analysis; GPUShader *edit_particle_strand; GPUShader *edit_particle_point; + GPUShader *edit_uv_verts; + GPUShader *edit_uv_faces; + GPUShader *edit_uv_edges; + GPUShader *edit_uv_face_dots; + GPUShader *edit_uv_stretching_angle; + GPUShader *edit_uv_stretching_area; + GPUShader *edit_uv_tiled_image_borders; GPUShader *extra; GPUShader *extra_select; GPUShader *extra_groundline; @@ -175,6 +193,7 @@ typedef struct OVERLAY_Shaders { GPUShader *facing; GPUShader *gpencil_canvas; GPUShader *grid; + GPUShader *grid_image; GPUShader *image; GPUShader *motion_path_line; GPUShader *motion_path_vert; @@ -203,8 +222,20 @@ typedef struct OVERLAY_Shaders { static struct { OVERLAY_Shaders sh_data[GPU_SHADER_CFG_LEN]; + DRWShaderLibrary *lib; } e_data = {{{NULL}}}; +void OVERLAY_shader_library_ensure(void) +{ + if (e_data.lib == NULL) { + e_data.lib = DRW_shader_library_create(); + /* NOTE: Theses needs to be ordered by dependencies. */ + DRW_SHADER_LIB_ADD(e_data.lib, common_globals_lib); + DRW_SHADER_LIB_ADD(e_data.lib, common_overlay_lib); + DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib); + } +} + GPUShader *OVERLAY_shader_antialiasing(void) { OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; @@ -1012,6 +1043,20 @@ GPUShader *OVERLAY_shader_grid(void) return sh_data->grid; } +GPUShader *OVERLAY_shader_grid_image(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->grid_image) { + sh_data->grid_image = DRW_shader_create_with_shaderlib( + datatoc_edit_uv_tiled_image_borders_vert_glsl, + NULL, + datatoc_gpu_shader_uniform_color_frag_glsl, + e_data.lib, + "#define blender_srgb_to_framebuffer_space(a) a\n"); + } + return sh_data->grid_image; +} + GPUShader *OVERLAY_shader_image(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -1449,6 +1494,108 @@ GPUShader *OVERLAY_shader_xray_fade(void) return sh_data->xray_fade; } +/* -------------------------------------------------------------------- */ +/** \name Edit UV shaders + * \{ */ + +GPUShader *OVERLAY_shader_edit_uv_edges_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_edges) { + sh_data->edit_uv_edges = DRW_shader_create_with_shaderlib(datatoc_edit_uv_edges_vert_glsl, + datatoc_edit_uv_edges_geom_glsl, + datatoc_edit_uv_edges_frag_glsl, + e_data.lib, + NULL); + } + return sh_data->edit_uv_edges; +} + +GPUShader *OVERLAY_shader_edit_uv_face_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_faces) { + sh_data->edit_uv_faces = DRW_shader_create_with_shaderlib( + datatoc_edit_uv_faces_vert_glsl, + NULL, + datatoc_gpu_shader_flat_color_frag_glsl, + e_data.lib, + "#define blender_srgb_to_framebuffer_space(a) a\n"); + } + return sh_data->edit_uv_faces; +} + +GPUShader *OVERLAY_shader_edit_uv_face_dots_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_face_dots) { + sh_data->edit_uv_face_dots = DRW_shader_create_with_shaderlib( + datatoc_edit_uv_face_dots_vert_glsl, + NULL, + datatoc_gpu_shader_flat_color_frag_glsl, + e_data.lib, + "#define blender_srgb_to_framebuffer_space(a) a\n"); + } + return sh_data->edit_uv_face_dots; +} + +GPUShader *OVERLAY_shader_edit_uv_verts_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_verts) { + sh_data->edit_uv_verts = DRW_shader_create_with_shaderlib( + datatoc_edit_uv_verts_vert_glsl, NULL, datatoc_edit_uv_verts_frag_glsl, e_data.lib, NULL); + } + + return sh_data->edit_uv_verts; +} + +GPUShader *OVERLAY_shader_edit_uv_stretching_area_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_stretching_area) { + sh_data->edit_uv_stretching_area = DRW_shader_create_with_shaderlib( + datatoc_edit_uv_stretching_vert_glsl, + NULL, + datatoc_gpu_shader_2D_smooth_color_frag_glsl, + e_data.lib, + "#define blender_srgb_to_framebuffer_space(a) a\n"); + } + + return sh_data->edit_uv_stretching_area; +} + +GPUShader *OVERLAY_shader_edit_uv_stretching_angle_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_stretching_angle) { + sh_data->edit_uv_stretching_angle = DRW_shader_create_with_shaderlib( + datatoc_edit_uv_stretching_vert_glsl, + NULL, + datatoc_gpu_shader_2D_smooth_color_frag_glsl, + e_data.lib, + "#define blender_srgb_to_framebuffer_space(a) a\n#define STRETCH_ANGLE\n"); + } + + return sh_data->edit_uv_stretching_angle; +} + +GPUShader *OVERLAY_shader_edit_uv_tiled_image_borders_get(void) +{ + OVERLAY_Shaders *sh_data = &e_data.sh_data[0]; + if (!sh_data->edit_uv_tiled_image_borders) { + sh_data->edit_uv_tiled_image_borders = DRW_shader_create_with_shaderlib( + datatoc_edit_uv_tiled_image_borders_vert_glsl, + NULL, + datatoc_gpu_shader_uniform_color_frag_glsl, + e_data.lib, + "#define blender_srgb_to_framebuffer_space(a) a\n"); + } + return sh_data->edit_uv_tiled_image_borders; +} + +/* \} */ + static OVERLAY_InstanceFormats g_formats = {NULL}; OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void) @@ -1521,6 +1668,8 @@ OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void) void OVERLAY_shader_free(void) { + DRW_SHADER_LIB_FREE_SAFE(e_data.lib); + for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) { OVERLAY_Shaders *sh_data = &e_data.sh_data[sh_data_index]; GPUShader **sh_data_as_array = (GPUShader **)sh_data; diff --git a/source/blender/draw/engines/overlay/shaders/background_frag.glsl b/source/blender/draw/engines/overlay/shaders/background_frag.glsl index d5aaaf75b79..71bfd2f8e73 100644 --- a/source/blender/draw/engines/overlay/shaders/background_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/background_frag.glsl @@ -13,6 +13,7 @@ out vec4 fragColor; #define BG_GRADIENT 1 #define BG_CHECKER 2 #define BG_RADIAL 3 +#define BG_SOLID_CHECKER 4 #define SQRT2 1.4142135623730950488 /* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ @@ -43,7 +44,11 @@ void main() vec3 col_high; vec3 col_low; - switch (bgType) { + /* BG_SOLID_CHECKER selects BG_SOLID when no pixel has been drawn otherwise use the BG_CHERKER. + */ + int bg_type = bgType == BG_SOLID_CHECKER ? (depth == 1.0 ? BG_SOLID : BG_CHECKER) : bgType; + + switch (bg_type) { case BG_SOLID: bg_col = colorBackground.rgb; break; diff --git a/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl b/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl new file mode 100644 index 00000000000..65aeb81a4ef --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/common_overlay_lib.glsl @@ -0,0 +1,5 @@ +#define OVERLAY_UV_LINE_STYLE_OUTLINE 0 +#define OVERLAY_UV_LINE_STYLE_DASH 1 +#define OVERLAY_UV_LINE_STYLE_BLACK 2 +#define OVERLAY_UV_LINE_STYLE_WHITE 3 +#define OVERLAY_UV_LINE_STYLE_SHADOW 4 diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl new file mode 100644 index 00000000000..b81fdd2c712 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_frag.glsl @@ -0,0 +1,77 @@ +#pragma BLENDER_REQUIRE(common_globals_lib.glsl) +#pragma BLENDER_REQUIRE(common_overlay_lib.glsl) + +uniform int lineStyle; +uniform bool doSmoothWire; +uniform float alpha; +uniform float dashLength; + +in float selectionFac_f; +noperspective in float edgeCoord_f; +noperspective in vec2 stipplePos_f; +flat in vec2 stippleStart_f; + +layout(location = 0) out vec4 fragColor; + +#define M_1_SQRTPI 0.5641895835477563 /* 1/sqrt(pi) */ + +/** + * We want to know how much a pixel is covered by a line. + * We replace the square pixel with acircle of the same area and try to find the intersection area. + * The area we search is the circular segment. https://en.wikipedia.org/wiki/Circular_segment + * The formula for the area uses inverse trig function and is quite complexe. Instead, + * we approximate it by using the smoothstep function and a 1.05 factor to the disc radius. + */ +#define DISC_RADIUS (M_1_SQRTPI * 1.05) +#define GRID_LINE_SMOOTH_START (0.5 - DISC_RADIUS) +#define GRID_LINE_SMOOTH_END (0.5 + DISC_RADIUS) + +void main() +{ + vec4 inner_color = vec4(vec3(0.0), 1.0); + vec4 outer_color = vec4(0.0); + + vec2 dd = fwidth(stipplePos_f); + float line_distance = distance(stipplePos_f, stippleStart_f) / max(dd.x, dd.y); + + if (lineStyle == OVERLAY_UV_LINE_STYLE_OUTLINE) { + inner_color = mix(colorWireEdit, colorEdgeSelect, selectionFac_f); + outer_color = vec4(vec3(0.0), 1.0); + } + else if (lineStyle == OVERLAY_UV_LINE_STYLE_DASH) { + if (fract(line_distance / dashLength) < 0.5) { + inner_color = mix(vec4(1.0), colorEdgeSelect, selectionFac_f); + } + } + else if (lineStyle == OVERLAY_UV_LINE_STYLE_BLACK) { + vec4 base_color = vec4(vec3(0.0), 1.0); + inner_color = mix(base_color, colorEdgeSelect, selectionFac_f); + } + else if (lineStyle == OVERLAY_UV_LINE_STYLE_WHITE) { + vec4 base_color = vec4(1.0); + inner_color = mix(base_color, colorEdgeSelect, selectionFac_f); + } + else if (lineStyle == OVERLAY_UV_LINE_STYLE_SHADOW) { + inner_color = colorUVShadow; + } + + float dist = abs(edgeCoord_f) - max(sizeEdge - 0.5, 0.0); + float dist_outer = dist - max(sizeEdge, 1.0); + float mix_w; + float mix_w_outer; + + if (doSmoothWire) { + mix_w = smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, dist); + mix_w_outer = smoothstep(GRID_LINE_SMOOTH_START, GRID_LINE_SMOOTH_END, dist_outer); + } + else { + mix_w = step(0.5, dist); + mix_w_outer = step(0.5, dist_outer); + } + + vec4 final_color = mix(outer_color, inner_color, 1.0 - mix_w * outer_color.a); + final_color.a *= 1.0 - (outer_color.a > 0.0 ? mix_w_outer : mix_w); + final_color.a *= alpha; + + fragColor = final_color; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl new file mode 100644 index 00000000000..4f8d553a220 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_geom.glsl @@ -0,0 +1,63 @@ +#pragma BLENDER_REQUIRE(common_globals_lib.glsl) +#pragma BLENDER_REQUIRE(common_overlay_lib.glsl) + +layout(lines) in; +layout(triangle_strip, max_vertices = 4) out; + +in float selectionFac[2]; +flat in vec2 stippleStart[2]; +noperspective in vec2 stipplePos[2]; + +uniform int lineStyle; +uniform bool doSmoothWire; + +out float selectionFac_f; +noperspective out float edgeCoord_f; +noperspective out vec2 stipplePos_f; +flat out vec2 stippleStart_f; + +void do_vertex( + vec4 pos, float selection_fac, vec2 stipple_start, vec2 stipple_pos, float coord, vec2 offset) +{ + selectionFac_f = selection_fac; + edgeCoord_f = coord; + stippleStart_f = stipple_start; + stipplePos_f = stipple_pos; + + gl_Position = pos; + /* Multiply offset by 2 because gl_Position range is [-1..1]. */ + gl_Position.xy += offset * 2.0; + EmitVertex(); +} + +void main() +{ + vec2 ss_pos[2]; + vec4 pos0 = gl_in[0].gl_Position; + vec4 pos1 = gl_in[1].gl_Position; + ss_pos[0] = pos0.xy / pos0.w; + ss_pos[1] = pos1.xy / pos1.w; + + float half_size = sizeEdge; + /* Enlarge edge for outline drawing. */ + /* Factor of 3.0 out of nowhere! Seems to fix issues with float imprecision. */ + half_size += (lineStyle == OVERLAY_UV_LINE_STYLE_OUTLINE) ? + max(sizeEdge * (doSmoothWire ? 1.0 : 3.0), 1.0) : + 0.0; + /* Add 1 px for AA */ + if (doSmoothWire) { + half_size += 0.5; + } + + vec2 line = ss_pos[0] - ss_pos[1]; + vec2 line_dir = normalize(line); + vec2 line_perp = vec2(-line_dir.y, line_dir.x); + vec2 edge_ofs = line_perp * sizeViewportInv * ceil(half_size); + + do_vertex(pos0, selectionFac[0], stippleStart[0], stipplePos[0], half_size, edge_ofs.xy); + do_vertex(pos0, selectionFac[0], stippleStart[0], stipplePos[0], -half_size, -edge_ofs.xy); + do_vertex(pos1, selectionFac[1], stippleStart[1], stipplePos[1], half_size, edge_ofs.xy); + do_vertex(pos1, selectionFac[1], stippleStart[1], stipplePos[1], -half_size, -edge_ofs.xy); + + EndPrimitive(); +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl new file mode 100644 index 00000000000..4661cf248e6 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_edges_vert.glsl @@ -0,0 +1,32 @@ +#pragma BLENDER_REQUIRE(common_globals_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +in vec3 pos; +in vec2 u; +in int flag; + +out float selectionFac; +noperspective out vec2 stipplePos; +flat out vec2 stippleStart; + +void main() +{ + vec3 world_pos = point_object_to_world(vec3(u, 0.0)); + gl_Position = point_world_to_ndc(world_pos); + /* Snap vertices to the pixel grid to reduce artifacts. */ + vec2 half_viewport_res = sizeViewport.xy * 0.5; + vec2 half_pixel_offset = sizeViewportInv * 0.5; + gl_Position.xy = floor(gl_Position.xy * half_viewport_res) / half_viewport_res + + half_pixel_offset; + + bool is_select = (flag & VERT_UV_SELECT) != 0; + selectionFac = is_select ? 1.0 : 0.0; + /* Move selected edges to the top + * Vertices are between 0.0 and 0.2, Edges between 0.2 and 0.4 + * actual pixels are at 0.75, 1.0 is used for the background. */ + float depth = is_select ? 0.25 : 0.35; + gl_Position.z = depth; + + /* Avoid precision loss. */ + stippleStart = stipplePos = 500.0 + 500.0 * (gl_Position.xy / gl_Position.w); +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl new file mode 100644 index 00000000000..61152c83a29 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_face_dots_vert.glsl @@ -0,0 +1,18 @@ +#pragma BLENDER_REQUIRE(common_globals_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +uniform float pointSize; + +in vec2 u; +in int flag; + +flat out vec4 finalColor; + +void main() +{ + vec3 world_pos = point_object_to_world(vec3(u, 0.0)); + gl_Position = point_world_to_ndc(world_pos); + + finalColor = ((flag & FACE_UV_SELECT) != 0) ? colorVertexSelect : vec4(colorWire.rgb, 1.0); + gl_PointSize = pointSize; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl new file mode 100644 index 00000000000..cf1018ae5f9 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_faces_vert.glsl @@ -0,0 +1,22 @@ +#pragma BLENDER_REQUIRE(common_globals_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +uniform float uvOpacity; + +in vec2 u; +in int flag; + +flat out vec4 finalColor; + +void main() +{ + vec3 world_pos = point_object_to_world(vec3(u, 0.0)); + gl_Position = point_world_to_ndc(world_pos); + + bool is_selected = (flag & FACE_UV_SELECT) != 0; + bool is_active = (flag & FACE_UV_ACTIVE) != 0; + + finalColor = (is_selected) ? colorFaceSelect : colorFace; + finalColor = (is_active) ? colorEditMeshActive : finalColor; + finalColor.a *= uvOpacity; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl new file mode 100644 index 00000000000..ce97f1e27ac --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_stretching_vert.glsl @@ -0,0 +1,98 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +uniform vec2 aspect; +in vec2 pos; + +#ifdef STRETCH_ANGLE +in vec2 uv_angles; +in float angle; + +#else +in float ratio; +uniform float totalAreaRatio; +uniform float totalAreaRatioInv; + +#endif + +noperspective out vec4 finalColor; + +vec3 weight_to_rgb(float weight) +{ + vec3 r_rgb; + float blend = ((weight / 2.0) + 0.5); + + if (weight <= 0.25) { /* blue->cyan */ + r_rgb[0] = 0.0; + r_rgb[1] = blend * weight * 4.0; + r_rgb[2] = blend; + } + else if (weight <= 0.50) { /* cyan->green */ + r_rgb[0] = 0.0; + r_rgb[1] = blend; + r_rgb[2] = blend * (1.0 - ((weight - 0.25) * 4.0)); + } + else if (weight <= 0.75) { /* green->yellow */ + r_rgb[0] = blend * ((weight - 0.50) * 4.0); + r_rgb[1] = blend; + r_rgb[2] = 0.0; + } + else if (weight <= 1.0) { /* yellow->red */ + r_rgb[0] = blend; + r_rgb[1] = blend * (1.0 - ((weight - 0.75) * 4.0)); + r_rgb[2] = 0.0; + } + else { + /* exceptional value, unclamped or nan, + * avoid uninitialized memory use */ + r_rgb[0] = 1.0; + r_rgb[1] = 0.0; + r_rgb[2] = 1.0; + } + + return r_rgb; +} + +#define M_PI 3.1415926535897932 + +vec2 angle_to_v2(float angle) +{ + return vec2(cos(angle), sin(angle)); +} + +/* Adapted from BLI_math_vector.h */ +float angle_normalized_v2v2(vec2 v1, vec2 v2) +{ + v1 = normalize(v1 * aspect); + v2 = normalize(v2 * aspect); + /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */ + bool q = (dot(v1, v2) >= 0.0); + vec2 v = (q) ? (v1 - v2) : (v1 + v2); + float a = 2.0 * asin(length(v) / 2.0); + return (q) ? a : M_PI - a; +} + +float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_tot_ratio) +{ + ratio *= (ratio > 0.0f) ? tot_ratio : -inv_tot_ratio; + return (ratio > 1.0f) ? (1.0f / ratio) : ratio; +} + +void main() +{ + vec3 world_pos = point_object_to_world(vec3(pos, 0.0)); + gl_Position = point_world_to_ndc(world_pos); + +#ifdef STRETCH_ANGLE + vec2 v1 = angle_to_v2(uv_angles.x * M_PI); + vec2 v2 = angle_to_v2(uv_angles.y * M_PI); + float uv_angle = angle_normalized_v2v2(v1, v2) / M_PI; + float stretch = 1.0 - abs(uv_angle - angle); + stretch = stretch; + stretch = 1.0 - stretch * stretch; +#else + float stretch = 1.0 - area_ratio_to_stretch(ratio, totalAreaRatio, totalAreaRatioInv); + +#endif + + finalColor = vec4(weight_to_rgb(stretch), 1.0); +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl new file mode 100644 index 00000000000..c762858a910 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_tiled_image_borders_vert.glsl @@ -0,0 +1,12 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +in vec3 pos; + +void main() +{ + /* `pos` contains the coordinates of a quad (-1..1). but we need the coordinates of an image + * plane (0..1) */ + vec3 image_pos = pos * 0.5 + 0.5; + vec4 position = point_object_to_ndc(image_pos); + gl_Position = position; +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl new file mode 100644 index 00000000000..11694de38ca --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_frag.glsl @@ -0,0 +1,33 @@ + +uniform vec4 outlineColor; + +in vec4 radii; +in vec4 fillColor; +out vec4 fragColor; + +void main() +{ + float dist = length(gl_PointCoord - vec2(0.5)); + + // transparent outside of point + // --- 0 --- + // smooth transition + // --- 1 --- + // pure outline color + // --- 2 --- + // smooth transition + // --- 3 --- + // pure fill color + // ... + // dist = 0 at center of point + + float midStroke = 0.5 * (radii[1] + radii[2]); + + if (dist > midStroke) { + fragColor.rgb = outlineColor.rgb; + fragColor.a = mix(outlineColor.a, 0.0, smoothstep(radii[1], radii[0], dist)); + } + else { + fragColor = mix(fillColor, outlineColor, smoothstep(radii[3], radii[2], dist)); + } +} diff --git a/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl new file mode 100644 index 00000000000..327a35ce6b2 --- /dev/null +++ b/source/blender/draw/engines/overlay/shaders/edit_uv_verts_vert.glsl @@ -0,0 +1,44 @@ +#pragma BLENDER_REQUIRE(common_globals_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +uniform float pointSize; +uniform float outlineWidth; + +in vec2 u; +in int flag; + +out vec4 fillColor; +out vec4 outlineColor; +out vec4 radii; + +/* TODO Theme? */ +const vec4 pinned_col = vec4(1.0, 0.0, 0.0, 1.0); + +void main() +{ + bool is_selected = (flag & (VERT_UV_SELECT | FACE_UV_SELECT)) != 0; + bool is_pinned = (flag & VERT_UV_PINNED) != 0; + vec4 deselect_col = (is_pinned) ? pinned_col : vec4(colorWire.rgb, 1.0); + fillColor = (is_selected) ? colorVertexSelect : deselect_col; + outlineColor = (is_pinned) ? pinned_col : vec4(fillColor.rgb, 0.0); + + vec3 world_pos = point_object_to_world(vec3(u, 0.0)); + /* Move selected vertices to the top + * Vertices are between 0.0 and 0.2, Edges between 0.2 and 0.4 + * actual pixels are at 0.75, 1.0 is used for the background. */ + float depth = is_selected ? 0.05 : 0.15; + gl_Position = vec4(point_world_to_ndc(world_pos).xy, depth, 1.0); + gl_PointSize = pointSize; + + // calculate concentric radii in pixels + float radius = 0.5 * pointSize; + + // start at the outside and progress toward the center + radii[0] = radius; + radii[1] = radius - 1.0; + radii[2] = radius - outlineWidth; + radii[3] = radius - outlineWidth - 1.0; + + // convert to PointCoord units + radii /= pointSize; +} diff --git a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl index dd0e771ad93..6df4ead9f2a 100644 --- a/source/blender/draw/engines/overlay/shaders/grid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/grid_vert.glsl @@ -12,7 +12,7 @@ uniform int gridFlag; #define PLANE_YZ (1 << 6) #define CLIP_Z_POS (1 << 7) #define CLIP_Z_NEG (1 << 8) - +#define PLANE_IMAGE (1 << 11) in vec3 pos; out vec3 local_pos; @@ -28,9 +28,12 @@ void main() else if ((gridFlag & PLANE_XZ) != 0) { vert_pos = vec3(pos.x, 0.0, pos.y); } - else { + else if ((gridFlag & PLANE_YZ) != 0) { vert_pos = vec3(0.0, pos.x, pos.y); } + else /* PLANE_IMAGE */ { + vert_pos = vec3(pos.xy * 0.5 + 0.5, 0.0); + } local_pos = vert_pos; |