most unused arg warnings corrected.
[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, short is_preview)
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         if(is_preview == 0) {
859                 /* position */
860                 glRasterPos2f(x,y);
861         }
862
863         /* draw */
864         if((w<1 || h<1)) {
865                 // XXX - TODO 2.5 verify whether this case can happen
866                 if (G.f & G_DEBUG)
867                         printf("what the heck! - icons are %i x %i pixels?\n", w, h);
868         }
869         /* rect contains image in 'rendersize', we only scale if needed */
870         else if(rw!=w && rh!=h) {
871                 if(w>2000 || h>2000) { /* something has gone wrong! */
872                         if (G.f & G_DEBUG)
873                                 printf("insane icon size w=%d h=%d\n",w,h);
874                 }
875                 else {
876                         ImBuf *ima;
877
878                         /* first allocate imbuf for scaling and copy preview into it */
879                         ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
880                         memcpy(ima->rect, rect, rw*rh*sizeof(unsigned int));    
881                         
882                         /* scale it */
883                         IMB_scaleImBuf(ima, w, h);
884
885                         if(is_preview) {
886                                 glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, ima->rect);
887                         }
888                         else {
889                                 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, ima->rect);
890                         }
891
892                         IMB_freeImBuf(ima);
893                 }
894         }
895         else {
896                 if(is_preview) {
897                         glaDrawPixelsSafe(x, y, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, rect);
898                 }
899                 else {
900                         glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
901                 }
902         }
903
904         /* restore color */
905         if(alpha != 0.0f)
906                 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
907         
908         if(rgb) {
909                 glPixelTransferf(GL_RED_SCALE, 1.0f);
910                 glPixelTransferf(GL_GREEN_SCALE, 1.0f);
911                 glPixelTransferf(GL_BLUE_SCALE, 1.0f);
912         }
913 }
914
915 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)
916 {
917         float x1, x2, y1, y2;
918
919         if(rgb) glColor4f(rgb[0], rgb[1], rgb[2], alpha);
920         else glColor4f(1.0f, 1.0f, 1.0f, alpha);
921
922         x1= ix*icongltex.invw;
923         x2= (ix + ih)*icongltex.invw;
924         y1= iy*icongltex.invh;
925         y2= (iy + ih)*icongltex.invh;
926
927         glEnable(GL_TEXTURE_2D);
928         glBindTexture(GL_TEXTURE_2D, icongltex.id);
929
930         glBegin(GL_QUADS);
931         glTexCoord2f(x1, y1);
932         glVertex2f(x, y);
933
934         glTexCoord2f(x2, y1);
935         glVertex2f(x+w, y);
936
937         glTexCoord2f(x2, y2);
938         glVertex2f(x+w, y+h);
939
940         glTexCoord2f(x1, y2);
941         glVertex2f(x, y+h);
942         glEnd();
943
944         glBindTexture(GL_TEXTURE_2D, 0);
945         glDisable(GL_TEXTURE_2D);
946 }
947
948 /* Drawing size for preview images at level miplevel */
949 static int preview_size(int miplevel)
950 {
951         switch (miplevel) {
952                 case 0: return ICON_DEFAULT_HEIGHT;
953                 case 1: return PREVIEW_DEFAULT_HEIGHT;
954         }
955         return 0;
956 }
957
958 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)
959 {
960         Icon *icon = NULL;
961         DrawInfo *di = NULL;
962         IconImage *iimg;
963         int w, h;
964         
965         icon = BKE_icon_get(icon_id);
966         
967         if (!icon) {
968                 if (G.f & G_DEBUG)
969                         printf("icon_draw_mipmap: Internal error, no icon for icon ID: %d\n", icon_id);
970                 return;
971         }
972
973         di = (DrawInfo*)icon->drawinfo;
974         
975         if (!di) {
976                 di = icon_create_drawinfo();
977         
978                 icon->drawinfo = di;            
979                 icon->drawinfo_free = UI_icons_free_drawinfo;           
980         }
981         
982         /* scale width and height according to aspect */
983         w = (int)(draw_size/aspect + 0.5f);
984         h = (int)(draw_size/aspect + 0.5f);
985         
986         if(di->type == ICON_TYPE_VECTOR) {
987                 /* vector icons use the uiBlock transformation, they are not drawn
988                 with untransformed coordinates like the other icons */
989                 di->data.vector.func(x, y, ICON_DEFAULT_HEIGHT, ICON_DEFAULT_HEIGHT, 1.0f); 
990         } 
991         else if(di->type == ICON_TYPE_TEXTURE) {
992                 icon_draw_texture(x, y, w, h, di->data.texture.x, di->data.texture.y,
993                         di->data.texture.w, di->data.texture.h, alpha, rgb);
994         }
995         else if(di->type == ICON_TYPE_BUFFER) {
996                 /* it is a builtin icon */              
997                 iimg= di->data.buffer.image;
998
999                 if(!iimg->rect) return; /* something has gone wrong! */
1000
1001                 icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb, is_preview);
1002         }
1003         else if(di->type == ICON_TYPE_PREVIEW) {
1004                 PreviewImage* pi = BKE_previewimg_get((ID*)icon->obj); 
1005
1006                 if(pi) {                        
1007                         /* no create icon on this level in code */
1008                         if(!pi->rect[miplevel]) return; /* something has gone wrong! */
1009                         
1010                         /* preview images use premul alpha ... */
1011                         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1012                         icon_draw_rect(x, y, w, h, aspect, pi->w[miplevel], pi->h[miplevel], pi->rect[miplevel], 1.0f, NULL, is_preview);
1013                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1014                 }
1015         }
1016 }
1017
1018 void ui_id_icon_render(bContext *C, ID *id, int preview)
1019 {
1020         PreviewImage *pi = BKE_previewimg_get(id); 
1021                 
1022         if (pi) {                       
1023                 if ((pi->changed[0] ||!pi->rect[0])) /* changed only ever set by dynamic icons */
1024                 {
1025                         /* create the preview rect if necessary */                              
1026                         
1027                         icon_set_image(C, id, pi, 0);           /* icon size */
1028                         if (preview)
1029                                 icon_set_image(C, id, pi, 1);   /* preview size */
1030                         
1031                         pi->changed[0] = 0;
1032                 }
1033         }
1034 }
1035
1036 static int ui_id_brush_get_icon(bContext *C, ID *id, int preview)
1037 {
1038         Brush *br = (Brush*)id;
1039
1040         if(br->flag & BRUSH_CUSTOM_ICON) {
1041                 BKE_icon_getid(id);
1042                 ui_id_icon_render(C, id, preview);
1043         }
1044         else if(!id->icon_id) {
1045                 /* no icon found, reset it */
1046                 
1047                 /* this is not nice, should probably make
1048                    brushes be strictly in one paint mode only
1049                    to avoid this kind of thing */
1050                 Object *ob = CTX_data_active_object(C);
1051                 EnumPropertyItem *items;
1052                 int tool;
1053                 
1054                 if(ob && (ob->mode & OB_MODE_SCULPT)) {
1055                         items = brush_sculpt_tool_items;
1056                         tool = br->sculpt_tool;
1057                 }
1058                 else if(ob && (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT))) {
1059                         items = brush_vertexpaint_tool_items;
1060                         tool = br->vertexpaint_tool;
1061                 }
1062                 else {
1063                         items = brush_imagepaint_tool_items;
1064                         tool = br->imagepaint_tool;
1065                 }
1066
1067                 RNA_enum_icon_from_value(items, tool, &id->icon_id);
1068         }
1069
1070         return id->icon_id;
1071 }
1072
1073 int ui_id_icon_get(bContext *C, ID *id, int preview)
1074 {
1075         int iconid= 0;
1076         
1077         /* icon */
1078         switch(GS(id->name))
1079         {
1080                 case ID_BR:
1081                         iconid= ui_id_brush_get_icon(C, id, preview);
1082                         break;
1083                 case ID_MA: /* fall through */
1084                 case ID_TE: /* fall through */
1085                 case ID_IM: /* fall through */
1086                 case ID_WO: /* fall through */
1087                 case ID_LA: /* fall through */
1088                         iconid= BKE_icon_getid(id);
1089                         /* checks if not exists, or changed */
1090                         ui_id_icon_render(C, id, preview);
1091                         break;
1092                 default:
1093                         break;
1094         }
1095
1096         return iconid;
1097 }
1098
1099 static void icon_draw_mipmap(float x, float y, int icon_id, float aspect, float alpha, int miplevel, int nocreate)
1100 {
1101         int draw_size = preview_size(miplevel);
1102         icon_draw_size(x, y, icon_id, aspect, alpha, NULL, miplevel, draw_size, nocreate, FALSE);
1103 }
1104
1105 void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha)
1106 {
1107         icon_draw_mipmap(x, y, icon_id, aspect, alpha, PREVIEW_MIPMAP_ZERO, 0);
1108 }
1109
1110 void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, float *rgb)
1111 {
1112         int draw_size = preview_size(PREVIEW_MIPMAP_ZERO);
1113         icon_draw_size(x, y, icon_id, aspect, 1.0f, rgb, PREVIEW_MIPMAP_ZERO, draw_size, FALSE, FALSE);
1114 }
1115
1116 void UI_icon_draw(float x, float y, int icon_id)
1117 {
1118         UI_icon_draw_aspect(x, y, icon_id, 1.0f, 1.0f);
1119 }
1120
1121 void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha)
1122 {
1123         icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, PREVIEW_MIPMAP_ZERO, size, TRUE, FALSE);
1124 }
1125
1126 void UI_icon_draw_preview(float x, float y, int icon_id)
1127 {
1128         icon_draw_mipmap(x, y, icon_id, 1.0f, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
1129 }
1130
1131 void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
1132 {
1133         icon_draw_mipmap(x, y, icon_id, aspect, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
1134 }
1135
1136 void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
1137 {
1138         icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, PREVIEW_MIPMAP_LARGE, size, FALSE, TRUE);
1139 }
1140