Fix WITH_HEADLESS build
[blender.git] / source / blender / editors / interface / interface_icons.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edinterface
22  */
23
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "GPU_draw.h"
31 #include "GPU_matrix.h"
32 #include "GPU_batch.h"
33 #include "GPU_immediate.h"
34 #include "GPU_state.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_utildefines.h"
38 #include "BLI_fileops_types.h"
39 #include "BLI_math_vector.h"
40 #include "BLI_math_color_blend.h"
41
42 #include "DNA_brush_types.h"
43 #include "DNA_curve_types.h"
44 #include "DNA_dynamicpaint_types.h"
45 #include "DNA_gpencil_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_workspace_types.h"
50
51 #include "RNA_access.h"
52 #include "RNA_enum_types.h"
53
54 #include "BKE_context.h"
55 #include "BKE_global.h"
56 #include "BKE_paint.h"
57 #include "BKE_icons.h"
58 #include "BKE_appdir.h"
59 #include "BKE_studiolight.h"
60
61 #include "IMB_imbuf.h"
62 #include "IMB_imbuf_types.h"
63 #include "IMB_thumbs.h"
64
65 #include "BIF_glutil.h"
66
67 #include "DEG_depsgraph.h"
68
69 #include "DRW_engine.h"
70
71 #include "ED_datafiles.h"
72 #include "ED_keyframes_draw.h"
73 #include "ED_render.h"
74
75 #include "UI_interface.h"
76 #include "UI_interface_icons.h"
77
78 #include "WM_api.h"
79 #include "WM_types.h"
80
81 #include "interface_intern.h"
82
83 #ifndef WITH_HEADLESS
84 #  define ICON_GRID_COLS 26
85 #  define ICON_GRID_ROWS 30
86
87 #  define ICON_MONO_BORDER_OUTSET 2
88 #  define ICON_GRID_MARGIN 10
89 #  define ICON_GRID_W 32
90 #  define ICON_GRID_H 32
91 #endif /* WITH_HEADLESS */
92
93 typedef struct IconImage {
94   int w;
95   int h;
96   uint *rect;
97   const uchar *datatoc_rect;
98   int datatoc_size;
99 } IconImage;
100
101 typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
102
103 #define ICON_TYPE_PREVIEW 0
104 #define ICON_TYPE_COLOR_TEXTURE 1
105 #define ICON_TYPE_MONO_TEXTURE 2
106 #define ICON_TYPE_BUFFER 3
107 #define ICON_TYPE_VECTOR 4
108 #define ICON_TYPE_GEOM 5
109 #define ICON_TYPE_EVENT 6 /* draw keymap entries using custom renderer. */
110 #define ICON_TYPE_GPLAYER 7
111 #define ICON_TYPE_BLANK 8
112
113 typedef struct DrawInfo {
114   int type;
115
116   union {
117     /* type specific data */
118     struct {
119       VectorDrawFunc func;
120     } vector;
121     struct {
122       ImBuf *image_cache;
123     } geom;
124     struct {
125       IconImage *image;
126     } buffer;
127     struct {
128       int x, y, w, h;
129       int theme_color;
130     } texture;
131     struct {
132       /* Can be packed into a single int. */
133       short event_type;
134       short event_value;
135       int icon;
136       /* Allow lookups. */
137       struct DrawInfo *next;
138     } input;
139   } data;
140 } DrawInfo;
141
142 typedef struct IconTexture {
143   GLuint id[2];
144   int num_textures;
145   int w;
146   int h;
147   float invw;
148   float invh;
149 } IconTexture;
150
151 typedef struct IconType {
152   int type;
153   int theme_color;
154 } IconType;
155
156 /* ******************* STATIC LOCAL VARS ******************* */
157 /* static here to cache results of icon directory scan, so it's not
158  * scanning the filesystem each time the menu is drawn */
159 static struct ListBase iconfilelist = {NULL, NULL};
160 static IconTexture icongltex = {{0, 0}, 0, 0, 0, 0.0f, 0.0f};
161
162 #ifndef WITH_HEADLESS
163
164 static const IconType icontypes[] = {
165 #  define DEF_ICON(name) {ICON_TYPE_MONO_TEXTURE, 0},
166 #  define DEF_ICON_SCENE(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SCENE},
167 #  define DEF_ICON_COLLECTION(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_COLLECTION},
168 #  define DEF_ICON_OBJECT(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT},
169 #  define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA},
170 #  define DEF_ICON_MODIFIER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_MODIFIER},
171 #  define DEF_ICON_SHADING(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SHADING},
172 #  define DEF_ICON_VECTOR(name) {ICON_TYPE_VECTOR, 0},
173 #  define DEF_ICON_COLOR(name) {ICON_TYPE_COLOR_TEXTURE, 0},
174 #  define DEF_ICON_BLANK(name) {ICON_TYPE_BLANK, 0},
175 #  include "UI_icons.h"
176 };
177
178 /* **************************************************** */
179
180 static DrawInfo *def_internal_icon(
181     ImBuf *bbuf, int icon_id, int xofs, int yofs, int size, int type, int theme_color)
182 {
183   Icon *new_icon = NULL;
184   IconImage *iimg = NULL;
185   DrawInfo *di;
186
187   new_icon = MEM_callocN(sizeof(Icon), "texicon");
188
189   new_icon->obj = NULL; /* icon is not for library object */
190   new_icon->id_type = 0;
191
192   di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
193   di->type = type;
194
195   if (ELEM(type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) {
196     di->data.texture.theme_color = theme_color;
197     di->data.texture.x = xofs;
198     di->data.texture.y = yofs;
199     di->data.texture.w = size;
200     di->data.texture.h = size;
201   }
202   else if (type == ICON_TYPE_BUFFER) {
203     iimg = MEM_callocN(sizeof(IconImage), "icon_img");
204     iimg->w = size;
205     iimg->h = size;
206
207     /* icon buffers can get initialized runtime now, via datatoc */
208     if (bbuf) {
209       int y, imgsize;
210
211       iimg->rect = MEM_mallocN(size * size * sizeof(uint), "icon_rect");
212
213       /* Here we store the rect in the icon - same as before */
214       if (size == bbuf->x && size == bbuf->y && xofs == 0 && yofs == 0) {
215         memcpy(iimg->rect, bbuf->rect, size * size * sizeof(int));
216       }
217       else {
218         /* this code assumes square images */
219         imgsize = bbuf->x;
220         for (y = 0; y < size; y++) {
221           memcpy(
222               &iimg->rect[y * size], &bbuf->rect[(y + yofs) * imgsize + xofs], size * sizeof(int));
223         }
224       }
225     }
226     di->data.buffer.image = iimg;
227   }
228
229   new_icon->drawinfo_free = UI_icons_free_drawinfo;
230   new_icon->drawinfo = di;
231
232   BKE_icon_set(icon_id, new_icon);
233
234   return di;
235 }
236
237 static void def_internal_vicon(int icon_id, VectorDrawFunc drawFunc)
238 {
239   Icon *new_icon = NULL;
240   DrawInfo *di;
241
242   new_icon = MEM_callocN(sizeof(Icon), "texicon");
243
244   new_icon->obj = NULL; /* icon is not for library object */
245   new_icon->id_type = 0;
246
247   di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
248   di->type = ICON_TYPE_VECTOR;
249   di->data.vector.func = drawFunc;
250
251   new_icon->drawinfo_free = NULL;
252   new_icon->drawinfo = di;
253
254   BKE_icon_set(icon_id, new_icon);
255 }
256
257 /* Vector Icon Drawing Routines */
258
259 /* Utilities */
260
261 static void viconutil_set_point(GLint pt[2], int x, int y)
262 {
263   pt[0] = x;
264   pt[1] = y;
265 }
266
267 static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
268 {
269   GLint pts[3][2];
270   int cx = x + w / 2 - 4;
271   int cy = y + w / 2;
272   int d = w / 5, d2 = w / 7;
273
274   viconutil_set_point(pts[0], cx - d2, cy + d);
275   viconutil_set_point(pts[1], cx - d2, cy - d);
276   viconutil_set_point(pts[2], cx + d2, cy);
277
278   uint pos = GPU_vertformat_attr_add(
279       immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
280   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
281   immUniformColor4f(0.2f, 0.2f, 0.2f, alpha);
282
283   immBegin(GPU_PRIM_TRIS, 3);
284   immVertex2iv(pos, pts[0]);
285   immVertex2iv(pos, pts[1]);
286   immVertex2iv(pos, pts[2]);
287   immEnd();
288
289   immUnbindProgram();
290 }
291
292 static void vicon_keytype_draw_wrapper(
293     int x, int y, int w, int h, float alpha, short key_type, short handle_type)
294 {
295   /* init dummy theme state for Action Editor - where these colors are defined
296    * (since we're doing this offscreen, free from any particular space_id)
297    */
298   struct bThemeState theme_state;
299
300   UI_Theme_Store(&theme_state);
301   UI_SetTheme(SPACE_ACTION, RGN_TYPE_WINDOW);
302
303   /* the "x" and "y" given are the bottom-left coordinates of the icon,
304    * while the draw_keyframe_shape() function needs the midpoint for
305    * the keyframe
306    */
307   float xco = x + w / 2 + 0.5f;
308   float yco = y + h / 2 + 0.5f;
309
310   GPUVertFormat *format = immVertexFormat();
311   uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
312   uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
313   uint color_id = GPU_vertformat_attr_add(
314       format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
315   uint outline_color_id = GPU_vertformat_attr_add(
316       format, "outlineColor", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
317   uint flags_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
318
319   immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
320   GPU_enable_program_point_size();
321   immUniform2f("ViewportSize", -1.0f, -1.0f);
322   immBegin(GPU_PRIM_POINTS, 1);
323
324   /* draw keyframe
325    * - size: (default icon size == 16, default dopesheet icon size == 10)
326    * - sel: true unless in handletype icons (so that "keyframe" state shows the iconic yellow icon)
327    */
328   bool sel = (handle_type == KEYFRAME_HANDLE_NONE);
329
330   draw_keyframe_shape(xco,
331                       yco,
332                       (10.0f / 16.0f) * h,
333                       sel,
334                       key_type,
335                       KEYFRAME_SHAPE_BOTH,
336                       alpha,
337                       pos_id,
338                       size_id,
339                       color_id,
340                       outline_color_id,
341                       flags_id,
342                       handle_type,
343                       KEYFRAME_EXTREME_NONE);
344
345   immEnd();
346   GPU_disable_program_point_size();
347   immUnbindProgram();
348
349   UI_Theme_Restore(&theme_state);
350 }
351
352 static void vicon_keytype_keyframe_draw(int x, int y, int w, int h, float alpha)
353 {
354   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_NONE);
355 }
356
357 static void vicon_keytype_breakdown_draw(int x, int y, int w, int h, float alpha)
358 {
359   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_BREAKDOWN, KEYFRAME_HANDLE_NONE);
360 }
361
362 static void vicon_keytype_extreme_draw(int x, int y, int w, int h, float alpha)
363 {
364   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_EXTREME, KEYFRAME_HANDLE_NONE);
365 }
366
367 static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha)
368 {
369   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER, KEYFRAME_HANDLE_NONE);
370 }
371
372 static void vicon_keytype_moving_hold_draw(int x, int y, int w, int h, float alpha)
373 {
374   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD, KEYFRAME_HANDLE_NONE);
375 }
376
377 static void vicon_handletype_free_draw(int x, int y, int w, int h, float alpha)
378 {
379   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_FREE);
380 }
381
382 static void vicon_handletype_aligned_draw(int x, int y, int w, int h, float alpha)
383 {
384   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_ALIGNED);
385 }
386
387 static void vicon_handletype_vector_draw(int x, int y, int w, int h, float alpha)
388 {
389   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_VECTOR);
390 }
391
392 static void vicon_handletype_auto_draw(int x, int y, int w, int h, float alpha)
393 {
394   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_AUTO);
395 }
396
397 static void vicon_handletype_auto_clamp_draw(int x, int y, int w, int h, float alpha)
398 {
399   vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_KEYFRAME, KEYFRAME_HANDLE_AUTO_CLAMP);
400 }
401
402 static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha))
403 {
404   bTheme *btheme = UI_GetTheme();
405   ThemeWireColor *cs = &btheme->tarm[index];
406
407   /* Draw three bands of color: One per color
408    *    x-----a-----b-----c
409    *    |  N  |  S  |  A  |
410    *    x-----a-----b-----c
411    */
412   const int a = x + w / 3;
413   const int b = x + w / 3 * 2;
414   const int c = x + w;
415
416   uint pos = GPU_vertformat_attr_add(
417       immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
418   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
419
420   /* XXX: Include alpha into this... */
421   /* normal */
422   immUniformColor3ubv((uchar *)cs->solid);
423   immRecti(pos, x, y, a, y + h);
424
425   /* selected */
426   immUniformColor3ubv((uchar *)cs->select);
427   immRecti(pos, a, y, b, y + h);
428
429   /* active */
430   immUniformColor3ubv((uchar *)cs->active);
431   immRecti(pos, b, y, c, y + h);
432
433   immUnbindProgram();
434 }
435
436 #  define DEF_ICON_VECTOR_COLORSET_DRAW_NTH(prefix, index) \
437     static void vicon_colorset_draw_##prefix(int x, int y, int w, int h, float alpha) \
438     { \
439       vicon_colorset_draw(index, x, y, w, h, alpha); \
440     }
441
442 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(01, 0)
443 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(02, 1)
444 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(03, 2)
445 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(04, 3)
446 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(05, 4)
447 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(06, 5)
448 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(07, 6)
449 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(08, 7)
450 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(09, 8)
451 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(10, 9)
452 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(11, 10)
453 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(12, 11)
454 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(13, 12)
455 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(14, 13)
456 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(15, 14)
457 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(16, 15)
458 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(17, 16)
459 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(18, 17)
460 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(19, 18)
461 DEF_ICON_VECTOR_COLORSET_DRAW_NTH(20, 19)
462
463 #  undef DEF_ICON_VECTOR_COLORSET_DRAW_NTH
464
465 /* Dynamically render icon instead of rendering a plain color to a texture/buffer
466  * This is mot strictly a "vicon", as it needs access to icon->obj to get the color info,
467  * but it works in a very similar way.
468  */
469 static void vicon_gplayer_color_draw(Icon *icon, int x, int y, int w, int h)
470 {
471   bGPDlayer *gpl = (bGPDlayer *)icon->obj;
472
473   /* Just draw a colored rect - Like for vicon_colorset_draw() */
474   /* TODO: Make this have rounded corners, and maybe be a bit smaller.
475    * However, UI_draw_roundbox_aa() draws the colors too dark, so can't be used.
476    */
477   uint pos = GPU_vertformat_attr_add(
478       immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
479   immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
480
481   immUniformColor3fv(gpl->color);
482   immRecti(pos, x, y, x + w - 1, y + h - 1);
483
484   immUnbindProgram();
485 }
486
487 #  ifndef WITH_HEADLESS
488
489 static void init_brush_icons(void)
490 {
491
492 #    define INIT_BRUSH_ICON(icon_id, name) \
493       { \
494         uchar *rect = (uchar *)datatoc_##name##_png; \
495         int size = datatoc_##name##_png_size; \
496         DrawInfo *di; \
497 \
498         di = def_internal_icon(NULL, icon_id, 0, 0, w, ICON_TYPE_BUFFER, 0); \
499         di->data.buffer.image->datatoc_rect = rect; \
500         di->data.buffer.image->datatoc_size = size; \
501       } \
502       ((void)0)
503   /* end INIT_BRUSH_ICON */
504
505   const int w = 96; /* warning, brush size hardcoded in C, but it gets scaled */
506
507   INIT_BRUSH_ICON(ICON_BRUSH_BLOB, blob);
508   INIT_BRUSH_ICON(ICON_BRUSH_BLUR, blur);
509   INIT_BRUSH_ICON(ICON_BRUSH_CLAY, clay);
510   INIT_BRUSH_ICON(ICON_BRUSH_CLAY_STRIPS, claystrips);
511   INIT_BRUSH_ICON(ICON_BRUSH_CLONE, clone);
512   INIT_BRUSH_ICON(ICON_BRUSH_CREASE, crease);
513   INIT_BRUSH_ICON(ICON_BRUSH_SCULPT_DRAW, draw);
514   INIT_BRUSH_ICON(ICON_BRUSH_FILL, fill);
515   INIT_BRUSH_ICON(ICON_BRUSH_FLATTEN, flatten);
516   INIT_BRUSH_ICON(ICON_BRUSH_GRAB, grab);
517   INIT_BRUSH_ICON(ICON_BRUSH_INFLATE, inflate);
518   INIT_BRUSH_ICON(ICON_BRUSH_LAYER, layer);
519   INIT_BRUSH_ICON(ICON_BRUSH_MASK, mask);
520   INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix);
521   INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge);
522   INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch);
523   INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape);
524   INIT_BRUSH_ICON(ICON_BRUSH_SMEAR, smear);
525   INIT_BRUSH_ICON(ICON_BRUSH_SMOOTH, smooth);
526   INIT_BRUSH_ICON(ICON_BRUSH_SNAKE_HOOK, snake_hook);
527   INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften);
528   INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw);
529   INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill);
530   INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask);
531   INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
532   INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
533
534   /* grease pencil sculpt */
535   INIT_BRUSH_ICON(ICON_GPBRUSH_SMOOTH, gp_brush_smooth);
536   INIT_BRUSH_ICON(ICON_GPBRUSH_THICKNESS, gp_brush_thickness);
537   INIT_BRUSH_ICON(ICON_GPBRUSH_STRENGTH, gp_brush_strength);
538   INIT_BRUSH_ICON(ICON_GPBRUSH_GRAB, gp_brush_grab);
539   INIT_BRUSH_ICON(ICON_GPBRUSH_PUSH, gp_brush_push);
540   INIT_BRUSH_ICON(ICON_GPBRUSH_TWIST, gp_brush_twist);
541   INIT_BRUSH_ICON(ICON_GPBRUSH_PINCH, gp_brush_pinch);
542   INIT_BRUSH_ICON(ICON_GPBRUSH_RANDOMIZE, gp_brush_randomize);
543   INIT_BRUSH_ICON(ICON_GPBRUSH_CLONE, gp_brush_clone);
544   INIT_BRUSH_ICON(ICON_GPBRUSH_WEIGHT, gp_brush_weight);
545
546   /* grease pencil drawing brushes */
547   INIT_BRUSH_ICON(ICON_GPBRUSH_PENCIL, gp_brush_pencil);
548   INIT_BRUSH_ICON(ICON_GPBRUSH_PEN, gp_brush_pen);
549   INIT_BRUSH_ICON(ICON_GPBRUSH_INK, gp_brush_ink);
550   INIT_BRUSH_ICON(ICON_GPBRUSH_INKNOISE, gp_brush_inknoise);
551   INIT_BRUSH_ICON(ICON_GPBRUSH_BLOCK, gp_brush_block);
552   INIT_BRUSH_ICON(ICON_GPBRUSH_MARKER, gp_brush_marker);
553   INIT_BRUSH_ICON(ICON_GPBRUSH_FILL, gp_brush_fill);
554   INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_SOFT, gp_brush_erase_soft);
555   INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_HARD, gp_brush_erase_hard);
556   INIT_BRUSH_ICON(ICON_GPBRUSH_ERASE_STROKE, gp_brush_erase_stroke);
557
558 #    undef INIT_BRUSH_ICON
559 }
560
561 static DrawInfo *g_di_event_list = NULL;
562
563 int UI_icon_from_event_type(short event_type, short event_value)
564 {
565   if (event_type == RIGHTSHIFTKEY) {
566     event_type = LEFTSHIFTKEY;
567   }
568   else if (event_type == RIGHTCTRLKEY) {
569     event_type = LEFTCTRLKEY;
570   }
571   else if (event_type == RIGHTALTKEY) {
572     event_type = LEFTALTKEY;
573   }
574   else if (event_type == EVT_TWEAK_L) {
575     event_type = LEFTMOUSE;
576     event_value = KM_CLICK_DRAG;
577   }
578   else if (event_type == EVT_TWEAK_M) {
579     event_type = MIDDLEMOUSE;
580     event_value = KM_CLICK_DRAG;
581   }
582   else if (event_type == EVT_TWEAK_R) {
583     event_type = RIGHTMOUSE;
584     event_value = KM_CLICK_DRAG;
585   }
586
587   DrawInfo *di = g_di_event_list;
588   do {
589     if (di->data.input.event_type == event_type) {
590       return di->data.input.icon;
591     }
592   } while ((di = di->data.input.next));
593
594   if (event_type == LEFTMOUSE) {
595     return ELEM(event_value, KM_CLICK, KM_PRESS) ? ICON_MOUSE_LMB : ICON_MOUSE_LMB_DRAG;
596   }
597   else if (event_type == MIDDLEMOUSE) {
598     return ELEM(event_value, KM_CLICK, KM_PRESS) ? ICON_MOUSE_MMB : ICON_MOUSE_MMB_DRAG;
599   }
600   else if (event_type == RIGHTMOUSE) {
601     return ELEM(event_value, KM_CLICK, KM_PRESS) ? ICON_MOUSE_RMB : ICON_MOUSE_RMB_DRAG;
602   }
603
604   return ICON_NONE;
605 }
606
607 int UI_icon_from_keymap_item(const wmKeyMapItem *kmi, int r_icon_mod[4])
608 {
609   if (r_icon_mod) {
610     memset(r_icon_mod, 0x0, sizeof(int[4]));
611     int i = 0;
612     if (!ELEM(kmi->ctrl, KM_NOTHING, KM_ANY)) {
613       r_icon_mod[i++] = ICON_EVENT_CTRL;
614     }
615     if (!ELEM(kmi->alt, KM_NOTHING, KM_ANY)) {
616       r_icon_mod[i++] = ICON_EVENT_ALT;
617     }
618     if (!ELEM(kmi->shift, KM_NOTHING, KM_ANY)) {
619       r_icon_mod[i++] = ICON_EVENT_SHIFT;
620     }
621     if (!ELEM(kmi->oskey, KM_NOTHING, KM_ANY)) {
622       r_icon_mod[i++] = ICON_EVENT_OS;
623     }
624   }
625   return UI_icon_from_event_type(kmi->type, kmi->val);
626 }
627
628 static void init_event_icons(void)
629 {
630   DrawInfo *di_next = NULL;
631
632 #    define INIT_EVENT_ICON(icon_id, type, value) \
633       { \
634         DrawInfo *di = def_internal_icon(NULL, icon_id, 0, 0, w, ICON_TYPE_EVENT, 0); \
635         di->data.input.event_type = type; \
636         di->data.input.event_value = value; \
637         di->data.input.icon = icon_id; \
638         di->data.input.next = di_next; \
639         di_next = di; \
640       } \
641       ((void)0)
642   /* end INIT_EVENT_ICON */
643
644   const int w = 16; /* DUMMY */
645
646   INIT_EVENT_ICON(ICON_EVENT_A, AKEY, KM_ANY);
647   INIT_EVENT_ICON(ICON_EVENT_B, BKEY, KM_ANY);
648   INIT_EVENT_ICON(ICON_EVENT_C, CKEY, KM_ANY);
649   INIT_EVENT_ICON(ICON_EVENT_D, DKEY, KM_ANY);
650   INIT_EVENT_ICON(ICON_EVENT_E, EKEY, KM_ANY);
651   INIT_EVENT_ICON(ICON_EVENT_F, FKEY, KM_ANY);
652   INIT_EVENT_ICON(ICON_EVENT_G, GKEY, KM_ANY);
653   INIT_EVENT_ICON(ICON_EVENT_H, HKEY, KM_ANY);
654   INIT_EVENT_ICON(ICON_EVENT_I, IKEY, KM_ANY);
655   INIT_EVENT_ICON(ICON_EVENT_J, JKEY, KM_ANY);
656   INIT_EVENT_ICON(ICON_EVENT_K, KKEY, KM_ANY);
657   INIT_EVENT_ICON(ICON_EVENT_L, LKEY, KM_ANY);
658   INIT_EVENT_ICON(ICON_EVENT_M, MKEY, KM_ANY);
659   INIT_EVENT_ICON(ICON_EVENT_N, NKEY, KM_ANY);
660   INIT_EVENT_ICON(ICON_EVENT_O, OKEY, KM_ANY);
661   INIT_EVENT_ICON(ICON_EVENT_P, PKEY, KM_ANY);
662   INIT_EVENT_ICON(ICON_EVENT_Q, QKEY, KM_ANY);
663   INIT_EVENT_ICON(ICON_EVENT_R, RKEY, KM_ANY);
664   INIT_EVENT_ICON(ICON_EVENT_S, SKEY, KM_ANY);
665   INIT_EVENT_ICON(ICON_EVENT_T, TKEY, KM_ANY);
666   INIT_EVENT_ICON(ICON_EVENT_U, UKEY, KM_ANY);
667   INIT_EVENT_ICON(ICON_EVENT_V, VKEY, KM_ANY);
668   INIT_EVENT_ICON(ICON_EVENT_W, WKEY, KM_ANY);
669   INIT_EVENT_ICON(ICON_EVENT_X, XKEY, KM_ANY);
670   INIT_EVENT_ICON(ICON_EVENT_Y, YKEY, KM_ANY);
671   INIT_EVENT_ICON(ICON_EVENT_Z, ZKEY, KM_ANY);
672   INIT_EVENT_ICON(ICON_EVENT_SHIFT, LEFTSHIFTKEY, KM_ANY);
673   INIT_EVENT_ICON(ICON_EVENT_CTRL, LEFTCTRLKEY, KM_ANY);
674   INIT_EVENT_ICON(ICON_EVENT_ALT, LEFTALTKEY, KM_ANY);
675   INIT_EVENT_ICON(ICON_EVENT_OS, OSKEY, KM_ANY);
676   INIT_EVENT_ICON(ICON_EVENT_F1, F1KEY, KM_ANY);
677   INIT_EVENT_ICON(ICON_EVENT_F2, F2KEY, KM_ANY);
678   INIT_EVENT_ICON(ICON_EVENT_F3, F3KEY, KM_ANY);
679   INIT_EVENT_ICON(ICON_EVENT_F4, F4KEY, KM_ANY);
680   INIT_EVENT_ICON(ICON_EVENT_F5, F5KEY, KM_ANY);
681   INIT_EVENT_ICON(ICON_EVENT_F6, F6KEY, KM_ANY);
682   INIT_EVENT_ICON(ICON_EVENT_F7, F7KEY, KM_ANY);
683   INIT_EVENT_ICON(ICON_EVENT_F8, F8KEY, KM_ANY);
684   INIT_EVENT_ICON(ICON_EVENT_F9, F9KEY, KM_ANY);
685   INIT_EVENT_ICON(ICON_EVENT_F10, F10KEY, KM_ANY);
686   INIT_EVENT_ICON(ICON_EVENT_F11, F11KEY, KM_ANY);
687   INIT_EVENT_ICON(ICON_EVENT_F12, F12KEY, KM_ANY);
688   INIT_EVENT_ICON(ICON_EVENT_ESC, ESCKEY, KM_ANY);
689   INIT_EVENT_ICON(ICON_EVENT_TAB, TABKEY, KM_ANY);
690   INIT_EVENT_ICON(ICON_EVENT_PAGEUP, PAGEUPKEY, KM_ANY);
691   INIT_EVENT_ICON(ICON_EVENT_PAGEDOWN, PAGEDOWNKEY, KM_ANY);
692   INIT_EVENT_ICON(ICON_EVENT_RETURN, RETKEY, KM_ANY);
693
694   g_di_event_list = di_next;
695
696 #    undef INIT_EVENT_ICON
697 }
698
699 static void icon_verify_datatoc(IconImage *iimg)
700 {
701   /* if it has own rect, things are all OK */
702   if (iimg->rect) {
703     return;
704   }
705
706   if (iimg->datatoc_rect) {
707     ImBuf *bbuf = IMB_ibImageFromMemory(
708         iimg->datatoc_rect, iimg->datatoc_size, IB_rect, NULL, "<matcap icon>");
709     /* w and h were set on initialize */
710     if (bbuf->x != iimg->h && bbuf->y != iimg->w) {
711       IMB_scaleImBuf(bbuf, iimg->w, iimg->h);
712     }
713
714     iimg->rect = bbuf->rect;
715     bbuf->rect = NULL;
716     IMB_freeImBuf(bbuf);
717   }
718 }
719
720 static ImBuf *create_mono_icon_with_border(ImBuf *buf,
721                                            int resolution_divider,
722                                            float border_intensity)
723 {
724   ImBuf *result = IMB_dupImBuf(buf);
725   const float border_sharpness = 16.0 / (resolution_divider * resolution_divider);
726
727   float blurred_alpha_buffer[(ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) *
728                              (ICON_GRID_H + 2 * ICON_MONO_BORDER_OUTSET)];
729   const int icon_width = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider;
730   const int icon_height = (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) / resolution_divider;
731
732   for (int y = 0; y < ICON_GRID_ROWS; y++) {
733     for (int x = 0; x < ICON_GRID_COLS; x++) {
734       IconType icontype = icontypes[y * ICON_GRID_COLS + x];
735       if (icontype.type != ICON_TYPE_MONO_TEXTURE) {
736         continue;
737       }
738
739       int sx = x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET;
740       int sy = y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN - ICON_MONO_BORDER_OUTSET;
741       sx = sx / resolution_divider;
742       sy = sy / resolution_divider;
743
744       /* blur the alpha channel and store it in blurred_alpha_buffer */
745       int blur_size = 2 / resolution_divider;
746       for (int bx = 0; bx < icon_width; bx++) {
747         const int asx = MAX2(bx - blur_size, 0);
748         const int aex = MIN2(bx + blur_size + 1, icon_width);
749         for (int by = 0; by < icon_height; by++) {
750           const int asy = MAX2(by - blur_size, 0);
751           const int aey = MIN2(by + blur_size + 1, icon_height);
752
753           // blur alpha channel
754           const int write_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx;
755           float alpha_accum = 0.0;
756           unsigned int alpha_samples = 0;
757           for (int ax = asx; ax < aex; ax++) {
758             for (int ay = asy; ay < aey; ay++) {
759               const int offset_read = (sy + ay) * buf->x + (sx + ax);
760               unsigned int color_read = buf->rect[offset_read];
761               const float alpha_read = ((color_read & 0xff000000) >> 24) / 255.0;
762               alpha_accum += alpha_read;
763               alpha_samples += 1;
764             }
765           }
766           blurred_alpha_buffer[write_offset] = alpha_accum / alpha_samples;
767         }
768       }
769
770       /* apply blurred alpha */
771       for (int bx = 0; bx < icon_width; bx++) {
772         for (int by = 0; by < icon_height; by++) {
773           const int blurred_alpha_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx;
774           const int offset_write = (sy + by) * buf->x + (sx + bx);
775           const float blurred_alpha = blurred_alpha_buffer[blurred_alpha_offset];
776           float border_srgb[4] = {
777               0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity};
778
779           const unsigned int color_read = buf->rect[offset_write];
780           const unsigned char *orig_color = (unsigned char *)&color_read;
781
782           float border_rgba[4];
783           float orig_rgba[4];
784           float dest_rgba[4];
785           float dest_srgb[4];
786
787           srgb_to_linearrgb_v4(border_rgba, border_srgb);
788           srgb_to_linearrgb_uchar4(orig_rgba, orig_color);
789           blend_color_interpolate_float(dest_rgba, orig_rgba, border_rgba, 1.0 - orig_rgba[3]);
790           linearrgb_to_srgb_v4(dest_srgb, dest_rgba);
791
792           unsigned int alpha_mask = ((unsigned int)(dest_srgb[3] * 255)) << 24;
793           unsigned int cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask;
794           result->rect[offset_write] = cpack;
795         }
796       }
797     }
798   }
799   return result;
800 }
801
802 /* Generate the mipmap levels for the icon textures
803  * During creation the source16 ImBuf will be freed to reduce memory overhead
804  * A new ImBuf will be returned that needs is owned by the caller.
805  *
806  * FIXME: Mipmap levels are generated until the width of the image is 1, which
807  *        are too many levels than that are needed.*/
808 static ImBuf *create_mono_icon_mipmaps(ImBuf *source32, ImBuf *source16, int level)
809 {
810   if (level == 0) {
811     glTexImage2D(GL_TEXTURE_2D,
812                  level,
813                  GL_RGBA8,
814                  source32->x,
815                  source32->y,
816                  0,
817                  GL_RGBA,
818                  GL_UNSIGNED_BYTE,
819                  source32->rect);
820     return create_mono_icon_mipmaps(source32, source16, level + 1);
821   }
822   else {
823     glTexImage2D(GL_TEXTURE_2D,
824                  level,
825                  GL_RGBA8,
826                  source16->x,
827                  source16->y,
828                  0,
829                  GL_RGBA,
830                  GL_UNSIGNED_BYTE,
831                  source16->rect);
832     if (source16->x > 1) {
833       ImBuf *nbuf = IMB_onehalf(source16);
834       IMB_freeImBuf(source16);
835       source16 = create_mono_icon_mipmaps(source32, nbuf, level + 1);
836     }
837     return source16;
838   }
839 }
840
841 static void free_icons_textures(void)
842 {
843   if (icongltex.num_textures > 0) {
844     glDeleteTextures(icongltex.num_textures, icongltex.id);
845     icongltex.id[0] = 0;
846     icongltex.id[1] = 0;
847     icongltex.num_textures = 0;
848   }
849 }
850
851 /* Reload the textures for internal icons.
852  * This function will release the previous textures. */
853 void UI_icons_reload_internal_textures(void)
854 {
855   bTheme *btheme = UI_GetTheme();
856   ImBuf *b16buf = NULL, *b32buf = NULL, *b16buf_border = NULL, *b32buf_border = NULL;
857   const float icon_border_intensity = btheme->tui.icon_border_intensity;
858   bool need_icons_with_border = icon_border_intensity > 0.0f;
859
860   if (b16buf == NULL) {
861     b16buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons16_png,
862                                    datatoc_blender_icons16_png_size,
863                                    IB_rect,
864                                    NULL,
865                                    "<blender icons>");
866   }
867   if (b16buf) {
868     if (need_icons_with_border) {
869       b16buf_border = create_mono_icon_with_border(b16buf, 2, icon_border_intensity);
870       IMB_premultiply_alpha(b16buf_border);
871     }
872     IMB_premultiply_alpha(b16buf);
873   }
874
875   if (b32buf == NULL) {
876     b32buf = IMB_ibImageFromMemory((const uchar *)datatoc_blender_icons32_png,
877                                    datatoc_blender_icons32_png_size,
878                                    IB_rect,
879                                    NULL,
880                                    "<blender icons>");
881   }
882   if (b32buf) {
883     if (need_icons_with_border) {
884       b32buf_border = create_mono_icon_with_border(b32buf, 1, icon_border_intensity);
885       IMB_premultiply_alpha(b32buf_border);
886     }
887     IMB_premultiply_alpha(b32buf);
888   }
889
890   if (b16buf && b32buf) {
891     /* Free existing texture if any. */
892     free_icons_textures();
893
894     /* Allocate OpenGL texture. */
895     icongltex.num_textures = need_icons_with_border ? 2 : 1;
896     glGenTextures(icongltex.num_textures, icongltex.id);
897
898     if (icongltex.id[0]) {
899       icongltex.w = b32buf->x;
900       icongltex.h = b32buf->y;
901       icongltex.invw = 1.0f / b32buf->x;
902       icongltex.invh = 1.0f / b32buf->y;
903
904       glBindTexture(GL_TEXTURE_2D, icongltex.id[0]);
905       b16buf = create_mono_icon_mipmaps(b32buf, b16buf, 0);
906       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
907       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
908       glBindTexture(GL_TEXTURE_2D, 0);
909     }
910
911     if (need_icons_with_border && icongltex.id[1]) {
912       glBindTexture(GL_TEXTURE_2D, icongltex.id[1]);
913       b16buf_border = create_mono_icon_mipmaps(b32buf_border, b16buf_border, 0);
914       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
915       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
916       glBindTexture(GL_TEXTURE_2D, 0);
917     }
918   }
919
920   IMB_freeImBuf(b16buf);
921   IMB_freeImBuf(b32buf);
922   IMB_freeImBuf(b16buf_border);
923   IMB_freeImBuf(b32buf_border);
924 }
925
926 static void init_internal_icons(void)
927 {
928   int x, y;
929
930 #    if 0  // temp disabled
931   if ((btheme != NULL) && btheme->tui.iconfile[0]) {
932     char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons");
933     char iconfilestr[FILE_MAX];
934
935     if (icondir) {
936       BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile);
937
938       /* if the image is missing bbuf will just be NULL */
939       bbuf = IMB_loadiffname(iconfilestr, IB_rect, NULL);
940
941       if (bbuf && (bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H)) {
942         printf(
943             "\n***WARNING***\n"
944             "Icons file '%s' too small.\n"
945             "Using built-in Icons instead\n",
946             iconfilestr);
947         IMB_freeImBuf(bbuf);
948         bbuf = NULL;
949       }
950     }
951     else {
952       printf("%s: 'icons' data path not found, continuing\n", __func__);
953     }
954   }
955 #    endif
956
957   /* Define icons. */
958   for (y = 0; y < ICON_GRID_ROWS; y++) {
959     /* Row W has monochrome icons. */
960     for (x = 0; x < ICON_GRID_COLS; x++) {
961       IconType icontype = icontypes[y * ICON_GRID_COLS + x];
962       if (!ELEM(icontype.type, ICON_TYPE_COLOR_TEXTURE, ICON_TYPE_MONO_TEXTURE)) {
963         continue;
964       }
965
966       def_internal_icon(NULL,
967                         BIFICONID_FIRST + y * ICON_GRID_COLS + x,
968                         x * (ICON_GRID_W + ICON_GRID_MARGIN) + ICON_GRID_MARGIN,
969                         y * (ICON_GRID_H + ICON_GRID_MARGIN) + ICON_GRID_MARGIN,
970                         ICON_GRID_W,
971                         icontype.type,
972                         icontype.theme_color);
973     }
974   }
975
976   def_internal_vicon(ICON_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
977
978   def_internal_vicon(ICON_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw);
979   def_internal_vicon(ICON_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw);
980   def_internal_vicon(ICON_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw);
981   def_internal_vicon(ICON_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw);
982   def_internal_vicon(ICON_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw);
983
984   def_internal_vicon(ICON_HANDLETYPE_FREE_VEC, vicon_handletype_free_draw);
985   def_internal_vicon(ICON_HANDLETYPE_ALIGNED_VEC, vicon_handletype_aligned_draw);
986   def_internal_vicon(ICON_HANDLETYPE_VECTOR_VEC, vicon_handletype_vector_draw);
987   def_internal_vicon(ICON_HANDLETYPE_AUTO_VEC, vicon_handletype_auto_draw);
988   def_internal_vicon(ICON_HANDLETYPE_AUTO_CLAMP_VEC, vicon_handletype_auto_clamp_draw);
989
990   def_internal_vicon(ICON_COLORSET_01_VEC, vicon_colorset_draw_01);
991   def_internal_vicon(ICON_COLORSET_02_VEC, vicon_colorset_draw_02);
992   def_internal_vicon(ICON_COLORSET_03_VEC, vicon_colorset_draw_03);
993   def_internal_vicon(ICON_COLORSET_04_VEC, vicon_colorset_draw_04);
994   def_internal_vicon(ICON_COLORSET_05_VEC, vicon_colorset_draw_05);
995   def_internal_vicon(ICON_COLORSET_06_VEC, vicon_colorset_draw_06);
996   def_internal_vicon(ICON_COLORSET_07_VEC, vicon_colorset_draw_07);
997   def_internal_vicon(ICON_COLORSET_08_VEC, vicon_colorset_draw_08);
998   def_internal_vicon(ICON_COLORSET_09_VEC, vicon_colorset_draw_09);
999   def_internal_vicon(ICON_COLORSET_10_VEC, vicon_colorset_draw_10);
1000   def_internal_vicon(ICON_COLORSET_11_VEC, vicon_colorset_draw_11);
1001   def_internal_vicon(ICON_COLORSET_12_VEC, vicon_colorset_draw_12);
1002   def_internal_vicon(ICON_COLORSET_13_VEC, vicon_colorset_draw_13);
1003   def_internal_vicon(ICON_COLORSET_14_VEC, vicon_colorset_draw_14);
1004   def_internal_vicon(ICON_COLORSET_15_VEC, vicon_colorset_draw_15);
1005   def_internal_vicon(ICON_COLORSET_16_VEC, vicon_colorset_draw_16);
1006   def_internal_vicon(ICON_COLORSET_17_VEC, vicon_colorset_draw_17);
1007   def_internal_vicon(ICON_COLORSET_18_VEC, vicon_colorset_draw_18);
1008   def_internal_vicon(ICON_COLORSET_19_VEC, vicon_colorset_draw_19);
1009   def_internal_vicon(ICON_COLORSET_20_VEC, vicon_colorset_draw_20);
1010 }
1011 #  endif /* WITH_HEADLESS */
1012
1013 static void init_iconfile_list(struct ListBase *list)
1014 {
1015   IconFile *ifile;
1016   struct direntry *dir;
1017   int totfile, i, index = 1;
1018   const char *icondir;
1019
1020   BLI_listbase_clear(list);
1021   icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons");
1022
1023   if (icondir == NULL) {
1024     return;
1025   }
1026
1027   totfile = BLI_filelist_dir_contents(icondir, &dir);
1028
1029   for (i = 0; i < totfile; i++) {
1030     if ((dir[i].type & S_IFREG)) {
1031       const char *filename = dir[i].relname;
1032
1033       if (BLI_path_extension_check(filename, ".png")) {
1034         /* loading all icons on file start is overkill & slows startup
1035          * its possible they change size after blender load anyway. */
1036 #  if 0
1037         int ifilex, ifiley;
1038         char iconfilestr[FILE_MAX + 16]; /* allow 256 chars for file+dir */
1039         ImBuf *bbuf = NULL;
1040         /* check to see if the image is the right size, continue if not */
1041         /* copying strings here should go ok, assuming that we never get back
1042          * a complete path to file longer than 256 chars */
1043         BLI_join_dirfile(iconfilestr, sizeof(iconfilestr), icondir, filename);
1044         bbuf = IMB_loadiffname(iconfilestr, IB_rect);
1045
1046         if (bbuf) {
1047           ifilex = bbuf->x;
1048           ifiley = bbuf->y;
1049           IMB_freeImBuf(bbuf);
1050         }
1051         else {
1052           ifilex = ifiley = 0;
1053         }
1054
1055         /* bad size or failed to load */
1056         if ((ifilex != ICON_IMAGE_W) || (ifiley != ICON_IMAGE_H)) {
1057           printf("icon '%s' is wrong size %dx%d\n", iconfilestr, ifilex, ifiley);
1058           continue;
1059         }
1060 #  endif /* removed */
1061
1062         /* found a potential icon file, so make an entry for it in the cache list */
1063         ifile = MEM_callocN(sizeof(IconFile), "IconFile");
1064
1065         BLI_strncpy(ifile->filename, filename, sizeof(ifile->filename));
1066         ifile->index = index;
1067
1068         BLI_addtail(list, ifile);
1069
1070         index++;
1071       }
1072     }
1073   }
1074
1075   BLI_filelist_free(dir, totfile);
1076   dir = NULL;
1077 }
1078
1079 static void free_iconfile_list(struct ListBase *list)
1080 {
1081   IconFile *ifile = NULL, *next_ifile = NULL;
1082
1083   for (ifile = list->first; ifile; ifile = next_ifile) {
1084     next_ifile = ifile->next;
1085     BLI_freelinkN(list, ifile);
1086   }
1087 }
1088
1089 #else
1090
1091 void UI_icons_reload_internal_textures(void)
1092 {
1093 }
1094
1095 #endif /* WITH_HEADLESS */
1096
1097 int UI_iconfile_get_index(const char *filename)
1098 {
1099   IconFile *ifile;
1100   ListBase *list = &(iconfilelist);
1101
1102   for (ifile = list->first; ifile; ifile = ifile->next) {
1103     if (BLI_path_cmp(filename, ifile->filename) == 0) {
1104       return ifile->index;
1105     }
1106   }
1107
1108   return 0;
1109 }
1110
1111 ListBase *UI_iconfile_list(void)
1112 {
1113   ListBase *list = &(iconfilelist);
1114
1115   return list;
1116 }
1117
1118 void UI_icons_free(void)
1119 {
1120 #ifndef WITH_HEADLESS
1121   free_icons_textures();
1122   free_iconfile_list(&iconfilelist);
1123   BKE_icons_free();
1124 #endif
1125 }
1126
1127 void UI_icons_free_drawinfo(void *drawinfo)
1128 {
1129   DrawInfo *di = drawinfo;
1130
1131   if (di) {
1132     if (di->type == ICON_TYPE_BUFFER) {
1133       if (di->data.buffer.image) {
1134         if (di->data.buffer.image->rect) {
1135           MEM_freeN(di->data.buffer.image->rect);
1136         }
1137         MEM_freeN(di->data.buffer.image);
1138       }
1139     }
1140     else if (di->type == ICON_TYPE_GEOM) {
1141       if (di->data.geom.image_cache) {
1142         IMB_freeImBuf(di->data.geom.image_cache);
1143       }
1144     }
1145
1146     MEM_freeN(di);
1147   }
1148 }
1149
1150 /**
1151  * #Icon.data_type and #Icon.obj
1152  */
1153 static DrawInfo *icon_create_drawinfo(Icon *icon)
1154 {
1155   int icon_data_type = icon->obj_type;
1156   DrawInfo *di = NULL;
1157
1158   di = MEM_callocN(sizeof(DrawInfo), "di_icon");
1159
1160   if (ELEM(icon_data_type, ICON_DATA_ID, ICON_DATA_PREVIEW)) {
1161     di->type = ICON_TYPE_PREVIEW;
1162   }
1163   else if (icon_data_type == ICON_DATA_GEOM) {
1164     di->type = ICON_TYPE_GEOM;
1165   }
1166   else if (icon_data_type == ICON_DATA_STUDIOLIGHT) {
1167     di->type = ICON_TYPE_BUFFER;
1168   }
1169   else if (icon_data_type == ICON_DATA_GPLAYER) {
1170     di->type = ICON_TYPE_GPLAYER;
1171   }
1172   else {
1173     BLI_assert(0);
1174   }
1175
1176   return di;
1177 }
1178
1179 static DrawInfo *icon_ensure_drawinfo(Icon *icon)
1180 {
1181   if (icon->drawinfo) {
1182     return icon->drawinfo;
1183   }
1184   DrawInfo *di = icon_create_drawinfo(icon);
1185   icon->drawinfo = di;
1186   icon->drawinfo_free = UI_icons_free_drawinfo;
1187   return di;
1188 }
1189
1190 /* note!, returns unscaled by DPI */
1191 int UI_icon_get_width(int icon_id)
1192 {
1193   Icon *icon = NULL;
1194   DrawInfo *di = NULL;
1195
1196   icon = BKE_icon_get(icon_id);
1197
1198   if (icon == NULL) {
1199     if (G.debug & G_DEBUG) {
1200       printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
1201     }
1202     return 0;
1203   }
1204
1205   di = icon_ensure_drawinfo(icon);
1206   if (di) {
1207     return ICON_DEFAULT_WIDTH;
1208   }
1209
1210   return 0;
1211 }
1212
1213 int UI_icon_get_height(int icon_id)
1214 {
1215   Icon *icon = BKE_icon_get(icon_id);
1216   if (icon == NULL) {
1217     if (G.debug & G_DEBUG) {
1218       printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
1219     }
1220     return 0;
1221   }
1222
1223   DrawInfo *di = icon_ensure_drawinfo(icon);
1224   if (di) {
1225     return ICON_DEFAULT_HEIGHT;
1226   }
1227
1228   return 0;
1229 }
1230
1231 bool UI_icon_get_theme_color(int icon_id, uchar color[4])
1232 {
1233   Icon *icon = BKE_icon_get(icon_id);
1234   if (icon == NULL) {
1235     return false;
1236   }
1237
1238   DrawInfo *di = icon_ensure_drawinfo(icon);
1239   return UI_GetIconThemeColor4ubv(di->data.texture.theme_color, color);
1240 }
1241
1242 void UI_icons_init()
1243 {
1244 #ifndef WITH_HEADLESS
1245   init_iconfile_list(&iconfilelist);
1246   UI_icons_reload_internal_textures();
1247   init_internal_icons();
1248   init_brush_icons();
1249   init_event_icons();
1250 #endif
1251 }
1252
1253 /* Render size for preview images and icons
1254  */
1255 int UI_preview_render_size(enum eIconSizes size)
1256 {
1257   switch (size) {
1258     case ICON_SIZE_ICON:
1259       return ICON_RENDER_DEFAULT_HEIGHT;
1260     case ICON_SIZE_PREVIEW:
1261       return PREVIEW_RENDER_DEFAULT_HEIGHT;
1262     default:
1263       return 0;
1264   }
1265 }
1266
1267 /* Create rect for the icon
1268  */
1269 static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size)
1270 {
1271   uint render_size = UI_preview_render_size(size);
1272
1273   if (!prv_img) {
1274     if (G.debug & G_DEBUG) {
1275       printf("%s, error: requested preview image does not exist", __func__);
1276     }
1277   }
1278   else if (!prv_img->rect[size]) {
1279     prv_img->w[size] = render_size;
1280     prv_img->h[size] = render_size;
1281     prv_img->flag[size] |= PRV_CHANGED;
1282     prv_img->changed_timestamp[size] = 0;
1283     prv_img->rect[size] = MEM_callocN(render_size * render_size * sizeof(uint), "prv_rect");
1284   }
1285 }
1286
1287 static void ui_id_preview_image_render_size(
1288     const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job);
1289
1290 static void ui_studiolight_icon_job_exec(void *customdata,
1291                                          short *UNUSED(stop),
1292                                          short *UNUSED(do_update),
1293                                          float *UNUSED(progress))
1294 {
1295   Icon **tmp = (Icon **)customdata;
1296   Icon *icon = *tmp;
1297   DrawInfo *di = icon_ensure_drawinfo(icon);
1298   StudioLight *sl = icon->obj;
1299   BKE_studiolight_preview(di->data.buffer.image->rect, sl, icon->id_type);
1300 }
1301
1302 static void ui_studiolight_kill_icon_preview_job(wmWindowManager *wm, int icon_id)
1303 {
1304   Icon *icon = BKE_icon_get(icon_id);
1305   WM_jobs_kill_type(wm, icon, WM_JOB_TYPE_STUDIOLIGHT);
1306   icon->obj = NULL;
1307 }
1308
1309 static void ui_studiolight_free_function(StudioLight *sl, void *data)
1310 {
1311   wmWindowManager *wm = data;
1312
1313   /* Happens if job was canceled or already finished. */
1314   if (wm == NULL) {
1315     return;
1316   }
1317
1318   // get icons_id, get icons and kill wm jobs
1319   if (sl->icon_id_radiance) {
1320     ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_radiance);
1321   }
1322   if (sl->icon_id_irradiance) {
1323     ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_irradiance);
1324   }
1325   if (sl->icon_id_matcap) {
1326     ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_matcap);
1327   }
1328   if (sl->icon_id_matcap_flipped) {
1329     ui_studiolight_kill_icon_preview_job(wm, sl->icon_id_matcap_flipped);
1330   }
1331 }
1332
1333 static void ui_studiolight_icon_job_end(void *customdata)
1334 {
1335   Icon **tmp = (Icon **)customdata;
1336   Icon *icon = *tmp;
1337   StudioLight *sl = icon->obj;
1338   BKE_studiolight_set_free_function(sl, &ui_studiolight_free_function, NULL);
1339 }
1340
1341 void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big)
1342 {
1343   Icon *icon = BKE_icon_get(icon_id);
1344
1345   if (icon) {
1346     DrawInfo *di = icon_ensure_drawinfo(icon);
1347
1348     if (di) {
1349       switch (di->type) {
1350         case ICON_TYPE_PREVIEW: {
1351           ID *id = (icon->id_type != 0) ? icon->obj : NULL;
1352           PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj;
1353           /* Using jobs for screen previews crashes due to offscreen rendering.
1354            * XXX would be nicer if PreviewImage could store if it supports jobs */
1355           const bool use_jobs = !id || (GS(id->name) != ID_SCR);
1356
1357           if (prv) {
1358             const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON;
1359
1360             if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) {
1361               ui_id_preview_image_render_size(C, NULL, id, prv, size, use_jobs);
1362             }
1363           }
1364           break;
1365         }
1366         case ICON_TYPE_BUFFER: {
1367           if (icon->obj_type == ICON_DATA_STUDIOLIGHT) {
1368             if (di->data.buffer.image == NULL) {
1369               wmWindowManager *wm = CTX_wm_manager(C);
1370               StudioLight *sl = icon->obj;
1371               BKE_studiolight_set_free_function(sl, &ui_studiolight_free_function, wm);
1372               IconImage *img = MEM_mallocN(sizeof(IconImage), __func__);
1373
1374               img->w = STUDIOLIGHT_ICON_SIZE;
1375               img->h = STUDIOLIGHT_ICON_SIZE;
1376               size_t size = STUDIOLIGHT_ICON_SIZE * STUDIOLIGHT_ICON_SIZE * sizeof(uint);
1377               img->rect = MEM_mallocN(size, __func__);
1378               memset(img->rect, 0, size);
1379               di->data.buffer.image = img;
1380
1381               wmJob *wm_job = WM_jobs_get(
1382                   wm, CTX_wm_window(C), icon, "StudioLight Icon", 0, WM_JOB_TYPE_STUDIOLIGHT);
1383               Icon **tmp = MEM_callocN(sizeof(Icon *), __func__);
1384               *tmp = icon;
1385               WM_jobs_customdata_set(wm_job, tmp, MEM_freeN);
1386               WM_jobs_timer(wm_job, 0.01, 0, NC_WINDOW);
1387               WM_jobs_callbacks(
1388                   wm_job, ui_studiolight_icon_job_exec, NULL, NULL, ui_studiolight_icon_job_end);
1389               WM_jobs_start(CTX_wm_manager(C), wm_job);
1390             }
1391           }
1392           break;
1393         }
1394       }
1395     }
1396   }
1397 }
1398
1399 /* only called when icon has changed */
1400 /* only call with valid pointer from UI_icon_draw */
1401 static void icon_set_image(const bContext *C,
1402                            Scene *scene,
1403                            ID *id,
1404                            PreviewImage *prv_img,
1405                            enum eIconSizes size,
1406                            const bool use_job)
1407 {
1408   if (!prv_img) {
1409     if (G.debug & G_DEBUG) {
1410       printf("%s: no preview image for this ID: %s\n", __func__, id->name);
1411     }
1412     return;
1413   }
1414
1415   if (prv_img->flag[size] & PRV_USER_EDITED) {
1416     /* user-edited preview, do not auto-update! */
1417     return;
1418   }
1419
1420   icon_create_rect(prv_img, size);
1421
1422   if (use_job) {
1423     /* Job (background) version */
1424     ED_preview_icon_job(C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
1425   }
1426   else {
1427     if (!scene) {
1428       scene = CTX_data_scene(C);
1429     }
1430     /* Immediate version */
1431     ED_preview_icon_render(
1432         CTX_data_main(C), scene, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]);
1433   }
1434 }
1435
1436 PreviewImage *UI_icon_to_preview(int icon_id)
1437 {
1438   Icon *icon = BKE_icon_get(icon_id);
1439
1440   if (icon) {
1441     DrawInfo *di = (DrawInfo *)icon->drawinfo;
1442     if (di) {
1443       if (di->type == ICON_TYPE_PREVIEW) {
1444         PreviewImage *prv = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) :
1445                                                    icon->obj;
1446
1447         if (prv) {
1448           return BKE_previewimg_copy(prv);
1449         }
1450       }
1451       else if (di->data.buffer.image) {
1452         ImBuf *bbuf;
1453
1454         bbuf = IMB_ibImageFromMemory(di->data.buffer.image->datatoc_rect,
1455                                      di->data.buffer.image->datatoc_size,
1456                                      IB_rect,
1457                                      NULL,
1458                                      __func__);
1459         if (bbuf) {
1460           PreviewImage *prv = BKE_previewimg_create();
1461
1462           prv->rect[0] = bbuf->rect;
1463
1464           prv->w[0] = bbuf->x;
1465           prv->h[0] = bbuf->y;
1466
1467           bbuf->rect = NULL;
1468           IMB_freeImBuf(bbuf);
1469
1470           return prv;
1471         }
1472       }
1473     }
1474   }
1475   return NULL;
1476 }
1477
1478 static void icon_draw_rect(float x,
1479                            float y,
1480                            int w,
1481                            int h,
1482                            float UNUSED(aspect),
1483                            int rw,
1484                            int rh,
1485                            uint *rect,
1486                            float alpha,
1487                            const float desaturate)
1488 {
1489   ImBuf *ima = NULL;
1490   int draw_w = w;
1491   int draw_h = h;
1492   int draw_x = x;
1493   int draw_y = y;
1494
1495   /* sanity check */
1496   if (w <= 0 || h <= 0 || w > 2000 || h > 2000) {
1497     printf("%s: icons are %i x %i pixels?\n", __func__, w, h);
1498     BLI_assert(!"invalid icon size");
1499     return;
1500   }
1501   /* modulate color */
1502   float col[4] = {1.0f, 1.0f, 1.0f, alpha};
1503
1504   /* rect contains image in 'rendersize', we only scale if needed */
1505   if (rw != w || rh != h) {
1506     /* preserve aspect ratio and center */
1507     if (rw > rh) {
1508       draw_w = w;
1509       draw_h = (int)(((float)rh / (float)rw) * (float)w);
1510       draw_y += (h - draw_h) / 2;
1511     }
1512     else if (rw < rh) {
1513       draw_w = (int)(((float)rw / (float)rh) * (float)h);
1514       draw_h = h;
1515       draw_x += (w - draw_w) / 2;
1516     }
1517     /* if the image is squared, the draw_ initialization values are good */
1518
1519     /* first allocate imbuf for scaling and copy preview into it */
1520     ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
1521     memcpy(ima->rect, rect, rw * rh * sizeof(uint));
1522     IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
1523     rect = ima->rect;
1524   }
1525
1526   /* draw */
1527   eGPUBuiltinShader shader;
1528   if (desaturate != 0.0f) {
1529     shader = GPU_SHADER_2D_IMAGE_DESATURATE_COLOR;
1530   }
1531   else {
1532     shader = GPU_SHADER_2D_IMAGE_COLOR;
1533   }
1534   IMMDrawPixelsTexState state = immDrawPixelsTexSetup(shader);
1535
1536   if (shader == GPU_SHADER_2D_IMAGE_DESATURATE_COLOR) {
1537     immUniform1f("factor", desaturate);
1538   }
1539
1540   immDrawPixelsTex(&state,
1541                    draw_x,
1542                    draw_y,
1543                    draw_w,
1544                    draw_h,
1545                    GL_RGBA,
1546                    GL_UNSIGNED_BYTE,
1547                    GL_NEAREST,
1548                    rect,
1549                    1.0f,
1550                    1.0f,
1551                    col);
1552
1553   if (ima) {
1554     IMB_freeImBuf(ima);
1555   }
1556 }
1557
1558 /* High enough to make a difference, low enough so that
1559  * small draws are still efficient with the use of glUniform.
1560  * NOTE TODO: We could use UBO but we would need some triple
1561  * buffer system + persistent mapping for this to be more
1562  * efficient than simple glUniform calls. */
1563 #define ICON_DRAW_CACHE_SIZE 16
1564
1565 typedef struct IconDrawCall {
1566   rctf pos;
1567   rctf tex;
1568   float color[4];
1569 } IconDrawCall;
1570
1571 typedef struct IconTextureDrawCall {
1572   IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE];
1573   int calls; /* Number of calls batched together */
1574 } IconTextureDrawCall;
1575
1576 static struct {
1577   IconTextureDrawCall normal;
1578   IconTextureDrawCall border;
1579   bool enabled;
1580   float mat[4][4];
1581 } g_icon_draw_cache = {{{{{0}}}}};
1582
1583 void UI_icon_draw_cache_begin(void)
1584 {
1585   BLI_assert(g_icon_draw_cache.enabled == false);
1586   g_icon_draw_cache.enabled = true;
1587 }
1588
1589 static void icon_draw_cache_texture_flush_ex(GLuint texture,
1590                                              IconTextureDrawCall *texture_draw_calls)
1591 {
1592   if (texture_draw_calls->calls == 0) {
1593     return;
1594   }
1595
1596   glActiveTexture(GL_TEXTURE0);
1597   glBindTexture(GL_TEXTURE_2D, texture);
1598
1599   GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
1600   GPU_shader_bind(shader);
1601
1602   int img_loc = GPU_shader_get_uniform_ensure(shader, "image");
1603   int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]");
1604
1605   glUniform1i(img_loc, 0);
1606   glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache);
1607
1608   GPU_draw_primitive(GPU_PRIM_TRIS, 6 * texture_draw_calls->calls);
1609
1610   glBindTexture(GL_TEXTURE_2D, 0);
1611
1612   texture_draw_calls->calls = 0;
1613 }
1614
1615 static void icon_draw_cache_flush_ex(bool only_full_caches)
1616 {
1617   bool should_draw = false;
1618   if (only_full_caches) {
1619     should_draw = g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE ||
1620                   g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE;
1621   }
1622   else {
1623     should_draw = g_icon_draw_cache.normal.calls || g_icon_draw_cache.border.calls;
1624   }
1625
1626   if (should_draw) {
1627     /* We need to flush widget base first to ensure correct ordering. */
1628     UI_widgetbase_draw_cache_flush();
1629
1630     GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1631
1632     if (!only_full_caches || g_icon_draw_cache.normal.calls == ICON_DRAW_CACHE_SIZE) {
1633       icon_draw_cache_texture_flush_ex(icongltex.id[0], &g_icon_draw_cache.normal);
1634     }
1635
1636     if (!only_full_caches || g_icon_draw_cache.border.calls == ICON_DRAW_CACHE_SIZE) {
1637       icon_draw_cache_texture_flush_ex(icongltex.id[1], &g_icon_draw_cache.border);
1638     }
1639
1640     GPU_blend_set_func_separate(
1641         GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1642   }
1643 }
1644
1645 void UI_icon_draw_cache_end(void)
1646 {
1647   BLI_assert(g_icon_draw_cache.enabled == true);
1648   g_icon_draw_cache.enabled = false;
1649
1650   /* Don't change blend state if it's not needed. */
1651   if (g_icon_draw_cache.border.calls == 0 && g_icon_draw_cache.normal.calls == 0) {
1652     return;
1653   }
1654
1655   GPU_blend(true);
1656   icon_draw_cache_flush_ex(false);
1657   GPU_blend(false);
1658 }
1659
1660 static void icon_draw_texture_cached(float x,
1661                                      float y,
1662                                      float w,
1663                                      float h,
1664                                      int ix,
1665                                      int iy,
1666                                      int UNUSED(iw),
1667                                      int ih,
1668                                      float alpha,
1669                                      const float rgb[3],
1670                                      bool with_border)
1671 {
1672
1673   float mvp[4][4];
1674   GPU_matrix_model_view_projection_get(mvp);
1675
1676   IconTextureDrawCall *texture_call = with_border ? &g_icon_draw_cache.border :
1677                                                     &g_icon_draw_cache.normal;
1678
1679   IconDrawCall *call = &texture_call->drawcall_cache[texture_call->calls];
1680   texture_call->calls++;
1681
1682   /* Manual mat4*vec2 */
1683   call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0];
1684   call->pos.ymin = x * mvp[0][1] + y * mvp[1][1] + mvp[3][1];
1685   call->pos.xmax = call->pos.xmin + w * mvp[0][0] + h * mvp[1][0];
1686   call->pos.ymax = call->pos.ymin + w * mvp[0][1] + h * mvp[1][1];
1687
1688   call->tex.xmin = ix * icongltex.invw;
1689   call->tex.xmax = (ix + ih) * icongltex.invw;
1690   call->tex.ymin = iy * icongltex.invh;
1691   call->tex.ymax = (iy + ih) * icongltex.invh;
1692
1693   if (rgb) {
1694     copy_v4_fl4(call->color, rgb[0], rgb[1], rgb[2], alpha);
1695   }
1696   else {
1697     copy_v4_fl(call->color, alpha);
1698   }
1699
1700   if (texture_call->calls == ICON_DRAW_CACHE_SIZE) {
1701     icon_draw_cache_flush_ex(true);
1702   }
1703 }
1704
1705 static void icon_draw_texture(float x,
1706                               float y,
1707                               float w,
1708                               float h,
1709                               int ix,
1710                               int iy,
1711                               int iw,
1712                               int ih,
1713                               float alpha,
1714                               const float rgb[3],
1715                               bool with_border)
1716 {
1717   if (g_icon_draw_cache.enabled) {
1718     icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb, with_border);
1719     return;
1720   }
1721
1722   /* We need to flush widget base first to ensure correct ordering. */
1723   UI_widgetbase_draw_cache_flush();
1724
1725   GPU_blend_set_func(GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1726
1727   float x1, x2, y1, y2;
1728
1729   x1 = ix * icongltex.invw;
1730   x2 = (ix + ih) * icongltex.invw;
1731   y1 = iy * icongltex.invh;
1732   y2 = (iy + ih) * icongltex.invh;
1733
1734   glActiveTexture(GL_TEXTURE0);
1735   glBindTexture(GL_TEXTURE_2D, with_border ? icongltex.id[1] : icongltex.id[0]);
1736
1737   GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
1738   GPU_shader_bind(shader);
1739
1740   if (rgb) {
1741     glUniform4f(
1742         GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), rgb[0], rgb[1], rgb[2], alpha);
1743   }
1744   else {
1745     glUniform4f(
1746         GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), alpha, alpha, alpha, alpha);
1747   }
1748
1749   glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0);
1750   glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"), x1, y1, x2, y2);
1751   glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"), x, y, x + w, y + h);
1752
1753   GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4);
1754
1755   glBindTexture(GL_TEXTURE_2D, 0);
1756
1757   GPU_blend_set_func_separate(
1758       GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1759 }
1760
1761 /* Drawing size for preview images */
1762 static int get_draw_size(enum eIconSizes size)
1763 {
1764   switch (size) {
1765     case ICON_SIZE_ICON:
1766       return ICON_DEFAULT_HEIGHT;
1767     case ICON_SIZE_PREVIEW:
1768       return PREVIEW_DEFAULT_HEIGHT;
1769     default:
1770       return 0;
1771   }
1772 }
1773
1774 static void icon_draw_size(float x,
1775                            float y,
1776                            int icon_id,
1777                            float aspect,
1778                            float alpha,
1779                            enum eIconSizes size,
1780                            int draw_size,
1781                            const float desaturate,
1782                            const char mono_rgba[4],
1783                            const bool mono_border)
1784 {
1785   bTheme *btheme = UI_GetTheme();
1786   Icon *icon = NULL;
1787   IconImage *iimg;
1788   const float fdraw_size = (float)draw_size;
1789   int w, h;
1790
1791   icon = BKE_icon_get(icon_id);
1792   alpha *= btheme->tui.icon_alpha;
1793
1794   if (icon == NULL) {
1795     if (G.debug & G_DEBUG) {
1796       printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
1797     }
1798     return;
1799   }
1800
1801   /* scale width and height according to aspect */
1802   w = (int)(fdraw_size / aspect + 0.5f);
1803   h = (int)(fdraw_size / aspect + 0.5f);
1804
1805   DrawInfo *di = icon_ensure_drawinfo(icon);
1806
1807   /* We need to flush widget base first to ensure correct ordering. */
1808   UI_widgetbase_draw_cache_flush();
1809
1810   if (di->type == ICON_TYPE_VECTOR) {
1811     /* vector icons use the uiBlock transformation, they are not drawn
1812      * with untransformed coordinates like the other icons */
1813     di->data.vector.func((int)x, (int)y, w, h, 1.0f);
1814   }
1815   else if (di->type == ICON_TYPE_GEOM) {
1816 #ifdef USE_UI_TOOLBAR_HACK
1817     /* TODO(campbell): scale icons up for toolbar,
1818      * we need a way to detect larger buttons and do this automatic. */
1819     {
1820       float scale = (float)ICON_DEFAULT_HEIGHT_TOOLBAR / (float)ICON_DEFAULT_HEIGHT;
1821       y = (y + (h / 2)) - ((h * scale) / 2);
1822       w *= scale;
1823       h *= scale;
1824     }
1825 #endif
1826
1827     /* This could re-generate often if rendered at different sizes in the one interface.
1828      * TODO(campbell): support caching multiple sizes. */
1829     ImBuf *ibuf = di->data.geom.image_cache;
1830     if ((ibuf == NULL) || (ibuf->x != w) || (ibuf->y != h)) {
1831       if (ibuf) {
1832         IMB_freeImBuf(ibuf);
1833       }
1834       ibuf = BKE_icon_geom_rasterize(icon->obj, w, h);
1835       di->data.geom.image_cache = ibuf;
1836     }
1837
1838     GPU_blend_set_func_separate(
1839         GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1840     icon_draw_rect(x, y, w, h, aspect, w, h, ibuf->rect, alpha, desaturate);
1841     GPU_blend_set_func_separate(
1842         GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1843   }
1844   else if (di->type == ICON_TYPE_EVENT) {
1845     const short event_type = di->data.input.event_type;
1846     const short event_value = di->data.input.event_value;
1847     icon_draw_rect_input(x, y, w, h, alpha, event_type, event_value);
1848   }
1849   else if (di->type == ICON_TYPE_COLOR_TEXTURE) {
1850     /* texture image use premul alpha for correct scaling */
1851     icon_draw_texture(x,
1852                       y,
1853                       (float)w,
1854                       (float)h,
1855                       di->data.texture.x,
1856                       di->data.texture.y,
1857                       di->data.texture.w,
1858                       di->data.texture.h,
1859                       alpha,
1860                       NULL,
1861                       false);
1862   }
1863   else if (di->type == ICON_TYPE_MONO_TEXTURE) {
1864     /* Monochrome icon that uses text or theme color. */
1865     bool with_border = mono_border && (btheme->tui.icon_border_intensity > 0.0f);
1866     float color[4];
1867     if (mono_rgba) {
1868       rgba_uchar_to_float(color, (const uchar *)mono_rgba);
1869     }
1870     else {
1871       UI_GetThemeColor4fv(TH_TEXT, color);
1872     }
1873
1874     mul_v4_fl(color, alpha);
1875
1876     float border_outset = 0.0;
1877     unsigned int border_texel = 0;
1878 #ifndef WITH_HEADLESS
1879     if (with_border) {
1880       const float scale = (float)ICON_GRID_W / (float)ICON_DEFAULT_WIDTH;
1881       border_texel = ICON_MONO_BORDER_OUTSET;
1882       border_outset = ICON_MONO_BORDER_OUTSET / (scale * aspect);
1883     }
1884 #endif
1885     icon_draw_texture(x - border_outset,
1886                       y - border_outset,
1887                       (float)w + 2 * border_outset,
1888                       (float)h + 2 * border_outset,
1889                       di->data.texture.x - border_texel,
1890                       di->data.texture.y - border_texel,
1891                       di->data.texture.w + 2 * border_texel,
1892                       di->data.texture.h + 2 * border_texel,
1893                       color[3],
1894                       color,
1895                       with_border);
1896   }
1897
1898   else if (di->type == ICON_TYPE_BUFFER) {
1899     /* it is a builtin icon */
1900     iimg = di->data.buffer.image;
1901 #ifndef WITH_HEADLESS
1902     icon_verify_datatoc(iimg);
1903 #endif
1904     if (!iimg->rect) {
1905       /* something has gone wrong! */
1906       return;
1907     }
1908
1909     icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, desaturate);
1910   }
1911   else if (di->type == ICON_TYPE_PREVIEW) {
1912     PreviewImage *pi = (icon->id_type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) :
1913                                               icon->obj;
1914
1915     if (pi) {
1916       /* no create icon on this level in code */
1917       if (!pi->rect[size]) {
1918         /* Something has gone wrong! */
1919         return;
1920       }
1921
1922       /* Preview images use premultiplied alpha. */
1923       GPU_blend_set_func_separate(
1924           GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1925       icon_draw_rect(
1926           x, y, w, h, aspect, pi->w[size], pi->h[size], pi->rect[size], alpha, desaturate);
1927       GPU_blend_set_func_separate(
1928           GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
1929     }
1930   }
1931   else if (di->type == ICON_TYPE_GPLAYER) {
1932     BLI_assert(icon->obj != NULL);
1933
1934     /* Just draw a colored rect - Like for vicon_colorset_draw() */
1935 #ifndef WITH_HEADLESS
1936     vicon_gplayer_color_draw(icon, (int)x, (int)y, w, h);
1937 #endif
1938   }
1939 }
1940
1941 static void ui_id_preview_image_render_size(
1942     const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job)
1943 {
1944   /* changed only ever set by dynamic icons */
1945   if (((pi->flag[size] & PRV_CHANGED) || !pi->rect[size])) {
1946     /* create the rect if necessary */
1947     icon_set_image(C, scene, id, pi, size, use_job);
1948
1949     pi->flag[size] &= ~PRV_CHANGED;
1950   }
1951 }
1952
1953 void UI_id_icon_render(const bContext *C, Scene *scene, ID *id, const bool big, const bool use_job)
1954 {
1955   PreviewImage *pi = BKE_previewimg_id_ensure(id);
1956
1957   if (pi) {
1958     if (big) {
1959       /* bigger preview size */
1960       ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_PREVIEW, use_job);
1961     }
1962     else {
1963       /* icon size */
1964       ui_id_preview_image_render_size(C, scene, id, pi, ICON_SIZE_ICON, use_job);
1965     }
1966   }
1967 }
1968
1969 static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs)
1970 {
1971   PreviewImage *pi = BKE_previewimg_id_ensure(id);
1972   enum eIconSizes i;
1973
1974   if (!pi) {
1975     return;
1976   }
1977
1978   for (i = 0; i < NUM_ICON_SIZES; i++) {
1979     /* check if rect needs to be created; changed
1980      * only set by dynamic icons */
1981     if (((pi->flag[i] & PRV_CHANGED) || !pi->rect[i])) {
1982       icon_set_image(C, NULL, id, pi, i, use_jobs);
1983       pi->flag[i] &= ~PRV_CHANGED;
1984     }
1985   }
1986 }
1987
1988 static int ui_id_brush_get_icon(const bContext *C, ID *id)
1989 {
1990   Brush *br = (Brush *)id;
1991
1992   if (br->flag & BRUSH_CUSTOM_ICON) {
1993     BKE_icon_id_ensure(id);
1994     ui_id_icon_render(C, id, true);
1995   }
1996   else {
1997     Object *ob = CTX_data_active_object(C);
1998     const EnumPropertyItem *items = NULL;
1999     ePaintMode paint_mode = PAINT_MODE_INVALID;
2000     ScrArea *sa = CTX_wm_area(C);
2001     char space_type = sa->spacetype;
2002     /* Fallback to 3D view. */
2003     if (space_type == SPACE_PROPERTIES) {
2004       space_type = SPACE_VIEW3D;
2005     }
2006
2007     /* XXX: this is not nice, should probably make brushes
2008      * be strictly in one paint mode only to avoid
2009      * checking various context stuff here */
2010
2011     if ((space_type == SPACE_VIEW3D) && ob) {
2012       if (ob->mode & OB_MODE_SCULPT) {
2013         paint_mode = PAINT_MODE_SCULPT;
2014       }
2015       else if (ob->mode & OB_MODE_VERTEX_PAINT) {
2016         paint_mode = PAINT_MODE_VERTEX;
2017       }
2018       else if (ob->mode & OB_MODE_WEIGHT_PAINT) {
2019         paint_mode = PAINT_MODE_WEIGHT;
2020       }
2021       else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
2022         paint_mode = PAINT_MODE_TEXTURE_3D;
2023       }
2024     }
2025     else if (space_type == SPACE_IMAGE) {
2026       if (sa->spacetype == space_type) {
2027         const SpaceImage *sima = sa->spacedata.first;
2028         if (sima->mode == SI_MODE_PAINT) {
2029           paint_mode = PAINT_MODE_TEXTURE_2D;
2030         }
2031       }
2032     }
2033
2034     /* reset the icon */
2035     if ((ob != NULL) && (ob->mode & OB_MODE_PAINT_GPENCIL) && (br->gpencil_settings != NULL)) {
2036       switch (br->gpencil_settings->icon_id) {
2037         case GP_BRUSH_ICON_PENCIL:
2038           br->id.icon_id = ICON_GPBRUSH_PENCIL;
2039           break;
2040         case GP_BRUSH_ICON_PEN:
2041           br->id.icon_id = ICON_GPBRUSH_PEN;
2042           break;
2043         case GP_BRUSH_ICON_INK:
2044           br->id.icon_id = ICON_GPBRUSH_INK;
2045           break;
2046         case GP_BRUSH_ICON_INKNOISE:
2047           br->id.icon_id = ICON_GPBRUSH_INKNOISE;
2048           break;
2049         case GP_BRUSH_ICON_BLOCK:
2050           br->id.icon_id = ICON_GPBRUSH_BLOCK;
2051           break;
2052         case GP_BRUSH_ICON_MARKER:
2053           br->id.icon_id = ICON_GPBRUSH_MARKER;
2054           break;
2055         case GP_BRUSH_ICON_FILL:
2056           br->id.icon_id = ICON_GPBRUSH_FILL;
2057           break;
2058         case GP_BRUSH_ICON_ERASE_SOFT:
2059           br->id.icon_id = ICON_GPBRUSH_ERASE_SOFT;
2060           break;
2061         case GP_BRUSH_ICON_ERASE_HARD:
2062           br->id.icon_id = ICON_GPBRUSH_ERASE_HARD;
2063           break;
2064         case GP_BRUSH_ICON_ERASE_STROKE:
2065           br->id.icon_id = ICON_GPBRUSH_ERASE_STROKE;
2066           break;
2067         default:
2068           br->id.icon_id = ICON_GPBRUSH_PEN;
2069           break;
2070       }
2071       return id->icon_id;
2072     }
2073     else if (paint_mode != PAINT_MODE_INVALID) {
2074       items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
2075       const uint tool_offset = BKE_paint_get_brush_tool_offset_from_paintmode(paint_mode);
2076       const int tool_type = *(char *)POINTER_OFFSET(br, tool_offset);
2077       if (!items || !RNA_enum_icon_from_value(items, tool_type, &id->icon_id)) {
2078         id->icon_id = 0;
2079       }
2080     }
2081     else {
2082       id->icon_id = 0;
2083     }
2084   }
2085
2086   return id->icon_id;
2087 }
2088
2089 static int ui_id_screen_get_icon(const bContext *C, ID *id)
2090 {
2091   BKE_icon_id_ensure(id);
2092   /* Don't use jobs here, offscreen rendering doesn't like this and crashes. */
2093   ui_id_icon_render(C, id, false);
2094
2095   return id->icon_id;
2096 }
2097
2098 int ui_id_icon_get(const bContext *C, ID *id, const bool big)
2099 {
2100   int iconid = 0;
2101
2102   /* icon */
2103   switch (GS(id->name)) {
2104     case ID_BR:
2105       iconid = ui_id_brush_get_icon(C, id);
2106       break;
2107     case ID_MA: /* fall through */
2108     case ID_TE: /* fall through */
2109     case ID_IM: /* fall through */
2110     case ID_WO: /* fall through */
2111     case ID_LA: /* fall through */
2112       iconid = BKE_icon_id_ensure(id);
2113       /* checks if not exists, or changed */
2114       UI_id_icon_render(C, NULL, id, big, true);
2115       break;
2116     case ID_SCR:
2117       iconid = ui_id_screen_get_icon(C, id);
2118       break;
2119     default:
2120       break;
2121   }
2122
2123   return iconid;
2124 }
2125
2126 int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, const bool big)
2127 {
2128   ID *id = NULL;
2129
2130   if (!ptr->data) {
2131     return rnaicon;
2132   }
2133
2134   /* try ID, material, texture or dynapaint slot */
2135   if (RNA_struct_is_ID(ptr->type)) {
2136     id = ptr->id.data;
2137   }
2138   else if (RNA_struct_is_a(ptr->type, &RNA_MaterialSlot)) {
2139     id = RNA_pointer_get(ptr, "material").data;
2140   }
2141   else if (RNA_struct_is_a(ptr->type, &RNA_TextureSlot)) {
2142     id = RNA_pointer_get(ptr, "texture").data;
2143   }
2144   else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) {
2145     DynamicPaintSurface *surface = ptr->data;
2146
2147     if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) {
2148       return ICON_SHADING_TEXTURE;
2149     }
2150     else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) {
2151       return ICON_OUTLINER_DATA_MESH;
2152     }
2153     else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {
2154       return ICON_FILE_IMAGE;
2155     }
2156   }
2157   else if (RNA_struct_is_a(ptr->type, &RNA_StudioLight)) {
2158     StudioLight *sl = ptr->data;
2159     switch (sl->flag & STUDIOLIGHT_FLAG_ORIENTATIONS) {
2160       case STUDIOLIGHT_TYPE_STUDIO:
2161         return sl->icon_id_irradiance;
2162       case STUDIOLIGHT_TYPE_WORLD:
2163       default:
2164         return sl->icon_id_radiance;
2165       case STUDIOLIGHT_TYPE_MATCAP:
2166         return sl->icon_id_matcap;
2167     }
2168   }
2169
2170   /* get icon from ID */
2171   if (id) {
2172     int icon = ui_id_icon_get(C, id, big);
2173
2174     return icon ? icon : rnaicon;
2175   }
2176
2177   return rnaicon;
2178 }
2179
2180 int UI_idcode_icon_get(const int idcode)
2181 {
2182   switch (idcode) {
2183     case ID_AC:
2184       return ICON_ACTION;
2185     case ID_AR:
2186       return ICON_ARMATURE_DATA;
2187     case ID_BR:
2188       return ICON_BRUSH_DATA;
2189     case ID_CA:
2190       return ICON_CAMERA_DATA;
2191     case ID_CF:
2192       return ICON_FILE;
2193     case ID_CU:
2194       return ICON_CURVE_DATA;
2195     case ID_GD:
2196       return ICON_GREASEPENCIL;
2197     case ID_GR:
2198       return ICON_GROUP;
2199     case ID_IM:
2200       return ICON_IMAGE_DATA;
2201     case ID_LA:
2202       return ICON_LIGHT_DATA;
2203     case ID_LS:
2204       return ICON_LINE_DATA;
2205     case ID_LT:
2206       return ICON_LATTICE_DATA;
2207     case ID_MA:
2208       return ICON_MATERIAL_DATA;
2209     case ID_MB:
2210       return ICON_META_DATA;
2211     case ID_MC:
2212       return ICON_TRACKER;
2213     case ID_ME:
2214       return ICON_MESH_DATA;
2215     case ID_MSK:
2216       return ICON_MOD_MASK; /* TODO! this would need its own icon! */
2217     case ID_NT:
2218       return ICON_NODETREE;
2219     case ID_OB:
2220       return ICON_OBJECT_DATA;
2221     case ID_PA:
2222       return ICON_PARTICLE_DATA;
2223     case ID_PAL:
2224       return ICON_COLOR; /* TODO! this would need its own icon! */
2225     case ID_PC:
2226       return ICON_CURVE_BEZCURVE; /* TODO! this would need its own icon! */
2227     case ID_LP:
2228       return ICON_OUTLINER_DATA_LIGHTPROBE;
2229     case ID_SCE:
2230       return ICON_SCENE_DATA;
2231     case ID_SPK:
2232       return ICON_SPEAKER;
2233     case ID_SO:
2234       return ICON_SOUND;
2235     case ID_TE:
2236       return ICON_TEXTURE_DATA;
2237     case ID_TXT:
2238       return ICON_TEXT;
2239     case ID_VF:
2240       return ICON_FONT_DATA;
2241     case ID_WO:
2242       return ICON_WORLD_DATA;
2243     default:
2244       return ICON_NONE;
2245   }
2246 }
2247
2248 /* draws icon with dpi scale factor */
2249 void UI_icon_draw(float x, float y, int icon_id)
2250 {
2251   UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, NULL, false);
2252 }
2253
2254 void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha)
2255 {
2256   UI_icon_draw_ex(x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, NULL, false);
2257 }
2258
2259 void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size)
2260 {
2261   icon_draw_size(x, y, icon_id, aspect, alpha, ICON_SIZE_PREVIEW, size, false, NULL, false);
2262 }
2263
2264 void UI_icon_draw_ex(float x,
2265                      float y,
2266                      int icon_id,
2267                      float aspect,
2268                      float alpha,
2269                      float desaturate,
2270                      const char mono_color[4],
2271                      const bool mono_border)
2272 {
2273   int draw_size = get_draw_size(ICON_SIZE_ICON);
2274   icon_draw_size(x,
2275                  y,
2276                  icon_id,
2277                  aspect,
2278                  alpha,
2279                  ICON_SIZE_ICON,
2280                  draw_size,
2281                  desaturate,
2282                  mono_color,
2283                  mono_border);
2284 }