|
|
|
|
@@ -37,6 +37,7 @@
|
|
|
|
|
#include "BLI_utildefines.h"
|
|
|
|
|
#include "BLI_fileops_types.h"
|
|
|
|
|
#include "BLI_math_vector.h"
|
|
|
|
|
#include "BLI_math_color_blend.h"
|
|
|
|
|
|
|
|
|
|
#include "DNA_brush_types.h"
|
|
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
|
@@ -83,6 +84,7 @@
|
|
|
|
|
# define ICON_GRID_COLS 26
|
|
|
|
|
# define ICON_GRID_ROWS 30
|
|
|
|
|
|
|
|
|
|
# define ICON_MONO_BORDER_OUTSET 2
|
|
|
|
|
# define ICON_GRID_MARGIN 10
|
|
|
|
|
# define ICON_GRID_W 32
|
|
|
|
|
# define ICON_GRID_H 32
|
|
|
|
|
@@ -138,7 +140,8 @@ typedef struct DrawInfo {
|
|
|
|
|
} DrawInfo;
|
|
|
|
|
|
|
|
|
|
typedef struct IconTexture {
|
|
|
|
|
GLuint id;
|
|
|
|
|
GLuint id[2];
|
|
|
|
|
int num_textures;
|
|
|
|
|
int w;
|
|
|
|
|
int h;
|
|
|
|
|
float invw;
|
|
|
|
|
@@ -154,7 +157,7 @@ typedef struct IconType {
|
|
|
|
|
/* static here to cache results of icon directory scan, so it's not
|
|
|
|
|
* scanning the filesystem each time the menu is drawn */
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
@@ -714,10 +717,214 @@ static void icon_verify_datatoc(IconImage *iimg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ImBuf *create_mono_icon_with_border(ImBuf *buf,
|
|
|
|
|
int resolution_divider,
|
|
|
|
|
float border_intensity)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
for (int y = 0; y < ICON_GRID_ROWS; y++) {
|
|
|
|
|
for (int x = 0; x < ICON_GRID_COLS; x++) {
|
|
|
|
|
IconType icontype = icontypes[y * ICON_GRID_COLS + x];
|
|
|
|
|
if (icontype.type != ICON_TYPE_MONO_TEXTURE) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sx = x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET;
|
|
|
|
|
int sy = y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET;
|
|
|
|
|
sx = sx / resolution_divider;
|
|
|
|
|
sy = sy / resolution_divider;
|
|
|
|
|
|
|
|
|
|
/* blur the alpha channel and store it in blurred_alpha_buffer */
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
// blur alpha channel
|
|
|
|
|
const int write_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx;
|
|
|
|
|
float alpha_accum = 0.0;
|
|
|
|
|
unsigned int alpha_samples = 0;
|
|
|
|
|
for (int ax = asx; ax < aex; ax++) {
|
|
|
|
|
for (int ay = asy; ay < aey; ay++) {
|
|
|
|
|
const int offset_read = (sy + ay) * buf->x + (sx + ax);
|
|
|
|
|
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 {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
b16buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons16_png,
|
|
|
|
|
datatoc_blender_icons16_png_size,
|
|
|
|
|
IB_rect,
|
|
|
|
|
NULL,
|
|
|
|
|
"<blender icons>");
|
|
|
|
|
}
|
|
|
|
|
if (b16buf) {
|
|
|
|
|
if (need_icons_with_border) {
|
|
|
|
|
b16buf_border = create_mono_icon_with_border(b16buf, 2, icon_border_intensity);
|
|
|
|
|
IMB_premultiply_alpha(b16buf_border);
|
|
|
|
|
}
|
|
|
|
|
IMB_premultiply_alpha(b16buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b32buf == NULL) {
|
|
|
|
|
b32buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons32_png,
|
|
|
|
|
datatoc_blender_icons32_png_size,
|
|
|
|
|
IB_rect,
|
|
|
|
|
NULL,
|
|
|
|
|
"<blender icons>");
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b16buf && b32buf) {
|
|
|
|
|
/* Free existing texture if any. */
|
|
|
|
|
free_icons_textures();
|
|
|
|
|
|
|
|
|
|
/* Allocate OpenGL texture. */
|
|
|
|
|
icongltex.num_textures = need_icons_with_border ? 2 : 1;
|
|
|
|
|
glGenTextures(icongltex.num_textures, icongltex.id);
|
|
|
|
|
|
|
|
|
|
if (icongltex.id) {
|
|
|
|
|
icongltex.w = b32buf->x;
|
|
|
|
|
icongltex.h = b32buf->y;
|
|
|
|
|
icongltex.invw = 1.0f / b32buf->x;
|
|
|
|
|
icongltex.invh = 1.0f / b32buf->y;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (need_icons_with_border && icongltex.id[1]) {
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, icongltex.id[1]);
|
|
|
|
|
b16buf_border = create_mono_icon_mipmaps(b32buf_border, b16buf_border, 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IMB_freeImBuf(b16buf);
|
|
|
|
|
IMB_freeImBuf(b32buf);
|
|
|
|
|
IMB_freeImBuf(b16buf_border);
|
|
|
|
|
IMB_freeImBuf(b32buf_border);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void init_internal_icons(void)
|
|
|
|
|
{
|
|
|
|
|
// bTheme *btheme = UI_GetTheme();
|
|
|
|
|
ImBuf *b16buf = NULL, *b32buf = NULL;
|
|
|
|
|
int x, y;
|
|
|
|
|
|
|
|
|
|
# if 0 // temp disabled
|
|
|
|
|
@@ -746,106 +953,23 @@ static void init_internal_icons(void)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
# endif
|
|
|
|
|
if (b16buf == NULL) {
|
|
|
|
|
b16buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons16_png,
|
|
|
|
|
datatoc_blender_icons16_png_size,
|
|
|
|
|
IB_rect,
|
|
|
|
|
NULL,
|
|
|
|
|
"<blender icons>");
|
|
|
|
|
}
|
|
|
|
|
if (b16buf) {
|
|
|
|
|
IMB_premultiply_alpha(b16buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b32buf == NULL) {
|
|
|
|
|
b32buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons32_png,
|
|
|
|
|
datatoc_blender_icons32_png_size,
|
|
|
|
|
IB_rect,
|
|
|
|
|
NULL,
|
|
|
|
|
"<blender icons>");
|
|
|
|
|
}
|
|
|
|
|
if (b32buf) {
|
|
|
|
|
IMB_premultiply_alpha(b32buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b16buf && b32buf) {
|
|
|
|
|
/* Free existing texture if any. */
|
|
|
|
|
if (icongltex.id) {
|
|
|
|
|
glDeleteTextures(1, &icongltex.id);
|
|
|
|
|
icongltex.id = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate OpenGL texture. */
|
|
|
|
|
glGenTextures(1, &icongltex.id);
|
|
|
|
|
|
|
|
|
|
if (icongltex.id) {
|
|
|
|
|
int level = 2;
|
|
|
|
|
|
|
|
|
|
icongltex.w = b32buf->x;
|
|
|
|
|
icongltex.h = b32buf->y;
|
|
|
|
|
icongltex.invw = 1.0f / b32buf->x;
|
|
|
|
|
icongltex.invh = 1.0f / b32buf->y;
|
|
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, icongltex.id);
|
|
|
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D,
|
|
|
|
|
0,
|
|
|
|
|
GL_RGBA8,
|
|
|
|
|
b32buf->x,
|
|
|
|
|
b32buf->y,
|
|
|
|
|
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);
|
|
|
|
|
b16buf = nbuf;
|
|
|
|
|
/* Define icons. */
|
|
|
|
|
for (y = 0; y < ICON_GRID_ROWS; y++) {
|
|
|
|
|
/* Row W has monochrome icons. */
|
|
|
|
|
for (x = 0; x < ICON_GRID_COLS; x++) {
|
|
|
|
|
IconType icontype = icontypes[y * ICON_GRID_COLS + x];
|
|
|
|
|
if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define icons. */
|
|
|
|
|
for (y = 0; y < ICON_GRID_ROWS; y++) {
|
|
|
|
|
/* Row W has monochrome icons. */
|
|
|
|
|
for (x = 0; x < ICON_GRID_COLS; x++) {
|
|
|
|
|
IconType icontype = icontypes[y * ICON_GRID_COLS + x];
|
|
|
|
|
if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def_internal_icon(b32buf,
|
|
|
|
|
BIFICONID_FIRST + y * ICON_GRID_COLS + x,
|
|
|
|
|
x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN,
|
|
|
|
|
y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN,
|
|
|
|
|
ICON_GRID_W,
|
|
|
|
|
icontype.type,
|
|
|
|
|
icontype.theme_color);
|
|
|
|
|
}
|
|
|
|
|
def_internal_icon(NULL,
|
|
|
|
|
BIFICONID_FIRST + y * ICON_GRID_COLS + x,
|
|
|
|
|
x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN,
|
|
|
|
|
y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN,
|
|
|
|
|
ICON_GRID_W,
|
|
|
|
|
icontype.type,
|
|
|
|
|
icontype.theme_color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -883,9 +1007,6 @@ static void init_internal_icons(void)
|
|
|
|
|
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_20_VEC, vicon_colorset_draw_20);
|
|
|
|
|
|
|
|
|
|
IMB_freeImBuf(b16buf);
|
|
|
|
|
IMB_freeImBuf(b32buf);
|
|
|
|
|
}
|
|
|
|
|
# endif /* WITH_HEADLESS */
|
|
|
|
|
|
|
|
|
|
@@ -991,11 +1112,7 @@ ListBase *UI_iconfile_list(void)
|
|
|
|
|
void UI_icons_free(void)
|
|
|
|
|
{
|
|
|
|
|
#ifndef WITH_HEADLESS
|
|
|
|
|
if (icongltex.id) {
|
|
|
|
|
glDeleteTextures(1, &icongltex.id);
|
|
|
|
|
icongltex.id = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free_icons_textures();
|
|
|
|
|
free_iconfile_list(&iconfilelist);
|
|
|
|
|
BKE_icons_free();
|
|
|
|
|
#endif
|
|
|
|
|
@@ -1109,6 +1226,7 @@ void UI_icons_init()
|
|
|
|
|
{
|
|
|
|
|
#ifndef WITH_HEADLESS
|
|
|
|
|
init_iconfile_list(&iconfilelist);
|
|
|
|
|
UI_icons_reload_internal_textures();
|
|
|
|
|
init_internal_icons();
|
|
|
|
|
init_brush_icons();
|
|
|
|
|
init_event_icons();
|
|
|
|
|
@@ -1440,12 +1558,17 @@ typedef struct IconDrawCall {
|
|
|
|
|
float color[4];
|
|
|
|
|
} IconDrawCall;
|
|
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
|
typedef struct IconTextureDrawCall {
|
|
|
|
|
IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE];
|
|
|
|
|
int calls; /* Number of calls batched together */
|
|
|
|
|
} IconTextureDrawCall;
|
|
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
|
IconTextureDrawCall normal;
|
|
|
|
|
IconTextureDrawCall border;
|
|
|
|
|
bool enabled;
|
|
|
|
|
float mat[4][4];
|
|
|
|
|
} g_icon_draw_cache = {{{{0}}}};
|
|
|
|
|
} g_icon_draw_cache = {{{{{0}}}}};
|
|
|
|
|
|
|
|
|
|
void UI_icon_draw_cache_begin(void)
|
|
|
|
|
{
|
|
|
|
|
@@ -1453,19 +1576,15 @@ void UI_icon_draw_cache_begin(void)
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
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);
|
|
|
|
|
GPU_shader_bind(shader);
|
|
|
|
|
@@ -1474,16 +1593,43 @@ static void icon_draw_cache_flush_ex(void)
|
|
|
|
|
int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[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);
|
|
|
|
|
|
|
|
|
|
g_icon_draw_cache.calls = 0;
|
|
|
|
|
texture_draw_calls->calls = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPU_blend_set_func_separate(
|
|
|
|
|
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
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_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UI_icon_draw_cache_end(void)
|
|
|
|
|
@@ -1492,12 +1638,12 @@ void UI_icon_draw_cache_end(void)
|
|
|
|
|
g_icon_draw_cache.enabled = false;
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GPU_blend(true);
|
|
|
|
|
icon_draw_cache_flush_ex();
|
|
|
|
|
icon_draw_cache_flush_ex(false);
|
|
|
|
|
GPU_blend(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1510,14 +1656,18 @@ static void icon_draw_texture_cached(float x,
|
|
|
|
|
int UNUSED(iw),
|
|
|
|
|
int ih,
|
|
|
|
|
float alpha,
|
|
|
|
|
const float rgb[3])
|
|
|
|
|
const float rgb[3],
|
|
|
|
|
bool with_border)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
float mvp[4][4];
|
|
|
|
|
GPU_matrix_model_view_projection_get(mvp);
|
|
|
|
|
|
|
|
|
|
IconDrawCall *call = &g_icon_draw_cache.drawcall_cache[g_icon_draw_cache.calls];
|
|
|
|
|
g_icon_draw_cache.calls++;
|
|
|
|
|
IconTextureDrawCall *texture_call = with_border ? &g_icon_draw_cache.border :
|
|
|
|
|
&g_icon_draw_cache.normal;
|
|
|
|
|
|
|
|
|
|
IconDrawCall *call = &texture_call->drawcall_cache[texture_call->calls];
|
|
|
|
|
texture_call->calls++;
|
|
|
|
|
|
|
|
|
|
/* Manual mat4*vec2 */
|
|
|
|
|
call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0];
|
|
|
|
|
@@ -1537,8 +1687,8 @@ static void icon_draw_texture_cached(float x,
|
|
|
|
|
copy_v4_fl(call->color, alpha);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_icon_draw_cache.calls == ICON_DRAW_CACHE_SIZE) {
|
|
|
|
|
icon_draw_cache_flush_ex();
|
|
|
|
|
if (texture_call->calls == ICON_DRAW_CACHE_SIZE) {
|
|
|
|
|
icon_draw_cache_flush_ex(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1551,10 +1701,11 @@ static void icon_draw_texture(float x,
|
|
|
|
|
int iw,
|
|
|
|
|
int ih,
|
|
|
|
|
float alpha,
|
|
|
|
|
const float rgb[3])
|
|
|
|
|
const float rgb[3],
|
|
|
|
|
bool with_border)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1571,7 +1722,7 @@ static void icon_draw_texture(float x,
|
|
|
|
|
y2 = (iy + ih) * icongltex.invh;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
GPU_shader_bind(shader);
|
|
|
|
|
@@ -1696,10 +1847,12 @@ static void icon_draw_size(float x,
|
|
|
|
|
di->data.texture.w,
|
|
|
|
|
di->data.texture.h,
|
|
|
|
|
alpha,
|
|
|
|
|
rgb);
|
|
|
|
|
rgb,
|
|
|
|
|
false);
|
|
|
|
|
}
|
|
|
|
|
else if (di->type == ICON_TYPE_MONO_TEXTURE) {
|
|
|
|
|
/* icon that matches text color, assumed to be white */
|
|
|
|
|
bool with_border = false;
|
|
|
|
|
float color[4];
|
|
|
|
|
if (!UI_GetIconThemeColor4fv(di->data.texture.theme_color, color)) {
|
|
|
|
|
if (mono_rgba) {
|
|
|
|
|
@@ -1709,6 +1862,9 @@ static void icon_draw_size(float x,
|
|
|
|
|
UI_GetThemeColor4fv(TH_TEXT, color);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
with_border = (btheme->tui.icon_border_intensity > 0.0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rgb) {
|
|
|
|
|
mul_v3_v3(color, rgb);
|
|
|
|
|
@@ -1716,16 +1872,24 @@ static void icon_draw_size(float x,
|
|
|
|
|
|
|
|
|
|
mul_v4_fl(color, alpha);
|
|
|
|
|
|
|
|
|
|
icon_draw_texture(x,
|
|
|
|
|
y,
|
|
|
|
|
(float)w,
|
|
|
|
|
(float)h,
|
|
|
|
|
di->data.texture.x,
|
|
|
|
|
di->data.texture.y,
|
|
|
|
|
di->data.texture.w,
|
|
|
|
|
di->data.texture.h,
|
|
|
|
|
float border_outset = 0.0;
|
|
|
|
|
unsigned int border_texel = 0;
|
|
|
|
|
if (with_border) {
|
|
|
|
|
const float scale = (float)ICON_GRID_W / (float)ICON_DEFAULT_WIDTH;
|
|
|
|
|
border_texel = ICON_MONO_BORDER_OUTSET;
|
|
|
|
|
border_outset = ICON_MONO_BORDER_OUTSET / (scale * aspect);
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
color,
|
|
|
|
|
with_border);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (di->type == ICON_TYPE_BUFFER) {
|
|
|
|
|
|