Warning fixes, one actual bug found in sequencer sound wave drawing. Also
[blender-staging.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 && !chdir(olddir))
577                 ; /* fix warning about checking return value */
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                 MEM_freeN(dir[i].path);
617                 if (dir[i].string) MEM_freeN(dir[i].string);
618         }
619         free(dir);
620         dir= 0;
621 }
622
623 static void free_iconfile_list(struct ListBase *list)
624 {
625         IconFile *ifile=NULL, *next_ifile=NULL;
626         
627         for(ifile=list->first; ifile; ifile=next_ifile) {
628                 next_ifile = ifile->next;
629                 BLI_freelinkN(list, ifile);
630         }
631 }
632
633 int UI_iconfile_get_index(char *filename)
634 {
635         IconFile *ifile;
636         ListBase *list=&(iconfilelist);
637         
638         for(ifile=list->first; ifile; ifile=ifile->next) {
639                 if ( BLI_streq(filename, ifile->filename)) {
640                         return ifile->index;
641                 }
642         }
643         
644         return 0;
645 }
646
647 ListBase *UI_iconfile_list(void)
648 {
649         ListBase *list=&(iconfilelist);
650         
651         return list;
652 }
653
654
655 void UI_icons_free()
656 {
657         if(icongltex.id) {
658                 glDeleteTextures(1, &icongltex.id);
659                 icongltex.id= 0;
660         }
661
662         free_iconfile_list(&iconfilelist);
663         BKE_icons_free();
664 }
665
666 void UI_icons_free_drawinfo(void *drawinfo)
667 {
668         DrawInfo *di = drawinfo;
669
670         if(di) {
671                 if(di->type == ICON_TYPE_BUFFER) {
672                         if(di->data.buffer.image) {
673                                 MEM_freeN(di->data.buffer.image->rect);
674                                 MEM_freeN(di->data.buffer.image);
675                         }
676                 }
677
678                 MEM_freeN(di);
679         }
680 }
681
682 static DrawInfo *icon_create_drawinfo()
683 {
684         DrawInfo *di = NULL;
685
686         di = MEM_callocN(sizeof(DrawInfo), "di_icon");
687         di->type= ICON_TYPE_PREVIEW;
688
689         return di;
690 }
691
692 int UI_icon_get_width(int icon_id)
693 {
694         Icon *icon = NULL;
695         DrawInfo *di = NULL;
696
697         icon = BKE_icon_get(icon_id);
698         
699         if (!icon) {
700                 if (G.f & G_DEBUG)
701                         printf("UI_icon_get_width: Internal error, no icon for icon ID: %d\n", icon_id);
702                 return 0;
703         }
704         
705         di = (DrawInfo *)icon->drawinfo;
706         if (!di) {
707                 di = icon_create_drawinfo();
708                 icon->drawinfo = di;
709         }
710
711         if (di)
712                 return ICON_DEFAULT_WIDTH;
713
714         return 0;
715 }
716
717 int UI_icon_get_height(int icon_id)
718 {
719         Icon *icon = NULL;
720         DrawInfo *di = NULL;
721
722         icon = BKE_icon_get(icon_id);
723         
724         if (!icon) {
725                 if (G.f & G_DEBUG)
726                         printf("UI_icon_get_height: Internal error, no icon for icon ID: %d\n", icon_id);
727                 return 0;
728         }
729         
730         di = (DrawInfo*)icon->drawinfo;
731
732         if (!di) {
733                 di = icon_create_drawinfo();
734                 icon->drawinfo = di;
735         }
736         
737         if (di)
738                 return ICON_DEFAULT_HEIGHT;
739
740         return 0;
741 }
742
743 void UI_icons_init(int first_dyn_id)
744 {
745         init_iconfile_list(&iconfilelist);
746         BKE_icons_init(first_dyn_id);
747         init_internal_icons();
748 }
749
750 /* Render size for preview images at level miplevel */
751 static int preview_render_size(int miplevel)
752 {
753         switch (miplevel) {
754                 case 0: return 32;
755                 case 1: return PREVIEW_DEFAULT_HEIGHT;
756         }
757         return 0;
758 }
759
760 static void icon_create_mipmap(struct PreviewImage* prv_img, int miplevel) 
761 {
762         unsigned int size = preview_render_size(miplevel);
763
764         if (!prv_img) {
765                 if (G.f & G_DEBUG)
766                         printf("Error: requested preview image does not exist");
767         }
768         if (!prv_img->rect[miplevel]) {
769                 prv_img->w[miplevel] = size;
770                 prv_img->h[miplevel] = size;
771                 prv_img->changed[miplevel] = 1;
772                 prv_img->rect[miplevel] = MEM_callocN(size*size*sizeof(unsigned int), "prv_rect"); 
773         }
774 }
775
776 /* only called when icon has changed */
777 /* only call with valid pointer from UI_icon_draw */
778 static void icon_set_image(bContext *C, ID *id, PreviewImage* prv_img, int miplevel)
779 {
780         if (!prv_img) {
781                 if (G.f & G_DEBUG)
782                         printf("No preview image for this ID: %s\n", id->name);
783                 return;
784         }       
785
786         /* create the preview rect */
787         icon_create_mipmap(prv_img, miplevel);
788
789         ED_preview_icon_job(C, prv_img, id, prv_img->rect[miplevel],
790                 prv_img->w[miplevel], prv_img->h[miplevel]);
791 }
792
793 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)
794 {
795         /* modulate color */
796         if(alpha != 1.0f)
797                 glPixelTransferf(GL_ALPHA_SCALE, alpha);
798
799         if(rgb) {
800                 glPixelTransferf(GL_RED_SCALE, rgb[0]);
801                 glPixelTransferf(GL_GREEN_SCALE, rgb[1]);
802                 glPixelTransferf(GL_BLUE_SCALE, rgb[2]);
803         }
804
805         /* position */
806         glRasterPos2f(x, y);
807         // XXX ui_rasterpos_safe(x, y, aspect);
808         
809         /* draw */
810         if((w<1 || h<1)) {
811                 // XXX - TODO 2.5 verify whether this case can happen
812                 if (G.f & G_DEBUG)
813                         printf("what the heck! - icons are %i x %i pixels?\n", w, h);
814         }
815         /* rect contains image in 'rendersize', we only scale if needed */
816         else if(rw!=w && rh!=h) {
817                 if(w>2000 || h>2000) { /* something has gone wrong! */
818                         if (G.f & G_DEBUG)
819                                 printf("insane icon size w=%d h=%d\n",w,h);
820                 }
821                 else {
822                         ImBuf *ima;
823
824                         /* first allocate imbuf for scaling and copy preview into it */
825                         ima = IMB_allocImBuf(rw, rh, 32, IB_rect, 0);
826                         memcpy(ima->rect, rect, rw*rh*sizeof(unsigned int));    
827                         
828                         /* scale it */
829                         IMB_scaleImBuf(ima, w, h);
830                         glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, ima->rect);
831                         
832                         IMB_freeImBuf(ima);
833                 }
834         }
835         else
836                 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
837
838         /* restore color */
839         if(alpha != 0.0f)
840                 glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
841         
842         if(rgb) {
843                 glPixelTransferf(GL_RED_SCALE, 1.0f);
844                 glPixelTransferf(GL_GREEN_SCALE, 1.0f);
845                 glPixelTransferf(GL_BLUE_SCALE, 1.0f);
846         }
847 }
848
849 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)
850 {
851         float x1, x2, y1, y2;
852
853         if(rgb) glColor4f(rgb[0], rgb[1], rgb[2], alpha);
854         else glColor4f(1.0f, 1.0f, 1.0f, alpha);
855
856         x1= ix*icongltex.invw;
857         x2= (ix + ih)*icongltex.invw;
858         y1= iy*icongltex.invh;
859         y2= (iy + ih)*icongltex.invh;
860
861         glEnable(GL_TEXTURE_2D);
862         glBindTexture(GL_TEXTURE_2D, icongltex.id);
863
864         glBegin(GL_QUADS);
865         glTexCoord2f(x1, y1);
866         glVertex2f(x, y);
867
868         glTexCoord2f(x2, y1);
869         glVertex2f(x+w, y);
870
871         glTexCoord2f(x2, y2);
872         glVertex2f(x+w, y+h);
873
874         glTexCoord2f(x1, y2);
875         glVertex2f(x, y+h);
876         glEnd();
877
878         glBindTexture(GL_TEXTURE_2D, 0);
879         glDisable(GL_TEXTURE_2D);
880 }
881
882 /* Drawing size for preview images at level miplevel */
883 static int preview_size(int miplevel)
884 {
885         switch (miplevel) {
886                 case 0: return ICON_DEFAULT_HEIGHT;
887                 case 1: return PREVIEW_DEFAULT_HEIGHT;
888         }
889         return 0;
890 }
891
892 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)
893 {
894         Icon *icon = NULL;
895         DrawInfo *di = NULL;
896         IconImage *iimg;
897         int w, h;
898         
899         icon = BKE_icon_get(icon_id);
900         
901         if (!icon) {
902                 if (G.f & G_DEBUG)
903                         printf("icon_draw_mipmap: Internal error, no icon for icon ID: %d\n", icon_id);
904                 return;
905         }
906
907         di = (DrawInfo*)icon->drawinfo;
908         
909         if (!di) {
910                 di = icon_create_drawinfo();
911         
912                 icon->drawinfo = di;            
913                 icon->drawinfo_free = UI_icons_free_drawinfo;           
914         }
915         
916         /* scale width and height according to aspect */
917         w = (int)(draw_size/aspect + 0.5f);
918         h = (int)(draw_size/aspect + 0.5f);
919         
920         if(di->type == ICON_TYPE_VECTOR) {
921                 /* vector icons use the uiBlock transformation, they are not drawn
922                 with untransformed coordinates like the other icons */
923                 di->data.vector.func(x, y, ICON_DEFAULT_HEIGHT, ICON_DEFAULT_HEIGHT, 1.0f); 
924         } 
925         else if(di->type == ICON_TYPE_TEXTURE) {
926                 icon_draw_texture(x, y, w, h, di->data.texture.x, di->data.texture.y,
927                         di->data.texture.w, di->data.texture.h, alpha, rgb);
928         }
929         else if(di->type == ICON_TYPE_BUFFER) {
930                 /* it is a builtin icon */              
931                 iimg= di->data.buffer.image;
932
933                 if(!iimg->rect) return; /* something has gone wrong! */
934
935                 icon_draw_rect(x, y, w, h, aspect, iimg->w, iimg->h, iimg->rect, alpha, rgb);
936         }
937         else if(di->type == ICON_TYPE_PREVIEW) {
938                 PreviewImage* pi = BKE_previewimg_get((ID*)icon->obj); 
939
940                 if(pi) {                        
941                         /* no create icon on this level in code */
942                         if(!pi->rect[miplevel]) return; /* something has gone wrong! */
943                         
944                         /* preview images use premul alpha ... */
945                         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
946                         icon_draw_rect(x, y, w, h, aspect, pi->w[miplevel], pi->h[miplevel], pi->rect[miplevel], 1.0f, NULL);
947                         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
948                 }
949         }
950 }
951
952 void ui_id_icon_render(bContext *C, ID *id, int preview)
953 {
954         PreviewImage *pi = BKE_previewimg_get(id); 
955                 
956         if (pi) {                       
957                 if ((pi->changed[0] ||!pi->rect[0])) /* changed only ever set by dynamic icons */
958                 {
959                         /* create the preview rect if necessary */                              
960                         
961                         icon_set_image(C, id, pi, 0);           /* icon size */
962                         if (preview)
963                                 icon_set_image(C, id, pi, 1);   /* preview size */
964                         
965                         pi->changed[0] = 0;
966                 }
967         }
968 }
969
970 int ui_id_icon_get(bContext *C, ID *id, int preview)
971 {
972         int iconid= 0;
973         
974         /* icon */
975         switch(GS(id->name))
976         {
977                 case ID_MA: /* fall through */
978                 case ID_TE: /* fall through */
979                 case ID_IM: /* fall through */
980                 case ID_WO: /* fall through */
981                 case ID_LA: /* fall through */
982                         iconid= BKE_icon_getid(id);
983                         /* checks if not exists, or changed */
984                         ui_id_icon_render(C, id, preview);
985                         break;
986                 default:
987                         break;
988         }
989
990         return iconid;
991 }
992
993 static void icon_draw_mipmap(float x, float y, int icon_id, float aspect, float alpha, int miplevel, int nocreate)
994 {
995         int draw_size = preview_size(miplevel);
996         icon_draw_size(x, y, icon_id, aspect, alpha, NULL, miplevel, draw_size, nocreate);
997 }
998
999 void UI_icon_draw_aspect(float x, float y, int icon_id, float aspect, float alpha)
1000 {
1001         icon_draw_mipmap(x, y, icon_id, aspect, alpha, PREVIEW_MIPMAP_ZERO, 0);
1002 }
1003
1004 void UI_icon_draw_aspect_color(float x, float y, int icon_id, float aspect, float *rgb)
1005 {
1006         int draw_size = preview_size(PREVIEW_MIPMAP_ZERO);
1007         icon_draw_size(x, y, icon_id, aspect, 1.0f, rgb, PREVIEW_MIPMAP_ZERO, draw_size, 0);
1008 }
1009
1010 void UI_icon_draw(float x, float y, int icon_id)
1011 {
1012         UI_icon_draw_aspect(x, y, icon_id, 1.0f, 1.0f);
1013 }
1014
1015 void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha)
1016 {
1017         icon_draw_size(x, y, icon_id, 1.0f, alpha, NULL, 0, size, 1);
1018 }
1019
1020 void UI_icon_draw_preview(float x, float y, int icon_id)
1021 {
1022         icon_draw_mipmap(x, y, icon_id, 1.0f, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
1023 }
1024
1025 void UI_icon_draw_preview_aspect(float x, float y, int icon_id, float aspect)
1026 {
1027         icon_draw_mipmap(x, y, icon_id, aspect, 1.0f, PREVIEW_MIPMAP_LARGE, 0);
1028 }
1029
1030 void UI_icon_draw_preview_aspect_size(float x, float y, int icon_id, float aspect, int size)
1031 {
1032         icon_draw_size(x, y, icon_id, aspect, 1.0f, NULL, PREVIEW_MIPMAP_LARGE, size, 0);
1033 }
1034