Path: blob/master/SLICK_HOME/src/org/newdawn/slick/opengl/InternalTextureLoader.java
1461 views
package org.newdawn.slick.opengl;12import java.io.BufferedInputStream;3import java.io.File;4import java.io.FileInputStream;5import java.io.IOException;6import java.io.InputStream;7import java.lang.ref.SoftReference;8import java.nio.ByteBuffer;9import java.nio.ByteOrder;10import java.nio.IntBuffer;11import java.util.HashMap;1213import org.lwjgl.BufferUtils;14import org.lwjgl.opengl.GL11;15import org.newdawn.slick.util.ResourceLoader;1617/**18* A texture loaded based on many old versions that will load image data from a file19* and produce OpenGL textures.20*21* @see ImageData22*23* @author kevin24*/25public class InternalTextureLoader {26/** The standard texture loaded used everywhere */27private static final InternalTextureLoader loader = new InternalTextureLoader();2829/**30* Get the single instance of this texture loader31*32* @return The single instance of the texture loader33*/34public static InternalTextureLoader get() {35return loader;36}3738/** The table of textures that have been loaded in this loader */39private HashMap texturesLinear = new HashMap();40/** The table of textures that have been loaded in this loader */41private HashMap texturesNearest = new HashMap();42/** The destination pixel format */43private int dstPixelFormat = GL11.GL_RGBA8;44/** True if we're using deferred loading */45private boolean deferred;4647/**48* Create a new texture loader based on the game panel49*/50private InternalTextureLoader() {51}5253/**54* True if we should only record the request to load in the intention55* of loading the texture later56*57* @param deferred True if the we should load a token58*/59public void setDeferredLoading(boolean deferred) {60this.deferred = deferred;61}6263/**64* Check if we're using deferred loading65*66* @return True if we're loading deferred textures67*/68public boolean isDeferredLoading() {69return deferred;70}7172/**73* Remove a particular named image from the cache74*75* @param name The name of the image to be cleared76*/77public void clear(String name) {78texturesLinear.remove(name);79texturesNearest.remove(name);80}8182/**83* Clear out the cached textures84*/85public void clear() {86texturesLinear.clear();87texturesNearest.clear();88}8990/**91* Tell the loader to produce 16 bit textures92*/93public void set16BitMode() {94dstPixelFormat = GL11.GL_RGBA16;95}9697/**98* Create a new texture ID99*100* @return A new texture ID101*/102public static int createTextureID()103{104IntBuffer tmp = createIntBuffer(1);105GL11.glGenTextures(tmp);106return tmp.get(0);107}108109/**110* Get a texture from a specific file111*112* @param source The file to load the texture from113* @param flipped True if we should flip the texture on the y axis while loading114* @param filter The filter to use115* @return The texture loaded116* @throws IOException Indicates a failure to load the image117*/118public Texture getTexture(File source, boolean flipped,int filter) throws IOException {119String resourceName = source.getAbsolutePath();120InputStream in = new FileInputStream(source);121122return getTexture(in, resourceName, flipped, filter, null);123}124125/**126* Get a texture from a specific file127*128* @param source The file to load the texture from129* @param flipped True if we should flip the texture on the y axis while loading130* @param filter The filter to use131* @param transparent The colour to interpret as transparent or null if none132* @return The texture loaded133* @throws IOException Indicates a failure to load the image134*/135public Texture getTexture(File source, boolean flipped,int filter, int[] transparent) throws IOException {136String resourceName = source.getAbsolutePath();137InputStream in = new FileInputStream(source);138139return getTexture(in, resourceName, flipped, filter, transparent);140}141142/**143* Get a texture from a resource location144*145* @param resourceName The location to load the texture from146* @param flipped True if we should flip the texture on the y axis while loading147* @param filter The filter to use when scaling the texture148* @return The texture loaded149* @throws IOException Indicates a failure to load the image150*/151public Texture getTexture(String resourceName, boolean flipped, int filter) throws IOException {152InputStream in = ResourceLoader.getResourceAsStream(resourceName);153154return getTexture(in, resourceName, flipped, filter, null);155}156157/**158* Get a texture from a resource location159*160* @param resourceName The location to load the texture from161* @param flipped True if we should flip the texture on the y axis while loading162* @param filter The filter to use when scaling the texture163* @param transparent The colour to interpret as transparent or null if none164* @return The texture loaded165* @throws IOException Indicates a failure to load the image166*/167public Texture getTexture(String resourceName, boolean flipped, int filter, int[] transparent) throws IOException {168InputStream in = ResourceLoader.getResourceAsStream(resourceName);169170return getTexture(in, resourceName, flipped, filter, transparent);171}172/**173* Get a texture from a image file174*175* @param in The stream from which we can load the image176* @param resourceName The name to give this image in the internal cache177* @param flipped True if we should flip the image on the y-axis while loading178* @param filter The filter to use when scaling the texture179* @return The texture loaded180* @throws IOException Indicates a failure to load the image181*/182public Texture getTexture(InputStream in, String resourceName, boolean flipped, int filter) throws IOException {183return getTexture(in, resourceName, flipped, filter, null);184}185186/**187* Get a texture from a image file188*189* @param in The stream from which we can load the image190* @param resourceName The name to give this image in the internal cache191* @param flipped True if we should flip the image on the y-axis while loading192* @param filter The filter to use when scaling the texture193* @param transparent The colour to interpret as transparent or null if none194* @return The texture loaded195* @throws IOException Indicates a failure to load the image196*/197public TextureImpl getTexture(InputStream in, String resourceName, boolean flipped, int filter, int[] transparent) throws IOException {198if (deferred) {199return new DeferredTexture(in, resourceName, flipped, filter, transparent);200}201202HashMap hash = texturesLinear;203if (filter == GL11.GL_NEAREST) {204hash = texturesNearest;205}206207String resName = resourceName;208if (transparent != null) {209resName += ":"+transparent[0]+":"+transparent[1]+":"+transparent[2];210}211resName += ":"+flipped;212213SoftReference ref = (SoftReference) hash.get(resName);214if (ref != null) {215TextureImpl tex = (TextureImpl) ref.get();216if (tex != null) {217return tex;218} else {219hash.remove(resName);220}221}222223// horrible test until I can find something more suitable224try {225GL11.glGetError();226} catch (NullPointerException e) {227throw new RuntimeException("Image based resources must be loaded as part of init() or the game loop. They cannot be loaded before initialisation.");228}229230TextureImpl tex = getTexture(in, resourceName,231GL11.GL_TEXTURE_2D,232filter,233filter, flipped, transparent);234235tex.setCacheName(resName);236hash.put(resName, new SoftReference(tex));237238return tex;239}240241/**242* Get a texture from a image file243*244* @param in The stream from which we can load the image245* @param resourceName The name to give this image in the internal cache246* @param flipped True if we should flip the image on the y-axis while loading247* @param target The texture target we're loading this texture into248* @param minFilter The scaling down filter249* @param magFilter The scaling up filter250* @param transparent The colour to interpret as transparent or null if none251* @return The texture loaded252* @throws IOException Indicates a failure to load the image253*/254private TextureImpl getTexture(InputStream in,255String resourceName,256int target,257int magFilter,258int minFilter, boolean flipped, int[] transparent) throws IOException259{260// create the texture ID for this texture261int textureID = createTextureID();262TextureImpl texture = new TextureImpl(resourceName, target, textureID);263264// bind this texture265GL11.glBindTexture(target, textureID);266267ByteBuffer textureBuffer;268int width;269int height;270int texWidth;271int texHeight;272273boolean hasAlpha;274275LoadableImageData imageData = ImageDataFactory.getImageDataFor(resourceName);276textureBuffer = imageData.loadImage(new BufferedInputStream(in), flipped, transparent);277278width = imageData.getWidth();279height = imageData.getHeight();280hasAlpha = imageData.getDepth() == 32;281282texture.setTextureWidth(imageData.getTexWidth());283texture.setTextureHeight(imageData.getTexHeight());284285texWidth = texture.getTextureWidth();286texHeight = texture.getTextureHeight();287288IntBuffer temp = BufferUtils.createIntBuffer(16);289GL11.glGetInteger(GL11.GL_MAX_TEXTURE_SIZE, temp);290int max = temp.get(0);291if ((texWidth > max) || (texHeight > max)) {292throw new IOException("Attempt to allocate a texture to big for the current hardware");293}294295int srcPixelFormat = hasAlpha ? GL11.GL_RGBA : GL11.GL_RGB;296int componentCount = hasAlpha ? 4 : 3;297298texture.setWidth(width);299texture.setHeight(height);300texture.setAlpha(hasAlpha);301302GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);303GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);304305// produce a texture from the byte buffer306GL11.glTexImage2D(target,3070,308dstPixelFormat,309get2Fold(width),310get2Fold(height),3110,312srcPixelFormat,313GL11.GL_UNSIGNED_BYTE,314textureBuffer);315316return texture;317}318319/**320* Create an empty texture321*322* @param width The width of the new texture323* @param height The height of the new texture324* @return The created empty texture325* @throws IOException Indicates a failure to create the texture on the graphics hardware326*/327public Texture createTexture(final int width, final int height) throws IOException {328return createTexture(width, height, GL11.GL_NEAREST);329}330331/**332* Create an empty texture333*334* @param width The width of the new texture335* @param height The height of the new texture336* @return The created empty texture337* @throws IOException Indicates a failure to create the texture on the graphics hardware338*/339public Texture createTexture(final int width, final int height, final int filter) throws IOException {340ImageData ds = new EmptyImageData(width, height);341342return getTexture(ds, filter);343}344345/**346* Get a texture from a image file347*348* @param dataSource The image data to generate the texture from349* @param filter The filter to use when scaling the texture350* @return The texture created351* @throws IOException Indicates the texture is too big for the hardware352*/353public Texture getTexture(ImageData dataSource, int filter) throws IOException354{355int target = GL11.GL_TEXTURE_2D;356357// create the texture ID for this texture358int textureID = createTextureID();359TextureImpl texture = new TextureImpl("generated:"+dataSource, target ,textureID);360361int minFilter = filter;362int magFilter = filter;363boolean flipped = false;364365// bind this texture366GL11.glBindTexture(target, textureID);367368ByteBuffer textureBuffer;369int width;370int height;371int texWidth;372int texHeight;373374boolean hasAlpha;375textureBuffer = dataSource.getImageBufferData();376377width = dataSource.getWidth();378height = dataSource.getHeight();379hasAlpha = dataSource.getDepth() == 32;380381texture.setTextureWidth(dataSource.getTexWidth());382texture.setTextureHeight(dataSource.getTexHeight());383384texWidth = texture.getTextureWidth();385texHeight = texture.getTextureHeight();386387int srcPixelFormat = hasAlpha ? GL11.GL_RGBA : GL11.GL_RGB;388int componentCount = hasAlpha ? 4 : 3;389390texture.setWidth(width);391texture.setHeight(height);392texture.setAlpha(hasAlpha);393394IntBuffer temp = BufferUtils.createIntBuffer(16);395GL11.glGetInteger(GL11.GL_MAX_TEXTURE_SIZE, temp);396int max = temp.get(0);397if ((texWidth > max) || (texHeight > max)) {398throw new IOException("Attempt to allocate a texture to big for the current hardware");399}400401GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);402GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);403404// produce a texture from the byte buffer405GL11.glTexImage2D(target,4060,407dstPixelFormat,408get2Fold(width),409get2Fold(height),4100,411srcPixelFormat,412GL11.GL_UNSIGNED_BYTE,413textureBuffer);414415return texture;416}417418/**419* Get the closest greater power of 2 to the fold number420*421* @param fold The target number422* @return The power of 2423*/424public static int get2Fold(int fold) {425int ret = 2;426while (ret < fold) {427ret *= 2;428}429return ret;430}431432/**433* Creates an integer buffer to hold specified ints434* - strictly a utility method435*436* @param size how many int to contain437* @return created IntBuffer438*/439public static IntBuffer createIntBuffer(int size) {440ByteBuffer temp = ByteBuffer.allocateDirect(4 * size);441temp.order(ByteOrder.nativeOrder());442443return temp.asIntBuffer();444}445}446447448