• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright 2011 See AUTHORS file.
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 package com.badlogic.gdx.graphics.g3d.utils;
18 
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.Input.Keys;
21 import com.badlogic.gdx.InputAdapter;
22 import com.badlogic.gdx.Input.Buttons;
23 import com.badlogic.gdx.graphics.Camera;
24 import com.badlogic.gdx.input.GestureDetector;
25 import com.badlogic.gdx.math.MathUtils;
26 import com.badlogic.gdx.math.Vector2;
27 import com.badlogic.gdx.math.Vector3;
28 
29 public class CameraInputController extends GestureDetector {
30 	/** The button for rotating the camera. */
31 	public int rotateButton = Buttons.LEFT;
32 	/** The angle to rotate when moved the full width or height of the screen. */
33 	public float rotateAngle = 360f;
34 	/** The button for translating the camera along the up/right plane */
35 	public int translateButton = Buttons.RIGHT;
36 	/** The units to translate the camera when moved the full width or height of the screen. */
37 	public float translateUnits = 10f; // FIXME auto calculate this based on the target
38 	/** The button for translating the camera along the direction axis */
39 	public int forwardButton = Buttons.MIDDLE;
40 	/** The key which must be pressed to activate rotate, translate and forward or 0 to always activate. */
41 	public int activateKey = 0;
42 	/** Indicates if the activateKey is currently being pressed. */
43 	protected boolean activatePressed;
44 	/** Whether scrolling requires the activeKey to be pressed (false) or always allow scrolling (true). */
45 	public boolean alwaysScroll = true;
46 	/** The weight for each scrolled amount. */
47 	public float scrollFactor = -0.1f;
48 	/** World units per screen size */
49 	public float pinchZoomFactor = 10f;
50 	/** Whether to update the camera after it has been changed. */
51 	public boolean autoUpdate = true;
52 	/** The target to rotate around. */
53 	public Vector3 target = new Vector3();
54 	/** Whether to update the target on translation */
55 	public boolean translateTarget = true;
56 	/** Whether to update the target on forward */
57 	public boolean forwardTarget = true;
58 	/** Whether to update the target on scroll */
59 	public boolean scrollTarget = false;
60 	public int forwardKey = Keys.W;
61 	protected boolean forwardPressed;
62 	public int backwardKey = Keys.S;
63 	protected boolean backwardPressed;
64 	public int rotateRightKey = Keys.A;
65 	protected boolean rotateRightPressed;
66 	public int rotateLeftKey = Keys.D;
67 	protected boolean rotateLeftPressed;
68 	/** The camera. */
69 	public Camera camera;
70 	/** The current (first) button being pressed. */
71 	protected int button = -1;
72 
73 	private float startX, startY;
74 	private final Vector3 tmpV1 = new Vector3();
75 	private final Vector3 tmpV2 = new Vector3();
76 
77 	protected static class CameraGestureListener extends GestureAdapter {
78 		public CameraInputController controller;
79 		private float previousZoom;
80 
81 		@Override
touchDown(float x, float y, int pointer, int button)82 		public boolean touchDown (float x, float y, int pointer, int button) {
83 			previousZoom = 0;
84 			return false;
85 		}
86 
87 		@Override
tap(float x, float y, int count, int button)88 		public boolean tap (float x, float y, int count, int button) {
89 			return false;
90 		}
91 
92 		@Override
longPress(float x, float y)93 		public boolean longPress (float x, float y) {
94 			return false;
95 		}
96 
97 		@Override
fling(float velocityX, float velocityY, int button)98 		public boolean fling (float velocityX, float velocityY, int button) {
99 			return false;
100 		}
101 
102 		@Override
pan(float x, float y, float deltaX, float deltaY)103 		public boolean pan (float x, float y, float deltaX, float deltaY) {
104 			return false;
105 		}
106 
107 		@Override
zoom(float initialDistance, float distance)108 		public boolean zoom (float initialDistance, float distance) {
109 			float newZoom = distance - initialDistance;
110 			float amount = newZoom - previousZoom;
111 			previousZoom = newZoom;
112 			float w = Gdx.graphics.getWidth(), h = Gdx.graphics.getHeight();
113 			return controller.pinchZoom(amount / ((w > h) ? h : w));
114 		}
115 
116 		@Override
pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2)117 		public boolean pinch (Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
118 			return false;
119 		}
120 	};
121 
122 	protected final CameraGestureListener gestureListener;
123 
CameraInputController(final CameraGestureListener gestureListener, final Camera camera)124 	protected CameraInputController (final CameraGestureListener gestureListener, final Camera camera) {
125 		super(gestureListener);
126 		this.gestureListener = gestureListener;
127 		this.gestureListener.controller = this;
128 		this.camera = camera;
129 	}
130 
CameraInputController(final Camera camera)131 	public CameraInputController (final Camera camera) {
132 		this(new CameraGestureListener(), camera);
133 	}
134 
update()135 	public void update () {
136 		if (rotateRightPressed || rotateLeftPressed || forwardPressed || backwardPressed) {
137 			final float delta = Gdx.graphics.getDeltaTime();
138 			if (rotateRightPressed) camera.rotate(camera.up, -delta * rotateAngle);
139 			if (rotateLeftPressed) camera.rotate(camera.up, delta * rotateAngle);
140 			if (forwardPressed) {
141 				camera.translate(tmpV1.set(camera.direction).scl(delta * translateUnits));
142 				if (forwardTarget) target.add(tmpV1);
143 			}
144 			if (backwardPressed) {
145 				camera.translate(tmpV1.set(camera.direction).scl(-delta * translateUnits));
146 				if (forwardTarget) target.add(tmpV1);
147 			}
148 			if (autoUpdate) camera.update();
149 		}
150 	}
151 
152 	private int touched;
153 	private boolean multiTouch;
154 
155 	@Override
touchDown(int screenX, int screenY, int pointer, int button)156 	public boolean touchDown (int screenX, int screenY, int pointer, int button) {
157 		touched |= (1 << pointer);
158 		multiTouch = !MathUtils.isPowerOfTwo(touched);
159 		if (multiTouch)
160 			this.button = -1;
161 		else if (this.button < 0 && (activateKey == 0 || activatePressed)) {
162 			startX = screenX;
163 			startY = screenY;
164 			this.button = button;
165 		}
166 		return super.touchDown(screenX, screenY, pointer, button) || (activateKey == 0 || activatePressed);
167 	}
168 
169 	@Override
touchUp(int screenX, int screenY, int pointer, int button)170 	public boolean touchUp (int screenX, int screenY, int pointer, int button) {
171 		touched &= -1 ^ (1 << pointer);
172 		multiTouch = !MathUtils.isPowerOfTwo(touched);
173 		if (button == this.button) this.button = -1;
174 		return super.touchUp(screenX, screenY, pointer, button) || activatePressed;
175 	}
176 
process(float deltaX, float deltaY, int button)177 	protected boolean process (float deltaX, float deltaY, int button) {
178 		if (button == rotateButton) {
179 			tmpV1.set(camera.direction).crs(camera.up).y = 0f;
180 			camera.rotateAround(target, tmpV1.nor(), deltaY * rotateAngle);
181 			camera.rotateAround(target, Vector3.Y, deltaX * -rotateAngle);
182 		} else if (button == translateButton) {
183 			camera.translate(tmpV1.set(camera.direction).crs(camera.up).nor().scl(-deltaX * translateUnits));
184 			camera.translate(tmpV2.set(camera.up).scl(-deltaY * translateUnits));
185 			if (translateTarget) target.add(tmpV1).add(tmpV2);
186 		} else if (button == forwardButton) {
187 			camera.translate(tmpV1.set(camera.direction).scl(deltaY * translateUnits));
188 			if (forwardTarget) target.add(tmpV1);
189 		}
190 		if (autoUpdate) camera.update();
191 		return true;
192 	}
193 
194 	@Override
touchDragged(int screenX, int screenY, int pointer)195 	public boolean touchDragged (int screenX, int screenY, int pointer) {
196 		boolean result = super.touchDragged(screenX, screenY, pointer);
197 		if (result || this.button < 0) return result;
198 		final float deltaX = (screenX - startX) / Gdx.graphics.getWidth();
199 		final float deltaY = (startY - screenY) / Gdx.graphics.getHeight();
200 		startX = screenX;
201 		startY = screenY;
202 		return process(deltaX, deltaY, button);
203 	}
204 
205 	@Override
scrolled(int amount)206 	public boolean scrolled (int amount) {
207 		return zoom(amount * scrollFactor * translateUnits);
208 	}
209 
zoom(float amount)210 	public boolean zoom (float amount) {
211 		if (!alwaysScroll && activateKey != 0 && !activatePressed) return false;
212 		camera.translate(tmpV1.set(camera.direction).scl(amount));
213 		if (scrollTarget) target.add(tmpV1);
214 		if (autoUpdate) camera.update();
215 		return true;
216 	}
217 
pinchZoom(float amount)218 	protected boolean pinchZoom (float amount) {
219 		return zoom(pinchZoomFactor * amount);
220 	}
221 
222 	@Override
keyDown(int keycode)223 	public boolean keyDown (int keycode) {
224 		if (keycode == activateKey) activatePressed = true;
225 		if (keycode == forwardKey)
226 			forwardPressed = true;
227 		else if (keycode == backwardKey)
228 			backwardPressed = true;
229 		else if (keycode == rotateRightKey)
230 			rotateRightPressed = true;
231 		else if (keycode == rotateLeftKey) rotateLeftPressed = true;
232 		return false;
233 	}
234 
235 	@Override
keyUp(int keycode)236 	public boolean keyUp (int keycode) {
237 		if (keycode == activateKey) {
238 			activatePressed = false;
239 			button = -1;
240 		}
241 		if (keycode == forwardKey)
242 			forwardPressed = false;
243 		else if (keycode == backwardKey)
244 			backwardPressed = false;
245 		else if (keycode == rotateRightKey)
246 			rotateRightPressed = false;
247 		else if (keycode == rotateLeftKey) rotateLeftPressed = false;
248 		return false;
249 	}
250 }
251