Bugfix #25720
[blender.git] / source / blender / editors / interface / interface_icons.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributors: Blender Foundation, full recode
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <math.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #ifndef WIN32
33 #include <unistd.h>
34 #else
35 #include <io.h>
36 #include <direct.h>
37 #include "BLI_winstuff.h"
38 #endif   
39 #include "MEM_guardedalloc.h"
40
41 #include "GPU_extensions.h"
42
43 #include "BLI_math.h"
44 #include "BLI_blenlib.h"
45 #include "BLI_storage_types.h"
46 #include "BLI_utildefines.h"
47
48 #include "DNA_brush_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_space_types.h"
52
53 #include "RNA_access.h"
54 #include "RNA_enum_types.h"
55
56 #include "BKE_context.h"
57 #include "BKE_global.h"
58 #include "BKE_icons.h"
59 #include "BKE_utildefines.h"
60
61 #include "IMB_imbuf.h"
62 #include "IMB_imbuf_types.h"
63
64 #include "BIF_gl.h"
65 #include "BIF_glutil.h"
66
67 #include "ED_datafiles.h"
68 #include "ED_render.h"
69
70 #include "UI_interface.h"
71 #include "UI_interface_icons.h"
72
73 #include "interface_intern.h"
74
75
76 #define ICON_IMAGE_W            600
77 #define ICON_IMAGE_H            640
78
79 #define ICON_GRID_COLS          26
80 #define ICON_GRID_ROWS          30
81
82 #define ICON_GRID_MARGIN        5
83 #define ICON_GRID_W             16
84 #define ICON_GRID_H             16
85
86 typedef struct IconImage {
87         int w;
88         int h;
89         unsigned int *rect; 
90 } IconImage;
91
92 typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
93
94 #define ICON_TYPE_PREVIEW       0
95 #define ICON_TYPE_TEXTURE       1
96 #define ICON_TYPE_BUFFER        2
97 #define ICON_TYPE_VECTOR        3
98
99 typedef struct DrawInfo {
100         int type;
101
102         union {
103                 /* type specific data */
104                 struct {
105                         VectorDrawFunc func;
106                 } vector;
107                 struct {
108                         IconImage* image;
109                 } buffer;
110                 struct {
111                         int x, y, w, h;
112                 } texture;
113         } data;
114 } DrawInfo;
115
116 typedef struct IconTexture {
117         GLuint id;
118         int w;
119         int h;
120         float invw;
121         float invh;
122 } IconTexture;
123
124 /* ******************* STATIC LOCAL VARS ******************* */
125 /* static here to cache results of icon directory scan, so it's not 
126  * scanning the filesystem each time the menu is drawn */
127 static struct ListBase iconfilelist = {0, 0};
128 static IconTexture icongltex = {0, 0, 0, 0.0f, 0.0f};
129
130 /* **************************************************** */
131
132 static void def_internal_icon(ImBuf *bbuf, int icon_id, int xofs, int yofs, int size, int type)
133 {
134         Icon *new_icon = NULL;
135         IconImage *iimg = NULL;
136         DrawInfo *di;
137         int y = 0;
138         int imgsize = 0;
139
140         new_icon = MEM_callocN(sizeof(Icon), "texicon");
141
142         new_icon->obj = 0; /* icon is not for library object */
143         new_icon->type = 0;     
144
145         di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
146         di->type= type;
147
148         if(type == ICON_TYPE_TEXTURE) {
149                 di->data.texture.x= xofs;
150                 di->data.texture.y= yofs;
151                 di->data.texture.w= size;
152                 di->data.texture.h= size;
153         }
154         else if(type == ICON_TYPE_BUFFER) {
155                 iimg = MEM_mallocN(sizeof(IconImage), "icon_img");
156                 iimg->rect = MEM_mallocN(size*size*sizeof(unsigned int), "icon_rect");
157                 iimg->w = size;
158                 iimg->h = size;
159
160                 /* Here we store the rect in the icon - same as before */
161                 imgsize = bbuf->x;
162                 for (y=0; y<size; y++) {
163                         memcpy(&iimg->rect[y*size], &bbuf->rect[(y+yofs)*imgsize+xofs], size*sizeof(int));
164                 }
165
166                 di->data.buffer.image = iimg;
167         }
168
169         new_icon->drawinfo_free = UI_icons_free_drawinfo;
170         new_icon->drawinfo = di;
171
172         BKE_icon_set(icon_id, new_icon);
173 }
174
175 static void def_internal_vicon( int icon_id, VectorDrawFunc drawFunc)
176 {
177         Icon *new_icon = NULL;
178         DrawInfo* di;
179
180         new_icon = MEM_callocN(sizeof(Icon), "texicon");
181
182         new_icon->obj = 0; /* icon is not for library object */
183         new_icon->type = 0;
184
185         di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
186         di->type= ICON_TYPE_VECTOR;
187         di->data.vector.func =drawFunc;
188
189         new_icon->drawinfo_free = 0;
190         new_icon->drawinfo = di;
191
192         BKE_icon_set(icon_id, new_icon);
193 }
194
195 /* Vector Icon Drawing Routines */
196
197         /* Utilities */
198
199 static void viconutil_set_point(GLint pt[2], int x, int y)
200 {
201         pt[0] = x;
202         pt[1] = y;
203 }
204
205 static void viconutil_draw_tri(GLint (*pts)[2])
206 {
207         glBegin(GL_TRIANGLES);
208         glVertex2iv(pts[0]);
209         glVertex2iv(pts[1]);
210         glVertex2iv(pts[2]);
211         glEnd();
212 }
213
214 static void viconutil_draw_lineloop(GLint (*pts)[2], int numPoints)
215 {
216         int i;
217
218         glBegin(GL_LINE_LOOP);
219         for (i=0; i<numPoints; i++) {
220                 glVertex2iv(pts[i]);
221         }
222         glEnd();
223 }
224
225 static void viconutil_draw_lineloop_smooth(GLint (*pts)[2], int numPoints)
226 {
227         glEnable(GL_LINE_SMOOTH);
228         viconutil_draw_lineloop(pts, numPoints);
229         glDisable(GL_LINE_SMOOTH);
230 }
231
232 static void viconutil_draw_points(GLint (*pts)[2], int numPoints, int pointSize)
233 {
234         int i;
235
236         glBegin(GL_QUADS);
237         for (i=0; i<numPoints; i++) {
238                 int x = pts[i][0], y = pts[i][1];
239
240                 glVertex2i(x-pointSize,y-pointSize);
241                 glVertex2i(x+pointSize,y-pointSize);
242                 glVertex2i(x+pointSize,y+pointSize);
243                 glVertex2i(x-pointSize,y+pointSize);
244         }
245         glEnd();
246 }
247
248         /* Drawing functions */
249
250 static void vicon_x_draw(int x, int y, int w, int h, float alpha)
251 {
252         x += 3;
253         y += 3;
254         w -= 6;
255         h -= 6;
256
257         glEnable( GL_LINE_SMOOTH );
258
259         glLineWidth(2.5);
260         
261         glColor4f(0.0, 0.0, 0.0, alpha);
262         glBegin(GL_LINES);
263         glVertex2i(x  ,y  );
264         glVertex2i(x+w,y+h);
265         glVertex2i(x+w,y  );
266         glVertex2i(x  ,y+h);
267         glEnd();
268
269         glLineWidth(1.0);
270         
271         glDisable( GL_LINE_SMOOTH );
272 }
273
274 static void vicon_view3d_draw(int x, int y, int w, int h, float alpha)
275 {
276         int cx = x + w/2;
277         int cy = y + h/2;
278         int d = MAX2(2, h/3);
279
280         glColor4f(0.5, 0.5, 0.5, alpha);
281         glBegin(GL_LINES);
282         glVertex2i(x  , cy-d);
283         glVertex2i(x+w, cy-d);
284         glVertex2i(x  , cy+d);
285         glVertex2i(x+w, cy+d);
286
287         glVertex2i(cx-d, y  );
288         glVertex2i(cx-d, y+h);
289         glVertex2i(cx+d, y  );
290         glVertex2i(cx+d, y+h);
291         glEnd();
292         
293         glColor4f(0.0, 0.0, 0.0, alpha);
294         glBegin(GL_LINES);
295         glVertex2i(x  , cy);
296         glVertex2i(x+w, cy);
297         glVertex2i(cx, y  );
298         glVertex2i(cx, y+h);
299         glEnd();
300 }
301
302 static void vicon_edit_draw(int x, int y, int w, int h, float alpha)
303 {
304         GLint pts[4][2];
305
306         viconutil_set_point(pts[0], x+3  , y+3  );
307         viconutil_set_point(pts[1], x+w-3, y+3  );
308         viconutil_set_point(pts[2], x+w-3, y+h-3);
309         viconutil_set_point(pts[3], x+3  , y+h-3);
310
311         glColor4f(0.0, 0.0, 0.0, alpha);
312         viconutil_draw_lineloop(pts, 4);
313
314         glColor3f(1, 1, 0.0);
315         viconutil_draw_points(pts, 4, 1);
316 }
317
318 static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha)
319 {
320         GLint pts[3][2];
321
322         viconutil_set_point(pts[0], x+w/2, y+h-2);
323         viconutil_set_point(pts[1], x+3, y+4);
324         viconutil_set_point(pts[2], x+w-3, y+4);
325
326         glColor4f(0.5, 0.5, 0.5, alpha);
327         viconutil_draw_tri(pts);
328
329         glColor4f(0.0, 0.0, 0.0, 1);
330         viconutil_draw_lineloop_smooth(pts, 3);
331
332         glColor3f(1, 1, 0.0);
333         viconutil_draw_points(pts, 3, 1);
334 }
335
336 static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float UNUSED(alpha))
337 {
338         GLint pts[3][2];
339
340         viconutil_set_point(pts[0], x+w/2, y+h-2);
341         viconutil_set_point(pts[1], x+3, y+4);
342         viconutil_set_point(pts[2], x+w-3, y+4);
343
344         glColor4f(0.0f, 0.0f, 0.0f, 1);
345         viconutil_draw_lineloop_smooth(pts, 3);
346
347         glColor3f(.9f, .9f, .9f);
348         viconutil_draw_points(pts, 3, 1);
349 }
350
351 static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
352 {
353         GLint pts[3][2];
354         int cx = x+w/2;
355         int cy = y+w/2;
356         int d = w/3, d2 = w/5;
357
358         viconutil_set_point(pts[0], cx-d2, cy+d);
359         viconutil_set_point(pts[1], cx-d2, cy-d);
360         viconutil_set_point(pts[2], cx+d2, cy);
361
362         glShadeModel(GL_SMOOTH);
363         glBegin(GL_TRIANGLES);
364         glColor4f(0.8f, 0.8f, 0.8f, alpha);
365         glVertex2iv(pts[0]);
366         glVertex2iv(pts[1]);
367         glColor4f(0.3f, 0.3f, 0.3f, alpha);
368         glVertex2iv(pts[2]);
369         glEnd();
370         glShadeModel(GL_FLAT);
371
372         glColor4f(0.0f, 0.0f, 0.0f, 1);
373         viconutil_draw_lineloop_smooth(pts, 3);
374 }
375
376 static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha)
377 {
378         GLint pts[3][2];
379         int cx = x+w/2-4;
380         int cy = y+w/2;
381         int d = w/5, d2 = w/7;
382
383         viconutil_set_point(pts[0], cx-d2, cy+d);
384         viconutil_set_point(pts[1], cx-d2, cy-d);
385         viconutil_set_point(pts[2], cx+d2, cy);
386
387         glColor4f(0.2f, 0.2f, 0.2f, alpha);
388
389         glShadeModel(GL_SMOOTH);
390         glBegin(GL_TRIANGLES);
391         glVertex2iv(pts[0]);
392         glVertex2iv(pts[1]);
393         glVertex2iv(pts[2]);
394         glEnd();
395         glShadeModel(GL_FLAT);
396 }
397
398 static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha)
399 {
400         GLint pts[3][2];
401         int cx = x+w/2;
402         int cy = y+w/2;
403         int d = w/3, d2 = w/5;
404
405         viconutil_set_point(pts[0], cx+d, cy+d2);
406         viconutil_set_point(pts[1], cx-d, cy+d2);
407         viconutil_set_point(pts[2], cx, cy-d2);
408
409         glShadeModel(GL_SMOOTH);
410         glBegin(GL_TRIANGLES);
411         glColor4f(0.8f, 0.8f, 0.8f, alpha);
412         glVertex2iv(pts[0]);
413         glVertex2iv(pts[1]);
414         glColor4f(0.3f, 0.3f, 0.3f, alpha);
415         glVertex2iv(pts[2]);
416         glEnd();
417         glShadeModel(GL_FLAT);
418
419         glColor4f(0.0f, 0.0f, 0.0f, 1);
420         viconutil_draw_lineloop_smooth(pts, 3);
421 }
422
423 static void vicon_move_up_draw(int x, int y, int w, int h, float UNUSED(alpha))
424 {
425         int d=-2;
426
427         glEnable(GL_LINE_SMOOTH);
428         glLineWidth(1);
429         glColor3f(0.0, 0.0, 0.0);
430
431         glBegin(GL_LINE_STRIP);
432         glVertex2i(x+w/2-d*2, y+h/2+d);
433         glVertex2i(x+w/2, y+h/2-d + 1);
434         glVertex2i(x+w/2+d*2, y+h/2+d);
435         glEnd();
436
437         glLineWidth(1.0);
438         glDisable(GL_LINE_SMOOTH);
439 }
440
441 static void vicon_move_down_draw(int x, int y, int w, int h, float UNUSED(alpha))
442 {
443         int d=2;
444
445         glEnable(GL_LINE_SMOOTH);
446         glLineWidth(1);
447         glColor3f(0.0, 0.0, 0.0);
448
449         glBegin(GL_LINE_STRIP);
450         glVertex2i(x+w/2-d*2, y+h/2+d);
451         glVertex2i(x+w/2, y+h/2-d - 1);
452         glVertex2i(x+w/2+d*2, y+h/2+d);
453         glEnd();
454
455         glLineWidth(1.0);
456         glDisable(GL_LINE_SMOOTH);
457 }
458
459 static void init_brush_icons(void)
460 {
461
462 #define INIT_BRUSH_ICON(icon_id, name)                                       \
463         bbuf = IMB_ibImageFromMemory((unsigned char*)datatoc_ ##name## _png, \
464                                      datatoc_ ##name## _png_size, IB_rect);  \
465         def_internal_icon(bbuf, icon_id, 0, 0, w, ICON_TYPE_BUFFER);         \
466         IMB_freeImBuf(bbuf);
467         // end INIT_BRUSH_ICON
468
469         ImBuf *bbuf;
470         const int w = 96;
471
472         INIT_BRUSH_ICON(ICON_BRUSH_ADD, add);
473         INIT_BRUSH_ICON(ICON_BRUSH_BLOB, blob);
474         INIT_BRUSH_ICON(ICON_BRUSH_BLUR, blur);
475         INIT_BRUSH_ICON(ICON_BRUSH_CLAY, clay);
476         INIT_BRUSH_ICON(ICON_BRUSH_CLONE, clone);
477         INIT_BRUSH_ICON(ICON_BRUSH_CREASE, crease);
478         INIT_BRUSH_ICON(ICON_BRUSH_DARKEN, darken);
479         INIT_BRUSH_ICON(ICON_BRUSH_SCULPT_DRAW, draw);
480         INIT_BRUSH_ICON(ICON_BRUSH_FILL, fill);
481         INIT_BRUSH_ICON(ICON_BRUSH_FLATTEN, flatten);
482         INIT_BRUSH_ICON(ICON_BRUSH_GRAB, grab);
483         INIT_BRUSH_ICON(ICON_BRUSH_INFLATE, inflate);
484         INIT_BRUSH_ICON(ICON_BRUSH_LAYER, layer);
485         INIT_BRUSH_ICON(ICON_BRUSH_LIGHTEN, lighten);
486         INIT_BRUSH_ICON(ICON_BRUSH_MIX, mix);
487         INIT_BRUSH_ICON(ICON_BRUSH_MULTIPLY, multiply);
488         INIT_BRUSH_ICON(ICON_BRUSH_NUDGE, nudge);
489         INIT_BRUSH_ICON(ICON_BRUSH_PINCH, pinch);
490         INIT_BRUSH_ICON(ICON_BRUSH_SCRAPE, scrape);
491         INIT_BRUSH_ICON(ICON_BRUSH_SMEAR, smear);
492         INIT_BRUSH_ICON(ICON_BRUSH_SMOOTH, smooth);
493         INIT_BRUSH_ICON(ICON_BRUSH_SNAKE_HOOK, snake_hook);
494         INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften);
495         INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract);
496         INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw);
497         INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
498         INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
499         INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
500
501 #undef INIT_BRUSH_ICON
502 }
503
504 static void init_internal_icons(void)
505 {
506         bTheme *btheme= U.themes.first;
507         ImBuf *bbuf= NULL;
508         int x, y, icontype;
509         char iconfilestr[FILE_MAXDIR+FILE_MAXFILE];
510         
511         if ((btheme!=NULL) && btheme->tui.iconfile[0]) {
512                 char *datadir= BLI_get_folder(BLENDER_DATAFILES, NULL);
513                 if (datadir) {
514                         BLI_make_file_string("/", iconfilestr, datadir, btheme->tui.iconfile);
515                         
516                         if (BLI_exists(iconfilestr)) {
517                                 bbuf = IMB_loadiffname(iconfilestr, IB_rect);
518                                 if(bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H) {
519                                         if (G.f & G_DEBUG)
520                                                 printf("\n***WARNING***\nIcons file %s too small.\nUsing built-in Icons instead\n", iconfilestr);
521                                         IMB_freeImBuf(bbuf);
522                                         bbuf= NULL;
523                                 }
524                         }
525                 }
526         }
527         if(bbuf==NULL)
528                 bbuf = IMB_ibImageFromMemory((unsigned char*)datatoc_blenderbuttons, datatoc_blenderbuttons_size, IB_rect);
529
530         if(bbuf) {
531                 /* free existing texture if any */
532                 if(icongltex.id) {
533                         glDeleteTextures(1, &icongltex.id);
534                         icongltex.id= 0;
535                 }
536
537                 /* we only use a texture for cards with non-power of two */
538                 if(GPU_non_power_of_two_support()) {
539                         glGenTextures(1, &icongltex.id);
540
541                         if(icongltex.id) {
542                                 icongltex.w = bbuf->x;
543                                 icongltex.h = bbuf->y;
544                                 icongltex.invw = 1.0f/bbuf->x;
545                                 icongltex.invh = 1.0f/bbuf->y;
546
547                                 glBindTexture(GL_TEXTURE_2D, icongltex.id);
548                                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bbuf->x, bbuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, bbuf->rect);
549                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
550                                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
551                                 glBindTexture(GL_TEXTURE_2D, 0);
552
553                                 if(glGetError() == GL_OUT_OF_MEMORY) {
554                                         glDeleteTextures(1, &icongltex.id);
555                                         icongltex.id= 0;
556                                 }
557                         }
558                 }
559         }
560
561         if(icongltex.id)
562                 icontype= ICON_TYPE_TEXTURE;
563         else
564                 icontype= ICON_TYPE_BUFFER;
565         
566         if(bbuf) {
567                 for (y=0; y<ICON_GRID_ROWS; y++) {
568                         for (x=0; x<ICON_GRID_COLS; x++) {
569                                 def_internal_icon(bbuf, BIFICONID_FIRST + y*ICON_GRID_COLS + x,
570                                         x*(ICON_GRID_W+ICON_GRID_MARGIN)+ICON_GRID_MARGIN,
571                                         y*(ICON_GRID_H+ICON_GRID_MARGIN)+ICON_GRID_MARGIN, ICON_GRID_W,
572                                         icontype);
573                         }
574                 }
575         }
576
577         def_internal_vicon(VICO_VIEW3D_VEC, vicon_view3d_draw);
578         def_internal_vicon(VICO_EDIT_VEC, vicon_edit_draw);
579         def_internal_vicon(VICO_EDITMODE_DEHLT, vicon_editmode_dehlt_draw);
580         def_internal_vicon(VICO_EDITMODE_HLT, vicon_editmode_hlt_draw);
581         def_internal_vicon(VICO_DISCLOSURE_TRI_RIGHT_VEC, vicon_disclosure_tri_right_draw);
582         def_internal_vicon(VICO_DISCLOSURE_TRI_DOWN_VEC, vicon_disclosure_tri_down_draw);
583         def_internal_vicon(VICO_MOVE_UP_VEC, vicon_move_up_draw);
584         def_internal_vicon(VICO_MOVE_DOWN_VEC, vicon_move_down_draw);
585         def_internal_vicon(VICO_X_VEC, vicon_x_draw);
586         def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw);
587
588         IMB_freeImBuf(bbuf);
589 }
590
591
592 static void init_iconfile_list(struct ListBase *list)
593 {
594         IconFile *ifile;
595         ImBuf *bbuf= NULL;
596         struct direntry *dir;
597         int restoredir = 1; /* restore to current directory */
598         int totfile, i, index=1;
599         int ifilex, ifiley;
600         char icondirstr[FILE_MAX];
601         char iconfilestr[FILE_MAX+16]; /* allow 256 chars for file+dir */
602         char olddir[FILE_MAX];
603         char *datadir= NULL;
604
605         list->first = list->last = NULL;
606         datadir = BLI_get_folder(BLENDER_DATAFILES, NULL);
607
608         if (!datadir) return;
609
610         BLI_make_file_string("/", icondirstr, datadir, "");
611         
612         if(BLI_exists(icondirstr)==0)
613                 return;
614         
615         /* since BLI_getdir changes the current working directory, restore it 
616            back to old value afterwards */
617         if(!BLI_getwdN(olddir)) 
618                 restoredir = 0;
619         totfile = BLI_getdir(icondirstr, &dir);
620         if (restoredir && !chdir(olddir)) {} /* fix warning about checking return value */
621
622         for(i=0; i<totfile; i++) {
623                 if( (dir[i].type & S_IFREG) ) {
624                         char *filename = dir[i].relname;
625                         
626                         if(BLI_testextensie(filename, ".png")) {
627
628                                 /* check to see if the image is the right size, continue if not */
629                                 /* copying strings here should go ok, assuming that we never get back
630                                    a complete path to file longer than 256 chars */
631                                 sprintf(iconfilestr, "%s/%s", icondirstr, filename);
632                                 if(BLI_exists(iconfilestr))
633                                         bbuf= IMB_loadiffname(iconfilestr, IB_rect);
634                                 else
635                                         bbuf= NULL;
636
637
638                                 if(bbuf) {
639                                         ifilex = bbuf->x;
640                                         ifiley = bbuf->y;
641                                         IMB_freeImBuf(bbuf);
642                                 }
643                                 else {
644                                         ifilex= ifiley= 0;
645                                 }
646                                 
647                                 /* bad size or failed to load */
648                                 if ((ifilex != ICON_IMAGE_W) || (ifiley != ICON_IMAGE_H))
649                                         continue;
650
651                                 /* found a potential icon file, so make an entry for it in the cache list */
652                                 ifile = MEM_callocN(sizeof(IconFile), "IconFile");
653                                 
654                                 BLI_strncpy(ifile->filename, filename, sizeof(ifile->filename));
655                                 ifile->index = index;
656
657                                 BLI_addtail(list, ifile);
658                                 
659                                 index++;
660                         }
661                 }
662         }
663         
664         /* free temporary direntry structure that's been created by BLI_getdir() */
665         i= totfile-1;
666         
667         for(; i>=0; i--){
668                 MEM_freeN(dir[i].relname);
669                 MEM_freeN(dir[i].path);
670                 if (dir[i].string) MEM_freeN(dir[i].string);
671         }
672         free(dir);
673         dir= 0;
674 }
675
676 static void free_iconfile_list(struct ListBase *list)
677 {
678         IconFile *ifile=NULL, *next_ifile=NULL;
679         
680         for(ifile=list->first; ifile; ifile=next_ifile) {
681                 next_ifile = ifile->next;
682                 BLI_freelinkN(list, ifile);
683         }
684 }
685
686 int UI_iconfile_get_index(const char *filename)
687 {
688         IconFile *ifile;
689         ListBase *list=&(iconfilelist);
690         
691         for(ifile=list->first; ifile; ifile=ifile->next) {
692                 if ( BLI_streq(filename, ifile->filename)) {
693                         return ifile->index;
694                 }
695         }
696         
697         return 0;
698 }
699
700 ListBase *UI_iconfile_list(void)
701 {
702         ListBase *list=&(iconfilelist);
703         
704         return list;
705 }
706
707
708 void UI_icons_free()
709 {
710         if(icongltex.id) {
711                 glDeleteTextures(1, &icongltex.id);
712                 icongltex.id= 0;
713         }
714
715         free_iconfile_list(&iconfilelist);
716         BKE_icons_free();
717 }
718
719 void UI_icons_free_drawinfo(void *drawinfo)
720 {
721         DrawInfo *di = drawinfo;
722
723         if(di) {
724                 if(di->type == ICON_TYPE_BUFFER) {
725                         if(di->data.buffer.image) {
726                                 MEM_freeN(di->data.buffer.image->rect);
727                                 MEM_freeN(di->data.buffer.image);
728                         }
729                 }
730
731                 MEM_freeN(di);
732         }
733 }
734
735 static DrawInfo *icon_create_drawinfo(void)
736 {
737         DrawInfo *di = NULL;
738
739         di = MEM_callocN(sizeof(DrawInfo), "di_icon");
740         di->type= ICON_TYPE_PREVIEW;
741
742         return di;
743 }
744
745 int UI_icon_get_width(int icon_id)
746 {
747         Icon *icon = NULL;
748         DrawInfo *di = NULL;
749
750         icon = BKE_icon_get(icon_id);
751         
752         if (icon==ICON_NULL) {
753                 if (G.f & G_DEBUG)
754                         printf("UI_icon_get_width: Internal error, no icon for icon ID: %d\n", icon_id);
755                 return 0;
756         }
757         
758         di = (DrawInfo *)icon->drawinfo;
759         if (!di) {
760                 di = icon_create_drawinfo();
761                 icon->drawinfo = di;
762         }
763
764         if (di)
765                 return ICON_DEFAULT_WIDTH;
766
767         return 0;
768 }
769
770 int UI_icon_get_height(int icon_id)
771 {
772         Icon *icon = NULL;
773         DrawInfo *di = NULL;
774
775         icon = BKE_icon_get(icon_id);
776         
777         if (icon==ICON_NULL) {
778                 if (G.f & G_DEBUG)
779                         printf("UI_icon_get_height: Internal error, no icon for icon ID: %d\n", icon_id);
780                 return 0;
781         }
782         
783         di = (DrawInfo*)icon->drawinfo;
784
785         if (!di) {
786                 di = icon_create_drawinfo();
787                 icon->drawinfo = di;
788         }
789         
790         if (di)
791                 return ICON_DEFAULT_HEIGHT;
792
793         return 0;
794 }
795
796 void UI_icons_init(int first_dyn_id)
797 {
798         init_iconfile_list(&iconfilelist);
799         BKE_icons_init(first_dyn_id);
800         init_internal_icons();
801         init_brush_icons();
802 }
803
804 /* Render size for preview images at level miplevel */
805 static int preview_render_size(int miplevel)
806 {
807         switch (miplevel) {
808                 case 0: return 32;
809                 case 1: return PREVIEW_DEFAULT_HEIGHT;
810         }
811         return 0;
812 }
813
814 static void icon_create_mipmap(struct PreviewImage* prv_img, int miplevel) 
815 {
816         unsigned int size = preview_render_size(miplevel);
817
818         if (!prv_img) {
819                 if (G.f & G_DEBUG)
820                         printf("Error: requested preview image does not exist");
821         }
822         if (!prv_img->rect[miplevel]) {
823                 prv_img->w[miplevel] = size;
824                 prv_img->h[miplevel] = size;
825                 prv_img->changed[miplevel] = 1;
826                 prv_img->changed_timestamp[miplevel] = 0;
827                 prv_img->rect[miplevel] = MEM_callocN(size*size*sizeof(unsigned int), "prv_rect"); 
828         }
829 }
830
831 /* only called when icon has changed */
832 /* only call with valid pointer from UI_icon_draw */
833 static void icon_set_image(bContext *C, ID *id, PreviewImage* prv_img, int miplevel)
834 {
835         if (!prv_img) {
836                 if (G.f & G_DEBUG)
837                         printf("No preview image for this ID: %s\n", id->name);
838                 return;
839         }       
840
841         /* create the preview rect */
842         icon_create_mipmap(prv_img, miplevel);
843
844         ED_preview_icon_job(C, prv_img, id, prv_img->rect[miplevel],
845                 prv_img->w[miplevel], prv_img->h[miplevel]);
846 }
847
848 static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect), int rw, int rh, unsigned int *rect, float alpha, float *rgb, short is_preview)
849 {
850         ImBuf *ima= NULL;
851
852         /* sanity check */
853         if(w<=0 || h<=0 || w>2000 || h>2000) {
854                 printf("icon_draw_rect: icons are %i x %i pixels?\n", w, h);
855                 BLI_assert(!"invalid icon size");
856                 return;
857         }
858
859         /* modulate color */
860         if(alpha != 1.0f)
861                 glPixelTransferf(GL_ALPHA_SCALE, alpha);
862
863         if(rgb) {
864                 glPixelTransferf(GL_RED_SCALE, rgb[0]);
865                 glPixelTransferf(GL_GREEN_SCALE, rgb[1]);
866                 glPixelTransferf(GL_BLUE_SCALE, rgb[2]);
867         }
868
869         /* rect contains image in 'rendersize', we only scale if needed */
870         if(rw!=w && rh!=h) {
871                 /* first allocate imbuf for scaling and copy preview into it */
872                 ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
873                 memcpy(ima->rect, rect, rw*rh*sizeof(unsigned int));    
874                 IMB_scaleImBuf(ima, w, h); /* scale it */
875                 rect= ima->rect;
876         }
877
878         /* draw */
879         if(is_preview) {
880                 glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
881         }
882         else {
883                 glRasterPos2f(x, y);
884                 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
885         }
886
887         if(ima)
888                 IMB_freeImBuf(ima);
889
890         /* restore color */
891         if(alpha != 0.0f)
892                 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
893         
894         if(rgb) {
895                 glPixelTransferf(GL_RED_SCALE, 1.0f);
896                 glPixelTransferf(GL_GREEN_SCALE, 1.0f);
897                 glPixelTransferf(GL_BLUE_SCALE, 1.0f);
898         }
899 }
900
901 static void icon_draw_texture(float x, float y, float w, float h, int ix, int iy, int UNUSED(iw), int ih, float alpha, float *rgb)
902 {
903         float x1, x2, y1, y2;
904
905         if(rgb) glColor4f(rgb[0], rgb[1], rgb[2], alpha);
906         else glColor4f(1.0f, 1.0f, 1.0f, alpha);
907
908         x1= ix*icongltex.invw;
909         x2= (ix + ih)*icongltex.invw;
910         y1= iy*icongltex.invh;
911         y2= (iy + ih)*icongltex.invh;
912
913         glEnable(GL_TEXTURE_2D);
914         glBindTexture(GL_TEXTURE_2D, icongltex.id);
915
916         glBegin(GL_QUADS);
917         glTexCoord2f(x1, y1);
918         glVertex2f(x, y);
919
920         glTexCoord2f(x2, y1);
921         glVertex2f(x+w, y);
922
923         glTexCoord2f(x2, y2);
924         glVertex2f(x+w, y+h);
925
926         glTexCoord2f(x1, y2);
927         glVertex2f(x, y+h);
928         glEnd();
929
930         glBindTexture(GL_TEXTURE_2D, 0);
931         glDisable(GL_TEXTURE_2D);
932 }
933
934 /* Drawing size for preview images at level miplevel */
935 static int preview_size(int miplevel)
936 {
937         switch (miplevel) {
938                 case 0: return ICON_DEFAULT_HEIGHT;
939                 case 1: return PREVIEW_DEFAULT_HEIGHT;
940         }
941         return 0;
942 }
943
944 static void icon_draw_size(float x, float y, int icon_id, float aspect, float alpha, float *rgb, int miplevel, int draw_size, int UNUSED(nocreate), int is_preview)
945 {
946         Icon *icon = NULL;
947         DrawInfo *di = NULL;
948         IconImage *iimg;
949         int w, h;
950         
951         icon = BKE_icon_get(icon_id);
952         
953         if (icon==ICON_NULL) {
954                 if (G.f & G_DEBUG)
955                         printf("icon_draw_mipmap: Internal error, no icon for icon ID: %d\n", icon_id);
956                 return;
957         }
958
959         di = (DrawInfo*)icon->drawinfo;
960         
961         if (!di) {
962                 di = icon_create_drawinfo();
963         
964                 icon->drawinfo = di;            
965                 icon->drawinfo_free = UI_icons_free_drawinfo;           
966         }
967         
968         /* scale width and height according to aspect */
969         w = (int)(draw_size/aspect + 0.5f);
970         h = (int)(draw_size/aspect + 0.5f);
971         
972         if(di->type == ICON_TYPE_VECTOR) {
973                 /* vector icons use the uiBlock transformation, they are not drawn
974                 with untransformed coordinates like the other icons */
975                 di->data.vector.func(x, y, ICON_DEFAULT_HEIGHT, ICON_DEFAULT_HEIGHT, 1.0f); 
976         } 
977         else if(di->type == ICON_TYPE_TEXTURE) {
978                 icon_draw_texture(x, y, w, h, di->data.texture.x, di->data.texture.y,
979                         di->data.texture.w, di->data.texture.h, alpha, rgb);
980         }
981         else if(di->type == ICON_TYPE_BUFFER) {
982                 /* it is a builtin icon */              
983                 iimg= di->data.buffer.image;
984
985                 if(!iimg->rect) return; /* something has gone wrong! */
986
987                 icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb, is_preview);
988         }
989         else if(di->type == ICON_TYPE_PREVIEW) {
990                 PreviewImage* pi = BKE_previewimg_get((ID*)icon->obj); 
991
992                 if(pi) {                        
993                         /* no create icon on this level in code */
994                         if(!pi->rect[miplevel]) return; /* something has gone wrong! */
995                         
996                         /* preview images use premul alpha ... */
997                         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
998                         icon_draw_rect(x, y, w, h, aspect, pi->w[miplevel], pi->h[miplevel], pi->rect[miplevel], 1.0f, NULL, is_preview);
999                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1000                 }
1001         }
1002 }
1003
1004 static void ui_id_icon_render(bContext *C, ID *id, int big)
1005 {
1006         PreviewImage *pi = BKE_previewimg_get(id); 
1007         
1008         if (pi) {                       
1009                 if ((pi->changed[0] ||!pi->rect[0])) /* changed only ever set by dynamic icons */
1010                 {
1011                         /* create the rect if necessary */                              
1012                         
1013                         icon_set_image(C, id, pi, 0);           /* icon size */
1014                         if (big)
1015                                 icon_set_image(C, id, pi, 1);   /* bigger preview size */
1016                         
1017                         pi->changed[0] = 0;
1018                 }
1019         }
1020 }
1021
1022 static void ui_id_brush_render(bContext *C, ID *id)
1023 {
1024         PreviewImage *pi = BKE_previewimg_get(id); 
1025         int i;
1026         
1027         if(!pi)
1028                 return;
1029         
1030         for(i = 0; i < PREVIEW_MIPMAPS; i++) {
1031                 /* check if rect needs to be created; changed
1032                  only set by dynamic icons */
1033                 if((pi->changed[i] || !pi->rect[i])) {
1034                         icon_set_image(C, id, pi, i);
1035                         pi->changed[i] = 0;
1036                 }
1037         }
1038 }
1039
1040
1041 static int ui_id_brush_get_icon(bContext *C, ID *id)
1042 {
1043         Brush *br = (Brush*)id;
1044
1045         if(br->flag & BRUSH_CUSTOM_ICON) {
1046                 BKE_icon_getid(id);
1047                 ui_id_brush_render(C, id);
1048         }
1049         else {
1050                 Object *ob = CTX_data_active_object(C);
1051                 SpaceImage *sima;
1052                 EnumPropertyItem *items = NULL;
1053                 int tool, mode = 0;
1054
1055                 /* XXX: this is not nice, should probably make brushes
1056                    be strictly in one paint mode only to avoid
1057                    checking various context stuff here */
1058
1059                 if(CTX_wm_view3d(C) && ob) {
1060                         if(ob->mode & OB_MODE_SCULPT)
1061                                 mode = OB_MODE_SCULPT;
1062                         else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT))
1063                                 mode = OB_MODE_VERTEX_PAINT;
1064                         else if(ob->mode & OB_MODE_TEXTURE_PAINT)
1065                                 mode = OB_MODE_TEXTURE_PAINT;
1066                 }
1067                 else if((sima = CTX_wm_space_image(C)) &&
1068                         (sima->flag & SI_DRAWTOOL)) {
1069                         mode = OB_MODE_TEXTURE_PAINT;
1070                 }
1071
1072                 /* reset the icon */
1073                 if(mode == OB_MODE_SCULPT) {
1074                         items = brush_sculpt_tool_items;
1075                         tool = br->sculpt_tool;
1076                 }
1077                 else if(mode == OB_MODE_VERTEX_PAINT) {
1078                         items = brush_vertexpaint_tool_items;
1079                         tool = br->vertexpaint_tool;
1080                 }
1081                 else if(mode == OB_MODE_TEXTURE_PAINT) {
1082                         items = brush_imagepaint_tool_items;
1083                         tool = br->imagepaint_tool;
1084                 }
1085
1086                 if(!items || !RNA_enum_icon_from_value(items, tool, &id->icon_id))
1087                         id->icon_id = 0;
1088         }
1089
1090         return id->icon_id;
1091 }
1092
1093 int ui_id_icon_get(bContext *C, ID *id, int big)
1094 {
1095         int iconid= 0;
1096         
1097         /* icon */
1098         switch(GS(id->name))
1099         {
1100                 case ID_BR:
1101                         iconid= ui_id_brush_get_icon(C, id);
1102                         break;
1103                 case ID_MA: /* fall through */
1104                 case ID_TE: /* fall through */
1105                 case ID_IM: /* fall through */
1106                 case ID_WO: /* fall through */
1107                 case ID_LA: /* fall through */
1108                         iconid= BKE_icon_getid(id);
1109                         /* checks if not exists, or changed */
1110                         ui_id_icon_render(C, id, big);
1111                         break;
1112                 default:
1113                         break;
1114         }
1115
1116         return iconid;
1117 }
1118
1119 static void icon_draw_mipmap(float x, float y, int icon_id, float aspect, float alpha, int miplevel, int nocreate)
1120 {
1121         int draw_size = preview_size(miplevel);
1122         icon_draw_size(x, y, icon_id, aspect, alpha, NULL, miplevel, draw_size, nocreate, FALSE);
1123 }
1124
1125 void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha)
1126 {
1127         icon_draw_mipmap(x, y, icon_id, aspect, alpha, PREVIEW_MIPMAP_ZERO, 0);
1128 }
1129
1130 void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, float *rgb)
1131 {
1132         int draw_size = preview_size(PREVIEW_MIPMAP_ZERO);
1133         icon_draw_size(x, y, icon_id, aspect, 1.0f, rgb, PREVIEW_MIPMAP_ZERO, draw_size, FALSE, FALSE);
1134 }
1135
1136 void UI_icon_draw(float x, float y, int icon_id)
1137 {
1138         UI_icon_draw_aspect(x, y, icon_id, 1.0f, 1.0f);
1139 }
1140
1141 void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha)
1142 {
1143         icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, PREVIEW_MIPMAP_ZERO, size, TRUE, FALSE);
1144 }
1145
1146 void UI_icon_draw_preview(float x, float y, int icon_id)
1147 {
1148         icon_draw_mipmap(x, y, icon_id, 1.0f, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
1149 }
1150
1151 void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
1152 {
1153         icon_draw_mipmap(x, y, icon_id, aspect, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
1154 }
1155
1156 void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
1157 {
1158         icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, PREVIEW_MIPMAP_LARGE, size, FALSE, TRUE);
1159 }
1160