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