diff --git a/engine/src/tools/jme3tools/optimize/TextureAtlas.java b/engine/src/tools/jme3tools/optimize/TextureAtlas.java index c1885a88c..d43267754 100644 --- a/engine/src/tools/jme3tools/optimize/TextureAtlas.java +++ b/engine/src/tools/jme3tools/optimize/TextureAtlas.java @@ -35,14 +35,12 @@ import com.jme3.asset.AssetKey; import com.jme3.asset.AssetManager; import com.jme3.material.MatParamTexture; import com.jme3.material.Material; -import com.jme3.math.Matrix4f; import com.jme3.math.Vector2f; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; import com.jme3.scene.Spatial; import com.jme3.scene.VertexBuffer; import com.jme3.scene.VertexBuffer.Type; -import com.jme3.scene.mesh.IndexBuffer; import com.jme3.texture.Image; import com.jme3.texture.Image.Format; import com.jme3.texture.Texture; @@ -261,17 +259,63 @@ public class TextureAtlas { } /** - * Creates one geometry out of the given root spatial and merges all single - * textures into one texture of the given size. - * @param spat The root spatial of the scene to batch - * @param mgr An assetmanager that can be used to create the material - * @param atlasSize A size for the atlas texture, it has to be large enough to hold all single textures - * @return + * Applies the texture coordinates to the given geometry + * if its DiffuseMap or ColorMap exists in the atlas. + * @param geom The geometry to change the texture coordinate buffer on. + * @return true if texture has been found and coords have been changed, false otherwise */ - public static Geometry makeAtlasBatch(Spatial spat, AssetManager mgr, int atlasSize) { + public boolean applyCoords(Geometry geom) { + return applyCoords(geom, 0, geom.getMesh()); + } + + /** + * Applies the texture coordinates to the given geometry + * if its DiffuseMap or ColorMap exists in the atlas. + * @param geom The geometry to change the texture coordinate buffer on. + * @param offset Target buffer offset + * @param outMesh The mesh to set the coords in (can be same as input) + * @return true if texture has been found and coords have been changed, false otherwise + */ + public boolean applyCoords(Geometry geom, int offset, Mesh outMesh) { + Mesh inMesh = geom.getMesh(); + geom.computeWorldMatrix(); + + VertexBuffer inBuf = inMesh.getBuffer(Type.TexCoord); + VertexBuffer outBuf = outMesh.getBuffer(Type.TexCoord); + + if (inBuf == null || outBuf == null) { + throw new IllegalStateException("Geometry mesh has no texture coordinate buffer."); + } + + Texture tex = getMaterialTexture(geom, "DiffuseMap"); + if (tex == null) { + tex = getMaterialTexture(geom, "ColorMap"); + + } + if (tex != null) { + TextureAtlasTile tile = getAtlasTile(tex); + if (tile != null) { + FloatBuffer inPos = (FloatBuffer) inBuf.getData(); + FloatBuffer outPos = (FloatBuffer) outBuf.getData(); + tile.transformTextureCoords(inPos, offset, outPos); + return true; + } else { + return false; + } + } else { + throw new IllegalStateException("Geometry has no proper texture."); + } + } + + /** + * Create a texture atlas for the given root node, containing DiffuseMap, NormalMap and SpecularMap. + * @param root The rootNode to create the atlas for + * @param atlasSize The size of the atlas (width and height) + * @return Null if the atlas cannot be created because not all textures fit + */ + public static TextureAtlas createAtlas(Spatial root, int atlasSize) { List geometries = new ArrayList(); - GeometryBatchFactory.gatherGeoms(spat, geometries); - //TODO: specular etc. maps, needs to use main atlas for locations + GeometryBatchFactory.gatherGeoms(root, geometries); TextureAtlas atlas = new TextureAtlas(atlasSize, atlasSize); for (Geometry geometry : geometries) { Texture diffuse = getMaterialTexture(geometry, "DiffuseMap"); @@ -284,7 +328,7 @@ public class TextureAtlas { if (diffuse != null && diffuse.getKey() != null) { String keyName = diffuse.getKey().getName(); if (!atlas.addTexture(diffuse, "DiffuseMap")) { - throw new IllegalStateException("Adding diffuse texture" + keyName + "to atlas failed, atlas full."); + return null; } else { if (normal != null && normal.getKey() != null) { atlas.addTexture(diffuse, "NormalMap", keyName); @@ -295,6 +339,24 @@ public class TextureAtlas { } } } + return atlas; + } + + /** + * Creates one geometry out of the given root spatial and merges all single + * textures into one texture of the given size. + * @param spat The root spatial of the scene to batch + * @param mgr An assetmanager that can be used to create the material + * @param atlasSize A size for the atlas texture, it has to be large enough to hold all single textures + * @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 + */ + public static Geometry makeAtlasBatch(Spatial spat, AssetManager mgr, int atlasSize) { + List geometries = new ArrayList(); + GeometryBatchFactory.gatherGeoms(spat, geometries); + TextureAtlas atlas = createAtlas(spat, atlasSize); + if (atlas == null) { + return null; + } Geometry geom = new Geometry(); Mesh mesh = new Mesh(); GeometryBatchFactory.mergeGeometries(geometries, mesh); @@ -339,19 +401,7 @@ public class TextureAtlas { continue; } - Texture tex = getMaterialTexture(geom, "DiffuseMap"); - if (tex == null) { - tex = getMaterialTexture(geom, "ColorMap"); - - } - if (tex != null) { - TextureAtlasTile tile = atlas.getAtlasTile(tex); - if (tile != null) { - FloatBuffer inPos = (FloatBuffer) inBuf.getData(); - FloatBuffer outPos = (FloatBuffer) outBuf.getData(); - tile.transformTextureCoords(inPos, globalVertIndex, outPos); - } - } + atlas.applyCoords(geom, globalVertIndex, outMesh); globalVertIndex += geomVertCount; }