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