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