UI: add own icon rasterizer
Use software drawing, cache to an image at the requested pixel size.
This commit is contained in:
parent
122d0d1504
commit
25a529f440
Notes:
blender-bot
2023-02-14 05:59:34 +01:00
Referenced by issue #54709, Mesh Icon Support
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue