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