Two in one:
[blender.git] / source / blender / src / oops.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  */
32
33 #include <math.h> 
34 #include "MEM_guardedalloc.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_arithb.h"
38
39 #include "DNA_curve_types.h"
40 #include "DNA_image_types.h"
41 #include "DNA_ipo_types.h"
42 #include "DNA_lamp_types.h"
43 #include "DNA_material_types.h"
44 #include "DNA_mesh_types.h"
45 #include "DNA_meta_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_oops_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_space_types.h"
50 #include "DNA_texture_types.h"
51 #include "DNA_texture_types.h"
52 #include "DNA_key_types.h"
53
54 #include "BKE_utildefines.h"
55 #include "BKE_global.h"
56 #include "BKE_library.h"
57 #include "BKE_main.h"
58
59 #include "BIF_screen.h"
60 #include "BIF_space.h"
61 #include "BIF_toolbox.h"
62 #include "BIF_oops.h"
63 #include "BIF_drawoops.h"
64 #include "BIF_outliner.h"
65
66 #include "blendef.h"
67 #include "mydevice.h"
68
69 #ifdef HAVE_CONFIG_H
70 #include <config.h>
71 #endif
72
73 static int correct_oops_y(Oops *oops);
74
75
76 Oops *add_oops(void *id)
77 {
78         Oops *oops;
79         
80         if(G.soops==0) return NULL;
81         oops= MEM_callocN(sizeof(Oops), "oops");
82
83         BLI_addtail(&G.soops->oops, oops);
84         
85         oops->id= id;
86         oops->type= GS(oops->id->name);
87         
88         return oops;
89 }
90
91
92 Oops *find_oops(ID *id)
93 {
94         Oops *oops;
95
96         /* searching for an oops with this ID */
97         oops= G.soops->oops.first;
98         while(oops) {
99                 if(oops->id == id) {
100                         /* this error once happened. securing it doesnt harm */
101                         if(oops->type != GS(id->name)) oops->id= 0;
102                         else break;
103                 }
104                 oops= oops->next;
105         }
106         return oops;
107 }
108
109 /* never even called! (ton) */
110 int test_oops(Oops *oops)
111 {
112         /* test if own ID block still exists */
113         ListBase *lb;
114         ID *id;
115         
116         if(G.soops==0) return 0;
117         
118         lb= wich_libbase(G.main, oops->type);
119         id= lb->first;
120         while(id) {
121                 if(id==oops->id) break;
122                 id= id->next;
123         }
124         
125         if(id==0) return 0;
126         
127         
128         return 1;
129 }
130
131 void test_oopslinko(OopsLink *ol)
132 {
133         /* test if links exist */
134         Oops *oops;
135         ListBase *lb;
136         ID *id, *from;
137         
138         if(G.soops==0) return;
139         
140         ol->to= 0;
141         from= *ol->idfrom;
142
143         if(from==0) return;
144         
145         lb= wich_libbase(G.main, ol->type);
146         id= lb->first;
147         while(id) {
148                 if(id==from) break;
149                 id= id->next;
150         }
151         
152         if(id==0) {
153                 /* ID does not exist anymore */
154                 *ol->idfrom= 0;
155         }
156         else {
157                 /* search for oops with this ID */
158                 oops= G.soops->oops.first;
159                 while(oops) {
160                         if(oops->id == id) break;
161                         oops= oops->next;
162                 }
163                 
164                 ol->to= oops;
165         }
166 }
167
168 void test_oopslink(OopsLink *ol)
169 {
170         /* test if links exist */
171         Oops *oops;
172         ID *from;
173         
174         if(G.soops==0) return;
175         
176         ol->to= 0;
177         from= *ol->idfrom;
178
179         if(from==0) return;
180         
181         /* search for oops with this ID */
182         oops= G.soops->oops.first;
183         while(oops) {
184                 if(oops->id == from) break;
185                 oops= oops->next;
186         }
187         
188         ol->to= oops;
189         if(oops) oops->flag |= OOPS_REFER;
190 }
191
192
193 OopsLink *add_oopslink(char *name, Oops *oops, short type, void *from, float xof, float yof)
194 {
195         OopsLink *ol;
196         
197         if(G.soops==0) return NULL;
198         
199         /* testing if it exsists:  */
200         /* ol= oops->link.first; */
201         /* while(ol) { */
202         /*      if(ol->idfrom == from) { */
203         /*              strncpy(ol->name, name, 11); */
204         /*              ol->type= type; */
205         /*              ol->xof= xof; */
206         /*              ol->yof= yof; */
207         /*              return ol; */
208         /*      } */
209         /*      ol= ol->next; */
210         /* } */
211         
212         if(* ((int *)from) == 0) return NULL;
213         
214         /* make new */
215         ol= MEM_callocN(sizeof(OopsLink), "oopslink");
216
217         BLI_addtail(&oops->link, ol);
218
219         ol->type= type;
220         ol->idfrom= from;
221         ol->xof= xof;
222         ol->yof= yof;
223         BLI_strncpy(ol->name, name, sizeof(ol->name));
224         
225         return ol;
226 }
227
228 int oops_test_overlap(Oops *test)
229 {
230         Oops *oops;
231         rctf rt, ro;
232         
233         rt.xmin= test->x;
234         rt.xmax= (float)(test->x+OOPSX);
235         rt.ymin= test->y;
236         rt.ymax= (float)(test->y+OOPSY);
237
238         oops= G.soops->oops.first;
239         while(oops) {
240                 if(oops!=test) {        /* do net test for hide: is only a temporal flag */
241                         
242                         ro.xmin= oops->x;
243                         ro.xmax= (float)(oops->x+OOPSX);
244                         ro.ymin= oops->y;
245                         ro.ymax= (float)(oops->y+OOPSY);
246
247                         if( BLI_isect_rctf(&rt, &ro, 0) ) return 1;
248                         
249                 }
250                 oops= oops->next;
251         }
252         
253         return 0;
254 }
255
256 int oops_test_overlaphide(Oops *test)
257 {
258         Oops *oops;
259         rctf rt, ro;
260         
261         rt.xmin= (float)(test->x);
262         rt.xmax= (float)(test->x+OOPSX);
263         rt.ymin= (float)(test->y);
264         rt.ymax= (float)(test->y+OOPSY);
265
266         oops= G.soops->oops.first;
267         while(oops) {
268                 if(oops->hide==0 && oops!=test) {       /* do test for hide, but not use it during build_oops */
269                         
270                         ro.xmin= oops->x;
271                         ro.xmax= (float)(oops->x+OOPSX);
272                         ro.ymin= oops->y;
273                         ro.ymax= (float)(oops->y+OOPSY);
274
275                         if( BLI_isect_rctf(&rt, &ro, 0) ) return 1;
276                         
277                 }
278                 oops= oops->next;
279         }
280         
281         return 0;
282 }
283
284 float oopslink_totlen(Oops *oops)
285 {
286         OopsLink *ol;
287         float vec[4], dx, dy, len= 0.0;
288         
289         
290         ol= oops->link.first;
291         while(ol) {
292                 if(ol->to) {
293                         give_oopslink_line(oops, ol, vec, vec+2);
294                         
295                         dx= vec[0]-vec[2];
296                         dy= vec[1]-vec[3];
297                         
298                         len+= (float)sqrt( dx*dx + dy*dy );
299                 }
300                 ol= ol->next;
301         }
302         return len;
303 }
304
305
306 void add_from_link(Oops *from, Oops *oops)
307 {
308         OopsLink *ol;
309         
310         ol= MEM_callocN(sizeof(OopsLink), "oopslinktemp");
311         BLI_addtail(&oops->link, ol);
312         ol->from= from;
313         
314 }
315
316 void shuffle_oops()
317 {
318         Oops *o2, *oops;
319         OopsLink *ol, *oln;
320         float olen, len1, f1, f2;
321         int go= 1, tot=0, dir=1, type1, type2;
322         
323         
324         /* we take two oopses, calc the 'beauty' and the exchanged beauty */
325         
326         if(G.soops==0) return;
327         
328         waitcursor(1);
329         
330         /* to make it 100% OK and fast: temporal insert
331          * to the ooplinklist - per oops - the 'from' links.
332          * Don't forget to free!
333          */
334         
335         oops= G.soops->oops.first;
336         while(oops) {
337                 if(oops->hide==0) {
338                         ol= oops->link.first;
339                         while(ol) {
340                                 if(ol->to && ol->to->hide==0) {
341                                         if(ol->to->flag & SELECT) {
342                                                 add_from_link(oops, ol->to);
343                                         }
344                                 }
345                                 ol= ol->next;
346                         }
347                 }
348                 oops= oops->next;
349         }
350         
351         while(go) {
352                 
353                 go= 0;
354                 dir= 1-dir;
355                 tot++;
356                 
357                 if(dir) oops= G.soops->oops.last;
358                 else oops= G.soops->oops.first;
359                 while(oops) {
360                         
361                         if(oops->link.first && oops->hide==0 && (oops->flag & SELECT)) {
362                                 /* find a good exchangable pair */
363                                 olen= oopslink_totlen(oops);
364                                 
365                                 if(dir) o2= oops->prev;
366                                 else o2= oops->next;
367                                 
368                                 if ELEM3(oops->type, ID_OB, ID_LI, ID_SCE) type1= 1; else type1= 0;
369                                         
370
371                                 while(o2) {
372                                         if(o2->hide==0 && (o2->flag & SELECT)) {
373                                         
374                                                 if ELEM3(o2->type, ID_OB, ID_LI, ID_SCE) type2= 1; else type2= 0;
375                                                 
376                                                 if(type1==type2) {
377                                         
378                                                         len1= oopslink_totlen(o2);
379                                                         
380                                                         SWAP(float, oops->x, o2->x);
381                                                         SWAP(float, oops->y, o2->y);
382                                                         
383                                                         f1= oopslink_totlen(oops);
384                                                         f2= oopslink_totlen(o2);
385                                                         
386                                                         if( f1<=olen && f2<len1) {              /* 1 x <= !!! */
387                                                                 olen= oopslink_totlen(oops);
388                                                                 go= 1;
389                                                         }
390                                                         else {
391                                                                 SWAP(float, oops->x, o2->x);
392                                                                 SWAP(float, oops->y, o2->y);
393                                                         }
394                                                 }
395                                         }
396                                         if(dir) o2= o2->prev;
397                                         else o2= o2->next;
398                                 }
399                         }       
400                         if(dir) oops= oops->prev;
401                         else oops= oops->next;
402                         
403                         
404                 }
405                 if(tot>5) break;
406         }
407         waitcursor(0);
408         
409         /* free the from links */
410         oops= G.soops->oops.first;
411         while(oops) {
412                 if(oops->hide==0) {
413                         ol= oops->link.first;
414                         while(ol) {
415                                 oln= ol->next;
416                                 if(ol->from) {
417                                         BLI_remlink(&oops->link, ol);
418                                         MEM_freeN(ol);
419                                 }
420                                 ol= oln;
421                         }
422                 }
423                 oops= oops->next;
424         }
425
426         allqueue(REDRAWOOPS, 1);
427 }
428
429 void shrink_oops()
430 {
431         Oops *oops;
432         OopsLink *ol;
433         float vec[4];
434         int /*  go= 1,  */tot=4;
435         
436         
437         if(G.soops==0) return;
438         
439         if(okee("Shrink oops")==0) return;
440         
441         waitcursor(1);
442         
443         /* clear */
444         oops= G.soops->oops.first;
445         while(oops) {
446                 oops->dx= oops->dy= 0.0;
447                 oops= oops->next;
448         }
449         
450         while(tot) {
451                 tot--;
452
453                 /* shrink */
454                 oops= G.soops->oops.first;
455                 while(oops) {
456                         if(oops->link.first && oops->hide==0 && (oops->flag & SELECT)) {
457                                 
458                                 ol= oops->link.first;
459                                 while(ol) {
460                                         if(ol->to && ol->to->hide==0) {
461                                                 
462                                                 give_oopslink_line(oops, ol, vec, vec+2);
463                                                 
464                                                 oops->dx= (float)(.8*oops->dx + .2*( vec[2]-vec[0]));
465                                                 oops->dy= (float)(.8*oops->dy + .2*( vec[3]-vec[1]));
466                                                 
467                                                 if(ol->to->flag & SELECT) {
468                                                         ol->to->dx= (float)(.8*ol->to->dx + .2*( vec[0]-vec[2]));
469                                                         ol->to->dy= (float)(.8*ol->to->dy + .2*( vec[1]-vec[3]));
470                                                 }
471                                         }
472                                         
473                                         ol= ol->next;
474                                 }
475                         }       
476                         oops= oops->next;
477                 }
478                         
479                 /* apply */
480                 oops= G.soops->oops.first;
481                 while(oops) {
482                         if(oops->hide==0 && (oops->flag & SELECT)) {
483                         
484                                 /* shrink */
485                                 oops->x+= oops->dx;
486                                 oops->y+= oops->dy;
487                                 
488                                 if(oops_test_overlaphide(oops)) {
489                                         oops->x-= oops->dx;
490                                         oops->y-= oops->dy;
491                                 }
492                         
493                                 oops->dx= oops->dy= 0.0;
494                         }       
495                         oops= oops->next;
496                 }
497         }
498         waitcursor(0);
499         
500         allqueue(REDRAWOOPS, 1);
501 }
502
503 #define LIMSCE  -20.0
504 #define LIMOB   14.0
505 #define LIMDATA 24.0
506
507 static int correct_oops_y(Oops *oops)
508 {
509         float y;
510         
511         y= oops->y;
512         
513         switch(oops->type) {
514         case ID_SCE:
515         case ID_LI:
516                 if(oops->y > LIMSCE-OOPSY) oops->y= (float)(LIMSCE-OOPSY);
517                 break;
518         case ID_OB:
519                 CLAMP(oops->y, LIMSCE, LIMOB);
520                 break;
521         case ID_IP:
522         case ID_MA:
523         case ID_TE:
524                 if(oops->y < LIMDATA+OOPSY) oops->y= (float)(LIMDATA+OOPSY);
525                 break;
526         default:
527                 CLAMP(oops->y, (float)(LIMOB+OOPSY), LIMDATA);
528                 break;
529         }
530         
531         if(y==oops->y) return 0;
532         else return 1;
533 }
534
535 float oopslastx=0.0, oopslasty= 0.0;
536
537 void new_oops_location(Oops *new)
538 {
539         float dirvec[4][2];
540         static int cnt=0;
541         int a, b, rc= 1, tel=1, ok=0;
542         
543         if(G.soops==0) return;
544         
545         if(G.soops->oops.first==G.soops->oops.last) {
546                 oopslastx= oopslasty= 0.0;
547         }
548
549         cnt++;
550         
551         new->x= oopslastx;
552         new->y= oopslasty;
553         
554         correct_oops_y(new);
555         
556         /* find from center free location */
557         dirvec[cnt & 3][0]= 1.2*OOPSX;
558         dirvec[cnt & 3][1]= 0;
559         cnt++;
560         dirvec[cnt & 3][0]= 0;
561         dirvec[cnt & 3][1]= (float)(-1.2*OOPSY);
562         cnt++;
563         dirvec[cnt & 3][0]= -1.2*OOPSX;
564         dirvec[cnt & 3][1]= 0;
565         cnt++;
566         dirvec[cnt & 3][0]= 0;
567         dirvec[cnt & 3][1]= (float)(1.2*OOPSY);
568         cnt++;
569
570         
571         new->x+= dirvec[ (rc-2) & 3][0];
572         new->y+= dirvec[ (rc-2) & 3][1];
573         rc+= correct_oops_y(new);
574
575         if( oops_test_overlap(new)==0 ) {
576                 ok= 1;
577         }
578
579         rc++;
580         
581         if(ok==0) {             
582                 new->x+= dirvec[ (rc-1) & 3][0];
583                 new->y+= dirvec[ (rc-1) & 3][1];
584                 rc+= correct_oops_y(new);
585                 
586                 if(oops_test_overlap(new)==0 ) {
587                         ok= 1;
588                 }
589                 rc++;
590         }
591         
592         
593         while(ok==0) {
594                 
595                 for(a=0;a<2;a++) {
596                         for(b=0;b<tel;b++) {
597
598                                 if( oops_test_overlap(new)==0 ) {
599                                         ok= 1;
600                                         break;
601                                 }
602                                 
603                                 rc &= 3;
604                                 new->x += dirvec[rc][0];
605                                 new->y += dirvec[rc][1];
606                                 rc+= correct_oops_y(new);
607                         }
608                         rc++;
609                         
610                         
611                         
612                         if(ok) break;
613                 }
614                 if(ok || tel>100) break;
615                 tel++;
616         }
617         oopslastx= new->x;
618         oopslasty= new->y;
619
620 }
621
622
623 void free_oops(Oops *oops)      /* also oops itself */
624 {
625         BLI_freelistN(&oops->link);
626         MEM_freeN(oops);
627 }
628
629 void free_oopspace(SpaceOops *so)
630 {
631         Oops *oops;
632
633         while( (oops= so->oops.first) ) {
634                 BLI_remlink(&so->oops, oops);
635                 free_oops(oops);
636         }
637         
638         outliner_free_tree(&so->tree);
639         if(so->treestore) {
640                 if(so->treestore->data) MEM_freeN(so->treestore->data);
641                 MEM_freeN(so->treestore);
642         }
643 }
644
645 void add_material_oopslinks(Material *ma, Oops *oops, short flag)
646 {
647         int a;
648         
649         if(flag & OOPS_TE) {
650                 for(a=0; a<MAX_MTEX; a++) {
651                         if(ma->mtex[a]) add_oopslink("tex", oops, ID_TE, &(ma->mtex[a]->tex), (float)(0.5*OOPSX), (float)OOPSY);
652                 }
653         }
654         if(flag & OOPS_OB) {
655                 for(a=0; a<MAX_MTEX; a++) {
656                         if(ma->mtex[a]) add_oopslink("ob", oops, ID_OB, &(ma->mtex[a]->object), 0.0, (float)(0.2*OOPSY));
657                 }
658         }
659         if(flag & OOPS_IP) {
660                 if(ma->ipo) add_oopslink("ipo", oops, ID_IP, &(ma->ipo), OOPSX, (float)(0.5*OOPSY));
661         }
662 }
663
664
665 void add_object_oopslinks(Object *ob, Oops *oops, short flag)
666 {
667         ID *id;
668         
669         if(ob->parent) add_oopslink("parent", oops, ID_OB, &ob->parent, (float)(.6*OOPSX), (float)OOPSY);
670         if(ob->track) add_oopslink("parent", oops, ID_OB, &ob->track, (float)(.4*OOPSX), (float)OOPSY);
671
672         id= ob->data;
673         if(id) {
674                 switch( GS(id->name) ) {
675                 case ID_ME:
676                         if(flag & OOPS_ME) add_oopslink("data", oops, ID_ME, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
677                         break;
678                 case ID_CU:
679                         if(flag & OOPS_CU) add_oopslink("data", oops, ID_CU, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
680                         break;
681                 case ID_MB:
682                         if(flag & OOPS_MB) add_oopslink("data", oops, ID_MB, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
683                         break;
684                 case ID_LT:
685                         if(flag & OOPS_LT) add_oopslink("data", oops, ID_LT, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
686                         break;
687                 case ID_LA:
688                         if(flag & OOPS_LA) add_oopslink("data", oops, ID_LA, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
689                         break;
690                 }
691         }
692         
693         if(flag & OOPS_MA) {
694                 short a;
695                 
696                 for(a=0; a<ob->totcol; a++) {
697                         if(ob->mat[a]) {
698                                 add_oopslink("mat", oops, ID_MA, ob->mat+a, 0, (float)(0.5*OOPSY));
699                         }
700                 }
701         }
702         
703         if(flag & OOPS_IP) add_oopslink("ipo", oops, ID_IP, &ob->ipo, OOPSX, (float)(0.5*OOPSY));
704 }
705
706 void add_mesh_oopslinks(Mesh *me, Oops *oops, short flag)
707 {
708         int a;
709         
710         if(flag & OOPS_MA) {
711                 for(a=0; a<me->totcol; a++) {
712                         if(me->mat[a]) {
713                                 add_oopslink("ma", oops, ID_MA, me->mat+a, 0.0, (float)(0.5*OOPSY));
714                         }
715                 }
716         }
717         if(flag & OOPS_IP) {
718                 if(me->key) add_oopslink("ipo", oops, ID_IP, &me->key->ipo, OOPSX, (float)(0.5*OOPSY));
719         }
720 }
721
722 void add_curve_oopslinks(Curve *cu, Oops *oops, short flag)
723 {
724         int a;
725         
726         if(flag & OOPS_MA) {
727                 for(a=0; a<cu->totcol; a++) {
728                         if(cu->mat[a]) {
729                                 add_oopslink("ma", oops, ID_MA, cu->mat+a, 0.0, (float)(0.5*OOPSY));
730                         }
731                 }
732         }
733         if(flag & OOPS_IP) {
734                 add_oopslink("speed", oops, ID_IP, &cu->ipo, OOPSX, (float)(0.5*OOPSY));
735                 if(cu->key) add_oopslink("ipo", oops, ID_IP, &cu->key->ipo, OOPSX, (float)(0.5*OOPSY));
736         }
737         
738 }
739
740 void add_mball_oopslinks(MetaBall *mb, Oops *oops, short flag)
741 {
742         int a;
743         
744         if(flag & OOPS_MA) {
745                 for(a=0; a<mb->totcol; a++) {
746                         if(mb->mat[a]) {
747                                 add_oopslink("ma", oops, ID_MA, mb->mat+a, 0.0, (float)(0.5*OOPSY));
748                         }
749                 }
750         }
751 }
752
753 void add_lamp_oopslinks(Lamp *la, Oops *oops, short flag)
754 {
755         int a;
756         
757         if(flag & OOPS_TE) {
758                 for(a=0; a<MAX_MTEX; a++) {
759                         if(la->mtex[a]) {
760                                 add_oopslink("tex", oops, ID_TE, &(la->mtex[a]->tex), 0.0, (float)(0.5*OOPSY));
761                         }
762                 }
763         }
764 }
765
766
767 Oops *add_test_oops(void *id)   /* incl links */
768 {
769         Oops *oops;
770         Object *ob;
771         Lamp *la;
772         Tex *tex;
773         
774         if(id==0) return NULL;
775         
776         /* test if it exists */
777         oops= find_oops(id);
778         
779         if(oops) {
780                 oops->hide= 0;
781         }
782         else {
783                 oops= add_oops(id);
784                 new_oops_location(oops);
785                 if(G.soops->flag & SO_NEWSELECTED) {
786                         oops->flag |= SELECT;
787                 }
788         }
789         
790         switch( GS( ((ID *)id)->name)) {
791         case ID_SCE:
792                 add_oopslink("set", oops, ID_SCE, &((Scene *)id)->set, (float)(.5*OOPSX), (float)OOPSY);
793                 break;
794         case ID_OB:
795                 ob= (Object *)id;
796                 if(ob->flag & SELECT) oops->flag |= SELECT;
797                 else oops->flag &= ~SELECT;             
798                 add_object_oopslinks(ob, oops, G.soops->visiflag);
799                 break;
800         case ID_ME:
801                 add_mesh_oopslinks((Mesh *)id, oops, G.soops->visiflag);
802                 break;
803         case ID_CU:
804                 add_curve_oopslinks((Curve *)id, oops, G.soops->visiflag);
805                 break;
806         case ID_MB:
807                 add_mball_oopslinks((MetaBall *)id, oops, G.soops->visiflag);
808                 break;
809         case ID_LA:
810                 la= (Lamp *)id;
811                 add_lamp_oopslinks(la, oops, G.soops->visiflag);
812                 if(la->ipo) if(G.soops->visiflag & OOPS_IP) add_oopslink("ipo", oops, ID_IP, &la->ipo, OOPSX, (float)(0.3*OOPSY));
813                 break;   
814         case ID_IP:
815
816                 break;
817         case ID_MA:
818                 add_material_oopslinks((Material *)id, oops, G.soops->visiflag);
819                 break;
820         case ID_TE:
821                 tex= (Tex *)id;
822                 if(tex->ima) if(G.soops->visiflag & OOPS_IM) add_oopslink("image", oops, ID_IM, &tex->ima, OOPSX, (float)(0.3*OOPSY));
823         }
824         
825         return oops;
826 }
827
828 void add_texture_oops(Material *ma)
829 {
830         int a;
831         
832         for(a=0; a<MAX_MTEX; a++) {
833                 if(ma->mtex[a]) {
834                         add_test_oops(ma->mtex[a]->tex);
835                         if(ma->mtex[a]->tex) if(G.soops->visiflag & OOPS_IM) add_test_oops(ma->mtex[a]->tex->ima);
836                 }
837         }
838 }
839
840 void build_oops()
841 {
842         Oops *oops;
843         OopsLink *ol;
844         ID *id;
845         Base *base;
846         Object *ob;
847         short a, type;
848         
849         /* always build it all! */
850
851         if(G.soops==0) return;  
852         
853         /* set hide flags */
854         oops= G.soops->oops.first;
855         while(oops) {
856                 oops->hide= 1;
857                 oops->flag &= ~OOPS_REFER;
858                 
859                 BLI_freelistN(&oops->link);     /* much safer */
860                 
861                 oops= oops->next;
862         }
863
864         /* make oops, includes testing for existance */
865
866         /* always */    
867         if(G.soops->visiflag & OOPS_LI) {
868                 Library *li= G.main->library.first;
869                 while(li) {
870                         oops= add_test_oops(li);
871                         li= li->id.next;
872                 }
873         }
874         
875         /* the rest in 2 ways: or everything (OOPS_SCE) or only the ones in this scene */
876         
877         if(G.soops->visiflag & OOPS_SCE) {
878                 Scene *sce= G.main->scene.first;
879                 
880                 while(sce) {
881                 
882                         oops= add_test_oops(sce);
883
884                         if(G.soops->visiflag & OOPS_OB) {
885                                 base= sce->base.first;
886                                 while(base) {
887                                         
888                                         add_oopslink("object", oops, ID_OB, &base->object, (float)(.5*OOPSX), (float)OOPSY);
889                                         base= base->next;
890                                 }
891                         }
892                         
893                         sce= sce->id.next;
894                 }
895                 
896                 if(G.soops->visiflag & OOPS_OB) {
897                         Object *ob= G.main->object.first;
898
899                         while(ob) {
900                                 oops= add_test_oops(ob);
901                                 ob= ob->id.next;
902                         }
903                 }
904                 if(G.soops->visiflag & OOPS_ME) {
905                         Mesh *me= G.main->mesh.first;
906                         while(me) {
907                                 oops= add_test_oops(me);
908                                 me= me->id.next;
909                         }
910                 }
911         
912                 if(G.soops->visiflag & OOPS_CU) {
913                         Curve *cu= G.main->curve.first;
914                         while(cu) {
915                                 oops= add_test_oops(cu);
916                                 cu= cu->id.next;
917                         }
918                 }
919
920                 if(G.soops->visiflag & OOPS_MB) {
921                         MetaBall *mb= G.main->mball.first;
922                         while(mb) {
923                                 oops= add_test_oops(mb);
924                                 mb= mb->id.next;
925                         }
926                 }
927         
928                 if(G.soops->visiflag & OOPS_LA) {
929                         Lamp *la= G.main->lamp.first;
930                         while(la) {
931                                 oops= add_test_oops(la);
932                                 la= la->id.next;
933                         }
934                 }
935                 
936                 if(G.soops->visiflag & OOPS_IP) {
937                         Ipo *ipo= G.main->ipo.first;
938                         while(ipo) {
939                                 oops= add_test_oops(ipo);
940                                 ipo= ipo->id.next;
941                         }
942                 }
943                 
944                 if(G.soops->visiflag & OOPS_MA) {
945                         Material *ma= G.main->mat.first;
946                         while(ma) {
947                                 oops= add_test_oops(ma);
948                                 ma= ma->id.next;
949                         }
950                 }
951                 if(G.soops->visiflag & OOPS_TE) {
952                         Tex *tex= G.main->tex.first;
953                         while(tex) {
954                                 oops= add_test_oops(tex);
955                                 tex= tex->id.next;
956                         }
957                 }
958                 if(G.soops->visiflag & OOPS_IM) {
959                         Image *ima= G.main->image.first;
960                         while(ima) {
961                                 oops= add_test_oops(ima);
962                                 ima= ima->id.next;
963                         }
964                 }
965                 
966         }
967         else {
968                 
969                 /* only blocks from this scene */
970                 
971                 base= FIRSTBASE;
972                 while(base) {
973                         
974                         /* layer? */
975                         if( (G.soops->visiflag & OOPS_LAY)==0 || (base->lay & G.scene->lay)) {
976                                 ob= base->object;
977                                 
978                                 if(G.soops->visiflag & OOPS_OB) {
979                                         oops= add_test_oops(ob);
980                                 }
981                                 if(G.soops->visiflag & OOPS_MA) {
982                                         for(a=0; a<ob->totcol; a++) {
983                                                 if(ob->mat[a]) {
984                                                         oops= add_test_oops(ob->mat[a]);
985                                                         if(G.soops->visiflag & OOPS_TE) add_texture_oops(ob->mat[a]);
986                                                         if(G.soops->visiflag & OOPS_IP) add_test_oops(ob->mat[a]->ipo);
987                                                 }
988                                         }
989                                 }
990                                 if(G.soops->visiflag & OOPS_IP) oops= add_test_oops(ob->ipo);
991                                 
992                                 id= ob->data;
993                                 if(id) {
994                                         type= GS(id->name);
995                                         
996                                         if(type==ID_ME && G.soops->visiflag & OOPS_ME) {
997                                                 Mesh *me= ob->data;
998                                                 oops= add_test_oops(ob->data);
999                                                 
1000                                                 if(G.soops->visiflag & OOPS_MA) {
1001                                                         for(a=0; a<me->totcol; a++) {
1002                                                                 if(me->mat[a]) {
1003                                                                         oops= add_test_oops(me->mat[a]);
1004                                                                         if(G.soops->visiflag & OOPS_TE) add_texture_oops(me->mat[a]);
1005                                                                         if(G.soops->visiflag & OOPS_IP) add_test_oops(me->mat[a]->ipo);
1006                                                                 }
1007                                                         }
1008                                                 }
1009                                                 if(G.soops->visiflag & OOPS_IP) {
1010                                                         if(me->key) oops= add_test_oops(me->key->ipo);
1011                                                 }
1012                                         }
1013                                         else if(type==ID_CU && G.soops->visiflag & OOPS_CU) {
1014                                                 Curve *cu= ob->data;
1015                                                 oops= add_test_oops(ob->data);
1016                                                 
1017                                                 if(G.soops->visiflag & OOPS_MA) {
1018                                                         for(a=0; a<cu->totcol; a++) {
1019                                                                 if(cu->mat[a]) {
1020                                                                         oops= add_test_oops(cu->mat[a]);
1021                                                                         if(G.soops->visiflag & OOPS_TE) add_texture_oops(cu->mat[a]);
1022                                                                         if(G.soops->visiflag & OOPS_IP) add_test_oops(cu->mat[a]->ipo);
1023                                                                 }
1024                                                         }
1025                                                 }
1026                                                 if(G.soops->visiflag & OOPS_IP) {
1027                                                         if(cu->ipo) oops= add_test_oops(cu->ipo);
1028                                                         if(cu->key) oops= add_test_oops(cu->key->ipo);
1029                                                 }
1030                                         }
1031                                         else if(type==ID_MB && G.soops->visiflag & OOPS_MB) {
1032                                                 oops= add_test_oops(ob->data);
1033                                                 
1034                                                 if(G.soops->visiflag & OOPS_MA) {
1035                                                         MetaBall *mb= ob->data;
1036                                                         for(a=0; a<mb->totcol; a++) {
1037                                                                 if(mb->mat[a]) {
1038                                                                         oops= add_test_oops(mb->mat[a]);
1039                                                                         if(G.soops->visiflag & OOPS_TE) add_texture_oops(mb->mat[a]);
1040                                                                         if(G.soops->visiflag & OOPS_IP) add_test_oops(mb->mat[a]->ipo);
1041                                                                 }
1042                                                         }
1043                                                 }
1044                                         }
1045                                         else if(type==ID_LA && G.soops->visiflag & OOPS_LA) {
1046                                                 Lamp *la= ob->data;
1047                                                 oops= add_test_oops(ob->data);
1048                                                 if(G.soops->visiflag & OOPS_IP) add_test_oops(la->ipo);
1049                                                 if(G.soops->visiflag & OOPS_TE) {
1050                                                         for(a=0; a<MAX_MTEX; a++) {
1051                                                                 if(la->mtex[a]) add_test_oops(la->mtex[a]->tex);
1052                                                         }
1053                                                 }
1054                                         }
1055                                 }
1056                         }
1057                         base= base->next;
1058                 }
1059         }
1060         
1061         
1062
1063
1064         /* test links */
1065         oops= G.soops->oops.first;
1066         while(oops) {
1067                 if(oops->hide==0) {     
1068                         ol= oops->link.first;
1069                         while(ol) {
1070                                 test_oopslink(ol);
1071                                 ol= ol->next;
1072                         }
1073                 }
1074                 oops= oops->next;
1075         }
1076         
1077         G.soops->flag &= ~SO_NEWSELECTED;
1078 }