From bc11cb3daa60c28e41bc400df29d7f8085993888 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Apr 2018 15:15:10 +0200 Subject: UI: Support for runtime geometry icons --- source/blender/blenkernel/BKE_icons.h | 30 ++++- source/blender/blenkernel/intern/icons.c | 124 +++++++++++++++----- source/blender/editors/interface/interface_icons.c | 125 ++++++++++++++------- .../blender/editors/interface/interface_intern.h | 3 + .../blender/editors/interface/interface_widgets.c | 6 +- source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/GPU_shader.h | 1 + source/blender/gpu/intern/gpu_shader.c | 3 + ..._shader_2D_smooth_color_uniform_alpha_vert.glsl | 14 +++ 9 files changed, 236 insertions(+), 71 deletions(-) create mode 100644 source/blender/gpu/shaders/gpu_shader_2D_smooth_color_uniform_alpha_vert.glsl diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 686dba21283..47cac895645 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -36,14 +36,39 @@ typedef void (*DrawInfoFreeFP)(void *drawinfo); +enum { + /** ID preview: obj is #ID. */ + ICON_DATA_ID = 0, + /** Preview: obj is #PreviewImage */ + ICON_DATA_PREVIEW, + /** 2D triangles: obj is #Icon_Geom */ + ICON_DATA_GEOM, +}; + struct Icon { void *drawinfo; + /** + * Data defined by #obj_type + * \note for #ICON_DATA_GEOM the memory is owned by the icon, + * could be made into a flag if we want that to be optional. + */ void *obj; + char obj_type; + /** Internal use only. */ + char flag; /** #ID_Type or 0 when not used for ID preview. */ short id_type; DrawInfoFreeFP drawinfo_free; }; +/** Used for #ICON_DATA_GEOM, assigned to #Icon.obj. */ +struct Icon_Geom { + int icon_id; + int coords_len; + const unsigned char (*coords)[2]; + const unsigned char (*colors)[4]; +}; + typedef struct Icon Icon; struct PreviewImage; @@ -58,6 +83,8 @@ int BKE_icon_id_ensure(struct ID *id); int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview); +int BKE_icon_geom_ensure(struct Icon_Geom *geom); + /* retrieve icon for id */ struct Icon *BKE_icon_get(const int icon_id); @@ -68,7 +95,8 @@ void BKE_icon_set(const int icon_id, struct Icon *icon); /* remove icon and free data if library object becomes invalid */ void BKE_icon_id_delete(struct ID *id); -void BKE_icon_delete(const int icon_id); +bool BKE_icon_delete(const int icon_id); +bool BKE_icon_delete_unmanaged(const int icon_id); /* report changes - icon needs to be recalculated */ void BKE_icon_changed(const int icon_id); diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 7cf7bb7452a..7097b349125 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -64,6 +64,14 @@ #include "IMB_imbuf_types.h" #include "IMB_thumbs.h" +/** + * Only allow non-managed icons to be removed (by Python for eg). + * Previews & ID's have their own functions to remove icons. + */ +enum { + ICON_FLAG_MANAGED = (1 << 0), +}; + /* GLOBALS */ static GHash *gIcons = NULL; @@ -86,6 +94,13 @@ static void icon_free(void *val) Icon *icon = val; if (icon) { + if (icon->obj_type == ICON_DATA_GEOM) { + struct Icon_Geom *obj = icon->obj; + MEM_freeN((void *)obj->coords); + MEM_freeN((void *)obj->colors); + MEM_freeN(icon->obj); + } + if (icon->drawinfo_free) { icon->drawinfo_free(icon->drawinfo); } @@ -96,6 +111,22 @@ static void icon_free(void *val) } } +static void icon_free_data(Icon *icon) +{ + if (icon->obj_type == ICON_DATA_ID) { + ((ID *)(icon->obj))->icon_id = 0; + } + else if (icon->obj_type == ICON_DATA_PREVIEW) { + ((PreviewImage *)(icon->obj))->icon_id = 0; + } + else if (icon->obj_type == ICON_DATA_GEOM) { + ((struct Icon_Geom *)(icon->obj))->icon_id = 0; + } + else { + BLI_assert(0); + } +} + /* create an id for a new icon and make sure that ids from deleted icons get reused * after the integer number range is used up */ static int get_next_free_id(void) @@ -478,6 +509,7 @@ void BKE_icon_changed(const int icon_id) if (icon) { /* We *only* expect ID-tied icons here, not non-ID icon/preview! */ BLI_assert(icon->id_type != 0); + BLI_assert(icon->obj_type == ICON_DATA_ID); /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here , * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */ @@ -494,22 +526,31 @@ void BKE_icon_changed(const int icon_id) } } -static int icon_id_ensure_create_icon(struct ID *id) +static Icon *icon_create(int icon_id, int obj_type, void *obj) { - BLI_assert(BLI_thread_is_main()); - - Icon *new_icon = NULL; + Icon *new_icon = MEM_mallocN(sizeof(Icon), __func__); - new_icon = MEM_mallocN(sizeof(Icon), __func__); - - new_icon->obj = id; - new_icon->id_type = GS(id->name); + new_icon->obj_type = obj_type; + new_icon->obj = obj; + new_icon->id_type = 0; + new_icon->flag = 0; /* next two lines make sure image gets created */ new_icon->drawinfo = NULL; new_icon->drawinfo_free = NULL; - BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon); + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), new_icon); + + return new_icon; +} + +static int icon_id_ensure_create_icon(struct ID *id) +{ + BLI_assert(BLI_thread_is_main()); + + Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id); + icon->id_type = GS(id->name); + icon->flag = ICON_FLAG_MANAGED; return id->icon_id; } @@ -544,8 +585,6 @@ int BKE_icon_id_ensure(struct ID *id) */ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) { - Icon *new_icon = NULL; - if (!preview || G.background) return 0; @@ -576,18 +615,26 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) return icon_id_ensure_create_icon(id); } - new_icon = MEM_mallocN(sizeof(Icon), __func__); + Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview); + icon->flag = ICON_FLAG_MANAGED; - new_icon->obj = preview; - new_icon->id_type = 0; /* Special, tags as non-ID icon/preview. */ + return preview->icon_id; +} - /* next two lines make sure image gets created */ - new_icon->drawinfo = NULL; - new_icon->drawinfo_free = NULL; +int BKE_icon_geom_ensure(struct Icon_Geom *geom) +{ + BLI_assert(BLI_thread_is_main()); + + if (geom->icon_id) { + return geom->icon_id; + } - BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon); + geom->icon_id = get_next_free_id(); - return preview->icon_id; + icon_create(geom->icon_id, ICON_DATA_GEOM, geom); + /* Not managed for now, we may want this to be configurable per icon). */ + + return geom->icon_id; } Icon *BKE_icon_get(const int icon_id) @@ -647,21 +694,44 @@ void BKE_icon_id_delete(struct ID *id) /** * Remove icon and free data. */ -void BKE_icon_delete(const int icon_id) +bool BKE_icon_delete(const int icon_id) { - Icon *icon; + if (icon_id == 0) { + /* no icon defined for library object */ + return false; + } - if (!icon_id) return; /* no icon defined for library object */ + Icon *icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL); + if (icon) { + icon_free_data(icon); + icon_free(icon); + return true; + } + else { + return false; + } +} - icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL); +bool BKE_icon_delete_unmanaged(const int icon_id) +{ + if (icon_id == 0) { + /* no icon defined for library object */ + return false; + } + Icon *icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL); if (icon) { - if (icon->id_type != 0) { - ((ID *)(icon->obj))->icon_id = 0; + if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) { + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(icon_id), icon); + return false; } else { - ((PreviewImage *)(icon->obj))->icon_id = 0; + icon_free_data(icon); + icon_free(icon); + return true; } - icon_free(icon); + } + else { + return false; } } diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index a33dcfc5ab6..6bcdc2f9266 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -35,6 +35,7 @@ #include "GPU_draw.h" #include "GPU_matrix.h" +#include "GPU_batch.h" #include "GPU_immediate.h" #include "BLI_blenlib.h" @@ -98,6 +99,7 @@ typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha); #define ICON_TYPE_TEXTURE 1 #define ICON_TYPE_BUFFER 2 #define ICON_TYPE_VECTOR 3 +#define ICON_TYPE_GEOM 4 typedef struct DrawInfo { int type; @@ -107,6 +109,9 @@ typedef struct DrawInfo { struct { VectorDrawFunc func; } vector; + struct { + Gwn_Batch *batch; + } geom; struct { IconImage *image; } buffer; @@ -742,18 +747,61 @@ void UI_icons_free_drawinfo(void *drawinfo) MEM_freeN(di->data.buffer.image); } } + else if (di->type == ICON_TYPE_GEOM) { + if (di->data.geom.batch) { + GWN_BATCH_DISCARD_SAFE(di->data.geom.batch); + } + } MEM_freeN(di); } } -static DrawInfo *icon_create_drawinfo(void) +/** + * #Icon.data_type and #Icon.obj + */ +static DrawInfo *icon_create_drawinfo(int icon_data_type, void *icon_obj) { DrawInfo *di = NULL; di = MEM_callocN(sizeof(DrawInfo), "di_icon"); - di->type = ICON_TYPE_PREVIEW; + if (ELEM(icon_data_type, ICON_DATA_ID, ICON_DATA_PREVIEW)) { + di->type = ICON_TYPE_PREVIEW; + } + else if (icon_data_type == ICON_DATA_GEOM) { + di->type = ICON_TYPE_GEOM; + + struct Icon_Geom *geom = icon_obj; + static Gwn_VertFormat format = {0}; + static struct { uint pos, color; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_U8, 2, GWN_FETCH_INT_TO_FLOAT_UNIT); + attr_id.color = GWN_vertformat_attr_add(&format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + } + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, geom->coords_len * 3); + GWN_vertbuf_attr_fill(vbo, attr_id.pos, geom->coords); + GWN_vertbuf_attr_fill(vbo, attr_id.color, geom->colors); + + Gwn_Batch *batch = GWN_batch_create_ex(GWN_PRIM_TRIS, vbo, NULL, GWN_BATCH_OWNS_VBO); + di->data.geom.batch = batch; + } + else { + BLI_assert(0); + } + + return di; +} + +static DrawInfo *icon_ensure_drawinfo(Icon *icon) +{ + if (icon->drawinfo) { + return icon->drawinfo; + } + DrawInfo *di = icon_create_drawinfo(icon->obj_type, icon->obj); + icon->drawinfo = di; + icon->drawinfo_free = UI_icons_free_drawinfo; return di; } @@ -771,40 +819,27 @@ int UI_icon_get_width(int icon_id) return 0; } - di = (DrawInfo *)icon->drawinfo; - if (!di) { - di = icon_create_drawinfo(); - icon->drawinfo = di; - } - - if (di) + di = icon_ensure_drawinfo(icon); + if (di) { return ICON_DEFAULT_WIDTH; + } return 0; } int UI_icon_get_height(int icon_id) { - Icon *icon = NULL; - DrawInfo *di = NULL; - - icon = BKE_icon_get(icon_id); - + Icon *icon = BKE_icon_get(icon_id); if (icon == NULL) { if (G.debug & G_DEBUG) printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id); return 0; } - - di = (DrawInfo *)icon->drawinfo; - if (!di) { - di = icon_create_drawinfo(); - icon->drawinfo = di; - } - - if (di) + DrawInfo *di = icon_ensure_drawinfo(icon); + if (di) { return ICON_DEFAULT_HEIGHT; + } return 0; } @@ -861,14 +896,7 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi Icon *icon = BKE_icon_get(icon_id); if (icon) { - DrawInfo *di = (DrawInfo *)icon->drawinfo; - - if (!di) { - di = icon_create_drawinfo(); - - icon->drawinfo = di; - icon->drawinfo_free = UI_icons_free_drawinfo; - } + DrawInfo *di = icon_ensure_drawinfo(icon); if (di) { switch (di->type) { @@ -1183,7 +1211,6 @@ static void icon_draw_size( { bTheme *btheme = UI_GetTheme(); Icon *icon = NULL; - DrawInfo *di = NULL; IconImage *iimg; const float fdraw_size = (float)draw_size; int w, h; @@ -1197,19 +1224,12 @@ static void icon_draw_size( return; } - di = (DrawInfo *)icon->drawinfo; - - if (!di) { - di = icon_create_drawinfo(); - - icon->drawinfo = di; - icon->drawinfo_free = UI_icons_free_drawinfo; - } - /* scale width and height according to aspect */ w = (int)(fdraw_size / aspect + 0.5f); h = (int)(fdraw_size / aspect + 0.5f); - + + DrawInfo *di = icon_ensure_drawinfo(icon); + if (di->type == ICON_TYPE_VECTOR) { /* We need to flush widget base first to ensure correct ordering. */ UI_widgetbase_draw_cache_flush(); @@ -1217,6 +1237,29 @@ static void icon_draw_size( * with untransformed coordinates like the other icons */ di->data.vector.func((int)x, (int)y, w, h, 1.0f); } + else if (di->type == ICON_TYPE_GEOM) { + /* We need to flush widget base first to ensure correct ordering. */ + UI_widgetbase_draw_cache_flush(); + + gpuPushMatrix(); + gpuTranslate2f(x, y); + gpuScale2f(w, h); + + { + struct Gwn_Batch *batch = di->data.geom.batch; + GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_SMOOTH_COLOR_UNIFORM_ALPHA); + GWN_batch_uniform_1f(batch, "alpha", 1.0f / UI_PIXEL_AA_JITTER); + + for (uint i = 0; i < UI_PIXEL_AA_JITTER; i += 1) { + gpuTranslate2f(ui_pixel_jitter[i][0] / w, ui_pixel_jitter[i][1] / h); + GWN_batch_draw(batch); + gpuTranslate2f(-ui_pixel_jitter[i][0] / w, -ui_pixel_jitter[i][1] / h); + } + GWN_batch_program_use_end(batch); + } + + gpuPopMatrix(); + } else if (di->type == ICON_TYPE_TEXTURE) { /* texture image use premul alpha for correct scaling */ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 0d2a8da265d..17ea50d5465 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -749,6 +749,9 @@ void ui_draw_preview_item(struct uiFontStyle *fstyle, rcti *rect, const char *na /* margin at top of screen for popups */ #define UI_POPUP_MENU_TOP (int)(8 * UI_DPI_FAC) +#define UI_PIXEL_AA_JITTER 8 +const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2]; + /* interface_style.c */ void uiStyleInit(void); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 5cfee9d0e72..7714d065363 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -157,13 +157,15 @@ static const float cornervec[WIDGET_CURVE_RESOLU][2] = { {0.924, 0.617}, {0.98, 0.805}, {1.0, 1.0} }; -#define WIDGET_AA_JITTER 8 -static const float jit[WIDGET_AA_JITTER][2] = { + +const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2] = { { 0.468813, -0.481430}, {-0.155755, -0.352820}, { 0.219306, -0.238501}, {-0.393286, -0.110949}, {-0.024699, 0.013908}, { 0.343805, 0.147431}, {-0.272855, 0.269918}, { 0.095909, 0.388710} }; +#define WIDGET_AA_JITTER UI_PIXEL_AA_JITTER +#define jit ui_pixel_jitter /* -------------------------------------------------------------------- */ /** \name Shape Preset Data diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index c3ef9d18f13..f915191fc28 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -142,6 +142,7 @@ data_to_c_simple(shaders/gpu_shader_2D_line_dashed_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_line_dashed_geom.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_2D_smooth_color_uniform_alpha_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index df38b08d5c4..9131f56a07e 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -111,6 +111,7 @@ typedef enum GPUBuiltinShader { GPU_SHADER_2D_UNIFORM_COLOR, GPU_SHADER_2D_FLAT_COLOR, GPU_SHADER_2D_SMOOTH_COLOR, + GPU_SHADER_2D_SMOOTH_COLOR_UNIFORM_ALPHA, GPU_SHADER_2D_IMAGE, GPU_SHADER_2D_IMAGE_COLOR, GPU_SHADER_2D_IMAGE_ALPHA_COLOR, diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index f88b00dfb93..db464498a27 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -63,6 +63,7 @@ extern char datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl[]; extern char datatoc_gpu_shader_flat_id_frag_glsl[]; extern char datatoc_gpu_shader_2D_vert_glsl[]; extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_2D_smooth_color_uniform_alpha_vert_glsl[]; extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[]; extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[]; extern char datatoc_gpu_shader_2D_image_vert_glsl[]; @@ -699,6 +700,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) datatoc_gpu_shader_flat_color_frag_glsl }, [GPU_SHADER_2D_SMOOTH_COLOR] = { datatoc_gpu_shader_2D_smooth_color_vert_glsl, datatoc_gpu_shader_2D_smooth_color_frag_glsl }, + [GPU_SHADER_2D_SMOOTH_COLOR_UNIFORM_ALPHA] = { datatoc_gpu_shader_2D_smooth_color_uniform_alpha_vert_glsl, + datatoc_gpu_shader_2D_smooth_color_frag_glsl }, [GPU_SHADER_2D_IMAGE_LINEAR_TO_SRGB] = { datatoc_gpu_shader_2D_image_vert_glsl, datatoc_gpu_shader_image_linear_frag_glsl }, [GPU_SHADER_2D_IMAGE] = { datatoc_gpu_shader_2D_image_vert_glsl, diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_uniform_alpha_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_uniform_alpha_vert.glsl new file mode 100644 index 00000000000..a8ad5575235 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_uniform_alpha_vert.glsl @@ -0,0 +1,14 @@ + +uniform mat4 ModelViewProjectionMatrix; +uniform float alpha; + +in vec2 pos; +in vec4 color; + +noperspective out vec4 finalColor; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos, 0.0, 1.0); + finalColor = vec4(color[0], color[1], color[2], color[3] * alpha); +} -- cgit v1.2.3