f69495483ea552af7ffffc7b1d87eef00aa54bff
[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
47 #include "BLI_blenlib.h"
48
49 #include "BKE_screen.h"
50
51 /* ************ Spacetype/regiontype handling ************** */
52
53 /* keep global; this has to be accessible outside of windowmanager */
54 static ListBase spacetypes= {NULL, NULL};
55
56 /* not SpaceType itself */
57 static void spacetype_free(SpaceType *st)
58 {
59         ARegionType *art;
60         PanelType *pt;
61         HeaderType *ht;
62         
63         for (art= st->regiontypes.first; art; art= art->next) {
64                 BLI_freelistN(&art->drawcalls);
65
66                 for (pt= art->paneltypes.first; pt; pt= pt->next)
67                         if (pt->ext.free)
68                                 pt->ext.free(pt->ext.data);
69
70                 for (ht= art->headertypes.first; ht; ht= ht->next)
71                         if (ht->ext.free)
72                                 ht->ext.free(ht->ext.data);
73
74                 BLI_freelistN(&art->paneltypes);
75                 BLI_freelistN(&art->headertypes);
76         }
77         
78         BLI_freelistN(&st->regiontypes);
79         BLI_freelistN(&st->toolshelf);
80
81 }
82
83 void BKE_spacetypes_free(void)
84 {
85         SpaceType *st;
86         
87         for (st= spacetypes.first; st; st= st->next) {
88                 spacetype_free(st);
89         }
90         
91         BLI_freelistN(&spacetypes);
92 }
93
94 SpaceType *BKE_spacetype_from_id(int spaceid)
95 {
96         SpaceType *st;
97         
98         for (st= spacetypes.first; st; st= st->next) {
99                 if (st->spaceid==spaceid)
100                         return st;
101         }
102         return NULL;
103 }
104
105 ARegionType *BKE_regiontype_from_id(SpaceType *st, int regionid)
106 {
107         ARegionType *art;
108         
109         for (art= st->regiontypes.first; art; art= art->next)
110                 if (art->regionid==regionid)
111                         return art;
112         
113         printf("Error, region type missing in - name:\"%s\", id:%d\n", st->name, st->spaceid);
114         return st->regiontypes.first;
115 }
116
117
118 const ListBase *BKE_spacetypes_list(void)
119 {
120         return &spacetypes;
121 }
122
123 void BKE_spacetype_register(SpaceType *st)
124 {
125         SpaceType *stype;
126         
127         /* sanity check */
128         stype= BKE_spacetype_from_id(st->spaceid);
129         if (stype) {
130                 printf("error: redefinition of spacetype %s\n", stype->name);
131                 spacetype_free(stype);
132                 MEM_freeN(stype);
133         }
134         
135         BLI_addtail(&spacetypes, st);
136 }
137
138 /* ***************** Space handling ********************** */
139
140 void BKE_spacedata_freelist(ListBase *lb)
141 {
142         SpaceLink *sl;
143         ARegion *ar;
144         
145         for (sl= lb->first; sl; sl= sl->next) {
146                 SpaceType *st= BKE_spacetype_from_id(sl->spacetype);
147                 
148                 /* free regions for pushed spaces */
149                 for (ar=sl->regionbase.first; ar; ar=ar->next)
150                         BKE_area_region_free(st, ar);
151
152                 BLI_freelistN(&sl->regionbase);
153                 
154                 if (st && st->free) 
155                         st->free(sl);
156         }
157         
158         BLI_freelistN(lb);
159 }
160
161 ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar)
162 {
163         ARegion *newar= MEM_dupallocN(ar);
164         Panel *pa, *newpa, *patab;
165         
166         newar->prev= newar->next= NULL;
167         newar->handlers.first= newar->handlers.last= NULL;
168         newar->uiblocks.first= newar->uiblocks.last= NULL;
169         newar->swinid= 0;
170         
171         /* use optional regiondata callback */
172         if (ar->regiondata) {
173                 ARegionType *art= BKE_regiontype_from_id(st, ar->regiontype);
174
175                 if (art && art->duplicate)
176                         newar->regiondata= art->duplicate(ar->regiondata);
177                 else
178                         newar->regiondata= MEM_dupallocN(ar->regiondata);
179         }
180
181         if (ar->v2d.tab_offset)
182                 newar->v2d.tab_offset= MEM_dupallocN(ar->v2d.tab_offset);
183         
184         newar->panels.first= newar->panels.last= NULL;
185         BLI_duplicatelist(&newar->panels, &ar->panels);
186         
187         /* copy panel pointers */
188         for (newpa= newar->panels.first; newpa; newpa= newpa->next) {
189                 patab= newar->panels.first;
190                 pa= ar->panels.first;
191                 while (patab) {
192                         if (newpa->paneltab == pa) {
193                                 newpa->paneltab = patab;
194                                 break;
195                         }
196                         patab= patab->next;
197                         pa= pa->next;
198                 }
199         }
200         
201         return newar;
202 }
203
204
205 /* from lb2 to lb1, lb1 is supposed to be freed */
206 static void region_copylist(SpaceType *st, ListBase *lb1, ListBase *lb2)
207 {
208         ARegion *ar;
209         
210         /* to be sure */
211         lb1->first= lb1->last= NULL;
212         
213         for (ar= lb2->first; ar; ar= ar->next) {
214                 ARegion *arnew= BKE_area_region_copy(st, ar);
215                 BLI_addtail(lb1, arnew);
216         }
217 }
218
219
220 /* lb1 should be empty */
221 void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2)
222 {
223         SpaceLink *sl;
224         
225         lb1->first= lb1->last= NULL;    /* to be sure */
226         
227         for (sl= lb2->first; sl; sl= sl->next) {
228                 SpaceType *st= BKE_spacetype_from_id(sl->spacetype);
229                 
230                 if (st && st->duplicate) {
231                         SpaceLink *slnew= st->duplicate(sl);
232                         
233                         BLI_addtail(lb1, slnew);
234                         
235                         region_copylist(st, &slnew->regionbase, &sl->regionbase);
236                 }
237         }
238 }
239
240 /* facility to set locks for drawing to survive (render) threads accessing drawing data */
241 /* lock can become bitflag too */
242 /* should be replaced in future by better local data handling for threads */
243 void BKE_spacedata_draw_locks(int set)
244 {
245         SpaceType *st;
246         
247         for (st= spacetypes.first; st; st= st->next) {
248                 ARegionType *art;
249         
250                 for (art= st->regiontypes.first; art; art= art->next) {
251                         if (set) 
252                                 art->do_lock= art->lock;
253                         else 
254                                 art->do_lock= 0;
255                 }
256         }
257 }
258
259
260 /* not region itself */
261 void BKE_area_region_free(SpaceType *st, ARegion *ar)
262 {
263         if (st) {
264                 ARegionType *art= BKE_regiontype_from_id(st, ar->regiontype);
265                 
266                 if (art && art->free)
267                         art->free(ar);
268                 
269                 if (ar->regiondata)
270                         printf("regiondata free error\n");
271         }
272         else if (ar->type && ar->type->free)
273                 ar->type->free(ar);
274         
275         if (ar->v2d.tab_offset) {
276                 MEM_freeN(ar->v2d.tab_offset);
277                 ar->v2d.tab_offset= NULL;
278         }
279
280         BLI_freelistN(&ar->panels);
281 }
282
283 /* not area itself */
284 void BKE_screen_area_free(ScrArea *sa)
285 {
286         SpaceType *st= BKE_spacetype_from_id(sa->spacetype);
287         ARegion *ar;
288         
289         for (ar=sa->regionbase.first; ar; ar=ar->next)
290                 BKE_area_region_free(st, ar);
291
292         BLI_freelistN(&sa->regionbase);
293         
294         BKE_spacedata_freelist(&sa->spacedata);
295         
296         BLI_freelistN(&sa->actionzones);
297 }
298
299 /* don't free screen itself */
300 void free_screen(bScreen *sc)
301 {
302         ScrArea *sa, *san;
303         ARegion *ar;
304         
305         for (ar=sc->regionbase.first; ar; ar=ar->next)
306                 BKE_area_region_free(NULL, ar);
307
308         BLI_freelistN(&sc->regionbase);
309         
310         for (sa= sc->areabase.first; sa; sa= san) {
311                 san= sa->next;
312                 BKE_screen_area_free(sa);
313         }
314         
315         BLI_freelistN(&sc->vertbase);
316         BLI_freelistN(&sc->edgebase);
317         BLI_freelistN(&sc->areabase);
318 }
319
320 /* for depsgraph */
321 unsigned int BKE_screen_visible_layers(bScreen *screen, Scene *scene)
322 {
323         ScrArea *sa;
324         unsigned int layer= 0;
325
326         if (screen) {
327                 /* get all used view3d layers */
328                 for (sa= screen->areabase.first; sa; sa= sa->next)
329                         if (sa->spacetype==SPACE_VIEW3D)
330                                 layer |= ((View3D *)sa->spacedata.first)->lay;
331         }
332
333         if (!layer)
334                 return scene->lay;
335
336         return layer;
337 }
338
339 /* ***************** Utilities ********************** */
340
341 /* Find a region of the specified type from the given area */
342 ARegion *BKE_area_find_region_type(ScrArea *sa, int type)
343 {
344         if (sa) {
345                 ARegion *ar;
346                 
347                 for (ar=sa->regionbase.first; ar; ar= ar->next) {
348                         if (ar->regiontype == type)
349                                 return ar;
350                 }
351         }
352         return NULL;
353 }
354
355 /* note, using this function is generally a last resort, you really want to be
356  * using the context when you can - campbell
357  * -1 for any type */
358 struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min)
359 {
360         ScrArea *sa, *big= NULL;
361         int size, maxsize= 0;
362
363         for (sa= sc->areabase.first; sa; sa= sa->next) {
364                 if ((spacetype == -1) || sa->spacetype == spacetype) {
365                         if (min <= sa->winx && min <= sa->winy) {
366                                 size= sa->winx*sa->winy;
367                                 if (size > maxsize) {
368                                         maxsize= size;
369                                         big= sa;
370                                 }
371                         }
372                 }
373         }
374
375         return big;
376 }
377
378 void BKE_screen_view3d_sync(struct View3D *v3d, struct Scene *scene)
379 {
380         int bit;
381
382         if (v3d->scenelock && v3d->localvd==NULL) {
383                 v3d->lay= scene->lay;
384                 v3d->camera= scene->camera;
385
386                 if (v3d->camera==NULL) {
387                         ARegion *ar;
388
389                         for (ar=v3d->regionbase.first; ar; ar= ar->next) {
390                                 if (ar->regiontype == RGN_TYPE_WINDOW) {
391                                         RegionView3D *rv3d= ar->regiondata;
392                                         if (rv3d->persp==RV3D_CAMOB)
393                                                 rv3d->persp= RV3D_PERSP;
394                                 }
395                         }
396                 }
397
398                 if ((v3d->lay & v3d->layact) == 0) {
399                         for (bit= 0; bit<32; bit++) {
400                                 if (v3d->lay & (1<<bit)) {
401                                         v3d->layact= 1<<bit;
402                                         break;
403                                 }
404                         }
405                 }
406         }
407 }
408
409 void BKE_screen_view3d_scene_sync(bScreen *sc)
410 {
411         /* are there cameras in the views that are not in the scene? */
412         ScrArea *sa;
413         for (sa= sc->areabase.first; sa; sa= sa->next) {
414                 SpaceLink *sl;
415                 for (sl= sa->spacedata.first; sl; sl= sl->next) {
416                         if (sl->spacetype==SPACE_VIEW3D) {
417                                 View3D *v3d= (View3D*) sl;
418                                 BKE_screen_view3d_sync(v3d, sc->scene);
419                         }
420                 }
421         }
422 }
423
424 void BKE_screen_view3d_main_sync(ListBase *screen_lb, Scene *scene)
425 {
426         bScreen *sc;
427         ScrArea *sa;
428         SpaceLink *sl;
429
430         /* from scene copy to the other views */
431         for (sc=screen_lb->first; sc; sc=sc->id.next) {
432                 if (sc->scene!=scene)
433                         continue;
434
435                 for (sa=sc->areabase.first; sa; sa=sa->next)
436                         for (sl=sa->spacedata.first; sl; sl=sl->next)
437                                 if (sl->spacetype==SPACE_VIEW3D)
438                                         BKE_screen_view3d_sync((View3D*)sl, scene);
439         }
440 }
441
442 /* magic zoom calculation, no idea what
443  * it signifies, if you find out, tell me! -zr
444  */
445
446 /* simple, its magic dude!
447  * well, to be honest, this gives a natural feeling zooming
448  * with multiple keypad presses (ton)
449  */
450 float BKE_screen_view3d_zoom_to_fac(float camzoom)
451 {
452         return powf(((float)M_SQRT2 + camzoom/50.0f), 2.0f) / 4.0f;
453 }
454
455 float BKE_screen_view3d_zoom_from_fac(float zoomfac)
456 {
457         return ((sqrtf(4.0f * zoomfac) - (float)M_SQRT2) * 50.0f);
458 }