Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2008 Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * 00022 * Contributor(s): Blender Foundation 00023 * 00024 * ***** END GPL LICENSE BLOCK ***** 00025 */ 00026 00032 #include "DNA_camera_types.h" 00033 #include "DNA_scene_types.h" 00034 #include "DNA_object_types.h" 00035 #include "DNA_lamp_types.h" 00036 00037 #include "MEM_guardedalloc.h" 00038 00039 #include "BLI_math.h" 00040 #include "BLI_rect.h" 00041 #include "BLI_listbase.h" 00042 #include "BLI_utildefines.h" 00043 00044 #include "BKE_anim.h" 00045 #include "BKE_action.h" 00046 #include "BKE_camera.h" 00047 #include "BKE_context.h" 00048 #include "BKE_depsgraph.h" 00049 #include "BKE_object.h" 00050 #include "BKE_global.h" 00051 #include "BKE_main.h" 00052 #include "BKE_report.h" 00053 #include "BKE_scene.h" 00054 #include "BKE_screen.h" 00055 00056 #include "BIF_gl.h" 00057 #include "BIF_glutil.h" 00058 00059 #include "GPU_draw.h" 00060 00061 #include "WM_api.h" 00062 #include "WM_types.h" 00063 00064 #include "ED_screen.h" 00065 #include "ED_armature.h" 00066 00067 #ifdef WITH_GAMEENGINE 00068 #include "BL_System.h" 00069 #endif 00070 00071 #include "view3d_intern.h" // own include 00072 00073 /* use this call when executing an operator, 00074 event system doesn't set for each event the 00075 opengl drawing context */ 00076 void view3d_operator_needs_opengl(const bContext *C) 00077 { 00078 wmWindow *win = CTX_wm_window(C); 00079 ARegion *ar= CTX_wm_region(C); 00080 00081 view3d_region_operator_needs_opengl(win, ar); 00082 } 00083 00084 void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar) 00085 { 00086 /* for debugging purpose, context should always be OK */ 00087 if ((ar == NULL) || (ar->regiontype!=RGN_TYPE_WINDOW)) 00088 printf("view3d_region_operator_needs_opengl error, wrong region\n"); 00089 else { 00090 RegionView3D *rv3d= ar->regiondata; 00091 00092 wmSubWindowSet(win, ar->swinid); 00093 glMatrixMode(GL_PROJECTION); 00094 glLoadMatrixf(rv3d->winmat); 00095 glMatrixMode(GL_MODELVIEW); 00096 glLoadMatrixf(rv3d->viewmat); 00097 } 00098 } 00099 00100 float *give_cursor(Scene *scene, View3D *v3d) 00101 { 00102 if(v3d && v3d->localvd) return v3d->cursor; 00103 else return scene->cursor; 00104 } 00105 00106 00107 /* ****************** smooth view operator ****************** */ 00108 /* This operator is one of the 'timer refresh' ones like animation playback */ 00109 00110 struct SmoothViewStore { 00111 float orig_dist, new_dist; 00112 float orig_lens, new_lens; 00113 float orig_quat[4], new_quat[4]; 00114 float orig_ofs[3], new_ofs[3]; 00115 00116 int to_camera, orig_view; 00117 00118 double time_allowed; 00119 }; 00120 00121 /* will start timer if appropriate */ 00122 /* the arguments are the desired situation */ 00123 void smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens) 00124 { 00125 wmWindowManager *wm= CTX_wm_manager(C); 00126 wmWindow *win= CTX_wm_window(C); 00127 ScrArea *sa= CTX_wm_area(C); 00128 00129 RegionView3D *rv3d= ar->regiondata; 00130 struct SmoothViewStore sms= {0}; 00131 short ok= FALSE; 00132 00133 /* initialize sms */ 00134 copy_v3_v3(sms.new_ofs, rv3d->ofs); 00135 copy_qt_qt(sms.new_quat, rv3d->viewquat); 00136 sms.new_dist= rv3d->dist; 00137 sms.new_lens= v3d->lens; 00138 sms.to_camera= 0; 00139 00140 /* note on camera locking, this is a little confusing but works ok. 00141 * we may be changing the view 'as if' there is no active camera, but infact 00142 * there is an active camera which is locked to the view. 00143 * 00144 * In the case where smooth view is moving _to_ a camera we dont want that 00145 * camera to be moved or changed, so only when the camera is not being set should 00146 * we allow camera option locking to initialize the view settings from the camera. 00147 */ 00148 if(camera == NULL && oldcamera == NULL) { 00149 ED_view3d_camera_lock_init(v3d, rv3d); 00150 } 00151 00152 /* store the options we want to end with */ 00153 if(ofs) copy_v3_v3(sms.new_ofs, ofs); 00154 if(quat) copy_qt_qt(sms.new_quat, quat); 00155 if(dist) sms.new_dist= *dist; 00156 if(lens) sms.new_lens= *lens; 00157 00158 if (camera) { 00159 ED_view3d_from_object(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens); 00160 sms.to_camera= 1; /* restore view3d values in end */ 00161 } 00162 00163 if (C && U.smooth_viewtx) { 00164 int changed = 0; /* zero means no difference */ 00165 00166 if (oldcamera != camera) 00167 changed = 1; 00168 else if (sms.new_dist != rv3d->dist) 00169 changed = 1; 00170 else if (sms.new_lens != v3d->lens) 00171 changed = 1; 00172 else if (!equals_v3v3(sms.new_ofs, rv3d->ofs)) 00173 changed = 1; 00174 else if (!equals_v4v4(sms.new_quat, rv3d->viewquat)) 00175 changed = 1; 00176 00177 /* The new view is different from the old one 00178 * so animate the view */ 00179 if (changed) { 00180 00181 /* original values */ 00182 if (oldcamera) { 00183 sms.orig_dist= rv3d->dist; // below function does weird stuff with it... 00184 ED_view3d_from_object(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens); 00185 } 00186 else { 00187 copy_v3_v3(sms.orig_ofs, rv3d->ofs); 00188 copy_qt_qt(sms.orig_quat, rv3d->viewquat); 00189 sms.orig_dist= rv3d->dist; 00190 sms.orig_lens= v3d->lens; 00191 } 00192 /* grid draw as floor */ 00193 if((rv3d->viewlock & RV3D_LOCKED)==0) { 00194 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */ 00195 sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view; 00196 rv3d->view= RV3D_VIEW_USER; 00197 } 00198 00199 sms.time_allowed= (double)U.smooth_viewtx / 1000.0; 00200 00201 /* if this is view rotation only 00202 * we can decrease the time allowed by 00203 * the angle between quats 00204 * this means small rotations wont lag */ 00205 if (quat && !ofs && !dist) { 00206 float vec1[3]={0,0,1}, vec2[3]= {0,0,1}; 00207 float q1[4], q2[4]; 00208 00209 invert_qt_qt(q1, sms.new_quat); 00210 invert_qt_qt(q2, sms.orig_quat); 00211 00212 mul_qt_v3(q1, vec1); 00213 mul_qt_v3(q2, vec2); 00214 00215 /* scale the time allowed by the rotation */ 00216 sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */ 00217 } 00218 00219 /* ensure it shows correct */ 00220 if(sms.to_camera) rv3d->persp= RV3D_PERSP; 00221 00222 rv3d->rflag |= RV3D_NAVIGATING; 00223 00224 /* keep track of running timer! */ 00225 if(rv3d->sms==NULL) 00226 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d"); 00227 *rv3d->sms= sms; 00228 if(rv3d->smooth_timer) 00229 WM_event_remove_timer(wm, win, rv3d->smooth_timer); 00230 /* TIMER1 is hardcoded in keymap */ 00231 rv3d->smooth_timer= WM_event_add_timer(wm, win, TIMER1, 1.0/100.0); /* max 30 frs/sec */ 00232 00233 ok= TRUE; 00234 } 00235 } 00236 00237 /* if we get here nothing happens */ 00238 if(ok == FALSE) { 00239 if(sms.to_camera==0) { 00240 copy_v3_v3(rv3d->ofs, sms.new_ofs); 00241 copy_qt_qt(rv3d->viewquat, sms.new_quat); 00242 rv3d->dist = sms.new_dist; 00243 v3d->lens = sms.new_lens; 00244 } 00245 00246 if(rv3d->viewlock & RV3D_BOXVIEW) 00247 view3d_boxview_copy(sa, ar); 00248 00249 ED_region_tag_redraw(ar); 00250 } 00251 } 00252 00253 /* only meant for timer usage */ 00254 static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) 00255 { 00256 View3D *v3d = CTX_wm_view3d(C); 00257 RegionView3D *rv3d= CTX_wm_region_view3d(C); 00258 struct SmoothViewStore *sms= rv3d->sms; 00259 float step, step_inv; 00260 00261 /* escape if not our timer */ 00262 if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata) 00263 return OPERATOR_PASS_THROUGH; 00264 00265 if(sms->time_allowed != 0.0) 00266 step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed); 00267 else 00268 step = 1.0f; 00269 00270 /* end timer */ 00271 if(step >= 1.0f) { 00272 00273 /* if we went to camera, store the original */ 00274 if(sms->to_camera) { 00275 rv3d->persp= RV3D_CAMOB; 00276 copy_v3_v3(rv3d->ofs, sms->orig_ofs); 00277 copy_qt_qt(rv3d->viewquat, sms->orig_quat); 00278 rv3d->dist = sms->orig_dist; 00279 v3d->lens = sms->orig_lens; 00280 } 00281 else { 00282 copy_v3_v3(rv3d->ofs, sms->new_ofs); 00283 copy_qt_qt(rv3d->viewquat, sms->new_quat); 00284 rv3d->dist = sms->new_dist; 00285 v3d->lens = sms->new_lens; 00286 00287 ED_view3d_camera_lock_sync(v3d, rv3d); 00288 } 00289 00290 if((rv3d->viewlock & RV3D_LOCKED)==0) { 00291 rv3d->view= sms->orig_view; 00292 } 00293 00294 MEM_freeN(rv3d->sms); 00295 rv3d->sms= NULL; 00296 00297 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer); 00298 rv3d->smooth_timer= NULL; 00299 rv3d->rflag &= ~RV3D_NAVIGATING; 00300 } 00301 else { 00302 int i; 00303 00304 /* ease in/out */ 00305 if (step < 0.5f) step = (float)pow(step*2.0f, 2.0)/2.0f; 00306 else step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f); 00307 00308 step_inv = 1.0f-step; 00309 00310 for (i=0; i<3; i++) 00311 rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv; 00312 00313 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step); 00314 00315 rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv; 00316 v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv; 00317 00318 ED_view3d_camera_lock_sync(v3d, rv3d); 00319 } 00320 00321 if(rv3d->viewlock & RV3D_BOXVIEW) 00322 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C)); 00323 00324 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d); 00325 00326 return OPERATOR_FINISHED; 00327 } 00328 00329 void VIEW3D_OT_smoothview(wmOperatorType *ot) 00330 { 00331 00332 /* identifiers */ 00333 ot->name= "Smooth View"; 00334 ot->idname= "VIEW3D_OT_smoothview"; 00335 ot->description="The time to animate the change of view (in milliseconds)"; 00336 00337 /* api callbacks */ 00338 ot->invoke= view3d_smoothview_invoke; 00339 00340 ot->poll= ED_operator_view3d_active; 00341 } 00342 00343 /* ****************** change view operators ****************** */ 00344 00345 static int view3d_camera_to_view_exec(bContext *C, wmOperator *UNUSED(op)) 00346 { 00347 View3D *v3d = CTX_wm_view3d(C); 00348 RegionView3D *rv3d= CTX_wm_region_view3d(C); 00349 ObjectTfmProtectedChannels obtfm; 00350 00351 copy_qt_qt(rv3d->lviewquat, rv3d->viewquat); 00352 rv3d->lview= rv3d->view; 00353 if(rv3d->persp != RV3D_CAMOB) { 00354 rv3d->lpersp= rv3d->persp; 00355 } 00356 00357 object_tfm_protected_backup(v3d->camera, &obtfm); 00358 00359 ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); 00360 00361 object_tfm_protected_restore(v3d->camera, &obtfm, v3d->camera->protectflag); 00362 00363 DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); 00364 rv3d->persp = RV3D_CAMOB; 00365 00366 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, v3d->camera); 00367 00368 return OPERATOR_FINISHED; 00369 00370 } 00371 00372 static int view3d_camera_to_view_poll(bContext *C) 00373 { 00374 View3D *v3d= CTX_wm_view3d(C); 00375 if(v3d && v3d->camera && v3d->camera->id.lib==NULL) { 00376 RegionView3D *rv3d= CTX_wm_region_view3d(C); 00377 if(rv3d && !rv3d->viewlock) { 00378 return 1; 00379 } 00380 } 00381 00382 return 0; 00383 } 00384 00385 void VIEW3D_OT_camera_to_view(wmOperatorType *ot) 00386 { 00387 /* identifiers */ 00388 ot->name= "Align Camera To View"; 00389 ot->description= "Set camera view to active view"; 00390 ot->idname= "VIEW3D_OT_camera_to_view"; 00391 00392 /* api callbacks */ 00393 ot->exec= view3d_camera_to_view_exec; 00394 ot->poll= view3d_camera_to_view_poll; 00395 00396 /* flags */ 00397 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00398 } 00399 00400 /* unlike VIEW3D_OT_view_selected this is for framing a render and not 00401 * meant to take into account vertex/bone selection for eg. */ 00402 static int view3d_camera_to_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) 00403 { 00404 Scene *scene= CTX_data_scene(C); 00405 View3D *v3d = CTX_wm_view3d(C); 00406 Object *camera_ob= v3d->camera; 00407 00408 float r_co[3]; /* the new location to apply */ 00409 00410 /* this function does all the important stuff */ 00411 if (camera_view_frame_fit_to_scene(scene, v3d, camera_ob, r_co)) { 00412 00413 ObjectTfmProtectedChannels obtfm; 00414 float obmat_new[4][4]; 00415 00416 copy_m4_m4(obmat_new, camera_ob->obmat); 00417 copy_v3_v3(obmat_new[3], r_co); 00418 00419 /* only touch location */ 00420 object_tfm_protected_backup(camera_ob, &obtfm); 00421 object_apply_mat4(camera_ob, obmat_new, TRUE, TRUE); 00422 object_tfm_protected_restore(camera_ob, &obtfm, OB_LOCK_SCALE | OB_LOCK_ROT4D); 00423 00424 /* notifiers */ 00425 DAG_id_tag_update(&camera_ob->id, OB_RECALC_OB); 00426 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, camera_ob); 00427 return OPERATOR_FINISHED; 00428 } 00429 else { 00430 return OPERATOR_CANCELLED; 00431 } 00432 } 00433 00434 static int view3d_camera_to_view_selected_poll(bContext *C) 00435 { 00436 View3D *v3d= CTX_wm_view3d(C); 00437 if(v3d && v3d->camera && v3d->camera->id.lib==NULL) { 00438 RegionView3D *rv3d= CTX_wm_region_view3d(C); 00439 if(rv3d) { 00440 if (rv3d->is_persp == FALSE) { 00441 CTX_wm_operator_poll_msg_set(C, "Only valid for a perspective camera view"); 00442 } 00443 else if (!rv3d->viewlock) { 00444 return 1; 00445 } 00446 } 00447 } 00448 00449 return 0; 00450 } 00451 00452 void VIEW3D_OT_camera_to_view_selected(wmOperatorType *ot) 00453 { 00454 /* identifiers */ 00455 ot->name= "Camera Fit Frame to Selected"; 00456 ot->description= "Move the camera so selected objects are framed"; 00457 ot->idname= "VIEW3D_OT_camera_to_view_selected"; 00458 00459 /* api callbacks */ 00460 ot->exec= view3d_camera_to_view_selected_exec; 00461 ot->poll= view3d_camera_to_view_selected_poll; 00462 00463 /* flags */ 00464 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00465 } 00466 00467 00468 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op)) 00469 { 00470 View3D *v3d; 00471 ARegion *ar; 00472 RegionView3D *rv3d; 00473 00474 Scene *scene= CTX_data_scene(C); 00475 Object *ob = CTX_data_active_object(C); 00476 00477 /* no NULL check is needed, poll checks */ 00478 ED_view3d_context_user_region(C, &v3d, &ar); 00479 rv3d = ar->regiondata; 00480 00481 if(ob) { 00482 Object *camera_old= (rv3d->persp == RV3D_CAMOB) ? V3D_CAMERA_SCENE(scene, v3d) : NULL; 00483 rv3d->persp= RV3D_CAMOB; 00484 v3d->camera= ob; 00485 if(v3d->scenelock) 00486 scene->camera= ob; 00487 00488 if(camera_old != ob) /* unlikely but looks like a glitch when set to the same */ 00489 smooth_view(C, v3d, ar, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens); 00490 00491 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C)); 00492 } 00493 00494 return OPERATOR_FINISHED; 00495 } 00496 00497 int ED_operator_rv3d_user_region_poll(bContext *C) 00498 { 00499 View3D *v3d_dummy; 00500 ARegion *ar_dummy; 00501 00502 return ED_view3d_context_user_region(C, &v3d_dummy, &ar_dummy); 00503 } 00504 00505 void VIEW3D_OT_object_as_camera(wmOperatorType *ot) 00506 { 00507 00508 /* identifiers */ 00509 ot->name= "Set Active Object as Camera"; 00510 ot->description= "Set the active object as the active camera for this view or scene"; 00511 ot->idname= "VIEW3D_OT_object_as_camera"; 00512 00513 /* api callbacks */ 00514 ot->exec= view3d_setobjectascamera_exec; 00515 ot->poll= ED_operator_rv3d_user_region_poll; 00516 00517 /* flags */ 00518 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00519 } 00520 00521 /* ********************************** */ 00522 00523 void ED_view3d_calc_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, const rcti *rect) 00524 { 00525 float modelview[4][4]; 00526 double xs, ys, p[3]; 00527 int val, flip_sign, a; 00528 00529 /* near zero floating point values can give issues with gluUnProject 00530 in side view on some implementations */ 00531 if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0; 00532 if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0; 00533 00534 /* Set up viewport so that gluUnProject will give correct values */ 00535 mats->viewport[0] = 0; 00536 mats->viewport[1] = 0; 00537 00538 /* four clipping planes and bounding volume */ 00539 /* first do the bounding volume */ 00540 for(val=0; val<4; val++) { 00541 xs= (val==0||val==3)?rect->xmin:rect->xmax; 00542 ys= (val==0||val==1)?rect->ymin:rect->ymax; 00543 00544 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]); 00545 VECCOPY(bb->vec[val], p); 00546 00547 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]); 00548 VECCOPY(bb->vec[4+val], p); 00549 } 00550 00551 /* verify if we have negative scale. doing the transform before cross 00552 product flips the sign of the vector compared to doing cross product 00553 before transform then, so we correct for that. */ 00554 for(a=0; a<16; a++) 00555 ((float*)modelview)[a] = mats->modelview[a]; 00556 flip_sign = is_negative_m4(modelview); 00557 00558 /* then plane equations */ 00559 for(val=0; val<4; val++) { 00560 00561 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]); 00562 00563 if(flip_sign) 00564 negate_v3(planes[val]); 00565 00566 planes[val][3]= - planes[val][0]*bb->vec[val][0] 00567 - planes[val][1]*bb->vec[val][1] 00568 - planes[val][2]*bb->vec[val][2]; 00569 } 00570 } 00571 00572 /* create intersection coordinates in view Z direction at mouse coordinates */ 00573 void ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3]) 00574 { 00575 RegionView3D *rv3d= ar->regiondata; 00576 00577 if(rv3d->is_persp) { 00578 float vec[3]; 00579 ED_view3d_win_to_vector(ar, mval, vec); 00580 00581 copy_v3_v3(ray_start, rv3d->viewinv[3]); 00582 madd_v3_v3v3fl(ray_start, rv3d->viewinv[3], vec, v3d->near); 00583 madd_v3_v3v3fl(ray_end, rv3d->viewinv[3], vec, v3d->far); 00584 } 00585 else { 00586 float vec[4]; 00587 vec[0] = 2.0f * mval[0] / ar->winx - 1; 00588 vec[1] = 2.0f * mval[1] / ar->winy - 1; 00589 vec[2] = 0.0f; 00590 vec[3] = 1.0f; 00591 00592 mul_m4_v4(rv3d->persinv, vec); 00593 00594 madd_v3_v3v3fl(ray_start, vec, rv3d->viewinv[2], 1000.0f); 00595 madd_v3_v3v3fl(ray_end, vec, rv3d->viewinv[2], -1000.0f); 00596 } 00597 00598 /* clipping */ 00599 if(rv3d->rflag & RV3D_CLIPPING) { 00600 int a; 00601 for(a=0; a<4; a++) { 00602 clip_line_plane(ray_start, ray_end, rv3d->clip[a]); 00603 } 00604 } 00605 } 00606 00607 /* create intersection ray in view Z direction at mouse coordinates */ 00608 void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3]) 00609 { 00610 float ray_end[3]; 00611 00612 ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end); 00613 sub_v3_v3v3(ray_normal, ray_end, ray_start); 00614 normalize_v3(ray_normal); 00615 } 00616 00617 void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3]) 00618 { 00619 if (rv3d->is_persp) { 00620 float p1[4], p2[4]; 00621 00622 copy_v3_v3(p1, coord); 00623 p1[3] = 1.0f; 00624 copy_v3_v3(p2, p1); 00625 p2[3] = 1.0f; 00626 mul_m4_v4(rv3d->viewmat, p2); 00627 00628 mul_v3_fl(p2, 2.0f); 00629 00630 mul_m4_v4(rv3d->viewinv, p2); 00631 00632 sub_v3_v3v3(vec, p1, p2); 00633 } 00634 else { 00635 copy_v3_v3(vec, rv3d->viewinv[2]); 00636 } 00637 normalize_v3(vec); 00638 } 00639 00640 int initgrabz(RegionView3D *rv3d, float x, float y, float z) 00641 { 00642 int flip= FALSE; 00643 if(rv3d==NULL) return flip; 00644 rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3]; 00645 if (rv3d->zfac < 0.0f) 00646 flip= TRUE; 00647 /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 00648 * (accounting for near zero values) 00649 * */ 00650 if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f; 00651 00652 /* Negative zfac means x, y, z was behind the camera (in perspective). 00653 * This gives flipped directions, so revert back to ok default case. 00654 */ 00655 // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok 00656 // -- Aligorith, 2009Aug31 00657 //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f; 00658 if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac; 00659 00660 return flip; 00661 } 00662 00663 void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]) 00664 { 00665 RegionView3D *rv3d= ar->regiondata; 00666 00667 float line_sta[3]; 00668 float line_end[3]; 00669 00670 if(rv3d->is_persp) { 00671 float mousevec[3]; 00672 copy_v3_v3(line_sta, rv3d->viewinv[3]); 00673 ED_view3d_win_to_vector(ar, mval, mousevec); 00674 add_v3_v3v3(line_end, line_sta, mousevec); 00675 00676 if(isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], TRUE) == 0) { 00677 /* highly unlikely to ever happen, mouse vec paralelle with view plane */ 00678 zero_v3(out); 00679 } 00680 } 00681 else { 00682 const float dx= (2.0f * mval[0] / (float)ar->winx) - 1.0f; 00683 const float dy= (2.0f * mval[1] / (float)ar->winy) - 1.0f; 00684 line_sta[0]= (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0]; 00685 line_sta[1]= (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1]; 00686 line_sta[2]= (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2]; 00687 00688 add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]); 00689 closest_to_line_v3(out, depth_pt, line_sta, line_end); 00690 } 00691 } 00692 00693 /* always call initgrabz */ 00694 /* only to detect delta motion */ 00695 void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3]) 00696 { 00697 RegionView3D *rv3d= ar->regiondata; 00698 float dx, dy; 00699 00700 dx= 2.0f*mval[0]*rv3d->zfac/ar->winx; 00701 dy= 2.0f*mval[1]*rv3d->zfac/ar->winy; 00702 00703 out[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy); 00704 out[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy); 00705 out[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy); 00706 } 00707 00708 /* doesn't rely on initgrabz */ 00709 /* for perspective view, get the vector direction to 00710 * the mouse cursor as a normalized vector */ 00711 void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3]) 00712 { 00713 RegionView3D *rv3d= ar->regiondata; 00714 00715 if(rv3d->is_persp) { 00716 out[0]= 2.0f * (mval[0] / ar->winx) - 1.0f; 00717 out[1]= 2.0f * (mval[1] / ar->winy) - 1.0f; 00718 out[2]= -0.5f; 00719 mul_project_m4_v3(rv3d->persinv, out); 00720 sub_v3_v3(out, rv3d->viewinv[3]); 00721 } 00722 else { 00723 copy_v3_v3(out, rv3d->viewinv[2]); 00724 } 00725 normalize_v3(out); 00726 } 00727 00728 float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y) 00729 { 00730 ViewDepths *vd = vc->rv3d->depths; 00731 00732 x -= vc->ar->winrct.xmin; 00733 y -= vc->ar->winrct.ymin; 00734 00735 if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h) 00736 return vd->depths[y * vd->w + x]; 00737 else 00738 return 1; 00739 } 00740 00741 void ED_view3d_depth_tag_update(RegionView3D *rv3d) 00742 { 00743 if(rv3d->depths) 00744 rv3d->depths->damaged= 1; 00745 } 00746 00747 void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4]) 00748 { 00749 float vmat[4][4]; 00750 00751 mult_m4_m4m4(vmat, rv3d->viewmat, ob->obmat); 00752 mult_m4_m4m4(pmat, rv3d->winmat, vmat); 00753 } 00754 00755 #if 0 00756 /* Uses window coordinates (x,y) and depth component z to find a point in 00757 modelspace */ 00758 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z) 00759 { 00760 double ux, uy, uz; 00761 00762 gluUnProject(x,y,z, mats->modelview, mats->projection, 00763 (GLint *)mats->viewport, &ux, &uy, &uz ); 00764 out[0] = ux; 00765 out[1] = uy; 00766 out[2] = uz; 00767 } 00768 #endif 00769 00770 /* use view3d_get_object_project_mat to get projecting mat */ 00771 void ED_view3d_project_float(const ARegion *ar, const float vec[3], float adr[2], float mat[4][4]) 00772 { 00773 float vec4[4]; 00774 00775 adr[0]= IS_CLIPPED; 00776 copy_v3_v3(vec4, vec); 00777 vec4[3]= 1.0; 00778 00779 mul_m4_v4(mat, vec4); 00780 00781 if( vec4[3]>FLT_EPSILON ) { 00782 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3]; 00783 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3]; 00784 } else { 00785 adr[0] = adr[1] = 0.0f; 00786 } 00787 } 00788 00789 /* use view3d_get_object_project_mat to get projecting mat */ 00790 void ED_view3d_project_float_v3(ARegion *ar, float *vec, float *adr, float mat[4][4]) 00791 { 00792 float vec4[4]; 00793 00794 copy_v3_v3(vec4, vec); 00795 vec4[3]= 1.0; 00796 adr[0]= IS_CLIPPED; 00797 00798 mul_m4_v4(mat, vec4); 00799 00800 if( vec4[3]>FLT_EPSILON ) { 00801 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3]; 00802 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3]; 00803 adr[2] = vec4[2]/vec4[3]; 00804 } else { 00805 adr[0] = adr[1] = adr[2] = 0.0f; 00806 } 00807 } 00808 00809 int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb) 00810 { 00811 /* return 1: draw */ 00812 00813 float mat[4][4]; 00814 float vec[4], min, max; 00815 int a, flag= -1, fl; 00816 00817 if(bb==NULL) return 1; 00818 if(bb->flag & OB_BB_DISABLED) return 1; 00819 00820 mult_m4_m4m4(mat, rv3d->persmat, obmat); 00821 00822 for(a=0; a<8; a++) { 00823 copy_v3_v3(vec, bb->vec[a]); 00824 vec[3]= 1.0; 00825 mul_m4_v4(mat, vec); 00826 max= vec[3]; 00827 min= -vec[3]; 00828 00829 fl= 0; 00830 if(vec[0] < min) fl+= 1; 00831 if(vec[0] > max) fl+= 2; 00832 if(vec[1] < min) fl+= 4; 00833 if(vec[1] > max) fl+= 8; 00834 if(vec[2] < min) fl+= 16; 00835 if(vec[2] > max) fl+= 32; 00836 00837 flag &= fl; 00838 if(flag==0) return 1; 00839 } 00840 00841 return 0; 00842 } 00843 00844 void project_short(ARegion *ar, const float vec[3], short adr[2]) /* clips */ 00845 { 00846 RegionView3D *rv3d= ar->regiondata; 00847 float fx, fy, vec4[4]; 00848 00849 adr[0]= IS_CLIPPED; 00850 00851 if(rv3d->rflag & RV3D_CLIPPING) { 00852 if(ED_view3d_test_clipping(rv3d, vec, 0)) 00853 return; 00854 } 00855 00856 copy_v3_v3(vec4, vec); 00857 vec4[3]= 1.0; 00858 mul_m4_v4(rv3d->persmat, vec4); 00859 00860 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ 00861 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); 00862 00863 if( fx>0 && fx<ar->winx) { 00864 00865 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); 00866 00867 if(fy > 0.0f && fy < (float)ar->winy) { 00868 adr[0]= (short)floor(fx); 00869 adr[1]= (short)floor(fy); 00870 } 00871 } 00872 } 00873 } 00874 00875 void project_int(ARegion *ar, const float vec[3], int adr[2]) 00876 { 00877 RegionView3D *rv3d= ar->regiondata; 00878 float fx, fy, vec4[4]; 00879 00880 copy_v3_v3(vec4, vec); 00881 vec4[3]= 1.0; 00882 adr[0]= (int)2140000000.0f; 00883 00884 mul_m4_v4(rv3d->persmat, vec4); 00885 00886 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ 00887 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); 00888 00889 if( fx>-2140000000.0f && fx<2140000000.0f) { 00890 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); 00891 00892 if(fy>-2140000000.0f && fy<2140000000.0f) { 00893 adr[0]= (int)floor(fx); 00894 adr[1]= (int)floor(fy); 00895 } 00896 } 00897 } 00898 } 00899 00900 void project_int_noclip(ARegion *ar, const float vec[3], int adr[2]) 00901 { 00902 RegionView3D *rv3d= ar->regiondata; 00903 float fx, fy, vec4[4]; 00904 00905 copy_v3_v3(vec4, vec); 00906 vec4[3]= 1.0; 00907 00908 mul_m4_v4(rv3d->persmat, vec4); 00909 00910 if( fabs(vec4[3]) > BL_NEAR_CLIP ) { 00911 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]); 00912 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]); 00913 00914 adr[0] = (int)floor(fx); 00915 adr[1] = (int)floor(fy); 00916 } 00917 else { 00918 adr[0] = ar->winx / 2; 00919 adr[1] = ar->winy / 2; 00920 } 00921 } 00922 00923 void project_short_noclip(ARegion *ar, const float vec[3], short adr[2]) 00924 { 00925 RegionView3D *rv3d= ar->regiondata; 00926 float fx, fy, vec4[4]; 00927 00928 copy_v3_v3(vec4, vec); 00929 vec4[3]= 1.0; 00930 adr[0]= IS_CLIPPED; 00931 00932 mul_m4_v4(rv3d->persmat, vec4); 00933 00934 if( vec4[3] > (float)BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ 00935 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]); 00936 00937 if( fx>-32700 && fx<32700) { 00938 00939 fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]); 00940 00941 if(fy > -32700.0f && fy < 32700.0f) { 00942 adr[0]= (short)floor(fx); 00943 adr[1]= (short)floor(fy); 00944 } 00945 } 00946 } 00947 } 00948 00949 void project_float(ARegion *ar, const float vec[3], float adr[2]) 00950 { 00951 RegionView3D *rv3d= ar->regiondata; 00952 float vec4[4]; 00953 00954 copy_v3_v3(vec4, vec); 00955 vec4[3]= 1.0; 00956 adr[0]= IS_CLIPPED; 00957 00958 mul_m4_v4(rv3d->persmat, vec4); 00959 00960 if(vec4[3] > (float)BL_NEAR_CLIP) { 00961 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3]; 00962 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3]; 00963 } 00964 } 00965 00966 void project_float_noclip(ARegion *ar, const float vec[3], float adr[2]) 00967 { 00968 RegionView3D *rv3d= ar->regiondata; 00969 float vec4[4]; 00970 00971 copy_v3_v3(vec4, vec); 00972 vec4[3]= 1.0; 00973 00974 mul_m4_v4(rv3d->persmat, vec4); 00975 00976 if( fabs(vec4[3]) > BL_NEAR_CLIP ) { 00977 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3]; 00978 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3]; 00979 } 00980 else { 00981 adr[0] = ar->winx / 2.0f; 00982 adr[1] = ar->winy / 2.0f; 00983 } 00984 } 00985 00986 /* copies logic of get_view3d_viewplane(), keep in sync */ 00987 int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) 00988 { 00989 CameraParams params; 00990 00991 camera_params_init(¶ms); 00992 camera_params_from_view3d(¶ms, v3d, rv3d); 00993 00994 if(clipsta) *clipsta= params.clipsta; 00995 if(clipend) *clipend= params.clipend; 00996 00997 return params.is_ortho; 00998 } 00999 01000 /* also exposed in previewrender.c */ 01001 int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winx, int winy, rctf *viewplane, float *clipsta, float *clipend) 01002 { 01003 CameraParams params; 01004 01005 camera_params_init(¶ms); 01006 camera_params_from_view3d(¶ms, v3d, rv3d); 01007 camera_params_compute_viewplane(¶ms, winx, winy, 1.0f, 1.0f); 01008 01009 if(viewplane) *viewplane= params.viewplane; 01010 if(clipsta) *clipsta= params.clipsta; 01011 if(clipend) *clipend= params.clipend; 01012 01013 return params.is_ortho; 01014 } 01015 01016 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect) /* rect: for picking */ 01017 { 01018 RegionView3D *rv3d= ar->regiondata; 01019 rctf viewplane; 01020 float clipsta, clipend, x1, y1, x2, y2; 01021 int orth; 01022 01023 orth= ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend); 01024 rv3d->is_persp= !orth; 01025 01026 // printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend); 01027 x1= viewplane.xmin; 01028 y1= viewplane.ymin; 01029 x2= viewplane.xmax; 01030 y2= viewplane.ymax; 01031 01032 if(rect) { /* picking */ 01033 rect->xmin/= (float)ar->winx; 01034 rect->xmin= x1+rect->xmin*(x2-x1); 01035 rect->ymin/= (float)ar->winy; 01036 rect->ymin= y1+rect->ymin*(y2-y1); 01037 rect->xmax/= (float)ar->winx; 01038 rect->xmax= x1+rect->xmax*(x2-x1); 01039 rect->ymax/= (float)ar->winy; 01040 rect->ymax= y1+rect->ymax*(y2-y1); 01041 01042 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend); 01043 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend); 01044 01045 } 01046 else { 01047 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend); 01048 else wmFrustum(x1, x2, y1, y2, clipsta, clipend); 01049 } 01050 01051 /* update matrix in 3d view region */ 01052 glGetFloatv(GL_PROJECTION_MATRIX, (float*)rv3d->winmat); 01053 } 01054 01055 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth) 01056 { 01057 float bmat[4][4]; 01058 float tmat[3][3]; 01059 01060 rv3d->view= RV3D_VIEW_USER; /* dont show the grid */ 01061 01062 copy_m4_m4(bmat, ob->obmat); 01063 normalize_m4(bmat); 01064 invert_m4_m4(rv3d->viewmat, bmat); 01065 01066 /* view quat calculation, needed for add object */ 01067 copy_m3_m4(tmat, rv3d->viewmat); 01068 if (smooth) { 01069 float new_quat[4]; 01070 if (rv3d->persp==RV3D_CAMOB && v3d->camera) { 01071 /* were from a camera view */ 01072 01073 float orig_ofs[3]; 01074 float orig_dist= rv3d->dist; 01075 float orig_lens= v3d->lens; 01076 copy_v3_v3(orig_ofs, rv3d->ofs); 01077 01078 /* Switch from camera view */ 01079 mat3_to_quat( new_quat,tmat); 01080 01081 rv3d->persp=RV3D_PERSP; 01082 rv3d->dist= 0.0; 01083 01084 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens); 01085 smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX 01086 01087 rv3d->persp=RV3D_CAMOB; /* just to be polite, not needed */ 01088 01089 } else { 01090 mat3_to_quat( new_quat,tmat); 01091 smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX 01092 } 01093 } else { 01094 mat3_to_quat( rv3d->viewquat,tmat); 01095 } 01096 } 01097 01098 #define QUATSET(a, b, c, d, e) a[0]=b; a[1]=c; a[2]=d; a[3]=e; 01099 01100 int ED_view3d_lock(RegionView3D *rv3d) 01101 { 01102 switch(rv3d->view) { 01103 case RV3D_VIEW_BOTTOM : 01104 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0); 01105 break; 01106 01107 case RV3D_VIEW_BACK: 01108 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0)); 01109 break; 01110 01111 case RV3D_VIEW_LEFT: 01112 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5); 01113 break; 01114 01115 case RV3D_VIEW_TOP: 01116 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0); 01117 break; 01118 01119 case RV3D_VIEW_FRONT: 01120 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0); 01121 break; 01122 01123 case RV3D_VIEW_RIGHT: 01124 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5); 01125 break; 01126 default: 01127 return FALSE; 01128 } 01129 01130 return TRUE; 01131 } 01132 01133 /* dont set windows active in here, is used by renderwin too */ 01134 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d) 01135 { 01136 if(rv3d->persp==RV3D_CAMOB) { /* obs/camera */ 01137 if(v3d->camera) { 01138 where_is_object(scene, v3d->camera); 01139 obmat_to_viewmat(v3d, rv3d, v3d->camera, 0); 01140 } 01141 else { 01142 quat_to_mat4( rv3d->viewmat,rv3d->viewquat); 01143 rv3d->viewmat[3][2]-= rv3d->dist; 01144 } 01145 } 01146 else { 01147 /* should be moved to better initialize later on XXX */ 01148 if(rv3d->viewlock) 01149 ED_view3d_lock(rv3d); 01150 01151 quat_to_mat4( rv3d->viewmat,rv3d->viewquat); 01152 if(rv3d->persp==RV3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist; 01153 if(v3d->ob_centre) { 01154 Object *ob= v3d->ob_centre; 01155 float vec[3]; 01156 01157 copy_v3_v3(vec, ob->obmat[3]); 01158 if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) { 01159 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone); 01160 if(pchan) { 01161 copy_v3_v3(vec, pchan->pose_mat[3]); 01162 mul_m4_v3(ob->obmat, vec); 01163 } 01164 } 01165 translate_m4( rv3d->viewmat,-vec[0], -vec[1], -vec[2]); 01166 } 01167 else if (v3d->ob_centre_cursor) { 01168 float vec[3]; 01169 copy_v3_v3(vec, give_cursor(scene, v3d)); 01170 translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]); 01171 } 01172 else translate_m4( rv3d->viewmat,rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]); 01173 } 01174 } 01175 01176 /* IGLuint-> GLuint*/ 01177 /* Warning: be sure to account for a negative return value 01178 * This is an error, "Too many objects in select buffer" 01179 * and no action should be taken (can crash blender) if this happens 01180 */ 01181 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input) 01182 { 01183 Scene *scene= vc->scene; 01184 View3D *v3d= vc->v3d; 01185 ARegion *ar= vc->ar; 01186 rctf rect; 01187 short code, hits; 01188 char dt, dtx; 01189 01190 G.f |= G_PICKSEL; 01191 01192 /* case not a border select */ 01193 if(input->xmin==input->xmax) { 01194 rect.xmin= input->xmin-12; // seems to be default value for bones only now 01195 rect.xmax= input->xmin+12; 01196 rect.ymin= input->ymin-12; 01197 rect.ymax= input->ymin+12; 01198 } 01199 else { 01200 rect.xmin= input->xmin; 01201 rect.xmax= input->xmax; 01202 rect.ymin= input->ymin; 01203 rect.ymax= input->ymax; 01204 } 01205 01206 setwinmatrixview3d(ar, v3d, &rect); 01207 mult_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); 01208 01209 if(v3d->drawtype > OB_WIRE) { 01210 v3d->zbuf= TRUE; 01211 glEnable(GL_DEPTH_TEST); 01212 } 01213 01214 if(vc->rv3d->rflag & RV3D_CLIPPING) 01215 view3d_set_clipping(vc->rv3d); 01216 01217 glSelectBuffer( bufsize, (GLuint *)buffer); 01218 glRenderMode(GL_SELECT); 01219 glInitNames(); /* these two calls whatfor? It doesnt work otherwise */ 01220 glPushName(-1); 01221 code= 1; 01222 01223 if(vc->obedit && vc->obedit->type==OB_MBALL) { 01224 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR); 01225 } 01226 else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) { 01227 /* if not drawing sketch, draw bones */ 01228 if(!BDR_drawSketchNames(vc)) { 01229 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR); 01230 } 01231 } 01232 else { 01233 Base *base; 01234 01235 v3d->xray= TRUE; // otherwise it postpones drawing 01236 for(base= scene->base.first; base; base= base->next) { 01237 if(base->lay & v3d->lay) { 01238 01239 if (base->object->restrictflag & OB_RESTRICT_SELECT) 01240 base->selcol= 0; 01241 else { 01242 base->selcol= code; 01243 glLoadName(code); 01244 draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR); 01245 01246 /* we draw group-duplicators for selection too */ 01247 if((base->object->transflag & OB_DUPLI) && base->object->dup_group) { 01248 ListBase *lb; 01249 DupliObject *dob; 01250 Base tbase; 01251 01252 tbase.flag= OB_FROMDUPLI; 01253 lb= object_duplilist(scene, base->object); 01254 01255 for(dob= lb->first; dob; dob= dob->next) { 01256 tbase.object= dob->ob; 01257 copy_m4_m4(dob->ob->obmat, dob->mat); 01258 01259 /* extra service: draw the duplicator in drawtype of parent */ 01260 /* MIN2 for the drawtype to allow bounding box objects in groups for lods */ 01261 dt= tbase.object->dt; tbase.object->dt= MIN2(tbase.object->dt, base->object->dt); 01262 dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx; 01263 01264 draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR); 01265 01266 tbase.object->dt= dt; 01267 tbase.object->dtx= dtx; 01268 01269 copy_m4_m4(dob->ob->obmat, dob->omat); 01270 } 01271 free_object_duplilist(lb); 01272 } 01273 code++; 01274 } 01275 } 01276 } 01277 v3d->xray= FALSE; // restore 01278 } 01279 01280 glPopName(); /* see above (pushname) */ 01281 hits= glRenderMode(GL_RENDER); 01282 01283 G.f &= ~G_PICKSEL; 01284 setwinmatrixview3d(ar, v3d, NULL); 01285 mult_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat); 01286 01287 if(v3d->drawtype > OB_WIRE) { 01288 v3d->zbuf= 0; 01289 glDisable(GL_DEPTH_TEST); 01290 } 01291 // XXX persp(PERSP_WIN); 01292 01293 if(vc->rv3d->rflag & RV3D_CLIPPING) 01294 view3d_clr_clipping(); 01295 01296 if(hits<0) printf("Too many objects in select buffer\n"); // XXX make error message 01297 01298 return hits; 01299 } 01300 01301 /* ********************** local view operator ******************** */ 01302 01303 static unsigned int free_localbit(Main *bmain) 01304 { 01305 unsigned int lay; 01306 ScrArea *sa; 01307 bScreen *sc; 01308 01309 lay= 0; 01310 01311 /* sometimes we loose a localview: when an area is closed */ 01312 /* check all areas: which localviews are in use? */ 01313 for(sc= bmain->screen.first; sc; sc= sc->id.next) { 01314 for(sa= sc->areabase.first; sa; sa= sa->next) { 01315 SpaceLink *sl= sa->spacedata.first; 01316 for(; sl; sl= sl->next) { 01317 if(sl->spacetype==SPACE_VIEW3D) { 01318 View3D *v3d= (View3D*) sl; 01319 lay |= v3d->lay; 01320 } 01321 } 01322 } 01323 } 01324 01325 if( (lay & 0x01000000)==0) return 0x01000000; 01326 if( (lay & 0x02000000)==0) return 0x02000000; 01327 if( (lay & 0x04000000)==0) return 0x04000000; 01328 if( (lay & 0x08000000)==0) return 0x08000000; 01329 if( (lay & 0x10000000)==0) return 0x10000000; 01330 if( (lay & 0x20000000)==0) return 0x20000000; 01331 if( (lay & 0x40000000)==0) return 0x40000000; 01332 if( (lay & 0x80000000)==0) return 0x80000000; 01333 01334 return 0; 01335 } 01336 01337 int ED_view3d_scene_layer_set(int lay, const int *values, int *active) 01338 { 01339 int i, tot= 0; 01340 01341 /* ensure we always have some layer selected */ 01342 for(i=0; i<20; i++) 01343 if(values[i]) 01344 tot++; 01345 01346 if(tot==0) 01347 return lay; 01348 01349 for(i=0; i<20; i++) { 01350 01351 if (active) { 01352 /* if this value has just been switched on, make that layer active */ 01353 if (values[i] && (lay & (1<<i))==0) { 01354 *active = (1<<i); 01355 } 01356 } 01357 01358 if (values[i]) lay |= (1<<i); 01359 else lay &= ~(1<<i); 01360 } 01361 01362 /* ensure always an active layer */ 01363 if (active && (lay & *active)==0) { 01364 for(i=0; i<20; i++) { 01365 if(lay & (1<<i)) { 01366 *active= 1<<i; 01367 break; 01368 } 01369 } 01370 } 01371 01372 return lay; 01373 } 01374 01375 static void initlocalview(Main *bmain, Scene *scene, ScrArea *sa) 01376 { 01377 View3D *v3d= sa->spacedata.first; 01378 Base *base; 01379 float size = 0.0, min[3], max[3], box[3]; 01380 unsigned int locallay; 01381 int ok=0; 01382 01383 if(v3d->localvd) return; 01384 01385 INIT_MINMAX(min, max); 01386 01387 locallay= free_localbit(bmain); 01388 01389 if(locallay==0) { 01390 printf("Sorry, no more than 8 localviews\n"); // XXX error 01391 ok= 0; 01392 } 01393 else { 01394 if(scene->obedit) { 01395 minmax_object(scene->obedit, min, max); 01396 01397 ok= 1; 01398 01399 BASACT->lay |= locallay; 01400 scene->obedit->lay= BASACT->lay; 01401 } 01402 else { 01403 for(base= FIRSTBASE; base; base= base->next) { 01404 if(TESTBASE(v3d, base)) { 01405 minmax_object(base->object, min, max); 01406 base->lay |= locallay; 01407 base->object->lay= base->lay; 01408 ok= 1; 01409 } 01410 } 01411 } 01412 01413 box[0]= (max[0]-min[0]); 01414 box[1]= (max[1]-min[1]); 01415 box[2]= (max[2]-min[2]); 01416 size= MAX3(box[0], box[1], box[2]); 01417 if(size <= 0.01f) size= 0.01f; 01418 } 01419 01420 if(ok) { 01421 ARegion *ar; 01422 01423 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview"); 01424 01425 memcpy(v3d->localvd, v3d, sizeof(View3D)); 01426 01427 for(ar= sa->regionbase.first; ar; ar= ar->next) { 01428 if(ar->regiontype == RGN_TYPE_WINDOW) { 01429 RegionView3D *rv3d= ar->regiondata; 01430 01431 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region"); 01432 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D)); 01433 01434 rv3d->ofs[0]= -(min[0]+max[0])/2.0f; 01435 rv3d->ofs[1]= -(min[1]+max[1])/2.0f; 01436 rv3d->ofs[2]= -(min[2]+max[2])/2.0f; 01437 01438 rv3d->dist= size; 01439 /* perspective should be a bit farther away to look nice */ 01440 if(rv3d->persp==RV3D_ORTHO) 01441 rv3d->dist*= 0.7f; 01442 01443 // correction for window aspect ratio 01444 if(ar->winy>2 && ar->winx>2) { 01445 float asp= (float)ar->winx/(float)ar->winy; 01446 if(asp < 1.0f) asp= 1.0f/asp; 01447 rv3d->dist*= asp; 01448 } 01449 01450 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; 01451 01452 v3d->cursor[0]= -rv3d->ofs[0]; 01453 v3d->cursor[1]= -rv3d->ofs[1]; 01454 v3d->cursor[2]= -rv3d->ofs[2]; 01455 } 01456 } 01457 01458 v3d->lay= locallay; 01459 } 01460 else { 01461 /* clear flags */ 01462 for(base= FIRSTBASE; base; base= base->next) { 01463 if( base->lay & locallay ) { 01464 base->lay-= locallay; 01465 if(base->lay==0) base->lay= v3d->layact; 01466 if(base->object != scene->obedit) base->flag |= SELECT; 01467 base->object->lay= base->lay; 01468 } 01469 } 01470 } 01471 01472 } 01473 01474 static void restore_localviewdata(ScrArea *sa, int free) 01475 { 01476 ARegion *ar; 01477 View3D *v3d= sa->spacedata.first; 01478 01479 if(v3d->localvd==NULL) return; 01480 01481 v3d->near= v3d->localvd->near; 01482 v3d->far= v3d->localvd->far; 01483 v3d->lay= v3d->localvd->lay; 01484 v3d->layact= v3d->localvd->layact; 01485 v3d->drawtype= v3d->localvd->drawtype; 01486 v3d->camera= v3d->localvd->camera; 01487 01488 if(free) { 01489 MEM_freeN(v3d->localvd); 01490 v3d->localvd= NULL; 01491 } 01492 01493 for(ar= sa->regionbase.first; ar; ar= ar->next) { 01494 if(ar->regiontype == RGN_TYPE_WINDOW) { 01495 RegionView3D *rv3d= ar->regiondata; 01496 01497 if(rv3d->localvd) { 01498 rv3d->dist= rv3d->localvd->dist; 01499 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs); 01500 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat); 01501 rv3d->view= rv3d->localvd->view; 01502 rv3d->persp= rv3d->localvd->persp; 01503 rv3d->camzoom= rv3d->localvd->camzoom; 01504 01505 if(free) { 01506 MEM_freeN(rv3d->localvd); 01507 rv3d->localvd= NULL; 01508 } 01509 } 01510 } 01511 } 01512 } 01513 01514 static void endlocalview(Main *bmain, Scene *scene, ScrArea *sa) 01515 { 01516 View3D *v3d= sa->spacedata.first; 01517 struct Base *base; 01518 unsigned int locallay; 01519 01520 if(v3d->localvd) { 01521 01522 locallay= v3d->lay & 0xFF000000; 01523 01524 restore_localviewdata(sa, 1); // 1 = free 01525 01526 /* for when in other window the layers have changed */ 01527 if(v3d->scenelock) v3d->lay= scene->lay; 01528 01529 for(base= FIRSTBASE; base; base= base->next) { 01530 if( base->lay & locallay ) { 01531 base->lay-= locallay; 01532 if(base->lay==0) base->lay= v3d->layact; 01533 if(base->object != scene->obedit) { 01534 base->flag |= SELECT; 01535 base->object->flag |= SELECT; 01536 } 01537 base->object->lay= base->lay; 01538 } 01539 } 01540 01541 DAG_on_visible_update(bmain, FALSE); 01542 } 01543 } 01544 01545 static int localview_exec(bContext *C, wmOperator *UNUSED(unused)) 01546 { 01547 View3D *v3d= CTX_wm_view3d(C); 01548 01549 if(v3d->localvd) 01550 endlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C)); 01551 else 01552 initlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C)); 01553 01554 ED_area_tag_redraw(CTX_wm_area(C)); 01555 01556 return OPERATOR_FINISHED; 01557 } 01558 01559 void VIEW3D_OT_localview(wmOperatorType *ot) 01560 { 01561 01562 /* identifiers */ 01563 ot->name= "Local View"; 01564 ot->description= "Toggle display of selected object(s) separately and centered in view"; 01565 ot->idname= "VIEW3D_OT_localview"; 01566 01567 /* api callbacks */ 01568 ot->exec= localview_exec; 01569 ot->flag= OPTYPE_UNDO; /* localview changes object layer bitflags */ 01570 01571 ot->poll= ED_operator_view3d_active; 01572 } 01573 01574 #ifdef WITH_GAMEENGINE 01575 01576 static ListBase queue_back; 01577 static void SaveState(bContext *C, wmWindow *win) 01578 { 01579 Object *obact = CTX_data_active_object(C); 01580 01581 glPushAttrib(GL_ALL_ATTRIB_BITS); 01582 01583 if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) 01584 GPU_paint_set_mipmap(1); 01585 01586 queue_back= win->queue; 01587 01588 win->queue.first= win->queue.last= NULL; 01589 01590 //XXX waitcursor(1); 01591 } 01592 01593 static void RestoreState(bContext *C, wmWindow *win) 01594 { 01595 Object *obact = CTX_data_active_object(C); 01596 01597 if(obact && obact->mode & OB_MODE_TEXTURE_PAINT) 01598 GPU_paint_set_mipmap(0); 01599 01600 //XXX curarea->win_swap = 0; 01601 //XXX curarea->head_swap=0; 01602 //XXX allqueue(REDRAWVIEW3D, 1); 01603 //XXX allqueue(REDRAWBUTSALL, 0); 01604 //XXX reset_slowparents(); 01605 //XXX waitcursor(0); 01606 //XXX G.qual= 0; 01607 01608 if(win) /* check because closing win can set to NULL */ 01609 win->queue= queue_back; 01610 01611 GPU_state_init(); 01612 GPU_set_tpage(NULL, 0, 0); 01613 01614 glPopAttrib(); 01615 } 01616 01617 /* was space_set_commmandline_options in 2.4x */ 01618 static void game_set_commmandline_options(GameData *gm) 01619 { 01620 SYS_SystemHandle syshandle; 01621 int test; 01622 01623 if ( (syshandle = SYS_GetSystem()) ) { 01624 /* User defined settings */ 01625 test= (U.gameflags & USER_DISABLE_MIPMAP); 01626 GPU_set_mipmap(!test); 01627 SYS_WriteCommandLineInt(syshandle, "nomipmap", test); 01628 01629 /* File specific settings: */ 01630 /* Only test the first one. These two are switched 01631 * simultaneously. */ 01632 test= (gm->flag & GAME_SHOW_FRAMERATE); 01633 SYS_WriteCommandLineInt(syshandle, "show_framerate", test); 01634 SYS_WriteCommandLineInt(syshandle, "show_profile", test); 01635 01636 test = (gm->flag & GAME_SHOW_DEBUG_PROPS); 01637 SYS_WriteCommandLineInt(syshandle, "show_properties", test); 01638 01639 test= (gm->flag & GAME_SHOW_PHYSICS); 01640 SYS_WriteCommandLineInt(syshandle, "show_physics", test); 01641 01642 test= (gm->flag & GAME_ENABLE_ALL_FRAMES); 01643 SYS_WriteCommandLineInt(syshandle, "fixedtime", test); 01644 01645 test= (gm->flag & GAME_ENABLE_ANIMATION_RECORD); 01646 SYS_WriteCommandLineInt(syshandle, "animation_record", test); 01647 01648 test= (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS); 01649 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test); 01650 01651 test= (gm->matmode == GAME_MAT_MULTITEX); 01652 SYS_WriteCommandLineInt(syshandle, "blender_material", test); 01653 test= (gm->matmode == GAME_MAT_GLSL); 01654 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test); 01655 test= (gm->flag & GAME_DISPLAY_LISTS); 01656 SYS_WriteCommandLineInt(syshandle, "displaylists", test); 01657 01658 01659 } 01660 } 01661 01662 #endif // WITH_GAMEENGINE 01663 01664 static int game_engine_poll(bContext *C) 01665 { 01666 /* we need a context and area to launch BGE 01667 it's a temporary solution to avoid crash at load time 01668 if we try to auto run the BGE. Ideally we want the 01669 context to be set as soon as we load the file. */ 01670 01671 if(CTX_wm_window(C)==NULL) return 0; 01672 if(CTX_wm_screen(C)==NULL) return 0; 01673 if(CTX_wm_area(C)==NULL) return 0; 01674 01675 if(CTX_data_mode_enum(C)!=CTX_MODE_OBJECT) 01676 return 0; 01677 01678 return 1; 01679 } 01680 01681 int ED_view3d_context_activate(bContext *C) 01682 { 01683 bScreen *sc= CTX_wm_screen(C); 01684 ScrArea *sa= CTX_wm_area(C); 01685 ARegion *ar; 01686 01687 /* sa can be NULL when called from python */ 01688 if(sa==NULL || sa->spacetype != SPACE_VIEW3D) 01689 for(sa=sc->areabase.first; sa; sa= sa->next) 01690 if(sa->spacetype==SPACE_VIEW3D) 01691 break; 01692 01693 if(!sa) 01694 return 0; 01695 01696 for(ar=sa->regionbase.first; ar; ar=ar->next) 01697 if(ar->regiontype == RGN_TYPE_WINDOW) 01698 break; 01699 01700 if(!ar) 01701 return 0; 01702 01703 // bad context switch .. 01704 CTX_wm_area_set(C, sa); 01705 CTX_wm_region_set(C, ar); 01706 01707 return 1; 01708 } 01709 01710 static int game_engine_exec(bContext *C, wmOperator *op) 01711 { 01712 #ifdef WITH_GAMEENGINE 01713 Scene *startscene = CTX_data_scene(C); 01714 ScrArea /* *sa, */ /* UNUSED */ *prevsa= CTX_wm_area(C); 01715 ARegion *ar, *prevar= CTX_wm_region(C); 01716 wmWindow *prevwin= CTX_wm_window(C); 01717 RegionView3D *rv3d; 01718 rcti cam_frame; 01719 01720 (void)op; /* unused */ 01721 01722 // bad context switch .. 01723 if(!ED_view3d_context_activate(C)) 01724 return OPERATOR_CANCELLED; 01725 01726 /* redraw to hide any menus/popups, we don't go back to 01727 the window manager until after this operator exits */ 01728 WM_redraw_windows(C); 01729 01730 rv3d= CTX_wm_region_view3d(C); 01731 /* sa= CTX_wm_area(C); */ /* UNUSED */ 01732 ar= CTX_wm_region(C); 01733 01734 view3d_operator_needs_opengl(C); 01735 01736 game_set_commmandline_options(&startscene->gm); 01737 01738 if((rv3d->persp == RV3D_CAMOB) && 01739 (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) && 01740 (startscene->gm.stereoflag != STEREO_DOME)) 01741 { 01742 /* Letterbox */ 01743 rctf cam_framef; 01744 ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE); 01745 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin; 01746 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin; 01747 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin; 01748 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin; 01749 BLI_isect_rcti(&ar->winrct, &cam_frame, &cam_frame); 01750 } 01751 else { 01752 cam_frame.xmin = ar->winrct.xmin; 01753 cam_frame.xmax = ar->winrct.xmax; 01754 cam_frame.ymin = ar->winrct.ymin; 01755 cam_frame.ymax = ar->winrct.ymax; 01756 } 01757 01758 01759 SaveState(C, prevwin); 01760 01761 StartKetsjiShell(C, ar, &cam_frame, 1); 01762 01763 /* window wasnt closed while the BGE was running */ 01764 if(BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) { 01765 prevwin= NULL; 01766 CTX_wm_window_set(C, NULL); 01767 } 01768 01769 ED_area_tag_redraw(CTX_wm_area(C)); 01770 01771 if(prevwin) { 01772 /* restore context, in case it changed in the meantime, for 01773 example by working in another window or closing it */ 01774 CTX_wm_region_set(C, prevar); 01775 CTX_wm_window_set(C, prevwin); 01776 CTX_wm_area_set(C, prevsa); 01777 } 01778 01779 RestoreState(C, prevwin); 01780 01781 //XXX restore_all_scene_cfra(scene_cfra_store); 01782 set_scene_bg(CTX_data_main(C), startscene); 01783 //XXX scene_update_for_newframe(bmain, scene, scene->lay); 01784 01785 return OPERATOR_FINISHED; 01786 #else 01787 (void)C; /* unused */ 01788 BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build"); 01789 return OPERATOR_CANCELLED; 01790 #endif 01791 } 01792 01793 void VIEW3D_OT_game_start(wmOperatorType *ot) 01794 { 01795 01796 /* identifiers */ 01797 ot->name= "Start Game Engine"; 01798 ot->description= "Start game engine"; 01799 ot->idname= "VIEW3D_OT_game_start"; 01800 01801 /* api callbacks */ 01802 ot->exec= game_engine_exec; 01803 01804 ot->poll= game_engine_poll; 01805 } 01806 01807 /* ************************************** */ 01808 01809 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3]) 01810 { 01811 float alignaxis[3] = {0.0, 0.0, 0.0}; 01812 float norm[3], axis[3], angle, new_quat[4]; 01813 01814 if(axisidx > 0) alignaxis[axisidx-1]= 1.0; 01815 else alignaxis[-axisidx-1]= -1.0; 01816 01817 normalize_v3_v3(norm, vec); 01818 01819 angle= (float)acos(dot_v3v3(alignaxis, norm)); 01820 cross_v3_v3v3(axis, alignaxis, norm); 01821 axis_angle_to_quat( new_quat,axis, -angle); 01822 01823 rv3d->view= RV3D_VIEW_USER; 01824 01825 if (rv3d->persp==RV3D_CAMOB && v3d->camera) { 01826 /* switch out of camera view */ 01827 float orig_ofs[3]; 01828 float orig_dist= rv3d->dist; 01829 float orig_lens= v3d->lens; 01830 01831 copy_v3_v3(orig_ofs, rv3d->ofs); 01832 rv3d->persp= RV3D_PERSP; 01833 rv3d->dist= 0.0; 01834 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens); 01835 smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX 01836 } else { 01837 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */ 01838 smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX 01839 } 01840 } 01841 01842 float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3]) 01843 { 01844 return (rv3d->persmat[3][3] + ( 01845 rv3d->persmat[0][3]*co[0] + 01846 rv3d->persmat[1][3]*co[1] + 01847 rv3d->persmat[2][3]*co[2]) 01848 ) * rv3d->pixsize; 01849 }