From 25a529f440873f7ee22671e9c7f251c1a66f8a0d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 21 Apr 2018 21:10:09 +0200 Subject: UI: add own icon rasterizer Use software drawing, cache to an image at the requested pixel size. --- source/blender/blenkernel/BKE_icons.h | 5 + source/blender/blenkernel/CMakeLists.txt | 1 + source/blender/blenkernel/intern/icons_rasterize.c | 131 +++++++++++++++++++++ source/blender/editors/interface/interface_icons.c | 53 +++------ 4 files changed, 155 insertions(+), 35 deletions(-) create mode 100644 source/blender/blenkernel/intern/icons_rasterize.c diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 47cac895645..fb40e5be281 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -71,6 +71,7 @@ struct Icon_Geom { typedef struct Icon Icon; +struct ImBuf; struct PreviewImage; struct ID; @@ -148,6 +149,10 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read( void BKE_previewimg_cached_release(const char *name); void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv); +struct ImBuf *BKE_icon_geom_rasterize( + const struct Icon_Geom *geom, + const unsigned int size_x, const unsigned int size_y); + #define ICON_RENDER_DEFAULT_HEIGHT 32 #endif /* __BKE_ICONS_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index d90831605b5..91915bf679a 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -116,6 +116,7 @@ set(SRC intern/gpencil.c intern/group.c intern/icons.c + intern/icons_rasterize.c intern/idcode.c intern/idprop.c intern/image.c diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c new file mode 100644 index 00000000000..bb6ef38f8f7 --- /dev/null +++ b/source/blender/blenkernel/intern/icons_rasterize.c @@ -0,0 +1,131 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenkernel/intern/icons_rasterize.c + * \ingroup bke + */ +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_bitmap_draw_2d.h" +#include "BLI_math_geom.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_icons.h" + +#include "BLI_strict_flags.h" + +struct UserRasterInfo { + int pt[3][2]; + const uint *color; + /* only for smooth shading */ + struct { + float pt_fl[3][2]; + uint color_u[3][4]; + } smooth; + int rect_size[2]; + uint *rect; +}; + +static void tri_fill_flat(int x, int x_end, int y, void *user_data) +{ + struct UserRasterInfo *data = user_data; + uint *p = &data->rect[(y * data->rect_size[1]) + x]; + uint col = data->color[0]; + while (x++ != x_end) { + *p++ = col; + } +} + +static void tri_fill_smooth(int x, int x_end, int y, void *user_data) +{ + struct UserRasterInfo *data = user_data; + uint *p = &data->rect[(y * data->rect_size[1]) + x]; + float pt_step_fl[2] = {(float)x, (float)y}; + while (x++ != x_end) { + float w[3]; + barycentric_weights_v2_clamped(UNPACK3(data->smooth.pt_fl), pt_step_fl, w); + + uint col_u[4] = {0, 0, 0, 0}; + for (uint corner = 0; corner < 3; corner++) { + for (uint chan = 0; chan < 4; chan++) { + col_u[chan] += data->smooth.color_u[corner][chan] * (uint)(w[corner] * 255.0f); + } + } + union { + uint as_u32; + uchar as_bytes[4]; + } col; + col.as_bytes[0] = (uchar)(col_u[0] / 255); + col.as_bytes[1] = (uchar)(col_u[1] / 255); + col.as_bytes[2] = (uchar)(col_u[2] / 255); + col.as_bytes[3] = (uchar)(col_u[3] / 255); + *p++ = col.as_u32; + + pt_step_fl[0] += 1.0f; + } +} + +ImBuf *BKE_icon_geom_rasterize( + const struct Icon_Geom *geom, + const unsigned int size_x, const unsigned int size_y) +{ + const int coords_len = geom->coords_len; + + const uchar (*pos)[2] = geom->coords; + const uint *col = (void *)geom->colors; + + /* TODO(campbell): Currently rasterizes to fixed size, then scales. + * Should rasterize to double size for eg instead. */ + const int rect_size[2] = {256, 256}; + + ImBuf *ibuf = IMB_allocImBuf((uint)rect_size[0], (uint)rect_size[1], 32, IB_rect); + + struct UserRasterInfo data; + + data.rect_size[0] = rect_size[0]; + data.rect_size[1] = rect_size[1]; + + data.rect = ibuf->rect; + + for (int t = 0; t < coords_len; t += 1, pos += 3, col += 3) { + ARRAY_SET_ITEMS(data.pt[0], UNPACK2(pos[0])); + ARRAY_SET_ITEMS(data.pt[1], UNPACK2(pos[1])); + ARRAY_SET_ITEMS(data.pt[2], UNPACK2(pos[2])); + data.color = col; + if ((col[0] == col[1]) && (col[0] == col[2])) { + BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_flat, &data); + } + else { + ARRAY_SET_ITEMS(data.smooth.pt_fl[0], UNPACK2_EX((float), data.pt[0], )); + ARRAY_SET_ITEMS(data.smooth.pt_fl[1], UNPACK2_EX((float), data.pt[1], )); + ARRAY_SET_ITEMS(data.smooth.pt_fl[2], UNPACK2_EX((float), data.pt[2], )); + ARRAY_SET_ITEMS(data.smooth.color_u[0], UNPACK4_EX((uint), ((uchar *)(col + 0)), )); + ARRAY_SET_ITEMS(data.smooth.color_u[1], UNPACK4_EX((uint), ((uchar *)(col + 1)), )); + ARRAY_SET_ITEMS(data.smooth.color_u[2], UNPACK4_EX((uint), ((uchar *)(col + 2)), )); + BLI_bitmap_draw_2d_tri_v2i(UNPACK3(data.pt), tri_fill_smooth, &data); + } + } + IMB_scaleImBuf(ibuf, size_x, size_y); + return ibuf; +} diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 6bcdc2f9266..ec255ed73a0 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -110,7 +110,7 @@ typedef struct DrawInfo { VectorDrawFunc func; } vector; struct { - Gwn_Batch *batch; + ImBuf *image_cache; } geom; struct { IconImage *image; @@ -748,8 +748,8 @@ void UI_icons_free_drawinfo(void *drawinfo) } } else if (di->type == ICON_TYPE_GEOM) { - if (di->data.geom.batch) { - GWN_BATCH_DISCARD_SAFE(di->data.geom.batch); + if (di->data.geom.image_cache) { + IMB_freeImBuf(di->data.geom.image_cache); } } @@ -760,7 +760,7 @@ void UI_icons_free_drawinfo(void *drawinfo) /** * #Icon.data_type and #Icon.obj */ -static DrawInfo *icon_create_drawinfo(int icon_data_type, void *icon_obj) +static DrawInfo *icon_create_drawinfo(int icon_data_type) { DrawInfo *di = NULL; @@ -771,21 +771,6 @@ static DrawInfo *icon_create_drawinfo(int icon_data_type, void *icon_obj) } 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); @@ -799,7 +784,7 @@ static DrawInfo *icon_ensure_drawinfo(Icon *icon) if (icon->drawinfo) { return icon->drawinfo; } - DrawInfo *di = icon_create_drawinfo(icon->obj_type, icon->obj); + DrawInfo *di = icon_create_drawinfo(icon->obj_type); icon->drawinfo = di; icon->drawinfo_free = UI_icons_free_drawinfo; return di; @@ -1241,24 +1226,22 @@ static void icon_draw_size( /* We need to flush widget base first to ensure correct ordering. */ UI_widgetbase_draw_cache_flush(); - gpuPushMatrix(); - gpuTranslate2f(x, y); - gpuScale2f(w, h); - + /* This could re-generate often if rendered at different sizes in the one interface. + * TODO(campbell): support caching multiple sizes. */ + ImBuf *ibuf = di->data.geom.image_cache; + if ((ibuf == NULL) || + (ibuf->x != w) || + (ibuf->y != 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); + if (ibuf) { + IMB_freeImBuf(ibuf); } - GWN_batch_program_use_end(batch); + ibuf = BKE_icon_geom_rasterize(icon->obj, w, h); + di->data.geom.image_cache = ibuf; } - - gpuPopMatrix(); + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, rgb, is_preview); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else if (di->type == ICON_TYPE_TEXTURE) { /* texture image use premul alpha for correct scaling */ -- cgit v1.2.3