/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.
*/
package com.projecttango.rajawali;
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import org.rajawali3d.cameras.Camera;
import org.rajawali3d.math.Quaternion;
import org.rajawali3d.math.vector.Vector3;
/**
* This is a helper class that adds top-down and third-person views in a VR setting, including
* handling of standard pan and zoom touch interactions.
*/
public class TouchViewHandler {
// Touch interaction tuning constants.
private static final int TOUCH_THIRD_PITCH_LIMIT = 60;
private static final int TOUCH_THIRD_PITCH_DEFAULT = 45;
private static final int TOUCH_THIRD_YAW_DEFAULT = -45;
private static final int TOUCH_FOV_MAX = 120;
private static final int TOUCH_THIRD_DISTANCE = 10;
private static final int TOUCH_TOP_DISTANCE = 10;
// Virtual reality view parameters.
private static final float FIRST_PERSON_FOV = 37.8f;
private static final int THIRD_PERSON_FOV = 65;
private static final int TOP_DOWN_FOV = 65;
private enum ViewMode {
FIRST_PERSON, TOP_DOWN, THIRD_PERSON
}
private ViewMode viewMode = ViewMode.THIRD_PERSON;
private GestureDetector gestureDetector;
private ScaleGestureDetector scaleGestureDetector;
private Vector3 topDownCameraDelta = new Vector3();
private float thirdPersonPitch = TOUCH_THIRD_PITCH_DEFAULT;
private float thirdPersonYaw = TOUCH_THIRD_YAW_DEFAULT;
private Camera camera;
public TouchViewHandler(Context context, Camera camera) {
gestureDetector = new GestureDetector(context, new DragListener());
scaleGestureDetector = new ScaleGestureDetector(context, new ScaleListener());
this.camera = camera;
}
public Camera getCamera() {
return camera;
}
public void setCamera(Camera camera) {
this.camera = camera;
}
public void updateCamera(Vector3 position, Quaternion orientation) {
if (viewMode == ViewMode.FIRST_PERSON) {
camera.setPosition(position);
camera.setOrientation(orientation);
} else if (viewMode == ViewMode.TOP_DOWN) {
camera.setPosition(position.x + topDownCameraDelta.x, TOUCH_TOP_DISTANCE,
position.z + topDownCameraDelta.z);
camera.setRotation(Vector3.Axis.X, 90);
} else if (viewMode == ViewMode.THIRD_PERSON) {
camera.setPosition(position.x, position.y, position.z);
camera.setRotZ(thirdPersonPitch);
camera.rotate(Vector3.Axis.Y, thirdPersonYaw);
camera.moveForward(TOUCH_THIRD_DISTANCE);
}
}
public void onTouchEvent(MotionEvent motionEvent) {
gestureDetector.onTouchEvent(motionEvent);
scaleGestureDetector.onTouchEvent(motionEvent);
}
public void setFirstPersonView() {
viewMode = ViewMode.FIRST_PERSON;
camera.setFieldOfView(FIRST_PERSON_FOV);
}
public void setTopDownView() {
viewMode = ViewMode.TOP_DOWN;
topDownCameraDelta = new Vector3();
camera.setFieldOfView(TOP_DOWN_FOV);
}
public void setThirdPersonView() {
viewMode = ViewMode.THIRD_PERSON;
thirdPersonYaw = TOUCH_THIRD_YAW_DEFAULT;
thirdPersonPitch = TOUCH_THIRD_PITCH_DEFAULT;
camera.setFieldOfView(THIRD_PERSON_FOV);
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
float scale = 1f;
@Override
public boolean onScale(ScaleGestureDetector detector) {
scale = detector.getScaleFactor();
scale = Math.max(0.1f, Math.min(scale, 5f));
camera.setFieldOfView(
Math.min(camera.getFieldOfView() / scale, TOUCH_FOV_MAX));
return true;
}
}
private class DragListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (viewMode == ViewMode.TOP_DOWN) {
double factor = camera.getFieldOfView() / 45;
topDownCameraDelta.add(
new Vector3(distanceX / 100 * factor, 0, distanceY / 100 * factor));
} else if (viewMode == ViewMode.THIRD_PERSON) {
thirdPersonPitch -= distanceY / 10;
thirdPersonPitch =
Math.min(thirdPersonPitch, TOUCH_THIRD_PITCH_LIMIT);
thirdPersonPitch =
Math.max(thirdPersonPitch, -TOUCH_THIRD_PITCH_LIMIT);
thirdPersonYaw -= distanceX / 10;
thirdPersonYaw %= 360;
}
return true;
}
}
}