• 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;
18 
19 import com.badlogic.gdx.Gdx;
20 import com.badlogic.gdx.Graphics;
21 import com.badlogic.gdx.Input;
22 import com.badlogic.gdx.graphics.g2d.Batch;
23 import com.badlogic.gdx.math.Frustum;
24 import com.badlogic.gdx.math.Matrix4;
25 import com.badlogic.gdx.math.Quaternion;
26 import com.badlogic.gdx.math.Vector3;
27 import com.badlogic.gdx.math.collision.Ray;
28 
29 /** Base class for {@link OrthographicCamera} and {@link PerspectiveCamera}.
30  * @author mzechner */
31 public abstract class Camera {
32 	/** the position of the camera **/
33 	public final Vector3 position = new Vector3();
34 	/** the unit length direction vector of the camera **/
35 	public final Vector3 direction = new Vector3(0, 0, -1);
36 	/** the unit length up vector of the camera **/
37 	public final Vector3 up = new Vector3(0, 1, 0);
38 
39 	/** the projection matrix **/
40 	public final Matrix4 projection = new Matrix4();
41 	/** the view matrix **/
42 	public final Matrix4 view = new Matrix4();
43 	/** the combined projection and view matrix **/
44 	public final Matrix4 combined = new Matrix4();
45 	/** the inverse combined projection and view matrix **/
46 	public final Matrix4 invProjectionView = new Matrix4();
47 
48 	/** the near clipping plane distance, has to be positive **/
49 	public float near = 1;
50 	/** the far clipping plane distance, has to be positive **/
51 	public float far = 100;
52 
53 	/** the viewport width **/
54 	public float viewportWidth = 0;
55 	/** the viewport height **/
56 	public float viewportHeight = 0;
57 
58 	/** the frustum **/
59 	public final Frustum frustum = new Frustum();
60 
61 	private final Vector3 tmpVec = new Vector3();
62 	private final Ray ray = new Ray(new Vector3(), new Vector3());
63 
64 	/** Recalculates the projection and view matrix of this camera and the {@link Frustum} planes. Use this after you've manipulated
65 	 * any of the attributes of the camera. */
update()66 	public abstract void update ();
67 
68 	/** Recalculates the projection and view matrix of this camera and the {@link Frustum} planes if <code>updateFrustum</code> is
69 	 * true. Use this after you've manipulated any of the attributes of the camera. */
update(boolean updateFrustum)70 	public abstract void update (boolean updateFrustum);
71 
72 	/** Recalculates the direction of the camera to look at the point (x, y, z). This function assumes the up vector is normalized.
73 	 * @param x the x-coordinate of the point to look at
74 	 * @param y the y-coordinate of the point to look at
75 	 * @param z the z-coordinate of the point to look at */
lookAt(float x, float y, float z)76 	public void lookAt (float x, float y, float z) {
77 		tmpVec.set(x, y, z).sub(position).nor();
78 		if (!tmpVec.isZero()) {
79 			float dot = tmpVec.dot(up); // up and direction must ALWAYS be orthonormal vectors
80 			if (Math.abs(dot - 1) < 0.000000001f) {
81 				// Collinear
82 				up.set(direction).scl(-1);
83 			} else if (Math.abs(dot + 1) < 0.000000001f) {
84 				// Collinear opposite
85 				up.set(direction);
86 			}
87 			direction.set(tmpVec);
88 			normalizeUp();
89 		}
90 	}
91 
92 	/** Recalculates the direction of the camera to look at the point (x, y, z).
93 	 * @param target the point to look at */
lookAt(Vector3 target)94 	public void lookAt (Vector3 target) {
95 		lookAt(target.x, target.y, target.z);
96 	}
97 
98 	/** Normalizes the up vector by first calculating the right vector via a cross product between direction and up, and then
99 	 * recalculating the up vector via a cross product between right and direction. */
normalizeUp()100 	public void normalizeUp () {
101 		tmpVec.set(direction).crs(up).nor();
102 		up.set(tmpVec).crs(direction).nor();
103 	}
104 
105 	/** Rotates the direction and up vector of this camera by the given angle around the given axis. The direction and up vector
106 	 * will not be orthogonalized.
107 	 *
108 	 * @param angle the angle
109 	 * @param axisX the x-component of the axis
110 	 * @param axisY the y-component of the axis
111 	 * @param axisZ the z-component of the axis */
rotate(float angle, float axisX, float axisY, float axisZ)112 	public void rotate (float angle, float axisX, float axisY, float axisZ) {
113 		direction.rotate(angle, axisX, axisY, axisZ);
114 		up.rotate(angle, axisX, axisY, axisZ);
115 	}
116 
117 	/** Rotates the direction and up vector of this camera by the given angle around the given axis. The direction and up vector
118 	 * will not be orthogonalized.
119 	 *
120 	 * @param axis the axis to rotate around
121 	 * @param angle the angle */
rotate(Vector3 axis, float angle)122 	public void rotate (Vector3 axis, float angle) {
123 		direction.rotate(axis, angle);
124 		up.rotate(axis, angle);
125 	}
126 
127 	/** Rotates the direction and up vector of this camera by the given rotation matrix. The direction and up vector will not be
128 	 * orthogonalized.
129 	 *
130 	 * @param transform The rotation matrix */
rotate(final Matrix4 transform)131 	public void rotate (final Matrix4 transform) {
132 		direction.rot(transform);
133 		up.rot(transform);
134 	}
135 
136 	/** Rotates the direction and up vector of this camera by the given {@link Quaternion}. The direction and up vector will not be
137 	 * orthogonalized.
138 	 *
139 	 * @param quat The quaternion */
rotate(final Quaternion quat)140 	public void rotate (final Quaternion quat) {
141 		quat.transform(direction);
142 		quat.transform(up);
143 	}
144 
145 	/** Rotates the direction and up vector of this camera by the given angle around the given axis, with the axis attached to given
146 	 * point. The direction and up vector will not be orthogonalized.
147 	 *
148 	 * @param point the point to attach the axis to
149 	 * @param axis the axis to rotate around
150 	 * @param angle the angle */
rotateAround(Vector3 point, Vector3 axis, float angle)151 	public void rotateAround (Vector3 point, Vector3 axis, float angle) {
152 		tmpVec.set(point);
153 		tmpVec.sub(position);
154 		translate(tmpVec);
155 		rotate(axis, angle);
156 		tmpVec.rotate(axis, angle);
157 		translate(-tmpVec.x, -tmpVec.y, -tmpVec.z);
158 	}
159 
160 	/** Transform the position, direction and up vector by the given matrix
161 	 *
162 	 * @param transform The transform matrix */
transform(final Matrix4 transform)163 	public void transform (final Matrix4 transform) {
164 		position.mul(transform);
165 		rotate(transform);
166 	}
167 
168 	/** Moves the camera by the given amount on each axis.
169 	 * @param x the displacement on the x-axis
170 	 * @param y the displacement on the y-axis
171 	 * @param z the displacement on the z-axis */
translate(float x, float y, float z)172 	public void translate (float x, float y, float z) {
173 		position.add(x, y, z);
174 	}
175 
176 	/** Moves the camera by the given vector.
177 	 * @param vec the displacement vector */
translate(Vector3 vec)178 	public void translate (Vector3 vec) {
179 		position.add(vec);
180 	}
181 
182 	/** Function to translate a point given in screen coordinates to world space. It's the same as GLU gluUnProject, but does not
183 	 * rely on OpenGL. The x- and y-coordinate of vec are assumed to be in screen coordinates (origin is the top left corner, y
184 	 * pointing down, x pointing to the right) as reported by the touch methods in {@link Input}. A z-coordinate of 0 will return a
185 	 * point on the near plane, a z-coordinate of 1 will return a point on the far plane. This method allows you to specify the
186 	 * viewport position and dimensions in the coordinate system expected by {@link GL20#glViewport(int, int, int, int)}, with the
187 	 * origin in the bottom left corner of the screen.
188 	 * @param screenCoords the point in screen coordinates (origin top left)
189 	 * @param viewportX the coordinate of the bottom left corner of the viewport in glViewport coordinates.
190 	 * @param viewportY the coordinate of the bottom left corner of the viewport in glViewport coordinates.
191 	 * @param viewportWidth the width of the viewport in pixels
192 	 * @param viewportHeight the height of the viewport in pixels */
unproject(Vector3 screenCoords, float viewportX, float viewportY, float viewportWidth, float viewportHeight)193 	public Vector3 unproject (Vector3 screenCoords, float viewportX, float viewportY, float viewportWidth, float viewportHeight) {
194 		float x = screenCoords.x, y = screenCoords.y;
195 		x = x - viewportX;
196 		y = Gdx.graphics.getHeight() - y - 1;
197 		y = y - viewportY;
198 		screenCoords.x = (2 * x) / viewportWidth - 1;
199 		screenCoords.y = (2 * y) / viewportHeight - 1;
200 		screenCoords.z = 2 * screenCoords.z - 1;
201 		screenCoords.prj(invProjectionView);
202 		return screenCoords;
203 	}
204 
205 	/** Function to translate a point given in screen coordinates to world space. It's the same as GLU gluUnProject but does not
206 	 * rely on OpenGL. The viewport is assumed to span the whole screen and is fetched from {@link Graphics#getWidth()} and
207 	 * {@link Graphics#getHeight()}. The x- and y-coordinate of vec are assumed to be in screen coordinates (origin is the top left
208 	 * corner, y pointing down, x pointing to the right) as reported by the touch methods in {@link Input}. A z-coordinate of 0
209 	 * will return a point on the near plane, a z-coordinate of 1 will return a point on the far plane.
210 	 * @param screenCoords the point in screen coordinates */
unproject(Vector3 screenCoords)211 	public Vector3 unproject (Vector3 screenCoords) {
212 		unproject(screenCoords, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
213 		return screenCoords;
214 	}
215 
216 	/** Projects the {@link Vector3} given in world space to screen coordinates. It's the same as GLU gluProject with one small
217 	 * deviation: The viewport is assumed to span the whole screen. The screen coordinate system has its origin in the
218 	 * <b>bottom</b> left, with the y-axis pointing <b>upwards</b> and the x-axis pointing to the right. This makes it easily
219 	 * useable in conjunction with {@link Batch} and similar classes. */
project(Vector3 worldCoords)220 	public Vector3 project (Vector3 worldCoords) {
221 		project(worldCoords, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
222 		return worldCoords;
223 	}
224 
225 	/** Projects the {@link Vector3} given in world space to screen coordinates. It's the same as GLU gluProject with one small
226 	 * deviation: The viewport is assumed to span the whole screen. The screen coordinate system has its origin in the
227 	 * <b>bottom</b> left, with the y-axis pointing <b>upwards</b> and the x-axis pointing to the right. This makes it easily
228 	 * useable in conjunction with {@link Batch} and similar classes. This method allows you to specify the viewport position and
229 	 * dimensions in the coordinate system expected by {@link GL20#glViewport(int, int, int, int)}, with the origin in the bottom
230 	 * left corner of the screen.
231 	 * @param viewportX the coordinate of the bottom left corner of the viewport in glViewport coordinates.
232 	 * @param viewportY the coordinate of the bottom left corner of the viewport in glViewport coordinates.
233 	 * @param viewportWidth the width of the viewport in pixels
234 	 * @param viewportHeight the height of the viewport in pixels */
project(Vector3 worldCoords, float viewportX, float viewportY, float viewportWidth, float viewportHeight)235 	public Vector3 project (Vector3 worldCoords, float viewportX, float viewportY, float viewportWidth, float viewportHeight) {
236 		worldCoords.prj(combined);
237 		worldCoords.x = viewportWidth * (worldCoords.x + 1) / 2 + viewportX;
238 		worldCoords.y = viewportHeight * (worldCoords.y + 1) / 2 + viewportY;
239 		worldCoords.z = (worldCoords.z + 1) / 2;
240 		return worldCoords;
241 	}
242 
243 	/** Creates a picking {@link Ray} from the coordinates given in screen coordinates. It is assumed that the viewport spans the
244 	 * whole screen. The screen coordinates origin is assumed to be in the top left corner, its y-axis pointing down, the x-axis
245 	 * pointing to the right. The returned instance is not a new instance but an internal member only accessible via this function.
246 	 * @param viewportX the coordinate of the bottom left corner of the viewport in glViewport coordinates.
247 	 * @param viewportY the coordinate of the bottom left corner of the viewport in glViewport coordinates.
248 	 * @param viewportWidth the width of the viewport in pixels
249 	 * @param viewportHeight the height of the viewport in pixels
250 	 * @return the picking Ray. */
getPickRay(float screenX, float screenY, float viewportX, float viewportY, float viewportWidth, float viewportHeight)251 	public Ray getPickRay (float screenX, float screenY, float viewportX, float viewportY, float viewportWidth,
252 		float viewportHeight) {
253 		unproject(ray.origin.set(screenX, screenY, 0), viewportX, viewportY, viewportWidth, viewportHeight);
254 		unproject(ray.direction.set(screenX, screenY, 1), viewportX, viewportY, viewportWidth, viewportHeight);
255 		ray.direction.sub(ray.origin).nor();
256 		return ray;
257 	}
258 
259 	/** Creates a picking {@link Ray} from the coordinates given in screen coordinates. It is assumed that the viewport spans the
260 	 * whole screen. The screen coordinates origin is assumed to be in the top left corner, its y-axis pointing down, the x-axis
261 	 * pointing to the right. The returned instance is not a new instance but an internal member only accessible via this function.
262 	 * @return the picking Ray. */
getPickRay(float screenX, float screenY)263 	public Ray getPickRay (float screenX, float screenY) {
264 		return getPickRay(screenX, screenY, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
265 	}
266 }
267