svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r22935:23022
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 "BLI_arithb.h"
42 #include "BLI_blenlib.h"
43 #include "BLI_storage_types.h"
44
45 #include "DNA_material_types.h"
46 #include "DNA_screen_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_userdef_types.h"
49
50 #include "BKE_image.h"
51 #include "BKE_icons.h"
52 #include "BKE_utildefines.h"
53
54 #include "IMB_imbuf.h"
55 #include "IMB_imbuf_types.h"
56
57 #include "BIF_gl.h"
58 #include "BIF_glutil.h"
59
60 #include "ED_datafiles.h"
61 #include "ED_previewrender.h"
62
63 #include "UI_interface.h"
64 #include "UI_interface_icons.h"
65 #include "UI_resources.h" /* elubie: should be removed once the enum for the ICONS is in BIF_preview_icons.h */
66
67 #include "interface_intern.h"
68
69
70 #define ICON_IMAGE_W            600
71 #define ICON_IMAGE_H            640
72
73 #define ICON_GRID_COLS          26
74 #define ICON_GRID_ROWS          30
75
76 #define ICON_GRID_MARGIN        5
77 #define ICON_GRID_W             16
78 #define ICON_GRID_H             16
79
80 typedef struct IconImage {
81         int w;
82         int h;
83         unsigned int *rect; 
84 } IconImage;
85
86 typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
87
88 typedef struct DrawInfo {
89         int w;
90         int h;
91         float aspect;
92         VectorDrawFunc drawFunc; /* If drawFunc is defined then it is a vector icon, otherwise use rect */              
93         IconImage* icon;
94 } DrawInfo;
95
96 /* ******************* STATIC LOCAL VARS ******************* */
97 /* static here to cache results of icon directory scan, so it's not 
98  * scanning the filesystem each time the menu is drawn */
99 static struct ListBase iconfilelist = {0, 0};
100
101
102 /* **************************************************** */
103
104 static void def_internal_icon(ImBuf *bbuf, int icon_id, int xofs, int yofs, int size)
105 {
106         Icon *new_icon = NULL;
107         IconImage *iimg = NULL;
108         DrawInfo *di;
109         int y = 0;
110         int imgsize = 0;
111
112         new_icon = MEM_callocN(sizeof(Icon), "texicon");
113
114         new_icon->obj = 0; /* icon is not for library object */
115         new_icon->type = 0;     
116
117         di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
118         di->drawFunc = 0;
119         di->w = size;
120         di->h = size;
121         di->aspect = 1.0f;
122         
123         iimg = MEM_mallocN(sizeof(IconImage), "icon_img");
124         iimg->rect = MEM_mallocN(size*size*sizeof(unsigned int), "icon_rect");
125         iimg->w = size;
126         iimg->h = size;
127
128         /* Here we store the rect in the icon - same as before */
129         imgsize = bbuf->x;
130         for (y=0; y<size; y++) {
131                 memcpy(&iimg->rect[y*size], &bbuf->rect[(y+yofs)*imgsize+xofs], size*sizeof(int));
132         }
133
134         di->icon = iimg;
135
136         new_icon->drawinfo_free = UI_icons_free_drawinfo;
137         new_icon->drawinfo = di;
138
139         BKE_icon_set(icon_id, new_icon);
140 }
141
142 static void def_internal_vicon( int icon_id, VectorDrawFunc drawFunc)
143 {
144         Icon *new_icon = NULL;
145         DrawInfo* di;
146
147         new_icon = MEM_callocN(sizeof(Icon), "texicon");
148
149         new_icon->obj = 0; /* icon is not for library object */
150         new_icon->type = 0;
151
152         di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
153         di->drawFunc =drawFunc;
154         di->w = ICON_DEFAULT_HEIGHT;
155         di->h = ICON_DEFAULT_HEIGHT;
156         di->aspect = 1.0f;
157         di->icon = NULL;
158
159         new_icon->drawinfo_free = 0;
160         new_icon->drawinfo = di;
161
162         BKE_icon_set(icon_id, new_icon);
163 }
164
165 /* Vector Icon Drawing Routines */
166
167         /* Utilities */
168
169 static void viconutil_set_point(GLint pt[2], int x, int y)
170 {
171         pt[0] = x;
172         pt[1] = y;
173 }
174
175 static void viconutil_draw_tri(GLint (*pts)[2])
176 {
177         glBegin(GL_TRIANGLES);
178         glVertex2iv(pts[0]);
179         glVertex2iv(pts[1]);
180         glVertex2iv(pts[2]);
181         glEnd();
182 }
183
184 static void viconutil_draw_lineloop(GLint (*pts)[2], int numPoints)
185 {
186         int i;
187
188         glBegin(GL_LINE_LOOP);
189         for (i=0; i<numPoints; i++) {
190                 glVertex2iv(pts[i]);
191         }
192         glEnd();
193 }
194
195 static void viconutil_draw_lineloop_smooth(GLint (*pts)[2], int numPoints)
196 {
197         glEnable(GL_LINE_SMOOTH);
198         viconutil_draw_lineloop(pts, numPoints);
199         glDisable(GL_LINE_SMOOTH);
200 }
201
202 static void viconutil_draw_points(GLint (*pts)[2], int numPoints, int pointSize)
203 {
204         int i;
205
206         glBegin(GL_QUADS);
207         for (i=0; i<numPoints; i++) {
208                 int x = pts[i][0], y = pts[i][1];
209
210                 glVertex2i(x-pointSize,y-pointSize);
211                 glVertex2i(x+pointSize,y-pointSize);
212                 glVertex2i(x+pointSize,y+pointSize);
213                 glVertex2i(x-pointSize,y+pointSize);
214         }
215         glEnd();
216 }
217
218         /* Drawing functions */
219
220 static void vicon_x_draw(int x, int y, int w, int h, float alpha)
221 {
222         x += 3;
223         y += 3;
224         w -= 6;
225         h -= 6;
226
227         glEnable( GL_LINE_SMOOTH );
228
229         glLineWidth(2.5);
230         
231         glColor4f(0.0, 0.0, 0.0, alpha);
232         glBegin(GL_LINES);
233         glVertex2i(x  ,y  );
234         glVertex2i(x+w,y+h);
235         glVertex2i(x+w,y  );
236         glVertex2i(x  ,y+h);
237         glEnd();
238
239         glLineWidth(1.0);
240         
241         glDisable( GL_LINE_SMOOTH );
242 }
243
244 static void vicon_view3d_draw(int x, int y, int w, int h, float alpha)
245 {
246         int cx = x + w/2;
247         int cy = y + h/2;
248         int d = MAX2(2, h/3);
249
250         glColor4f(0.5, 0.5, 0.5, alpha);
251         glBegin(GL_LINES);
252         glVertex2i(x  , cy-d);
253         glVertex2i(x+w, cy-d);
254         glVertex2i(x  , cy+d);
255         glVertex2i(x+w, cy+d);
256
257         glVertex2i(cx-d, y  );
258         glVertex2i(cx-d, y+h);
259         glVertex2i(cx+d, y  );
260         glVertex2i(cx+d, y+h);
261         glEnd();
262         
263         glColor4f(0.0, 0.0, 0.0, alpha);
264         glBegin(GL_LINES);
265         glVertex2i(x  , cy);
266         glVertex2i(x+w, cy);
267         glVertex2i(cx, y  );
268         glVertex2i(cx, y+h);
269         glEnd();
270 }
271
272 static void vicon_edit_draw(int x, int y, int w, int h, float alpha)
273 {
274         GLint pts[4][2];
275
276         viconutil_set_point(pts[0], x+3  , y+3  );
277         viconutil_set_point(pts[1], x+w-3, y+3  );
278         viconutil_set_point(pts[2], x+w-3, y+h-3);
279         viconutil_set_point(pts[3], x+3  , y+h-3);
280
281         glColor4f(0.0, 0.0, 0.0, alpha);
282         viconutil_draw_lineloop(pts, 4);
283
284         glColor3f(1, 1, 0.0);
285         viconutil_draw_points(pts, 4, 1);
286 }
287
288 static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha)
289 {
290         GLint pts[3][2];
291
292         viconutil_set_point(pts[0], x+w/2, y+h-2);
293         viconutil_set_point(pts[1], x+3, y+4);
294         viconutil_set_point(pts[2], x+w-3, y+4);
295
296         glColor4f(0.5, 0.5, 0.5, alpha);
297         viconutil_draw_tri(pts);
298
299         glColor4f(0.0, 0.0, 0.0, 1);
300         viconutil_draw_lineloop_smooth(pts, 3);
301
302         glColor3f(1, 1, 0.0);
303         viconutil_draw_points(pts, 3, 1);
304 }
305
306 static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float alpha)
307 {
308         GLint pts[3][2];
309
310         viconutil_set_point(pts[0], x+w/2, y+h-2);
311         viconutil_set_point(pts[1], x+3, y+4);
312         viconutil_set_point(pts[2], x+w-3, y+4);
313
314         glColor4f(0.0f, 0.0f, 0.0f, 1);
315         viconutil_draw_lineloop_smooth(pts, 3);
316
317         glColor3f(.9f, .9f, .9f);
318         viconutil_draw_points(pts, 3, 1);
319 }
320
321 static void vicon_disclosure_tri_right_draw(int x, int y, int w, int h, float alpha)
322 {
323         GLint pts[3][2];
324         int cx = x+w/2;
325         int cy = y+w/2;
326         int d = w/3, d2 = w/5;
327
328         viconutil_set_point(pts[0], cx-d2, cy+d);
329         viconutil_set_point(pts[1], cx-d2, cy-d);
330         viconutil_set_point(pts[2], cx+d2, cy);
331
332         glShadeModel(GL_SMOOTH);
333         glBegin(GL_TRIANGLES);
334         glColor4f(0.8f, 0.8f, 0.8f, alpha);
335         glVertex2iv(pts[0]);
336         glVertex2iv(pts[1]);
337         glColor4f(0.3f, 0.3f, 0.3f, alpha);
338         glVertex2iv(pts[2]);
339         glEnd();
340         glShadeModel(GL_FLAT);
341
342         glColor4f(0.0f, 0.0f, 0.0f, 1);
343         viconutil_draw_lineloop_smooth(pts, 3);
344 }
345
346 static void vicon_small_tri_right_draw(int x, int y, int w, int h, float alpha)
347 {
348         GLint pts[3][2];
349         int cx = x+w/2-4;
350         int cy = y+w/2;
351         int d = w/5, d2 = w/7;
352
353         viconutil_set_point(pts[0], cx-d2, cy+d);
354         viconutil_set_point(pts[1], cx-d2, cy-d);
355         viconutil_set_point(pts[2], cx+d2, cy);
356
357         glColor4f(0.2f, 0.2f, 0.2f, alpha);
358
359         glShadeModel(GL_SMOOTH);
360         glBegin(GL_TRIANGLES);
361         glVertex2iv(pts[0]);
362         glVertex2iv(pts[1]);
363         glVertex2iv(pts[2]);
364         glEnd();
365         glShadeModel(GL_FLAT);
366 }
367
368 static void vicon_disclosure_tri_down_draw(int x, int y, int w, int h, float alpha)
369 {
370         GLint pts[3][2];
371         int cx = x+w/2;
372         int cy = y+w/2;
373         int d = w/3, d2 = w/5;
374
375         viconutil_set_point(pts[0], cx+d, cy+d2);
376         viconutil_set_point(pts[1], cx-d, cy+d2);
377         viconutil_set_point(pts[2], cx, cy-d2);
378
379         glShadeModel(GL_SMOOTH);
380         glBegin(GL_TRIANGLES);
381         glColor4f(0.8f, 0.8f, 0.8f, alpha);
382         glVertex2iv(pts[0]);
383         glVertex2iv(pts[1]);
384         glColor4f(0.3f, 0.3f, 0.3f, alpha);
385         glVertex2iv(pts[2]);
386         glEnd();
387         glShadeModel(GL_FLAT);
388
389         glColor4f(0.0f, 0.0f, 0.0f, 1);
390         viconutil_draw_lineloop_smooth(pts, 3);
391 }
392
393 static void vicon_move_up_draw(int x, int y, int w, int h, float alpha)
394 {
395         int d=-2;
396
397         glEnable(GL_LINE_SMOOTH);
398         glLineWidth(1);
399         glColor3f(0.0, 0.0, 0.0);
400
401         glBegin(GL_LINE_STRIP);
402         glVertex2i(x+w/2-d*2, y+h/2+d);
403         glVertex2i(x+w/2, y+h/2-d + 1);
404         glVertex2i(x+w/2+d*2, y+h/2+d);
405         glEnd();
406
407         glLineWidth(1.0);
408         glDisable(GL_LINE_SMOOTH);
409 }
410
411 static void vicon_move_down_draw(int x, int y, int w, int h, float alpha)
412 {
413         int d=2;
414
415         glEnable(GL_LINE_SMOOTH);
416         glLineWidth(1);
417         glColor3f(0.0, 0.0, 0.0);
418
419         glBegin(GL_LINE_STRIP);
420         glVertex2i(x+w/2-d*2, y+h/2+d);
421         glVertex2i(x+w/2, y+h/2-d - 1);
422         glVertex2i(x+w/2+d*2, y+h/2+d);
423         glEnd();
424
425         glLineWidth(1.0);
426         glDisable(GL_LINE_SMOOTH);
427 }
428
429 static void init_internal_icons()
430 {
431         bTheme *btheme= U.themes.first;
432         ImBuf *bbuf= NULL;
433         int x, y;
434         char iconfilestr[FILE_MAXDIR+FILE_MAXFILE];
435         char filenamestr[FILE_MAXFILE+16];      // 16 == strlen(".blender/icons/")+1
436         
437         if ((btheme!=NULL) && (strlen(btheme->tui.iconfile) > 0)) {
438         
439 #ifdef WIN32
440                 sprintf(filenamestr, "icons/%s", btheme->tui.iconfile);
441 #else
442                 sprintf(filenamestr, ".blender/icons/%s", btheme->tui.iconfile);
443 #endif
444                 
445                 BLI_make_file_string("/", iconfilestr, BLI_gethome(), filenamestr);
446                 
447                 if (BLI_exists(iconfilestr)) {
448                         bbuf = IMB_loadiffname(iconfilestr, IB_rect);
449                         if(bbuf->x < ICON_IMAGE_W || bbuf->y < ICON_IMAGE_H) {
450                                 printf("\n***WARNING***\nIcons file %s too small.\nUsing built-in Icons instead\n", iconfilestr);
451                                 IMB_freeImBuf(bbuf);
452                                 bbuf= NULL;
453                 }
454         }
455         }
456         if(bbuf==NULL)
457                 bbuf = IMB_ibImageFromMemory((int *)datatoc_blenderbuttons, datatoc_blenderbuttons_size, IB_rect);
458
459         for (y=0; y<ICON_GRID_ROWS; y++) {
460                 for (x=0; x<ICON_GRID_COLS; x++) {
461                         def_internal_icon(bbuf, BIFICONID_FIRST + y*ICON_GRID_COLS + x,
462                                 x*(ICON_GRID_W+ICON_GRID_MARGIN)+ICON_GRID_MARGIN,
463                                 y*(ICON_GRID_H+ICON_GRID_MARGIN)+ICON_GRID_MARGIN, ICON_GRID_W);
464                 }
465         }
466
467         def_internal_vicon(VICON_VIEW3D, vicon_view3d_draw);
468         def_internal_vicon(VICON_EDIT, vicon_edit_draw);
469         def_internal_vicon(VICON_EDITMODE_DEHLT, vicon_editmode_dehlt_draw);
470         def_internal_vicon(VICON_EDITMODE_HLT, vicon_editmode_hlt_draw);
471         def_internal_vicon(VICON_DISCLOSURE_TRI_RIGHT, vicon_disclosure_tri_right_draw);
472         def_internal_vicon(VICON_DISCLOSURE_TRI_DOWN, vicon_disclosure_tri_down_draw);
473         def_internal_vicon(VICON_MOVE_UP, vicon_move_up_draw);
474         def_internal_vicon(VICON_MOVE_DOWN, vicon_move_down_draw);
475         def_internal_vicon(VICON_X, vicon_x_draw);
476         def_internal_vicon(VICON_SMALL_TRI_RIGHT, vicon_small_tri_right_draw);
477
478         IMB_freeImBuf(bbuf);
479 }
480
481
482 static void init_iconfile_list(struct ListBase *list)
483 {
484         IconFile *ifile;
485         ImBuf *bbuf= NULL;
486         struct direntry *dir;
487         int restoredir = 1; /* restore to current directory */
488         int totfile, i, index=1;
489         int ifilex, ifiley;
490         char icondirstr[FILE_MAX];
491         char iconfilestr[FILE_MAX+16]; /* allow 256 chars for file+dir */
492         char olddir[FILE_MAX];
493         
494         list->first = list->last = NULL;
495
496 #ifdef WIN32
497         BLI_make_file_string("/", icondirstr, BLI_gethome(), "icons");
498 #else
499         BLI_make_file_string("/", icondirstr, BLI_gethome(), ".blender/icons");
500 #endif
501         
502         if(BLI_exists(icondirstr)==0)
503                 return;
504         
505         /* since BLI_getdir changes the current working directory, restore it 
506            back to old value afterwards */
507         if(!BLI_getwdN(olddir)) 
508                 restoredir = 0;
509         totfile = BLI_getdir(icondirstr, &dir);
510         if (restoredir)
511                 chdir(olddir);
512
513         for(i=0; i<totfile; i++) {
514                 if( (dir[i].type & S_IFREG) ) {
515                         char *filename = dir[i].relname;
516                         
517                         if(BLI_testextensie(filename, ".png")) {
518                         
519                                 /* check to see if the image is the right size, continue if not */
520                                 /* copying strings here should go ok, assuming that we never get back
521                                    a complete path to file longer than 256 chars */
522                                 sprintf(iconfilestr, "%s/%s", icondirstr, filename);
523                                 if(BLI_exists(iconfilestr)) bbuf = IMB_loadiffname(iconfilestr, IB_rect);
524                                 
525                                 ifilex = bbuf->x;
526                                 ifiley = bbuf->y;
527                                 IMB_freeImBuf(bbuf);
528                                 
529                                 if ((ifilex != ICON_IMAGE_W) || (ifiley != ICON_IMAGE_H))
530                                         continue;
531                         
532                                 /* found a potential icon file, so make an entry for it in the cache list */
533                                 ifile = MEM_callocN(sizeof(IconFile), "IconFile");
534                                 
535                                 BLI_strncpy(ifile->filename, filename, sizeof(ifile->filename));
536                                 ifile->index = index;
537
538                                 BLI_addtail(list, ifile);
539                                 
540                                 index++;
541                         }
542                 }
543         }
544         
545         /* free temporary direntry structure that's been created by BLI_getdir() */
546         i= totfile-1;
547         
548         for(; i>=0; i--){
549                 MEM_freeN(dir[i].relname);
550                 if (dir[i].string) MEM_freeN(dir[i].string);
551         }
552         free(dir);
553         dir= 0;
554 }
555
556 static void free_iconfile_list(struct ListBase *list)
557 {
558         IconFile *ifile=NULL, *next_ifile=NULL;
559         
560         for(ifile=list->first; ifile; ifile=next_ifile) {
561                 next_ifile = ifile->next;
562                 BLI_freelinkN(list, ifile);
563         }
564 }
565
566 int UI_iconfile_get_index(char *filename)
567 {
568         IconFile *ifile;
569         ListBase *list=&(iconfilelist);
570         
571         for(ifile=list->first; ifile; ifile=ifile->next) {
572                 if ( BLI_streq(filename, ifile->filename)) {
573                         return ifile->index;
574                 }
575         }
576         
577         return 0;
578 }
579
580 ListBase *UI_iconfile_list(void)
581 {
582         ListBase *list=&(iconfilelist);
583         
584         return list;
585 }
586
587
588 void UI_icons_free()
589 {
590         free_iconfile_list(&iconfilelist);
591         BKE_icons_free();
592 }
593
594 void UI_icons_free_drawinfo(void *drawinfo)
595 {
596         DrawInfo *di = drawinfo;
597
598         if (di)
599         {
600                 if (di->icon) {
601                         MEM_freeN(di->icon->rect);
602                         MEM_freeN(di->icon);
603                 }
604                 MEM_freeN(di);
605         }
606 }
607
608 static DrawInfo *icon_create_drawinfo()
609 {
610         DrawInfo *di = NULL;
611
612         di = MEM_callocN(sizeof(DrawInfo), "di_icon");
613         
614         di->drawFunc = 0;
615         di->w = ICON_DEFAULT_HEIGHT;
616         di->h = ICON_DEFAULT_HEIGHT;
617         di->icon = NULL;
618         di->aspect = 1.0f;
619
620         return di;
621 }
622
623 int UI_icon_get_width(int icon_id)
624 {
625         Icon *icon = NULL;
626         DrawInfo *di = NULL;
627
628         icon = BKE_icon_get(icon_id);
629         
630         if (!icon) {
631                 printf("UI_icon_get_width: Internal error, no icon for icon ID: %d\n", icon_id);
632                 return 0;
633         }
634         
635         di = (DrawInfo *)icon->drawinfo;
636         if (!di) {
637                 di = icon_create_drawinfo();
638                 icon->drawinfo = di;
639         }
640
641         if (di)
642                 return di->w;
643
644         return 0;
645 }
646
647 int UI_icon_get_height(int icon_id)
648 {
649         Icon *icon = NULL;
650         DrawInfo *di = NULL;
651
652         icon = BKE_icon_get(icon_id);
653         
654         if (!icon) {
655                 printf("UI_icon_get_height: Internal error, no icon for icon ID: %d\n", icon_id);
656                 return 0;
657         }
658         
659         di = (DrawInfo*)icon->drawinfo;
660
661         if (!di) {
662                 di = icon_create_drawinfo();
663                 icon->drawinfo = di;
664         }
665         
666         if (di)
667                 return di->h;
668
669         return 0;
670 }
671
672 void UI_icons_init(int first_dyn_id)
673 {
674         init_iconfile_list(&iconfilelist);
675         BKE_icons_init(first_dyn_id);
676         init_internal_icons();
677 }
678
679 static void icon_copy_rect(ImBuf *ibuf, unsigned int w, unsigned int h, unsigned int *rect)
680 {
681         struct ImBuf *ima;
682         unsigned int *drect, *srect;
683         float scaledx, scaledy;
684         short ex, ey, dx, dy;
685
686         /* paranoia test */
687         if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL))
688                 return;
689         
690         /* waste of cpu cyles... but the imbuf API has no other way to scale fast (ton) */
691         ima = IMB_dupImBuf(ibuf);
692         
693         if (!ima) 
694                 return;
695         
696         if (ima->x > ima->y) {
697                 scaledx = (float)w;
698                 scaledy =  ( (float)ima->y/(float)ima->x )*(float)w;
699         }
700         else {                  
701                 scaledx =  ( (float)ima->x/(float)ima->y )*(float)h;
702                 scaledy = (float)h;
703         }
704         
705         ex = (short)scaledx;
706         ey = (short)scaledy;
707         
708         dx = (w - ex) / 2;
709         dy = (h - ey) / 2;
710         
711         IMB_scalefastImBuf(ima, ex, ey);
712         
713         /* if needed, convert to 32 bits */
714         if(ima->rect==NULL)
715                 IMB_rect_from_float(ima);
716
717         srect = ima->rect;
718         drect = rect;
719
720         drect+= dy*w+dx;
721         for (;ey > 0; ey--){            
722                 memcpy(drect,srect, ex * sizeof(int));
723                 drect += w;
724                 srect += ima->x;
725         }
726         IMB_freeImBuf(ima);
727 }
728
729 /* Render size for preview images at level miplevel */
730 static int preview_render_size(int miplevel)
731 {
732         switch (miplevel) {
733                 case 0: return 32;
734                 case 1: return PREVIEW_DEFAULT_HEIGHT;
735         }
736         return 0;
737 }
738
739 static void icon_create_mipmap(struct PreviewImage* prv_img, int miplevel) 
740 {
741         unsigned int size = preview_render_size(miplevel);
742
743         if (!prv_img) {
744                 printf("Error: requested preview image does not exist");
745         }
746         if (!prv_img->rect[miplevel]) {
747                 prv_img->w[miplevel] = size;
748                 prv_img->h[miplevel] = size;
749                 prv_img->changed[miplevel] = 1;
750                 prv_img->rect[miplevel] = MEM_callocN(size*size*sizeof(unsigned int), "prv_rect"); 
751         }
752 }
753
754 /* create single icon from jpg, png etc. */
755 static void icon_from_image(Scene *scene, Image *img, int miplevel)
756 {
757         ImBuf *ibuf= NULL;
758         ImageUser iuser;
759         PreviewImage *pi;
760         unsigned int pr_size;
761         short image_loaded = 0;
762
763         /* img->ok is zero when Image cannot load */
764         if (img==NULL || img->ok==0)
765                 return;
766
767         /* setup dummy image user */
768         memset(&iuser, 0, sizeof(ImageUser));
769         iuser.ok= iuser.framenr= 1;
770         iuser.scene= scene;
771         
772         /* elubie: this needs to be changed: here image is always loaded if not
773            already there. Very expensive for large images. Need to find a way to 
774            only get existing ibuf */
775         
776         ibuf = BKE_image_get_ibuf(img, &iuser);
777         if(ibuf==NULL || ibuf->rect==NULL) {
778                 return;
779         }
780         
781         pi = BKE_previewimg_get((ID*)img);      
782         
783         if(!pi) {
784                 printf("preview image could'nt be allocated");
785                 return;
786         }
787         /* we can only create the preview rect here, since loading possibly deallocated
788            old preview */
789         icon_create_mipmap(pi, miplevel);
790
791         pr_size = img->preview->w[miplevel]*img->preview->h[miplevel]*sizeof(unsigned int);
792
793         image_loaded = 1;
794         icon_copy_rect(ibuf, img->preview->w[miplevel], img->preview->h[miplevel], img->preview->rect[miplevel]);       
795 }
796
797 static void set_alpha(char* cp, int sizex, int sizey, char alpha) 
798 {
799         int x,y;
800         for(y=0; y<sizey; y++) {
801                 for(x=0; x<sizex; x++, cp+=4) {
802                         cp[3]= alpha;
803                 }
804         }
805 }
806
807 /* only called when icon has changed */
808 /* only call with valid pointer from UI_icon_draw */
809 static void icon_set_image(Scene *scene, ID *id, PreviewImage* prv_img, int miplevel)
810 {
811         RenderInfo ri;  
812         unsigned int pr_size = 0;
813         
814         if (!prv_img) {
815                 printf("No preview image for this ID: %s\n", id->name);
816                 return;
817         }       
818
819         /* no drawing (see last parameter doDraw, just calculate preview image 
820                 - hopefully small enough to be fast */
821         if (GS(id->name) == ID_IM)
822                 icon_from_image(scene, (struct Image*)id, miplevel);
823         else {  
824                 /* create the preview rect */
825                 icon_create_mipmap(prv_img, miplevel);
826
827                 ri.curtile= 0;
828                 ri.tottile= 0;
829                 ri.pr_rectx = prv_img->w[miplevel];
830                 ri.pr_recty = prv_img->h[miplevel];
831                 pr_size = ri.pr_rectx*ri.pr_recty*sizeof(unsigned int);
832                 ri.rect = MEM_callocN(pr_size, "pr icon rect");
833
834                 ED_preview_iconrender(scene, id, ri.rect, ri.pr_rectx, ri.pr_recty);
835
836                 /* world is rendered with alpha=0, so it wasn't displayed 
837                    this could be render option for sky to, for later */
838                 if (GS(id->name) == ID_WO) { 
839                         set_alpha( (char*) ri.rect, ri.pr_rectx, ri.pr_recty, 255);
840                 } 
841                 else if (GS(id->name) == ID_MA) {
842                         Material* mat = (Material*)id;
843                         if (mat->material_type == MA_TYPE_HALO) {
844                                 set_alpha( (char*) ri.rect, ri.pr_rectx, ri.pr_recty, 255);
845                         }
846                 }
847
848                 memcpy(prv_img->rect[miplevel], ri.rect, pr_size);
849
850                 /* and clean up */
851                 MEM_freeN(ri.rect);
852         }
853 }
854
855 static void icon_draw_rect(float x, float y, int w, int h, float aspect, int rw, int rh, unsigned int *rect)
856 {
857         
858         glRasterPos2f(x, y);
859         // XXX ui_rasterpos_safe(x, y, aspect);
860         
861         if((w<1 || h<1)) {
862                 // XXX - TODO 2.5 verify whether this case can happen
863                 // and only print in debug
864                 printf("what the heck! - icons are %i x %i pixels?\n", w, h);
865         }
866         /* rect contains image in 'rendersize', we only scale if needed */
867         else if(rw!=w && rh!=h) {
868                 ImBuf *ima;
869                 if(w>2000 || h>2000) { /* something has gone wrong! */
870                         printf("insane icon size w=%d h=%d\n",w,h);
871                         return;
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                 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, ima->rect);
880                 
881                 IMB_freeImBuf(ima);
882         }
883         else
884                 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
885 }
886
887 /* Drawing size for preview images at level miplevel */
888 static int preview_size(int miplevel)
889 {
890         switch (miplevel) {
891                 case 0: return ICON_DEFAULT_HEIGHT;
892                 case 1: return PREVIEW_DEFAULT_HEIGHT;
893         }
894         return 0;
895 }
896
897 static void icon_draw_size(float x, float y, int icon_id, float aspect, int miplevel, int draw_size, int nocreate)
898 {
899         Icon *icon = NULL;
900         DrawInfo *di = NULL;
901         
902         icon = BKE_icon_get(icon_id);
903         
904         if (!icon) {
905                 printf("icon_draw_mipmap: Internal error, no icon for icon ID: %d\n", icon_id);
906                 return;
907         }
908         
909         di = (DrawInfo*)icon->drawinfo;
910         
911         if (!di) {
912                 di = icon_create_drawinfo();
913         
914                 icon->drawinfo = di;            
915                 icon->drawinfo_free = UI_icons_free_drawinfo;           
916         }
917         
918         di->aspect = aspect;
919         /* scale width and height according to aspect */
920         di->w = (int)(draw_size/di->aspect + 0.5f);
921         di->h = (int)(draw_size/di->aspect + 0.5f);
922         
923         if (di->drawFunc) {
924                 /* vector icons use the uiBlock transformation, they are not drawn
925                 with untransformed coordinates like the other icons */
926                 di->drawFunc(x, y, ICON_DEFAULT_HEIGHT, ICON_DEFAULT_HEIGHT, 1.0f); 
927         } 
928         else if (di->icon) {
929                 /* it is a builtin icon */              
930                 if (!di->icon->rect) return; /* something has gone wrong! */
931
932                 icon_draw_rect(x,y,di->w, di->h, di->aspect, di->icon->w, di->icon->h, di->icon->rect);
933         }
934         else {
935                 PreviewImage* pi = BKE_previewimg_get((ID*)icon->obj); 
936
937                 if (pi) {                       
938                         /* no create icon on this level in code */
939                         
940                         if (!pi->rect[miplevel]) return; /* something has gone wrong! */
941                         
942                         icon_draw_rect(x,y,di->w, di->h, di->aspect, pi->w[miplevel], pi->h[miplevel], pi->rect[miplevel]);             
943                 }
944         }
945 }
946
947 void ui_id_icon_render(Scene *scene, ID *id)
948 {
949         PreviewImage *pi = BKE_previewimg_get(id); 
950                 
951         if (pi) {                       
952                 if ((pi->changed[0] ||!pi->rect[0])) /* changed only ever set by dynamic icons */
953                 {
954                         /* create the preview rect if necessary */                              
955                         icon_set_image(scene, id, pi, 0);
956                         pi->changed[0] = 0;
957                 }
958         }
959 }
960
961 int ui_id_icon_get(Scene *scene, ID *id)
962 {
963         int iconid= 0;
964         
965         /* icon */
966         switch(GS(id->name))
967         {
968                 case ID_MA: /* fall through */
969                 case ID_TE: /* fall through */
970                 case ID_IM: /* fall through */
971                 case ID_WO: /* fall through */
972                 case ID_LA: /* fall through */
973                         iconid= BKE_icon_getid(id);
974                         /* checks if not exists, or changed */
975                         ui_id_icon_render(scene, id);
976                         break;
977                 default:
978                         break;
979         }
980
981         return iconid;
982 }
983
984 static void icon_draw_mipmap(float x, float y, int icon_id, float aspect, int miplevel, int nocreate)
985 {
986         int draw_size = preview_size(miplevel);
987         icon_draw_size(x,y,icon_id, aspect, miplevel, draw_size, nocreate);
988 }
989
990
991 void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect)
992 {
993         icon_draw_mipmap(x,y,icon_id, aspect, PREVIEW_MIPMAP_ZERO, 0);
994 }
995
996 void UI_icon_draw(float x, float y, int icon_id)
997 {
998         UI_icon_draw_aspect(x, y, icon_id, 1.0f);
999 }
1000
1001 void UI_icon_draw_size_blended(float x, float y, int size, int icon_id, int shade)
1002 {
1003         if(shade < 0) {
1004                 float r= (128+shade)/128.0f;
1005                 glPixelTransferf(GL_ALPHA_SCALE, r);
1006         }
1007
1008         icon_draw_size(x,y,icon_id, 1.0f, 0, size, 1);
1009
1010         if(shade < 0)
1011                 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
1012 }
1013
1014 void UI_icon_draw_preview(float x, float y, int icon_id, int nocreate)
1015 {
1016         icon_draw_mipmap(x,y,icon_id, 1.0f, PREVIEW_MIPMAP_LARGE, nocreate);
1017 }
1018
1019 void UI_icon_draw_aspect_blended(float x, float y, int icon_id, float aspect, int shade)
1020 {
1021         if(shade < 0) {
1022                 float r= (128+shade)/128.0f;
1023                 glPixelTransferf(GL_ALPHA_SCALE, r);
1024         }
1025
1026         UI_icon_draw_aspect(x, y, icon_id, aspect);
1027
1028         if(shade < 0)
1029                 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
1030 }