Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / icons.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2006-2007 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  */
28
29 /** \file blender/blenkernel/intern/icons.c
30  *  \ingroup bke
31  */
32
33
34 #include <math.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_group_types.h"
41 #include "DNA_lamp_types.h"
42 #include "DNA_material_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_texture_types.h"
47 #include "DNA_world_types.h"
48 #include "DNA_brush_types.h"
49
50 #include "BLI_utildefines.h"
51 #include "BLI_ghash.h"
52 #include "BLI_linklist_lockfree.h"
53 #include "BLI_string.h"
54 #include "BLI_threads.h"
55
56 #include "BKE_icons.h"
57 #include "BKE_global.h" /* only for G.background test */
58
59 #include "BLI_sys_types.h" // for intptr_t support
60
61 #include "GPU_texture.h"
62
63 #include "IMB_imbuf.h"
64 #include "IMB_imbuf_types.h"
65 #include "IMB_thumbs.h"
66
67 /* GLOBALS */
68
69 static GHash *gIcons = NULL;
70
71 static int gNextIconId = 1;
72
73 static int gFirstIconId = 1;
74
75 static GHash *gCachedPreviews = NULL;
76
77 /* Queue of icons for deferred deletion. */
78 typedef struct DeferredIconDeleteNode {
79         struct DeferredIconDeleteNode *next;
80         int icon_id;
81 } DeferredIconDeleteNode;
82 static LockfreeLinkList g_icon_delete_queue;
83
84 static void icon_free(void *val)
85 {
86         Icon *icon = val;
87
88         if (icon) {
89                 if (icon->drawinfo_free) {
90                         icon->drawinfo_free(icon->drawinfo);
91                 }
92                 else if (icon->drawinfo) {
93                         MEM_freeN(icon->drawinfo);
94                 }
95                 MEM_freeN(icon);
96         }
97 }
98
99 /* create an id for a new icon and make sure that ids from deleted icons get reused
100  * after the integer number range is used up */
101 static int get_next_free_id(void)
102 {
103         BLI_assert(BLI_thread_is_main());
104         int startId = gFirstIconId;
105
106         /* if we haven't used up the int number range, we just return the next int */
107         if (gNextIconId >= gFirstIconId)
108                 return gNextIconId++;
109         
110         /* now we try to find the smallest icon id not stored in the gIcons hash */
111         while (BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(startId)) && startId >= gFirstIconId)
112                 startId++;
113
114         /* if we found a suitable one that isn't used yet, return it */
115         if (startId >= gFirstIconId)
116                 return startId;
117
118         /* fail */
119         return 0;
120 }
121
122 void BKE_icons_init(int first_dyn_id)
123 {
124         BLI_assert(BLI_thread_is_main());
125
126         gNextIconId = first_dyn_id;
127         gFirstIconId = first_dyn_id;
128
129         if (!gIcons) {
130                 gIcons = BLI_ghash_int_new(__func__);
131                 BLI_linklist_lockfree_init(&g_icon_delete_queue);
132         }
133
134         if (!gCachedPreviews) {
135                 gCachedPreviews = BLI_ghash_str_new(__func__);
136         }
137 }
138
139 void BKE_icons_free(void)
140 {
141         BLI_assert(BLI_thread_is_main());
142
143         if (gIcons) {
144                 BLI_ghash_free(gIcons, NULL, icon_free);
145                 gIcons = NULL;
146         }
147
148         if (gCachedPreviews) {
149                 BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
150                 gCachedPreviews = NULL;
151         }
152
153         BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN);
154 }
155
156 void BKE_icons_deferred_free(void)
157 {
158         BLI_assert(BLI_thread_is_main());
159
160         for (DeferredIconDeleteNode *node =
161                      (DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue);
162              node != NULL;
163              node = node->next)
164         {
165                 BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(node->icon_id), NULL, icon_free);
166         }
167         BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN);
168 }
169
170 static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
171 {
172         PreviewImage *prv_img = NULL;
173         int i;
174
175         prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
176         memset(prv_img, 0, sizeof(*prv_img));  /* leave deferred data dirty */
177
178         if (deferred_data_size) {
179                 prv_img->tag |= PRV_TAG_DEFFERED;
180         }
181
182         for (i = 0; i < NUM_ICON_SIZES; ++i) {
183                 prv_img->flag[i] |= PRV_CHANGED;
184                 prv_img->changed_timestamp[i] = 0;
185         }
186         return prv_img;
187 }
188
189 PreviewImage *BKE_previewimg_create(void)
190 {
191         return previewimg_create_ex(0);
192 }
193
194 void BKE_previewimg_freefunc(void *link)
195 {
196         PreviewImage *prv = (PreviewImage *)link;
197         if (prv) {
198                 int i;
199
200                 for (i = 0; i < NUM_ICON_SIZES; ++i) {
201                         if (prv->rect[i]) {
202                                 MEM_freeN(prv->rect[i]);
203                         }
204                         if (prv->gputexture[i])
205                                 GPU_texture_free(prv->gputexture[i]);
206                 }
207                 
208                 MEM_freeN(prv);
209         }
210 }
211
212 void BKE_previewimg_free(PreviewImage **prv)
213 {
214         if (prv && (*prv)) {
215                 BKE_previewimg_freefunc(*prv);
216                 *prv = NULL;
217         }
218 }
219
220 void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
221 {
222         MEM_SAFE_FREE(prv->rect[size]);
223         if (prv->gputexture[size]) {
224                 GPU_texture_free(prv->gputexture[size]);
225         }
226         prv->h[size] = prv->w[size] = 0;
227         prv->flag[size] |= PRV_CHANGED;
228         prv->flag[size] &= ~PRV_USER_EDITED;
229         prv->changed_timestamp[size] = 0;
230 }
231
232 void BKE_previewimg_clear(struct PreviewImage *prv)
233 {
234         int i;
235         for (i = 0; i < NUM_ICON_SIZES; ++i) {
236                 BKE_previewimg_clear_single(prv, i);
237         }
238 }
239
240 PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
241 {
242         PreviewImage *prv_img = NULL;
243         int i;
244
245         if (prv) {
246                 prv_img = MEM_dupallocN(prv);
247                 for (i = 0; i < NUM_ICON_SIZES; ++i) {
248                         if (prv->rect[i]) {
249                                 prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
250                         }
251                         prv_img->gputexture[i] = NULL;
252                 }
253         }
254         return prv_img;
255 }
256
257 /** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */
258 void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
259 {
260         PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
261         PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
262
263         if (old_prv_p && *old_prv_p) {
264                 BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
265 //              const int new_icon_id = get_next_free_id();
266
267 //              if (new_icon_id == 0) {
268 //                      return;  /* Failure. */
269 //              }
270                 *new_prv_p = BKE_previewimg_copy(*old_prv_p);
271                 new_id->icon_id = (*new_prv_p)->icon_id = 0;
272         }
273 }
274
275 PreviewImage **BKE_previewimg_id_get_p(const ID *id)
276 {
277         switch (GS(id->name)) {
278 #define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; } ((void)0)
279                 ID_PRV_CASE(ID_MA, Material);
280                 ID_PRV_CASE(ID_TE, Tex);
281                 ID_PRV_CASE(ID_WO, World);
282                 ID_PRV_CASE(ID_LA, Lamp);
283                 ID_PRV_CASE(ID_IM, Image);
284                 ID_PRV_CASE(ID_BR, Brush);
285                 ID_PRV_CASE(ID_OB, Object);
286                 ID_PRV_CASE(ID_GR, Group);
287                 ID_PRV_CASE(ID_SCE, Scene);
288                 ID_PRV_CASE(ID_SCR, bScreen);
289 #undef ID_PRV_CASE
290                 default:
291                         break;
292         }
293
294         return NULL;
295 }
296
297 void BKE_previewimg_id_free(ID *id)
298 {
299         PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
300         if (prv_p) {
301                 BKE_previewimg_free(prv_p);
302         }
303 }
304
305 PreviewImage *BKE_previewimg_id_ensure(ID *id)
306 {
307         PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
308
309         if (prv_p) {
310                 if (*prv_p == NULL) {
311                         *prv_p = BKE_previewimg_create();
312                 }
313                 return *prv_p;
314         }
315
316         return NULL;
317 }
318
319 PreviewImage *BKE_previewimg_cached_get(const char *name)
320 {
321         return BLI_ghash_lookup(gCachedPreviews, name);
322 }
323
324 /**
325  * Generate an empty PreviewImage, if not yet existing.
326  */
327 PreviewImage *BKE_previewimg_cached_ensure(const char *name)
328 {
329         PreviewImage *prv = NULL;
330         void **key_p, **prv_p;
331
332         if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
333                 *key_p = BLI_strdup(name);
334                 *prv_p = BKE_previewimg_create();
335         }
336         prv = *prv_p;
337         BLI_assert(prv);
338
339         return prv;
340 }
341
342 /**
343  * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
344  */
345 PreviewImage *BKE_previewimg_cached_thumbnail_read(
346         const char *name, const char *path, const int source, bool force_update)
347 {
348         PreviewImage *prv = NULL;
349         void **prv_p;
350
351         prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
352
353         if (prv_p) {
354                 prv = *prv_p;
355                 BLI_assert(prv);
356         }
357
358         if (prv && force_update) {
359                 const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
360                 if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
361                         /* If same path, no need to re-allocate preview, just clear it up. */
362                         BKE_previewimg_clear(prv);
363                 }
364                 else {
365                         BKE_previewimg_free(&prv);
366                 }
367         }
368
369         if (!prv) {
370                 /* We pack needed data for lazy loading (source type, in a single char, and path). */
371                 const size_t deferred_data_size = strlen(path) + 2;
372                 char *deferred_data;
373
374                 prv = previewimg_create_ex(deferred_data_size);
375                 deferred_data = PRV_DEFERRED_DATA(prv);
376                 deferred_data[0] = source;
377                 memcpy(&deferred_data[1], path, deferred_data_size - 1);
378
379                 force_update = true;
380         }
381
382         if (force_update) {
383                 if (prv_p) {
384                         *prv_p = prv;
385                 }
386                 else {
387                         BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv);
388                 }
389         }
390
391         return prv;
392 }
393
394 void BKE_previewimg_cached_release_pointer(PreviewImage *prv)
395 {
396         if (prv) {
397                 if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
398                         /* We cannot delete the preview while it is being loaded in another thread... */
399                         prv->tag |= PRV_TAG_DEFFERED_DELETE;
400                         return;
401                 }
402                 if (prv->icon_id) {
403                         BKE_icon_delete(prv->icon_id);
404                 }
405                 BKE_previewimg_freefunc(prv);
406         }
407 }
408
409 void BKE_previewimg_cached_release(const char *name)
410 {
411         PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
412
413         BKE_previewimg_cached_release_pointer(prv);
414 }
415
416 /** Handle deferred (lazy) loading/generation of preview image, if needed.
417  * For now, only used with file thumbnails. */
418 void BKE_previewimg_ensure(PreviewImage *prv, const int size)
419 {
420         if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
421                 const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
422                 const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
423
424                 if (do_icon || do_preview) {
425                         ImBuf *thumb;
426                         char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
427                         int source =  prv_deferred_data[0];
428                         char *path = &prv_deferred_data[1];
429                         int icon_w, icon_h;
430
431                         thumb = IMB_thumb_manage(path, THB_LARGE, source);
432
433                         if (thumb) {
434                                 /* PreviewImage assumes premultiplied alhpa... */
435                                 IMB_premultiply_alpha(thumb);
436
437                                 if (do_preview) {
438                                         prv->w[ICON_SIZE_PREVIEW] = thumb->x;
439                                         prv->h[ICON_SIZE_PREVIEW] = thumb->y;
440                                         prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
441                                         prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
442                                 }
443                                 if (do_icon) {
444                                         if (thumb->x > thumb->y) {
445                                                 icon_w = ICON_RENDER_DEFAULT_HEIGHT;
446                                                 icon_h = (thumb->y * icon_w) / thumb->x + 1;
447                                         }
448                                         else if (thumb->x < thumb->y) {
449                                                 icon_h = ICON_RENDER_DEFAULT_HEIGHT;
450                                                 icon_w = (thumb->x * icon_h) / thumb->y + 1;
451                                         }
452                                         else {
453                                                 icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
454                                         }
455
456                                         IMB_scaleImBuf(thumb, icon_w, icon_h);
457                                         prv->w[ICON_SIZE_ICON] = icon_w;
458                                         prv->h[ICON_SIZE_ICON] = icon_h;
459                                         prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
460                                         prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
461                                 }
462                                 IMB_freeImBuf(thumb);
463                         }
464                 }
465         }
466 }
467
468 void BKE_icon_changed(const int icon_id)
469 {
470         BLI_assert(BLI_thread_is_main());
471
472         Icon *icon = NULL;
473         
474         if (!icon_id || G.background) return;
475
476         icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
477         
478         if (icon) {
479                 /* We *only* expect ID-tied icons here, not non-ID icon/preview! */
480                 BLI_assert(icon->type != 0);
481
482                 /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here ,
483                  * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */
484                 PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj);
485
486                 /* If we have previews, they all are now invalid changed. */
487                 if (p_prv && *p_prv) {
488                         int i;
489                         for (i = 0; i < NUM_ICON_SIZES; ++i) {
490                                 (*p_prv)->flag[i] |= PRV_CHANGED;
491                                 (*p_prv)->changed_timestamp[i]++;
492                         }
493                 }
494         }
495 }
496
497 static int icon_id_ensure_create_icon(struct ID *id)
498 {
499         BLI_assert(BLI_thread_is_main());
500
501         Icon *new_icon = NULL;
502
503         new_icon = MEM_mallocN(sizeof(Icon), __func__);
504
505         new_icon->obj = id;
506         new_icon->type = GS(id->name);
507
508         /* next two lines make sure image gets created */
509         new_icon->drawinfo = NULL;
510         new_icon->drawinfo_free = NULL;
511
512         BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon);
513
514         return id->icon_id;
515 }
516
517 int BKE_icon_id_ensure(struct ID *id)
518 {
519         if (!id || G.background)
520                 return 0;
521
522         if (id->icon_id)
523                 return id->icon_id;
524
525         id->icon_id = get_next_free_id();
526
527         if (!id->icon_id) {
528                 printf("%s: Internal error - not enough IDs\n", __func__);
529                 return 0;
530         }
531
532         /* Ensure we synchronize ID icon_id with its previewimage if it has one. */
533         PreviewImage **p_prv = BKE_previewimg_id_get_p(id);
534         if (p_prv && *p_prv) {
535                 BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id));
536                 (*p_prv)->icon_id = id->icon_id;
537         }
538
539         return icon_id_ensure_create_icon(id);
540 }
541
542 /**
543  * Return icon id of given preview, or create new icon if not found.
544  */
545 int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
546 {
547         Icon *new_icon = NULL;
548
549         if (!preview || G.background)
550                 return 0;
551
552         if (id) {
553                 BLI_assert(BKE_previewimg_id_ensure(id) == preview);
554         }
555
556         if (preview->icon_id) {
557                 BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id);
558                 return preview->icon_id;
559         }
560
561         if (id && id->icon_id) {
562                 preview->icon_id = id->icon_id;
563                 return preview->icon_id;
564         }
565
566         preview->icon_id = get_next_free_id();
567
568         if (!preview->icon_id) {
569                 printf("%s: Internal error - not enough IDs\n", __func__);
570                 return 0;
571         }
572
573         /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */
574         if (id) {
575                 id->icon_id = preview->icon_id;
576                 return icon_id_ensure_create_icon(id);
577         }
578
579         new_icon = MEM_mallocN(sizeof(Icon), __func__);
580
581         new_icon->obj = preview;
582         new_icon->type = 0;  /* Special, tags as non-ID icon/preview. */
583
584         /* next two lines make sure image gets created */
585         new_icon->drawinfo = NULL;
586         new_icon->drawinfo_free = NULL;
587
588         BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon);
589
590         return preview->icon_id;
591 }
592
593 Icon *BKE_icon_get(const int icon_id)
594 {
595         BLI_assert(BLI_thread_is_main());
596
597         Icon *icon = NULL;
598
599         icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
600         
601         if (!icon) {
602                 printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
603                 return NULL;
604         }
605
606         return icon;
607 }
608
609 void BKE_icon_set(const int icon_id, struct Icon *icon)
610 {
611         BLI_assert(BLI_thread_is_main());
612
613         void **val_p;
614
615         if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) {
616                 printf("%s: Internal error, icon already set: %d\n", __func__, icon_id);
617                 return;
618         }
619
620         *val_p = icon;
621 }
622
623 static void icon_add_to_deferred_delete_queue(int icon_id)
624 {
625         DeferredIconDeleteNode *node =
626                 MEM_mallocN(sizeof(DeferredIconDeleteNode), __func__);
627         node->icon_id = icon_id;
628         BLI_linklist_lockfree_insert(&g_icon_delete_queue,
629                                      (LockfreeLinkNode *)node);
630 }
631
632 void BKE_icon_id_delete(struct ID *id)
633 {
634         const int icon_id = id->icon_id;
635         if (!icon_id) return;  /* no icon defined for library object */
636         id->icon_id = 0;
637
638         if (!BLI_thread_is_main()) {
639                 icon_add_to_deferred_delete_queue(icon_id);
640                 return;
641         }
642
643         BKE_icons_deferred_free();
644         BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(icon_id), NULL, icon_free);
645 }
646
647 /**
648  * Remove icon and free data.
649  */
650 void BKE_icon_delete(const int icon_id)
651 {
652         Icon *icon;
653
654         if (!icon_id) return;  /* no icon defined for library object */
655
656         icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
657
658         if (icon) {
659                 if (icon->type) {
660                         ((ID *)(icon->obj))->icon_id = 0;
661                 }
662                 else {
663                         ((PreviewImage *)(icon->obj))->icon_id = 0;
664                 }
665                 icon_free(icon);
666         }
667 }