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