More fix various gcc warning, mainly related to signed/unsigned parameters
[blender-staging.git] / source / blender / src / interface_icons.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <math.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #ifndef WIN32
38 #include <unistd.h>
39 #else
40 #include <io.h>
41 #include <direct.h>
42 #endif   
43 #include "MEM_guardedalloc.h"
44
45 #include "BLI_arithb.h"
46 #include "BLI_blenlib.h"
47 #include "BLI_storage_types.h"
48
49 #include "DNA_material_types.h"
50 #include "DNA_texture_types.h"
51 #include "DNA_world_types.h"
52 #include "DNA_object_types.h"
53 #include "DNA_lamp_types.h"
54 #include "DNA_image_types.h"
55 #include "DNA_texture_types.h"
56 #include "DNA_world_types.h"
57 #include "DNA_camera_types.h"
58 #include "DNA_image_types.h"
59 #include "DNA_scene_types.h"
60 #include "DNA_screen_types.h"
61 #include "DNA_space_types.h"
62 #include "DNA_userdef_types.h"
63
64 #include "BKE_global.h"
65 #include "BKE_material.h"
66 #include "BKE_texture.h"
67 #include "BKE_world.h"
68 #include "BKE_image.h"
69 #include "BKE_object.h"
70 #include "BKE_utildefines.h"
71 #include "BKE_icons.h"
72 #include "BKE_packedFile.h"
73
74 #include "IMB_imbuf.h"
75 #include "IMB_imbuf_types.h"
76
77 #include "BIF_gl.h"
78 #include "BIF_glutil.h"
79 #include "BIF_interface.h"
80 #include "BIF_interface_icons.h"
81 #include "BIF_previewrender.h"
82 #include "BIF_screen.h"
83 #include "BIF_resources.h" /* elubie: should be removed once the enum for the ICONS is in BIF_preview_icons.h */
84
85 #include "interface.h"
86
87 #include "PIL_time.h"
88
89 #include "blendef.h"    // CLAMP
90 #include "datatoc.h"
91 #include "mydevice.h"
92
93 /* OpenGL textures have to be size 2n+2 x 2m+2 for some n,m */
94 /* choose ICON_RENDERSIZE accordingly */
95 #define ICON_RENDERSIZE 32      
96 #define ICON_MIPMAPS 8
97
98 #define ICON_IMAGE_W            512
99 #define ICON_IMAGE_H            256
100
101 #define ICON_GRID_COLS          25
102 #define ICON_GRID_ROWS          12
103
104 #define ICON_GRID_MARGIN        5
105 #define ICON_GRID_W             15
106 #define ICON_GRID_H             16
107
108 typedef struct DrawInfo {
109         int w;
110         int h;
111         int rw;
112         int rh;
113         VectorDrawFunc drawFunc; /* If drawFunc is defined then it is a vector icon, otherwise use rect */
114         float aspect;
115         unsigned int *rect; 
116 } DrawInfo;
117
118
119 /* ******************* STATIC LOCAL VARS ******************* */
120 /* static here to cache results of icon directory scan, so it's not 
121  * scanning the filesystem each time the menu is drawn */
122 static struct ListBase iconfilelist = {0, 0};
123
124
125 /* **************************************************** */
126
127 static void def_internal_icon(ImBuf *bbuf, int icon_id, int xofs, int yofs)
128 {
129         Icon *new_icon = NULL;
130         DrawInfo *di;
131         int y = 0;
132
133         new_icon = MEM_callocN(sizeof(Icon), "texicon");
134
135         new_icon->obj = 0; /* icon is not for library object */
136         new_icon->type = 0;
137         new_icon->changed = 0; 
138         
139
140         di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
141         di->drawFunc = 0;
142         di->w = ICON_DEFAULT_HEIGHT;
143         di->h = ICON_DEFAULT_HEIGHT;
144         di->rw = ICON_DEFAULT_HEIGHT;
145         di->rh = ICON_DEFAULT_HEIGHT;
146         di->aspect = 1.0f;
147         di->rect = MEM_mallocN(ICON_DEFAULT_HEIGHT*ICON_DEFAULT_HEIGHT*sizeof(unsigned int), "icon_rect");
148         
149         /* Here we store the rect in the icon - same as before */
150         for (y=0; y<ICON_DEFAULT_HEIGHT; y++) {
151                 memcpy(&di->rect[y*ICON_DEFAULT_HEIGHT], &bbuf->rect[(y+yofs)*512+xofs], ICON_DEFAULT_HEIGHT*sizeof(int));
152         }
153
154         new_icon->drawinfo_free = BIF_icons_free_drawinfo;
155         new_icon->drawinfo = di;
156
157         BKE_icon_set(icon_id, new_icon);
158 }
159
160 static void def_internal_vicon( int icon_id, VectorDrawFunc drawFunc)
161 {
162         Icon *new_icon = NULL;
163         DrawInfo* di;
164
165         new_icon = MEM_callocN(sizeof(Icon), "texicon");
166
167         new_icon->obj = 0; /* icon is not for library object */
168         new_icon->type = 0;
169         new_icon->changed = 0; 
170         
171         di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
172         di->drawFunc =drawFunc;
173         di->w = ICON_DEFAULT_HEIGHT;
174         di->h = ICON_DEFAULT_HEIGHT;
175         di->rw = ICON_DEFAULT_HEIGHT;
176         di->rh = ICON_DEFAULT_HEIGHT;
177         di->aspect = 1.0f;
178         di->rect = NULL;
179         
180         new_icon->drawinfo_free = 0;
181         new_icon->drawinfo = di;
182
183         BKE_icon_set(icon_id, new_icon);
184 }
185
186 /* Vector Icon Drawing Routines */
187
188         /* Utilities */
189
190 static void viconutil_set_point(GLint pt[2], int x, int y)
191 {
192         pt[0] = x;
193         pt[1] = y;
194 }
195
196 static void viconutil_draw_tri(GLint (*pts)[2])
197 {
198         glBegin(GL_TRIANGLES);
199         glVertex2iv(pts[0]);
200         glVertex2iv(pts[1]);
201         glVertex2iv(pts[2]);
202         glEnd();
203 }
204
205 #if 0
206 static void viconutil_draw_quad(GLint (*pts)[2])
207 {
208         glBegin(GL_QUADS);
209         glVertex2iv(pts[0]);
210         glVertex2iv(pts[1]);
211         glVertex2iv(pts[2]);
212         glVertex2iv(pts[3]);
213         glEnd();
214 }
215 #endif
216
217 static void viconutil_draw_lineloop(GLint (*pts)[2], int numPoints)
218 {
219         int i;
220
221         glBegin(GL_LINE_LOOP);
222         for (i=0; i<numPoints; i++) {
223                 glVertex2iv(pts[i]);
224         }
225         glEnd();
226 }
227
228 static void viconutil_draw_lineloop_smooth(GLint (*pts)[2], int numPoints)
229 {
230         glEnable(GL_LINE_SMOOTH);
231         viconutil_draw_lineloop(pts, numPoints);
232         glDisable(GL_LINE_SMOOTH);
233 }
234
235 static void viconutil_draw_points(GLint (*pts)[2], int numPoints, int pointSize)
236 {
237         int i;
238
239         glBegin(GL_QUADS);
240         for (i=0; i<numPoints; i++) {
241                 int x = pts[i][0], y = pts[i][1];
242
243                 glVertex2i(x-pointSize,y-pointSize);
244                 glVertex2i(x+pointSize,y-pointSize);
245                 glVertex2i(x+pointSize,y+pointSize);
246                 glVertex2i(x-pointSize,y+pointSize);
247         }
248         glEnd();
249 }
250
251         /* Drawing functions */
252
253 static void vicon_x_draw(int x, int y, int w, int h, float alpha)
254 {
255         x += 3;
256         y += 3;
257         w -= 6;
258         h -= 6;
259
260         glEnable( GL_LINE_SMOOTH );
261
262         glLineWidth(2.5);
263         
264         glColor4f(0.0, 0.0, 0.0, alpha);
265         glBegin(GL_LINES);
266         glVertex2i(x  ,y  );
267         glVertex2i(x+w,y+h);
268         glVertex2i(x+w,y  );
269         glVertex2i(x  ,y+h);
270         glEnd();
271
272         glLineWidth(1.0);
273         
274         glDisable( GL_LINE_SMOOTH );
275 }
276
277 static void vicon_view3d_draw(int x, int y, int w, int h, float alpha)
278 {
279         int cx = x + w/2;
280         int cy = y + h/2;
281         int d = MAX2(2, h/3);
282
283         glColor4f(0.5, 0.5, 0.5, alpha);
284         glBegin(GL_LINES);
285         glVertex2i(x  , cy-d);
286         glVertex2i(x+w, cy-d);
287         glVertex2i(x  , cy+d);
288         glVertex2i(x+w, cy+d);
289
290         glVertex2i(cx-d, y  );
291         glVertex2i(cx-d, y+h);
292         glVertex2i(cx+d, y  );
293         glVertex2i(cx+d, y+h);
294         glEnd();
295         
296         glColor4f(0.0, 0.0, 0.0, alpha);
297         glBegin(GL_LINES);
298         glVertex2i(x  , cy);
299         glVertex2i(x+w, cy);
300         glVertex2i(cx, y  );
301         glVertex2i(cx, y+h);
302         glEnd();
303 }
304
305 static void vicon_edit_draw(int x, int y, int w, int h, float alpha)
306 {
307         GLint pts[4][2];
308
309         viconutil_set_point(pts[0], x+3  , y+3  );
310         viconutil_set_point(pts[1], x+w-3, y+3  );
311         viconutil_set_point(pts[2], x+w-3, y+h-3);
312         viconutil_set_point(pts[3], x+3  , y+h-3);
313
314         glColor4f(0.0, 0.0, 0.0, alpha);
315         viconutil_draw_lineloop(pts, 4);
316
317         glColor3f(1, 1, 0.0);
318         viconutil_draw_points(pts, 4, 1);
319 }
320
321 static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha)
322 {
323         GLint pts[3][2];
324
325         viconutil_set_point(pts[0], x+w/2, y+h-2);
326         viconutil_set_point(pts[1], x+3, y+4);
327         viconutil_set_point(pts[2], x+w-3, y+4);
328
329         glColor4f(0.5, 0.5, 0.5, alpha);
330         viconutil_draw_tri(pts);
331
332         glColor4f(0.0, 0.0, 0.0, 1);
333         viconutil_draw_lineloop_smooth(pts, 3);
334
335         glColor3f(1, 1, 0.0);
336         viconutil_draw_points(pts, 3, 1);
337 }
338
339 static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float alpha)
340 {
341         GLint pts[3][2];
342
343         viconutil_set_point(pts[0], x+w/2, y+h-2);
344         viconutil_set_point(pts[1], x+3, y+4);
345         viconutil_set_point(pts[2], x+w-3, y+4);
346
347         glColor4f(0.0, 0.0, 0.0, 1);
348         viconutil_draw_lineloop_smooth(pts, 3);
349
350         glColor3f(.9, .9, .9);
351         viconutil_draw_points(pts, 3, 1);
352 }
353
354 static void vicon_disclosure_tri_right_draw(int x, int y, int w, int h, float alpha)
355 {
356         GLint pts[3][2];
357         int cx = x+w/2;
358         int cy = y+w/2;
359         int d = w/3, d2 = w/5;
360
361         viconutil_set_point(pts[0], cx-d2, cy+d);
362         viconutil_set_point(pts[1], cx-d2, cy-d);
363         viconutil_set_point(pts[2], cx+d2, cy);
364
365         glShadeModel(GL_SMOOTH);
366         glBegin(GL_TRIANGLES);
367         glColor4f(0.8, 0.8, 0.8, alpha);
368         glVertex2iv(pts[0]);
369         glVertex2iv(pts[1]);
370         glColor4f(0.3, 0.3, 0.3, alpha);
371         glVertex2iv(pts[2]);
372         glEnd();
373         glShadeModel(GL_FLAT);
374
375         glColor4f(0.0, 0.0, 0.0, 1);
376         viconutil_draw_lineloop_smooth(pts, 3);
377 }
378
379 static void vicon_disclosure_tri_down_draw(int x, int y, int w, int h, float alpha)
380 {
381         GLint pts[3][2];
382         int cx = x+w/2;
383         int cy = y+w/2;
384         int d = w/3, d2 = w/5;
385
386         viconutil_set_point(pts[0], cx+d, cy+d2);
387         viconutil_set_point(pts[1], cx-d, cy+d2);
388         viconutil_set_point(pts[2], cx, cy-d2);
389
390         glShadeModel(GL_SMOOTH);
391         glBegin(GL_TRIANGLES);
392         glColor4f(0.8, 0.8, 0.8, alpha);
393         glVertex2iv(pts[0]);
394         glVertex2iv(pts[1]);
395         glColor4f(0.3, 0.3, 0.3, alpha);
396         glVertex2iv(pts[2]);
397         glEnd();
398         glShadeModel(GL_FLAT);
399
400         glColor4f(0.0, 0.0, 0.0, 1);
401         viconutil_draw_lineloop_smooth(pts, 3);
402 }
403
404 static void vicon_move_up_draw(int x, int y, int w, int h, float alpha)
405 {
406         int d=-2;
407
408         glEnable(GL_LINE_SMOOTH);
409         glLineWidth(1);
410         glColor3f(0.0, 0.0, 0.0);
411
412         glBegin(GL_LINE_STRIP);
413         glVertex2i(x+w/2-d*2, y+h/2+d);
414         glVertex2i(x+w/2, y+h/2-d + 1);
415         glVertex2i(x+w/2+d*2, y+h/2+d);
416         glEnd();
417
418         glLineWidth(1.0);
419         glDisable(GL_LINE_SMOOTH);
420 }
421
422 static void vicon_move_down_draw(int x, int y, int w, int h, float alpha)
423 {
424         int d=2;
425
426         glEnable(GL_LINE_SMOOTH);
427         glLineWidth(1);
428         glColor3f(0.0, 0.0, 0.0);
429
430         glBegin(GL_LINE_STRIP);
431         glVertex2i(x+w/2-d*2, y+h/2+d);
432         glVertex2i(x+w/2, y+h/2-d - 1);
433         glVertex2i(x+w/2+d*2, y+h/2+d);
434         glEnd();
435
436         glLineWidth(1.0);
437         glDisable(GL_LINE_SMOOTH);
438 }
439
440 /***/
441
442
443 /* this only works for the hardcoded buttons image, turning the grey AA pixels to alpha, and slight off-grey to half alpha */
444 #if 0
445 static void clear_transp_rect_soft(unsigned char *transp, unsigned char *rect, int w, int h, int rowstride)
446 {
447         int x, y, val;
448         
449         for (y=1; y<h-1; y++) {
450                 unsigned char *row0= &rect[(y-1)*rowstride];
451                 unsigned char *row= &rect[y*rowstride];
452                 unsigned char *row1= &rect[(y+1)*rowstride];
453                 for (x=1; x<w-1; x++) {
454                         unsigned char *pxl0= &row0[x*4];
455                         unsigned char *pxl= &row[x*4];
456                         unsigned char *pxl1= &row1[x*4];
457                         
458                         if(pxl[3]!=0) {
459                                 val= (abs(pxl[0]-transp[0]) + abs(pxl[1]-transp[1]) + abs(pxl[2]-transp[2]))/3;
460                                 if(val<20) {
461                                         pxl[3]= 128;
462                                 }
463                                 else if(val<50) {
464                                         // one of pixels surrounding has alpha null?
465                                         if(pxl[3-4]==0 || pxl[3+4]==0 || pxl0[3]==0 || pxl1[3]==0) {
466                                 
467                                                 if(pxl[0]>val) pxl[0]-= val; else pxl[0]= 0;
468                                                 if(pxl[1]>val) pxl[1]-= val; else pxl[1]= 0;
469                                                 if(pxl[2]>val) pxl[2]-= val; else pxl[2]= 0;
470                                                 
471                                                 pxl[3]= 128;
472                                         }
473                                 }
474                         }
475                 }
476         }
477 }
478 #endif
479
480 static void clear_icon_grid_margins(unsigned char *rect, int w, int h)
481 {
482         int x, y;
483         int xoffs=ICON_GRID_W+ICON_GRID_MARGIN;
484         int yoffs=ICON_GRID_H+ICON_GRID_MARGIN;
485
486         for (y=0; y<h; y++) {
487                 unsigned char *row= &rect[y*w*4];
488
489                 for (x=0; x<w; x++) {
490                         unsigned char *pxl= &row[x*4];
491
492                         if ((x % xoffs < ICON_GRID_MARGIN-2) || (x % xoffs > ICON_GRID_W+2))
493                                 pxl[3] = 0;     //alpha channel == x+3
494                         else if ((y % yoffs < ICON_GRID_MARGIN-2) || (y % yoffs > ICON_GRID_H+2))
495                                 pxl[3] = 0;
496                 }
497         }
498 }
499
500 static void prepare_internal_icons(ImBuf *bbuf)
501 {
502
503         unsigned char *back= (unsigned char *)bbuf->rect;
504         
505         /* this sets the icon grid margin area outside of icon to zero alpha */
506         clear_icon_grid_margins(back, bbuf->x, bbuf->y);
507         
508         /* hack! */
509 #if 0   
510         for (y=0; y<12; y++) {
511                 for (x=0; x<21; x++) {
512                         unsigned char *start= ((unsigned char*) bbuf->rect) + (y*21 + 3)*rowstride + (x*20 + 3)*4;
513                         /* this sets backdrop of icon to zero alpha */
514                         transp[0]= start[0];
515                         transp[1]= start[1];
516                         transp[2]= start[2];
517                         transp[3]= start[3];
518                         clear_transp_rect(transp, start, 20, 21, rowstride);
519                         clear_transp_rect_soft(transp, start, 20, 21, rowstride);
520                                 
521                 }
522         } 
523 #endif
524 }
525
526
527 static void init_internal_icons()
528 {
529         bTheme *btheme= U.themes.first;
530         ImBuf *bbuf;
531         int x, y;
532         char iconfilestr[FILE_MAXDIR+FILE_MAXFILE];
533         char filenamestr[FILE_MAXFILE+16];      // 16 == strlen(".blender/icons/")+1
534         
535         if ((btheme!=NULL) && (strlen(btheme->tui.iconfile) > 0)) {
536         
537 #ifdef WIN32
538                 sprintf(filenamestr, "icons/%s", btheme->tui.iconfile);
539 #else
540                 sprintf(filenamestr, ".blender/icons/%s", btheme->tui.iconfile);
541 #endif
542                 
543                 BLI_make_file_string("/", iconfilestr, BLI_gethome(), filenamestr);
544                 
545                 if (BLI_exists(iconfilestr)) {
546                         bbuf = IMB_loadiffname(iconfilestr, IB_rect);
547                 } else {
548                         bbuf = IMB_ibImageFromMemory((int *)datatoc_blenderbuttons, datatoc_blenderbuttons_size, IB_rect);
549                 }
550         } else {
551                 bbuf = IMB_ibImageFromMemory((int *)datatoc_blenderbuttons, datatoc_blenderbuttons_size, IB_rect);
552         }
553         
554         prepare_internal_icons(bbuf);
555
556         for (y=0; y<ICON_GRID_ROWS; y++) {
557                 for (x=0; x<ICON_GRID_COLS; x++) {
558                         def_internal_icon(bbuf, BIFICONID_FIRST + y*ICON_GRID_COLS + x,
559                                 x*(ICON_GRID_W+ICON_GRID_MARGIN)+3,
560                                 y*(ICON_GRID_H+ICON_GRID_MARGIN)+3);
561                 }
562         }
563
564         def_internal_vicon(VICON_VIEW3D, vicon_view3d_draw);
565         def_internal_vicon(VICON_EDIT, vicon_edit_draw);
566         def_internal_vicon(VICON_EDITMODE_DEHLT, vicon_editmode_dehlt_draw);
567         def_internal_vicon(VICON_EDITMODE_HLT, vicon_editmode_hlt_draw);
568         def_internal_vicon(VICON_DISCLOSURE_TRI_RIGHT, vicon_disclosure_tri_right_draw);
569         def_internal_vicon(VICON_DISCLOSURE_TRI_DOWN, vicon_disclosure_tri_down_draw);
570         def_internal_vicon(VICON_MOVE_UP, vicon_move_up_draw);
571         def_internal_vicon(VICON_MOVE_DOWN, vicon_move_down_draw);
572         def_internal_vicon(VICON_X, vicon_x_draw);
573
574         IMB_freeImBuf(bbuf);
575 }
576
577
578 static void init_iconfile_list(struct ListBase *list)
579 {
580         IconFile *ifile;
581         ImBuf *bbuf= NULL;
582         struct direntry *dir;
583         int restoredir = 1; /* restore to current directory */
584         int totfile, i, index=1;
585         int ifilex, ifiley;
586         char icondirstr[FILE_MAX];
587         char iconfilestr[FILE_MAX+16]; /* allow 256 chars for file+dir */
588         char olddir[FILE_MAX];
589         
590         list->first = list->last = NULL;
591
592 #ifdef WIN32
593         BLI_make_file_string("/", icondirstr, BLI_gethome(), "icons");
594 #else
595         BLI_make_file_string("/", icondirstr, BLI_gethome(), ".blender/icons");
596 #endif
597         
598         if(BLI_exists(icondirstr)==0)
599                 return;
600         
601         /* since BLI_getdir changes the current working directory, restore it 
602            back to old value afterwards */
603         if(!BLI_getwdN(olddir)) 
604                 restoredir = 0;
605         totfile = BLI_getdir(icondirstr, &dir);
606         if (restoredir)
607                 chdir(olddir);
608
609         for(i=0; i<totfile; i++) {
610                 if( (dir[i].type & S_IFREG) ) {
611                         char *filename = dir[i].relname;
612                         
613                         if(BLI_testextensie(filename, ".png")) {
614                         
615                                 /* check to see if the image is the right size, continue if not */
616                                 /* copying strings here should go ok, assuming that we never get back
617                                    a complete path to file longer than 256 chars */
618                                 sprintf(iconfilestr, "%s/%s", icondirstr, filename);
619                                 if(BLI_exists(iconfilestr)) bbuf = IMB_loadiffname(iconfilestr, IB_rect);
620                                 
621                                 ifilex = bbuf->x;
622                                 ifiley = bbuf->y;
623                                 IMB_freeImBuf(bbuf);
624                                 
625                                 if ((ifilex != ICON_IMAGE_W) || (ifiley != ICON_IMAGE_H))
626                                         continue;
627                         
628                                 /* found a potential icon file, so make an entry for it in the cache list */
629                                 ifile = MEM_callocN(sizeof(IconFile), "IconFile");
630                                 
631                                 BLI_strncpy(ifile->filename, filename, sizeof(ifile->filename));
632                                 ifile->index = index;
633
634                                 BLI_addtail(list, ifile);
635                                 
636                                 index++;
637                         }
638                 }
639         }
640         
641         /* free temporary direntry structure that's been created by BLI_getdir() */
642         i= totfile-1;
643         
644         for(; i>=0; i--){
645                 MEM_freeN(dir[i].relname);
646                 if (dir[i].string) MEM_freeN(dir[i].string);
647         }
648         free(dir);
649         dir= 0;
650 }
651
652 static void free_iconfile_list(struct ListBase *list)
653 {
654         IconFile *ifile=NULL, *next_ifile=NULL;
655         
656         for(ifile=list->first; ifile; ifile=next_ifile) {
657                 next_ifile = ifile->next;
658                 BLI_freelinkN(list, ifile);
659         }
660 }
661
662 int BIF_iconfile_get_index(char *filename)
663 {
664         IconFile *ifile;
665         ListBase *list=&(iconfilelist);
666         
667         for(ifile=list->first; ifile; ifile=ifile->next) {
668                 if ( BLI_streq(filename, ifile->filename)) {
669                         return ifile->index;
670                 }
671         }
672         
673         return 0;
674 }
675
676 ListBase *BIF_iconfile_list(void)
677 {
678         ListBase *list=&(iconfilelist);
679         
680         return list;
681 }
682
683
684 void BIF_icons_free()
685 {
686         free_iconfile_list(&iconfilelist);
687         BKE_icons_free();
688 }
689
690 void BIF_icons_free_drawinfo(void *drawinfo)
691 {
692         DrawInfo *di = drawinfo;
693
694         if (di)
695         {
696                 MEM_freeN(di->rect);
697                 MEM_freeN(di);
698         }
699 }
700
701 static DrawInfo *icon_create_drawinfo()
702 {
703         DrawInfo *di = NULL;
704
705         di = MEM_callocN(sizeof(DrawInfo), "di_icon");
706         
707         di->drawFunc = 0;
708         di->w = 16;
709         di->h = 16;
710         di->rw = ICON_RENDERSIZE;
711         di->rh = ICON_RENDERSIZE;
712         di->rect = 0;
713         di->aspect = 1.0f;
714
715         return di;
716 }
717
718 int BIF_icon_get_width(int icon_id)
719 {
720         Icon *icon = NULL;
721         DrawInfo *di = NULL;
722
723         icon = BKE_icon_get(icon_id);
724         
725         if (!icon) {
726                 printf("BIF_icon_get_width: Internal error, no icon for icon ID: %d\n", icon_id);
727                 return 0;
728         }
729         
730         di = (DrawInfo *)icon->drawinfo;
731         if (!di) {
732                 di = icon_create_drawinfo();
733                 icon->drawinfo = di;
734         }
735
736         if (di)
737                 return di->w;
738
739         return 0;
740 }
741
742 int BIF_icon_get_height(int icon_id)
743 {
744         Icon *icon = NULL;
745         DrawInfo *di = NULL;
746
747         icon = BKE_icon_get(icon_id);
748         
749         if (!icon) {
750                 printf("BIF_icon_get_width: Internal error, no icon for icon ID: %d\n", icon_id);
751                 return 0;
752         }
753         
754         di = (DrawInfo*)icon->drawinfo;
755
756         if (!di) {
757                 di = icon_create_drawinfo();
758                 icon->drawinfo = di;
759         }
760         
761         if (di)
762                 return di->h;
763
764         return 0;
765 }
766
767 void BIF_icons_init(int first_dyn_id)
768 {
769         init_iconfile_list(&iconfilelist);
770         BKE_icons_init(first_dyn_id);
771         init_internal_icons();
772 }
773
774 static void icon_copy_rect(ImBuf *ibuf, RenderInfo *ri)
775 {
776         struct ImBuf *ima;
777         unsigned int *drect, *srect;
778         float scaledx, scaledy;
779         short ex, ey, dx, dy;
780
781         /* paranoia test */
782         if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL))
783                 return;
784         
785         /* waste of cpu cyles... but the imbuf API has no other way to scale fast (ton) */
786         ima = IMB_dupImBuf(ibuf);
787         
788         if (!ima) 
789                 return;
790         
791         if (ima->x > ima->y) {
792                 scaledx = (float)ri->pr_rectx;
793                 scaledy =  ( (float)ima->y/(float)ima->x )*(float)ri->pr_rectx;
794         }
795         else {                  
796                 scaledx =  ( (float)ima->x/(float)ima->y )*(float)ri->pr_recty;
797                 scaledy = (float)ri->pr_recty;
798         }
799         
800         ex = (short)scaledx;
801         ey = (short)scaledy;
802         
803         dx = (ri->pr_rectx - ex) / 2;
804         dy = (ri->pr_recty - ey) / 2;
805         
806         IMB_scalefastImBuf(ima, ex, ey);
807         
808         /* if needed, convert to 32 bits */
809         if(ima->rect==NULL)
810                 IMB_rect_from_float(ima);
811
812         srect = ima->rect;
813         drect = ri->rect;
814
815         drect+= dy*ri->pr_rectx+dx;
816         for (;ey > 0; ey--){            
817                 memcpy(drect,srect, ex * sizeof(int));
818                 drect += ri->pr_rectx;
819                 srect += ima->x;
820         }
821         IMB_freeImBuf(ima);
822 }
823
824 /* create single icon from jpg, png etc. */
825 static void icon_from_image(Image *img, RenderInfo *ri)
826 {
827         unsigned int pr_size = ri->pr_rectx*ri->pr_recty*sizeof(unsigned int);
828
829         /* img->ok is zero when Image cannot load */
830         if (img==NULL || img->ok==0)
831                 return;
832         
833         if (!ri->rect) {
834                 ri->rect= MEM_callocN(pr_size, "butsrect");
835                 memset(ri->rect, 0x00, pr_size);
836         }
837         
838         /* we only load image if there's no preview saved already ... 
839                 always loading and reducing images is too expensive */
840         /* new rule: never read images, so icons get created while user works, 
841             not always on first use of a menu */
842         if(!img->preview) {
843                 ImBuf *ibuf;
844                 if(img->ok!=IMA_OK_LOADED) {                            
845                         return;
846                 }
847                 ibuf= BKE_image_get_ibuf(img, NULL);
848                 icon_copy_rect(ibuf, ri);
849                 
850                 /* now copy the created preview to the DNA struct to be saved in file */
851                 img->preview = MEM_callocN(sizeof(PreviewImage), "img_prv");
852                 if (img->preview) {
853                         printf("created image prv\n");
854                         img->preview->w = ri->pr_rectx;
855                         img->preview->h = ri->pr_recty;
856                         img->preview->rect = MEM_callocN(pr_size, "prv_rect");
857                         memcpy(img->preview->rect, ri->rect, pr_size);
858                 }
859         }
860         else {
861                 unsigned int img_prv_size = img->preview->w*img->preview->h*sizeof(unsigned int);
862                 if (!img->preview->rect || img_prv_size != pr_size) {
863                         printf("Missing preview or wrong preview size!\n");
864                         return;
865                 }
866                 memcpy(ri->rect, img->preview->rect, pr_size);
867         }
868 }
869
870 static void set_alpha(char* cp, int sizex, int sizey, char alpha) 
871 {
872         int x,y;
873         for(y=0; y<sizey; y++) {
874                 for(x=0; x<sizex; x++, cp+=4) {
875                         cp[3]= alpha;
876                 }
877         }
878 }
879
880 /* only called when icon has changed */
881 /* only call with valid pointer from BIF_icon_draw */
882 static void icon_set_image(ID *id, DrawInfo *di)
883 {
884         RenderInfo ri;  
885
886         if (!di) return;                        
887
888         if (!di->rect)
889                 di->rect = MEM_callocN(di->rw*di->rh*sizeof(unsigned int), "laprevrect");               
890         
891         ri.curtile= 0;
892         ri.tottile= 0;
893         ri.rect = NULL;
894         ri.pr_rectx = di->rw;
895         ri.pr_recty = di->rh;
896
897         /* no drawing (see last parameter doDraw, just calculate preview image 
898                 - hopefully small enough to be fast */
899         if (GS(id->name) == ID_IM)
900                 icon_from_image((struct Image*)id, &ri);
901         else {
902                 BIF_previewrender(id, &ri, NULL, PR_ICON_RENDER);
903                 /* world is rendered with alpha=0, so it wasn't displayed 
904                    this could be render option for sky to, for later */
905                 if (GS(id->name) == ID_WO) { 
906                         set_alpha( (char*) ri.rect, ri.pr_rectx, ri.pr_recty, 255);
907                 } 
908                 else if (GS(id->name) == ID_MA) {
909                         Material* mat = (Material*)id;
910                         if (mat->mode & MA_HALO) {
911                                 set_alpha( (char*) ri.rect, ri.pr_rectx, ri.pr_recty, 255);
912                         } 
913                 }
914         }
915
916         /* and copy the image into the icon */
917         if (ri.rect) {
918                 memcpy(di->rect, ri.rect,di->rw*di->rh*sizeof(unsigned int));           
919
920                 /* and clean up */
921                 MEM_freeN(ri.rect);
922                 ri.rect = 0;
923         }
924 }
925
926 void BIF_icon_draw_aspect(float x, float y, int icon_id, float aspect)
927 {
928         Icon *icon = NULL;
929         DrawInfo *di = NULL;
930         
931         icon = BKE_icon_get(icon_id);
932         
933         if (!icon) {
934                 printf("BIF_icon_set_aspect: Internal error, no icon for icon ID: %d\n", icon_id);
935                 return;
936         }
937         
938         di = (DrawInfo*)icon->drawinfo;
939         
940         if (!di) {
941                 di = icon_create_drawinfo();
942                 
943                 icon->changed = 1; 
944                 icon->drawinfo = di;            
945                 icon->drawinfo_free = BIF_icons_free_drawinfo;          
946         }
947         
948         di->aspect = aspect;
949         /* scale width and height according to aspect */
950         di->w = (int)(ICON_DEFAULT_HEIGHT/di->aspect + 0.5f);
951         di->h = (int)(ICON_DEFAULT_HEIGHT/di->aspect + 0.5f);
952         
953         if (di->drawFunc) {
954                 /* vector icons use the uiBlock transformation, they are not drawn
955                 with untransformed coordinates like the other icons */
956                 di->drawFunc(x, y, ICON_DEFAULT_HEIGHT, ICON_DEFAULT_HEIGHT, 1.0f); 
957         }
958         else {
959                 if (icon->changed) /* changed only ever set by dynamic icons */
960                 {
961                         waitcursor(1);
962                         icon_set_image((ID*)icon->obj, icon->drawinfo);
963                         icon->changed = 0;              
964                         waitcursor(0);
965                 }
966                 
967                 if (!di->rect) return; /* something has gone wrong! */
968                 
969                 ui_rasterpos_safe(x, y, di->aspect);
970                 
971                 if(di->w<1 || di->h<1) {
972                         printf("what the heck!\n");
973                 }
974                 /* di->rect contains image in 'rendersize', we only scale if needed */
975                 else if(di->rw!=di->w && di->rh!=di->h) {
976                         ImBuf *ima;
977                         if(di->w>2000 || di->h>2000) { /* something has gone wrong! */
978                                 printf("insane icon size di->w %d di->h %d\n",di->w,di->h);
979                                 return;
980                         }
981                         /* first allocate imbuf for scaling and copy preview into it */
982                         ima = IMB_allocImBuf(di->rw, di->rh, 32, IB_rect, 0);
983                         memcpy(ima->rect, di->rect, di->rw*di->rh*sizeof(unsigned int));        
984                         
985                         /* scale it */
986                         IMB_scaleImBuf(ima, di->w, di->h);
987                         glDrawPixels(di->w, di->h, GL_RGBA, GL_UNSIGNED_BYTE, ima->rect);
988                         
989                         IMB_freeImBuf(ima);
990                 }
991                 else
992                         glDrawPixels(di->w, di->h, GL_RGBA, GL_UNSIGNED_BYTE, di->rect);
993         }
994 }
995
996 void BIF_icon_draw(float x, float y, int icon_id)
997 {
998         BIF_icon_draw_aspect(x, y, icon_id, 1.0f);
999 }
1000
1001
1002 void BIF_icon_draw_aspect_blended(float x, float y, int icon_id, float aspect, int shade)
1003 {
1004         
1005         if(shade < 0) {
1006                 float r= (128+shade)/128.0f;
1007                 glPixelTransferf(GL_ALPHA_SCALE, r);
1008         }
1009
1010         BIF_icon_draw_aspect(x, y, icon_id, aspect);
1011
1012         if(shade < 0)
1013                 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
1014 }