/** * \param ray_distance Distance to the hit point * \param r_location Location of the hit point * \param r_normal Normal of the hit surface, transformed to always face the camera */ static bool walk_ray_cast(bContext *C, RegionView3D *rv3d, WalkInfo *walk, float r_location[3], float r_normal[3], float *ray_distance) { float dummy_dist_px = 0; float ray_normal[3] = {0, 0, 1}; /* forward */ float ray_start[3]; float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ bool ret; *ray_distance = TRANSFORM_DIST_MAX_RAY; copy_v3_v3(ray_start, rv3d->viewinv[3]); copy_m3_m4(mat, rv3d->viewinv); mul_m3_v3(mat, ray_normal); mul_v3_fl(ray_normal, -1); normalize_v3(ray_normal); ret = snapObjectsRayEx(CTX_data_scene(C), NULL, NULL, NULL, NULL, SCE_SNAP_MODE_FACE, NULL, NULL, ray_start, ray_normal, ray_distance, NULL, &dummy_dist_px, r_location, r_normal, SNAP_ALL); /* dot is positive if both rays are facing the same direction */ if (dot_v3v3(ray_normal, r_normal) > 0) { copy_v3_fl3(r_normal, -r_normal[0], -r_normal[1], -r_normal[2]); } /* artifically scale the distance to the scene size */ *ray_distance /= walk->grid; return ret; }
/** * Release view control. * * \param restore Sets the view state to the values that were set * before #ED_view3d_control_aquire was called. */ void ED_view3d_cameracontrol_release( View3DCameraControl *vctrl, const bool restore) { View3D *v3d = vctrl->ctx_v3d; RegionView3D *rv3d = vctrl->ctx_rv3d; rv3d->dist = vctrl->dist_backup; if (restore) { /* Revert to original view? */ if (vctrl->persp_backup == RV3D_CAMOB) { /* a camera view */ Object *ob_back = view3d_cameracontrol_object(vctrl); /* store the original camera loc and rot */ BKE_object_tfm_restore(ob_back, vctrl->obtfm); DAG_id_tag_update(&ob_back->id, OB_RECALC_OB); } else { /* Non Camera we need to reset the view back to the original location bacause the user canceled*/ copy_qt_qt(rv3d->viewquat, vctrl->rot_backup); rv3d->persp = vctrl->persp_backup; } /* always, is set to zero otherwise */ copy_v3_v3(rv3d->ofs, vctrl->ofs_backup); } else if (vctrl->persp_backup == RV3D_CAMOB) { /* camera */ DAG_id_tag_update((ID *)view3d_cameracontrol_object(vctrl), OB_RECALC_OB); /* always, is set to zero otherwise */ copy_v3_v3(rv3d->ofs, vctrl->ofs_backup); } else { /* not camera */ float tvec[3]; /* Apply the fly mode view */ /* restore the dist */ copy_v3_fl3(tvec, 0.0f, 0.0f, vctrl->dist_backup); mul_mat3_m4_v3(rv3d->viewinv, tvec); add_v3_v3(rv3d->ofs, tvec); /* Done with correcting for the dist */ } if (vctrl->is_ortho_cam) { ((Camera *)v3d->camera->data)->type = CAM_ORTHO; } if (vctrl->obtfm) { MEM_freeN(vctrl->obtfm); } MEM_freeN(vctrl); }
/** * This function converts an object space normal map to a tangent space normal map for a given low poly mesh */ void RE_bake_normal_world_to_tangent( const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]) { size_t i; TriTessFace *triangles; DerivedMesh *dm = CDDM_from_mesh(me); triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh"); mesh_calc_tri_tessface(triangles, me, true, dm); BLI_assert(num_pixels >= 3); for (i = 0; i < num_pixels; i++) { TriTessFace *triangle; float tangents[3][3]; float normals[3][3]; float signs[3]; int j; float tangent[3]; float normal[3]; float binormal[3]; float sign; float u, v, w; float tsm[3][3]; /* tangent space matrix */ float itsm[3][3]; size_t offset; float nor[3]; /* texture normal */ bool is_smooth; int primitive_id = pixel_array[i].primitive_id; offset = i * depth; if (primitive_id == -1) { copy_v3_fl3(&result[offset], 0.5f, 0.5f, 1.0f); continue; } triangle = &triangles[primitive_id]; is_smooth = triangle->is_smooth; for (j = 0; j < 3; j++) { const TSpace *ts; if (is_smooth) normal_short_to_float_v3(normals[j], triangle->mverts[j]->no); else normal[j] = triangle->normal[j]; ts = triangle->tspace[j]; copy_v3_v3(tangents[j], ts->tangent); signs[j] = ts->sign; } u = pixel_array[i].uv[0]; v = pixel_array[i].uv[1]; w = 1.0f - u - v; /* normal */ if (is_smooth) interp_barycentric_tri_v3(normals, u, v, normal); /* tangent */ interp_barycentric_tri_v3(tangents, u, v, tangent); /* sign */ /* The sign is the same at all face vertices for any non degenerate face. * Just in case we clamp the interpolated value though. */ sign = (signs[0] * u + signs[1] * v + signs[2] * w) < 0 ? (-1.0f) : 1.0f; /* binormal */ /* B = sign * cross(N, T) */ cross_v3_v3v3(binormal, normal, tangent); mul_v3_fl(binormal, sign); /* populate tangent space matrix */ copy_v3_v3(tsm[0], tangent); copy_v3_v3(tsm[1], binormal); copy_v3_v3(tsm[2], normal); /* texture values */ normal_uncompress(nor, &result[offset]); /* converts from world space to local space */ mul_transposed_mat3_m4_v3(mat, nor); invert_m3_m3(itsm, tsm); mul_m3_v3(itsm, nor); normalize_v3(nor); /* save back the values */ normal_compress(&result[offset], nor, normal_swizzle); } /* garbage collection */ MEM_freeN(triangles); if (dm) dm->release(dm); }
/** * Creates a #View3DControl handle and sets up * the view for first-person style navigation. */ struct View3DCameraControl *ED_view3d_cameracontrol_aquire( Scene *scene, View3D *v3d, RegionView3D *rv3d, const bool use_parent_root) { View3DCameraControl *vctrl; vctrl = MEM_callocN(sizeof(View3DCameraControl), __func__); /* Store context */ vctrl->ctx_scene = scene; vctrl->ctx_v3d = v3d; vctrl->ctx_rv3d = rv3d; vctrl->use_parent_root = use_parent_root; vctrl->persp_backup = rv3d->persp; vctrl->dist_backup = rv3d->dist; /* check for flying ortho camera - which we cant support well * we _could_ also check for an ortho camera but this is easier */ if ((rv3d->persp == RV3D_CAMOB) && (rv3d->is_persp == false)) { ((Camera *)v3d->camera->data)->type = CAM_PERSP; vctrl->is_ortho_cam = true; } if (rv3d->persp == RV3D_CAMOB) { Object *ob_back; if (use_parent_root && (vctrl->root_parent = v3d->camera->parent)) { while (vctrl->root_parent->parent) vctrl->root_parent = vctrl->root_parent->parent; ob_back = vctrl->root_parent; } else { ob_back = v3d->camera; } /* store the original camera loc and rot */ vctrl->obtfm = BKE_object_tfm_backup(ob_back); BKE_object_where_is_calc(scene, v3d->camera); negate_v3_v3(rv3d->ofs, v3d->camera->obmat[3]); rv3d->dist = 0.0; } else { float tvec[3]; /* perspective or ortho */ if (rv3d->persp == RV3D_ORTHO) rv3d->persp = RV3D_PERSP; /* if ortho projection, make perspective */ copy_qt_qt(vctrl->rot_backup, rv3d->viewquat); copy_v3_v3(vctrl->ofs_backup, rv3d->ofs); /* the dist defines a vector that is infront of the offset * to rotate the view about. * this is no good for fly mode because we * want to rotate about the viewers center. * but to correct the dist removal we must * alter offset so the view doesn't jump. */ rv3d->dist = 0.0f; copy_v3_fl3(tvec, 0.0f, 0.0f, vctrl->dist_backup); mul_mat3_m4_v3(rv3d->viewinv, tvec); sub_v3_v3(rv3d->ofs, tvec); /* Done with correcting for the dist */ } ED_view3d_to_m4(vctrl->view_mat_prev, rv3d->ofs, rv3d->viewquat, rv3d->dist); return vctrl; }
static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk) { #define WALK_ROTATE_FAC 2.2f /* more is faster */ #define WALK_TOP_LIMIT DEG2RADF(85.0f) #define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f) #define WALK_MOVE_SPEED base_speed #define WALK_BOOST_FACTOR ((void)0, walk->speed_factor) /* walk mode - Ctrl+Shift+F * a walk loop where the user can move move the view as if they are in a walk game */ RegionView3D *rv3d = walk->rv3d; ARegion *ar = walk->ar; float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ float dvec[3] = {0.0f, 0.0f, 0.0f}; /* this is the direction that's added to the view offset per redraw */ /* Camera Uprighting variables */ float upvec[3] = {0.0f, 0.0f, 0.0f}; /* stores the view's up vector */ int moffset[2]; /* mouse offset from the views center */ float tmp_quat[4]; /* used for rotating the view */ #ifdef NDOF_WALK_DEBUG { static unsigned int iteration = 1; printf("walk timer %d\n", iteration++); } #endif { /* mouse offset from the center */ copy_v2_v2_int(moffset, walk->moffset); /* apply moffset so we can re-accumulate */ walk->moffset[0] = 0; walk->moffset[1] = 0; /* revert mouse */ if (walk->is_reversed) { moffset[1] = -moffset[1]; } /* Should we redraw? */ if ((walk->active_directions) || moffset[0] || moffset[1] || walk->teleport.state == WALK_TELEPORT_STATE_ON || walk->gravity_state != WALK_GRAVITY_STATE_OFF) { float dvec_tmp[3]; /* time how fast it takes for us to redraw, * this is so simple scenes don't walk too fast */ double time_current; float time_redraw; #ifdef NDOF_WALK_DRAW_TOOMUCH walk->redraw = 1; #endif time_current = PIL_check_seconds_timer(); time_redraw = (float)(time_current - walk->time_lastdraw); walk->time_lastdraw = time_current; /* base speed in m/s */ walk->speed = WALK_MOVE_SPEED; if (walk->is_fast) { walk->speed *= WALK_BOOST_FACTOR; } else if (walk->is_slow) { walk->speed *= 1.0f / WALK_BOOST_FACTOR; } copy_m3_m4(mat, rv3d->viewinv); { /* rotate about the X axis- look up/down */ if (moffset[1]) { float angle; float y; /* relative offset */ y = (float) moffset[1] / ar->winy; /* speed factor */ y *= WALK_ROTATE_FAC; /* user adjustement factor */ y *= walk->mouse_speed; /* clamp the angle limits */ /* it ranges from 90.0f to -90.0f */ angle = -asinf(rv3d->viewmat[2][2]); if (angle > WALK_TOP_LIMIT && y > 0.0f) y = 0.0f; else if (angle < WALK_BOTTOM_LIMIT && y < 0.0f) y = 0.0f; copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, -y); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); } /* rotate about the Y axis- look left/right */ if (moffset[0]) { float x; /* if we're upside down invert the moffset */ copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f); mul_m3_v3(mat, upvec); if (upvec[2] < 0.0f) moffset[0] = -moffset[0]; /* relative offset */ x = (float) moffset[0] / ar->winx; /* speed factor */ x *= WALK_ROTATE_FAC; /* user adjustement factor */ x *= walk->mouse_speed; copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); /* Rotate about the relative up vec */ axis_angle_normalized_to_quat(tmp_quat, upvec, x); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); } } /* WASD - 'move' translation code */ if ((walk->active_directions) && (walk->gravity_state == WALK_GRAVITY_STATE_OFF)) { short direction; zero_v3(dvec); if ((walk->active_directions & WALK_BIT_FORWARD) || (walk->active_directions & WALK_BIT_BACKWARD)) { direction = 0; if ((walk->active_directions & WALK_BIT_FORWARD)) direction += 1; if ((walk->active_directions & WALK_BIT_BACKWARD)) direction -= 1; copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction); mul_m3_v3(mat, dvec_tmp); if (walk->navigation_mode == WALK_MODE_GRAVITY) { dvec_tmp[2] = 0.0f; } normalize_v3(dvec_tmp); add_v3_v3(dvec, dvec_tmp); } if ((walk->active_directions & WALK_BIT_LEFT) || (walk->active_directions & WALK_BIT_RIGHT)) { direction = 0; if ((walk->active_directions & WALK_BIT_LEFT)) direction += 1; if ((walk->active_directions & WALK_BIT_RIGHT)) direction -= 1; dvec_tmp[0] = direction * rv3d->viewinv[0][0]; dvec_tmp[1] = direction * rv3d->viewinv[0][1]; dvec_tmp[2] = 0.0f; normalize_v3(dvec_tmp); add_v3_v3(dvec, dvec_tmp); } if ((walk->active_directions & WALK_BIT_UP) || (walk->active_directions & WALK_BIT_DOWN)) { if (walk->navigation_mode == WALK_MODE_FREE) { direction = 0; if ((walk->active_directions & WALK_BIT_UP)) direction -= 1; if ((walk->active_directions & WALK_BIT_DOWN)) direction = 1; copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction); add_v3_v3(dvec, dvec_tmp); } } /* apply movement */ mul_v3_fl(dvec, walk->speed * time_redraw); } /* stick to the floor */ if (walk->navigation_mode == WALK_MODE_GRAVITY && ELEM(walk->gravity_state, WALK_GRAVITY_STATE_OFF, WALK_GRAVITY_STATE_START)) { bool ret; float ray_distance; float difference = -100.0f; float fall_distance; ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; } /* the distance we would fall naturally smoothly enough that we * can manually drop the object without activating gravity */ fall_distance = time_redraw * walk->speed * WALK_BOOST_FACTOR; if (fabsf(difference) < fall_distance) { /* slope/stairs */ dvec[2] -= difference; /* in case we switched from FREE to GRAVITY too close to the ground */ if (walk->gravity_state == WALK_GRAVITY_STATE_START) walk->gravity_state = WALK_GRAVITY_STATE_OFF; } else { /* hijack the teleport variables */ walk->teleport.initial_time = PIL_check_seconds_timer(); walk->gravity_state = WALK_GRAVITY_STATE_ON; walk->teleport.duration = 0.0f; copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]); copy_v2_v2(walk->teleport.direction, dvec); } } /* Falling or jumping) */ if (ELEM(walk->gravity_state, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) { float t; float z_cur, z_new; bool ret; float ray_distance, difference = -100.0f; /* delta time */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); /* keep moving if we were moving */ copy_v2_v2(dvec, walk->teleport.direction); z_cur = walk->rv3d->viewinv[3][2]; z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid; /* jump */ z_new += t * walk->speed_jump * walk->grid; /* duration is the jump duration */ if (t > walk->teleport.duration) { /* check to see if we are landing */ ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; } if (difference > 0.0f) { /* quit falling, lands at "view_height" from the floor */ dvec[2] -= difference; walk->gravity_state = WALK_GRAVITY_STATE_OFF; walk->speed_jump = 0.0f; } else { /* keep falling */ dvec[2] = z_cur - z_new; } } else { /* keep going up (jump) */ dvec[2] = z_cur - z_new; } } /* Teleport */ else if (walk->teleport.state == WALK_TELEPORT_STATE_ON) { float t; /* factor */ float new_loc[3]; float cur_loc[3]; /* linear interpolation */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); t /= walk->teleport.duration; /* clamp so we don't go past our limit */ if (t >= 1.0f) { t = 1.0f; walk->teleport.state = WALK_TELEPORT_STATE_OFF; walk_navigation_mode_set(C, op, walk, walk->teleport.navigation_mode); } mul_v3_v3fl(new_loc, walk->teleport.direction, t); add_v3_v3(new_loc, walk->teleport.origin); copy_v3_v3(cur_loc, walk->rv3d->viewinv[3]); sub_v3_v3v3(dvec, cur_loc, new_loc); } if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control); if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0f; } /* scale the movement to the scene size */ mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(rv3d->ofs, dvec_tmp); if (rv3d->persp == RV3D_CAMOB) { const bool do_rotate = (moffset[0] || moffset[1]); const bool do_translate = (walk->speed != 0.0f); walkMoveCamera(C, walk, do_rotate, do_translate); } } else { /* we're not redrawing but we need to update the time else the view will jump */ walk->time_lastdraw = PIL_check_seconds_timer(); } /* end drawing */ copy_v3_v3(walk->dvec_prev, dvec); } return OPERATOR_FINISHED; #undef WALK_ROTATE_FAC #undef WALK_ZUP_CORRECT_FAC #undef WALK_ZUP_CORRECT_ACCEL #undef WALK_SMOOTH_FAC #undef WALK_TOP_LIMIT #undef WALK_BOTTOM_LIMIT #undef WALK_MOVE_SPEED #undef WALK_BOOST_FACTOR }
static int flyApply(bContext *C, FlyInfo *fly) { #define FLY_ROTATE_FAC 10.0f /* more is faster */ #define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */ #define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */ #define FLY_SMOOTH_FAC 20.0f /* higher value less lag */ /* fly mode - Shift+F * a fly loop where the user can move move the view as if they are flying */ RegionView3D *rv3d = fly->rv3d; float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ float dvec[3] = {0, 0, 0}; /* this is the direction that's added to the view offset per redraw */ /* Camera Uprighting variables */ float moffset[2]; /* mouse offset from the views center */ float tmp_quat[4]; /* used for rotating the view */ int xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */ #ifdef NDOF_FLY_DEBUG { static unsigned int iteration = 1; printf("fly timer %d\n", iteration++); } #endif xmargin = fly->width / 20.0f; ymargin = fly->height / 20.0f; { /* mouse offset from the center */ moffset[0] = fly->mval[0] - fly->center_mval[0]; moffset[1] = fly->mval[1] - fly->center_mval[1]; /* enforce a view margin */ if (moffset[0] > xmargin) moffset[0] -= xmargin; else if (moffset[0] < -xmargin) moffset[0] += xmargin; else moffset[0] = 0; if (moffset[1] > ymargin) moffset[1] -= ymargin; else if (moffset[1] < -ymargin) moffset[1] += ymargin; else moffset[1] = 0; /* scale the mouse movement by this value - scales mouse movement to the view size * moffset[0] / (ar->winx-xmargin * 2) - window size minus margin (same for y) * * the mouse moves isn't linear */ if (moffset[0]) { moffset[0] /= fly->width - (xmargin * 2); moffset[0] *= fabsf(moffset[0]); } if (moffset[1]) { moffset[1] /= fly->height - (ymargin * 2); moffset[1] *= fabsf(moffset[1]); } /* Should we redraw? */ if ((fly->speed != 0.0f) || moffset[0] || moffset[1] || (fly->zlock != FLY_AXISLOCK_STATE_OFF) || (fly->xlock != FLY_AXISLOCK_STATE_OFF) || dvec[0] || dvec[1] || dvec[2]) { float dvec_tmp[3]; /* time how fast it takes for us to redraw, * this is so simple scenes don't fly too fast */ double time_current; float time_redraw; float time_redraw_clamped; #ifdef NDOF_FLY_DRAW_TOOMUCH fly->redraw = 1; #endif time_current = PIL_check_seconds_timer(); time_redraw = (float)(time_current - fly->time_lastdraw); time_redraw_clamped = min_ff(0.05f, time_redraw); /* clamp redraw time to avoid jitter in roll correction */ fly->time_lastdraw = time_current; /* Scale the time to use shift to scale the speed down- just like * shift slows many other areas of blender down */ if (fly->use_precision) fly->speed = fly->speed * (1.0f - time_redraw_clamped); copy_m3_m4(mat, rv3d->viewinv); if (fly->pan_view == true) { /* pan only */ copy_v3_fl3(dvec_tmp, -moffset[0], -moffset[1], 0.0f); if (fly->use_precision) { dvec_tmp[0] *= 0.1f; dvec_tmp[1] *= 0.1f; } mul_m3_v3(mat, dvec_tmp); mul_v3_fl(dvec_tmp, time_redraw * 200.0f * fly->grid); } else { float roll; /* similar to the angle between the camera's up and the Z-up, * but its very rough so just roll */ /* rotate about the X axis- look up/down */ if (moffset[1]) { float upvec[3]; copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, moffset[1] * time_redraw * -FLY_ROTATE_FAC); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); if (fly->xlock != FLY_AXISLOCK_STATE_OFF) fly->xlock = FLY_AXISLOCK_STATE_ACTIVE; /* check for rotation */ if (fly->zlock != FLY_AXISLOCK_STATE_OFF) fly->zlock = FLY_AXISLOCK_STATE_ACTIVE; fly->xlock_momentum = 0.0f; } /* rotate about the Y axis- look left/right */ if (moffset[0]) { float upvec[3]; /* if we're upside down invert the moffset */ copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f); mul_m3_v3(mat, upvec); if (upvec[2] < 0.0f) moffset[0] = -moffset[0]; /* make the lock vectors */ if (fly->zlock) { copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); } else { copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f); mul_m3_v3(mat, upvec); } /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, moffset[0] * time_redraw * FLY_ROTATE_FAC); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); if (fly->xlock != FLY_AXISLOCK_STATE_OFF) fly->xlock = FLY_AXISLOCK_STATE_ACTIVE; /* check for rotation */ if (fly->zlock != FLY_AXISLOCK_STATE_OFF) fly->zlock = FLY_AXISLOCK_STATE_ACTIVE; } if (fly->zlock == FLY_AXISLOCK_STATE_ACTIVE) { float upvec[3]; copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* make sure we have some z rolling */ if (fabsf(upvec[2]) > 0.00001f) { roll = upvec[2] * 5.0f; /* rotate the view about this axis */ copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, roll * time_redraw_clamped * fly->zlock_momentum * FLY_ZUP_CORRECT_FAC); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); fly->zlock_momentum += FLY_ZUP_CORRECT_ACCEL; } else { fly->zlock = FLY_AXISLOCK_STATE_IDLE; /* don't check until the view rotates again */ fly->zlock_momentum = 0.0f; } } /* only apply xcorrect when mouse isn't applying x rot */ if (fly->xlock == FLY_AXISLOCK_STATE_ACTIVE && moffset[1] == 0) { float upvec[3]; copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); mul_m3_v3(mat, upvec); /* make sure we have some z rolling */ if (fabsf(upvec[2]) > 0.00001f) { roll = upvec[2] * -5.0f; /* rotate the view about this axis */ copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, roll * time_redraw_clamped * fly->xlock_momentum * 0.1f); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); fly->xlock_momentum += 0.05f; } else { fly->xlock = FLY_AXISLOCK_STATE_IDLE; /* see above */ fly->xlock_momentum = 0.0f; } } if (fly->axis == -1) { /* pause */ zero_v3(dvec_tmp); } else if (!fly->use_freelook) { /* Normal operation */ /* define dvec, view direction vector */ zero_v3(dvec_tmp); /* move along the current axis */ dvec_tmp[fly->axis] = 1.0f; mul_m3_v3(mat, dvec_tmp); } else { normalize_v3_v3(dvec_tmp, fly->dvec_prev); if (fly->speed < 0.0f) { negate_v3(dvec_tmp); } } mul_v3_fl(dvec_tmp, fly->speed * time_redraw * 0.25f); } /* impose a directional lag */ interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * FLY_SMOOTH_FAC)))); if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control); if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0; if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0; if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0; } add_v3_v3(rv3d->ofs, dvec); if (rv3d->persp == RV3D_CAMOB) { const bool do_rotate = ((fly->xlock != FLY_AXISLOCK_STATE_OFF) || (fly->zlock != FLY_AXISLOCK_STATE_OFF) || ((moffset[0] || moffset[1]) && !fly->pan_view)); const bool do_translate = (fly->speed != 0.0f || fly->pan_view); flyMoveCamera(C, fly, do_rotate, do_translate); } } else { /* we're not redrawing but we need to update the time else the view will jump */ fly->time_lastdraw = PIL_check_seconds_timer(); } /* end drawing */ copy_v3_v3(fly->dvec_prev, dvec); } return OPERATOR_FINISHED; }
static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); rctf viewborder; float upvec[3]; /* tmp */ float mat[3][3]; fly->rv3d = CTX_wm_region_view3d(C); fly->v3d = CTX_wm_view3d(C); fly->ar = CTX_wm_region(C); fly->scene = CTX_data_scene(C); #ifdef NDOF_FLY_DEBUG puts("\n-- fly begin --"); #endif /* sanity check: for rare but possible case (if lib-linking the camera fails) */ if ((fly->rv3d->persp == RV3D_CAMOB) && (fly->v3d->camera == NULL)) { fly->rv3d->persp = RV3D_PERSP; } if (fly->rv3d->persp == RV3D_CAMOB && ID_IS_LINKED(fly->v3d->camera)) { BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library"); return false; } if (ED_view3d_offset_lock_check(fly->v3d, fly->rv3d)) { BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view offset is locked"); return false; } if (fly->rv3d->persp == RV3D_CAMOB && fly->v3d->camera->constraints.first) { BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints"); return false; } fly->state = FLY_RUNNING; fly->speed = 0.0f; fly->axis = 2; fly->pan_view = false; fly->xlock = FLY_AXISLOCK_STATE_OFF; fly->zlock = FLY_AXISLOCK_STATE_OFF; fly->xlock_momentum = 0.0f; fly->zlock_momentum = 0.0f; fly->grid = 1.0f; fly->use_precision = false; fly->use_freelook = false; #ifdef NDOF_FLY_DRAW_TOOMUCH fly->redraw = 1; #endif zero_v3(fly->dvec_prev); fly->timer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, 0.01f); copy_v2_v2_int(fly->mval, event->mval); #ifdef WITH_INPUT_NDOF fly->ndof = NULL; #endif fly->time_lastdraw = fly->time_lastwheel = PIL_check_seconds_timer(); fly->draw_handle_pixel = ED_region_draw_cb_activate(fly->ar->type, drawFlyPixel, fly, REGION_DRAW_POST_PIXEL); fly->rv3d->rflag |= RV3D_NAVIGATING; /* detect whether to start with Z locking */ copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); copy_m3_m4(mat, fly->rv3d->viewinv); mul_m3_v3(mat, upvec); if (fabsf(upvec[2]) < 0.1f) { fly->zlock = FLY_AXISLOCK_STATE_IDLE; } fly->v3d_camera_control = ED_view3d_cameracontrol_acquire( fly->scene, fly->v3d, fly->rv3d, (U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0); /* calculate center */ if (fly->scene->camera) { ED_view3d_calc_camera_border(fly->scene, fly->ar, fly->v3d, fly->rv3d, &viewborder, false); fly->width = BLI_rctf_size_x(&viewborder); fly->height = BLI_rctf_size_y(&viewborder); fly->center_mval[0] = viewborder.xmin + fly->width / 2; fly->center_mval[1] = viewborder.ymin + fly->height / 2; } else { fly->width = fly->ar->winx; fly->height = fly->ar->winy; fly->center_mval[0] = fly->width / 2; fly->center_mval[1] = fly->height / 2; } /* center the mouse, probably the UI mafia are against this but without its quite annoying */ WM_cursor_warp(win, fly->ar->winrct.xmin + fly->center_mval[0], fly->ar->winrct.ymin + fly->center_mval[1]); fly_update_header(C, op, fly); return 1; }
/* patching UserDef struct and Themes */ void BLO_version_defaults_userpref_blend(Main *bmain, UserDef *userdef) { #define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(bmain, ver, subver) /* the UserDef struct is not corrected with do_versions() .... ugh! */ if (userdef->wheellinescroll == 0) { userdef->wheellinescroll = 3; } if (userdef->menuthreshold1 == 0) { userdef->menuthreshold1 = 5; userdef->menuthreshold2 = 2; } if (userdef->mixbufsize == 0) { userdef->mixbufsize = 2048; } if (userdef->autokey_mode == 0) { /* 'add/replace' but not on */ userdef->autokey_mode = 2; } if (userdef->savetime <= 0) { userdef->savetime = 1; // XXX error(STRINGIFY(BLENDER_STARTUP_FILE)" is buggy, please consider removing it.\n"); } if (userdef->gizmo_size == 0) { userdef->gizmo_size = 75; userdef->gizmo_flag |= USER_GIZMO_DRAW; } if (userdef->pad_rot_angle == 0.0f) { userdef->pad_rot_angle = 15.0f; } /* graph editor - unselected F-Curve visibility */ if (userdef->fcu_inactive_alpha == 0) { userdef->fcu_inactive_alpha = 0.25f; } if (!USER_VERSION_ATLEAST(192, 0)) { strcpy(userdef->sounddir, "/"); } /* patch to set Dupli Armature */ if (!USER_VERSION_ATLEAST(220, 0)) { userdef->dupflag |= USER_DUP_ARM; } /* added seam, normal color, undo */ if (!USER_VERSION_ATLEAST(235, 0)) { userdef->uiflag |= USER_GLOBALUNDO; if (userdef->undosteps == 0) { userdef->undosteps = 32; } } if (!USER_VERSION_ATLEAST(236, 0)) { /* illegal combo... */ if (userdef->flag & USER_LMOUSESELECT) { userdef->flag &= ~USER_TWOBUTTONMOUSE; } } if (!USER_VERSION_ATLEAST(240, 0)) { userdef->uiflag |= USER_PLAINMENUS; } if (!USER_VERSION_ATLEAST(242, 0)) { /* set defaults for 3D View rotating axis indicator */ /* since size can't be set to 0, this indicates it's not saved in startup.blend */ if (userdef->rvisize == 0) { userdef->rvisize = 15; userdef->rvibright = 8; userdef->uiflag |= USER_SHOW_GIZMO_AXIS; } } if (!USER_VERSION_ATLEAST(244, 0)) { /* set default number of recently-used files (if not set) */ if (userdef->recent_files == 0) { userdef->recent_files = 10; } } if (!USER_VERSION_ATLEAST(245, 3)) { if (userdef->coba_weight.tot == 0) { BKE_colorband_init(&userdef->coba_weight, true); } } if (!USER_VERSION_ATLEAST(245, 3)) { userdef->flag |= USER_ADD_VIEWALIGNED | USER_ADD_EDITMODE; } if (!USER_VERSION_ATLEAST(250, 0)) { /* adjust grease-pencil distances */ userdef->gp_manhattendist = 1; userdef->gp_euclideandist = 2; /* adjust default interpolation for new IPO-curves */ userdef->ipo_new = BEZT_IPO_BEZ; } if (!USER_VERSION_ATLEAST(250, 3)) { /* new audio system */ if (userdef->audiochannels == 0) { userdef->audiochannels = 2; } if (userdef->audioformat == 0) { userdef->audioformat = 0x24; } if (userdef->audiorate == 0) { userdef->audiorate = 48000; } } if (!USER_VERSION_ATLEAST(250, 8)) { wmKeyMap *km; for (km = userdef->user_keymaps.first; km; km = km->next) { if (STREQ(km->idname, "Armature_Sketch")) { strcpy(km->idname, "Armature Sketch"); } else if (STREQ(km->idname, "View3D")) { strcpy(km->idname, "3D View"); } else if (STREQ(km->idname, "View3D Generic")) { strcpy(km->idname, "3D View Generic"); } else if (STREQ(km->idname, "EditMesh")) { strcpy(km->idname, "Mesh"); } else if (STREQ(km->idname, "UVEdit")) { strcpy(km->idname, "UV Editor"); } else if (STREQ(km->idname, "Animation_Channels")) { strcpy(km->idname, "Animation Channels"); } else if (STREQ(km->idname, "GraphEdit Keys")) { strcpy(km->idname, "Graph Editor"); } else if (STREQ(km->idname, "GraphEdit Generic")) { strcpy(km->idname, "Graph Editor Generic"); } else if (STREQ(km->idname, "Action_Keys")) { strcpy(km->idname, "Dopesheet"); } else if (STREQ(km->idname, "NLA Data")) { strcpy(km->idname, "NLA Editor"); } else if (STREQ(km->idname, "Node Generic")) { strcpy(km->idname, "Node Editor"); } else if (STREQ(km->idname, "Logic Generic")) { strcpy(km->idname, "Logic Editor"); } else if (STREQ(km->idname, "File")) { strcpy(km->idname, "File Browser"); } else if (STREQ(km->idname, "FileMain")) { strcpy(km->idname, "File Browser Main"); } else if (STREQ(km->idname, "FileButtons")) { strcpy(km->idname, "File Browser Buttons"); } else if (STREQ(km->idname, "Buttons Generic")) { strcpy(km->idname, "Property Editor"); } } } if (!USER_VERSION_ATLEAST(252, 3)) { if (userdef->flag & USER_LMOUSESELECT) { userdef->flag &= ~USER_TWOBUTTONMOUSE; } } if (!USER_VERSION_ATLEAST(252, 4)) { /* default new handle type is auto handles */ userdef->keyhandles_new = HD_AUTO; } if (!USER_VERSION_ATLEAST(257, 0)) { /* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs, * so that it doesn't linger around from old configs like a ghost */ userdef->autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET; } if (!USER_VERSION_ATLEAST(260, 3)) { /* if new keyframes handle default is stuff "auto", make it "auto-clamped" instead * was changed in 260 as part of GSoC11, but version patch was wrong */ if (userdef->keyhandles_new == HD_AUTO) { userdef->keyhandles_new = HD_AUTO_ANIM; } /* enable (Cycles) addon by default */ BKE_addon_ensure(&userdef->addons, "cycles"); } if (!USER_VERSION_ATLEAST(267, 0)) { /* GL Texture Garbage Collection */ if (userdef->textimeout == 0) { userdef->texcollectrate = 60; userdef->textimeout = 120; } if (userdef->memcachelimit <= 0) { userdef->memcachelimit = 32; } if (userdef->dbl_click_time == 0) { userdef->dbl_click_time = 350; } if (userdef->v2d_min_gridsize == 0) { userdef->v2d_min_gridsize = 35; } if (userdef->widget_unit == 0) { userdef->widget_unit = 20; } if (userdef->anisotropic_filter <= 0) { userdef->anisotropic_filter = 1; } if (userdef->ndof_sensitivity == 0.0f) { userdef->ndof_sensitivity = 1.0f; userdef->ndof_flag = (NDOF_LOCK_HORIZON | NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE); } if (userdef->ndof_orbit_sensitivity == 0.0f) { userdef->ndof_orbit_sensitivity = userdef->ndof_sensitivity; if (!(userdef->flag & USER_TRACKBALL)) { userdef->ndof_flag |= NDOF_TURNTABLE; } } } /* NOTE!! from now on use userdef->versionfile and userdef->subversionfile */ #undef USER_VERSION_ATLEAST #define USER_VERSION_ATLEAST(ver, subver) MAIN_VERSION_ATLEAST(userdef, ver, subver) if (!USER_VERSION_ATLEAST(271, 5)) { userdef->pie_menu_radius = 100; userdef->pie_menu_threshold = 12; userdef->pie_animation_timeout = 6; } if (!USER_VERSION_ATLEAST(275, 2)) { userdef->ndof_deadzone = 0.1; } if (!USER_VERSION_ATLEAST(275, 4)) { userdef->node_margin = 80; } if (!USER_VERSION_ATLEAST(278, 6)) { /* Clear preference flags for re-use. */ userdef->flag &= ~(USER_FLAG_NUMINPUT_ADVANCED | USER_FLAG_UNUSED_2 | USER_FLAG_UNUSED_3 | USER_FLAG_UNUSED_6 | USER_FLAG_UNUSED_7 | USER_FLAG_UNUSED_9 | USER_DEVELOPER_UI); userdef->uiflag &= ~(USER_HEADER_BOTTOM); userdef->transopts &= ~(USER_TR_UNUSED_2 | USER_TR_UNUSED_3 | USER_TR_UNUSED_4 | USER_TR_UNUSED_6 | USER_TR_UNUSED_7); userdef->uiflag |= USER_LOCK_CURSOR_ADJUST; } if (!USER_VERSION_ATLEAST(280, 20)) { userdef->gpu_viewport_quality = 0.6f; /* Reset theme, old themes will not be compatible with minor version updates from now on. */ for (bTheme *btheme = userdef->themes.first; btheme; btheme = btheme->next) { memcpy(btheme, &U_theme_default, sizeof(*btheme)); } /* Annotations - new layer color * Replace anything that used to be set if it looks like was left * on the old default (i.e. black), which most users used */ if ((userdef->gpencil_new_layer_col[3] < 0.1f) || (userdef->gpencil_new_layer_col[0] < 0.1f)) { /* - New color matches the annotation pencil icon * - Non-full alpha looks better! */ ARRAY_SET_ITEMS(userdef->gpencil_new_layer_col, 0.38f, 0.61f, 0.78f, 0.9f); } } if (!USER_VERSION_ATLEAST(280, 31)) { /* Remove select/action mouse from user defined keymaps. */ for (wmKeyMap *keymap = userdef->user_keymaps.first; keymap; keymap = keymap->next) { for (wmKeyMapDiffItem *kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) { if (kmdi->remove_item) { do_version_select_mouse(userdef, kmdi->remove_item); } if (kmdi->add_item) { do_version_select_mouse(userdef, kmdi->add_item); } } for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { do_version_select_mouse(userdef, kmi); } } } if (!USER_VERSION_ATLEAST(280, 33)) { /* Enable GLTF addon by default. */ BKE_addon_ensure(&userdef->addons, "io_scene_gltf2"); } if (!USER_VERSION_ATLEAST(280, 35)) { /* Preserve RMB select setting after moving to Python and changing default value. */ if (USER_VERSION_ATLEAST(280, 32) || !(userdef->flag & USER_LMOUSESELECT)) { BKE_keyconfig_pref_set_select_mouse(userdef, 1, false); } userdef->flag &= ~USER_LMOUSESELECT; } if (!USER_VERSION_ATLEAST(280, 38)) { /* (keep this block even if it becomes empty). */ copy_v4_fl4(userdef->light_param[0].vec, -0.580952, 0.228571, 0.781185, 0.0); copy_v4_fl4(userdef->light_param[0].col, 0.900000, 0.900000, 0.900000, 1.000000); copy_v4_fl4(userdef->light_param[0].spec, 0.318547, 0.318547, 0.318547, 1.000000); userdef->light_param[0].flag = 1; userdef->light_param[0].smooth = 0.1; copy_v4_fl4(userdef->light_param[1].vec, 0.788218, 0.593482, -0.162765, 0.0); copy_v4_fl4(userdef->light_param[1].col, 0.267115, 0.269928, 0.358840, 1.000000); copy_v4_fl4(userdef->light_param[1].spec, 0.090838, 0.090838, 0.090838, 1.000000); userdef->light_param[1].flag = 1; userdef->light_param[1].smooth = 0.25; copy_v4_fl4(userdef->light_param[2].vec, 0.696472, -0.696472, -0.172785, 0.0); copy_v4_fl4(userdef->light_param[2].col, 0.293216, 0.304662, 0.401968, 1.000000); copy_v4_fl4(userdef->light_param[2].spec, 0.069399, 0.020331, 0.020331, 1.000000); userdef->light_param[2].flag = 1; userdef->light_param[2].smooth = 0.4; copy_v4_fl4(userdef->light_param[3].vec, 0.021053, -0.989474, 0.143173, 0.0); copy_v4_fl4(userdef->light_param[3].col, 0.0, 0.0, 0.0, 1.0); copy_v4_fl4(userdef->light_param[3].spec, 0.072234, 0.082253, 0.162642, 1.000000); userdef->light_param[3].flag = 1; userdef->light_param[3].smooth = 0.7; copy_v3_fl3(userdef->light_ambient, 0.025000, 0.025000, 0.025000); userdef->flag &= ~(USER_FLAG_UNUSED_4); userdef->uiflag &= ~(USER_HEADER_FROM_PREF | USER_UIFLAG_UNUSED_12 | USER_UIFLAG_UNUSED_22); } if (!USER_VERSION_ATLEAST(280, 41)) { /* (keep this block even if it becomes empty). */ if (userdef->pie_tap_timeout == 0) { userdef->pie_tap_timeout = 20; } } if (!USER_VERSION_ATLEAST(280, 44)) { userdef->uiflag &= ~(USER_UIFLAG_UNUSED_0 | USER_UIFLAG_UNUSED_1); userdef->uiflag2 &= ~(USER_UIFLAG2_UNUSED_0); userdef->gp_settings &= ~(GP_PAINT_UNUSED_0); } if (!USER_VERSION_ATLEAST(280, 50)) { /* 3ds is no longer enabled by default and not ported yet. */ BKE_addon_remove_safe(&userdef->addons, "io_scene_3ds"); } if (!USER_VERSION_ATLEAST(280, 51)) { userdef->move_threshold = 2; } if (!USER_VERSION_ATLEAST(280, 58)) { if (userdef->image_draw_method != IMAGE_DRAW_METHOD_GLSL) { userdef->image_draw_method = IMAGE_DRAW_METHOD_AUTO; } } /* patch to set Dupli Lightprobes and Grease Pencil */ if (!USER_VERSION_ATLEAST(280, 58)) { userdef->dupflag |= USER_DUP_LIGHTPROBE; userdef->dupflag |= USER_DUP_GPENCIL; } if (!USER_VERSION_ATLEAST(280, 60)) { const float GPU_VIEWPORT_QUALITY_FXAA = 0.10f; const float GPU_VIEWPORT_QUALITY_TAA8 = 0.25f; const float GPU_VIEWPORT_QUALITY_TAA16 = 0.6f; const float GPU_VIEWPORT_QUALITY_TAA32 = 0.8f; if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_FXAA) { userdef->viewport_aa = SCE_DISPLAY_AA_OFF; } else if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_TAA8) { userdef->viewport_aa = SCE_DISPLAY_AA_FXAA; } else if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_TAA16) { userdef->viewport_aa = SCE_DISPLAY_AA_SAMPLES_8; } else if (userdef->gpu_viewport_quality <= GPU_VIEWPORT_QUALITY_TAA32) { userdef->viewport_aa = SCE_DISPLAY_AA_SAMPLES_16; } else { userdef->viewport_aa = SCE_DISPLAY_AA_SAMPLES_32; } } if (!USER_VERSION_ATLEAST(280, 62)) { /* (keep this block even if it becomes empty). */ if (userdef->vbotimeout == 0) { userdef->vbocollectrate = 60; userdef->vbotimeout = 120; } if (userdef->lookdev_sphere_size == 0) { userdef->lookdev_sphere_size = 150; } userdef->pref_flag |= USER_PREF_FLAG_SAVE; } if (!USER_VERSION_ATLEAST(280, 73)) { userdef->drag_threshold = 30; userdef->drag_threshold_mouse = 3; userdef->drag_threshold_tablet = 10; } /** * Include next version bump. */ { /* pass */ } if (userdef->pixelsize == 0.0f) { userdef->pixelsize = 1.0f; } for (bTheme *btheme = userdef->themes.first; btheme; btheme = btheme->next) { do_versions_theme(userdef, btheme); } #undef USER_VERSION_ATLEAST }
/** * Iterates over ALL objects in the scene and all of its sets, including * making all duplis(not only metas). Copies metas to mainb array. * Computes bounding boxes for building BVH. */ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) { Scene *sce_iter = scene; Base *base; Object *bob; MetaBall *mb; const MetaElem *ml; float obinv[4][4], obmat[4][4]; unsigned int i; int obnr, zero_size = 0; char obname[MAX_ID_NAME]; SceneBaseIter iter; copy_m4_m4(obmat, ob->obmat); /* to cope with duplicators from BKE_scene_base_iter_next */ invert_m4_m4(obinv, ob->obmat); BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); /* make main array */ BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &bob)) { if (bob->type == OB_MBALL) { zero_size = 0; ml = NULL; if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { mb = ob->data; if (mb->editelems) ml = mb->editelems->first; else ml = mb->elems.first; } else { char name[MAX_ID_NAME]; int nr; BLI_split_name_num(name, &nr, bob->id.name + 2, '.'); if (STREQ(obname, name)) { mb = bob->data; if (mb->editelems) ml = mb->editelems->first; else ml = mb->elems.first; } } /* when metaball object has zero scale, then MetaElem to this MetaBall * will not be put to mainb array */ if (has_zero_axis_m4(bob->obmat)) { zero_size = 1; } else if (bob->parent) { struct Object *pob = bob->parent; while (pob) { if (has_zero_axis_m4(pob->obmat)) { zero_size = 1; break; } pob = pob->parent; } } if (zero_size) { while (ml) { ml = ml->next; } } else { while (ml) { if (!(ml->flag & MB_HIDE)) { float pos[4][4], rot[4][4]; float expx, expy, expz; float tempmin[3], tempmax[3]; MetaElem *new_ml; /* make a copy because of duplicates */ new_ml = BLI_memarena_alloc(process->pgn_elements, sizeof(MetaElem)); *(new_ml) = *ml; new_ml->bb = BLI_memarena_alloc(process->pgn_elements, sizeof(BoundBox)); new_ml->mat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); /* too big stiffness seems only ugly due to linear interpolation * no need to have possibility for too big stiffness */ if (ml->s > 10.0f) new_ml->s = 10.0f; else new_ml->s = ml->s; /* if metaball is negative, set stiffness negative */ if (new_ml->flag & MB_NEGATIVE) new_ml->s = -new_ml->s; /* Translation of MetaElem */ unit_m4(pos); pos[3][0] = ml->x; pos[3][1] = ml->y; pos[3][2] = ml->z; /* Rotation of MetaElem is stored in quat */ quat_to_mat4(rot, ml->quat); /* basis object space -> world -> ml object space -> position -> rotation -> ml local space */ mul_m4_series((float(*)[4])new_ml->mat, obinv, bob->obmat, pos, rot); /* ml local space -> basis object space */ invert_m4_m4((float(*)[4])new_ml->imat, (float(*)[4])new_ml->mat); /* rad2 is inverse of squared radius */ new_ml->rad2 = 1 / (ml->rad * ml->rad); /* initial dimensions = radius */ expx = ml->rad; expy = ml->rad; expz = ml->rad; switch (ml->type) { case MB_BALL: break; case MB_CUBE: /* cube is "expanded" by expz, expy and expx */ expz += ml->expz; /* fall through */ case MB_PLANE: /* plane is "expanded" by expy and expx */ expy += ml->expy; /* fall through */ case MB_TUBE: /* tube is "expanded" by expx */ expx += ml->expx; break; case MB_ELIPSOID: /* ellipsoid is "stretched" by exp* */ expx *= ml->expx; expy *= ml->expy; expz *= ml->expz; break; } /* untransformed Bounding Box of MetaElem */ /* TODO, its possible the elem type has been changed and the exp* values can use a fallback */ copy_v3_fl3(new_ml->bb->vec[0], -expx, -expy, -expz); /* 0 */ copy_v3_fl3(new_ml->bb->vec[1], +expx, -expy, -expz); /* 1 */ copy_v3_fl3(new_ml->bb->vec[2], +expx, +expy, -expz); /* 2 */ copy_v3_fl3(new_ml->bb->vec[3], -expx, +expy, -expz); /* 3 */ copy_v3_fl3(new_ml->bb->vec[4], -expx, -expy, +expz); /* 4 */ copy_v3_fl3(new_ml->bb->vec[5], +expx, -expy, +expz); /* 5 */ copy_v3_fl3(new_ml->bb->vec[6], +expx, +expy, +expz); /* 6 */ copy_v3_fl3(new_ml->bb->vec[7], -expx, +expy, +expz); /* 7 */ /* transformation of Metalem bb */ for (i = 0; i < 8; i++) mul_m4_v3((float(*)[4])new_ml->mat, new_ml->bb->vec[i]); /* find max and min of transformed bb */ INIT_MINMAX(tempmin, tempmax); for (i = 0; i < 8; i++) { DO_MINMAX(new_ml->bb->vec[i], tempmin, tempmax); } /* set only point 0 and 6 - AABB of Metaelem */ copy_v3_v3(new_ml->bb->vec[0], tempmin); copy_v3_v3(new_ml->bb->vec[6], tempmax); /* add new_ml to mainb[] */ if (UNLIKELY(process->totelem == process->mem)) { process->mem = process->mem * 2 + 10; process->mainb = MEM_reallocN(process->mainb, sizeof(MetaElem *) * process->mem); } process->mainb[process->totelem++] = new_ml; } ml = ml->next; } } } } /* compute AABB of all Metaelems */ if (process->totelem > 0) { copy_v3_v3(process->allbb.min, process->mainb[0]->bb->vec[0]); copy_v3_v3(process->allbb.max, process->mainb[0]->bb->vec[6]); for (i = 1; i < process->totelem; i++) make_box_union(process->mainb[i]->bb, &process->allbb, &process->allbb); } }