/** ensure \a v1 is \a dist from \a v2 */ void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist) { if (!equals_v3v3(v2, v1)) { float nor[3]; sub_v3_v3v3(nor, v1, v2); normalize_v3(nor); madd_v3_v3v3fl(v1, v2, nor, dist); } }
/* helper to fix a ebone position if its parent has moved due to alignment*/ static void fix_connected_bone(EditBone *ebone) { float diff[3]; if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head)) return; /* if the parent has moved we translate child's head and tail accordingly */ sub_v3_v3v3(diff, ebone->parent->tail, ebone->head); add_v3_v3(ebone->head, diff); add_v3_v3(ebone->tail, diff); }
static void bmbvh_find_face_segment_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { struct SegmentUserData *bmcb_data = userdata; const BMLoop **ltri = bmcb_data->looptris[index]; float dist, uv[2]; const float *tri_cos[3]; bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage); if (equals_v3v3(bmcb_data->co_a, tri_cos[0]) || equals_v3v3(bmcb_data->co_a, tri_cos[1]) || equals_v3v3(bmcb_data->co_a, tri_cos[2]) || equals_v3v3(bmcb_data->co_b, tri_cos[0]) || equals_v3v3(bmcb_data->co_b, tri_cos[1]) || equals_v3v3(bmcb_data->co_b, tri_cos[2])) { return; } if (isect_ray_tri_v3(ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv) && (dist < hit->dist)) { hit->dist = dist; hit->index = index; copy_v3_v3(hit->no, ltri[0]->f->no); madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist); copy_v2_v2(bmcb_data->uv, uv); } }
static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points) { EditBonePoint *ebp; float vec[3]; short found = 0; if (eb_tail) { copy_v3_v3(vec, ebo->tail); } else { copy_v3_v3(vec, ebo->head); } for (ebp = points->first; ebp; ebp = ebp->next) { if (equals_v3v3(ebp->vec, vec)) { if (eb_tail) { if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) { /* so this bone's tail owner is this bone */ ebp->tail_owner = ebo; found = 1; break; } } else { if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) { /* so this bone's head owner is this bone */ ebp->head_owner = ebo; found = 1; break; } } } } /* allocate a new point if no existing point was related */ if (found == 0) { ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint"); if (eb_tail) { copy_v3_v3(ebp->vec, ebo->tail); ebp->tail_owner = ebo; } else { copy_v3_v3(ebp->vec, ebo->head); ebp->head_owner = ebo; } BLI_addtail(points, ebp); } }
static int check_undistortion_cache_flags(MovieClip *clip) { MovieClipCache *cache = clip->cache; MovieTrackingCamera *camera = &clip->tracking.camera; /* check for distortion model changes */ if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) return FALSE; if (!equals_v3v3(&camera->k1, &cache->postprocessed.k1)) return FALSE; return TRUE; }
// With A, B and P indicating the three vertices of a given triangle, returns: // 1 if points A and B are in the same position in the 3D space; // 2 if the distance between point P and line segment AB is zero; and // zero otherwise. int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3[3]) { const float eps = 1.0e-6; const float eps_sq = eps * eps; #if 0 float area = area_tri_v3(v1, v2, v3); bool verbose = (area < 1.0e-6); #endif if (equals_v3v3(v1, v2) || equals_v3v3(v2, v3) || equals_v3v3(v1, v3)) { #if 0 if (verbose && G.debug & G_DEBUG_FREESTYLE) { printf("BlenderFileLoader::testDegenerateTriangle = 1\n"); } #endif return 1; } if (dist_squared_to_line_segment_v3(v1, v2, v3) < eps_sq || dist_squared_to_line_segment_v3(v2, v1, v3) < eps_sq || dist_squared_to_line_segment_v3(v3, v1, v2) < eps_sq) { #if 0 if (verbose && G.debug & G_DEBUG_FREESTYLE) { printf("BlenderFileLoader::testDegenerateTriangle = 2\n"); } #endif return 2; } #if 0 if (verbose && G.debug & G_DEBUG_FREESTYLE) { printf("BlenderFileLoader::testDegenerateTriangle = 0\n"); } #endif return 0; }
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges. * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) { const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata; const MVert *vert = data->vert; const MEdge *edge = &data->edge[index]; const float radius_sq = SQUARE(data->sphere_radius); float dist; const float *v1, *v2, *r1; float r2[3], i1[3], i2[3]; v1 = vert[edge->v1].co; v2 = vert[edge->v2].co; /* In case we get a zero-length edge, handle it as a point! */ if (equals_v3v3(v1, v2)) { mesh_verts_spherecast_do(data, index, v1, ray, hit); return; } r1 = ray->origin; add_v3_v3v3(r2, r1, ray->direction); if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) { /* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */ if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) { const float e_fac = line_point_factor_v3(i1, v1, v2); if (e_fac < 0.0f) { copy_v3_v3(i1, v1); } else if (e_fac > 1.0f) { copy_v3_v3(i1, v2); } /* Ensure ray is really close enough from edge! */ if (len_squared_v3v3(i1, i2) <= radius_sq) { hit->index = index; hit->dist = dist; copy_v3_v3(hit->co, i2); } } } }
static bool check_undistortion_cache_flags(MovieClip *clip) { MovieClipCache *cache = clip->cache; MovieTrackingCamera *camera = &clip->tracking.camera; /* check for distortion model changes */ if (!equals_v2v2(camera->principal, cache->postprocessed.principal)) { return false; } if (camera->distortion_model != cache->postprocessed.distortion_model) { return false; } if (!equals_v3v3(&camera->k1, &cache->postprocessed.polynomial_k1)) { return false; } if (!equals_v2v2(&camera->division_k1, &cache->postprocessed.division_k1)) { return false; } return true; }
/* Draw the given motion path for an Object or a Bone * - assumes that the viewport has already been initialized properly * i.e. draw_motion_paths_init() has been called */ void draw_motion_path_instance(Scene *scene, Object *ob, bPoseChannel *pchan, bAnimVizSettings *avs, bMotionPath *mpath) { //RegionView3D *rv3d = ar->regiondata; bMotionPathVert *mpv, *mpv_start; int i, stepsize = avs->path_step; int sfra, efra, sind, len; /* get frame ranges */ if (avs->path_type == MOTIONPATH_TYPE_ACFRA) { /* With "Around Current", we only choose frames from around * the current frame to draw. */ sfra = CFRA - avs->path_bc; efra = CFRA + avs->path_ac; } else { /* Use the current display range */ sfra = avs->path_sf; efra = avs->path_ef; } /* no matter what, we can only show what is in the cache and no more * - abort if whole range is past ends of path * - otherwise clamp endpoints to extents of path */ if (sfra < mpath->start_frame) { /* start clamp */ sfra = mpath->start_frame; } if (efra > mpath->end_frame) { /* end clamp */ efra = mpath->end_frame; } if ((sfra > mpath->end_frame) || (efra < mpath->start_frame)) { /* whole path is out of bounds */ return; } len = efra - sfra; if ((len <= 0) || (mpath->points == NULL)) { return; } /* get pointers to parts of path */ sind = sfra - mpath->start_frame; mpv_start = (mpath->points + sind); /* draw curve-line of path */ glShadeModel(GL_SMOOTH); glBegin(GL_LINE_STRIP); for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT); float intensity; /* how faint */ int frame = sfra + i; int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */ /* set color * - more intense for active/selected bones, less intense for unselected bones * - black for before current frame, green for current frame, blue for after current frame * - intensity decreases as distance from current frame increases */ #define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min) if (frame < CFRA) { /* black - before cfra */ if (sel) { /* intensity = 0.5f; */ intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f); } else { /* intensity = 0.8f; */ intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f); } UI_ThemeColorBlend(TH_WIRE, blend_base, intensity); } else if (frame > CFRA) { /* blue - after cfra */ if (sel) { /* intensity = 0.5f; */ intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f); } else { /* intensity = 0.8f; */ intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f); } UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity); } else { /* green - on cfra */ if (sel) { intensity = 0.5f; } else { intensity = 0.99f; } UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); } #undef SET_INTENSITY /* draw a vertex with this color */ glVertex3fv(mpv->co); } glEnd(); glShadeModel(GL_FLAT); glPointSize(1.0); /* draw little black point at each frame * NOTE: this is not really visible/noticeable */ glBegin(GL_POINTS); for (i = 0, mpv = mpv_start; i < len; i++, mpv++) glVertex3fv(mpv->co); glEnd(); /* Draw little white dots at each framestep value */ UI_ThemeColor(TH_TEXT_HI); glBegin(GL_POINTS); for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) glVertex3fv(mpv->co); glEnd(); /* Draw big green dot where the current frame is * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter */ if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) && (sfra < CFRA) && (CFRA <= efra)) { UI_ThemeColor(TH_CFRAME); glPointSize(6.0f); glBegin(GL_POINTS); mpv = mpv_start + (CFRA - sfra); glVertex3fv(mpv->co); glEnd(); UI_ThemeColor(TH_TEXT_HI); } /* XXX, this isn't up to date but probably should be kept so. */ invert_m4_m4(ob->imat, ob->obmat); /* Draw frame numbers at each framestep value */ if (avs->path_viewflag & MOTIONPATH_VIEW_FNUMS) { unsigned char col[4]; UI_GetThemeColor3ubv(TH_TEXT_HI, col); col[3] = 255; for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) { int frame = sfra + i; char numstr[32]; size_t numstr_len; float co[3]; /* only draw framenum if several consecutive highlighted points don't occur on same point */ if (i == 0) { numstr_len = sprintf(numstr, " %d", frame); mul_v3_m4v3(co, ob->imat, mpv->co); view3d_cached_text_draw_add(co, numstr, numstr_len, 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); } else if ((i >= stepsize) && (i < len - stepsize)) { bMotionPathVert *mpvP = (mpv - stepsize); bMotionPathVert *mpvN = (mpv + stepsize); if ((equals_v3v3(mpv->co, mpvP->co) == 0) || (equals_v3v3(mpv->co, mpvN->co) == 0)) { numstr_len = sprintf(numstr, " %d", frame); mul_v3_m4v3(co, ob->imat, mpv->co); view3d_cached_text_draw_add(co, numstr, numstr_len, 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); } } } } /* Keyframes - dots and numbers */ if (avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) { unsigned char col[4]; AnimData *adt = BKE_animdata_from_id(&ob->id); DLRBT_Tree keys; /* build list of all keyframes in active action for object or pchan */ BLI_dlrbTree_init(&keys); if (adt) { /* it is assumed that keyframes for bones are all grouped in a single group * unless an option is set to always use the whole action */ if ((pchan) && (avs->path_viewflag & MOTIONPATH_VIEW_KFACT) == 0) { bActionGroup *agrp = BKE_action_group_find_name(adt->action, pchan->name); if (agrp) { agroup_to_keylist(adt, agrp, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); } } else { action_to_keylist(adt, adt->action, &keys, NULL); BLI_dlrbTree_linkedlist_sync(&keys); } } /* Draw slightly-larger yellow dots at each keyframe */ UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col); col[3] = 255; glPointSize(4.0f); glColor3ubv(col); glBegin(GL_POINTS); for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { int frame = sfra + i; float mframe = (float)(frame); if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) glVertex3fv(mpv->co); } glEnd(); /* Draw frame numbers of keyframes */ if (avs->path_viewflag & MOTIONPATH_VIEW_KFNOS) { float co[3]; for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { float mframe = (float)(sfra + i); if (BLI_dlrbTree_search_exact(&keys, compare_ak_cfraPtr, &mframe)) { char numstr[32]; size_t numstr_len; numstr_len = sprintf(numstr, " %d", (sfra + i)); mul_v3_m4v3(co, ob->imat, mpv->co); view3d_cached_text_draw_add(co, numstr, numstr_len, 0, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, col); } } } BLI_dlrbTree_free(&keys); } }
static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_edit_object(C); bArmature *arm = (bArmature *)ob->data; ListBase chains = {NULL, NULL}; LinkData *chain; /* get chains of bones (ends on chains) */ chains_find_tips(arm->edbo, &chains); if (chains.first == NULL) return OPERATOR_CANCELLED; /* ensure that mirror bones will also be operated on */ armature_tag_select_mirrored(arm); /* clear BONE_TRANSFORM flags * - used to prevent duplicate/cancelling operations from occurring [#34123] * - BONE_DONE cannot be used here as that's already used for mirroring */ armature_clear_swap_done_flags(arm); /* loop over chains, only considering selected and visible bones */ for (chain = chains.first; chain; chain = chain->next) { EditBone *ebo, *child = NULL, *parent = NULL; /* loop over bones in chain */ for (ebo = chain->data; ebo; ebo = parent) { /* parent is this bone's original parent * - we store this, as the next bone that is checked is this one * but the value of ebo->parent may change here... */ parent = ebo->parent; /* skip bone if already handled... [#34123] */ if ((ebo->flag & BONE_TRANSFORM) == 0) { /* only if selected and editable */ if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) { /* swap head and tail coordinates */ SWAP(float, ebo->head[0], ebo->tail[0]); SWAP(float, ebo->head[1], ebo->tail[1]); SWAP(float, ebo->head[2], ebo->tail[2]); /* do parent swapping: * - use 'child' as new parent * - connected flag is only set if points are coincidental */ ebo->parent = child; if ((child) && equals_v3v3(ebo->head, child->tail)) ebo->flag |= BONE_CONNECTED; else ebo->flag &= ~BONE_CONNECTED; /* get next bones * - child will become the new parent of next bone */ child = ebo; } else { /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it * as it will be facing in opposite direction */ if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) { ebo->parent = NULL; ebo->flag &= ~BONE_CONNECTED; } /* get next bones * - child will become new parent of next bone (not swapping occurred, * so set to NULL to prevent infinite-loop) */ child = NULL; } /* tag as done (to prevent double-swaps) */ ebo->flag |= BONE_TRANSFORM; } }
/* the arguments are the desired situation */ void ED_view3d_smooth_view_ex( /* avoid passing in the context */ wmWindowManager *wm, wmWindow *win, ScrArea *sa, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, const float *ofs, const float *quat, const float *dist, const float *lens, const int smooth_viewtx) { RegionView3D *rv3d = ar->regiondata; struct SmoothView3DStore sms = {{0}}; bool ok = false; /* initialize sms */ view3d_smooth_view_state_backup(&sms.dst, v3d, rv3d); view3d_smooth_view_state_backup(&sms.src, v3d, rv3d); /* if smoothview runs multiple times... */ if (rv3d->sms == NULL) { view3d_smooth_view_state_backup(&sms.org, v3d, rv3d); sms.org_view = rv3d->view; } else { sms.org = rv3d->sms->org; sms.org_view = rv3d->sms->org_view; } /* sms.to_camera = false; */ /* initizlized to zero anyway */ /* note on camera locking, this is a little confusing but works ok. * we may be changing the view 'as if' there is no active camera, but in fact * there is an active camera which is locked to the view. * * In the case where smooth view is moving _to_ a camera we don't want that * camera to be moved or changed, so only when the camera is not being set should * we allow camera option locking to initialize the view settings from the camera. */ if (camera == NULL && oldcamera == NULL) { ED_view3d_camera_lock_init(v3d, rv3d); } /* store the options we want to end with */ if (ofs) copy_v3_v3(sms.dst.ofs, ofs); if (quat) copy_qt_qt(sms.dst.quat, quat); if (dist) sms.dst.dist = *dist; if (lens) sms.dst.lens = *lens; if (camera) { sms.dst.dist = ED_view3d_offset_distance(camera->obmat, ofs, VIEW3D_DIST_FALLBACK); ED_view3d_from_object(camera, sms.dst.ofs, sms.dst.quat, &sms.dst.dist, &sms.dst.lens); sms.to_camera = true; /* restore view3d values in end */ } /* skip smooth viewing for render engine draw */ if (smooth_viewtx && v3d->drawtype != OB_RENDER) { bool changed = false; /* zero means no difference */ if (oldcamera != camera) changed = true; else if (sms.dst.dist != rv3d->dist) changed = true; else if (sms.dst.lens != v3d->lens) changed = true; else if (!equals_v3v3(sms.dst.ofs, rv3d->ofs)) changed = true; else if (!equals_v4v4(sms.dst.quat, rv3d->viewquat)) changed = true; /* The new view is different from the old one * so animate the view */ if (changed) { /* original values */ if (oldcamera) { sms.src.dist = ED_view3d_offset_distance(oldcamera->obmat, rv3d->ofs, 0.0f); /* this */ ED_view3d_from_object(oldcamera, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens); } /* grid draw as floor */ if ((rv3d->viewlock & RV3D_LOCKED) == 0) { /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */ rv3d->view = RV3D_VIEW_USER; } sms.time_allowed = (double)smooth_viewtx / 1000.0; /* if this is view rotation only * we can decrease the time allowed by * the angle between quats * this means small rotations wont lag */ if (quat && !ofs && !dist) { float vec1[3] = {0, 0, 1}, vec2[3] = {0, 0, 1}; float q1[4], q2[4]; invert_qt_qt(q1, sms.dst.quat); invert_qt_qt(q2, sms.src.quat); mul_qt_v3(q1, vec1); mul_qt_v3(q2, vec2); /* scale the time allowed by the rotation */ sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */ } /* ensure it shows correct */ if (sms.to_camera) { /* use ortho if we move from an ortho view to an ortho camera */ rv3d->persp = (((rv3d->is_persp == false) && (camera->type == OB_CAMERA) && (((Camera *)camera->data)->type == CAM_ORTHO)) ? RV3D_ORTHO : RV3D_PERSP); } rv3d->rflag |= RV3D_NAVIGATING; /* not essential but in some cases the caller will tag the area for redraw, * and in that case we can get a flicker of the 'org' user view but we want to see 'src' */ view3d_smooth_view_state_restore(&sms.src, v3d, rv3d); /* keep track of running timer! */ if (rv3d->sms == NULL) { rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d"); } *rv3d->sms = sms; if (rv3d->smooth_timer) { WM_event_remove_timer(wm, win, rv3d->smooth_timer); } /* TIMER1 is hardcoded in keymap */ rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0); /* max 30 frs/sec */ ok = true; } } /* if we get here nothing happens */ if (ok == false) { if (sms.to_camera == false) { copy_v3_v3(rv3d->ofs, sms.dst.ofs); copy_qt_qt(rv3d->viewquat, sms.dst.quat); rv3d->dist = sms.dst.dist; v3d->lens = sms.dst.lens; ED_view3d_camera_lock_sync(v3d, rv3d); } if (rv3d->viewlock & RV3D_BOXVIEW) { view3d_boxview_copy(sa, ar); } ED_region_tag_redraw(ar); } }
static int select_groped_exec(bContext *C, wmOperator *op) { SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); MovieTrackingTrack *track; MovieTrackingMarker *marker; MovieTracking *tracking = &clip->tracking; ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking); int group = RNA_enum_get(op->ptr, "group"); int framenr = ED_space_clip_get_clip_frame_number(sc); track = tracksbase->first; while (track) { bool ok = false; marker = BKE_tracking_marker_get(track, framenr); if (group == 0) { /* Keyframed */ ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED) == 0; } else if (group == 1) { /* Estimated */ ok = marker->framenr != framenr; } else if (group == 2) { /* tracked */ ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED); } else if (group == 3) { /* locked */ ok = track->flag & TRACK_LOCKED; } else if (group == 4) { /* disabled */ ok = marker->flag & MARKER_DISABLED; } else if (group == 5) { /* color */ MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking); if (act_track) { ok = (track->flag & TRACK_CUSTOMCOLOR) == (act_track->flag & TRACK_CUSTOMCOLOR); if (ok && track->flag & TRACK_CUSTOMCOLOR) ok = equals_v3v3(track->color, act_track->color); } } else if (group == 6) { /* failed */ ok = (track->flag & TRACK_HAS_BUNDLE) == 0; } if (ok) { track->flag |= SELECT; if (sc->flag & SC_SHOW_MARKER_PATTERN) track->pat_flag |= SELECT; if (sc->flag & SC_SHOW_MARKER_SEARCH) track->search_flag |= SELECT; } track = track->next; } BKE_tracking_dopesheet_tag_update(tracking); WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip); return OPERATOR_FINISHED; }
/* the arguments are the desired situation */ void smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens) { wmWindowManager *wm= CTX_wm_manager(C); wmWindow *win= CTX_wm_window(C); ScrArea *sa= CTX_wm_area(C); RegionView3D *rv3d= ar->regiondata; struct SmoothViewStore sms= {0}; short ok= FALSE; /* initialize sms */ copy_v3_v3(sms.new_ofs, rv3d->ofs); copy_qt_qt(sms.new_quat, rv3d->viewquat); sms.new_dist= rv3d->dist; sms.new_lens= v3d->lens; sms.to_camera= 0; /* note on camera locking, this is a little confusing but works ok. * we may be changing the view 'as if' there is no active camera, but infact * there is an active camera which is locked to the view. * * In the case where smooth view is moving _to_ a camera we dont want that * camera to be moved or changed, so only when the camera is not being set should * we allow camera option locking to initialize the view settings from the camera. */ if(camera == NULL && oldcamera == NULL) { ED_view3d_camera_lock_init(v3d, rv3d); } /* store the options we want to end with */ if(ofs) copy_v3_v3(sms.new_ofs, ofs); if(quat) copy_qt_qt(sms.new_quat, quat); if(dist) sms.new_dist= *dist; if(lens) sms.new_lens= *lens; if (camera) { ED_view3d_from_object(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens); sms.to_camera= 1; /* restore view3d values in end */ } if (C && U.smooth_viewtx) { int changed = 0; /* zero means no difference */ if (oldcamera != camera) changed = 1; else if (sms.new_dist != rv3d->dist) changed = 1; else if (sms.new_lens != v3d->lens) changed = 1; else if (!equals_v3v3(sms.new_ofs, rv3d->ofs)) changed = 1; else if (!equals_v4v4(sms.new_quat, rv3d->viewquat)) changed = 1; /* The new view is different from the old one * so animate the view */ if (changed) { /* original values */ if (oldcamera) { sms.orig_dist= rv3d->dist; // below function does weird stuff with it... ED_view3d_from_object(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens); } else { copy_v3_v3(sms.orig_ofs, rv3d->ofs); copy_qt_qt(sms.orig_quat, rv3d->viewquat); sms.orig_dist= rv3d->dist; sms.orig_lens= v3d->lens; } /* grid draw as floor */ if((rv3d->viewlock & RV3D_LOCKED)==0) { /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */ sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view; rv3d->view= RV3D_VIEW_USER; } sms.time_allowed= (double)U.smooth_viewtx / 1000.0; /* if this is view rotation only * we can decrease the time allowed by * the angle between quats * this means small rotations wont lag */ if (quat && !ofs && !dist) { float vec1[3]={0,0,1}, vec2[3]= {0,0,1}; float q1[4], q2[4]; invert_qt_qt(q1, sms.new_quat); invert_qt_qt(q2, sms.orig_quat); mul_qt_v3(q1, vec1); mul_qt_v3(q2, vec2); /* scale the time allowed by the rotation */ sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */ } /* ensure it shows correct */ if(sms.to_camera) rv3d->persp= RV3D_PERSP; rv3d->rflag |= RV3D_NAVIGATING; /* keep track of running timer! */ if(rv3d->sms==NULL) rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d"); *rv3d->sms= sms; if(rv3d->smooth_timer) WM_event_remove_timer(wm, win, rv3d->smooth_timer); /* TIMER1 is hardcoded in keymap */ rv3d->smooth_timer= WM_event_add_timer(wm, win, TIMER1, 1.0/100.0); /* max 30 frs/sec */ ok= TRUE; } } /* if we get here nothing happens */ if(ok == FALSE) { if(sms.to_camera==0) { copy_v3_v3(rv3d->ofs, sms.new_ofs); copy_qt_qt(rv3d->viewquat, sms.new_quat); rv3d->dist = sms.new_dist; v3d->lens = sms.new_lens; } if(rv3d->viewlock & RV3D_BOXVIEW) view3d_boxview_copy(sa, ar); ED_region_tag_redraw(ar); } }