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