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