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