Merged 15170:15635 from trunk (no conflicts or even merges)
[blender.git] / source / blender / src / drawoops.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  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <math.h>
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include "BMF_Api.h"
39
40 #include "BLI_blenlib.h"
41 #include "BLI_arithb.h"
42
43 #include "DNA_ID.h"
44 #include "DNA_object_types.h"
45 #include "DNA_oops_types.h"
46 #include "DNA_scene_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_space_types.h"
49 #include "DNA_view2d_types.h"
50
51 #include "BKE_utildefines.h"
52 #include "BKE_global.h"
53
54 #include "BIF_interface.h"
55 #include "BIF_interface_icons.h"
56 #include "BIF_language.h"
57 #include "BIF_gl.h"
58 #include "BIF_glutil.h"
59 #include "BIF_mywindow.h"
60 #include "BIF_outliner.h"
61 #include "BIF_resources.h"
62 #include "BIF_screen.h"
63
64 /*  #include "BIF_drawoops.h" bad name :(*/
65 #include "BIF_oops.h"
66
67 #include "BSE_drawipo.h"
68 #include "BSE_drawoops.h"
69
70 float aspect;
71 void *font;
72
73
74 static float icon_width();
75 float center_oops_text(char *str);
76
77
78 void boundbox_oops(short sel)
79 {
80         Oops *oops;
81         float min[2], max[2];
82         int ok= 0;
83         
84         if(G.soops==0) return;
85         
86         min[0]= 1000.0;
87         max[0]= -1000.0;
88         min[1]= 1000.0;
89         max[1]= -1000.0;
90         
91         oops= G.soops->oops.first;
92         while(oops) {
93                 if ((oops->hide==0 && !sel) || (sel && oops->flag & SELECT )) {
94                         ok= 1;
95                         
96                         min[0]= MIN2(min[0], oops->x);
97                         max[0]= MAX2(max[0], oops->x+OOPSX);
98                         min[1]= MIN2(min[1], oops->y);
99                         max[1]= MAX2(max[1], oops->y+OOPSY);
100                 }
101                 oops= oops->next;
102         }
103         
104         if(ok==0) return;
105         
106         G.v2d->tot.xmin= min[0];
107         G.v2d->tot.xmax= max[0];
108         G.v2d->tot.ymin= min[1];
109         G.v2d->tot.ymax= max[1];
110         
111 }
112
113 void give_oopslink_line(Oops *oops, OopsLink *ol, float *v1, float *v2)
114 {
115
116         if(ol->to && ol->to->hide==0) {
117                 v1[0]= oops->x+ol->xof;
118                 v1[1]= oops->y+ol->yof;
119                 v2[0]= ol->to->x+OOPSX/2;
120                 v2[1]= ol->to->y;
121         }
122         else if(ol->from && ol->from->hide==0) {
123                 v1[0]= ol->from->x + ol->xof;
124                 v1[1]= ol->from->y + ol->xof;
125                 v2[0]= oops->x+OOPSX/2;
126                 v2[1]= oops->y;
127         }
128 }
129
130 void draw_oopslink(Oops *oops)
131 {
132         OopsLink *ol;
133         float vec[4][3], dist, spline_step;
134         short curve_res;
135         
136         if(oops->type==ID_SCE || oops->type==ID_GR) {
137                 if(oops->flag & SELECT) {
138                         /* when using python Mesh to make meshes a file was saved
139                         that had an oops with no ID, stops a segfault when looking for lib */
140                         if(oops->id && oops->id->lib) cpack(0x4080A0);
141                         else cpack(0x808080);
142                 }
143                 else cpack(0x606060);
144         }
145         else {
146                 if(oops->flag & SELECT) {
147                         if(oops->id && oops->id->lib) cpack(0x11AAFF);
148                         else cpack(0xFFFFFF);
149                 }
150                 else cpack(0x0);
151         }
152         
153         glEnable(GL_MAP1_VERTEX_3);
154         vec[0][2]= vec[1][2]= vec[2][2]= vec[3][2]= 0.0; /* only 2d spline, set the Z to 0*/
155         
156         ol= oops->link.first;
157         while(ol) {
158                 if(ol->to && ol->to->hide==0) {
159                         
160                         give_oopslink_line(oops, ol, vec[0], vec[3]);
161                         
162                         dist= 0.5*VecLenf(vec[0], vec[3]);
163
164                         /* check ol->xof and yof for direction */
165                         if(ol->xof == 0.0) {
166                                 vec[1][0]= vec[0][0]-dist;
167                                 vec[1][1]= vec[0][1];
168                         }
169                         else if(ol->xof==OOPSX) {
170                                 vec[1][0]= vec[0][0]+dist;
171                                 vec[1][1]= vec[0][1];
172                         }
173                         else {
174                                 vec[1][0]= vec[0][0];
175                                 vec[1][1]= vec[0][1]+dist;
176                         }
177                         
178                         /* v3 is always pointing down */
179                         vec[2][0]= vec[3][0];
180                         vec[2][1]= vec[3][1] - dist;
181                         
182                         if( MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > G.v2d->cur.xmax); /* clipped */  
183                                 else if ( MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < G.v2d->cur.xmin); /* clipped */
184                                         else {
185                                                 /* calculate a curve resolution to use based on the length of the curve.*/
186                                                 curve_res = MIN2(40, MAX2(2, 2*dist/aspect));
187                                                 
188                                                 /* we can reuse the dist variable here to increment the GL curve eval amount*/
189                                                 dist = (float)1/curve_res;
190                                                 spline_step = 0.0;
191                                                 
192                                                 glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
193                                                 glBegin(GL_LINE_STRIP);
194                                                 while (spline_step < 1.000001) {
195                                                         glEvalCoord1f(spline_step);
196                                                         spline_step += dist;
197                                                 }
198                                                 glEnd();
199                                         }
200                         
201                 }
202                 ol= ol->next;
203         }
204 }
205
206 static float icon_width()
207 {
208     /* change it in *one place* when you mess around */
209     return 0.8*OOPSY;
210 }
211
212 void draw_icon_oops(float *co, short type)
213 {
214         BIFIconID icon;
215     float ofs;
216         
217         switch(type) {
218         default: return;
219
220         case ID_OB:     icon= ICON_OBJECT_HLT; break;
221         case ID_ME:     icon= ICON_MESH_HLT; break;
222         case ID_CU:     icon= ICON_CURVE_HLT; break;
223         case ID_MB:     icon= ICON_MBALL_HLT; break;
224         case ID_LT:     icon= ICON_LATTICE_HLT; break;
225         case ID_LA:     icon= ICON_LAMP_HLT; break;
226         case ID_MA:     icon= ICON_MATERIAL_HLT; break;
227         case ID_TE:     icon= ICON_TEXTURE_HLT; break;
228         case ID_IP:     icon= ICON_IPO_HLT; break;
229         case ID_LI:     icon= ICON_LIBRARY_HLT; break;
230         case ID_IM:     icon= ICON_IMAGE_HLT; break;
231         case ID_GR:     icon= ICON_CIRCLE_DEHLT; break;
232         case ID_CA:     icon= ICON_CAMERA_DEHLT; break;
233         case ID_AR:     icon= ICON_ARMATURE; break;
234         }
235
236         glEnable(GL_BLEND);
237         glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA); 
238
239     /* height of box is OOPSY...icon is centered vertically */
240     ofs = (OOPSY - icon_width())/2.0;
241         BIF_icon_draw_aspect(co[0], co[1]+ofs, icon, icon_width()*aspect*ICON_DEFAULT_HEIGHT/OOPSY);
242
243         glBlendFunc(GL_ONE,  GL_ZERO); 
244         glDisable(GL_BLEND);
245 }
246
247 void mysbox(float x1, float y1, float x2, float y2)
248 {
249         float vec[2];
250         
251         glBegin(GL_LINE_LOOP);
252         vec[0]= x1; vec[1]= y1;
253         glVertex2fv(vec);
254         vec[0]= x2;
255         glVertex2fv(vec);
256         vec[1]= y2;
257         glVertex2fv(vec);
258         vec[0]= x1;
259         glVertex2fv(vec);
260         glEnd();
261 }
262
263 unsigned int give_oops_color(short type, short sel, unsigned int *border)
264 {
265         unsigned int body;
266         /* also finds out if a dashed line should be drawn */
267
268         switch(type) {
269         case ID_OB:
270                 body= 0x707070; break;
271         case ID_SCE:
272                 body= 0x608060; break;
273         case ID_MA:
274                 body= 0x808060; break;
275         case ID_TE:
276                 body= 0x7080a0; break;
277         case ID_IP:
278                 body= 0x906050; break;
279         case ID_LA:
280                 body= 0x608080; break;
281         case ID_LI:
282                 body= 0x2198DC; break;
283         case ID_IM:
284                 body= 0x35659F; break;
285         case ID_GR:
286                 body= 0x507050; break;
287         case ID_CA:
288                 body= 0x7570A0; break;
289         case ID_LT:
290                 body= 0xA08090; break;
291         case ID_AR:
292                 body= 0x70B0C0; break;
293         default:
294                 body= 0x606070; break;
295         }
296
297         if(sel) {
298                 if(G.moving) *border= 0xf0f0f0;
299                 else *border= 0xc0c0c0; 
300         }
301         else *border= 0x0;
302
303         
304         return body;
305 }
306
307
308 float center_oops_text(char *str)
309 /* gives x offset at which to draw oops text -- takes icon into account */
310 {
311     int len;
312     float width;
313
314         len= strlen(str);
315     if(len < 1) return 0;
316
317     /* center at box width of OOPSX */
318         width= aspect*BIF_GetStringWidth(font, str, 0) + icon_width();
319
320     while(width > OOPSX && len >= 0) {
321         str[len] = 0;
322         width= aspect*BIF_GetStringWidth(font, str, 0) + icon_width();
323         len--;
324     }
325     return (OOPSX - width)/2;
326 }
327
328 void draw_oops(Oops *oops)
329 {
330         OopsLink *ol;
331         float v1[2], x1, y1, x2, y2, f1, f2;
332         unsigned int body, border;
333         short line= 0;
334         char str[FILE_MAXDIR+FILE_MAXFILE+5];
335
336         x1= oops->x; 
337         x2= oops->x+OOPSX;
338         y1= oops->y; 
339         y2= oops->y+OOPSY;
340
341     /* do clip */
342         if(x2 < G.v2d->cur.xmin || x1 > G.v2d->cur.xmax) return;
343         if(y2 < G.v2d->cur.ymin || y1 > G.v2d->cur.ymax) return;
344
345         body= give_oops_color(oops->type, oops->flag & SELECT, &border);
346         if(oops->id== (ID *)((G.scene->basact) ? (G.scene->basact->object) : 0)) line= 1;
347         else if(oops->id== (ID *)G.scene) line= 1;
348
349         if (!oops->id) return;
350
351         if(oops->id->us) {
352                 cpack(body);
353
354                 glRectf(x1, y1, x2, y2);
355         }
356
357         if(oops->id->lib) { 
358                 if(oops->id->flag & LIB_INDIRECT) cpack(0x1144FF);
359                 else cpack(0x11AAFF);
360
361                 glRectf(x2-0.2*OOPSX,  y2-0.2*OOPSX,  x2-0.1*OOPSX,  y2-0.1*OOPSX);
362         }
363
364         v1[0]= x1; 
365         v1[1] = y1;
366
367         if(oops->type==ID_LI) {
368                 sprintf(str, " %s", ((Library *)oops->id)->name);
369         }
370         else {
371                 sprintf(str, " %s", oops->id->name+2);
372         }
373
374     BIF_SetScale(aspect);
375     v1[0] += center_oops_text(str);
376
377     draw_icon_oops(v1, oops->type);
378     v1[0] += icon_width();
379
380     v1[1] = y1+(y2-y1)/3.0;
381         if(oops->flag & SELECT) BIF_ThemeColor(TH_TEXT_HI);
382         else BIF_ThemeColor(TH_TEXT);
383         glRasterPos2f(v1[0],  v1[1]);
384     BIF_RasterPos(v1[0], v1[1]);
385     BIF_SetScale(aspect);
386         BIF_DrawString(font, str, 0);
387         
388     
389     if(line) setlinestyle(2);
390         cpack(border);
391
392         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
393         glRectf(x1,  y1,  x2,  y2);
394         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
395         if(line) setlinestyle(0);
396
397         /* connection blocks */
398         ol= oops->link.first;
399         while(ol) {
400
401                 f1= x1+ol->xof; 
402                 f2= y1+ol->yof;
403
404                 body= give_oops_color(ol->type, oops->flag & SELECT, &border);
405                 cpack(body);
406
407                 glRectf(f1-.2,  f2-.2,  f1+.2,  f2+.2);
408                 cpack(border);
409
410                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
411
412                 glRectf(f1-.2,  f2-.2,  f1+.2,  f2+.2);
413
414                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
415
416                 ol= ol->next;
417         }
418
419         if(oops->flag & OOPS_REFER) {
420         /* Draw the little rounded connection point */
421                 glColor3ub(0, 0, 0);
422                 glPushMatrix();
423
424                 glTranslatef(oops->x + 0.5*OOPSX, oops->y, 0.0);
425                 glutil_draw_filled_arc(0.0, M_PI, 0.05*OOPSX, 7);
426
427                 glPopMatrix();
428         }
429 }
430
431 void drawoopsspace(ScrArea *sa, void *spacedata)
432 {
433         SpaceOops *soops= spacedata;
434         Oops *oops;
435         float col[3];
436         
437         BIF_GetThemeColor3fv(TH_BACK, col);
438
439         if(soops==0) return;    
440         
441         /* darker background for oops */
442         if(soops->type!=SO_OUTLINER) {
443                 col[0] = col[0] * 0.75; col[1] = col[1] * 0.75; col[2] = col[2] * 0.75;
444         }
445         
446         glClearColor(col[0], col[1], col[2], 0.0);
447         glClear(GL_COLOR_BUFFER_BIT);
448         
449         if(soops->type==SO_OUTLINER) draw_outliner(sa, soops);
450         else {
451                 build_oops();   /* changed to become first call... */
452                 
453                 boundbox_oops(0);
454                 calc_scrollrcts(sa, G.v2d, curarea->winx, curarea->winy);
455
456         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
457         bwin_clear_viewmat(sa->win);    /* clear buttons view */
458         glLoadIdentity();
459
460         aspect= (G.v2d->cur.xmax - G.v2d->cur.xmin)/((float)sa->winx);
461         font= uiSetCurFont_ext(30*aspect);
462
463                 calc_ipogrid(); /* for scrollvariables */
464                 
465         /* drop shadow */
466                 BIF_ThemeColorShade(TH_BACK, -96); /* drop shadow color */
467         glRectf(G.v2d->tot.xmin-1, G.v2d->tot.ymin-3, G.v2d->tot.xmax+3,
468                 G.v2d->tot.ymax+1);
469         
470         /* light square in the center */
471                 BIF_GetThemeColor3fv(TH_BACK, col);
472                 glColor3fv(col);
473         glRectf(G.v2d->tot.xmin-2, G.v2d->tot.ymin-2,  G.v2d->tot.xmax+2,
474                 G.v2d->tot.ymax+2);
475
476                 /* box around the oops. */
477                 cpack(0x0);
478         mysbox(G.v2d->tot.xmin-2, G.v2d->tot.ymin-2,  G.v2d->tot.xmax+2,
479                 G.v2d->tot.ymax+2);
480         
481
482                 /* Draw unselected oops links */
483         for(oops= soops->oops.first; oops; oops = oops->next) {
484                         if(oops->hide==0 && (oops->flag & SELECT)); else {
485                                 draw_oopslink(oops);
486                         }
487                 }
488                 
489                 /* Draw selected oops links */
490         for(oops= soops->oops.first; oops; oops = oops->next) {
491                         if(oops->hide==0 && (oops->flag & SELECT)) {
492                                 draw_oopslink(oops);
493                         }
494                 }                       
495                 
496         for(oops= soops->oops.first; oops; oops = oops->next) {
497                         if(oops->hide==0) {
498                                 if(oops->flag & SELECT); else draw_oops(oops);
499                         }
500                 }
501                 
502         for(oops= soops->oops.first; oops; oops = oops->next) {
503                         if(oops->hide==0) {
504                                 if(oops->flag & SELECT) draw_oops(oops);
505                         }
506                 }
507         }
508         
509         /* restore viewport */
510         mywinset(curarea->win);
511         
512         /* ortho at pixel level curarea */
513         myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
514
515         if(soops->type==SO_OUTLINER) {
516                 if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
517                         if(G.v2d->scroll) drawscroll(0);                
518                 }
519         }
520         draw_area_emboss(sa);   
521         
522         curarea->win_swap= WIN_BACK_OK;
523 }
524
525
526
527