package org.simantics.proconf.g3d.base; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import org.eclipse.swt.graphics.ImageData; import org.simantics.db.Graph; import org.simantics.db.Resource; import org.simantics.proconf.g3d.Resources; import org.simantics.proconf.g3d.stubs.ImageTexture; import org.simantics.proconf.g3d.stubs.TextureCoordinateGenerator; import org.simantics.proconf.image.interfaces.IImage; import org.simantics.proconf.image.interfaces.IImageFactory; import org.simantics.utils.ui.ErrorLogger; import org.simantics.utils.ui.gfx.ImageUtils; import org.simantics.utils.ui.gfx.PixelDimension; import com.jme.image.Image; import com.jme.image.Texture; import com.jme.util.TextureManager; /** * Caches resource based textures. * TODO : use queries to update textures, now textures are read once and cannot be updated * TODO : either use shared context or use separate cache for each editor * TODO : ShapeNode implementation won't use release texture yet * TODO : Texture is released when reference count goes to zero; we probably want to wait for a while before texture is released because it might be used again. * * @author Marko Luukkainen * */ public class ResourceTextureCache { public static PixelDimension DEFAULT_SIZE = new PixelDimension(128,128); private static ResourceTextureCache instance = new ResourceTextureCache(); private Map images = new HashMap(); private Map imageReferences = new HashMap(); private Map textures = new HashMap(); private Map textureReferences = new HashMap(); private ResourceTextureCache() { } public Texture loadTexture(Graph g, Resource res) { Texture t = textures.get(res); if (t == null) { ImageTexture it = new ImageTexture(g,res); org.simantics.image.stubs.Image pattern = it.getImage(); Image image = loadImage(g, pattern.getResource()); // image.getData().rewind(); // while (image.getData().hasRemaining()) // image.getData().put((byte)(Math.random()*256.0 - 127.0)); if (image == null) { return null; } t = new Texture(); t.setImage(image); //t = TextureManager.loadTexture(image, Texture.MM_LINEAR, Texture.FM_LINEAR); // t.setImageLocation(res.toString()); // URL url = FileLocator.find(com.jme.eclipse.Activator.getDefault().getBundle(),new Path("data/texture/clouds.png"),null); // t = TextureManager.loadTexture(url, Texture.MM_LINEAR, Texture.FM_LINEAR); t.setFilter(com.jme.image.Texture.FM_LINEAR); t.setMipmapState(com.jme.image.Texture.MM_LINEAR); t.setApply(Texture.AM_COMBINE); t.setCombineFuncRGB(Texture.ACF_MODULATE); t.setCombineScaleRGB(2.f); //t.setWrap(com.jme.image.Texture.WM_WRAP_S_WRAP_T); TextureCoordinateGenerator gen = it.getTextureCoordinateGenerator(); setTextureCoordGenerator(gen, t); textures.put(res, t); } addTextureReference(res); return t; } public void releaseTexture(Graph g, Resource res) { Integer i = textureReferences.get(res); if (i != null) { i = i - 1; if (i == 0) { Texture t = textures.get(res); ImageTexture it = new ImageTexture(g,res); org.simantics.image.stubs.Image pattern = it.getImage(); releaseImage(pattern.getResource()); t.setImage(null); textureReferences.remove(res); //FIXME : release the texture } else { textureReferences.put(res, i); } } else { throw new RuntimeException("Cannot released texture that does not exist " + res); } } public Image loadImage(Graph g, Resource res) { Image image = images.get(res); if (image == null) { org.simantics.image.stubs.Image pattern = new org.simantics.image.stubs.Image(g,res); IImageFactory f = org.simantics.proconf.image.ImageUtils.getImageFactoryForResource(g,pattern.getResource()); try { IImage p = f.createImageForResource(g,pattern.getResource()); PixelDimension pd = p.getDimensions().getPixelDimension(); if (pd==null) pd = DEFAULT_SIZE; ImageData data = p.rasterize(pd.getWidth(), pd.getHeight()); image = getImage(data); images.put(res, image); } catch (Exception e) { ErrorLogger.defaultLogError("Cannor create pattern texture for resource " + pattern, e); return null; } } addImageReference(res); return image; } private void addTextureReference(Resource res) { Integer i = textureReferences.get(res); if (i != null) { imageReferences.put(res, i + 1); } else { imageReferences.put(res, 1); } } private void addImageReference(Resource res) { Integer i = imageReferences.get(res); if (i != null) { imageReferences.put(res, i + 1); } else { imageReferences.put(res, 1); } } public void releaseImage(Resource res) { Integer i = imageReferences.get(res); if (i != null) { i = i - 1; if (i == 0) { Image image = images.get(res); image.getData().clear(); image.setData(null); images.remove(res); imageReferences.remove(res); } else { imageReferences.put(res, i); } } else { throw new RuntimeException("Cannot release image that does not exist."); } } public static ResourceTextureCache getInstance() { return instance; } private static Image getImage(ImageData imageData) { int width = imageData.width; int height = imageData.height; int type = 0; int components = 3; type = Image.RGB888; if (imageData.alphaData != null) { type = Image.RGBA8888; components = 4; } ByteBuffer buf = ByteBuffer.allocateDirect(components * width * height); ImageUtils.convertToRGBA(imageData, buf); return new Image(type,width,height,buf); } public static void setTextureCoordGenerator(TextureCoordinateGenerator gen, com.jme.image.Texture texture) { if (gen == null) return ; //g3dResource. if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_sphere)) texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_SPHERE); else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_eyelinear)) texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_EYE_LINEAR); else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_objectlinear)) texture.setEnvironmentalMapMode(com.jme.image.Texture.EM_OBJECT_LINEAR); else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_normal)) ErrorLogger.getDefault().logWarning("JME doesn't support normal texture coordinate generation", null); else if (gen.equals(Resources.g3dResource.TextureCoordinateGenerator_reflection)) ErrorLogger.getDefault().logWarning("JME doesn't support reflection texture coordinate generation", null); else ErrorLogger.getDefault().logWarning("Unsupported TexGen type " + gen.getName(), null); } public void clear() { for (Image i : images.values()) i.setData(null); for (Texture t : textures.values()) t.setImage(null); imageReferences.clear(); textureReferences.clear(); images.clear(); textures.clear(); } }