| /* |
| * Copyright 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| //---------------------------------------------------------- |
| // tapCamera.cpp |
| // Camera control with tap |
| // |
| //---------------------------------------------------------- |
| #include <fstream> |
| #include "tapCamera.h" |
| |
| namespace ndk_helper |
| { |
| |
| const float TRANSFORM_FACTOR = 15.f; |
| const float TRANSFORM_FACTORZ = 10.f; |
| |
| const float MOMENTUM_FACTOR_DECREASE = 0.85f; |
| const float MOMENTUM_FACTOR_DECREASE_SHIFT = 0.9f; |
| const float MOMENTUM_FACTOR = 0.8f; |
| const float MOMENTUM_FACTOR_THRESHOLD = 0.001f; |
| |
| //---------------------------------------------------------- |
| // Ctor |
| //---------------------------------------------------------- |
| TapCamera::TapCamera() : |
| dragging_( false ), |
| pinching_( false ), |
| momentum_( false ), |
| ball_radius_( 0.75f ), |
| pinch_start_distance_SQ_( 0.f ), |
| camera_rotation_( 0.f ), |
| camera_rotation_start_( 0.f ), |
| camera_rotation_now_( 0.f ), |
| momemtum_steps_( 0.f ), |
| flip_z_( 0.f ) |
| { |
| //Init offset |
| InitParameters(); |
| |
| vec_flip_ = Vec2( 1.f, -1.f ); |
| flip_z_ = -1.f; |
| vec_pinch_transform_factor_ = Vec3( 1.f, 1.f, 1.f ); |
| |
| vec_ball_center_ = Vec2( 0, 0 ); |
| vec_ball_now_ = Vec2( 0, 0 ); |
| vec_ball_down_ = Vec2( 0, 0 ); |
| |
| vec_pinch_start_ = Vec2( 0, 0 ); |
| vec_pinch_start_center_ = Vec2( 0, 0 ); |
| |
| vec_flip_ = Vec2( 0, 0 ); |
| |
| } |
| |
| void TapCamera::InitParameters() |
| { |
| //Init parameters |
| vec_offset_ = Vec3(); |
| vec_offset_now_ = Vec3(); |
| |
| quat_ball_rot_ = Quaternion(); |
| quat_ball_now_ = Quaternion(); |
| quat_ball_now_.ToMatrix( mat_rotation_ ); |
| camera_rotation_ = 0.f; |
| |
| vec_drag_delta_ = Vec2(); |
| vec_offset_delta_ = Vec3(); |
| |
| momentum_ = false; |
| } |
| |
| //---------------------------------------------------------- |
| // Dtor |
| //---------------------------------------------------------- |
| TapCamera::~TapCamera() |
| { |
| |
| } |
| |
| void TapCamera::Update() |
| { |
| if( momentum_ ) |
| { |
| float momenttum_steps = momemtum_steps_; |
| |
| //Momentum rotation |
| Vec2 v = vec_drag_delta_; |
| BeginDrag( Vec2() ); //NOTE:This call reset _VDragDelta |
| Drag( v * vec_flip_ ); |
| |
| //Momentum shift |
| vec_offset_ += vec_offset_delta_; |
| |
| BallUpdate(); |
| EndDrag(); |
| |
| //Decrease deltas |
| vec_drag_delta_ = v * MOMENTUM_FACTOR_DECREASE; |
| vec_offset_delta_ = vec_offset_delta_ * MOMENTUM_FACTOR_DECREASE_SHIFT; |
| |
| //Count steps |
| momemtum_steps_ = momenttum_steps * MOMENTUM_FACTOR_DECREASE; |
| if( momemtum_steps_ < MOMENTUM_FACTOR_THRESHOLD ) |
| { |
| momentum_ = false; |
| } |
| } |
| else |
| { |
| vec_drag_delta_ *= MOMENTUM_FACTOR; |
| vec_offset_delta_ = vec_offset_delta_ * MOMENTUM_FACTOR; |
| BallUpdate(); |
| } |
| |
| Vec3 vec = vec_offset_ + vec_offset_now_; |
| Vec3 vec_tmp( TRANSFORM_FACTOR, -TRANSFORM_FACTOR, TRANSFORM_FACTORZ ); |
| |
| vec *= vec_tmp * vec_pinch_transform_factor_; |
| |
| mat_transform_ = Mat4::Translation( vec ); |
| } |
| |
| Mat4& TapCamera::GetRotationMatrix() |
| { |
| return mat_rotation_; |
| } |
| |
| Mat4& TapCamera::GetTransformMatrix() |
| { |
| return mat_transform_; |
| } |
| |
| void TapCamera::Reset( const bool bAnimate ) |
| { |
| InitParameters(); |
| Update(); |
| |
| } |
| |
| //---------------------------------------------------------- |
| //Drag control |
| //---------------------------------------------------------- |
| void TapCamera::BeginDrag( const Vec2& v ) |
| { |
| if( dragging_ ) |
| EndDrag(); |
| |
| if( pinching_ ) |
| EndPinch(); |
| |
| Vec2 vec = v * vec_flip_; |
| vec_ball_now_ = vec; |
| vec_ball_down_ = vec_ball_now_; |
| |
| dragging_ = true; |
| momentum_ = false; |
| vec_last_input_ = vec; |
| vec_drag_delta_ = Vec2(); |
| } |
| |
| void TapCamera::EndDrag() |
| { |
| quat_ball_down_ = quat_ball_now_; |
| quat_ball_rot_ = Quaternion(); |
| |
| dragging_ = false; |
| momentum_ = true; |
| momemtum_steps_ = 1.0f; |
| } |
| |
| void TapCamera::Drag( const Vec2& v ) |
| { |
| if( !dragging_ ) |
| return; |
| |
| Vec2 vec = v * vec_flip_; |
| vec_ball_now_ = vec; |
| |
| vec_drag_delta_ = vec_drag_delta_ * MOMENTUM_FACTOR + (vec - vec_last_input_); |
| vec_last_input_ = vec; |
| } |
| |
| //---------------------------------------------------------- |
| //Pinch controll |
| //---------------------------------------------------------- |
| void TapCamera::BeginPinch( const Vec2& v1, const Vec2& v2 ) |
| { |
| if( dragging_ ) |
| EndDrag(); |
| |
| if( pinching_ ) |
| EndPinch(); |
| |
| BeginDrag( Vec2() ); |
| |
| vec_pinch_start_center_ = (v1 + v2) / 2.f; |
| |
| Vec2 vec = v1 - v2; |
| float x_diff; |
| float y_diff; |
| vec.Value( x_diff, y_diff ); |
| |
| pinch_start_distance_SQ_ = x_diff * x_diff + y_diff * y_diff; |
| camera_rotation_start_ = atan2f( y_diff, x_diff ); |
| camera_rotation_now_ = 0; |
| |
| pinching_ = true; |
| momentum_ = false; |
| |
| //Init momentum factors |
| vec_offset_delta_ = Vec3(); |
| } |
| |
| void TapCamera::EndPinch() |
| { |
| pinching_ = false; |
| momentum_ = true; |
| momemtum_steps_ = 1.f; |
| vec_offset_ += vec_offset_now_; |
| camera_rotation_ += camera_rotation_now_; |
| vec_offset_now_ = Vec3(); |
| |
| camera_rotation_now_ = 0; |
| |
| EndDrag(); |
| } |
| |
| void TapCamera::Pinch( const Vec2& v1, const Vec2& v2 ) |
| { |
| if( !pinching_ ) |
| return; |
| |
| //Update momentum factor |
| vec_offset_last_ = vec_offset_now_; |
| |
| float x_diff, y_diff; |
| Vec2 vec = v1 - v2; |
| vec.Value( x_diff, y_diff ); |
| |
| float fDistanceSQ = x_diff * x_diff + y_diff * y_diff; |
| |
| float f = pinch_start_distance_SQ_ / fDistanceSQ; |
| if( f < 1.f ) |
| f = -1.f / f + 1.0f; |
| else |
| f = f - 1.f; |
| if( isnan( f ) ) |
| f = 0.f; |
| |
| vec = (v1 + v2) / 2.f - vec_pinch_start_center_; |
| vec_offset_now_ = Vec3( vec, flip_z_ * f ); |
| |
| //Update momentum factor |
| vec_offset_delta_ = vec_offset_delta_ * MOMENTUM_FACTOR |
| + (vec_offset_now_ - vec_offset_last_); |
| |
| // |
| //Update ration quaternion |
| float fRotation = atan2f( y_diff, x_diff ); |
| camera_rotation_now_ = fRotation - camera_rotation_start_; |
| |
| //Trackball rotation |
| quat_ball_rot_ = Quaternion( 0.f, 0.f, sinf( -camera_rotation_now_ * 0.5f ), |
| cosf( -camera_rotation_now_ * 0.5f ) ); |
| } |
| |
| //---------------------------------------------------------- |
| //Trackball controll |
| //---------------------------------------------------------- |
| void TapCamera::BallUpdate() |
| { |
| if( dragging_ ) |
| { |
| Vec3 vec_from = PointOnSphere( vec_ball_down_ ); |
| Vec3 vec_to = PointOnSphere( vec_ball_now_ ); |
| |
| Vec3 vec = vec_from.Cross( vec_to ); |
| float w = vec_from.Dot( vec_to ); |
| |
| Quaternion qDrag = Quaternion( vec, w ); |
| qDrag = qDrag * quat_ball_down_; |
| quat_ball_now_ = quat_ball_rot_ * qDrag; |
| } |
| quat_ball_now_.ToMatrix( mat_rotation_ ); |
| } |
| |
| Vec3 TapCamera::PointOnSphere( Vec2& point ) |
| { |
| Vec3 ball_mouse; |
| float mag; |
| Vec2 vec = (point - vec_ball_center_) / ball_radius_; |
| mag = vec.Dot( vec ); |
| if( mag > 1.f ) |
| { |
| float scale = 1.f / sqrtf( mag ); |
| vec *= scale; |
| ball_mouse = Vec3( vec, 0.f ); |
| } |
| else |
| { |
| ball_mouse = Vec3( vec, sqrtf( 1.f - mag ) ); |
| } |
| return ball_mouse; |
| } |
| |
| } //namespace ndkHelper |