• 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 java.util.HashMap;
20 import java.util.Map;
21 
22 import com.badlogic.gdx.Application;
23 import com.badlogic.gdx.Gdx;
24 import com.badlogic.gdx.assets.AssetLoaderParameters.LoadedCallback;
25 import com.badlogic.gdx.assets.AssetManager;
26 import com.badlogic.gdx.assets.loaders.AssetLoader;
27 import com.badlogic.gdx.assets.loaders.CubemapLoader.CubemapParameter;
28 import com.badlogic.gdx.files.FileHandle;
29 import com.badlogic.gdx.graphics.Pixmap.Format;
30 import com.badlogic.gdx.graphics.Texture.TextureFilter;
31 import com.badlogic.gdx.graphics.Texture.TextureWrap;
32 import com.badlogic.gdx.graphics.glutils.FacedCubemapData;
33 import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
34 import com.badlogic.gdx.math.Vector3;
35 import com.badlogic.gdx.utils.Array;
36 import com.badlogic.gdx.utils.GdxRuntimeException;
37 
38 /** Wraps a standard OpenGL ES Cubemap. Must be disposed when it is no longer used.
39  * @author Xoppa */
40 public class Cubemap extends GLTexture {
41 	private static AssetManager assetManager;
42 	final static Map<Application, Array<Cubemap>> managedCubemaps = new HashMap<Application, Array<Cubemap>>();
43 
44 	/** Enum to identify each side of a Cubemap */
45 	public enum CubemapSide {
46 		/** The positive X and first side of the cubemap */
47 		PositiveX(0, GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, -1, 0, 1, 0, 0),
48 		/** The negative X and second side of the cubemap */
49 		NegativeX(1, GL20.GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, -1, 0, -1, 0, 0),
50 		/** The positive Y and third side of the cubemap */
51 		PositiveY(2, GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, 0, 1, 0, 1, 0),
52 		/** The negative Y and fourth side of the cubemap */
53 		NegativeY(3, GL20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, 0, -1, 0, -1, 0),
54 		/** The positive Z and fifth side of the cubemap */
55 		PositiveZ(4, GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, -1, 0, 0, 0, 1),
56 		/** The negative Z and sixth side of the cubemap */
57 		NegativeZ(5, GL20.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, -1, 0, 0, 0, -1);
58 
59 		/** The zero based index of the side in the cubemap */
60 		public final int index;
61 		/** The OpenGL target (used for glTexImage2D) of the side. */
62 		public final int glEnum;
63 		/** The up vector to target the side. */
64 		public final Vector3 up;
65 		/** The direction vector to target the side. */
66 		public final Vector3 direction;
67 
CubemapSide(int index, int glEnum, float upX, float upY, float upZ, float directionX, float directionY, float directionZ)68 		CubemapSide (int index, int glEnum, float upX, float upY, float upZ, float directionX, float directionY, float directionZ) {
69 			this.index = index;
70 			this.glEnum = glEnum;
71 			this.up = new Vector3(upX, upY, upZ);
72 			this.direction = new Vector3(directionX, directionY, directionZ);
73 		}
74 
75 		/** @return The OpenGL target (used for glTexImage2D) of the side. */
getGLEnum()76 		public int getGLEnum () {
77 			return glEnum;
78 		}
79 
80 		/** @return The up vector of the side. */
getUp(Vector3 out)81 		public Vector3 getUp (Vector3 out) {
82 			return out.set(up);
83 		}
84 
85 		/** @return The direction vector of the side. */
getDirection(Vector3 out)86 		public Vector3 getDirection (Vector3 out) {
87 			return out.set(direction);
88 		}
89 	}
90 
91 	protected CubemapData data;
92 
93 	/** Construct an Cubemap based on the given CubemapData. */
Cubemap(CubemapData data)94 	public Cubemap (CubemapData data) {
95 		super(GL20.GL_TEXTURE_CUBE_MAP);
96 		this.data = data;
97 		load(data);
98 	}
99 
100 	/** Construct a Cubemap with the specified texture files for the sides, does not generate mipmaps. */
Cubemap(FileHandle positiveX, FileHandle negativeX, FileHandle positiveY, FileHandle negativeY, FileHandle positiveZ, FileHandle negativeZ)101 	public Cubemap (FileHandle positiveX, FileHandle negativeX, FileHandle positiveY, FileHandle negativeY, FileHandle positiveZ,
102 		FileHandle negativeZ) {
103 		this(positiveX, negativeX, positiveY, negativeY, positiveZ, negativeZ, false);
104 	}
105 
106 	/** Construct a Cubemap with the specified texture files for the sides, optionally generating mipmaps. */
Cubemap(FileHandle positiveX, FileHandle negativeX, FileHandle positiveY, FileHandle negativeY, FileHandle positiveZ, FileHandle negativeZ, boolean useMipMaps)107 	public Cubemap (FileHandle positiveX, FileHandle negativeX, FileHandle positiveY, FileHandle negativeY, FileHandle positiveZ,
108 		FileHandle negativeZ, boolean useMipMaps) {
109 		this(TextureData.Factory.loadFromFile(positiveX, useMipMaps), TextureData.Factory.loadFromFile(negativeX, useMipMaps),
110 			TextureData.Factory.loadFromFile(positiveY, useMipMaps), TextureData.Factory.loadFromFile(negativeY, useMipMaps),
111 			TextureData.Factory.loadFromFile(positiveZ, useMipMaps), TextureData.Factory.loadFromFile(negativeZ, useMipMaps));
112 	}
113 
114 	/** Construct a Cubemap with the specified {@link Pixmap}s for the sides, does not generate mipmaps. */
Cubemap(Pixmap positiveX, Pixmap negativeX, Pixmap positiveY, Pixmap negativeY, Pixmap positiveZ, Pixmap negativeZ)115 	public Cubemap (Pixmap positiveX, Pixmap negativeX, Pixmap positiveY, Pixmap negativeY, Pixmap positiveZ, Pixmap negativeZ) {
116 		this(positiveX, negativeX, positiveY, negativeY, positiveZ, negativeZ, false);
117 	}
118 
119 	/** Construct a Cubemap with the specified {@link Pixmap}s for the sides, optionally generating mipmaps. */
Cubemap(Pixmap positiveX, Pixmap negativeX, Pixmap positiveY, Pixmap negativeY, Pixmap positiveZ, Pixmap negativeZ, boolean useMipMaps)120 	public Cubemap (Pixmap positiveX, Pixmap negativeX, Pixmap positiveY, Pixmap negativeY, Pixmap positiveZ, Pixmap negativeZ,
121 		boolean useMipMaps) {
122 		this(positiveX == null ? null : new PixmapTextureData(positiveX, null, useMipMaps, false), negativeX == null ? null
123 			: new PixmapTextureData(negativeX, null, useMipMaps, false), positiveY == null ? null : new PixmapTextureData(positiveY,
124 			null, useMipMaps, false), negativeY == null ? null : new PixmapTextureData(negativeY, null, useMipMaps, false),
125 			positiveZ == null ? null : new PixmapTextureData(positiveZ, null, useMipMaps, false), negativeZ == null ? null
126 				: new PixmapTextureData(negativeZ, null, useMipMaps, false));
127 	}
128 
129 	/** Construct a Cubemap with {@link Pixmap}s for each side of the specified size. */
Cubemap(int width, int height, int depth, Format format)130 	public Cubemap (int width, int height, int depth, Format format) {
131 		this(new PixmapTextureData(new Pixmap(depth, height, format), null, false, true), new PixmapTextureData(new Pixmap(depth,
132 			height, format), null, false, true), new PixmapTextureData(new Pixmap(width, depth, format), null, false, true),
133 			new PixmapTextureData(new Pixmap(width, depth, format), null, false, true), new PixmapTextureData(new Pixmap(width,
134 				height, format), null, false, true), new PixmapTextureData(new Pixmap(width, height, format), null, false, true));
135 	}
136 
137 	/** Construct a Cubemap with the specified {@link TextureData}'s for the sides */
Cubemap(TextureData positiveX, TextureData negativeX, TextureData positiveY, TextureData negativeY, TextureData positiveZ, TextureData negativeZ)138 	public Cubemap (TextureData positiveX, TextureData negativeX, TextureData positiveY, TextureData negativeY,
139 		TextureData positiveZ, TextureData negativeZ) {
140 		super(GL20.GL_TEXTURE_CUBE_MAP);
141 		minFilter = TextureFilter.Nearest;
142 		magFilter = TextureFilter.Nearest;
143 		uWrap = TextureWrap.ClampToEdge;
144 		vWrap = TextureWrap.ClampToEdge;
145 		data = new FacedCubemapData(positiveX, negativeX, positiveY, negativeY, positiveZ, negativeZ);
146 		load(data);
147 	}
148 
149 	/** Sets the sides of this cubemap to the specified {@link CubemapData}. */
load(CubemapData data)150 	public void load (CubemapData data) {
151 		if (!data.isPrepared()) data.prepare();
152 		bind();
153 		unsafeSetFilter(minFilter, magFilter, true);
154 		unsafeSetWrap(uWrap, vWrap, true);
155 		data.consumeCubemapData();
156 		Gdx.gl.glBindTexture(glTarget, 0);
157 	}
158 
getCubemapData()159 	public CubemapData getCubemapData () {
160 		return data;
161 	}
162 
163 	@Override
isManaged()164 	public boolean isManaged () {
165 		return data.isManaged();
166 	}
167 
168 	@Override
reload()169 	protected void reload () {
170 		if (!isManaged()) throw new GdxRuntimeException("Tried to reload an unmanaged Cubemap");
171 		glHandle = Gdx.gl.glGenTexture();
172 		load(data);
173 	}
174 
175 	@Override
getWidth()176 	public int getWidth () {
177 		return data.getWidth();
178 	}
179 
180 	@Override
getHeight()181 	public int getHeight () {
182 		return data.getHeight();
183 	}
184 
185 	@Override
getDepth()186 	public int getDepth () {
187 		return 0;
188 	}
189 
190 	/** Disposes all resources associated with the cubemap */
191 	@Override
dispose()192 	public void dispose () {
193 		// this is a hack. reason: we have to set the glHandle to 0 for textures that are
194 		// reloaded through the asset manager as we first remove (and thus dispose) the texture
195 		// and then reload it. the glHandle is set to 0 in invalidateAllTextures prior to
196 		// removal from the asset manager.
197 		if (glHandle == 0) return;
198 		delete();
199 		if (data.isManaged()) if (managedCubemaps.get(Gdx.app) != null) managedCubemaps.get(Gdx.app).removeValue(this, true);
200 	}
201 
addManagedCubemap(Application app, Cubemap cubemap)202 	private static void addManagedCubemap (Application app, Cubemap cubemap) {
203 		Array<Cubemap> managedCubemapArray = managedCubemaps.get(app);
204 		if (managedCubemapArray == null) managedCubemapArray = new Array<Cubemap>();
205 		managedCubemapArray.add(cubemap);
206 		managedCubemaps.put(app, managedCubemapArray);
207 	}
208 
209 	/** Clears all managed cubemaps. This is an internal method. Do not use it! */
clearAllCubemaps(Application app)210 	public static void clearAllCubemaps (Application app) {
211 		managedCubemaps.remove(app);
212 	}
213 
214 	/** Invalidate all managed cubemaps. This is an internal method. Do not use it! */
invalidateAllCubemaps(Application app)215 	public static void invalidateAllCubemaps (Application app) {
216 		Array<Cubemap> managedCubemapArray = managedCubemaps.get(app);
217 		if (managedCubemapArray == null) return;
218 
219 		if (assetManager == null) {
220 			for (int i = 0; i < managedCubemapArray.size; i++) {
221 				Cubemap cubemap = managedCubemapArray.get(i);
222 				cubemap.reload();
223 			}
224 		} else {
225 			// first we have to make sure the AssetManager isn't loading anything anymore,
226 			// otherwise the ref counting trick below wouldn't work (when a cubemap is
227 			// currently on the task stack of the manager.)
228 			assetManager.finishLoading();
229 
230 			// next we go through each cubemap and reload either directly or via the
231 			// asset manager.
232 			Array<Cubemap> cubemaps = new Array<Cubemap>(managedCubemapArray);
233 			for (Cubemap cubemap : cubemaps) {
234 				String fileName = assetManager.getAssetFileName(cubemap);
235 				if (fileName == null) {
236 					cubemap.reload();
237 				} else {
238 					// get the ref count of the cubemap, then set it to 0 so we
239 					// can actually remove it from the assetmanager. Also set the
240 					// handle to zero, otherwise we might accidentially dispose
241 					// already reloaded cubemaps.
242 					final int refCount = assetManager.getReferenceCount(fileName);
243 					assetManager.setReferenceCount(fileName, 0);
244 					cubemap.glHandle = 0;
245 
246 					// create the parameters, passing the reference to the cubemap as
247 					// well as a callback that sets the ref count.
248 					CubemapParameter params = new CubemapParameter();
249 					params.cubemapData = cubemap.getCubemapData();
250 					params.minFilter = cubemap.getMinFilter();
251 					params.magFilter = cubemap.getMagFilter();
252 					params.wrapU = cubemap.getUWrap();
253 					params.wrapV = cubemap.getVWrap();
254 					params.cubemap = cubemap; // special parameter which will ensure that the references stay the same.
255 					params.loadedCallback = new LoadedCallback() {
256 						@Override
257 						public void finishedLoading (AssetManager assetManager, String fileName, Class type) {
258 							assetManager.setReferenceCount(fileName, refCount);
259 						}
260 					};
261 
262 					// unload the c, create a new gl handle then reload it.
263 					assetManager.unload(fileName);
264 					cubemap.glHandle = Gdx.gl.glGenTexture();
265 					assetManager.load(fileName, Cubemap.class, params);
266 				}
267 			}
268 			managedCubemapArray.clear();
269 			managedCubemapArray.addAll(cubemaps);
270 		}
271 	}
272 
273 	/** Sets the {@link AssetManager}. When the context is lost, cubemaps managed by the asset manager are reloaded by the manager
274 	 * on a separate thread (provided that a suitable {@link AssetLoader} is registered with the manager). Cubemaps not managed by
275 	 * the AssetManager are reloaded via the usual means on the rendering thread.
276 	 * @param manager the asset manager. */
setAssetManager(AssetManager manager)277 	public static void setAssetManager (AssetManager manager) {
278 		Cubemap.assetManager = manager;
279 	}
280 
getManagedStatus()281 	public static String getManagedStatus () {
282 		StringBuilder builder = new StringBuilder();
283 		builder.append("Managed cubemap/app: { ");
284 		for (Application app : managedCubemaps.keySet()) {
285 			builder.append(managedCubemaps.get(app).size);
286 			builder.append(" ");
287 		}
288 		builder.append("}");
289 		return builder.toString();
290 	}
291 
292 	/** @return the number of managed cubemaps currently loaded */
getNumManagedCubemaps()293 	public static int getNumManagedCubemaps () {
294 		return managedCubemaps.get(Gdx.app).size;
295 	}
296 
297 }
298