Changeset View
Changeset View
Standalone View
Standalone View
source/blender/draw/editors/image_uv_editor.c
- This file was added.
| /* | |||||
| * 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 2016, Blender Foundation. | |||||
| */ | |||||
| /** \file | |||||
| * \ingroup draw_editors | |||||
| * | |||||
| * Draw engine to draw the Image/UV editor | |||||
| */ | |||||
| #include "DRW_render.h" | |||||
| #include "draw_cache_impl.h" | |||||
| #include "GPU_batch.h" | |||||
| #include "GPU_shader.h" | |||||
| #include "BKE_object.h" | |||||
| #include "ED_image.h" | |||||
| #include "IMB_imbuf.h" | |||||
| #include "IMB_imbuf_types.h" | |||||
| #include "IMB_colormanagement.h" | |||||
| #include "DNA_space_types.h" | |||||
| #include "DNA_screen_types.h" | |||||
| #include "UI_resources.h" | |||||
| #include "UI_interface.h" | |||||
| #include "image_uv_editor.h" | |||||
| /* Shaders */ | |||||
| /* TODO: When in Paint mode and active object is tpaint or edit mesh, a shadow uv is shown */ | |||||
| /* *********** LISTS *********** */ | |||||
| /* GPUViewport.storage | |||||
| * Is freed everytime the viewport engine changes */ | |||||
| typedef struct IMAGE_UV_EDITOR_PrivateData { | |||||
| DRWShadingGroup *uv_overlay_faces_shgrp; | |||||
| DRWShadingGroup *uv_overlay_face_dots_shgrp; | |||||
| DRWShadingGroup *uv_overlay_verts_shgrp[2]; | |||||
| DRWShadingGroup *uv_overlay_edges_shgrp; | |||||
| DRWShadingGroup *uv_stretching_overlay_shgrp; | |||||
| DRWShadingGroup *uv_shadow_overlay_shgrp; | |||||
| float uv_stretching_total_area; | |||||
| float uv_stretching_total_area_uv; | |||||
| float uv_stretching_total_area_ratio; | |||||
| float uv_stretching_total_area_ratio_inv; | |||||
| } IMAGE_UV_EDITOR_PrivateData; | |||||
| typedef struct IMAGE_UV_EDITOR_StorageList { | |||||
| struct IMAGE_UV_EDITOR_PrivateData *g_data; | |||||
| } IMAGE_UV_EDITOR_StorageList; | |||||
| typedef struct IMAGE_UV_EDITOR_PassList { | |||||
| DRWPass *image_pass; | |||||
| DRWPass *uv_overlay_verts_pass; | |||||
| DRWPass *uv_overlay_edges_pass; | |||||
| DRWPass *uv_overlay_faces_pass; | |||||
| DRWPass *uv_stretching_overlay_pass; | |||||
| DRWPass *uv_shadow_overlay_pass; | |||||
| } IMAGE_UV_EDITOR_PassList; | |||||
| typedef struct IMAGE_UV_EDITOR_Data { | |||||
| void *engine_type; | |||||
| DRWViewportEmptyList *fbl; | |||||
| DRWViewportEmptyList *txl; | |||||
| IMAGE_UV_EDITOR_PassList *psl; | |||||
| IMAGE_UV_EDITOR_StorageList *stl; | |||||
| } IMAGE_UV_EDITOR_Data; | |||||
| typedef struct IMAGE_UV_EDITOR_DrawCallData { | |||||
| struct IMAGE_UV_EDITOR_DrawCallData *next, *prev; | |||||
| float image_mat[4][4]; | |||||
| } IMAGE_UV_EDITOR_DrawCallData; | |||||
| typedef struct IMAGE_UV_EDITOR_Shaders { | |||||
| } IMAGE_UV_EDITOR_Shaders; | |||||
| /* *********** STATIC *********** */ | |||||
| static struct { | |||||
| int flag; | |||||
| IMAGE_UV_EDITOR_Shaders shaders; | |||||
| /* TODO: when repeated we need multiple image_mats */ | |||||
| void *lock; | |||||
| ImBuf *ibuf; | |||||
| GPUTexture *texture; | |||||
| bool do_color_management; | |||||
| bool do_channel_shuffling; | |||||
| bool do_uv_overlay; | |||||
| bool do_uv_overlay_show_faces; | |||||
| bool do_uv_overlay_show_faces_dots; | |||||
| bool do_uv_stretching_overlay; | |||||
| bool do_shadow_overlay; | |||||
| void *cache_handle; | |||||
| GPUBatch *gpu_batch_image; | |||||
| ListBase draw_call_data; | |||||
| IMAGE_UV_EDITOR_DrawCallData *default_draw_call_data; | |||||
| } e_data = {0}; /* Engine data */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Image Pass | |||||
| * \{ */ | |||||
| static DRWShadingGroup *image_uv_editor_shgroup_create(IMAGE_UV_EDITOR_PassList *psl) | |||||
| { | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; | |||||
| GPUShader *shader = NULL; | |||||
| if (e_data.do_channel_shuffling) { | |||||
| shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); | |||||
| } | |||||
| else { | |||||
| shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE); | |||||
| } | |||||
| DRWShadingGroup *shgrp = DRW_shgroup_create(shader, psl->image_pass); | |||||
| if (e_data.do_channel_shuffling) { | |||||
| float shuffle[4] = {0.0f, 0.0f, 0.0f, 0.0f}; | |||||
| float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; | |||||
| if (sima->flag & SI_SHOW_R) { | |||||
| shuffle[0] = 1.0f; | |||||
| } | |||||
| else if (sima->flag & SI_SHOW_G) { | |||||
| shuffle[1] = 1.0f; | |||||
| } | |||||
| else if (sima->flag & SI_SHOW_B) { | |||||
| shuffle[2] = 1.0f; | |||||
| } | |||||
| else if (sima->flag & SI_SHOW_ALPHA) { | |||||
| shuffle[3] = 1.0f; | |||||
| } | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", shuffle); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "color", color); | |||||
| } | |||||
| return shgrp; | |||||
| } | |||||
| static IMAGE_UV_EDITOR_DrawCallData *image_uv_editor_create_call_data(int image_offset_x, | |||||
| int image_offset_y) | |||||
| { | |||||
| IMAGE_UV_EDITOR_DrawCallData *draw_call_data = MEM_callocN(sizeof(IMAGE_UV_EDITOR_DrawCallData), | |||||
| __func__); | |||||
| BLI_addtail(&e_data.draw_call_data, draw_call_data); | |||||
| unit_m4(draw_call_data->image_mat); | |||||
| // TODO: +0.5 px width | |||||
| translate_m4(draw_call_data->image_mat, (float)image_offset_x, (float)image_offset_y, 0.0f); | |||||
| return draw_call_data; | |||||
| } | |||||
| static void image_uv_editor_add_call(DRWShadingGroup *shgrp, | |||||
| int image_offset_x, | |||||
| int image_offset_y) | |||||
| { | |||||
| IMAGE_UV_EDITOR_DrawCallData *draw_call_data = (image_offset_x || image_offset_y) ? | |||||
| image_uv_editor_create_call_data( | |||||
| image_offset_x, image_offset_y) : | |||||
| e_data.default_draw_call_data; | |||||
| DRW_shgroup_call_obmat(shgrp, e_data.gpu_batch_image, draw_call_data->image_mat); | |||||
| } | |||||
| static void image_uv_editor_add_image(IMAGE_UV_EDITOR_PassList *psl, | |||||
| Image *ima, | |||||
| ImageUser *iuser, | |||||
| ImBuf *ibuf) | |||||
| { | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; | |||||
| e_data.do_color_management = (sima->flag & | |||||
| (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B | SI_SHOW_ALPHA)) == 0; | |||||
| e_data.do_channel_shuffling = sima->flag & (SI_SHOW_R | SI_SHOW_G | SI_SHOW_B | SI_SHOW_ALPHA); | |||||
| unsigned char *display_buffer; | |||||
| ColorManagedViewSettings *view_settings; | |||||
| ColorManagedDisplaySettings *display_settings; | |||||
| if (ima && ibuf) { | |||||
| DRWShadingGroup *shgrp = image_uv_editor_shgroup_create(psl); | |||||
| if (e_data.do_color_management) { | |||||
| IMB_colormanagement_display_settings_from_ctx( | |||||
| draw_ctx->evil_C, &view_settings, &display_settings); | |||||
| display_buffer = IMB_display_buffer_acquire( | |||||
| ibuf, view_settings, display_settings, &e_data.cache_handle); | |||||
| if (display_buffer) { | |||||
| e_data.texture = GPU_texture_create_nD(ibuf->x, | |||||
| ibuf->y, | |||||
| 0, | |||||
| 2, | |||||
| display_buffer, | |||||
| GPU_RGBA8, | |||||
| GPU_DATA_UNSIGNED_BYTE, | |||||
| 0, | |||||
| false, | |||||
| NULL); | |||||
| } | |||||
| GPU_texture_bind(e_data.texture, 0); | |||||
| GPU_texture_filters(e_data.texture, GPU_LINEAR, GPU_NEAREST); | |||||
| GPU_texture_unbind(e_data.texture); | |||||
| } | |||||
| else { | |||||
| e_data.texture = GPU_texture_from_blender(ima, iuser, GL_TEXTURE_2D); | |||||
| } | |||||
| if (e_data.texture) { | |||||
| DRW_shgroup_uniform_texture(shgrp, "image", e_data.texture); | |||||
| if (sima->flag & SI_DRAW_TILE) { | |||||
| // TODO: When the image is a single image we could do this in the shader... | |||||
| // That will save a lot of drawing time. | |||||
| ARegion *ar = draw_ctx->ar; | |||||
| const int xmax = ceil(ar->v2d.cur.xmax); | |||||
| const int ymax = ceil(ar->v2d.cur.ymax); | |||||
| const int xmin = floor(ar->v2d.cur.xmin); | |||||
| const int ymin = floor(ar->v2d.cur.ymin); | |||||
| for (int x = xmin; x <= xmax; x++) { | |||||
| for (int y = ymin; y <= ymax; y++) { | |||||
| image_uv_editor_add_call(shgrp, x, y); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| image_uv_editor_add_call(shgrp, 0, 0); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| // TODO: draw checkerboard with image 256x256 in pixel space. | |||||
| } | |||||
| } | |||||
| /* \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name UV Overlay Pass | |||||
| * \{ */ | |||||
| static bool image_uv_editor_draw_face_dots(const ToolSettings *ts) | |||||
| { | |||||
| /* checks if we are selecting only faces */ | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | |||||
| return (ts->selectmode & SCE_SELECT_FACE) != 0; | |||||
| } | |||||
| else { | |||||
| return (ts->uv_selectmode == UV_SELECT_FACE); | |||||
| } | |||||
| } | |||||
| static bool image_uv_editor_edges_interpolate(const ToolSettings *ts) | |||||
| { | |||||
| bool interpolate_edges; | |||||
| if (ts->uv_flag & UV_SYNC_SELECTION) { | |||||
| interpolate_edges = (ts->selectmode & SCE_SELECT_VERTEX) != 0; | |||||
| } | |||||
| else { | |||||
| interpolate_edges = (ts->uv_selectmode == UV_SELECT_VERTEX); | |||||
| } | |||||
| return interpolate_edges; | |||||
| } | |||||
| static bool image_uv_editor_edges_smooth(SpaceImage *sima) | |||||
| { | |||||
| return (sima->flag & SI_SMOOTH_UV) != 0; | |||||
| } | |||||
| static DRWShadingGroup *image_uv_editor_face_shgroup_create(IMAGE_UV_EDITOR_PassList *psl) | |||||
| { | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_FACES); | |||||
| DRWShadingGroup *shgrp = DRW_shgroup_create(sh, psl->uv_overlay_faces_pass); | |||||
| float face_color[4]; | |||||
| float face_select_color[4]; | |||||
| float face_active_color[4]; | |||||
| UI_GetThemeColor4fv(TH_FACE, face_color); | |||||
| UI_GetThemeColor4fv(TH_FACE_SELECT, face_select_color); | |||||
| UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, face_active_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "faceColor", face_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "selectColor", face_select_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "activeColor", face_active_color); | |||||
| return shgrp; | |||||
| } | |||||
| static DRWShadingGroup *image_uv_editor_edge_shgroup_create(IMAGE_UV_EDITOR_PassList *psl) | |||||
| { | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; | |||||
| const bool interpolate_edges = image_uv_editor_edges_interpolate(draw_ctx->scene->toolsettings); | |||||
| DRWShadingGroup *shgrp; | |||||
| const float black_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; | |||||
| const float white_color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; | |||||
| float edge_select_color[4]; | |||||
| UI_GetThemeColor4fv(TH_EDGE_SELECT, edge_select_color); | |||||
| switch (sima->dt_uv) { | |||||
| case SI_UVDT_DASH: { | |||||
| static float dash_colors[8] = {0.56f, 0.56f, 0.56f, 1.0f, 0.07f, 0.07f, 0.07f, 1.0f}; | |||||
| const float *viewport_size = DRW_viewport_size_get(); | |||||
| float viewport_size_processed[2] = {viewport_size[0] / UI_DPI_FAC, | |||||
| viewport_size[1] / UI_DPI_FAC}; | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); | |||||
| shgrp = DRW_shgroup_create(sh, psl->uv_overlay_edges_pass); | |||||
| DRW_shgroup_uniform_vec4(shgrp, "colors", dash_colors, 2); | |||||
| DRW_shgroup_uniform_vec2_copy(shgrp, "viewport_size", viewport_size_processed); | |||||
| DRW_shgroup_uniform_int_copy(shgrp, "colors_len", 2); | |||||
| DRW_shgroup_uniform_float_copy(shgrp, "dash_width", 4.0f); | |||||
| DRW_shgroup_uniform_float_copy(shgrp, "dash_factor", 0.5f); | |||||
| break; | |||||
| } | |||||
| case SI_UVDT_BLACK: { | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader( | |||||
| (interpolate_edges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES); | |||||
| shgrp = DRW_shgroup_create(sh, psl->uv_overlay_edges_pass); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "edgeColor", black_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "selectColor", edge_select_color); | |||||
| break; | |||||
| } | |||||
| case SI_UVDT_WHITE: { | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader( | |||||
| (interpolate_edges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES); | |||||
| shgrp = DRW_shgroup_create(sh, psl->uv_overlay_edges_pass); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "edgeColor", white_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "selectColor", edge_select_color); | |||||
| break; | |||||
| } | |||||
| case SI_UVDT_OUTLINE: { | |||||
| /* TODO: this is a dummy implementation so this choice does not crash */ | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_EDGES); | |||||
| shgrp = DRW_shgroup_create(sh, psl->uv_overlay_edges_pass); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "edgeColor", white_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "selectColor", edge_select_color); | |||||
| break; | |||||
| } | |||||
| } | |||||
| return shgrp; | |||||
| } | |||||
| /* \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name UV Stretching Overlay Pass | |||||
| * \{ */ | |||||
| static DRWShadingGroup *image_uv_editor_stretching_shgroup_create(IMAGE_UV_EDITOR_PassList *psl) | |||||
| { | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; | |||||
| DRWShadingGroup *shgrp = NULL; | |||||
| if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) { | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE); | |||||
| shgrp = DRW_shgroup_create(sh, psl->uv_stretching_overlay_pass); | |||||
| float asp[2]; | |||||
| ED_space_image_get_uv_aspect(sima, &asp[0], &asp[1]); | |||||
| DRW_shgroup_uniform_vec2_copy(shgrp, "aspect", asp); | |||||
| } | |||||
| else if (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) { | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_AREA); | |||||
| shgrp = DRW_shgroup_create(sh, psl->uv_stretching_overlay_pass); | |||||
| // Uniforms for the stretchign ratio are set in image_uv_editor_stretching_ratio_update | |||||
| } | |||||
| return shgrp; | |||||
| } | |||||
| static GPUBatch *image_uv_editor_stretching_batch_get(IMAGE_UV_EDITOR_PrivateData *pd, | |||||
| struct Mesh *mesh) | |||||
| { | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; | |||||
| GPUBatch *geom = NULL; | |||||
| if (sima->dt_uvstretch == SI_UVDT_STRETCH_ANGLE) { | |||||
| geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(mesh); | |||||
| } | |||||
| else if (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA) { | |||||
| float *tmp_tot_area, *tmp_tot_area_uv; | |||||
| geom = DRW_mesh_batch_cache_get_edituv_faces_stretch_area( | |||||
| mesh, &tmp_tot_area, &tmp_tot_area_uv); | |||||
| pd->uv_stretching_total_area += *tmp_tot_area; | |||||
| pd->uv_stretching_total_area_uv += *tmp_tot_area_uv; | |||||
| } | |||||
| return geom; | |||||
| } | |||||
| static void image_uv_editor_stretching_ratio_init(IMAGE_UV_EDITOR_PrivateData *pd) | |||||
| { | |||||
| pd->uv_stretching_total_area = 0.0f; | |||||
| pd->uv_stretching_total_area_uv = 0.0f; | |||||
| pd->uv_stretching_total_area_ratio = 0.0f; | |||||
| pd->uv_stretching_total_area_ratio_inv = 0.0f; | |||||
| } | |||||
| static void image_uv_editor_stretching_ratio_update(IMAGE_UV_EDITOR_PrivateData *pd) | |||||
| { | |||||
| if (pd->uv_stretching_total_area > FLT_EPSILON && | |||||
| pd->uv_stretching_total_area_uv > FLT_EPSILON) { | |||||
| pd->uv_stretching_total_area_ratio = pd->uv_stretching_total_area / | |||||
| pd->uv_stretching_total_area_uv; | |||||
| pd->uv_stretching_total_area_ratio_inv = pd->uv_stretching_total_area_uv / | |||||
| pd->uv_stretching_total_area; | |||||
| DRW_shgroup_uniform_float_copy( | |||||
| pd->uv_stretching_overlay_shgrp, "totalAreaRatio", pd->uv_stretching_total_area_ratio); | |||||
| DRW_shgroup_uniform_float_copy(pd->uv_stretching_overlay_shgrp, | |||||
| "totalAreaRatioInv", | |||||
| pd->uv_stretching_total_area_ratio_inv); | |||||
| } | |||||
| } | |||||
| /* \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name UV Shadow Overlay Pass | |||||
| * \{ */ | |||||
| static DRWShadingGroup *image_uv_editor_shadow_shgroup_create(IMAGE_UV_EDITOR_PassList *psl) | |||||
| { | |||||
| float shadow_color[4]; | |||||
| UI_GetThemeColor4fv(TH_UV_SHADOW, shadow_color); | |||||
| GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_EDGES_SMOOTH); | |||||
| DRWShadingGroup *shgrp = DRW_shgroup_create(sh, psl->uv_shadow_overlay_pass); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "edgeColor", shadow_color); | |||||
| return shgrp; | |||||
| } | |||||
| /* \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name DrawEngine Interface | |||||
| * \{ */ | |||||
| static void image_uv_editor_init(void *vedata) | |||||
| { | |||||
| IMAGE_UV_EDITOR_Data *ied = (IMAGE_UV_EDITOR_Data *)vedata; | |||||
| IMAGE_UV_EDITOR_StorageList *stl = ied->stl; | |||||
| e_data.ibuf = NULL; | |||||
| e_data.lock = NULL; | |||||
| e_data.texture = NULL; | |||||
| e_data.do_color_management = false; | |||||
| e_data.do_channel_shuffling = false; | |||||
| e_data.do_uv_overlay = false; | |||||
| e_data.do_uv_stretching_overlay = false; | |||||
| e_data.do_shadow_overlay = false; | |||||
| e_data.cache_handle = NULL; | |||||
| if (!stl->g_data) { | |||||
| /* Alloc transient pointers */ | |||||
| stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); | |||||
| } | |||||
| IMAGE_UV_EDITOR_PrivateData *pd = stl->g_data; | |||||
| pd->uv_stretching_overlay_shgrp = NULL; | |||||
| pd->uv_overlay_faces_shgrp = NULL; | |||||
| pd->uv_overlay_edges_shgrp = NULL; | |||||
| pd->uv_overlay_face_dots_shgrp = NULL; | |||||
| pd->uv_overlay_verts_shgrp[0] = NULL; | |||||
| pd->uv_overlay_verts_shgrp[1] = NULL; | |||||
| image_uv_editor_stretching_ratio_init(pd); | |||||
| BLI_listbase_clear(&e_data.draw_call_data); | |||||
| /* Create Shaders */ | |||||
| /* Create batch */ | |||||
| if (!e_data.gpu_batch_image) { | |||||
| e_data.gpu_batch_image = DRW_cache_image_plane_get(); | |||||
| } | |||||
| } | |||||
| static void image_uv_editor_cache_init(void *vedata) | |||||
| { | |||||
| IMAGE_UV_EDITOR_Data *ied = (IMAGE_UV_EDITOR_Data *)vedata; | |||||
| IMAGE_UV_EDITOR_PassList *psl = ied->psl; | |||||
| IMAGE_UV_EDITOR_StorageList *stl = ied->stl; | |||||
| IMAGE_UV_EDITOR_PrivateData *pd = stl->g_data; | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; | |||||
| e_data.do_uv_overlay = (sima->mode == SI_MODE_UV) && (draw_ctx->object_edit != NULL); | |||||
| e_data.do_uv_overlay_show_faces = ((sima->flag & SI_NO_DRAWFACES) == 0); | |||||
| e_data.do_uv_overlay_show_faces_dots = e_data.do_uv_overlay && | |||||
| image_uv_editor_draw_face_dots( | |||||
| draw_ctx->scene->toolsettings); | |||||
| e_data.do_uv_stretching_overlay = (sima->mode == SI_MODE_UV) && | |||||
| ((sima->flag & SI_DRAW_STRETCH) != 0); | |||||
| e_data.do_shadow_overlay = (sima->mode == SI_MODE_PAINT) && | |||||
| ((draw_ctx->object_mode & (OB_MODE_TEXTURE_PAINT | OB_MODE_EDIT)) != | |||||
| 0); | |||||
| { | |||||
| psl->image_pass = DRW_pass_create("Image", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); | |||||
| } | |||||
| if (e_data.do_uv_overlay) { | |||||
| psl->uv_overlay_faces_pass = DRW_pass_create( | |||||
| "UV Overlay face", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA); | |||||
| pd->uv_overlay_faces_shgrp = image_uv_editor_face_shgroup_create(psl); | |||||
| psl->uv_overlay_verts_pass = DRW_pass_create("UV Overlay verts", | |||||
| DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | | |||||
| DRW_STATE_PROGRAM_POINT_SIZE | | |||||
| DRW_STATE_BLEND_ALPHA); | |||||
| float vert_color[4]; | |||||
| const float pinned_color[4] = {1.0f, 0.0f, 0.0f, 1.0f}; | |||||
| const float transparent_color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; | |||||
| float select_color[4]; | |||||
| UI_GetThemeColor4fv(TH_VERTEX, vert_color); | |||||
| vert_color[3] = 1.0f; | |||||
| UI_GetThemeColor4fv(TH_VERTEX_SELECT, select_color); | |||||
| const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE); | |||||
| DRWShadingGroup *shgrp; | |||||
| shgrp = DRW_shgroup_create(GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_VERTS), | |||||
| psl->uv_overlay_verts_pass); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "vertColor", vert_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "selectColor", transparent_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "pinnedColor", pinned_color); | |||||
| DRW_shgroup_uniform_float_copy(shgrp, "pointSize", (point_size + 1.5f) * M_SQRT2); | |||||
| DRW_shgroup_uniform_float_copy(shgrp, "outlineWidth", 0.75f); | |||||
| pd->uv_overlay_verts_shgrp[0] = shgrp; | |||||
| /* We have problem in this mode when face order make some verts | |||||
| * appear unselected because an adjacent face is not selected and | |||||
| * render after the selected face. | |||||
| * So, to avoid sorting verts by state we just render selected verts | |||||
| * on top. A bit overkill but it's simple. */ | |||||
| shgrp = DRW_shgroup_create(GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_VERTS), | |||||
| psl->uv_overlay_verts_pass); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "vertColor", transparent_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "selectColor", select_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "pinnedColor", pinned_color); | |||||
| DRW_shgroup_uniform_float_copy(shgrp, "pointSize", (point_size + 1.5f) * M_SQRT2); | |||||
| DRW_shgroup_uniform_float_copy(shgrp, "outlineWidth", 0.75f); | |||||
| pd->uv_overlay_verts_shgrp[1] = shgrp; | |||||
| const bool smooth_edges = image_uv_editor_edges_smooth(sima); | |||||
| psl->uv_overlay_edges_pass = DRW_pass_create( | |||||
| "UV Overlay edge", | |||||
| DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_FIRST_VERTEX_CONVENTION | | |||||
| (smooth_edges ? (DRW_STATE_WIRE_SMOOTH | DRW_STATE_BLEND_ALPHA) : 0)); | |||||
| if (smooth_edges) { | |||||
| DRW_pass_line_width_set(psl->uv_overlay_edges_pass, 1.0f); | |||||
| } | |||||
| pd->uv_overlay_edges_shgrp = image_uv_editor_edge_shgroup_create(psl); | |||||
| } | |||||
| if (e_data.do_uv_overlay_show_faces_dots) { | |||||
| DRWShadingGroup *shgrp = DRW_shgroup_create( | |||||
| GPU_shader_get_builtin_shader(GPU_SHADER_2D_UV_FACEDOTS), psl->uv_overlay_verts_pass); | |||||
| float vert_color[4]; | |||||
| float select_color[4]; | |||||
| UI_GetThemeColor4fv(TH_WIRE, vert_color); | |||||
| vert_color[3] = 1.0f; | |||||
| UI_GetThemeColor4fv(TH_VERTEX_SELECT, select_color); | |||||
| const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "vertColor", vert_color); | |||||
| DRW_shgroup_uniform_vec4_copy(shgrp, "selectColor", select_color); | |||||
| DRW_shgroup_uniform_float_copy(shgrp, "pointSize", point_size); | |||||
| pd->uv_overlay_face_dots_shgrp = shgrp; | |||||
| } | |||||
| if (e_data.do_uv_stretching_overlay) { | |||||
| psl->uv_stretching_overlay_pass = DRW_pass_create( | |||||
| "UV Stretching Overlay", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); | |||||
| pd->uv_stretching_overlay_shgrp = image_uv_editor_stretching_shgroup_create(psl); | |||||
| } | |||||
| if (e_data.do_shadow_overlay) { | |||||
| psl->uv_shadow_overlay_pass = DRW_pass_create("UV Shadow Overlay", | |||||
| DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | | |||||
| DRW_STATE_WIRE_SMOOTH | | |||||
| DRW_STATE_BLEND_ALPHA); | |||||
| DRW_pass_line_width_set(psl->uv_shadow_overlay_pass, 1.0f); | |||||
| pd->uv_shadow_overlay_shgrp = image_uv_editor_shadow_shgroup_create(psl); | |||||
| } | |||||
| { | |||||
| e_data.default_draw_call_data = image_uv_editor_create_call_data(0, 0); | |||||
| } | |||||
| { | |||||
| Image *ima = ED_space_image(sima); | |||||
| ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &e_data.lock); | |||||
| image_uv_editor_add_image(psl, ima, &sima->iuser, ibuf); | |||||
| e_data.ibuf = ibuf; | |||||
| } | |||||
| } | |||||
| static void image_uv_editor_cache_populate(void *vedata, Object *ob) | |||||
| { | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| IMAGE_UV_EDITOR_Data *ied = (IMAGE_UV_EDITOR_Data *)vedata; | |||||
| IMAGE_UV_EDITOR_StorageList *stl = ied->stl; | |||||
| IMAGE_UV_EDITOR_PrivateData *pd = stl->g_data; | |||||
| if (e_data.do_uv_overlay) { | |||||
| if (ob->type == OB_MESH) { | |||||
| if ((ob == draw_ctx->object_edit) || BKE_object_is_in_editmode(ob)) { | |||||
| if (e_data.do_uv_overlay_show_faces) { | |||||
| struct GPUBatch *geom = DRW_mesh_batch_cache_get_edituv_faces(ob->data); | |||||
| if (geom) { | |||||
| DRW_shgroup_call_obmat( | |||||
| pd->uv_overlay_faces_shgrp, geom, e_data.default_draw_call_data->image_mat); | |||||
| } | |||||
| } | |||||
| if (e_data.do_uv_overlay_show_faces_dots) { | |||||
| struct GPUBatch *geom = DRW_mesh_batch_cache_get_edituv_facedots(ob->data); | |||||
| if (geom) { | |||||
| DRW_shgroup_call_obmat( | |||||
| pd->uv_overlay_face_dots_shgrp, geom, e_data.default_draw_call_data->image_mat); | |||||
| } | |||||
| } | |||||
| { | |||||
| struct GPUBatch *geom = DRW_mesh_batch_cache_get_edituv_edges(ob->data); | |||||
| if (geom) { | |||||
| DRW_shgroup_call_obmat( | |||||
| pd->uv_overlay_edges_shgrp, geom, e_data.default_draw_call_data->image_mat); | |||||
| } | |||||
| } | |||||
| { | |||||
| struct GPUBatch *geom = DRW_mesh_batch_cache_get_edituv_verts(ob->data); | |||||
| if (geom) { | |||||
| DRW_shgroup_call_obmat( | |||||
| pd->uv_overlay_verts_shgrp[0], geom, e_data.default_draw_call_data->image_mat); | |||||
| DRW_shgroup_call_obmat( | |||||
| pd->uv_overlay_verts_shgrp[1], geom, e_data.default_draw_call_data->image_mat); | |||||
| } | |||||
| } | |||||
| if (e_data.do_uv_stretching_overlay) { | |||||
| struct GPUBatch *geom = image_uv_editor_stretching_batch_get(pd, ob->data); | |||||
| if (geom) { | |||||
| DRW_shgroup_call_obmat( | |||||
| pd->uv_stretching_overlay_shgrp, geom, e_data.default_draw_call_data->image_mat); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| if (e_data.do_shadow_overlay) { | |||||
| if (ob->type == OB_MESH) { | |||||
| struct GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(ob->data); | |||||
| if (geom) { | |||||
| DRW_shgroup_call_obmat( | |||||
| pd->uv_shadow_overlay_shgrp, geom, e_data.default_draw_call_data->image_mat); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| static void image_uv_editor_cache_finish(void *vedata) | |||||
| { | |||||
| IMAGE_UV_EDITOR_Data *ied = (IMAGE_UV_EDITOR_Data *)vedata; | |||||
| IMAGE_UV_EDITOR_StorageList *stl = ied->stl; | |||||
| IMAGE_UV_EDITOR_PrivateData *pd = stl->g_data; | |||||
| image_uv_editor_stretching_ratio_update(pd); | |||||
| } | |||||
| static void image_uv_editor_draw_background(void *UNUSED(vedata)) | |||||
| { | |||||
| static float color[4]; | |||||
| UI_GetThemeColor3fv(TH_BACK, color); | |||||
| DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); | |||||
| GPU_framebuffer_clear_color(dfbl->default_fb, color); | |||||
| } | |||||
| static void image_uv_editor_draw_finish(void *UNUSED(vedata)) | |||||
| { | |||||
| const DRWContextState *draw_ctx = DRW_context_state_get(); | |||||
| SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; | |||||
| /* free temp memory */ | |||||
| if (e_data.do_color_management && e_data.texture) { | |||||
| GPU_texture_free(e_data.texture); | |||||
| IMB_display_buffer_release(e_data.cache_handle); | |||||
| } | |||||
| ED_space_image_release_buffer(sima, e_data.ibuf, e_data.lock); | |||||
| BLI_freelistN(&e_data.draw_call_data); | |||||
| } | |||||
| static void image_uv_editor_draw_scene(void *vedata) | |||||
| { | |||||
| IMAGE_UV_EDITOR_Data *ied = (IMAGE_UV_EDITOR_Data *)vedata; | |||||
| IMAGE_UV_EDITOR_PassList *psl = ied->psl; | |||||
| DRW_draw_pass(psl->image_pass); | |||||
| if (e_data.do_uv_stretching_overlay) { | |||||
| DRW_draw_pass(psl->uv_stretching_overlay_pass); | |||||
| } | |||||
| if (e_data.do_uv_overlay) { | |||||
| DRW_stats_group_start("UV Overlay"); | |||||
| DRW_draw_pass(psl->uv_overlay_faces_pass); | |||||
| DRW_draw_pass(psl->uv_overlay_edges_pass); | |||||
| DRW_draw_pass(psl->uv_overlay_verts_pass); | |||||
| DRW_stats_group_end(); | |||||
| } | |||||
| if (e_data.do_shadow_overlay) { | |||||
| DRW_draw_pass(psl->uv_shadow_overlay_pass); | |||||
| } | |||||
| image_uv_editor_draw_finish(vedata); | |||||
| } | |||||
| static void image_uv_editor_free(void) | |||||
| { | |||||
| GPUShader **sh_data_as_array = (GPUShader **)&e_data.shaders; | |||||
| for (int i = 0; i < (sizeof(IMAGE_UV_EDITOR_Shaders) / sizeof(GPUShader *)); i++) { | |||||
| DRW_SHADER_FREE_SAFE(sh_data_as_array[i]); | |||||
| } | |||||
| } | |||||
| /* \} */ | |||||
| static const DrawEngineDataSize image_uv_editor_data_size = DRW_VIEWPORT_DATA_SIZE( | |||||
| IMAGE_UV_EDITOR_Data); | |||||
| DrawEngineType draw_engine_image_uv_editor_type = { | |||||
| NULL, | |||||
| NULL, | |||||
| N_("Image/UV Editor"), | |||||
| &image_uv_editor_data_size, | |||||
| &image_uv_editor_init, | |||||
| &image_uv_editor_free, | |||||
| &image_uv_editor_cache_init, | |||||
| &image_uv_editor_cache_populate, | |||||
| &image_uv_editor_cache_finish, | |||||
| &image_uv_editor_draw_background, | |||||
| &image_uv_editor_draw_scene, | |||||
| NULL, | |||||
| NULL, | |||||
| NULL, | |||||
| }; | |||||