1 /* 2 * Copyright 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 //---------------------------------------------------------- 18 // tapCamera.cpp 19 // Camera control with tap 20 // 21 //---------------------------------------------------------- 22 #include <fstream> 23 #include "tapCamera.h" 24 25 namespace ndk_helper 26 { 27 28 const float TRANSFORM_FACTOR = 15.f; 29 const float TRANSFORM_FACTORZ = 10.f; 30 31 const float MOMENTUM_FACTOR_DECREASE = 0.85f; 32 const float MOMENTUM_FACTOR_DECREASE_SHIFT = 0.9f; 33 const float MOMENTUM_FACTOR = 0.8f; 34 const float MOMENTUM_FACTOR_THRESHOLD = 0.001f; 35 36 //---------------------------------------------------------- 37 // Ctor 38 //---------------------------------------------------------- 39 TapCamera::TapCamera() : 40 dragging_( false ), 41 pinching_( false ), 42 momentum_( false ), 43 ball_radius_( 0.75f ), 44 pinch_start_distance_SQ_( 0.f ), 45 camera_rotation_( 0.f ), 46 camera_rotation_start_( 0.f ), 47 camera_rotation_now_( 0.f ), 48 momemtum_steps_( 0.f ), 49 flip_z_( 0.f ) 50 { 51 //Init offset 52 InitParameters(); 53 54 vec_flip_ = Vec2( 1.f, -1.f ); 55 flip_z_ = -1.f; 56 vec_pinch_transform_factor_ = Vec3( 1.f, 1.f, 1.f ); 57 58 vec_ball_center_ = Vec2( 0, 0 ); 59 vec_ball_now_ = Vec2( 0, 0 ); 60 vec_ball_down_ = Vec2( 0, 0 ); 61 62 vec_pinch_start_ = Vec2( 0, 0 ); 63 vec_pinch_start_center_ = Vec2( 0, 0 ); 64 65 vec_flip_ = Vec2( 0, 0 ); 66 67 } 68 69 void TapCamera::InitParameters() 70 { 71 //Init parameters 72 vec_offset_ = Vec3(); 73 vec_offset_now_ = Vec3(); 74 75 quat_ball_rot_ = Quaternion(); 76 quat_ball_now_ = Quaternion(); 77 quat_ball_now_.ToMatrix( mat_rotation_ ); 78 camera_rotation_ = 0.f; 79 80 vec_drag_delta_ = Vec2(); 81 vec_offset_delta_ = Vec3(); 82 83 momentum_ = false; 84 } 85 86 //---------------------------------------------------------- 87 // Dtor 88 //---------------------------------------------------------- 89 TapCamera::~TapCamera() 90 { 91 92 } 93 94 void TapCamera::Update() 95 { 96 if( momentum_ ) 97 { 98 float momenttum_steps = momemtum_steps_; 99 100 //Momentum rotation 101 Vec2 v = vec_drag_delta_; 102 BeginDrag( Vec2() ); //NOTE:This call reset _VDragDelta 103 Drag( v * vec_flip_ ); 104 105 //Momentum shift 106 vec_offset_ += vec_offset_delta_; 107 108 BallUpdate(); 109 EndDrag(); 110 111 //Decrease deltas 112 vec_drag_delta_ = v * MOMENTUM_FACTOR_DECREASE; 113 vec_offset_delta_ = vec_offset_delta_ * MOMENTUM_FACTOR_DECREASE_SHIFT; 114 115 //Count steps 116 momemtum_steps_ = momenttum_steps * MOMENTUM_FACTOR_DECREASE; 117 if( momemtum_steps_ < MOMENTUM_FACTOR_THRESHOLD ) 118 { 119 momentum_ = false; 120 } 121 } 122 else 123 { 124 vec_drag_delta_ *= MOMENTUM_FACTOR; 125 vec_offset_delta_ = vec_offset_delta_ * MOMENTUM_FACTOR; 126 BallUpdate(); 127 } 128 129 Vec3 vec = vec_offset_ + vec_offset_now_; 130 Vec3 vec_tmp( TRANSFORM_FACTOR, -TRANSFORM_FACTOR, TRANSFORM_FACTORZ ); 131 132 vec *= vec_tmp * vec_pinch_transform_factor_; 133 134 mat_transform_ = Mat4::Translation( vec ); 135 } 136 137 Mat4& TapCamera::GetRotationMatrix() 138 { 139 return mat_rotation_; 140 } 141 142 Mat4& TapCamera::GetTransformMatrix() 143 { 144 return mat_transform_; 145 } 146 147 void TapCamera::Reset( const bool bAnimate ) 148 { 149 InitParameters(); 150 Update(); 151 152 } 153 154 //---------------------------------------------------------- 155 //Drag control 156 //---------------------------------------------------------- 157 void TapCamera::BeginDrag( const Vec2& v ) 158 { 159 if( dragging_ ) 160 EndDrag(); 161 162 if( pinching_ ) 163 EndPinch(); 164 165 Vec2 vec = v * vec_flip_; 166 vec_ball_now_ = vec; 167 vec_ball_down_ = vec_ball_now_; 168 169 dragging_ = true; 170 momentum_ = false; 171 vec_last_input_ = vec; 172 vec_drag_delta_ = Vec2(); 173 } 174 175 void TapCamera::EndDrag() 176 { 177 quat_ball_down_ = quat_ball_now_; 178 quat_ball_rot_ = Quaternion(); 179 180 dragging_ = false; 181 momentum_ = true; 182 momemtum_steps_ = 1.0f; 183 } 184 185 void TapCamera::Drag( const Vec2& v ) 186 { 187 if( !dragging_ ) 188 return; 189 190 Vec2 vec = v * vec_flip_; 191 vec_ball_now_ = vec; 192 193 vec_drag_delta_ = vec_drag_delta_ * MOMENTUM_FACTOR + (vec - vec_last_input_); 194 vec_last_input_ = vec; 195 } 196 197 //---------------------------------------------------------- 198 //Pinch controll 199 //---------------------------------------------------------- 200 void TapCamera::BeginPinch( const Vec2& v1, const Vec2& v2 ) 201 { 202 if( dragging_ ) 203 EndDrag(); 204 205 if( pinching_ ) 206 EndPinch(); 207 208 BeginDrag( Vec2() ); 209 210 vec_pinch_start_center_ = (v1 + v2) / 2.f; 211 212 Vec2 vec = v1 - v2; 213 float x_diff; 214 float y_diff; 215 vec.Value( x_diff, y_diff ); 216 217 pinch_start_distance_SQ_ = x_diff * x_diff + y_diff * y_diff; 218 camera_rotation_start_ = atan2f( y_diff, x_diff ); 219 camera_rotation_now_ = 0; 220 221 pinching_ = true; 222 momentum_ = false; 223 224 //Init momentum factors 225 vec_offset_delta_ = Vec3(); 226 } 227 228 void TapCamera::EndPinch() 229 { 230 pinching_ = false; 231 momentum_ = true; 232 momemtum_steps_ = 1.f; 233 vec_offset_ += vec_offset_now_; 234 camera_rotation_ += camera_rotation_now_; 235 vec_offset_now_ = Vec3(); 236 237 camera_rotation_now_ = 0; 238 239 EndDrag(); 240 } 241 242 void TapCamera::Pinch( const Vec2& v1, const Vec2& v2 ) 243 { 244 if( !pinching_ ) 245 return; 246 247 //Update momentum factor 248 vec_offset_last_ = vec_offset_now_; 249 250 float x_diff, y_diff; 251 Vec2 vec = v1 - v2; 252 vec.Value( x_diff, y_diff ); 253 254 float fDistanceSQ = x_diff * x_diff + y_diff * y_diff; 255 256 float f = pinch_start_distance_SQ_ / fDistanceSQ; 257 if( f < 1.f ) 258 f = -1.f / f + 1.0f; 259 else 260 f = f - 1.f; 261 if( isnan( f ) ) 262 f = 0.f; 263 264 vec = (v1 + v2) / 2.f - vec_pinch_start_center_; 265 vec_offset_now_ = Vec3( vec, flip_z_ * f ); 266 267 //Update momentum factor 268 vec_offset_delta_ = vec_offset_delta_ * MOMENTUM_FACTOR 269 + (vec_offset_now_ - vec_offset_last_); 270 271 // 272 //Update ration quaternion 273 float fRotation = atan2f( y_diff, x_diff ); 274 camera_rotation_now_ = fRotation - camera_rotation_start_; 275 276 //Trackball rotation 277 quat_ball_rot_ = Quaternion( 0.f, 0.f, sinf( -camera_rotation_now_ * 0.5f ), 278 cosf( -camera_rotation_now_ * 0.5f ) ); 279 } 280 281 //---------------------------------------------------------- 282 //Trackball controll 283 //---------------------------------------------------------- 284 void TapCamera::BallUpdate() 285 { 286 if( dragging_ ) 287 { 288 Vec3 vec_from = PointOnSphere( vec_ball_down_ ); 289 Vec3 vec_to = PointOnSphere( vec_ball_now_ ); 290 291 Vec3 vec = vec_from.Cross( vec_to ); 292 float w = vec_from.Dot( vec_to ); 293 294 Quaternion qDrag = Quaternion( vec, w ); 295 qDrag = qDrag * quat_ball_down_; 296 quat_ball_now_ = quat_ball_rot_ * qDrag; 297 } 298 quat_ball_now_.ToMatrix( mat_rotation_ ); 299 } 300 301 Vec3 TapCamera::PointOnSphere( Vec2& point ) 302 { 303 Vec3 ball_mouse; 304 float mag; 305 Vec2 vec = (point - vec_ball_center_) / ball_radius_; 306 mag = vec.Dot( vec ); 307 if( mag > 1.f ) 308 { 309 float scale = 1.f / sqrtf( mag ); 310 vec *= scale; 311 ball_mouse = Vec3( vec, 0.f ); 312 } 313 else 314 { 315 ball_mouse = Vec3( vec, sqrtf( 1.f - mag ) ); 316 } 317 return ball_mouse; 318 } 319 320 } //namespace ndkHelper 321