Blender  V3.3
icons.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2006-2007 Blender Foundation. All rights reserved. */
3 
8 #include <cmath>
9 #include <cstdlib>
10 #include <cstring>
11 #include <mutex>
12 
13 #include "CLG_log.h"
14 
15 #include "MEM_guardedalloc.h"
16 
17 #include "DNA_brush_types.h"
18 #include "DNA_collection_types.h"
19 #include "DNA_gpencil_types.h"
20 #include "DNA_light_types.h"
21 #include "DNA_material_types.h"
22 #include "DNA_node_types.h"
23 #include "DNA_object_types.h"
24 #include "DNA_scene_types.h"
25 #include "DNA_screen_types.h"
26 #include "DNA_texture_types.h"
27 #include "DNA_world_types.h"
28 
29 #include "BLI_fileops.h"
30 #include "BLI_ghash.h"
31 #include "BLI_linklist_lockfree.h"
32 #include "BLI_string.h"
33 #include "BLI_threads.h"
34 #include "BLI_utildefines.h"
35 #include "BLI_vector.hh"
36 
37 #include "BKE_global.h" /* only for G.background test */
38 #include "BKE_icons.h"
39 #include "BKE_studiolight.h"
40 
41 #include "BLI_sys_types.h" /* for intptr_t support */
42 
43 #include "GPU_texture.h"
44 
45 #include "IMB_imbuf.h"
46 #include "IMB_imbuf_types.h"
47 #include "IMB_thumbs.h"
48 
49 #include "BLO_read_write.h"
50 
51 #include "atomic_ops.h"
52 
57 enum {
58  ICON_FLAG_MANAGED = (1 << 0),
59 };
60 
61 /* GLOBALS */
62 
63 static CLG_LogRef LOG = {"bke.icons"};
64 
65 /* Protected by gIconMutex. */
66 static GHash *gIcons = nullptr;
67 
68 /* Protected by gIconMutex. */
69 static int gNextIconId = 1;
70 
71 /* Protected by gIconMutex. */
72 static int gFirstIconId = 1;
73 
75 
76 /* Not mutex-protected! */
77 static GHash *gCachedPreviews = nullptr;
78 
79 /* Queue of icons for deferred deletion. */
82  int icon_id;
83 };
84 /* Protected by gIconMutex. */
86 
87 static void icon_free(void *val)
88 {
89  Icon *icon = (Icon *)val;
90 
91  if (icon) {
92  if (icon->obj_type == ICON_DATA_GEOM) {
93  struct Icon_Geom *obj = (struct Icon_Geom *)icon->obj;
94  if (obj->mem) {
95  /* coords & colors are part of this memory. */
96  MEM_freeN((void *)obj->mem);
97  }
98  else {
99  MEM_freeN((void *)obj->coords);
100  MEM_freeN((void *)obj->colors);
101  }
102  MEM_freeN(icon->obj);
103  }
104 
105  if (icon->drawinfo_free) {
106  icon->drawinfo_free(icon->drawinfo);
107  }
108  else if (icon->drawinfo) {
109  MEM_freeN(icon->drawinfo);
110  }
111  MEM_freeN(icon);
112  }
113 }
114 
115 static void icon_free_data(int icon_id, Icon *icon)
116 {
117  switch (icon->obj_type) {
118  case ICON_DATA_ID:
119  ((ID *)(icon->obj))->icon_id = 0;
120  break;
121  case ICON_DATA_IMBUF: {
122  ImBuf *imbuf = (ImBuf *)icon->obj;
123  if (imbuf) {
124  IMB_freeImBuf(imbuf);
125  }
126  break;
127  }
128  case ICON_DATA_PREVIEW:
129  ((PreviewImage *)(icon->obj))->icon_id = 0;
130  break;
131  case ICON_DATA_GPLAYER:
132  ((bGPDlayer *)(icon->obj))->runtime.icon_id = 0;
133  break;
134  case ICON_DATA_GEOM:
135  ((struct Icon_Geom *)(icon->obj))->icon_id = 0;
136  break;
137  case ICON_DATA_STUDIOLIGHT: {
138  StudioLight *sl = (StudioLight *)icon->obj;
139  if (sl != nullptr) {
141  }
142  break;
143  }
144  default:
146  }
147 }
148 
150 {
151  std::scoped_lock lock(gIconMutex);
153 }
154 
155 /* create an id for a new icon and make sure that ids from deleted icons get reused
156  * after the integer number range is used up */
157 static int get_next_free_id()
158 {
159  std::scoped_lock lock(gIconMutex);
160  int startId = gFirstIconId;
161 
162  /* if we haven't used up the int number range, we just return the next int */
163  if (gNextIconId >= gFirstIconId) {
164  int next_id = gNextIconId++;
165  return next_id;
166  }
167 
168  /* Now we try to find the smallest icon id not stored in the gIcons hash.
169  * Don't use icon_ghash_lookup here, it would lock recursively (dead-lock). */
170  while (BLI_ghash_lookup(gIcons, POINTER_FROM_INT(startId)) && startId >= gFirstIconId) {
171  startId++;
172  }
173 
174  /* if we found a suitable one that isn't used yet, return it */
175  if (startId >= gFirstIconId) {
176  return startId;
177  }
178 
179  /* fail */
180  return 0;
181 }
182 
183 void BKE_icons_init(int first_dyn_id)
184 {
186 
187  gNextIconId = first_dyn_id;
188  gFirstIconId = first_dyn_id;
189 
190  if (!gIcons) {
191  gIcons = BLI_ghash_int_new(__func__);
193  }
194 
195  if (!gCachedPreviews) {
197  }
198 }
199 
201 {
203 
204  if (gIcons) {
205  BLI_ghash_free(gIcons, nullptr, icon_free);
206  gIcons = nullptr;
207  }
208 
209  if (gCachedPreviews) {
211  gCachedPreviews = nullptr;
212  }
213 
215 }
216 
218 {
219  std::scoped_lock lock(gIconMutex);
220 
223  node != nullptr;
224  node = node->next) {
225  BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), nullptr, icon_free);
226  }
228 }
229 
230 static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
231 {
232  PreviewImage *prv_img = (PreviewImage *)MEM_mallocN(sizeof(PreviewImage) + deferred_data_size,
233  "img_prv");
234  memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
235 
236  if (deferred_data_size) {
237  prv_img->tag |= PRV_TAG_DEFFERED;
238  }
239 
240  for (int i = 0; i < NUM_ICON_SIZES; i++) {
241  prv_img->flag[i] |= PRV_CHANGED;
242  prv_img->changed_timestamp[i] = 0;
243  }
244  return prv_img;
245 }
246 
247 static PreviewImage *previewimg_deferred_create(const char *filepath, int source)
248 {
249  /* We pack needed data for lazy loading (source type, in a single char, and filepath). */
250  const size_t deferred_data_size = strlen(filepath) + 2;
251  char *deferred_data;
252 
253  PreviewImage *prv = previewimg_create_ex(deferred_data_size);
254  deferred_data = (char *)PRV_DEFERRED_DATA(prv);
255  deferred_data[0] = source;
256  memcpy(&deferred_data[1], filepath, deferred_data_size - 1);
257 
258  return prv;
259 }
260 
262 {
263  return previewimg_create_ex(0);
264 }
265 
266 void BKE_previewimg_freefunc(void *link)
267 {
268  PreviewImage *prv = (PreviewImage *)link;
269  if (prv) {
270  for (int i = 0; i < NUM_ICON_SIZES; i++) {
271  if (prv->rect[i]) {
272  MEM_freeN(prv->rect[i]);
273  }
274  if (prv->gputexture[i]) {
275  GPU_texture_free(prv->gputexture[i]);
276  }
277  }
278 
279  MEM_freeN(prv);
280  }
281 }
282 
284 {
285  if (prv && (*prv)) {
287  *prv = nullptr;
288  }
289 }
290 
292 {
293  MEM_SAFE_FREE(prv->rect[size]);
294  if (prv->gputexture[size]) {
296  }
297  prv->h[size] = prv->w[size] = 0;
298  prv->flag[size] |= PRV_CHANGED;
299  prv->flag[size] &= ~PRV_USER_EDITED;
300  prv->changed_timestamp[size] = 0;
301 }
302 
304 {
305  for (int i = 0; i < NUM_ICON_SIZES; i++) {
307  }
308 }
309 
311 {
312  PreviewImage *prv_img = nullptr;
313 
314  if (prv) {
315  prv_img = (PreviewImage *)MEM_dupallocN(prv);
316  for (int i = 0; i < NUM_ICON_SIZES; i++) {
317  if (prv->rect[i]) {
318  prv_img->rect[i] = (uint *)MEM_dupallocN(prv->rect[i]);
319  }
320  prv_img->gputexture[i] = nullptr;
321  }
322  }
323  return prv_img;
324 }
325 
326 void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
327 {
328  PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
329  PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
330 
331  if (old_prv_p && *old_prv_p) {
332  BLI_assert(new_prv_p != nullptr && ELEM(*new_prv_p, nullptr, *old_prv_p));
333  // const int new_icon_id = get_next_free_id();
334 
335  // if (new_icon_id == 0) {
336  // return; /* Failure. */
337  // }
338  *new_prv_p = BKE_previewimg_copy(*old_prv_p);
339  new_id->icon_id = (*new_prv_p)->icon_id = 0;
340  }
341 }
342 
344 {
345  switch (GS(id->name)) {
346 #define ID_PRV_CASE(id_code, id_struct) \
347  case id_code: { \
348  return &((id_struct *)id)->preview; \
349  } \
350  ((void)0)
363 #undef ID_PRV_CASE
364  default:
365  break;
366  }
367 
368  return nullptr;
369 }
370 
372 {
374  return prv_p ? *prv_p : nullptr;
375 }
376 
378 {
380  if (prv_p) {
381  BKE_previewimg_free(prv_p);
382  }
383 }
384 
386 {
388 
389  if (prv_p) {
390  if (*prv_p == nullptr) {
391  *prv_p = BKE_previewimg_create();
392  }
393  return *prv_p;
394  }
395 
396  return nullptr;
397 }
398 
399 void BKE_previewimg_id_custom_set(ID *id, const char *filepath)
400 {
402 
403  /* Thumbnail previews must use the deferred pipeline. But we force them to be immediately
404  * generated here still. */
405 
406  if (*prv) {
408  }
410 
411  /* Can't lazy-render the preview on access. ID previews are saved to files and we want them to be
412  * there in time. Not only if something happened to have accessed it meanwhile. */
413  for (int i = 0; i < NUM_ICON_SIZES; i++) {
414  BKE_previewimg_ensure(*prv, i);
415  /* Prevent auto-updates. */
416  (*prv)->flag[i] |= PRV_USER_EDITED;
417  }
418 }
419 
421 {
422  return ELEM(GS(id->name), ID_OB, ID_MA, ID_TE, ID_LA, ID_WO, ID_IM, ID_BR, ID_GR);
423 }
424 
426 {
427  if (prv) {
428  if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
429  /* We cannot delete the preview while it is being loaded in another thread... */
431  return;
432  }
433  if (prv->icon_id) {
434  BKE_icon_delete(prv->icon_id);
435  }
437  }
438 }
439 
441 {
444 }
445 
447 {
449 
450  PreviewImage *prv = nullptr;
451  void **key_p, **prv_p;
452 
453  if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
454  *key_p = BLI_strdup(name);
455  *prv_p = BKE_previewimg_create();
456  }
457  prv = *(PreviewImage **)prv_p;
458  BLI_assert(prv);
459 
460  return prv;
461 }
462 
464  const char *filepath,
465  const int source,
466  bool force_update)
467 {
469 
470  PreviewImage *prv = nullptr;
471  void **prv_p;
472 
473  prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
474 
475  if (prv_p) {
476  prv = *(PreviewImage **)prv_p;
477  BLI_assert(prv);
478  }
479 
480  if (prv && force_update) {
481  const char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
482  if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], filepath)) {
483  /* If same filepath, no need to re-allocate preview, just clear it up. */
485  }
486  else {
487  BKE_previewimg_free(&prv);
488  }
489  }
490 
491  if (!prv) {
492  prv = previewimg_deferred_create(filepath, source);
493  force_update = true;
494  }
495 
496  if (force_update) {
497  if (prv_p) {
498  *prv_p = prv;
499  }
500  else {
502  }
503  }
504 
505  return prv;
506 }
507 
508 void BKE_previewimg_cached_release(const char *name)
509 {
511 
513 
515 }
516 
518 {
519  if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
520  const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
521  const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
522 
523  if (do_icon || do_preview) {
524  ImBuf *thumb;
525  char *prv_deferred_data = (char *)PRV_DEFERRED_DATA(prv);
526  int source = prv_deferred_data[0];
527  char *filepath = &prv_deferred_data[1];
528  int icon_w, icon_h;
529 
530  thumb = IMB_thumb_manage(filepath, THB_LARGE, (ThumbSource)source);
531 
532  if (thumb) {
533  /* PreviewImage assumes premultiplied alhpa... */
534  IMB_premultiply_alpha(thumb);
535 
536  if (do_preview) {
537  prv->w[ICON_SIZE_PREVIEW] = thumb->x;
538  prv->h[ICON_SIZE_PREVIEW] = thumb->y;
539  prv->rect[ICON_SIZE_PREVIEW] = (uint *)MEM_dupallocN(thumb->rect);
541  }
542  if (do_icon) {
543  if (thumb->x > thumb->y) {
545  icon_h = (thumb->y * icon_w) / thumb->x + 1;
546  }
547  else if (thumb->x < thumb->y) {
549  icon_w = (thumb->x * icon_h) / thumb->y + 1;
550  }
551  else {
552  icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
553  }
554 
555  IMB_scaleImBuf(thumb, icon_w, icon_h);
556  prv->w[ICON_SIZE_ICON] = icon_w;
557  prv->h[ICON_SIZE_ICON] = icon_h;
558  prv->rect[ICON_SIZE_ICON] = (uint *)MEM_dupallocN(thumb->rect);
560  }
561  IMB_freeImBuf(thumb);
562  }
563  }
564  }
565 }
566 
568 {
569  const unsigned int w = prv->w[size];
570  const unsigned int h = prv->h[size];
571  const unsigned int *rect = prv->rect[size];
572 
573  ImBuf *ima = nullptr;
574 
575  if (w > 0 && h > 0 && rect) {
576  /* first allocate imbuf for copying preview into it */
577  ima = IMB_allocImBuf(w, h, 32, IB_rect);
578  memcpy(ima->rect, rect, w * h * sizeof(*ima->rect));
579  }
580 
581  return ima;
582 }
583 
585 {
586  /* Previews may be calculated on a thread. */
588 }
589 
590 bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size)
591 {
592  return (prv->flag[size] & PRV_RENDERING) == 0;
593 }
594 
596 {
597  /* Note we write previews also for undo steps. It takes up some memory,
598  * but not doing so would causes all previews to be re-rendered after
599  * undo which is too expensive. */
600 
601  if (prv == nullptr) {
602  return;
603  }
604 
605  PreviewImage prv_copy = *prv;
606  BLO_write_struct_at_address(writer, PreviewImage, prv, &prv_copy);
607  if (prv_copy.rect[0]) {
608  BLO_write_uint32_array(writer, prv_copy.w[0] * prv_copy.h[0], prv_copy.rect[0]);
609  }
610  if (prv_copy.rect[1]) {
611  BLO_write_uint32_array(writer, prv_copy.w[1] * prv_copy.h[1], prv_copy.rect[1]);
612  }
613 }
614 
616 {
617  if (prv == nullptr) {
618  return;
619  }
620 
621  for (int i = 0; i < NUM_ICON_SIZES; i++) {
622  if (prv->rect[i]) {
623  BLO_read_data_address(reader, &prv->rect[i]);
624  }
625  prv->gputexture[i] = nullptr;
626 
627  /* PRV_RENDERING is a runtime only flag currently, but don't mess with it on undo! It gets
628  * special handling in #memfile_undosys_restart_unfinished_id_previews() then. */
629  if (!BLO_read_data_is_undo(reader)) {
630  prv->flag[i] &= ~PRV_RENDERING;
631  }
632  }
633  prv->icon_id = 0;
634  prv->tag = 0;
635 }
636 
637 void BKE_icon_changed(const int icon_id)
638 {
639  Icon *icon = nullptr;
640 
641  if (!icon_id || G.background) {
642  return;
643  }
644 
645  icon = icon_ghash_lookup(icon_id);
646 
647  if (icon) {
648  /* We *only* expect ID-tied icons here, not non-ID icon/preview! */
649  BLI_assert(icon->id_type != 0);
650  BLI_assert(icon->obj_type == ICON_DATA_ID);
651 
652  /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure()
653  * here, we only want to ensure *existing* preview images are properly tagged as
654  * changed/invalid, that's all. */
655  PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj);
656 
657  /* If we have previews, they all are now invalid changed. */
658  if (p_prv && *p_prv) {
659  for (int i = 0; i < NUM_ICON_SIZES; i++) {
660  (*p_prv)->flag[i] |= PRV_CHANGED;
661  (*p_prv)->changed_timestamp[i]++;
662  }
663  }
664  }
665 }
666 
667 static Icon *icon_create(int icon_id, int obj_type, void *obj)
668 {
669  Icon *new_icon = (Icon *)MEM_mallocN(sizeof(Icon), __func__);
670 
671  new_icon->obj_type = obj_type;
672  new_icon->obj = obj;
673  new_icon->id_type = 0;
674  new_icon->flag = 0;
675 
676  /* next two lines make sure image gets created */
677  new_icon->drawinfo = nullptr;
678  new_icon->drawinfo_free = nullptr;
679 
680  {
681  std::scoped_lock lock(gIconMutex);
683  }
684 
685  return new_icon;
686 }
687 
688 static int icon_id_ensure_create_icon(struct ID *id)
689 {
691 
692  Icon *icon = icon_create(id->icon_id, ICON_DATA_ID, id);
693  icon->id_type = GS(id->name);
694  icon->flag = ICON_FLAG_MANAGED;
695 
696  return id->icon_id;
697 }
698 
699 int BKE_icon_id_ensure(struct ID *id)
700 {
701  /* Never handle icons in non-main thread! */
703 
704  if (!id || G.background) {
705  return 0;
706  }
707 
708  if (id->icon_id) {
709  return id->icon_id;
710  }
711 
712  id->icon_id = get_next_free_id();
713 
714  if (!id->icon_id) {
715  CLOG_ERROR(&LOG, "not enough IDs");
716  return 0;
717  }
718 
719  /* Ensure we synchronize ID icon_id with its previewimage if it has one. */
721  if (p_prv && *p_prv) {
722  BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id));
723  (*p_prv)->icon_id = id->icon_id;
724  }
725 
726  return icon_id_ensure_create_icon(id);
727 }
728 
730 {
732 
733  /* NOTE: The color previews for GP Layers don't really need
734  * to be "rendered" to image per se (as it will just be a plain
735  * colored rectangle), we need to define icon data here so that
736  * we can store a pointer to the layer data in icon->obj.
737  */
738  Icon *icon = icon_create(gpl->runtime.icon_id, ICON_DATA_GPLAYER, gpl);
739  icon->flag = ICON_FLAG_MANAGED;
740 
741  return gpl->runtime.icon_id;
742 }
743 
745 {
746  /* Never handle icons in non-main thread! */
748 
749  if (!gpl || G.background) {
750  return 0;
751  }
752 
753  if (gpl->runtime.icon_id) {
754  return gpl->runtime.icon_id;
755  }
756 
758 
759  if (!gpl->runtime.icon_id) {
760  CLOG_ERROR(&LOG, "not enough IDs");
761  return 0;
762  }
763 
765 }
766 
768 {
769  if (!preview || G.background) {
770  return 0;
771  }
772 
773  if (id) {
775  }
776 
777  if (preview->icon_id) {
778  BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id);
779  return preview->icon_id;
780  }
781 
782  if (id && id->icon_id) {
783  preview->icon_id = id->icon_id;
784  return preview->icon_id;
785  }
786 
787  preview->icon_id = get_next_free_id();
788 
789  if (!preview->icon_id) {
790  CLOG_ERROR(&LOG, "not enough IDs");
791  return 0;
792  }
793 
794  /* Ensure we synchronize ID icon_id with its previewimage if available,
795  * and generate suitable 'ID' icon. */
796  if (id) {
797  id->icon_id = preview->icon_id;
798  return icon_id_ensure_create_icon(id);
799  }
800 
801  Icon *icon = icon_create(preview->icon_id, ICON_DATA_PREVIEW, preview);
802  icon->flag = ICON_FLAG_MANAGED;
803 
804  return preview->icon_id;
805 }
806 
808 {
809  int icon_id = get_next_free_id();
810 
811  Icon *icon = icon_create(icon_id, ICON_DATA_IMBUF, ibuf);
812  icon->flag = ICON_FLAG_MANAGED;
813 
814  return icon_id;
815 }
816 
818 {
819  Icon *icon = icon_ghash_lookup(icon_id);
820  if (!icon) {
821  CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
822  return nullptr;
823  }
824  if (icon->obj_type != ICON_DATA_IMBUF) {
825  CLOG_ERROR(&LOG, "icon ID does not refer to an imbuf icon: %d", icon_id);
826  return nullptr;
827  }
828 
829  return (ImBuf *)icon->obj;
830 }
831 
833 {
835 
836  Icon *icon = nullptr;
837 
838  icon = icon_ghash_lookup(icon_id);
839 
840  if (!icon) {
841  CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id);
842  return nullptr;
843  }
844 
845  return icon;
846 }
847 
848 void BKE_icon_set(const int icon_id, struct Icon *icon)
849 {
850  void **val_p;
851 
852  std::scoped_lock lock(gIconMutex);
854  CLOG_ERROR(&LOG, "icon already set: %d", icon_id);
855  return;
856  }
857 
858  *val_p = icon;
859 }
860 
862 {
864  sizeof(DeferredIconDeleteNode), __func__);
865  node->icon_id = icon_id;
866  /* Doesn't need lock. */
868 }
869 
870 void BKE_icon_id_delete(struct ID *id)
871 {
872  const int icon_id = id->icon_id;
873  if (!icon_id) {
874  return; /* no icon defined for library object */
875  }
876  id->icon_id = 0;
877 
878  if (!BLI_thread_is_main()) {
880  return;
881  }
882 
884  std::scoped_lock lock(gIconMutex);
886 }
887 
888 bool BKE_icon_delete(const int icon_id)
889 {
890  if (icon_id == 0) {
891  /* no icon defined for library object */
892  return false;
893  }
894 
895  std::scoped_lock lock(gIconMutex);
896  if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr)) {
897  icon_free_data(icon_id, icon);
898  icon_free(icon);
899  return true;
900  }
901 
902  return false;
903 }
904 
906 {
907  if (icon_id == 0) {
908  /* no icon defined for library object */
909  return false;
910  }
911 
912  std::scoped_lock lock(gIconMutex);
913 
914  Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr);
915  if (icon) {
916  if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) {
918  return false;
919  }
920 
921  icon_free_data(icon_id, icon);
922  icon_free(icon);
923  return true;
924  }
925 
926  return false;
927 }
928 
929 /* -------------------------------------------------------------------- */
934 {
936 
937  if (geom->icon_id) {
938  return geom->icon_id;
939  }
940 
941  geom->icon_id = get_next_free_id();
942 
943  icon_create(geom->icon_id, ICON_DATA_GEOM, geom);
944  /* Not managed for now, we may want this to be configurable per icon). */
945 
946  return geom->icon_id;
947 }
948 
949 struct Icon_Geom *BKE_icon_geom_from_memory(uchar *data, size_t data_len)
950 {
952  if (data_len <= 8) {
953  return nullptr;
954  }
955  /* Wrapper for RAII early exit cleanups. */
956  std::unique_ptr<uchar> data_wrapper(std::move(data));
957 
958  /* Skip the header. */
959  data_len -= 8;
960  const int div = 3 * 2 * 3;
961  const int coords_len = data_len / div;
962  if (coords_len * div != data_len) {
963  return nullptr;
964  }
965 
966  const uchar header[4] = {'V', 'C', 'O', 0};
967  uchar *p = data_wrapper.get();
968  if (memcmp(p, header, ARRAY_SIZE(header)) != 0) {
969  return nullptr;
970  }
971  p += 4;
972 
973  struct Icon_Geom *geom = (struct Icon_Geom *)MEM_mallocN(sizeof(*geom), __func__);
974  geom->coords_range[0] = (int)*p++;
975  geom->coords_range[1] = (int)*p++;
976  /* x, y ignored for now */
977  p += 2;
978 
979  geom->coords_len = coords_len;
980  geom->coords = reinterpret_cast<decltype(geom->coords)>(p);
981  geom->colors = reinterpret_cast<decltype(geom->colors)>(p + (data_len / 3));
982  geom->icon_id = 0;
983  /* Move buffer ownership to C buffer. */
984  geom->mem = data_wrapper.release();
985  return geom;
986 }
987 
988 struct Icon_Geom *BKE_icon_geom_from_file(const char *filename)
989 {
991  size_t data_len;
992  uchar *data = (uchar *)BLI_file_read_binary_as_mem(filename, 0, &data_len);
993  if (data == nullptr) {
994  return nullptr;
995  }
996  return BKE_icon_geom_from_memory(data, data_len);
997 }
998 
1001 /* -------------------------------------------------------------------- */
1005 int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
1006 {
1007  int icon_id = get_next_free_id();
1009  icon->id_type = id_type;
1010  return icon_id;
1011 }
1012 
#define ICON_RENDER_DEFAULT_HEIGHT
Definition: BKE_icons.h:253
@ ICON_DATA_IMBUF
Definition: BKE_icons.h:29
@ ICON_DATA_STUDIOLIGHT
Definition: BKE_icons.h:35
@ ICON_DATA_PREVIEW
Definition: BKE_icons.h:31
@ ICON_DATA_ID
Definition: BKE_icons.h:27
@ ICON_DATA_GPLAYER
Definition: BKE_icons.h:37
@ ICON_DATA_GEOM
Definition: BKE_icons.h:33
void BKE_studiolight_unset_icon_id(StudioLight *sl, int icon_id)
Definition: studiolight.c:1618
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
File and directory operations.
void * BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
Definition: storage.c:477
GHash * BLI_ghash_str_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
GHash * BLI_ghash_int_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:790
void * BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:805
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void ** BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:748
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:755
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:771
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
int BLI_thread_is_main(void)
Definition: threads.cc:207
#define ARRAY_SIZE(arr)
#define POINTER_FROM_INT(i)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr)
Definition: writefile.c:1576
#define BLO_read_data_address(reader, ptr_p)
bool BLO_read_data_is_undo(BlendDataReader *reader)
Definition: readfile.c:5288
#define BLO_write_struct_at_address(writer, struct_name, address, data_ptr)
#define CLOG_ERROR(clg_ref,...)
Definition: CLG_log.h:190
ThreadMutex mutex
@ PRV_TAG_DEFFERED_DELETE
Definition: DNA_ID.h:526
@ PRV_TAG_DEFFERED
Definition: DNA_ID.h:524
@ PRV_TAG_DEFFERED_RENDERING
Definition: DNA_ID.h:525
#define PRV_DEFERRED_DATA(prv)
Definition: DNA_ID.h:547
@ PRV_RENDERING
Definition: DNA_ID.h:519
@ PRV_CHANGED
Definition: DNA_ID.h:517
@ PRV_USER_EDITED
Definition: DNA_ID.h:518
eIconSizes
Definition: DNA_ID_enums.h:14
@ ICON_SIZE_PREVIEW
Definition: DNA_ID_enums.h:16
@ ICON_SIZE_ICON
Definition: DNA_ID_enums.h:15
@ NUM_ICON_SIZES
Definition: DNA_ID_enums.h:18
@ ID_TE
Definition: DNA_ID_enums.h:52
@ ID_IM
Definition: DNA_ID_enums.h:53
@ ID_NT
Definition: DNA_ID_enums.h:68
@ ID_LA
Definition: DNA_ID_enums.h:55
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_BR
Definition: DNA_ID_enums.h:69
@ ID_WO
Definition: DNA_ID_enums.h:59
@ ID_MA
Definition: DNA_ID_enums.h:51
@ ID_AC
Definition: DNA_ID_enums.h:67
@ ID_SCR
Definition: DNA_ID_enums.h:60
@ ID_GR
Definition: DNA_ID_enums.h:65
@ ID_OB
Definition: DNA_ID_enums.h:47
Object groups, one object can be in many groups at once.
Object is a sort of wrapper for general info.
void GPU_texture_free(GPUTexture *tex)
Definition: gpu_texture.cc:564
bool IMB_scaleImBuf(struct ImBuf *ibuf, unsigned int newx, unsigned int newy)
Definition: scaling.c:1644
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:500
void IMB_premultiply_alpha(struct ImBuf *ibuf)
Definition: filter.c:662
Contains defines and structs used throughout the imbuf module.
@ IB_rect
@ THB_LARGE
Definition: IMB_thumbs.h:24
ThumbSource
Definition: IMB_thumbs.h:28
@ THB_SOURCE_IMAGE
Definition: IMB_thumbs.h:29
struct ImBuf * IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source)
Definition: thumbs.c:516
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE int16_t atomic_fetch_and_and_int16(int16_t *p, int16_t b)
volatile int lock
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
OperationNode * node
void IMB_freeImBuf(ImBuf *UNUSED(ibuf))
static int gFirstIconId
Definition: icons.cc:72
void BKE_previewimg_deferred_release(PreviewImage *prv)
Definition: icons.cc:425
void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv)
Definition: icons.cc:595
int BKE_icon_gplayer_color_ensure(bGPDlayer *gpl)
Definition: icons.cc:744
static PreviewImage * previewimg_deferred_create(const char *filepath, int source)
Definition: icons.cc:247
static LockfreeLinkList g_icon_delete_queue
Definition: icons.cc:85
PreviewImage * BKE_previewimg_cached_thumbnail_read(const char *name, const char *filepath, const int source, bool force_update)
Definition: icons.cc:463
void BKE_icon_id_delete(struct ID *id)
Definition: icons.cc:870
void BKE_previewimg_cached_release(const char *name)
Definition: icons.cc:508
void BKE_icon_changed(const int icon_id)
Definition: icons.cc:637
static int icon_id_ensure_create_icon(struct ID *id)
Definition: icons.cc:688
void BKE_icons_deferred_free()
Definition: icons.cc:217
static void icon_free(void *val)
Definition: icons.cc:87
static int get_next_free_id()
Definition: icons.cc:157
int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
Definition: icons.cc:767
PreviewImage ** BKE_previewimg_id_get_p(const ID *id)
Definition: icons.cc:343
int BKE_icon_imbuf_create(ImBuf *ibuf)
Definition: icons.cc:807
bool BKE_previewimg_id_supports_jobs(const ID *id)
Definition: icons.cc:420
Icon * BKE_icon_get(const int icon_id)
Definition: icons.cc:832
static GHash * gCachedPreviews
Definition: icons.cc:77
static void icon_free_data(int icon_id, Icon *icon)
Definition: icons.cc:115
struct Icon_Geom * BKE_icon_geom_from_file(const char *filename)
Definition: icons.cc:988
@ ICON_FLAG_MANAGED
Definition: icons.cc:58
void BKE_previewimg_freefunc(void *link)
Definition: icons.cc:266
static std::mutex gIconMutex
Definition: icons.cc:74
void BKE_icons_free()
Definition: icons.cc:200
struct Icon_Geom * BKE_icon_geom_from_memory(uchar *data, size_t data_len)
Definition: icons.cc:949
void BKE_icon_set(const int icon_id, struct Icon *icon)
Definition: icons.cc:848
#define ID_PRV_CASE(id_code, id_struct)
static int icon_gplayer_color_ensure_create_icon(bGPDlayer *gpl)
Definition: icons.cc:729
bool BKE_previewimg_is_finished(const PreviewImage *prv, const int size)
Definition: icons.cc:590
static int gNextIconId
Definition: icons.cc:69
void BKE_previewimg_clear(struct PreviewImage *prv)
Definition: icons.cc:303
void BKE_previewimg_free(PreviewImage **prv)
Definition: icons.cc:283
static PreviewImage * previewimg_create_ex(size_t deferred_data_size)
Definition: icons.cc:230
ImBuf * BKE_previewimg_to_imbuf(PreviewImage *prv, const int size)
Definition: icons.cc:567
static Icon * icon_create(int icon_id, int obj_type, void *obj)
Definition: icons.cc:667
PreviewImage * BKE_previewimg_cached_get(const char *name)
Definition: icons.cc:440
void BKE_previewimg_ensure(PreviewImage *prv, const int size)
Definition: icons.cc:517
PreviewImage * BKE_previewimg_cached_ensure(const char *name)
Definition: icons.cc:446
void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
Definition: icons.cc:291
PreviewImage * BKE_previewimg_copy(const PreviewImage *prv)
Definition: icons.cc:310
void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv)
Definition: icons.cc:615
static Icon * icon_ghash_lookup(int icon_id)
Definition: icons.cc:149
int BKE_icon_geom_ensure(struct Icon_Geom *geom)
Definition: icons.cc:933
PreviewImage * BKE_previewimg_create()
Definition: icons.cc:261
static GHash * gIcons
Definition: icons.cc:66
void BKE_previewimg_id_custom_set(ID *id, const char *filepath)
Definition: icons.cc:399
PreviewImage * BKE_previewimg_id_get(const ID *id)
Definition: icons.cc:371
void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
Definition: icons.cc:326
static void icon_add_to_deferred_delete_queue(int icon_id)
Definition: icons.cc:861
void BKE_previewimg_finish(PreviewImage *prv, const int size)
Definition: icons.cc:584
PreviewImage * BKE_previewimg_id_ensure(ID *id)
Definition: icons.cc:385
static CLG_LogRef LOG
Definition: icons.cc:63
bool BKE_icon_delete_unmanaged(const int icon_id)
Definition: icons.cc:905
void BKE_previewimg_id_free(ID *id)
Definition: icons.cc:377
int BKE_icon_id_ensure(struct ID *id)
Definition: icons.cc:699
ImBuf * BKE_icon_imbuf_get_buffer(int icon_id)
Definition: icons.cc:817
int BKE_icon_ensure_studio_light(struct StudioLight *sl, int id_type)
Definition: icons.cc:1005
void BKE_icons_init(int first_dyn_id)
Definition: icons.cc:183
bool BKE_icon_delete(const int icon_id)
Definition: icons.cc:888
#define GS(x)
Definition: iris.c:225
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define G(x, y, z)
static const pxr::TfToken preview("preview", pxr::TfToken::Immortal)
struct DeferredIconDeleteNode * next
Definition: icons.cc:81
Definition: DNA_ID.h:368
int icon_id
Definition: DNA_ID.h:389
char name[66]
Definition: DNA_ID.h:378
int coords_len
Definition: BKE_icons.h:62
const void * mem
Definition: BKE_icons.h:67
unsigned char(* colors)[4]
Definition: BKE_icons.h:65
int icon_id
Definition: BKE_icons.h:61
unsigned char(* coords)[2]
Definition: BKE_icons.h:64
int coords_range[2]
Definition: BKE_icons.h:63
Definition: BKE_icons.h:43
void * obj
Definition: BKE_icons.h:50
char flag
Definition: BKE_icons.h:53
char obj_type
Definition: BKE_icons.h:51
void * drawinfo
Definition: BKE_icons.h:44
short id_type
Definition: BKE_icons.h:55
DrawInfoFreeFP drawinfo_free
Definition: BKE_icons.h:56
unsigned int * rect
unsigned int h[2]
Definition: DNA_ID.h:532
short tag
Definition: DNA_ID.h:543
short changed_timestamp[2]
Definition: DNA_ID.h:534
short flag[2]
Definition: DNA_ID.h:533
int icon_id
Definition: DNA_ID.h:540
unsigned int * rect[2]
Definition: DNA_ID.h:535
unsigned int w[2]
Definition: DNA_ID.h:531
struct GPUTexture * gputexture[2]
Definition: DNA_ID.h:538
bGPDlayer_Runtime runtime