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