4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/editors/space_view3d/view3d_view.c
34 #include "DNA_camera_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_lamp_types.h"
39 #include "MEM_guardedalloc.h"
43 #include "BLI_listbase.h"
44 #include "BLI_utildefines.h"
47 #include "BKE_action.h"
48 #include "BKE_context.h"
49 #include "BKE_depsgraph.h"
50 #include "BKE_object.h"
51 #include "BKE_global.h"
53 #include "BKE_report.h"
54 #include "BKE_scene.h"
55 #include "BKE_screen.h"
58 #include "BIF_glutil.h"
65 #include "ED_screen.h"
66 #include "ED_armature.h"
68 #ifdef WITH_GAMEENGINE
69 #include "BL_System.h"
72 #include "view3d_intern.h" // own include
74 /* use this call when executing an operator,
75 event system doesn't set for each event the
76 opengl drawing context */
77 void view3d_operator_needs_opengl(const bContext *C)
79 wmWindow *win = CTX_wm_window(C);
80 ARegion *ar= CTX_wm_region(C);
82 view3d_region_operator_needs_opengl(win, ar);
85 void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
87 /* for debugging purpose, context should always be OK */
88 if ((ar == NULL) || (ar->regiontype!=RGN_TYPE_WINDOW))
89 printf("view3d_region_operator_needs_opengl error, wrong region\n");
91 RegionView3D *rv3d= ar->regiondata;
93 wmSubWindowSet(win, ar->swinid);
94 glMatrixMode(GL_PROJECTION);
95 glLoadMatrixf(rv3d->winmat);
96 glMatrixMode(GL_MODELVIEW);
97 glLoadMatrixf(rv3d->viewmat);
101 float *give_cursor(Scene *scene, View3D *v3d)
103 if(v3d && v3d->localvd) return v3d->cursor;
104 else return scene->cursor;
108 /* Gets the lens and clipping values from a camera of lamp type object */
109 void ED_view3d_ob_clip_range_get(Object *ob, float *lens, float *clipsta, float *clipend)
111 if(ob->type==OB_LAMP ) {
115 fac= cosf((float)M_PI*la->spotsize/360.0f);
117 *lens= 16.0f*fac/sinf(x1);
119 if (clipsta) *clipsta= la->clipsta;
120 if (clipend) *clipend= la->clipend;
122 else if(ob->type==OB_CAMERA) {
123 Camera *cam= ob->data;
124 if (lens) *lens= cam->lens;
125 if (clipsta) *clipsta= cam->clipsta;
126 if (clipend) *clipend= cam->clipend;
129 if (lens) *lens= 35.0f;
133 /* ****************** smooth view operator ****************** */
134 /* This operator is one of the 'timer refresh' ones like animation playback */
136 struct SmoothViewStore {
137 float orig_dist, new_dist;
138 float orig_lens, new_lens;
139 float orig_quat[4], new_quat[4];
140 float orig_ofs[3], new_ofs[3];
142 int to_camera, orig_view;
147 /* will start timer if appropriate */
148 /* the arguments are the desired situation */
149 void smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
151 wmWindowManager *wm= CTX_wm_manager(C);
152 wmWindow *win= CTX_wm_window(C);
153 ScrArea *sa= CTX_wm_area(C);
155 RegionView3D *rv3d= ar->regiondata;
156 struct SmoothViewStore sms= {0};
160 copy_v3_v3(sms.new_ofs, rv3d->ofs);
161 copy_qt_qt(sms.new_quat, rv3d->viewquat);
162 sms.new_dist= rv3d->dist;
163 sms.new_lens= v3d->lens;
166 /* note on camera locking, this is a little confusing but works ok.
167 * we may be changing the view 'as if' there is no active camera, but infact
168 * there is an active camera which is locked to the view.
170 * In the case where smooth view is moving _to_ a camera we dont want that
171 * camera to be moved or changed, so only when the camera is not being set should
172 * we allow camera option locking to initialize the view settings from the camera.
174 if(camera == NULL && oldcamera == NULL) {
175 ED_view3d_camera_lock_init(v3d, rv3d);
178 /* store the options we want to end with */
179 if(ofs) copy_v3_v3(sms.new_ofs, ofs);
180 if(quat) copy_qt_qt(sms.new_quat, quat);
181 if(dist) sms.new_dist= *dist;
182 if(lens) sms.new_lens= *lens;
185 ED_view3d_from_object(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
186 sms.to_camera= 1; /* restore view3d values in end */
189 if (C && U.smooth_viewtx) {
190 int changed = 0; /* zero means no difference */
192 if (oldcamera != camera)
194 else if (sms.new_dist != rv3d->dist)
196 else if (sms.new_lens != v3d->lens)
198 else if (!equals_v3v3(sms.new_ofs, rv3d->ofs))
200 else if (!equals_v4v4(sms.new_quat, rv3d->viewquat))
203 /* The new view is different from the old one
204 * so animate the view */
207 /* original values */
209 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
210 ED_view3d_from_object(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
213 copy_v3_v3(sms.orig_ofs, rv3d->ofs);
214 copy_qt_qt(sms.orig_quat, rv3d->viewquat);
215 sms.orig_dist= rv3d->dist;
216 sms.orig_lens= v3d->lens;
218 /* grid draw as floor */
219 if((rv3d->viewlock & RV3D_LOCKED)==0) {
220 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */
221 sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view;
222 rv3d->view= RV3D_VIEW_USER;
225 sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
227 /* if this is view rotation only
228 * we can decrease the time allowed by
229 * the angle between quats
230 * this means small rotations wont lag */
231 if (quat && !ofs && !dist) {
232 float vec1[3]={0,0,1}, vec2[3]= {0,0,1};
235 invert_qt_qt(q1, sms.new_quat);
236 invert_qt_qt(q2, sms.orig_quat);
241 /* scale the time allowed by the rotation */
242 sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */
245 /* ensure it shows correct */
246 if(sms.to_camera) rv3d->persp= RV3D_PERSP;
248 rv3d->rflag |= RV3D_NAVIGATING;
250 /* keep track of running timer! */
252 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
254 if(rv3d->smooth_timer)
255 WM_event_remove_timer(wm, win, rv3d->smooth_timer);
256 /* TIMER1 is hardcoded in keymap */
257 rv3d->smooth_timer= WM_event_add_timer(wm, win, TIMER1, 1.0/100.0); /* max 30 frs/sec */
263 /* if we get here nothing happens */
265 if(sms.to_camera==0) {
266 copy_v3_v3(rv3d->ofs, sms.new_ofs);
267 copy_qt_qt(rv3d->viewquat, sms.new_quat);
268 rv3d->dist = sms.new_dist;
269 v3d->lens = sms.new_lens;
272 if(rv3d->viewlock & RV3D_BOXVIEW)
273 view3d_boxview_copy(sa, ar);
275 ED_region_tag_redraw(ar);
279 /* only meant for timer usage */
280 static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
282 View3D *v3d = CTX_wm_view3d(C);
283 RegionView3D *rv3d= CTX_wm_region_view3d(C);
284 struct SmoothViewStore *sms= rv3d->sms;
285 float step, step_inv;
287 /* escape if not our timer */
288 if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
289 return OPERATOR_PASS_THROUGH;
291 if(sms->time_allowed != 0.0)
292 step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed);
299 /* if we went to camera, store the original */
301 rv3d->persp= RV3D_CAMOB;
302 copy_v3_v3(rv3d->ofs, sms->orig_ofs);
303 copy_qt_qt(rv3d->viewquat, sms->orig_quat);
304 rv3d->dist = sms->orig_dist;
305 v3d->lens = sms->orig_lens;
308 copy_v3_v3(rv3d->ofs, sms->new_ofs);
309 copy_qt_qt(rv3d->viewquat, sms->new_quat);
310 rv3d->dist = sms->new_dist;
311 v3d->lens = sms->new_lens;
313 ED_view3d_camera_lock_sync(v3d, rv3d);
316 if((rv3d->viewlock & RV3D_LOCKED)==0) {
317 rv3d->view= sms->orig_view;
320 MEM_freeN(rv3d->sms);
323 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
324 rv3d->smooth_timer= NULL;
325 rv3d->rflag &= ~RV3D_NAVIGATING;
331 if (step < 0.5f) step = (float)pow(step*2.0f, 2.0)/2.0f;
332 else step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f);
334 step_inv = 1.0f-step;
337 rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv;
339 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
341 rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv;
342 v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv;
344 ED_view3d_camera_lock_sync(v3d, rv3d);
347 if(rv3d->viewlock & RV3D_BOXVIEW)
348 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
350 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
352 return OPERATOR_FINISHED;
355 void VIEW3D_OT_smoothview(wmOperatorType *ot)
359 ot->name= "Smooth View";
360 ot->idname= "VIEW3D_OT_smoothview";
361 ot->description="The time to animate the change of view (in milliseconds)";
364 ot->invoke= view3d_smoothview_invoke;
366 ot->poll= ED_operator_view3d_active;
369 /* ****************** change view operators ****************** */
371 static int view3d_setcameratoview_exec(bContext *C, wmOperator *UNUSED(op))
373 View3D *v3d = CTX_wm_view3d(C);
374 RegionView3D *rv3d= CTX_wm_region_view3d(C);
376 copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
377 rv3d->lview= rv3d->view;
378 if(rv3d->persp != RV3D_CAMOB) {
379 rv3d->lpersp= rv3d->persp;
382 ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
383 DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
384 rv3d->persp = RV3D_CAMOB;
386 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, v3d->camera);
388 return OPERATOR_FINISHED;
392 static int view3d_setcameratoview_poll(bContext *C)
394 View3D *v3d= CTX_wm_view3d(C);
395 if(v3d && v3d->camera && v3d->camera->id.lib==NULL) {
396 RegionView3D *rv3d= CTX_wm_region_view3d(C);
397 if(rv3d && !rv3d->viewlock) {
405 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
409 ot->name= "Align Camera To View";
410 ot->description= "Set camera view to active view";
411 ot->idname= "VIEW3D_OT_camera_to_view";
414 ot->exec= view3d_setcameratoview_exec;
415 ot->poll= view3d_setcameratoview_poll;
418 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
422 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op))
424 View3D *v3d = CTX_wm_view3d(C);
425 ARegion *ar= ED_view3d_context_region_unlock(C);
426 RegionView3D *rv3d= ar->regiondata; /* no NULL check is needed, poll checks */
427 Scene *scene= CTX_data_scene(C);
428 Object *ob = CTX_data_active_object(C);
431 Object *camera_old= (rv3d->persp == RV3D_CAMOB) ? V3D_CAMERA_SCENE(scene, v3d) : NULL;
432 rv3d->persp= RV3D_CAMOB;
437 if(camera_old != ob) /* unlikely but looks like a glitch when set to the same */
438 smooth_view(C, v3d, ar, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
440 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C));
443 return OPERATOR_FINISHED;
446 int ED_operator_rv3d_unlock_poll(bContext *C)
448 return ED_view3d_context_region_unlock(C) != NULL;
451 void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
455 ot->name= "Set Active Object as Camera";
456 ot->description= "Set the active object as the active camera for this view or scene";
457 ot->idname= "VIEW3D_OT_object_as_camera";
460 ot->exec= view3d_setobjectascamera_exec;
461 ot->poll= ED_operator_rv3d_unlock_poll;
464 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
467 /* ********************************** */
469 void ED_view3d_calc_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
471 float modelview[4][4];
473 int val, flip_sign, a;
475 /* near zero floating point values can give issues with gluUnProject
476 in side view on some implementations */
477 if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
478 if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
480 /* Set up viewport so that gluUnProject will give correct values */
481 mats->viewport[0] = 0;
482 mats->viewport[1] = 0;
484 /* four clipping planes and bounding volume */
485 /* first do the bounding volume */
486 for(val=0; val<4; val++) {
487 xs= (val==0||val==3)?rect->xmin:rect->xmax;
488 ys= (val==0||val==1)?rect->ymin:rect->ymax;
490 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
491 VECCOPY(bb->vec[val], p);
493 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
494 VECCOPY(bb->vec[4+val], p);
497 /* verify if we have negative scale. doing the transform before cross
498 product flips the sign of the vector compared to doing cross product
499 before transform then, so we correct for that. */
501 ((float*)modelview)[a] = mats->modelview[a];
502 flip_sign = is_negative_m4(modelview);
504 /* then plane equations */
505 for(val=0; val<4; val++) {
507 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
510 negate_v3(planes[val]);
512 planes[val][3]= - planes[val][0]*bb->vec[val][0]
513 - planes[val][1]*bb->vec[val][1]
514 - planes[val][2]*bb->vec[val][2];
518 /* create intersection coordinates in view Z direction at mouse coordinates */
519 void ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
521 RegionView3D *rv3d= ar->regiondata;
525 ED_view3d_win_to_vector(ar, mval, vec);
527 copy_v3_v3(ray_start, rv3d->viewinv[3]);
528 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
529 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
533 vec[0] = 2.0f * mval[0] / ar->winx - 1;
534 vec[1] = 2.0f * mval[1] / ar->winy - 1;
538 mul_m4_v4(rv3d->persinv, vec);
540 VECADDFAC(ray_start, vec, rv3d->viewinv[2], 1000.0f);
541 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
545 if(rv3d->rflag & RV3D_CLIPPING) {
548 clip_line_plane(ray_start, ray_end, rv3d->clip[a]);
553 /* create intersection ray in view Z direction at mouse coordinates */
554 void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3])
558 ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end);
559 sub_v3_v3v3(ray_normal, ray_end, ray_start);
560 normalize_v3(ray_normal);
563 void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3])
565 if (rv3d->is_persp) {
568 copy_v3_v3(p1, coord);
572 mul_m4_v4(rv3d->viewmat, p2);
576 mul_m4_v4(rv3d->viewinv, p2);
578 sub_v3_v3v3(vec, p1, p2);
581 copy_v3_v3(vec, rv3d->viewinv[2]);
586 int initgrabz(RegionView3D *rv3d, float x, float y, float z)
589 if(rv3d==NULL) return flip;
590 rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
591 if (rv3d->zfac < 0.0f)
593 /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that
594 * (accounting for near zero values)
596 if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
598 /* Negative zfac means x, y, z was behind the camera (in perspective).
599 * This gives flipped directions, so revert back to ok default case.
601 // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
602 // -- Aligorith, 2009Aug31
603 //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
604 if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac;
609 void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
611 RegionView3D *rv3d= ar->regiondata;
618 copy_v3_v3(line_sta, rv3d->viewinv[3]);
619 ED_view3d_win_to_vector(ar, mval, mousevec);
620 add_v3_v3v3(line_end, line_sta, mousevec);
622 if(isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], TRUE) == 0) {
623 /* highly unlikely to ever happen, mouse vec paralelle with view plane */
628 const float dx= (2.0f * mval[0] / (float)ar->winx) - 1.0f;
629 const float dy= (2.0f * mval[1] / (float)ar->winy) - 1.0f;
630 line_sta[0]= (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
631 line_sta[1]= (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
632 line_sta[2]= (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
634 add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]);
635 closest_to_line_v3(out, depth_pt, line_sta, line_end);
639 /* always call initgrabz */
640 /* only to detect delta motion */
641 void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
643 RegionView3D *rv3d= ar->regiondata;
646 dx= 2.0f*mval[0]*rv3d->zfac/ar->winx;
647 dy= 2.0f*mval[1]*rv3d->zfac/ar->winy;
649 out[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
650 out[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
651 out[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
654 /* doesn't rely on initgrabz */
655 /* for perspective view, get the vector direction to
656 * the mouse cursor as a normalized vector */
657 void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3])
659 RegionView3D *rv3d= ar->regiondata;
662 out[0]= 2.0f * (mval[0] / ar->winx) - 1.0f;
663 out[1]= 2.0f * (mval[1] / ar->winy) - 1.0f;
665 mul_project_m4_v3(rv3d->persinv, out);
666 sub_v3_v3(out, rv3d->viewinv[3]);
669 copy_v3_v3(out, rv3d->viewinv[2]);
674 float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
676 ViewDepths *vd = vc->rv3d->depths;
678 x -= vc->ar->winrct.xmin;
679 y -= vc->ar->winrct.ymin;
681 if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
682 return vd->depths[y * vd->w + x];
687 void ED_view3d_depth_tag_update(RegionView3D *rv3d)
690 rv3d->depths->damaged= 1;
693 void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4])
697 mul_m4_m4m4(vmat, ob->obmat, rv3d->viewmat);
698 mul_m4_m4m4(pmat, vmat, rv3d->winmat);
702 /* Uses window coordinates (x,y) and depth component z to find a point in
704 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
708 gluUnProject(x,y,z, mats->modelview, mats->projection,
709 (GLint *)mats->viewport, &ux, &uy, &uz );
716 /* use above call to get projecting mat */
717 void ED_view3d_project_float(ARegion *ar, const float vec[3], float adr[2], float mat[4][4])
722 copy_v3_v3(vec4, vec);
725 mul_m4_v4(mat, vec4);
727 if( vec4[3]>FLT_EPSILON ) {
728 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
729 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
731 adr[0] = adr[1] = 0.0f;
735 int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
740 float vec[4], min, max;
743 if(bb==NULL) return 1;
744 if(bb->flag & OB_BB_DISABLED) return 1;
746 mul_m4_m4m4(mat, obmat, rv3d->persmat);
749 copy_v3_v3(vec, bb->vec[a]);
756 if(vec[0] < min) fl+= 1;
757 if(vec[0] > max) fl+= 2;
758 if(vec[1] < min) fl+= 4;
759 if(vec[1] > max) fl+= 8;
760 if(vec[2] < min) fl+= 16;
761 if(vec[2] > max) fl+= 32;
764 if(flag==0) return 1;
770 void project_short(ARegion *ar, const float vec[3], short adr[2]) /* clips */
772 RegionView3D *rv3d= ar->regiondata;
773 float fx, fy, vec4[4];
777 if(rv3d->rflag & RV3D_CLIPPING) {
778 if(ED_view3d_test_clipping(rv3d, vec, 0))
782 copy_v3_v3(vec4, vec);
784 mul_m4_v4(rv3d->persmat, vec4);
786 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
787 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
789 if( fx>0 && fx<ar->winx) {
791 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
793 if(fy > 0.0f && fy < (float)ar->winy) {
794 adr[0]= (short)floor(fx);
795 adr[1]= (short)floor(fy);
801 void project_int(ARegion *ar, const float vec[3], int adr[2])
803 RegionView3D *rv3d= ar->regiondata;
804 float fx, fy, vec4[4];
806 adr[0]= (int)2140000000.0f;
807 copy_v3_v3(vec4, vec);
810 mul_m4_v4(rv3d->persmat, vec4);
812 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
813 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
815 if( fx>-2140000000.0f && fx<2140000000.0f) {
816 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
818 if(fy>-2140000000.0f && fy<2140000000.0f) {
819 adr[0]= (int)floor(fx);
820 adr[1]= (int)floor(fy);
826 void project_int_noclip(ARegion *ar, const float vec[3], int adr[2])
828 RegionView3D *rv3d= ar->regiondata;
829 float fx, fy, vec4[4];
831 copy_v3_v3(vec4, vec);
834 mul_m4_v4(rv3d->persmat, vec4);
836 if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
837 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
838 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
840 adr[0] = (int)floor(fx);
841 adr[1] = (int)floor(fy);
845 adr[0] = ar->winx / 2;
846 adr[1] = ar->winy / 2;
850 void project_short_noclip(ARegion *ar, const float vec[3], short adr[2])
852 RegionView3D *rv3d= ar->regiondata;
853 float fx, fy, vec4[4];
856 copy_v3_v3(vec4, vec);
859 mul_m4_v4(rv3d->persmat, vec4);
861 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
862 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
864 if( fx>-32700 && fx<32700) {
866 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
868 if(fy > -32700.0f && fy < 32700.0f) {
869 adr[0]= (short)floor(fx);
870 adr[1]= (short)floor(fy);
876 void project_float(ARegion *ar, const float vec[3], float adr[2])
878 RegionView3D *rv3d= ar->regiondata;
882 copy_v3_v3(vec4, vec);
885 mul_m4_v4(rv3d->persmat, vec4);
887 if(vec4[3] > (float)BL_NEAR_CLIP) {
888 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
889 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
893 void project_float_noclip(ARegion *ar, const float vec[3], float adr[2])
895 RegionView3D *rv3d= ar->regiondata;
898 copy_v3_v3(vec4, vec);
901 mul_m4_v4(rv3d->persmat, vec4);
903 if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
904 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
905 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
909 adr[0] = ar->winx / 2.0f;
910 adr[1] = ar->winy / 2.0f;
914 /* copies logic of get_view3d_viewplane(), keep in sync */
915 int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
922 if(rv3d->persp==RV3D_CAMOB) {
924 if(v3d->camera->type==OB_LAMP ) {
925 Lamp *la= v3d->camera->data;
926 *clipsta= la->clipsta;
927 *clipend= la->clipend;
929 else if(v3d->camera->type==OB_CAMERA) {
930 Camera *cam= v3d->camera->data;
931 *clipsta= cam->clipsta;
932 *clipend= cam->clipend;
934 if(cam->type==CAM_ORTHO)
940 if(rv3d->persp==RV3D_ORTHO) {
941 *clipend *= 0.5f; // otherwise too extreme low zbuffer quality
942 *clipsta= - *clipend;
949 /* also exposed in previewrender.c */
950 int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
953 float lens, fac, x1, y1, x2, y2;
954 float winx= (float)winxi, winy= (float)winyi;
962 if(rv3d->persp==RV3D_CAMOB) {
964 if(v3d->camera->type==OB_LAMP ) {
967 la= v3d->camera->data;
968 fac= cosf(((float)M_PI)*la->spotsize/360.0f);
971 lens= 16.0f*fac/sinf(x1);
973 *clipsta= la->clipsta;
974 *clipend= la->clipend;
976 else if(v3d->camera->type==OB_CAMERA) {
977 cam= v3d->camera->data;
979 *clipsta= cam->clipsta;
980 *clipend= cam->clipend;
985 if(rv3d->persp==RV3D_ORTHO) {
986 if(winx>winy) x1= -rv3d->dist;
987 else x1= -winx*rv3d->dist/winy;
990 if(winx>winy) y1= -winy*rv3d->dist/winx;
991 else y1= -rv3d->dist;
994 *clipend *= 0.5f; // otherwise too extreme low zbuffer quality
995 *clipsta= - *clipend;
999 /* fac for zoom, also used for camdx */
1000 if(rv3d->persp==RV3D_CAMOB) {
1001 fac= BKE_screen_view3d_zoom_to_fac((float)rv3d->camzoom) * 4.0f;
1007 /* viewplane size depends... */
1008 if(cam && cam->type==CAM_ORTHO) {
1009 /* ortho_scale == 1 means exact 1 to 1 mapping */
1010 float dfac= 2.0f*cam->ortho_scale/fac;
1012 if(winx>winy) x1= -dfac;
1013 else x1= -winx*dfac/winy;
1016 if(winx>winy) y1= -winy*dfac/winx;
1024 if(winx>winy) dfac= 64.0f/(fac*winx*lens);
1025 else dfac= 64.0f/(fac*winy*lens);
1027 x1= - *clipsta * winx*dfac;
1029 y1= - *clipsta * winy*dfac;
1033 /* cam view offset */
1035 float dx= 0.5f*fac*rv3d->camdx*(x2-x1);
1036 float dy= 0.5f*fac*rv3d->camdy*(y2-y1);
1039 if(cam->type==CAM_ORTHO) {
1040 dx += cam->shiftx * cam->ortho_scale;
1041 dy += cam->shifty * cam->ortho_scale;
1044 dx += cam->shiftx * (cam->clipsta / cam->lens) * 32.0f;
1045 dy += cam->shifty * (cam->clipsta / cam->lens) * 32.0f;
1059 viewfac= (winx >= winy)? winx: winy;
1060 *pixsize= 1.0f/viewfac;
1063 viewfac= (((winx >= winy)? winx: winy)*lens)/32.0f;
1064 *pixsize= *clipsta/viewfac;
1068 viewplane->xmin= x1;
1069 viewplane->ymin= y1;
1070 viewplane->xmax= x2;
1071 viewplane->ymax= y2;
1076 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect) /* rect: for picking */
1078 RegionView3D *rv3d= ar->regiondata;
1080 float clipsta, clipend, x1, y1, x2, y2;
1083 orth= ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
1084 rv3d->is_persp= !orth;
1086 // printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1092 if(rect) { /* picking */
1093 rect->xmin/= (float)ar->winx;
1094 rect->xmin= x1+rect->xmin*(x2-x1);
1095 rect->ymin/= (float)ar->winy;
1096 rect->ymin= y1+rect->ymin*(y2-y1);
1097 rect->xmax/= (float)ar->winx;
1098 rect->xmax= x1+rect->xmax*(x2-x1);
1099 rect->ymax/= (float)ar->winy;
1100 rect->ymax= y1+rect->ymax*(y2-y1);
1102 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1103 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1107 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
1108 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
1111 /* update matrix in 3d view region */
1112 glGetFloatv(GL_PROJECTION_MATRIX, (float*)rv3d->winmat);
1115 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
1120 rv3d->view= RV3D_VIEW_USER; /* dont show the grid */
1122 copy_m4_m4(bmat, ob->obmat);
1124 invert_m4_m4(rv3d->viewmat, bmat);
1126 /* view quat calculation, needed for add object */
1127 copy_m3_m4(tmat, rv3d->viewmat);
1130 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1131 /* were from a camera view */
1134 float orig_dist= rv3d->dist;
1135 float orig_lens= v3d->lens;
1136 copy_v3_v3(orig_ofs, rv3d->ofs);
1138 /* Switch from camera view */
1139 mat3_to_quat( new_quat,tmat);
1141 rv3d->persp=RV3D_PERSP;
1144 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1145 smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1147 rv3d->persp=RV3D_CAMOB; /* just to be polite, not needed */
1150 mat3_to_quat( new_quat,tmat);
1151 smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1154 mat3_to_quat( rv3d->viewquat,tmat);
1158 #define QUATSET(a, b, c, d, e) a[0]=b; a[1]=c; a[2]=d; a[3]=e;
1160 int ED_view3d_lock(RegionView3D *rv3d)
1162 switch(rv3d->view) {
1163 case RV3D_VIEW_BOTTOM :
1164 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
1167 case RV3D_VIEW_BACK:
1168 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
1171 case RV3D_VIEW_LEFT:
1172 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
1176 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
1179 case RV3D_VIEW_FRONT:
1180 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
1183 case RV3D_VIEW_RIGHT:
1184 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
1193 /* dont set windows active in in here, is used by renderwin too */
1194 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
1196 if(rv3d->persp==RV3D_CAMOB) { /* obs/camera */
1198 where_is_object(scene, v3d->camera);
1199 obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1202 quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1203 rv3d->viewmat[3][2]-= rv3d->dist;
1207 /* should be moved to better initialize later on XXX */
1209 ED_view3d_lock(rv3d);
1211 quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1212 if(rv3d->persp==RV3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1213 if(v3d->ob_centre) {
1214 Object *ob= v3d->ob_centre;
1217 copy_v3_v3(vec, ob->obmat[3]);
1218 if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1219 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1221 copy_v3_v3(vec, pchan->pose_mat[3]);
1222 mul_m4_v3(ob->obmat, vec);
1225 translate_m4( rv3d->viewmat,-vec[0], -vec[1], -vec[2]);
1227 else if (v3d->ob_centre_cursor) {
1229 copy_v3_v3(vec, give_cursor(scene, v3d));
1230 translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
1232 else translate_m4( rv3d->viewmat,rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
1236 /* IGLuint-> GLuint*/
1237 /* Warning: be sure to account for a negative return value
1238 * This is an error, "Too many objects in select buffer"
1239 * and no action should be taken (can crash blender) if this happens
1241 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1243 Scene *scene= vc->scene;
1244 View3D *v3d= vc->v3d;
1245 ARegion *ar= vc->ar;
1252 /* case not a border select */
1253 if(input->xmin==input->xmax) {
1254 rect.xmin= input->xmin-12; // seems to be default value for bones only now
1255 rect.xmax= input->xmin+12;
1256 rect.ymin= input->ymin-12;
1257 rect.ymax= input->ymin+12;
1260 rect.xmin= input->xmin;
1261 rect.xmax= input->xmax;
1262 rect.ymin= input->ymin;
1263 rect.ymax= input->ymax;
1266 setwinmatrixview3d(ar, v3d, &rect);
1267 mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1269 if(v3d->drawtype > OB_WIRE) {
1271 glEnable(GL_DEPTH_TEST);
1274 if(vc->rv3d->rflag & RV3D_CLIPPING)
1275 view3d_set_clipping(vc->rv3d);
1277 glSelectBuffer( bufsize, (GLuint *)buffer);
1278 glRenderMode(GL_SELECT);
1279 glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
1283 if(vc->obedit && vc->obedit->type==OB_MBALL) {
1284 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1286 else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1287 /* if not drawing sketch, draw bones */
1288 if(!BDR_drawSketchNames(vc)) {
1289 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1295 v3d->xray= TRUE; // otherwise it postpones drawing
1296 for(base= scene->base.first; base; base= base->next) {
1297 if(base->lay & v3d->lay) {
1299 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1304 draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1306 /* we draw group-duplicators for selection too */
1307 if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1312 tbase.flag= OB_FROMDUPLI;
1313 lb= object_duplilist(scene, base->object);
1315 for(dob= lb->first; dob; dob= dob->next) {
1316 tbase.object= dob->ob;
1317 copy_m4_m4(dob->ob->obmat, dob->mat);
1319 /* extra service: draw the duplicator in drawtype of parent */
1320 /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
1321 dt= tbase.object->dt; tbase.object->dt= MIN2(tbase.object->dt, base->object->dt);
1322 dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;
1324 draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1326 tbase.object->dt= dt;
1327 tbase.object->dtx= dtx;
1329 copy_m4_m4(dob->ob->obmat, dob->omat);
1331 free_object_duplilist(lb);
1337 v3d->xray= FALSE; // restore
1340 glPopName(); /* see above (pushname) */
1341 hits= glRenderMode(GL_RENDER);
1344 setwinmatrixview3d(ar, v3d, NULL);
1345 mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1347 if(v3d->drawtype > OB_WIRE) {
1349 glDisable(GL_DEPTH_TEST);
1351 // XXX persp(PERSP_WIN);
1353 if(vc->rv3d->rflag & RV3D_CLIPPING)
1354 view3d_clr_clipping();
1356 if(hits<0) printf("Too many objects in select buffer\n"); // XXX make error message
1361 /* ********************** local view operator ******************** */
1363 static unsigned int free_localbit(Main *bmain)
1371 /* sometimes we loose a localview: when an area is closed */
1372 /* check all areas: which localviews are in use? */
1373 for(sc= bmain->screen.first; sc; sc= sc->id.next) {
1374 for(sa= sc->areabase.first; sa; sa= sa->next) {
1375 SpaceLink *sl= sa->spacedata.first;
1376 for(; sl; sl= sl->next) {
1377 if(sl->spacetype==SPACE_VIEW3D) {
1378 View3D *v3d= (View3D*) sl;
1385 if( (lay & 0x01000000)==0) return 0x01000000;
1386 if( (lay & 0x02000000)==0) return 0x02000000;
1387 if( (lay & 0x04000000)==0) return 0x04000000;
1388 if( (lay & 0x08000000)==0) return 0x08000000;
1389 if( (lay & 0x10000000)==0) return 0x10000000;
1390 if( (lay & 0x20000000)==0) return 0x20000000;
1391 if( (lay & 0x40000000)==0) return 0x40000000;
1392 if( (lay & 0x80000000)==0) return 0x80000000;
1397 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
1401 /* ensure we always have some layer selected */
1409 for(i=0; i<20; i++) {
1412 /* if this value has just been switched on, make that layer active */
1413 if (values[i] && (lay & (1<<i))==0) {
1418 if (values[i]) lay |= (1<<i);
1419 else lay &= ~(1<<i);
1422 /* ensure always an active layer */
1423 if (active && (lay & *active)==0) {
1424 for(i=0; i<20; i++) {
1435 static void initlocalview(Main *bmain, Scene *scene, ScrArea *sa)
1437 View3D *v3d= sa->spacedata.first;
1439 float size = 0.0, min[3], max[3], box[3];
1440 unsigned int locallay;
1443 if(v3d->localvd) return;
1445 INIT_MINMAX(min, max);
1447 locallay= free_localbit(bmain);
1450 printf("Sorry, no more than 8 localviews\n"); // XXX error
1455 minmax_object(scene->obedit, min, max);
1459 BASACT->lay |= locallay;
1460 scene->obedit->lay= BASACT->lay;
1463 for(base= FIRSTBASE; base; base= base->next) {
1464 if(TESTBASE(v3d, base)) {
1465 minmax_object(base->object, min, max);
1466 base->lay |= locallay;
1467 base->object->lay= base->lay;
1473 box[0]= (max[0]-min[0]);
1474 box[1]= (max[1]-min[1]);
1475 box[2]= (max[2]-min[2]);
1476 size= MAX3(box[0], box[1], box[2]);
1477 if(size <= 0.01f) size= 0.01f;
1483 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1485 memcpy(v3d->localvd, v3d, sizeof(View3D));
1487 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1488 if(ar->regiontype == RGN_TYPE_WINDOW) {
1489 RegionView3D *rv3d= ar->regiondata;
1491 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
1492 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1494 rv3d->ofs[0]= -(min[0]+max[0])/2.0f;
1495 rv3d->ofs[1]= -(min[1]+max[1])/2.0f;
1496 rv3d->ofs[2]= -(min[2]+max[2])/2.0f;
1499 /* perspective should be a bit farther away to look nice */
1500 if(rv3d->persp==RV3D_ORTHO)
1503 // correction for window aspect ratio
1504 if(ar->winy>2 && ar->winx>2) {
1505 float asp= (float)ar->winx/(float)ar->winy;
1506 if(asp < 1.0f) asp= 1.0f/asp;
1510 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP;
1512 v3d->cursor[0]= -rv3d->ofs[0];
1513 v3d->cursor[1]= -rv3d->ofs[1];
1514 v3d->cursor[2]= -rv3d->ofs[2];
1522 for(base= FIRSTBASE; base; base= base->next) {
1523 if( base->lay & locallay ) {
1524 base->lay-= locallay;
1525 if(base->lay==0) base->lay= v3d->layact;
1526 if(base->object != scene->obedit) base->flag |= SELECT;
1527 base->object->lay= base->lay;
1534 static void restore_localviewdata(ScrArea *sa, int free)
1537 View3D *v3d= sa->spacedata.first;
1539 if(v3d->localvd==NULL) return;
1541 v3d->near= v3d->localvd->near;
1542 v3d->far= v3d->localvd->far;
1543 v3d->lay= v3d->localvd->lay;
1544 v3d->layact= v3d->localvd->layact;
1545 v3d->drawtype= v3d->localvd->drawtype;
1546 v3d->camera= v3d->localvd->camera;
1549 MEM_freeN(v3d->localvd);
1553 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1554 if(ar->regiontype == RGN_TYPE_WINDOW) {
1555 RegionView3D *rv3d= ar->regiondata;
1558 rv3d->dist= rv3d->localvd->dist;
1559 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs);
1560 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat);
1561 rv3d->view= rv3d->localvd->view;
1562 rv3d->persp= rv3d->localvd->persp;
1563 rv3d->camzoom= rv3d->localvd->camzoom;
1566 MEM_freeN(rv3d->localvd);
1567 rv3d->localvd= NULL;
1574 static void endlocalview(Main *bmain, Scene *scene, ScrArea *sa)
1576 View3D *v3d= sa->spacedata.first;
1578 unsigned int locallay;
1582 locallay= v3d->lay & 0xFF000000;
1584 restore_localviewdata(sa, 1); // 1 = free
1586 /* for when in other window the layers have changed */
1587 if(v3d->scenelock) v3d->lay= scene->lay;
1589 for(base= FIRSTBASE; base; base= base->next) {
1590 if( base->lay & locallay ) {
1591 base->lay-= locallay;
1592 if(base->lay==0) base->lay= v3d->layact;
1593 if(base->object != scene->obedit) {
1594 base->flag |= SELECT;
1595 base->object->flag |= SELECT;
1597 base->object->lay= base->lay;
1601 DAG_on_visible_update(bmain, FALSE);
1605 static int localview_exec(bContext *C, wmOperator *UNUSED(unused))
1607 View3D *v3d= CTX_wm_view3d(C);
1610 endlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
1612 initlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
1614 ED_area_tag_redraw(CTX_wm_area(C));
1616 return OPERATOR_FINISHED;
1619 void VIEW3D_OT_localview(wmOperatorType *ot)
1623 ot->name= "Local View";
1624 ot->description= "Toggle display of selected object(s) separately and centered in view";
1625 ot->idname= "VIEW3D_OT_localview";
1628 ot->exec= localview_exec;
1629 ot->flag= OPTYPE_UNDO; /* localview changes object layer bitflags */
1631 ot->poll= ED_operator_view3d_active;
1634 #ifdef WITH_GAMEENGINE
1636 static ListBase queue_back;
1637 static void SaveState(bContext *C, wmWindow *win)
1639 Object *obact = CTX_data_active_object(C);
1641 glPushAttrib(GL_ALL_ATTRIB_BITS);
1643 if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1644 GPU_paint_set_mipmap(1);
1646 queue_back= win->queue;
1648 win->queue.first= win->queue.last= NULL;
1650 //XXX waitcursor(1);
1653 static void RestoreState(bContext *C, wmWindow *win)
1655 Object *obact = CTX_data_active_object(C);
1657 if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1658 GPU_paint_set_mipmap(0);
1660 //XXX curarea->win_swap = 0;
1661 //XXX curarea->head_swap=0;
1662 //XXX allqueue(REDRAWVIEW3D, 1);
1663 //XXX allqueue(REDRAWBUTSALL, 0);
1664 //XXX reset_slowparents();
1665 //XXX waitcursor(0);
1668 if(win) /* check because closing win can set to NULL */
1669 win->queue= queue_back;
1672 GPU_set_tpage(NULL, 0);
1677 /* was space_set_commmandline_options in 2.4x */
1678 static void game_set_commmandline_options(GameData *gm)
1680 SYS_SystemHandle syshandle;
1683 if ( (syshandle = SYS_GetSystem()) ) {
1684 /* User defined settings */
1685 test= (U.gameflags & USER_DISABLE_MIPMAP);
1686 GPU_set_mipmap(!test);
1687 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
1689 /* File specific settings: */
1690 /* Only test the first one. These two are switched
1691 * simultaneously. */
1692 test= (gm->flag & GAME_SHOW_FRAMERATE);
1693 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
1694 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
1696 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
1697 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
1699 test= (gm->flag & GAME_SHOW_PHYSICS);
1700 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
1702 test= (gm->flag & GAME_ENABLE_ALL_FRAMES);
1703 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
1705 test= (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
1706 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
1708 test= (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
1709 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
1711 test= (gm->matmode == GAME_MAT_MULTITEX);
1712 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
1713 test= (gm->matmode == GAME_MAT_GLSL);
1714 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
1715 test= (gm->flag & GAME_DISPLAY_LISTS);
1716 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
1722 #endif // WITH_GAMEENGINE
1724 static int game_engine_poll(bContext *C)
1726 /* we need a context and area to launch BGE
1727 it's a temporary solution to avoid crash at load time
1728 if we try to auto run the BGE. Ideally we want the
1729 context to be set as soon as we load the file. */
1731 if(CTX_wm_window(C)==NULL) return 0;
1732 if(CTX_wm_screen(C)==NULL) return 0;
1733 if(CTX_wm_area(C)==NULL) return 0;
1735 if(CTX_data_mode_enum(C)!=CTX_MODE_OBJECT)
1741 int ED_view3d_context_activate(bContext *C)
1743 bScreen *sc= CTX_wm_screen(C);
1744 ScrArea *sa= CTX_wm_area(C);
1747 /* sa can be NULL when called from python */
1748 if(sa==NULL || sa->spacetype != SPACE_VIEW3D)
1749 for(sa=sc->areabase.first; sa; sa= sa->next)
1750 if(sa->spacetype==SPACE_VIEW3D)
1756 for(ar=sa->regionbase.first; ar; ar=ar->next)
1757 if(ar->regiontype == RGN_TYPE_WINDOW)
1763 // bad context switch ..
1764 CTX_wm_area_set(C, sa);
1765 CTX_wm_region_set(C, ar);
1770 static int game_engine_exec(bContext *C, wmOperator *op)
1772 #ifdef WITH_GAMEENGINE
1773 Scene *startscene = CTX_data_scene(C);
1774 ScrArea *sa, *prevsa= CTX_wm_area(C);
1775 ARegion *ar, *prevar= CTX_wm_region(C);
1776 wmWindow *prevwin= CTX_wm_window(C);
1780 (void)op; /* unused */
1782 // bad context switch ..
1783 if(!ED_view3d_context_activate(C))
1784 return OPERATOR_CANCELLED;
1786 rv3d= CTX_wm_region_view3d(C);
1788 ar= CTX_wm_region(C);
1790 view3d_operator_needs_opengl(C);
1792 game_set_commmandline_options(&startscene->gm);
1794 if(rv3d->persp==RV3D_CAMOB && startscene->gm.framing.type == SCE_GAMEFRAMING_BARS && startscene->gm.stereoflag != STEREO_DOME) { /* Letterbox */
1796 ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE);
1797 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
1798 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
1799 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
1800 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
1801 BLI_isect_rcti(&ar->winrct, &cam_frame, &cam_frame);
1804 cam_frame.xmin = ar->winrct.xmin;
1805 cam_frame.xmax = ar->winrct.xmax;
1806 cam_frame.ymin = ar->winrct.ymin;
1807 cam_frame.ymax = ar->winrct.ymax;
1811 SaveState(C, prevwin);
1813 StartKetsjiShell(C, ar, &cam_frame, 1);
1815 /* window wasnt closed while the BGE was running */
1816 if(BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
1818 CTX_wm_window_set(C, NULL);
1822 /* restore context, in case it changed in the meantime, for
1823 example by working in another window or closing it */
1824 CTX_wm_region_set(C, prevar);
1825 CTX_wm_window_set(C, prevwin);
1826 CTX_wm_area_set(C, prevsa);
1829 RestoreState(C, prevwin);
1831 //XXX restore_all_scene_cfra(scene_cfra_store);
1832 set_scene_bg(CTX_data_main(C), startscene);
1833 //XXX scene_update_for_newframe(bmain, scene, scene->lay);
1835 ED_area_tag_redraw(CTX_wm_area(C));
1837 return OPERATOR_FINISHED;
1839 (void)C; /* unused */
1840 BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build.");
1841 return OPERATOR_CANCELLED;
1845 void VIEW3D_OT_game_start(wmOperatorType *ot)
1849 ot->name= "Start Game Engine";
1850 ot->description= "Start game engine";
1851 ot->idname= "VIEW3D_OT_game_start";
1854 ot->exec= game_engine_exec;
1856 ot->poll= game_engine_poll;
1859 /* ************************************** */
1861 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1863 float alignaxis[3] = {0.0, 0.0, 0.0};
1864 float norm[3], axis[3], angle, new_quat[4];
1866 if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1867 else alignaxis[-axisidx-1]= -1.0;
1869 normalize_v3_v3(norm, vec);
1871 angle= (float)acos(dot_v3v3(alignaxis, norm));
1872 cross_v3_v3v3(axis, alignaxis, norm);
1873 axis_angle_to_quat( new_quat,axis, -angle);
1875 rv3d->view= RV3D_VIEW_USER;
1877 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1878 /* switch out of camera view */
1880 float orig_dist= rv3d->dist;
1881 float orig_lens= v3d->lens;
1883 copy_v3_v3(orig_ofs, rv3d->ofs);
1884 rv3d->persp= RV3D_PERSP;
1886 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1887 smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1889 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */
1890 smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1894 float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3])
1896 return (rv3d->persmat[3][3] + (
1897 rv3d->persmat[0][3]*co[0] +
1898 rv3d->persmat[1][3]*co[1] +
1899 rv3d->persmat[2][3]*co[2])