159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/* 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2012 jMonkeyEngine 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved. 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met: 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer. 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * notice, this list of conditions and the following disclaimer in the 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * documentation and/or other materials provided with the distribution. 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * may be used to endorse or promote products derived from this software 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * without specific prior written permission. 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage jme3tools.optimize; 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetKey; 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.AssetManager; 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.material.MatParamTexture; 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.material.Material; 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector2f; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Geometry; 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Mesh; 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Spatial; 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer; 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Type; 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image; 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Image.Format; 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Texture; 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.texture.Texture2D; 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils; 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.lang.reflect.InvocationTargetException; 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.ByteBuffer; 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.FloatBuffer; 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList; 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.HashMap; 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.List; 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Map; 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.TreeMap; 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level; 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger; 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <b><code>TextureAtlas</code></b> allows combining multiple textures to one texture atlas. 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p>After the TextureAtlas has been created with a certain size, textures can be added for 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * freely chosen "map names". The textures are automatically placed on the atlas map and the 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * image data is stored in a byte array for each map name. Later each map can be retrieved as 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * a Texture to be used further in materials.</p> 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p>The first map name used is the "master map" that defines new locations on the atlas. Secondary 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * textures (other map names) have to reference a texture of the master map to position the texture 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * on the secondary map. This is necessary as the maps share texture coordinates and thus need to be 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * placed at the same location on both maps.</p> 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p>The helper methods that work with <code>Geometry</code> objects handle the <em>DiffuseMap</em> or <em>ColorMap</em> as the master map and 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * additionally handle <em>NormalMap</em> and <em>SpecularMap</em> as secondary maps.</p> 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p>The textures are referenced by their <b>asset key name</b> and for each texture the location 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * inside the atlas is stored. A texture with an existing key name is never added more than once 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * to the atlas. You can access the information for each texture or geometry texture via helper methods.</p> 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p>The TextureAtlas also allows you to change the texture coordinates of a mesh or geometry 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * to point at the new locations of its texture inside the atlas (if the texture exists inside the atlas).</p> 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p>Note that models that use texture coordinates outside the 0-1 range (repeating/wrapping textures) 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * will not work correctly as their new coordinates leak into other parts of the atlas and thus display 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * other textures instead of repeating the texture.</p> 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p>Also note that textures are not scaled and the atlas needs to be large enough to hold all textures. 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All methods that allow adding textures return false if the texture could not be added due to the 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * atlas being full. Furthermore secondary textures (normal, spcular maps etc.) have to be the same size 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * as the main (e.g. DiffuseMap) texture.</p> 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <p><b>Usage examples</b></p> 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Create one geometry out of several geometries that are loaded from a j3o file: 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <pre> 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Node scene = assetManager.loadModel("Scenes/MyScene.j3o"); 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Geometry geom = TextureAtlas.makeAtlasBatch(scene); 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * rootNode.attachChild(geom); 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * </pre> 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Create a texture atlas and change the texture coordinates of one geometry: 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * <pre> 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Node scene = assetManager.loadModel("Scenes/MyScene.j3o"); 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * //either auto-create from node: 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TextureAtlas atlas = TextureAtlas.createAtlas(scene); 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * //or create manually by adding textures or geometries with textures 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TextureAtlas atlas = new TextureAtlas(1024,1024); 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * atlas.addTexture(myTexture, "DiffuseMap"); 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * atlas.addGeometry(myGeometry); 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * //create material and set texture 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Material mat = new Material(mgr, "Common/MatDefs/Light/Lighting.j3md"); 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * mat.setTexture("DiffuseMap", atlas.getAtlasTexture("DiffuseMap")); 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * //change one geometry to use atlas, apply texture coordinates and replace material. 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Geometry geom = scene.getChild("MyGeometry"); 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * atlas.applyCoords(geom); 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * geom.setMaterial(mat); 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * </pre> 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author normenhansen, Lukasz Bruun - lukasz.dk 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class TextureAtlas { 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static final Logger logger = Logger.getLogger(TextureAtlas.class.getName()); 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Map<String, byte[]> images; 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int atlasWidth, atlasHeight; 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Format format = Format.ABGR8; 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Node root; 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Map<String, TextureAtlasTile> locationMap; 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Map<String, String> mapNameMap; 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private String rootMapName; 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TextureAtlas(int width, int height) { 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.atlasWidth = width; 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.atlasHeight = height; 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta root = new Node(0, 0, width, height); 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta locationMap = new TreeMap<String, TextureAtlasTile>(); 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mapNameMap = new HashMap<String, String>(); 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Add a geometries DiffuseMap (or ColorMap), NormalMap and SpecularMap to the atlas. 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param geometry 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return false if the atlas is full. 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean addGeometry(Geometry geometry) { 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture diffuse = getMaterialTexture(geometry, "DiffuseMap"); 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture normal = getMaterialTexture(geometry, "NormalMap"); 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture specular = getMaterialTexture(geometry, "SpecularMap"); 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (diffuse == null) { 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta diffuse = getMaterialTexture(geometry, "ColorMap"); 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (diffuse != null && diffuse.getKey() != null) { 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String keyName = diffuse.getKey().toString(); 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!addTexture(diffuse, "DiffuseMap")) { 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (normal != null && normal.getKey() != null) { 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta addTexture(diffuse, "NormalMap", keyName); 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (specular != null && specular.getKey() != null) { 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta addTexture(specular, "SpecularMap", keyName); 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Add a texture for a specific map name 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param texture A texture to add to the atlas. 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mapName A freely chosen map name that can be later retrieved as a Texture. The first map name supplied will be the master map. 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return false if the atlas is full. 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean addTexture(Texture texture, String mapName) { 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (texture == null) { 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Texture cannot be null!"); 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String name = textureName(texture); 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (texture.getImage() != null && name != null) { 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return addImage(texture.getImage(), name, mapName, null); 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Texture has no asset key name!"); 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Add a texture for a specific map name at the location of another existing texture on the master map. 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param texture A texture to add to the atlas. 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mapName A freely chosen map name that can be later retrieved as a Texture. 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param masterTexture The master texture for determining the location, it has to exist in tha master map. 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void addTexture(Texture texture, String mapName, Texture masterTexture) { 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String sourceTextureName = textureName(masterTexture); 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (sourceTextureName == null) { 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Supplied master map texture has no asset key name!"); 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta addTexture(texture, mapName, sourceTextureName); 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Add a texture for a specific map name at the location of another existing texture (on the master map). 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param texture A texture to add to the atlas. 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mapName A freely chosen map name that can be later retrieved as a Texture. 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param sourceTextureName Name of the master map used for the location. 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void addTexture(Texture texture, String mapName, String sourceTextureName) { 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (texture == null) { 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Texture cannot be null!"); 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String name = textureName(texture); 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (texture.getImage() != null && name != null) { 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta addImage(texture.getImage(), name, mapName, sourceTextureName); 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Texture has no asset key name!"); 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private String textureName(Texture texture) { 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (texture == null) { 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta AssetKey key = texture.getKey(); 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (key != null) { 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return key.toString(); 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean addImage(Image image, String name, String mapName, String sourceTextureName) { 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (rootMapName == null) { 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rootMapName = mapName; 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (sourceTextureName == null && !rootMapName.equals(mapName)) { 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Atlas already has a master map called " + rootMapName + "." 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta + " Textures for new maps have to use a texture from the master map for their location."); 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TextureAtlasTile location = locationMap.get(name); 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (location != null) { 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //have location for texture 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!mapName.equals(mapNameMap.get(name))) { 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "Same texture " + name + " is used in different maps! (" + mapName + " and " + mapNameMap.get(name) + "). Location will be based on location in " + mapNameMap.get(name) + "!"); 24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta drawImage(image, location.getX(), location.getY(), mapName); 24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (sourceTextureName == null) { 25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //need to make new tile 25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node node = root.insert(image); 25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (node == null) { 25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta location = node.location; 25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //got old tile to align to 25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta location = locationMap.get(sourceTextureName); 25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (location == null) { 26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Cannot find master map texture for " + name + "."); 26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (location.width != image.getWidth() || location.height != image.getHeight()) { 26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException(mapName + " " + name + " does not fit " + rootMapName + " tile size. Make sure all textures (diffuse, normal, specular) for one model are the same size."); 26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mapNameMap.put(name, mapName); 26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta locationMap.put(name, location); 26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta drawImage(image, location.getX(), location.getY(), mapName); 26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void drawImage(Image source, int x, int y, String mapName) { 27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (images == null) { 27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta images = new HashMap<String, byte[]>(); 27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] image = images.get(mapName); 27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (image == null) { 27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image = new byte[atlasWidth * atlasHeight * 4]; 27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta images.put(mapName, image); 27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //TODO: all buffers? 28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer sourceData = source.getData(0); 28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int height = source.getHeight(); 28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int width = source.getWidth(); 28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Image newImage = null; 28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int yPos = 0; yPos < height; yPos++) { 28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int xPos = 0; xPos < width; xPos++) { 28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int i = ((xPos + x) + (yPos + y) * atlasWidth) * 4; 28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (source.getFormat() == Format.ABGR8) { 28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int j = (xPos + yPos * width) * 4; 29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i] = sourceData.get(j); //a 29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 1] = sourceData.get(j + 1); //b 29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 2] = sourceData.get(j + 2); //g 29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 3] = sourceData.get(j + 3); //r 29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (source.getFormat() == Format.BGR8) { 29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int j = (xPos + yPos * width) * 3; 29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i] = 1; //a 29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 1] = sourceData.get(j); //b 29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 2] = sourceData.get(j + 1); //g 29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 3] = sourceData.get(j + 2); //r 30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (source.getFormat() == Format.RGB8) { 30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int j = (xPos + yPos * width) * 3; 30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i] = 1; //a 30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 1] = sourceData.get(j + 2); //b 30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 2] = sourceData.get(j + 1); //g 30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 3] = sourceData.get(j); //r 30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (source.getFormat() == Format.RGBA8) { 30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int j = (xPos + yPos * width) * 4; 30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i] = sourceData.get(j + 3); //a 30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 1] = sourceData.get(j + 2); //b 31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 2] = sourceData.get(j + 1); //g 31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 3] = sourceData.get(j); //r 31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (source.getFormat() == Format.Luminance8) { 31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int j = (xPos + yPos * width) * 1; 31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i] = 1; //a 31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 1] = sourceData.get(j); //b 31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 2] = sourceData.get(j); //g 31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 3] = sourceData.get(j); //r 31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (source.getFormat() == Format.Luminance8Alpha8) { 31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int j = (xPos + yPos * width) * 2; 32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i] = sourceData.get(j + 1); //a 32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 1] = sourceData.get(j); //b 32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 2] = sourceData.get(j); //g 32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 3] = sourceData.get(j); //r 32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //ImageToAwt conversion 32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (newImage == null) { 32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta newImage = convertImageToAwt(source); 32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (newImage != null) { 32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta source = newImage; 33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta sourceData = source.getData(0); 33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int j = (xPos + yPos * width) * 4; 33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i] = sourceData.get(j); //a 33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 1] = sourceData.get(j + 1); //b 33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 2] = sourceData.get(j + 2); //g 33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta image[i + 3] = sourceData.get(j + 3); //r 33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta }else{ 33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new UnsupportedOperationException("Cannot draw or convert textures with format " + source.getFormat()); 33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new UnsupportedOperationException("Cannot draw textures with format " + source.getFormat()); 34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Image convertImageToAwt(Image source) { 34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //use awt dependent classes without actual dependency via reflection 34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta try { 35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Class clazz = Class.forName("jme3tools.converters.ImageToAwt"); 35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (clazz == null) { 35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Image newImage = new Image(format, source.getWidth(), source.getHeight(), BufferUtils.createByteBuffer(source.getWidth() * source.getHeight() * 4)); 35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clazz.getMethod("convert", Image.class, Image.class).invoke(clazz.newInstance(), source, newImage); 35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return newImage; 35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (InstantiationException ex) { 35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (IllegalAccessException ex) { 35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (IllegalArgumentException ex) { 36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (InvocationTargetException ex) { 36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (NoSuchMethodException ex) { 36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (SecurityException ex) { 36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } catch (ClassNotFoundException ex) { 36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Get the <code>TextureAtlasTile</code> for the given Texture 37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param texture The texture to retrieve the <code>TextureAtlasTile</code> for. 37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return 37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TextureAtlasTile getAtlasTile(Texture texture) { 37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta String sourceTextureName = textureName(texture); 37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (sourceTextureName != null) { 37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return getAtlasTile(sourceTextureName); 37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Get the <code>TextureAtlasTile</code> for the given Texture 38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param assetName The texture to retrieve the <code>TextureAtlasTile</code> for. 38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return 38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private TextureAtlasTile getAtlasTile(String assetName) { 38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return locationMap.get(assetName); 38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Creates a new atlas texture for the given map name. 39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mapName 39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return 39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Texture getAtlasTexture(String mapName) { 39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (images == null) { 39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] image = images.get(mapName); 40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (image != null) { 40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture2D tex = new Texture2D(new Image(format, atlasWidth, atlasHeight, BufferUtils.createByteBuffer(image))); 40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tex.setMagFilter(Texture.MagFilter.Bilinear); 40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tex.setMinFilter(Texture.MinFilter.BilinearNearestMipMap); 40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tex.setWrap(Texture.WrapMode.Clamp); 40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return tex; 40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Applies the texture coordinates to the given geometry 41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * if its DiffuseMap or ColorMap exists in the atlas. 41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param geom The geometry to change the texture coordinate buffer on. 41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return true if texture has been found and coords have been changed, false otherwise. 41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean applyCoords(Geometry geom) { 41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return applyCoords(geom, 0, geom.getMesh()); 41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Applies the texture coordinates to the given output mesh 42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * if the DiffuseMap or ColorMap of the input geometry exist in the atlas. 42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param geom The geometry to change the texture coordinate buffer on. 42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offset Target buffer offset. 42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param outMesh The mesh to set the coords in (can be same as input). 42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return true if texture has been found and coords have been changed, false otherwise. 42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean applyCoords(Geometry geom, int offset, Mesh outMesh) { 42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh inMesh = geom.getMesh(); 43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geom.computeWorldMatrix(); 43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer inBuf = inMesh.getBuffer(Type.TexCoord); 43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer outBuf = outMesh.getBuffer(Type.TexCoord); 43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (inBuf == null || outBuf == null) { 43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Geometry mesh has no texture coordinate buffer."); 43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture tex = getMaterialTexture(geom, "DiffuseMap"); 44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (tex == null) { 44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tex = getMaterialTexture(geom, "ColorMap"); 44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (tex != null) { 44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TextureAtlasTile tile = getAtlasTile(tex); 44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (tile != null) { 44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer inPos = (FloatBuffer) inBuf.getData(); 44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer outPos = (FloatBuffer) outBuf.getData(); 44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tile.transformTextureCoords(inPos, offset, outPos); 45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return true; 45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return false; 45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Geometry has no proper texture."); 45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Create a texture atlas for the given root node, containing DiffuseMap, NormalMap and SpecularMap. 46159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param root The rootNode to create the atlas for. 46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param atlasSize The size of the atlas (width and height). 46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return Null if the atlas cannot be created because not all textures fit. 46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public static TextureAtlas createAtlas(Spatial root, int atlasSize) { 46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> geometries = new ArrayList<Geometry>(); 46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta GeometryBatchFactory.gatherGeoms(root, geometries); 46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TextureAtlas atlas = new TextureAtlas(atlasSize, atlasSize); 46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Geometry geometry : geometries) { 47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!atlas.addGeometry(geometry)) { 47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta logger.log(Level.WARNING, "Texture atlas size too small, cannot add all textures"); 47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return atlas; 47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Creates one geometry out of the given root spatial and merges all single 48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * textures into one texture of the given size. 48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param spat The root spatial of the scene to batch 48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mgr An assetmanager that can be used to create the material. 48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param atlasSize A size for the atlas texture, it has to be large enough to hold all single textures. 48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return A new geometry that uses the generated texture atlas and merges all meshes of the root spatial, null if the atlas cannot be created because not all textures fit. 48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 48659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public static Geometry makeAtlasBatch(Spatial spat, AssetManager mgr, int atlasSize) { 48759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta List<Geometry> geometries = new ArrayList<Geometry>(); 48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta GeometryBatchFactory.gatherGeoms(spat, geometries); 48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TextureAtlas atlas = createAtlas(spat, atlasSize); 49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (atlas == null) { 49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Geometry geom = new Geometry(); 49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh mesh = new Mesh(); 49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta GeometryBatchFactory.mergeGeometries(geometries, mesh); 49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta applyAtlasCoords(geometries, mesh, atlas); 49759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mesh.updateCounts(); 49859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mesh.updateBound(); 49959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geom.setMesh(mesh); 50059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Material mat = new Material(mgr, "Common/MatDefs/Light/Lighting.j3md"); 50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mat.getAdditionalRenderState().setAlphaTest(true); 50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture diffuseMap = atlas.getAtlasTexture("DiffuseMap"); 50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture normalMap = atlas.getAtlasTexture("NormalMap"); 50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture specularMap = atlas.getAtlasTexture("SpecularMap"); 50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (diffuseMap != null) { 50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mat.setTexture("DiffuseMap", diffuseMap); 50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 50959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (normalMap != null) { 51059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mat.setTexture("NormalMap", normalMap); 51159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (specularMap != null) { 51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mat.setTexture("SpecularMap", specularMap); 51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mat.setFloat("Shininess", 16.0f); 51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geom.setMaterial(mat); 51859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return geom; 51959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static void applyAtlasCoords(List<Geometry> geometries, Mesh outMesh, TextureAtlas atlas) { 52259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int globalVertIndex = 0; 52359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Geometry geom : geometries) { 52559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh inMesh = geom.getMesh(); 52659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta geom.computeWorldMatrix(); 52759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int geomVertCount = inMesh.getVertexCount(); 52959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer inBuf = inMesh.getBuffer(Type.TexCoord); 53159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer outBuf = outMesh.getBuffer(Type.TexCoord); 53259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (inBuf == null || outBuf == null) { 53459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; 53559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 53659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta atlas.applyCoords(geom, globalVertIndex, outMesh); 53859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta globalVertIndex += geomVertCount; 54059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 54159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 54259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 54359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private static Texture getMaterialTexture(Geometry geometry, String mapName) { 54459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Material mat = geometry.getMaterial(); 54559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (mat == null || mat.getParam(mapName) == null || !(mat.getParam(mapName) instanceof MatParamTexture)) { 54659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 54759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 54859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta MatParamTexture param = (MatParamTexture) mat.getParam(mapName); 54959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Texture texture = param.getTextureValue(); 55059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (texture == null) { 55159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; 55259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 55359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return texture; 55459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 55559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 55659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 55759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 55859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private class Node { 55959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 56059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TextureAtlasTile location; 56159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Node child[]; 56259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean occupied; 56359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 56459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Node(int x, int y, int width, int height) { 56559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta location = new TextureAtlasTile(x, y, width, height); 56659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child = new Node[2]; 56759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child[0] = null; 56859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child[1] = null; 56959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta occupied = false; 57059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 57159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 57259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public boolean isLeaf() { 57359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return child[0] == null && child[1] == null; 57459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 57559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 57659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // Algorithm from http://www.blackpawn.com/texts/lightmaps/ 57759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Node insert(Image image) { 57859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!isLeaf()) { 57959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node newNode = child[0].insert(image); 58059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (newNode != null) { 58259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return newNode; 58359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 58459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 58559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return child[1].insert(image); 58659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 58759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (occupied) { 58859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; // occupied 58959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 59059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 59159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (image.getWidth() > location.getWidth() || image.getHeight() > location.getHeight()) { 59259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return null; // does not fit 59359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 59459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 59559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (image.getWidth() == location.getWidth() && image.getHeight() == location.getHeight()) { 59659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta occupied = true; // perfect fit 59759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return this; 59859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 59959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 60059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int dw = location.getWidth() - image.getWidth(); 60159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int dh = location.getHeight() - image.getHeight(); 60259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 60359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (dw > dh) { 60459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child[0] = new Node(location.getX(), location.getY(), image.getWidth(), location.getHeight()); 60559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child[1] = new Node(location.getX() + image.getWidth(), location.getY(), location.getWidth() - image.getWidth(), location.getHeight()); 60659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 60759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child[0] = new Node(location.getX(), location.getY(), location.getWidth(), image.getHeight()); 60859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta child[1] = new Node(location.getX(), location.getY() + image.getHeight(), location.getWidth(), location.getHeight() - image.getHeight()); 60959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 61059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 61159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return child[0].insert(image); 61259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 61359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 61459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 61559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 61659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public class TextureAtlasTile { 61759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 61859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int x; 61959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int y; 62059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int width; 62159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private int height; 62259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 62359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public TextureAtlasTile(int x, int y, int width, int height) { 62459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.x = x; 62559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.y = y; 62659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.width = width; 62759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.height = height; 62859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 62959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 63059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 63159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Get the transformed texture coordinate for a given input location. 63259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param previousLocation The old texture coordinate. 63359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return The new texture coordinate inside the atlas. 63459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 63559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Vector2f getLocation(Vector2f previousLocation) { 63659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float x = (float) getX() / (float) atlasWidth; 63759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float y = (float) getY() / (float) atlasHeight; 63859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float w = (float) getWidth() / (float) atlasWidth; 63959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float h = (float) getHeight() / (float) atlasHeight; 64059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector2f location = new Vector2f(x, y); 64159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float prevX = previousLocation.x; 64259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float prevY = previousLocation.y; 64359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta location.addLocal(prevX * w, prevY * h); 64459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return location; 64559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 64659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 64759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 64859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Transforms a whole texture coordinates buffer. 64959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param inBuf The input texture buffer. 65059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offset The offset in the output buffer 65159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param outBuf The output buffer. 65259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 65359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void transformTextureCoords(FloatBuffer inBuf, int offset, FloatBuffer outBuf) { 65459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector2f tex = new Vector2f(); 65559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 65659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // offset is given in element units 65759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // convert to be in component units 65859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta offset *= 2; 65959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 66059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < inBuf.capacity() / 2; i++) { 66159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tex.x = inBuf.get(i * 2 + 0); 66259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tex.y = inBuf.get(i * 2 + 1); 66359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Vector2f location = getLocation(tex); 66459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //TODO: add proper texture wrapping for atlases.. 66559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta outBuf.put(offset + i * 2 + 0, location.x); 66659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta outBuf.put(offset + i * 2 + 1, location.y); 66759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 66859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 66959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 67059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getX() { 67159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return x; 67259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 67359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 67459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getY() { 67559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return y; 67659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 67759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 67859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getWidth() { 67959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return width; 68059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 68159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 68259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public int getHeight() { 68359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return height; 68459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 68559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 68659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 687