Exemple #1
0
static void UpdateCamera(fplbase::InputSystem* input, Camera* camera) {
  const fplbase::InputPointer& pointer = input->get_pointers()[0];
  if (!pointer.used) return;

  // Update latitude and longitude: left mouse drag.
  if (input->GetButton(fplbase::K_POINTER1).is_down() &&
      pointer.mousedelta != mathfu::kZeros2i) {
    const float lat = camera->latitude.ToRadians() +
                      pointer.mousedelta.y * kLatitudeSensitivity;
    camera->latitude = Angle(mathfu::Clamp(lat, -kMaxLatitude, kMaxLatitude));
    camera->longitude += Angle(pointer.mousedelta.x * kLongitudeSensitivity);
  }

  // Update distance: right mouse drag.
  // (Unfortunately, InputSystem doesn't support scroll wheels yet)
  if (input->GetButton(fplbase::K_POINTER3).is_down() &&
      pointer.mousedelta != mathfu::kZeros2i) {
    const float dist = camera->distance +
                       (pointer.mousedelta.x + pointer.mousedelta.y) *
                           kDistanceSensitivity;
    camera->distance = std::max(dist, camera->z_near);
  }

  // Update target: middle mouse drag.
  if (input->GetButton(fplbase::K_POINTER2).is_down() &&
      pointer.mousedelta != mathfu::kZeros2i) {
    const vec3 right = CameraRight(*camera);
    const vec3 up = VectorSystemUp(camera->coordinate_system);
    const vec2 dist = kTargetSensitivity * vec2(pointer.mousedelta);
    camera->target += dist[0] * right + dist[1] * up;
  }
}
Exemple #2
0
void TestToVectorSystem(const AngleToVectorSystem system, const int zero_axis,
                        const int ninety_axis, const int ignored_axis) {
  // Angle zero should translate to the zero axis.
  const vec3 zero = Angle(0.0f).ToVectorSystem(system);
  EXPECT_NEAR(zero[zero_axis], 1.0f, kUnitVectorPrecision);
  EXPECT_NEAR(zero[ninety_axis], 0.0f, kUnitVectorPrecision);
  EXPECT_NEAR(zero[ignored_axis], 0.0f, kUnitVectorPrecision);

  // Angle 180 should translate to the negative zero axis.
  const vec3 minus_zero = Angle(kPi).ToVectorSystem(system);
  EXPECT_NEAR(minus_zero[zero_axis], -1.0f, kUnitVectorPrecision);
  EXPECT_NEAR(minus_zero[ninety_axis], 0.0f, kUnitVectorPrecision);
  EXPECT_NEAR(minus_zero[ignored_axis], 0.0f, kUnitVectorPrecision);

  // Angle 90 should translate to the 90 axis.
  const vec3 ninety = Angle(kHalfPi).ToVectorSystem(system);
  EXPECT_NEAR(ninety[zero_axis], 0.0f, kUnitVectorPrecision);
  EXPECT_NEAR(ninety[ninety_axis], 1.0f, kUnitVectorPrecision);
  EXPECT_NEAR(ninety[ignored_axis], 0.0f, kUnitVectorPrecision);

  // Angle -90 should translate to the -90 axis.
  const vec3 minus_ninety = Angle(-kHalfPi).ToVectorSystem(system);
  EXPECT_NEAR(minus_ninety[zero_axis], 0.0f, kUnitVectorPrecision);
  EXPECT_NEAR(minus_ninety[ninety_axis], -1.0f, kUnitVectorPrecision);
  EXPECT_NEAR(minus_ninety[ignored_axis], 0.0f, kUnitVectorPrecision);

  // Angle 45 should translate to a unit vector between the 0 and 90 axes.
  const vec3 forty_five = Angle(kQuarterPi).ToVectorSystem(system);
  const float one_over_root_two = 1.0f / sqrt(2.0f);
  EXPECT_NEAR(forty_five[zero_axis], one_over_root_two, kUnitVectorPrecision);
  EXPECT_NEAR(forty_five[ninety_axis], one_over_root_two, kUnitVectorPrecision);
  EXPECT_NEAR(forty_five[ignored_axis], 0.0f, kUnitVectorPrecision);
}
Exemple #3
0
int main() {

  // Since we use the ‘smooth’ animation algorithm, we must register it.
  motive::SmoothInit::Register();

  // The engine is the central place for animation data.
  motive::MotiveEngine engine;

  // In this example, we animate a one-dimensional floating point value.
  motive::Motivator1f facing_angle;

  // Initialize facing_angle Motivator to animate as a 'Smooth' Motivator.
  // Alternatively, we could initialize as an 'Overshoot' Motivator. All
  // Motivator types have the same interface. Internally, they are animated
  // with different algorithms, and they will move differently towards their
  // targets. However, to switch between Motivator types it is a simple matter
  // of initializing with a different kind of MotiveInit struct.
  //
  // Angles wrap around with modular arithmetic. That is, -pi is equivalent to
  // pi. Valid range for angles is -pi..pi, inclusive of +pi and exclusive of
  // -pi.
  const motive::SmoothInit init(Range(-kPi, kPi), true);
  facing_angle.Initialize(init, &engine);

  // Set initial state of the Motivator, and the target parameters.
  // 'Smooth' Motivators animate to a target-value in a target-time. Not all
  // types of Motivators use all target data.
  const Angle start = Angle::FromDegrees(120.0f);
  const float start_angular_velocity = 0.0f;
  const Angle target = Angle::FromDegrees(-120.0f);
  const float target_angular_velocity = 0.0f;
  const motive::MotiveTime target_time = 100;
  const motive::MotiveTime delta_time = 1;
  facing_angle.SetTarget(
      motive::CurrentToTarget1f(start.ToRadians(), start_angular_velocity,
                                target.ToRadians(), target_angular_velocity,
                                target_time));

  std::vector<vec2> points(target_time / delta_time + 1);
  for (motive::MotiveTime t = 0; t <= target_time; t += delta_time) {
    // All Motivators created with 'engine' are animated here.
    engine.AdvanceFrame(delta_time);

    // The current value of the variable being animated is always available.
    const Angle angle_at_t = Angle::FromWithinThreePi(facing_angle.Value());
    points.push_back(
        vec2(static_cast<float>(t), angle_at_t.ToDegrees()));
  }

  printf("\n%s", Graph2DPoints(&points[0], points.size()).c_str());
  return 0;
}
Exemple #4
0
  MotiveBenchmarker() {
    MatrixInit::Register();
    SplineInit::Register();

    // Create compact splines by modifying some basic functions (straight
    // line and sign wave). The straight line, in this case, represents an
    // angle that travels a total of 2pi, so it ends up where it started.
    CreateSpline(kStraightLine, MOTIVE_ARRAY_SIZE(kStraightLine),
                 kLinearOrbitPeriod, kTwoPi, &splines_[kLinearOrbit]);
    CreateSpline(kSinWave, MOTIVE_ARRAY_SIZE(kSinWave),
                 kOscillatingSlowlyPeriod, kOscillatingSlowlyAmplitude,
                 &splines_[kOscillatingSlowly]);
    CreateSpline(kSinWave, MOTIVE_ARRAY_SIZE(kSinWave),
                 kOscillatingQuicklyPeriod, kOscillatingQuicklyAmplitude,
                 &splines_[kOscillatingQuickly]);

    // Create a matrix initializer with a series of basic matrix operations.
    // The final matrix will be created by applying these operations, in turn.
    matrix_ops_.AddOp(motive::kRotateAboutY, kRotateInit,
                      splines_[kLinearOrbit]);
    matrix_ops_.AddOp(motive::kTranslateX, kTranslateInit,
                      splines_[kOscillatingSlowly]);
    matrix_ops_.AddOp(motive::kTranslateY, kTranslateInit,
                      splines_[kOscillatingQuickly]);

    // Initialize the large array of matrix motivators. Note that the
    // one dimensional motivators that drive the matrix motivators are created
    // by the matrix motivators themselves.
    for (size_t i = 0; i < kNumMatrices; ++i) {
      MatrixMotivator4f& m = matrices_[i];
      m.Initialize(MatrixInit(matrix_ops_), &engine_);
    }
  }
Exemple #5
0
 virtual void SetUp()
 {
   above_pi_ = MinutelyDifferentFloat(kPi, 1);
   below_pi_ = MinutelyDifferentFloat(kPi, -1);
   above_negative_pi_ = MinutelyDifferentFloat(-kPi, -1);
   below_negative_pi_ = MinutelyDifferentFloat(-kPi, 1);
   half_pi_ = Angle(kHalfPi);
 }
Exemple #6
0
 virtual void SetUp() {
   short_spline_.Init(Range(0.0f, 1.0f), 0.01f);
   short_spline_.AddNode(0.0f, 0.1f, 0.0f, motive::kAddWithoutModification);
   short_spline_.AddNode(1.0f, 0.4f, 0.0f, motive::kAddWithoutModification);
   short_spline_.AddNode(4.0f, 0.2f, 0.0f, motive::kAddWithoutModification);
   short_spline_.AddNode(40.0f, 0.2f, 0.0f, motive::kAddWithoutModification);
   short_spline_.AddNode(100.0f, 1.0f, 0.0f, motive::kAddWithoutModification);
 }
Exemple #7
0
// Take an array of SplineNodes (x, y, derivative) values and scale them
// to create a CompactSpline. We use Dual Cubic interpolation to ensure that
// the splines are well behaved.
static void CreateSpline(const SplineNode* nodes, size_t num_nodes,
                         float x_scale, float y_scale, CompactSpline* spline) {
  // Find y-extremes.
  float min = std::numeric_limits<float>::infinity();
  float max = -std::numeric_limits<float>::infinity();
  for (size_t i = 0; i < num_nodes; ++i) {
    min = std::min(nodes[i].y, min);
    max = std::max(nodes[i].y, max);
  }

  // Initialize the spline such that it's bounds are tight to the data.
  spline->Init(
      Range(y_scale * min, y_scale * max),
      CompactSpline::RecommendXGranularity(x_scale * nodes[num_nodes - 1].x));

  // Scale each node and add it to the curve.
  for (size_t i = 0; i < num_nodes; ++i) {
    const SplineNode& n = nodes[i];
    spline->AddNode(n.x * x_scale, n.y * y_scale, n.derivative / x_scale);
  }
}
Exemple #8
0
int main() {
  std::vector<vec2> points;
  points.reserve(100);

  // Since we will be using the ‘smooth’ animation algorithm, we must register
  // it with the engine.
  SmoothInit::Register();

  // The engine is the central place where animation data is stored and
  // processed.
  MotiveEngine motive_engine;

  //! [Duck Example]
  // Initialize the Motivator to use the "smooth" animation algorithm.
  Motivator2f duck_position;
  duck_position.InitializeWithTarget(SmoothInit(), &motive_engine,
                                     Tar2f::Current(kDuckStartPosition));

  // Smoothly transition the duck to wherever a touch occurs.
  while (FollowDuck()) {
    vec2 touch_position;
    if (ScreenTouch(&touch_position)) {
      // Set the duck's target position, velocity, and time.
      duck_position.SetTarget(Tar2f::Target(touch_position, kZeros2f,
                                            kTimeToTouchPosition));
    }

    // Once per frame, motive_engine.AdvanceFrame() is called to animate *all*
    // Motivators at once. In this case, we only have one Motivator,
    // but in many applications there will be thousands.
    motive_engine.AdvanceFrame(kDeltaTime);

    // Draw the duck at its current position.
    // Use the velocity to draw motion lines behind the duck, too.
    DrawDuck(duck_position.Value(), duck_position.Velocity());
  }
  //! [Duck Example]
  return 0;
}
Exemple #9
0
// Unary negate should send pi to pi, because -pi is not in range.
TEST_F(AngleTests, NegatePi) {
  const Angle a = Angle(kPi);
  const Angle negative_a = -a;
  EXPECT_FLOAT_EQ(negative_a.ToRadians(), kPi);
}
Exemple #10
0
// Unary negate should change the sign.
TEST_F(AngleTests, Negate) {
  const Angle a = Angle(kHalfPi);
  EXPECT_FLOAT_EQ(-a.ToRadians(), -kHalfPi);
}
Exemple #11
0
using motive::CubicCurve;
using motive::CubicInit;
using motive::kPi;
using motive::kTwoPi;
using motive::QuadraticCurve;
using motive::Range;
using motive::SplinePlayback;
using mathfu::vec2;
using mathfu::vec2i;
using motive::MotiveEngine;
using motive::MatrixInit;
using motive::MatrixOpArray;
using motive::MatrixMotivator4f;
using motive::SplineInit;

static const SplineInit kRotateInit(Range(-kPi, kPi), true);
static const SplineInit kTranslateInit(Range(-1.0f, 1.0f), true);
static const int kNumBenchmarkIds = 10;

struct SplineNode {
  float x;
  float y;
  float derivative;
};

static const SplineNode kSinWave[] = {{0.0f, 0.0f, 1.0f},
                                      {0.5f * kPi, 1.0f, 0.0f},
                                      {kPi, 0.0f, -1.0f},
                                      {1.5f * kPi, -1.0f, 0.0f},
                                      {kTwoPi, 0.0f, 1.0f}};
Exemple #12
0
static const CubicInit CubicInitScaleX(const CubicInit& init, float scale) {
  return CubicInit(init.start_y, init.start_derivative / scale, init.end_y,
                   init.end_derivative / scale, init.width_x * scale);
}
Exemple #13
0
static const CubicInit CubicInitMirrorY(const CubicInit& init) {
  return CubicInit(-init.start_y, -init.start_derivative, -init.end_y,
                   -init.end_derivative, init.width_x);
}
Exemple #14
0
static const float kDerivativePrecision = 0.01f;
static const float kSecondDerivativePrecision = 0.26f;
static const float kThirdDerivativePrecision = 6.0f;
static const float kNodeXPrecision = 0.0001f;
static const float kNodeYPrecision = 0.0001f;
static const float kXGranularityScale = 0.01f;
static const Range kAngleRange(-kPi, kPi);

// Use a ridiculous index that will never hit when doing a search.
// We use this to test the binary search algorithm, not the cache.
static const CompactSplineIndex kRidiculousSplineIndex = 10000;

static const CubicInit kSimpleSplines[] = {
    //    start_y         end_y        width_x
    //      start_derivative  end_derivative
    CubicInit(0.0f, 1.0f, 0.1f, 0.0f, 1.0f),
    CubicInit(1.0f, -8.0f, 0.0f, 0.0f, 1.0f),
    CubicInit(1.0f, -8.0f, -1.0f, 0.0f, 1.0f),
};
static const int kNumSimpleSplines =
    static_cast<int>(MOTIVE_ARRAY_SIZE(kSimpleSplines));

static const CubicInit CubicInitMirrorY(const CubicInit& init) {
  return CubicInit(-init.start_y, -init.start_derivative, -init.end_y,
                   -init.end_derivative, init.width_x);
}

static const CubicInit CubicInitScaleX(const CubicInit& init, float scale) {
  return CubicInit(init.start_y, init.start_derivative / scale, init.end_y,
                   init.end_derivative / scale, init.width_x * scale);
}