icons.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  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. /** \file blender/blenkernel/intern/icons.c
  29. * \ingroup bke
  30. */
  31. #include <math.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include "MEM_guardedalloc.h"
  35. #include "DNA_group_types.h"
  36. #include "DNA_lamp_types.h"
  37. #include "DNA_material_types.h"
  38. #include "DNA_object_types.h"
  39. #include "DNA_scene_types.h"
  40. #include "DNA_texture_types.h"
  41. #include "DNA_world_types.h"
  42. #include "DNA_brush_types.h"
  43. #include "BLI_utildefines.h"
  44. #include "BLI_ghash.h"
  45. #include "BLI_string.h"
  46. #include "BKE_icons.h"
  47. #include "BKE_global.h" /* only for G.background test */
  48. #include "BLI_sys_types.h" // for intptr_t support
  49. #include "GPU_texture.h"
  50. #include "IMB_imbuf.h"
  51. #include "IMB_imbuf_types.h"
  52. #include "IMB_thumbs.h"
  53. /* GLOBALS */
  54. static GHash *gIcons = NULL;
  55. static int gNextIconId = 1;
  56. static int gFirstIconId = 1;
  57. static GHash *gCachedPreviews = NULL;
  58. static void icon_free(void *val)
  59. {
  60. Icon *icon = val;
  61. if (icon) {
  62. if (icon->drawinfo_free) {
  63. icon->drawinfo_free(icon->drawinfo);
  64. }
  65. else if (icon->drawinfo) {
  66. MEM_freeN(icon->drawinfo);
  67. }
  68. MEM_freeN(icon);
  69. }
  70. }
  71. /* create an id for a new icon and make sure that ids from deleted icons get reused
  72. * after the integer number range is used up */
  73. static int get_next_free_id(void)
  74. {
  75. int startId = gFirstIconId;
  76. /* if we haven't used up the int number range, we just return the next int */
  77. if (gNextIconId >= gFirstIconId)
  78. return gNextIconId++;
  79. /* now we try to find the smallest icon id not stored in the gIcons hash */
  80. while (BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(startId)) && startId >= gFirstIconId)
  81. startId++;
  82. /* if we found a suitable one that isn't used yet, return it */
  83. if (startId >= gFirstIconId)
  84. return startId;
  85. /* fail */
  86. return 0;
  87. }
  88. void BKE_icons_init(int first_dyn_id)
  89. {
  90. gNextIconId = first_dyn_id;
  91. gFirstIconId = first_dyn_id;
  92. if (!gIcons)
  93. gIcons = BLI_ghash_int_new(__func__);
  94. if (!gCachedPreviews) {
  95. gCachedPreviews = BLI_ghash_str_new(__func__);
  96. }
  97. }
  98. void BKE_icons_free(void)
  99. {
  100. if (gIcons) {
  101. BLI_ghash_free(gIcons, NULL, icon_free);
  102. gIcons = NULL;
  103. }
  104. if (gCachedPreviews) {
  105. BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc);
  106. gCachedPreviews = NULL;
  107. }
  108. }
  109. static PreviewImage *previewimg_create_ex(size_t deferred_data_size)
  110. {
  111. PreviewImage *prv_img = NULL;
  112. int i;
  113. prv_img = MEM_mallocN(sizeof(PreviewImage) + deferred_data_size, "img_prv");
  114. memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */
  115. if (deferred_data_size) {
  116. prv_img->tag |= PRV_TAG_DEFFERED;
  117. }
  118. for (i = 0; i < NUM_ICON_SIZES; ++i) {
  119. prv_img->flag[i] |= PRV_CHANGED;
  120. prv_img->changed_timestamp[i] = 0;
  121. }
  122. return prv_img;
  123. }
  124. PreviewImage *BKE_previewimg_create(void)
  125. {
  126. return previewimg_create_ex(0);
  127. }
  128. void BKE_previewimg_freefunc(void *link)
  129. {
  130. PreviewImage *prv = (PreviewImage *)link;
  131. if (prv) {
  132. int i;
  133. for (i = 0; i < NUM_ICON_SIZES; ++i) {
  134. if (prv->rect[i]) {
  135. MEM_freeN(prv->rect[i]);
  136. }
  137. if (prv->gputexture[i])
  138. GPU_texture_free(prv->gputexture[i]);
  139. }
  140. MEM_freeN(prv);
  141. }
  142. }
  143. void BKE_previewimg_free(PreviewImage **prv)
  144. {
  145. if (prv && (*prv)) {
  146. BKE_previewimg_freefunc(*prv);
  147. *prv = NULL;
  148. }
  149. }
  150. void BKE_previewimg_clear_single(struct PreviewImage *prv, enum eIconSizes size)
  151. {
  152. MEM_SAFE_FREE(prv->rect[size]);
  153. if (prv->gputexture[size]) {
  154. GPU_texture_free(prv->gputexture[size]);
  155. }
  156. prv->h[size] = prv->w[size] = 0;
  157. prv->flag[size] |= PRV_CHANGED;
  158. prv->flag[size] &= ~PRV_USER_EDITED;
  159. prv->changed_timestamp[size] = 0;
  160. }
  161. void BKE_previewimg_clear(struct PreviewImage *prv)
  162. {
  163. int i;
  164. for (i = 0; i < NUM_ICON_SIZES; ++i) {
  165. BKE_previewimg_clear_single(prv, i);
  166. }
  167. }
  168. PreviewImage *BKE_previewimg_copy(const PreviewImage *prv)
  169. {
  170. PreviewImage *prv_img = NULL;
  171. int i;
  172. if (prv) {
  173. prv_img = MEM_dupallocN(prv);
  174. for (i = 0; i < NUM_ICON_SIZES; ++i) {
  175. if (prv->rect[i]) {
  176. prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
  177. }
  178. prv_img->gputexture[i] = NULL;
  179. }
  180. }
  181. return prv_img;
  182. }
  183. /** Duplicate preview image from \a id and clear icon_id, to be used by datablock copy functions. */
  184. void BKE_previewimg_id_copy(ID *new_id, const ID *old_id)
  185. {
  186. PreviewImage **old_prv_p = BKE_previewimg_id_get_p(old_id);
  187. PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id);
  188. if (old_prv_p && *old_prv_p) {
  189. BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p));
  190. // const int new_icon_id = get_next_free_id();
  191. // if (new_icon_id == 0) {
  192. // return; /* Failure. */
  193. // }
  194. *new_prv_p = BKE_previewimg_copy(*old_prv_p);
  195. new_id->icon_id = (*new_prv_p)->icon_id = 0;
  196. }
  197. }
  198. PreviewImage **BKE_previewimg_id_get_p(const ID *id)
  199. {
  200. switch (GS(id->name)) {
  201. #define ID_PRV_CASE(id_code, id_struct) case id_code: { return &((id_struct *)id)->preview; } ((void)0)
  202. ID_PRV_CASE(ID_MA, Material);
  203. ID_PRV_CASE(ID_TE, Tex);
  204. ID_PRV_CASE(ID_WO, World);
  205. ID_PRV_CASE(ID_LA, Lamp);
  206. ID_PRV_CASE(ID_IM, Image);
  207. ID_PRV_CASE(ID_BR, Brush);
  208. ID_PRV_CASE(ID_OB, Object);
  209. ID_PRV_CASE(ID_GR, Group);
  210. ID_PRV_CASE(ID_SCE, Scene);
  211. #undef ID_PRV_CASE
  212. }
  213. return NULL;
  214. }
  215. void BKE_previewimg_id_free(ID *id)
  216. {
  217. PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
  218. if (prv_p) {
  219. BKE_previewimg_free(prv_p);
  220. }
  221. }
  222. PreviewImage *BKE_previewimg_id_ensure(ID *id)
  223. {
  224. PreviewImage **prv_p = BKE_previewimg_id_get_p(id);
  225. if (prv_p) {
  226. if (*prv_p == NULL) {
  227. *prv_p = BKE_previewimg_create();
  228. }
  229. return *prv_p;
  230. }
  231. return NULL;
  232. }
  233. PreviewImage *BKE_previewimg_cached_get(const char *name)
  234. {
  235. return BLI_ghash_lookup(gCachedPreviews, name);
  236. }
  237. /**
  238. * Generate an empty PreviewImage, if not yet existing.
  239. */
  240. PreviewImage *BKE_previewimg_cached_ensure(const char *name)
  241. {
  242. PreviewImage *prv = NULL;
  243. void **key_p, **prv_p;
  244. if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) {
  245. *key_p = BLI_strdup(name);
  246. *prv_p = BKE_previewimg_create();
  247. }
  248. prv = *prv_p;
  249. BLI_assert(prv);
  250. return prv;
  251. }
  252. /**
  253. * Generate a PreviewImage from given file path, using thumbnails management, if not yet existing.
  254. */
  255. PreviewImage *BKE_previewimg_cached_thumbnail_read(
  256. const char *name, const char *path, const int source, bool force_update)
  257. {
  258. PreviewImage *prv = NULL;
  259. void **prv_p;
  260. prv_p = BLI_ghash_lookup_p(gCachedPreviews, name);
  261. if (prv_p) {
  262. prv = *prv_p;
  263. BLI_assert(prv);
  264. }
  265. if (prv && force_update) {
  266. const char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
  267. if (((int)prv_deferred_data[0] == source) && STREQ(&prv_deferred_data[1], path)) {
  268. /* If same path, no need to re-allocate preview, just clear it up. */
  269. BKE_previewimg_clear(prv);
  270. }
  271. else {
  272. BKE_previewimg_free(&prv);
  273. }
  274. }
  275. if (!prv) {
  276. /* We pack needed data for lazy loading (source type, in a single char, and path). */
  277. const size_t deferred_data_size = strlen(path) + 2;
  278. char *deferred_data;
  279. prv = previewimg_create_ex(deferred_data_size);
  280. deferred_data = PRV_DEFERRED_DATA(prv);
  281. deferred_data[0] = source;
  282. memcpy(&deferred_data[1], path, deferred_data_size - 1);
  283. force_update = true;
  284. }
  285. if (force_update) {
  286. if (prv_p) {
  287. *prv_p = prv;
  288. }
  289. else {
  290. BLI_ghash_insert(gCachedPreviews, BLI_strdup(name), prv);
  291. }
  292. }
  293. return prv;
  294. }
  295. void BKE_previewimg_cached_release_pointer(PreviewImage *prv)
  296. {
  297. if (prv) {
  298. if (prv->tag & PRV_TAG_DEFFERED_RENDERING) {
  299. /* We cannot delete the preview while it is being loaded in another thread... */
  300. prv->tag |= PRV_TAG_DEFFERED_DELETE;
  301. return;
  302. }
  303. if (prv->icon_id) {
  304. BKE_icon_delete(prv->icon_id);
  305. }
  306. BKE_previewimg_freefunc(prv);
  307. }
  308. }
  309. void BKE_previewimg_cached_release(const char *name)
  310. {
  311. PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN);
  312. BKE_previewimg_cached_release_pointer(prv);
  313. }
  314. /** Handle deferred (lazy) loading/generation of preview image, if needed.
  315. * For now, only used with file thumbnails. */
  316. void BKE_previewimg_ensure(PreviewImage *prv, const int size)
  317. {
  318. if ((prv->tag & PRV_TAG_DEFFERED) != 0) {
  319. const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]);
  320. const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]);
  321. if (do_icon || do_preview) {
  322. ImBuf *thumb;
  323. char *prv_deferred_data = PRV_DEFERRED_DATA(prv);
  324. int source = prv_deferred_data[0];
  325. char *path = &prv_deferred_data[1];
  326. int icon_w, icon_h;
  327. thumb = IMB_thumb_manage(path, THB_LARGE, source);
  328. if (thumb) {
  329. /* PreviewImage assumes premultiplied alhpa... */
  330. IMB_premultiply_alpha(thumb);
  331. if (do_preview) {
  332. prv->w[ICON_SIZE_PREVIEW] = thumb->x;
  333. prv->h[ICON_SIZE_PREVIEW] = thumb->y;
  334. prv->rect[ICON_SIZE_PREVIEW] = MEM_dupallocN(thumb->rect);
  335. prv->flag[ICON_SIZE_PREVIEW] &= ~(PRV_CHANGED | PRV_USER_EDITED);
  336. }
  337. if (do_icon) {
  338. if (thumb->x > thumb->y) {
  339. icon_w = ICON_RENDER_DEFAULT_HEIGHT;
  340. icon_h = (thumb->y * icon_w) / thumb->x + 1;
  341. }
  342. else if (thumb->x < thumb->y) {
  343. icon_h = ICON_RENDER_DEFAULT_HEIGHT;
  344. icon_w = (thumb->x * icon_h) / thumb->y + 1;
  345. }
  346. else {
  347. icon_w = icon_h = ICON_RENDER_DEFAULT_HEIGHT;
  348. }
  349. IMB_scaleImBuf(thumb, icon_w, icon_h);
  350. prv->w[ICON_SIZE_ICON] = icon_w;
  351. prv->h[ICON_SIZE_ICON] = icon_h;
  352. prv->rect[ICON_SIZE_ICON] = MEM_dupallocN(thumb->rect);
  353. prv->flag[ICON_SIZE_ICON] &= ~(PRV_CHANGED | PRV_USER_EDITED);
  354. }
  355. IMB_freeImBuf(thumb);
  356. }
  357. }
  358. }
  359. }
  360. void BKE_icon_changed(int id)
  361. {
  362. Icon *icon = NULL;
  363. if (!id || G.background) return;
  364. icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id));
  365. if (icon) {
  366. PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj);
  367. /* all previews changed */
  368. if (prv) {
  369. int i;
  370. for (i = 0; i < NUM_ICON_SIZES; ++i) {
  371. prv->flag[i] |= PRV_CHANGED;
  372. prv->changed_timestamp[i]++;
  373. }
  374. }
  375. }
  376. }
  377. static int icon_id_ensure_create_icon(struct ID *id)
  378. {
  379. Icon *new_icon = NULL;
  380. new_icon = MEM_mallocN(sizeof(Icon), __func__);
  381. new_icon->obj = id;
  382. new_icon->type = GS(id->name);
  383. /* next two lines make sure image gets created */
  384. new_icon->drawinfo = NULL;
  385. new_icon->drawinfo_free = NULL;
  386. BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon);
  387. return id->icon_id;
  388. }
  389. int BKE_icon_id_ensure(struct ID *id)
  390. {
  391. if (!id || G.background)
  392. return 0;
  393. if (id->icon_id)
  394. return id->icon_id;
  395. id->icon_id = get_next_free_id();
  396. if (!id->icon_id) {
  397. printf("%s: Internal error - not enough IDs\n", __func__);
  398. return 0;
  399. }
  400. /* Ensure we synchronize ID icon_id with its previewimage if it has one. */
  401. PreviewImage **p_prv = BKE_previewimg_id_get_p(id);
  402. if (p_prv && *p_prv) {
  403. BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id));
  404. (*p_prv)->icon_id = id->icon_id;
  405. }
  406. return icon_id_ensure_create_icon(id);
  407. }
  408. /**
  409. * Return icon id of given preview, or create new icon if not found.
  410. */
  411. int BKE_icon_preview_ensure(ID *id, PreviewImage *preview)
  412. {
  413. Icon *new_icon = NULL;
  414. if (!preview || G.background)
  415. return 0;
  416. if (id) {
  417. BLI_assert(BKE_previewimg_id_ensure(id) == preview);
  418. }
  419. if (preview->icon_id) {
  420. BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id);
  421. return preview->icon_id;
  422. }
  423. if (id && id->icon_id) {
  424. preview->icon_id = id->icon_id;
  425. return preview->icon_id;
  426. }
  427. preview->icon_id = get_next_free_id();
  428. if (!preview->icon_id) {
  429. printf("%s: Internal error - not enough IDs\n", __func__);
  430. return 0;
  431. }
  432. /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */
  433. if (id) {
  434. id->icon_id = preview->icon_id;
  435. return icon_id_ensure_create_icon(id);
  436. }
  437. new_icon = MEM_mallocN(sizeof(Icon), __func__);
  438. new_icon->obj = preview;
  439. new_icon->type = 0; /* Special, tags as non-ID icon/preview. */
  440. /* next two lines make sure image gets created */
  441. new_icon->drawinfo = NULL;
  442. new_icon->drawinfo_free = NULL;
  443. BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(preview->icon_id), new_icon);
  444. return preview->icon_id;
  445. }
  446. Icon *BKE_icon_get(int icon_id)
  447. {
  448. Icon *icon = NULL;
  449. icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id));
  450. if (!icon) {
  451. printf("%s: Internal error, no icon for icon ID: %d\n", __func__, icon_id);
  452. return NULL;
  453. }
  454. return icon;
  455. }
  456. void BKE_icon_set(int icon_id, struct Icon *icon)
  457. {
  458. void **val_p;
  459. if (BLI_ghash_ensure_p(gIcons, SET_INT_IN_POINTER(icon_id), &val_p)) {
  460. printf("%s: Internal error, icon already set: %d\n", __func__, icon_id);
  461. return;
  462. }
  463. *val_p = icon;
  464. }
  465. void BKE_icon_id_delete(struct ID *id)
  466. {
  467. if (!id->icon_id) return; /* no icon defined for library object */
  468. BLI_ghash_remove(gIcons, SET_INT_IN_POINTER(id->icon_id), NULL, icon_free);
  469. id->icon_id = 0;
  470. }
  471. /**
  472. * Remove icon and free data.
  473. */
  474. void BKE_icon_delete(int icon_id)
  475. {
  476. Icon *icon;
  477. if (!icon_id) return; /* no icon defined for library object */
  478. icon = BLI_ghash_popkey(gIcons, SET_INT_IN_POINTER(icon_id), NULL);
  479. if (icon) {
  480. if (icon->type) {
  481. ((ID *)(icon->obj))->icon_id = 0;
  482. }
  483. else {
  484. ((PreviewImage *)(icon->obj))->icon_id = 0;
  485. }
  486. icon_free(icon);
  487. }
  488. }