Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / screen.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/screen.c
29  *  \ingroup bke
30  */
31
32 #ifdef WIN32
33 #  include "BLI_winstuff.h"
34 #endif
35
36 #include <string.h>
37 #include <stdio.h>
38 #include <math.h>
39
40 #include "MEM_guardedalloc.h"
41
42 #include "DNA_scene_types.h"
43 #include "DNA_screen_types.h"
44 #include "DNA_space_types.h"
45 #include "DNA_view3d_types.h"
46 #include "DNA_workspace_types.h"
47
48 #include "BLI_listbase.h"
49 #include "BLI_utildefines.h"
50 #include "BLI_rect.h"
51
52 #include "BKE_icons.h"
53 #include "BKE_idprop.h"
54 #include "BKE_screen.h"
55 #include "BKE_workspace.h"
56
57 /* ************ Spacetype/regiontype handling ************** */
58
59 /* keep global; this has to be accessible outside of windowmanager */
60 static ListBase spacetypes = {NULL, NULL};
61
62 /* not SpaceType itself */
63 static void spacetype_free(SpaceType *st)
64 {
65         ARegionType *art;
66         PanelType *pt;
67         HeaderType *ht;
68         
69         for (art = st->regiontypes.first; art; art = art->next) {
70                 BLI_freelistN(&art->drawcalls);
71
72                 for (pt = art->paneltypes.first; pt; pt = pt->next) {
73                         if (pt->ext.free) {
74                                 pt->ext.free(pt->ext.data);
75                         }
76
77                         BLI_freelistN(&pt->children);
78                 }
79
80                 for (ht = art->headertypes.first; ht; ht = ht->next) {
81                         if (ht->ext.free) {
82                                 ht->ext.free(ht->ext.data);
83                         }
84                 }
85
86                 BLI_freelistN(&art->paneltypes);
87                 BLI_freelistN(&art->headertypes);
88         }
89         
90         BLI_freelistN(&st->regiontypes);
91         BLI_freelistN(&st->toolshelf);
92
93 }
94
95 void BKE_spacetypes_free(void)
96 {
97         SpaceType *st;
98         
99         for (st = spacetypes.first; st; st = st->next) {
100                 spacetype_free(st);
101         }
102         
103         BLI_freelistN(&spacetypes);
104 }
105
106 SpaceType *BKE_spacetype_from_id(int spaceid)
107 {
108         SpaceType *st;
109         
110         for (st = spacetypes.first; st; st = st->next) {
111                 if (st->spaceid == spaceid)
112                         return st;
113         }
114         return NULL;
115 }
116
117 ARegionType *BKE_regiontype_from_id_or_first(SpaceType *st, int regionid)
118 {
119         ARegionType *art;
120         
121         for (art = st->regiontypes.first; art; art = art->next)
122                 if (art->regionid == regionid)
123                         return art;
124         
125         printf("Error, region type %d missing in - name:\"%s\", id:%d\n", regionid, st->name, st->spaceid);
126         return st->regiontypes.first;
127 }
128
129 ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
130 {
131         ARegionType *art;
132         
133         for (art = st->regiontypes.first; art; art = art->next) {
134                 if (art->regionid == regionid) {
135                         return art;
136                 }
137         }
138         return NULL;
139 }
140
141
142 const ListBase *BKE_spacetypes_list(void)
143 {
144         return &spacetypes;
145 }
146
147 void BKE_spacetype_register(SpaceType *st)
148 {
149         SpaceType *stype;
150         
151         /* sanity check */
152         stype = BKE_spacetype_from_id(st->spaceid);
153         if (stype) {
154                 printf("error: redefinition of spacetype %s\n", stype->name);
155                 spacetype_free(stype);
156                 MEM_freeN(stype);
157         }
158         
159         BLI_addtail(&spacetypes, st);
160 }
161
162 bool BKE_spacetype_exists(int spaceid)
163 {
164         return BKE_spacetype_from_id(spaceid) != NULL;
165 }
166
167 /* ***************** Space handling ********************** */
168
169 void BKE_spacedata_freelist(ListBase *lb)
170 {
171         SpaceLink *sl;
172         ARegion *ar;
173         
174         for (sl = lb->first; sl; sl = sl->next) {
175                 SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
176                 
177                 /* free regions for pushed spaces */
178                 for (ar = sl->regionbase.first; ar; ar = ar->next)
179                         BKE_area_region_free(st, ar);
180
181                 BLI_freelistN(&sl->regionbase);
182                 
183                 if (st && st->free) 
184                         st->free(sl);
185         }
186         
187         BLI_freelistN(lb);
188 }
189
190 static void panel_list_copy(ListBase *newlb, const ListBase *lb)
191 {
192         BLI_listbase_clear(newlb);
193         BLI_duplicatelist(newlb, lb);
194
195         /* copy panel pointers */
196         Panel *newpa = newlb->first;
197         Panel *pa = lb->first;
198         for (; newpa; newpa = newpa->next, pa = pa->next) {
199                 newpa->activedata = NULL;
200
201                 Panel *newpatab = newlb->first;
202                 Panel *patab = lb->first;
203                 while (newpatab) {
204                         if (newpa->paneltab == patab) {
205                                 newpa->paneltab = newpatab;
206                                 break;
207                         }
208                         newpatab = newpatab->next;
209                         patab = patab->next;
210                 }
211
212                 panel_list_copy(&newpa->children, &pa->children);
213         }
214 }
215
216 ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
217 {
218         ARegion *newar = MEM_dupallocN(ar);
219         
220         newar->prev = newar->next = NULL;
221         BLI_listbase_clear(&newar->handlers);
222         BLI_listbase_clear(&newar->uiblocks);
223         BLI_listbase_clear(&newar->panels_category);
224         BLI_listbase_clear(&newar->panels_category_active);
225         BLI_listbase_clear(&newar->ui_lists);
226         newar->visible = 0;
227         newar->manipulator_map = NULL;
228         newar->regiontimer = NULL;
229         newar->headerstr = NULL;
230         newar->draw_buffer = NULL;
231         
232         /* use optional regiondata callback */
233         if (ar->regiondata) {
234                 ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
235
236                 if (art && art->duplicate)
237                         newar->regiondata = art->duplicate(ar->regiondata);
238                 else
239                         newar->regiondata = MEM_dupallocN(ar->regiondata);
240         }
241
242         if (ar->v2d.tab_offset)
243                 newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset);
244         
245         panel_list_copy(&newar->panels, &ar->panels);
246
247         BLI_listbase_clear(&newar->ui_previews);
248         BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews);
249         
250         return newar;
251 }
252
253
254 /* from lb2 to lb1, lb1 is supposed to be freed */
255 static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
256 {
257         ARegion *ar;
258         
259         /* to be sure */
260         BLI_listbase_clear(lb1);
261         
262         for (ar = lb2->first; ar; ar = ar->next) {
263                 ARegion *arnew = BKE_area_region_copy(st, ar);
264                 BLI_addtail(lb1, arnew);
265         }
266 }
267
268
269 /* lb1 should be empty */
270 void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
271 {
272         SpaceLink *sl;
273         
274         BLI_listbase_clear(lb1);  /* to be sure */
275         
276         for (sl = lb2->first; sl; sl = sl->next) {
277                 SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
278                 
279                 if (st && st->duplicate) {
280                         SpaceLink *slnew = st->duplicate(sl);
281                         
282                         BLI_addtail(lb1, slnew);
283                         
284                         region_copylist(st, &slnew->regionbase, &sl->regionbase);
285                 }
286         }
287 }
288
289 /* facility to set locks for drawing to survive (render) threads accessing drawing data */
290 /* lock can become bitflag too */
291 /* should be replaced in future by better local data handling for threads */
292 void BKE_spacedata_draw_locks(int set)
293 {
294         SpaceType *st;
295         
296         for (st = spacetypes.first; st; st = st->next) {
297                 ARegionType *art;
298         
299                 for (art = st->regiontypes.first; art; art = art->next) {
300                         if (set) 
301                                 art->do_lock = art->lock;
302                         else 
303                                 art->do_lock = false;
304                 }
305         }
306 }
307
308 static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL;
309
310 void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *))
311 {
312         spacedata_id_remap_cb = func;
313 }
314
315 /* UNUSED!!! */
316 void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id)
317 {
318         if (spacedata_id_remap_cb) {
319                 spacedata_id_remap_cb(sa, sl, id, NULL);
320         }
321 }
322
323 /**
324  * Avoid bad-level calls to #WM_manipulatormap_tag_refresh.
325  */
326 static void (*region_refresh_tag_manipulatormap_callback)(struct wmManipulatorMap *) = NULL;
327
328 void BKE_region_callback_refresh_tag_manipulatormap_set(void (*callback)(struct wmManipulatorMap *))
329 {
330         region_refresh_tag_manipulatormap_callback = callback;
331 }
332
333 void BKE_screen_manipulator_tag_refresh(struct bScreen *sc)
334 {
335         if (region_refresh_tag_manipulatormap_callback == NULL) {
336                 return;
337         }
338
339         ScrArea *sa;
340         ARegion *ar;
341         for (sa = sc->areabase.first; sa; sa = sa->next) {
342                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
343                         if (ar->manipulator_map != NULL) {
344                                 region_refresh_tag_manipulatormap_callback(ar->manipulator_map);
345                         }
346                 }
347         }
348 }
349
350 /**
351  * Avoid bad-level calls to #WM_manipulatormap_delete.
352  */
353 static void (*region_free_manipulatormap_callback)(struct wmManipulatorMap *) = NULL;
354
355 void BKE_region_callback_free_manipulatormap_set(void (*callback)(struct wmManipulatorMap *))
356 {
357         region_free_manipulatormap_callback = callback;
358 }
359
360 static void panel_list_free(ListBase *lb)
361 {
362         Panel *pa, *pa_next;
363         for (pa = lb->first; pa; pa = pa_next) {
364                 pa_next = pa->next;
365                 if (pa->activedata) {
366                         MEM_freeN(pa->activedata);
367                 }
368                 panel_list_free(&pa->children);
369                 MEM_freeN(pa);
370         }
371 }
372
373 /* not region itself */
374 void BKE_area_region_free(SpaceType *st, ARegion *ar)
375 {
376         uiList *uilst;
377
378         if (st) {
379                 ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype);
380                 
381                 if (art && art->free)
382                         art->free(ar);
383                 
384                 if (ar->regiondata)
385                         printf("regiondata free error\n");
386         }
387         else if (ar->type && ar->type->free)
388                 ar->type->free(ar);
389         
390         if (ar->v2d.tab_offset) {
391                 MEM_freeN(ar->v2d.tab_offset);
392                 ar->v2d.tab_offset = NULL;
393         }
394
395         panel_list_free(&ar->panels);
396
397         for (uilst = ar->ui_lists.first; uilst; uilst = uilst->next) {
398                 if (uilst->dyn_data) {
399                         uiListDyn *dyn_data = uilst->dyn_data;
400                         if (dyn_data->items_filter_flags) {
401                                 MEM_freeN(dyn_data->items_filter_flags);
402                         }
403                         if (dyn_data->items_filter_neworder) {
404                                 MEM_freeN(dyn_data->items_filter_neworder);
405                         }
406                         MEM_freeN(dyn_data);
407                 }
408                 if (uilst->properties) {
409                         IDP_FreeProperty(uilst->properties);
410                         MEM_freeN(uilst->properties);
411                 }
412         }
413
414         if (ar->manipulator_map != NULL) {
415                 region_free_manipulatormap_callback(ar->manipulator_map);
416         }
417
418         BLI_freelistN(&ar->ui_lists);
419         BLI_freelistN(&ar->ui_previews);
420         BLI_freelistN(&ar->panels_category);
421         BLI_freelistN(&ar->panels_category_active);
422 }
423
424 /* not area itself */
425 void BKE_screen_area_free(ScrArea *sa)
426 {
427         SpaceType *st = BKE_spacetype_from_id(sa->spacetype);
428         ARegion *ar;
429         
430         for (ar = sa->regionbase.first; ar; ar = ar->next)
431                 BKE_area_region_free(st, ar);
432
433         MEM_SAFE_FREE(sa->global);
434         BLI_freelistN(&sa->regionbase);
435         
436         BKE_spacedata_freelist(&sa->spacedata);
437         
438         BLI_freelistN(&sa->actionzones);
439 }
440
441 void BKE_screen_area_map_free(ScrAreaMap *area_map)
442 {
443         for (ScrArea *area = area_map->areabase.first, *area_next; area; area = area_next) {
444                 area_next = area->next;
445                 BKE_screen_area_free(area);
446         }
447
448         BLI_freelistN(&area_map->vertbase);
449         BLI_freelistN(&area_map->edgebase);
450         BLI_freelistN(&area_map->areabase);
451 }
452
453 /** Free (or release) any data used by this screen (does not free the screen itself). */
454 void BKE_screen_free(bScreen *sc)
455 {
456         ARegion *ar;
457
458         /* No animdata here. */
459         
460         for (ar = sc->regionbase.first; ar; ar = ar->next)
461                 BKE_area_region_free(NULL, ar);
462
463         BLI_freelistN(&sc->regionbase);
464
465         BKE_screen_area_map_free(AREAMAP_FROM_SCREEN(sc));
466
467         BKE_previewimg_free(&sc->preview);
468
469         /* Region and timer are freed by the window manager. */
470         MEM_SAFE_FREE(sc->tool_tip);
471 }
472
473 /* for depsgraph */
474 unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene)
475 {
476         ScrArea *sa;
477         unsigned int layer = 0;
478
479         if (screen) {
480                 /* get all used view3d layers */
481                 for (sa = screen->areabase.first; sa; sa = sa->next)
482                         if (sa->spacetype == SPACE_VIEW3D)
483                                 layer |= ((View3D *)sa->spacedata.first)->lay;
484         }
485
486         if (!layer)
487                 return scene->lay;
488
489         return layer;
490 }
491
492
493 /* ***************** Screen edges & verts ***************** */
494
495 ScrEdge *BKE_screen_find_edge(bScreen *sc, ScrVert *v1, ScrVert *v2)
496 {
497         ScrEdge *se;
498
499         BKE_screen_sort_scrvert(&v1, &v2);
500         for (se = sc->edgebase.first; se; se = se->next) {
501                 if (se->v1 == v1 && se->v2 == v2) {
502                         return se;
503                 }
504         }
505
506         return NULL;
507 }
508
509 void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
510 {
511         ScrVert *tmp;
512
513         if (*v1 > *v2) {
514                 tmp = *v1;
515                 *v1 = *v2;
516                 *v2 = tmp;
517         }
518 }
519
520 void BKE_screen_remove_double_scrverts(bScreen *sc)
521 {
522         ScrVert *v1, *verg;
523         ScrEdge *se;
524         ScrArea *sa;
525
526         verg = sc->vertbase.first;
527         while (verg) {
528                 if (verg->newv == NULL) { /* !!! */
529                         v1 = verg->next;
530                         while (v1) {
531                                 if (v1->newv == NULL) {   /* !?! */
532                                         if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
533                                                 /* printf("doublevert\n"); */
534                                                 v1->newv = verg;
535                                         }
536                                 }
537                                 v1 = v1->next;
538                         }
539                 }
540                 verg = verg->next;
541         }
542
543         /* replace pointers in edges and faces */
544         se = sc->edgebase.first;
545         while (se) {
546                 if (se->v1->newv) se->v1 = se->v1->newv;
547                 if (se->v2->newv) se->v2 = se->v2->newv;
548                 /* edges changed: so.... */
549                 BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
550                 se = se->next;
551         }
552         sa = sc->areabase.first;
553         while (sa) {
554                 if (sa->v1->newv) sa->v1 = sa->v1->newv;
555                 if (sa->v2->newv) sa->v2 = sa->v2->newv;
556                 if (sa->v3->newv) sa->v3 = sa->v3->newv;
557                 if (sa->v4->newv) sa->v4 = sa->v4->newv;
558                 sa = sa->next;
559         }
560
561         /* remove */
562         verg = sc->vertbase.first;
563         while (verg) {
564                 v1 = verg->next;
565                 if (verg->newv) {
566                         BLI_remlink(&sc->vertbase, verg);
567                         MEM_freeN(verg);
568                 }
569                 verg = v1;
570         }
571
572 }
573
574 void BKE_screen_remove_double_scredges(bScreen *sc)
575 {
576         ScrEdge *verg, *se, *sn;
577
578         /* compare */
579         verg = sc->edgebase.first;
580         while (verg) {
581                 se = verg->next;
582                 while (se) {
583                         sn = se->next;
584                         if (verg->v1 == se->v1 && verg->v2 == se->v2) {
585                                 BLI_remlink(&sc->edgebase, se);
586                                 MEM_freeN(se);
587                         }
588                         se = sn;
589                 }
590                 verg = verg->next;
591         }
592 }
593
594 void BKE_screen_remove_unused_scredges(bScreen *sc)
595 {
596         ScrEdge *se, *sen;
597         ScrArea *sa;
598         int a = 0;
599
600         /* sets flags when edge is used in area */
601         sa = sc->areabase.first;
602         while (sa) {
603                 se = BKE_screen_find_edge(sc, sa->v1, sa->v2);
604                 if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
605                 else se->flag = 1;
606                 se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
607                 if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
608                 else se->flag = 1;
609                 se = BKE_screen_find_edge(sc, sa->v3, sa->v4);
610                 if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
611                 else se->flag = 1;
612                 se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
613                 if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
614                 else se->flag = 1;
615                 sa = sa->next;
616                 a++;
617         }
618         se = sc->edgebase.first;
619         while (se) {
620                 sen = se->next;
621                 if (se->flag == 0) {
622                         BLI_remlink(&sc->edgebase, se);
623                         MEM_freeN(se);
624                 }
625                 else {
626                         se->flag = 0;
627                 }
628                 se = sen;
629         }
630 }
631
632 void BKE_screen_remove_unused_scrverts(bScreen *sc)
633 {
634         ScrVert *sv, *svn;
635         ScrEdge *se;
636
637         /* we assume edges are ok */
638
639         se = sc->edgebase.first;
640         while (se) {
641                 se->v1->flag = 1;
642                 se->v2->flag = 1;
643                 se = se->next;
644         }
645
646         sv = sc->vertbase.first;
647         while (sv) {
648                 svn = sv->next;
649                 if (sv->flag == 0) {
650                         BLI_remlink(&sc->vertbase, sv);
651                         MEM_freeN(sv);
652                 }
653                 else {
654                         sv->flag = 0;
655                 }
656                 sv = svn;
657         }
658 }
659
660 /* ***************** Utilities ********************** */
661
662 /* Find a region of the specified type from the given area */
663 ARegion *BKE_area_find_region_type(ScrArea *sa, int type)
664 {
665         if (sa) {
666                 ARegion *ar;
667                 
668                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
669                         if (ar->regiontype == type)
670                                 return ar;
671                 }
672         }
673         return NULL;
674 }
675
676 ARegion *BKE_area_find_region_active_win(ScrArea *sa)
677 {
678         if (sa) {
679                 ARegion *ar = BLI_findlink(&sa->regionbase, sa->region_active_win);
680                 if (ar && (ar->regiontype == RGN_TYPE_WINDOW)) {
681                         return ar;
682                 }
683
684                 /* fallback to any */
685                 return BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
686         }
687         return NULL;
688 }
689
690 ARegion *BKE_area_find_region_xy(ScrArea *sa, const int regiontype, int x, int y)
691 {
692         ARegion *ar_found = NULL;
693         if (sa) {
694                 ARegion *ar;
695                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
696                         if ((regiontype == RGN_TYPE_ANY) || (ar->regiontype == regiontype)) {
697                                 if (BLI_rcti_isect_pt(&ar->winrct, x, y)) {
698                                         ar_found = ar;
699                                         break;
700                                 }
701                         }
702                 }
703         }
704         return ar_found;
705 }
706
707 /**
708  * \note, ideally we can get the area from the context,
709  * there are a few places however where this isn't practical.
710  */
711 ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl)
712 {
713         ScrArea *sa;
714
715         for (sa = sc->areabase.first; sa; sa = sa->next) {
716                 if (BLI_findindex(&sa->spacedata, sl) != -1) {
717                         break;
718                 }
719         }
720
721         return sa;
722 }
723
724 /**
725  * \note Using this function is generally a last resort, you really want to be
726  * using the context when you can - campbell
727  */
728 ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short min)
729 {
730         ScrArea *sa, *big = NULL;
731         int size, maxsize = 0;
732
733         for (sa = sc->areabase.first; sa; sa = sa->next) {
734                 if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
735                         if (min <= sa->winx && min <= sa->winy) {
736                                 size = sa->winx * sa->winy;
737                                 if (size > maxsize) {
738                                         maxsize = size;
739                                         big = sa;
740                                 }
741                         }
742                 }
743         }
744
745         return big;
746 }
747
748 ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
749 {
750         ScrArea *sa, *sa_found = NULL;
751
752         for (sa = sc->areabase.first; sa; sa = sa->next) {
753                 if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
754                         if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
755                                 sa_found = sa;
756                         }
757                         break;
758                 }
759         }
760         return sa_found;
761 }
762
763
764 /**
765  * Utility function to get the active layer to use when adding new objects.
766  */
767 unsigned int BKE_screen_view3d_layer_active_ex(const View3D *v3d, const Scene *scene, bool use_localvd)
768 {
769         unsigned int lay;
770         if ((v3d == NULL) || (v3d->scenelock && !v3d->localvd)) {
771                 lay = scene->layact;
772         }
773         else {
774                 lay = v3d->layact;
775         }
776
777         if (use_localvd) {
778                 if (v3d && v3d->localvd) {
779                         lay |= v3d->lay;
780                 }
781         }
782
783         return lay;
784 }
785 unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const struct Scene *scene)
786 {
787         return BKE_screen_view3d_layer_active_ex(v3d, scene, true);
788 }
789
790 /**
791  * Accumulate all visible layers on this screen.
792  */
793 unsigned int BKE_screen_view3d_layer_all(const bScreen *sc)
794 {
795         const ScrArea *sa;
796         unsigned int lay = 0;
797         for (sa = sc->areabase.first; sa; sa = sa->next) {
798                 if (sa->spacetype == SPACE_VIEW3D) {
799                         View3D *v3d = sa->spacedata.first;
800                         lay |= v3d->lay;
801                 }
802         }
803
804         return lay;
805 }
806
807 void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
808 {
809         int bit;
810
811         if (v3d->scenelock && v3d->localvd == NULL) {
812                 v3d->lay = scene->lay;
813                 v3d->camera = scene->camera;
814
815                 if (v3d->camera == NULL) {
816                         ARegion *ar;
817
818                         for (ar = v3d->regionbase.first; ar; ar = ar->next) {
819                                 if (ar->regiontype == RGN_TYPE_WINDOW) {
820                                         RegionView3D *rv3d = ar->regiondata;
821                                         if (rv3d->persp == RV3D_CAMOB)
822                                                 rv3d->persp = RV3D_PERSP;
823                                 }
824                         }
825                 }
826
827                 if ((v3d->lay & v3d->layact) == 0) {
828                         for (bit = 0; bit < 32; bit++) {
829                                 if (v3d->lay & (1u << bit)) {
830                                         v3d->layact = (1u << bit);
831                                         break;
832                                 }
833                         }
834                 }
835         }
836 }
837
838 void BKE_screen_view3d_scene_sync(bScreen *sc, Scene *scene)
839 {
840         /* are there cameras in the views that are not in the scene? */
841         ScrArea *sa;
842         for (sa = sc->areabase.first; sa; sa = sa->next) {
843                 SpaceLink *sl;
844                 for (sl = sa->spacedata.first; sl; sl = sl->next) {
845                         if (sl->spacetype == SPACE_VIEW3D) {
846                                 View3D *v3d = (View3D *) sl;
847                                 BKE_screen_view3d_sync(v3d, scene);
848                         }
849                 }
850         }
851 }
852
853 /* magic zoom calculation, no idea what
854  * it signifies, if you find out, tell me! -zr
855  */
856
857 /* simple, its magic dude!
858  * well, to be honest, this gives a natural feeling zooming
859  * with multiple keypad presses (ton)
860  */
861 float BKE_screen_view3d_zoom_to_fac(float camzoom)
862 {
863         return powf(((float)M_SQRT2 + camzoom / 50.0f), 2.0f) / 4.0f;
864 }
865
866 float BKE_screen_view3d_zoom_from_fac(float zoomfac)
867 {
868         return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
869 }
870
871 bool BKE_screen_is_fullscreen_area(const bScreen *screen)
872 {
873         return ELEM(screen->state, SCREENMAXIMIZED, SCREENFULL);
874 }
875
876 bool BKE_screen_is_used(const bScreen *screen)
877 {
878         return (screen->winid != 0);
879 }