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