Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_icons.c
| Show All 31 Lines | |||||
| #include "GPU_batch.h" | #include "GPU_batch.h" | ||||
| #include "GPU_immediate.h" | #include "GPU_immediate.h" | ||||
| #include "GPU_state.h" | #include "GPU_state.h" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_fileops_types.h" | #include "BLI_fileops_types.h" | ||||
| #include "BLI_math_vector.h" | #include "BLI_math_vector.h" | ||||
| #include "BLI_math_color_blend.h" | |||||
| #include "DNA_brush_types.h" | #include "DNA_brush_types.h" | ||||
| #include "DNA_curve_types.h" | #include "DNA_curve_types.h" | ||||
| #include "DNA_dynamicpaint_types.h" | #include "DNA_dynamicpaint_types.h" | ||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_space_types.h" | #include "DNA_space_types.h" | ||||
| Show All 30 Lines | |||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "interface_intern.h" | #include "interface_intern.h" | ||||
| #ifndef WITH_HEADLESS | #ifndef WITH_HEADLESS | ||||
| # define ICON_GRID_COLS 26 | # define ICON_GRID_COLS 26 | ||||
| # define ICON_GRID_ROWS 30 | # define ICON_GRID_ROWS 30 | ||||
| # define ICON_MONO_BORDER_OUTSET 2 | |||||
| # define ICON_GRID_MARGIN 10 | # define ICON_GRID_MARGIN 10 | ||||
| # define ICON_GRID_W 32 | # define ICON_GRID_W 32 | ||||
| # define ICON_GRID_H 32 | # define ICON_GRID_H 32 | ||||
| #endif /* WITH_HEADLESS */ | #endif /* WITH_HEADLESS */ | ||||
| typedef struct IconImage { | typedef struct IconImage { | ||||
| int w; | int w; | ||||
| int h; | int h; | ||||
| Show All 39 Lines | struct { | ||||
| int icon; | int icon; | ||||
| /* Allow lookups. */ | /* Allow lookups. */ | ||||
| struct DrawInfo *next; | struct DrawInfo *next; | ||||
| } input; | } input; | ||||
| } data; | } data; | ||||
| } DrawInfo; | } DrawInfo; | ||||
| typedef struct IconTexture { | typedef struct IconTexture { | ||||
| GLuint id; | GLuint id[2]; | ||||
| int num_textures; | |||||
| int w; | int w; | ||||
| int h; | int h; | ||||
| float invw; | float invw; | ||||
| float invh; | float invh; | ||||
| } IconTexture; | } IconTexture; | ||||
| typedef struct IconType { | typedef struct IconType { | ||||
| int type; | int type; | ||||
| int theme_color; | int theme_color; | ||||
| } IconType; | } IconType; | ||||
| /* ******************* STATIC LOCAL VARS ******************* */ | /* ******************* STATIC LOCAL VARS ******************* */ | ||||
| /* static here to cache results of icon directory scan, so it's not | /* static here to cache results of icon directory scan, so it's not | ||||
| * scanning the filesystem each time the menu is drawn */ | * scanning the filesystem each time the menu is drawn */ | ||||
| static struct ListBase iconfilelist = {NULL, NULL}; | static struct ListBase iconfilelist = {NULL, NULL}; | ||||
| static IconTexture icongltex = {0, 0, 0, 0.0f, 0.0f}; | static IconTexture icongltex = {{0, 0}, 0, 0, 0, 0.0f, 0.0f}; | ||||
| #ifndef WITH_HEADLESS | #ifndef WITH_HEADLESS | ||||
| static const IconType icontypes[] = { | static const IconType icontypes[] = { | ||||
| # define DEF_ICON(name) {ICON_TYPE_MONO_TEXTURE, 0}, | # define DEF_ICON(name) {ICON_TYPE_MONO_TEXTURE, 0}, | ||||
| # define DEF_ICON_SCENE(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SCENE}, | # define DEF_ICON_SCENE(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SCENE}, | ||||
| # define DEF_ICON_COLLECTION(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_COLLECTION}, | # define DEF_ICON_COLLECTION(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_COLLECTION}, | ||||
| # define DEF_ICON_OBJECT(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT}, | # define DEF_ICON_OBJECT(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT}, | ||||
| ▲ Show 20 Lines • Show All 543 Lines • ▼ Show 20 Lines | if (iimg->datatoc_rect) { | ||||
| } | } | ||||
| iimg->rect = bbuf->rect; | iimg->rect = bbuf->rect; | ||||
| bbuf->rect = NULL; | bbuf->rect = NULL; | ||||
| IMB_freeImBuf(bbuf); | IMB_freeImBuf(bbuf); | ||||
| } | } | ||||
| } | } | ||||
| static void init_internal_icons(void) | static ImBuf *create_mono_icon_with_border(ImBuf *buf, | ||||
| { | int resolution_divider, | ||||
| // bTheme *btheme = UI_GetTheme(); | float border_intensity) | ||||
| ImBuf *b16buf = NULL, *b32buf = NULL; | { | ||||
| int x, y; | ImBuf *result = IMB_dupImBuf(buf); | ||||
| const float border_sharpness = 16.0 / (resolution_divider * resolution_divider); | |||||
| float blurred_alpha_buffer[(ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) * | |||||
| (ICON_GRID_H + 2 * ICON_MONO_BORDER_OUTSET)]; | |||||
| const int icon_width = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider; | |||||
| const int icon_height = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider; | |||||
| # if 0 // temp disabled | for (int y = 0; y < ICON_GRID_ROWS; y++) { | ||||
| if ((btheme != NULL) && btheme->tui.iconfile[0]) { | for (int x = 0; x < ICON_GRID_COLS; x++) { | ||||
| char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); | IconType icontype = icontypes[y * ICON_GRID_COLS + x]; | ||||
| char iconfilestr[FILE_MAX]; | if (icontype.type != ICON_TYPE_MONO_TEXTURE) { | ||||
| continue; | |||||
| } | |||||
| if (icondir) { | int sx = x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET; | ||||
| BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); | int sy = y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET; | ||||
| sx = sx / resolution_divider; | |||||
| sy = sy / resolution_divider; | |||||
| /* if the image is missing bbuf will just be NULL */ | /* blur the alpha channel and store it in blurred_alpha_buffer */ | ||||
| bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL); | int blur_size = 2 / resolution_divider; | ||||
| for (int bx = 0; bx < icon_width; bx++) { | |||||
| const int asx = MAX2(bx - blur_size, 0); | |||||
| const int aex = MIN2(bx + blur_size + 1, icon_width); | |||||
| for (int by = 0; by < icon_height; by++) { | |||||
| const int asy = MAX2(by - blur_size, 0); | |||||
| const int aey = MIN2(by + blur_size + 1, icon_height); | |||||
| if (bbuf && (bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H)) { | // blur alpha channel | ||||
| printf( | const int write_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx; | ||||
| "\n***WARNING***\n" | float alpha_accum = 0.0; | ||||
| "Icons file '%s' too small.\n" | unsigned int alpha_samples = 0; | ||||
| "Using built-in Icons instead\n", | for (int ax = asx; ax < aex; ax++) { | ||||
| iconfilestr); | for (int ay = asy; ay < aey; ay++) { | ||||
| IMB_freeImBuf(bbuf); | const int offset_read = (sy + ay) * buf->x + (sx + ax); | ||||
| bbuf = NULL; | unsigned int color_read = buf->rect[offset_read]; | ||||
| const float alpha_read = ((color_read & 0xff000000) >> 24) / 255.0; | |||||
| alpha_accum += alpha_read; | |||||
| alpha_samples += 1; | |||||
| } | |||||
| } | |||||
| blurred_alpha_buffer[write_offset] = alpha_accum / alpha_samples; | |||||
| } | |||||
| } | |||||
| /* apply blurred alpha */ | |||||
| for (int bx = 0; bx < icon_width; bx++) { | |||||
| for (int by = 0; by < icon_height; by++) { | |||||
| const int blurred_alpha_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx; | |||||
| const int offset_write = (sy + by) * buf->x + (sx + bx); | |||||
| const float blurred_alpha = blurred_alpha_buffer[blurred_alpha_offset]; | |||||
| float border_srgb[4] = { | |||||
| 0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity}; | |||||
| const unsigned int color_read = buf->rect[offset_write]; | |||||
| const unsigned char *orig_color = (unsigned char *)&color_read; | |||||
| float border_rgba[4]; | |||||
| float orig_rgba[4]; | |||||
| float dest_rgba[4]; | |||||
| float dest_srgb[4]; | |||||
| srgb_to_linearrgb_v4(border_rgba, border_srgb); | |||||
| srgb_to_linearrgb_uchar4(orig_rgba, orig_color); | |||||
| blend_color_interpolate_float(dest_rgba, orig_rgba, border_rgba, 1.0 - orig_rgba[3]); | |||||
| linearrgb_to_srgb_v4(dest_srgb, dest_rgba); | |||||
| unsigned int alpha_mask = ((unsigned int)(dest_srgb[3] * 255)) << 24; | |||||
| unsigned int cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask; | |||||
| result->rect[offset_write] = cpack; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| return result; | |||||
| } | |||||
| /* Generate the mipmap levels for the icon textures | |||||
| * During creation the source16 ImBuf will be freed to reduce memory overhead | |||||
| * A new ImBuf will be returned that needs is owned by the caller. | |||||
| * | |||||
| * FIXME: Mipmap levels are generated until the width of the image is 1, which | |||||
| * are too many levels than that are needed.*/ | |||||
| static ImBuf *create_mono_icon_mipmaps(ImBuf *source32, ImBuf *source16, int level) | |||||
| { | |||||
| if (level == 0) { | |||||
| glTexImage2D(GL_TEXTURE_2D, | |||||
| level, | |||||
| GL_RGBA8, | |||||
| source32->x, | |||||
| source32->y, | |||||
| 0, | |||||
| GL_RGBA, | |||||
| GL_UNSIGNED_BYTE, | |||||
| source32->rect); | |||||
| return create_mono_icon_mipmaps(source32, source16, level + 1); | |||||
| } | |||||
| else { | else { | ||||
| printf("%s: 'icons' data path not found, continuing\n", __func__); | glTexImage2D(GL_TEXTURE_2D, | ||||
| level, | |||||
| GL_RGBA8, | |||||
| source16->x, | |||||
| source16->y, | |||||
| 0, | |||||
| GL_RGBA, | |||||
| GL_UNSIGNED_BYTE, | |||||
| source16->rect); | |||||
| if (source16->x > 1) { | |||||
| ImBuf *nbuf = IMB_onehalf(source16); | |||||
| IMB_freeImBuf(source16); | |||||
| source16 = create_mono_icon_mipmaps(source32, nbuf, level + 1); | |||||
| } | } | ||||
| return source16; | |||||
| } | } | ||||
| # endif | } | ||||
| static void free_icons_textures(void) | |||||
| { | |||||
| if (icongltex.num_textures > 0) { | |||||
| glDeleteTextures(icongltex.num_textures, icongltex.id); | |||||
| icongltex.id[0] = 0; | |||||
| icongltex.id[1] = 0; | |||||
| icongltex.num_textures = 0; | |||||
| } | |||||
| } | |||||
| /* Reload the textures for internal icons. | |||||
| * This function will release the previous textures. */ | |||||
| void UI_icons_reload_internal_textures(void) | |||||
| { | |||||
| bTheme *btheme = UI_GetTheme(); | |||||
| ImBuf *b16buf = NULL, *b32buf = NULL, *b16buf_border = NULL, *b32buf_border = NULL; | |||||
| const float icon_border_intensity = btheme->tui.icon_border_intensity; | |||||
| bool need_icons_with_border = icon_border_intensity > 0.0f; | |||||
| if (b16buf == NULL) { | if (b16buf == NULL) { | ||||
| b16buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons16_png, | b16buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons16_png, | ||||
| datatoc_blender_icons16_png_size, | datatoc_blender_icons16_png_size, | ||||
| IB_rect, | IB_rect, | ||||
| NULL, | NULL, | ||||
| "<blender icons>"); | "<blender icons>"); | ||||
| } | } | ||||
| if (b16buf) { | if (b16buf) { | ||||
| if (need_icons_with_border) { | |||||
brecht: This should only be done if needed by the theme, and not take up memory or startup time… | |||||
| b16buf_border = create_mono_icon_with_border(b16buf, 2, icon_border_intensity); | |||||
| IMB_premultiply_alpha(b16buf_border); | |||||
| } | |||||
| IMB_premultiply_alpha(b16buf); | IMB_premultiply_alpha(b16buf); | ||||
| } | } | ||||
| if (b32buf == NULL) { | if (b32buf == NULL) { | ||||
| b32buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons32_png, | b32buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons32_png, | ||||
| datatoc_blender_icons32_png_size, | datatoc_blender_icons32_png_size, | ||||
| IB_rect, | IB_rect, | ||||
| NULL, | NULL, | ||||
| "<blender icons>"); | "<blender icons>"); | ||||
| } | } | ||||
| if (b32buf) { | if (b32buf) { | ||||
| if (need_icons_with_border) { | |||||
| b32buf_border = create_mono_icon_with_border(b32buf, 1, icon_border_intensity); | |||||
| IMB_premultiply_alpha(b32buf_border); | |||||
| } | |||||
| IMB_premultiply_alpha(b32buf); | IMB_premultiply_alpha(b32buf); | ||||
| } | } | ||||
| if (b16buf && b32buf) { | if (b16buf && b32buf) { | ||||
| /* Free existing texture if any. */ | /* Free existing texture if any. */ | ||||
| if (icongltex.id) { | free_icons_textures(); | ||||
| glDeleteTextures(1, &icongltex.id); | |||||
| icongltex.id = 0; | |||||
| } | |||||
| /* Allocate OpenGL texture. */ | /* Allocate OpenGL texture. */ | ||||
| glGenTextures(1, &icongltex.id); | icongltex.num_textures = need_icons_with_border ? 2 : 1; | ||||
| glGenTextures(icongltex.num_textures, icongltex.id); | |||||
| if (icongltex.id) { | if (icongltex.id) { | ||||
| int level = 2; | |||||
| icongltex.w = b32buf->x; | icongltex.w = b32buf->x; | ||||
| icongltex.h = b32buf->y; | icongltex.h = b32buf->y; | ||||
| icongltex.invw = 1.0f / b32buf->x; | icongltex.invw = 1.0f / b32buf->x; | ||||
| icongltex.invh = 1.0f / b32buf->y; | icongltex.invh = 1.0f / b32buf->y; | ||||
| glBindTexture(GL_TEXTURE_2D, icongltex.id); | glBindTexture(GL_TEXTURE_2D, icongltex.id[0]); | ||||
| b16buf = create_mono_icon_mipmaps(b32buf, b16buf, 0); | |||||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | |||||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
| glBindTexture(GL_TEXTURE_2D, 0); | |||||
| } | |||||
| glTexImage2D(GL_TEXTURE_2D, | if (need_icons_with_border && icongltex.id[1]) { | ||||
| 0, | glBindTexture(GL_TEXTURE_2D, icongltex.id[1]); | ||||
| GL_RGBA8, | b16buf_border = create_mono_icon_mipmaps(b32buf_border, b16buf_border, 0); | ||||
| b32buf->x, | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | ||||
| b32buf->y, | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||
| 0, | glBindTexture(GL_TEXTURE_2D, 0); | ||||
| GL_RGBA, | } | ||||
| GL_UNSIGNED_BYTE, | } | ||||
| b32buf->rect); | |||||
| glTexImage2D(GL_TEXTURE_2D, | |||||
| 1, | |||||
| GL_RGBA8, | |||||
| b16buf->x, | |||||
| b16buf->y, | |||||
| 0, | |||||
| GL_RGBA, | |||||
| GL_UNSIGNED_BYTE, | |||||
| b16buf->rect); | |||||
| while (b16buf->x > 1) { | |||||
| ImBuf *nbuf = IMB_onehalf(b16buf); | |||||
| glTexImage2D(GL_TEXTURE_2D, | |||||
| level, | |||||
| GL_RGBA8, | |||||
| nbuf->x, | |||||
| nbuf->y, | |||||
| 0, | |||||
| GL_RGBA, | |||||
| GL_UNSIGNED_BYTE, | |||||
| nbuf->rect); | |||||
| level++; | |||||
| IMB_freeImBuf(b16buf); | IMB_freeImBuf(b16buf); | ||||
| b16buf = nbuf; | IMB_freeImBuf(b32buf); | ||||
| IMB_freeImBuf(b16buf_border); | |||||
| IMB_freeImBuf(b32buf_border); | |||||
| } | } | ||||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | static void init_internal_icons(void) | ||||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | { | ||||
| int x, y; | |||||
| glBindTexture(GL_TEXTURE_2D, 0); | # if 0 // temp disabled | ||||
| if ((btheme != NULL) && btheme->tui.iconfile[0]) { | |||||
| char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); | |||||
| char iconfilestr[FILE_MAX]; | |||||
| if (icondir) { | |||||
| BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); | |||||
| /* if the image is missing bbuf will just be NULL */ | |||||
| bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL); | |||||
| if (bbuf && (bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H)) { | |||||
| printf( | |||||
| "\n***WARNING***\n" | |||||
| "Icons file '%s' too small.\n" | |||||
| "Using built-in Icons instead\n", | |||||
| iconfilestr); | |||||
| IMB_freeImBuf(bbuf); | |||||
| bbuf = NULL; | |||||
| } | |||||
| } | |||||
| else { | |||||
| printf("%s: 'icons' data path not found, continuing\n", __func__); | |||||
| } | |||||
| } | } | ||||
| # endif | |||||
| /* Define icons. */ | /* Define icons. */ | ||||
| for (y = 0; y < ICON_GRID_ROWS; y++) { | for (y = 0; y < ICON_GRID_ROWS; y++) { | ||||
| /* Row W has monochrome icons. */ | /* Row W has monochrome icons. */ | ||||
| for (x = 0; x < ICON_GRID_COLS; x++) { | for (x = 0; x < ICON_GRID_COLS; x++) { | ||||
| IconType icontype = icontypes[y * ICON_GRID_COLS + x]; | IconType icontype = icontypes[y * ICON_GRID_COLS + x]; | ||||
| if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) { | if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| def_internal_icon(b32buf, | def_internal_icon(NULL, | ||||
| BIFICONID_FIRST + y * ICON_GRID_COLS + x, | BIFICONID_FIRST + y * ICON_GRID_COLS + x, | ||||
| x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, | x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, | ||||
| y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, | y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN, | ||||
| ICON_GRID_W, | ICON_GRID_W, | ||||
| icontype.type, | icontype.type, | ||||
| icontype.theme_color); | icontype.theme_color); | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| def_internal_vicon(ICON_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw); | def_internal_vicon(ICON_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw); | ||||
| def_internal_vicon(ICON_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw); | def_internal_vicon(ICON_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw); | ||||
| def_internal_vicon(ICON_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw); | def_internal_vicon(ICON_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw); | ||||
| def_internal_vicon(ICON_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw); | def_internal_vicon(ICON_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw); | ||||
| def_internal_vicon(ICON_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw); | def_internal_vicon(ICON_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw); | ||||
| def_internal_vicon(ICON_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw); | def_internal_vicon(ICON_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw); | ||||
| Show All 19 Lines | # endif | ||||
| def_internal_vicon(ICON_COLORSET_13_VEC, vicon_colorset_draw_13); | def_internal_vicon(ICON_COLORSET_13_VEC, vicon_colorset_draw_13); | ||||
| def_internal_vicon(ICON_COLORSET_14_VEC, vicon_colorset_draw_14); | def_internal_vicon(ICON_COLORSET_14_VEC, vicon_colorset_draw_14); | ||||
| def_internal_vicon(ICON_COLORSET_15_VEC, vicon_colorset_draw_15); | def_internal_vicon(ICON_COLORSET_15_VEC, vicon_colorset_draw_15); | ||||
| def_internal_vicon(ICON_COLORSET_16_VEC, vicon_colorset_draw_16); | def_internal_vicon(ICON_COLORSET_16_VEC, vicon_colorset_draw_16); | ||||
| def_internal_vicon(ICON_COLORSET_17_VEC, vicon_colorset_draw_17); | def_internal_vicon(ICON_COLORSET_17_VEC, vicon_colorset_draw_17); | ||||
| def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18); | def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18); | ||||
| def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19); | def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19); | ||||
| def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20); | def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20); | ||||
| IMB_freeImBuf(b16buf); | |||||
| IMB_freeImBuf(b32buf); | |||||
| } | } | ||||
| # endif /* WITH_HEADLESS */ | # endif /* WITH_HEADLESS */ | ||||
| static void init_iconfile_list(struct ListBase *list) | static void init_iconfile_list(struct ListBase *list) | ||||
| { | { | ||||
| IconFile *ifile; | IconFile *ifile; | ||||
| struct direntry *dir; | struct direntry *dir; | ||||
| int totfile, i, index = 1; | int totfile, i, index = 1; | ||||
| ▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | ListBase *UI_iconfile_list(void) | ||||
| ListBase *list = &(iconfilelist); | ListBase *list = &(iconfilelist); | ||||
| return list; | return list; | ||||
| } | } | ||||
| void UI_icons_free(void) | void UI_icons_free(void) | ||||
| { | { | ||||
| #ifndef WITH_HEADLESS | #ifndef WITH_HEADLESS | ||||
| if (icongltex.id) { | free_icons_textures(); | ||||
| glDeleteTextures(1, &icongltex.id); | |||||
| icongltex.id = 0; | |||||
| } | |||||
| free_iconfile_list(&iconfilelist); | free_iconfile_list(&iconfilelist); | ||||
| BKE_icons_free(); | BKE_icons_free(); | ||||
| #endif | #endif | ||||
| } | } | ||||
| void UI_icons_free_drawinfo(void *drawinfo) | void UI_icons_free_drawinfo(void *drawinfo) | ||||
| { | { | ||||
| DrawInfo *di = drawinfo; | DrawInfo *di = drawinfo; | ||||
| ▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | int UI_icon_get_height(int icon_id) | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| void UI_icons_init() | void UI_icons_init() | ||||
| { | { | ||||
| #ifndef WITH_HEADLESS | #ifndef WITH_HEADLESS | ||||
| init_iconfile_list(&iconfilelist); | init_iconfile_list(&iconfilelist); | ||||
| UI_icons_reload_internal_textures(); | |||||
| init_internal_icons(); | init_internal_icons(); | ||||
| init_brush_icons(); | init_brush_icons(); | ||||
| init_event_icons(); | init_event_icons(); | ||||
| #endif | #endif | ||||
| } | } | ||||
| /* Render size for preview images and icons | /* Render size for preview images and icons | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 315 Lines • ▼ Show 20 Lines | |||||
| #define ICON_DRAW_CACHE_SIZE 16 | #define ICON_DRAW_CACHE_SIZE 16 | ||||
| typedef struct IconDrawCall { | typedef struct IconDrawCall { | ||||
| rctf pos; | rctf pos; | ||||
| rctf tex; | rctf tex; | ||||
| float color[4]; | float color[4]; | ||||
| } IconDrawCall; | } IconDrawCall; | ||||
| static struct { | typedef struct IconTextureDrawCall { | ||||
| IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE]; | IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE]; | ||||
| int calls; /* Number of calls batched together */ | int calls; /* Number of calls batched together */ | ||||
| } IconTextureDrawCall; | |||||
| static struct { | |||||
| IconTextureDrawCall normal; | |||||
| IconTextureDrawCall border; | |||||
| bool enabled; | bool enabled; | ||||
| float mat[4][4]; | float mat[4][4]; | ||||
| } g_icon_draw_cache = {{{{0}}}}; | } g_icon_draw_cache = {{{{{0}}}}}; | ||||
| void UI_icon_draw_cache_begin(void) | void UI_icon_draw_cache_begin(void) | ||||
| { | { | ||||
| BLI_assert(g_icon_draw_cache.enabled == false); | BLI_assert(g_icon_draw_cache.enabled == false); | ||||
| g_icon_draw_cache.enabled = true; | g_icon_draw_cache.enabled = true; | ||||
| } | } | ||||
| static void icon_draw_cache_flush_ex(void) | static void icon_draw_cache_texture_flush_ex(GLuint texture, | ||||
| IconTextureDrawCall *texture_draw_calls) | |||||
| { | { | ||||
| if (g_icon_draw_cache.calls == 0) { | if (texture_draw_calls->calls == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| /* We need to flush widget base first to ensure correct ordering. */ | |||||
| UI_widgetbase_draw_cache_flush(); | |||||
| GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); | |||||
| glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||||
| glBindTexture(GL_TEXTURE_2D, icongltex.id); | glBindTexture(GL_TEXTURE_2D, texture); | ||||
| GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); | GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); | ||||
| GPU_shader_bind(shader); | GPU_shader_bind(shader); | ||||
| int img_loc = GPU_shader_get_uniform_ensure(shader, "image"); | int img_loc = GPU_shader_get_uniform_ensure(shader, "image"); | ||||
| int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]"); | int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]"); | ||||
| glUniform1i(img_loc, 0); | glUniform1i(img_loc, 0); | ||||
| glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)g_icon_draw_cache.drawcall_cache); | glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache); | ||||
| GPU_draw_primitive(GPU_PRIM_TRIS, 6 * g_icon_draw_cache.calls); | GPU_draw_primitive(GPU_PRIM_TRIS, 6 * texture_draw_calls->calls); | ||||
| glBindTexture(GL_TEXTURE_2D, 0); | glBindTexture(GL_TEXTURE_2D, 0); | ||||
| g_icon_draw_cache.calls = 0; | texture_draw_calls->calls = 0; | ||||
| } | |||||
| static void icon_draw_cache_flush_ex(bool only_full_caches) | |||||
| { | |||||
| bool should_draw = false; | |||||
| if (only_full_caches) { | |||||
| should_draw = g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE || | |||||
| g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE; | |||||
| } | |||||
| else { | |||||
| should_draw = g_icon_draw_cache.normal.calls || g_icon_draw_cache.border.calls; | |||||
| } | |||||
| if (should_draw) { | |||||
| /* We need to flush widget base first to ensure correct ordering. */ | |||||
| UI_widgetbase_draw_cache_flush(); | |||||
| GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); | |||||
| if (!only_full_caches || g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE) { | |||||
| icon_draw_cache_texture_flush_ex(icongltex.id[0], &g_icon_draw_cache.normal); | |||||
| } | |||||
| if (!only_full_caches || g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE) { | |||||
| icon_draw_cache_texture_flush_ex(icongltex.id[1], &g_icon_draw_cache.border); | |||||
| } | |||||
| GPU_blend_set_func_separate( | GPU_blend_set_func_separate( | ||||
| GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); | GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); | ||||
| } | } | ||||
| } | |||||
| void UI_icon_draw_cache_end(void) | void UI_icon_draw_cache_end(void) | ||||
| { | { | ||||
| BLI_assert(g_icon_draw_cache.enabled == true); | BLI_assert(g_icon_draw_cache.enabled == true); | ||||
| g_icon_draw_cache.enabled = false; | g_icon_draw_cache.enabled = false; | ||||
| /* Don't change blend state if it's not needed. */ | /* Don't change blend state if it's not needed. */ | ||||
| if (g_icon_draw_cache.calls == 0) { | if (g_icon_draw_cache.border.calls == 0 && g_icon_draw_cache.normal.calls == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| GPU_blend(true); | GPU_blend(true); | ||||
| icon_draw_cache_flush_ex(); | icon_draw_cache_flush_ex(false); | ||||
| GPU_blend(false); | GPU_blend(false); | ||||
| } | } | ||||
| static void icon_draw_texture_cached(float x, | static void icon_draw_texture_cached(float x, | ||||
| float y, | float y, | ||||
| float w, | float w, | ||||
| float h, | float h, | ||||
| int ix, | int ix, | ||||
| int iy, | int iy, | ||||
| int UNUSED(iw), | int UNUSED(iw), | ||||
| int ih, | int ih, | ||||
| float alpha, | float alpha, | ||||
| const float rgb[3]) | const float rgb[3], | ||||
| bool with_border) | |||||
| { | { | ||||
| float mvp[4][4]; | float mvp[4][4]; | ||||
| GPU_matrix_model_view_projection_get(mvp); | GPU_matrix_model_view_projection_get(mvp); | ||||
| IconDrawCall *call = &g_icon_draw_cache.drawcall_cache[g_icon_draw_cache.calls]; | IconTextureDrawCall *texture_call = with_border ? &g_icon_draw_cache.border : | ||||
| g_icon_draw_cache.calls++; | &g_icon_draw_cache.normal; | ||||
| IconDrawCall *call = &texture_call->drawcall_cache[texture_call->calls]; | |||||
| texture_call->calls++; | |||||
| /* Manual mat4*vec2 */ | /* Manual mat4*vec2 */ | ||||
| call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0]; | call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0]; | ||||
| call->pos.ymin = x * mvp[0][1] + y * mvp[1][1] + mvp[3][1]; | call->pos.ymin = x * mvp[0][1] + y * mvp[1][1] + mvp[3][1]; | ||||
| call->pos.xmax = call->pos.xmin + w * mvp[0][0] + h * mvp[1][0]; | call->pos.xmax = call->pos.xmin + w * mvp[0][0] + h * mvp[1][0]; | ||||
| call->pos.ymax = call->pos.ymin + w * mvp[0][1] + h * mvp[1][1]; | call->pos.ymax = call->pos.ymin + w * mvp[0][1] + h * mvp[1][1]; | ||||
| call->tex.xmin = ix * icongltex.invw; | call->tex.xmin = ix * icongltex.invw; | ||||
| call->tex.xmax = (ix + ih) * icongltex.invw; | call->tex.xmax = (ix + ih) * icongltex.invw; | ||||
| call->tex.ymin = iy * icongltex.invh; | call->tex.ymin = iy * icongltex.invh; | ||||
| call->tex.ymax = (iy + ih) * icongltex.invh; | call->tex.ymax = (iy + ih) * icongltex.invh; | ||||
| if (rgb) { | if (rgb) { | ||||
| copy_v4_fl4(call->color, rgb[0], rgb[1], rgb[2], alpha); | copy_v4_fl4(call->color, rgb[0], rgb[1], rgb[2], alpha); | ||||
| } | } | ||||
| else { | else { | ||||
| copy_v4_fl(call->color, alpha); | copy_v4_fl(call->color, alpha); | ||||
| } | } | ||||
| if (g_icon_draw_cache.calls == ICON_DRAW_CACHE_SIZE) { | if (texture_call->calls == ICON_DRAW_CACHE_SIZE) { | ||||
| icon_draw_cache_flush_ex(); | icon_draw_cache_flush_ex(true); | ||||
| } | } | ||||
| } | } | ||||
| static void icon_draw_texture(float x, | static void icon_draw_texture(float x, | ||||
| float y, | float y, | ||||
| float w, | float w, | ||||
| float h, | float h, | ||||
| int ix, | int ix, | ||||
| int iy, | int iy, | ||||
| int iw, | int iw, | ||||
| int ih, | int ih, | ||||
| float alpha, | float alpha, | ||||
| const float rgb[3]) | const float rgb[3], | ||||
| bool with_border) | |||||
| { | { | ||||
| if (g_icon_draw_cache.enabled) { | if (g_icon_draw_cache.enabled) { | ||||
| icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb); | icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border); | ||||
| return; | return; | ||||
| } | } | ||||
| /* We need to flush widget base first to ensure correct ordering. */ | /* We need to flush widget base first to ensure correct ordering. */ | ||||
| UI_widgetbase_draw_cache_flush(); | UI_widgetbase_draw_cache_flush(); | ||||
| GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); | GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); | ||||
| float x1, x2, y1, y2; | float x1, x2, y1, y2; | ||||
| x1 = ix * icongltex.invw; | x1 = ix * icongltex.invw; | ||||
| x2 = (ix + ih) * icongltex.invw; | x2 = (ix + ih) * icongltex.invw; | ||||
| y1 = iy * icongltex.invh; | y1 = iy * icongltex.invh; | ||||
| y2 = (iy + ih) * icongltex.invh; | y2 = (iy + ih) * icongltex.invh; | ||||
| glActiveTexture(GL_TEXTURE0); | glActiveTexture(GL_TEXTURE0); | ||||
| glBindTexture(GL_TEXTURE_2D, icongltex.id); | glBindTexture(GL_TEXTURE_2D, with_border ? icongltex.id[1] : icongltex.id[0]); | ||||
| GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); | GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR); | ||||
| GPU_shader_bind(shader); | GPU_shader_bind(shader); | ||||
| if (rgb) { | if (rgb) { | ||||
| glUniform4f( | glUniform4f( | ||||
| GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), rgb[0], rgb[1], rgb[2], alpha); | GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), rgb[0], rgb[1], rgb[2], alpha); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | icon_draw_texture(x, | ||||
| y, | y, | ||||
| (float)w, | (float)w, | ||||
| (float)h, | (float)h, | ||||
| di->data.texture.x, | di->data.texture.x, | ||||
| di->data.texture.y, | di->data.texture.y, | ||||
| di->data.texture.w, | di->data.texture.w, | ||||
| di->data.texture.h, | di->data.texture.h, | ||||
| alpha, | alpha, | ||||
| rgb); | rgb, | ||||
| false); | |||||
| } | } | ||||
| else if (di->type == ICON_TYPE_MONO_TEXTURE) { | else if (di->type == ICON_TYPE_MONO_TEXTURE) { | ||||
| /* icon that matches text color, assumed to be white */ | /* icon that matches text color, assumed to be white */ | ||||
| bool with_border = false; | |||||
| float color[4]; | float color[4]; | ||||
| if (!UI_GetIconThemeColor4fv(di->data.texture.theme_color, color)) { | if (!UI_GetIconThemeColor4fv(di->data.texture.theme_color, color)) { | ||||
| if (mono_rgba) { | if (mono_rgba) { | ||||
| rgba_uchar_to_float(color, (const uchar *)mono_rgba); | rgba_uchar_to_float(color, (const uchar *)mono_rgba); | ||||
| } | } | ||||
| else { | else { | ||||
| UI_GetThemeColor4fv(TH_TEXT, color); | UI_GetThemeColor4fv(TH_TEXT, color); | ||||
| } | } | ||||
| } | } | ||||
| else { | |||||
| with_border = (btheme->tui.icon_border_intensity > 0.0f); | |||||
| } | |||||
| if (rgb) { | if (rgb) { | ||||
| mul_v3_v3(color, rgb); | mul_v3_v3(color, rgb); | ||||
| } | } | ||||
| mul_v4_fl(color, alpha); | mul_v4_fl(color, alpha); | ||||
| icon_draw_texture(x, | float border_outset = 0.0; | ||||
| y, | unsigned int border_texel = 0; | ||||
| (float)w, | if (with_border) { | ||||
| (float)h, | const float scale = (float)ICON_GRID_W / (float)ICON_DEFAULT_WIDTH; | ||||
| di->data.texture.x, | border_texel = ICON_MONO_BORDER_OUTSET; | ||||
| di->data.texture.y, | border_outset = ICON_MONO_BORDER_OUTSET / (scale * aspect); | ||||
| di->data.texture.w, | } | ||||
| di->data.texture.h, | icon_draw_texture(x - border_outset, | ||||
| y - border_outset, | |||||
| (float)w + 2 * border_outset, | |||||
| (float)h + 2 * border_outset, | |||||
| di->data.texture.x - border_texel, | |||||
| di->data.texture.y - border_texel, | |||||
| di->data.texture.w + 2 * border_texel, | |||||
| di->data.texture.h + 2 * border_texel, | |||||
| color[3], | color[3], | ||||
| color); | color, | ||||
| with_border); | |||||
| } | } | ||||
| else if (di->type == ICON_TYPE_BUFFER) { | else if (di->type == ICON_TYPE_BUFFER) { | ||||
| /* it is a builtin icon */ | /* it is a builtin icon */ | ||||
| iimg = di->data.buffer.image; | iimg = di->data.buffer.image; | ||||
| #ifndef WITH_HEADLESS | #ifndef WITH_HEADLESS | ||||
| icon_verify_datatoc(iimg); | icon_verify_datatoc(iimg); | ||||
| #endif | #endif | ||||
| ▲ Show 20 Lines • Show All 412 Lines • Show Last 20 Lines | |||||
This should only be done if needed by the theme, and not take up memory or startup time otherwise.