Package ae.gl.texture

Source Code of ae.gl.texture.GLTextureManager

/* [LGPL] Copyright 2010, 2011, 2012 Irah, Gima

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package ae.gl.texture;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.imageio.ImageIO;

import org.lwjgl.opengl.GL11;

import ae.image.ImageConversions;
import ae.image.ImageScaler;
import ae.image.ImageScaler.ScaleParams;
import ae.routines.S;
import ae.thread.DrainableExecutorService;
import ae.thread.ThreadWork;
import ae.thread.ThreadWorkRecipe;

public class GLTextureManager {
 
  private static GLTextureManager INSTANCE;
 
  private final DrainableExecutorService glExecutorService;
  private final ExecutorService workerExecutorService;
 
  private final HashMap<String, Integer> idMap;
  private int placeholderTextureID;
 
  public static GLTextureManager getInstance() {
    return INSTANCE;
  }
 
  public GLTextureManager(DrainableExecutorService glExecutorService) {
    this.glExecutorService = glExecutorService;
    workerExecutorService = Executors.newSingleThreadExecutor();
    idMap = new HashMap<>();
  }
 
  public void initialize() {
    INSTANCE = this;
    BufferedImage placeHolderImage = generatePlaceholderImage();
   
    placeholderTextureID = GLTextureRoutines.createTexture(placeHolderImage);
  }
 
  public void requestShutdown() {
    workerExecutorService.shutdown();
  }
 
  public int getPlaceholderTextureID() {
    return placeholderTextureID;
  }
 
  private static BufferedImage generatePlaceholderImage() {
    int w=64, h=64;
   
    BufferedImage placeholder = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
    Graphics2D g = (Graphics2D) placeholder.getGraphics();
   
    g.setColor(Color.black);
    g.fillRect(0, 0, w, h);
    g.setColor(Color.gray);
    g.fillOval(0, 0, w, h);
    g.setColor(Color.white);
    g.drawLine(0, 0, w, h);
    g.drawLine(0, w, h, 0);
   
    return placeholder;
  }
 
  public void deferredLoad(InputStream inputStream, String identifier) {
    internalLoadTextureFromStream(inputStream, identifier, false, -1, -1, null);
  }
 
  public void deferredLoad(Path filename, String identifier) {
    InputStream inputStream = getTextureInputStream(filename, identifier);
    if (inputStream == null) return;
    internalLoadTextureFromStream(inputStream, identifier, false, -1, -1, null);
  }
 
  public void deferredLoad(BufferedImage bufferedImage, String identifier) {
    internalLoadBufferedImageTexture(bufferedImage, identifier, false);
  }
 
  public int blockingLoad(InputStream inputStream, String identifier) {
    return internalLoadTextureFromStream(inputStream, identifier, true, -1, -1, null);
  }
 
  public int blockingLoad(Path filename, String identifier) {
    InputStream inputStream = getTextureInputStream(filename, identifier);
    if (inputStream == null) return placeholderTextureID;
    return internalLoadTextureFromStream(inputStream, identifier, true, -1, -1, null);
  }
 
  public int blockingLoad(BufferedImage bufferedImage, String identifier) {
    return internalLoadBufferedImageTexture(bufferedImage, identifier, true);
  }
 
  public void deferredScaledLoad(InputStream inputStream, String identifier, int newWidth, int newHeight, ScaleParams scaleParams) {
    internalLoadTextureFromStream(inputStream, identifier, false, newWidth, newHeight, scaleParams);
  }
 
  public void deferredScaledLoad(Path filename, String identifier, int newWidth, int newHeight, ScaleParams scaleParams) {
    InputStream inputStream = getTextureInputStream(filename, identifier);
    if (inputStream == null) return;
    internalLoadTextureFromStream(inputStream, identifier, false, newWidth, newHeight, scaleParams);
  }
 
  public int blockingScaledLoad(InputStream inputStream, String identifier, int newWidth, int newHeight, ScaleParams scaleParams) {
    return internalLoadTextureFromStream(inputStream, identifier, true, newWidth, newHeight, scaleParams);
  }
 
  public int blockingScaledLoad(Path filename, String identifier, int newWidth, int newHeight, ScaleParams scaleParams) {
    InputStream inputStream = getTextureInputStream(filename, identifier);
    if (inputStream == null) return placeholderTextureID;
    return internalLoadTextureFromStream(inputStream, identifier, true, newWidth, newHeight, scaleParams);
  }
 
  private InputStream getTextureInputStream(Path filename, String identifier) {
    try {
      return Files.newInputStream(filename, StandardOpenOption.READ);
    }
    catch (IOException e) {
      new Exception(S.sprintf("Cannot load texture '%s'", identifier), e).printStackTrace();
      return null;
    }
  }
 
  private int internalLoadTextureFromStream(InputStream inputStream, String identifier, boolean wait, int newWidth, int newHeight, ScaleParams scaleParams) {
    //S.funcArgs(inputStream, identifier);
    Integer textureID;
   
    synchronized (idMap) {
      textureID = idMap.get(identifier);
      if (textureID != null) {
        // texture already loaded, don't load it again
        // TODO: if it's in the process of being loaded, this can kick another loading into action
        return textureID;
      }
    }
   
    // texture doesn't exist, load it
    textureID = GLTextureRoutines.allocateTextureID();
   
    ThreadWorkRecipe recipe = new ThreadWorkRecipe();
   
    recipe.add(loadImageWork, workerExecutorService);
    if (scaleParams != null) {
      recipe.add(imageReducingWork, workerExecutorService, newWidth, newHeight, scaleParams);
    }
    recipe.add(imageConversionWork, workerExecutorService);
    recipe.add(glTextureUploadWork, glExecutorService, textureID);
    recipe.add(idMapUpdateWork, workerExecutorService, identifier, textureID);
   
    recipe.nextWork(recipe, inputStream);
   
    if (wait) {
      try {
        recipe.loopPollResultingCallParams(glExecutorService);
      }
      catch (InterruptedException e) {
        new Exception(S.sprintf("Failed to load texture '%s'.", identifier), e).printStackTrace();
      }
    }
   
    return textureID;
  }

  private int internalLoadBufferedImageTexture(BufferedImage bufferedImage, String identifier, boolean wait) {
    S.funcArgs(bufferedImage, identifier);
    Integer textureID;
   
    synchronized (idMap) {
      textureID = idMap.get(identifier);
      if (textureID != null) {
        // texture already loaded, don't load it again
        // TODO: if it's in the process of being loaded, this can kick another loading into action
        return textureID;
      }
    }
   
    // texture doesn't exist, load it
    textureID = GLTextureRoutines.allocateTextureID();
   
    ThreadWorkRecipe recipe = new ThreadWorkRecipe();
   
    recipe.add(imageConversionWork, workerExecutorService);
    recipe.add(glTextureUploadWork, glExecutorService, textureID);
    recipe.add(idMapUpdateWork, workerExecutorService, identifier, textureID);
   
    recipe.nextWork(bufferedImage);
   
    if (wait) {
      try {
        recipe.loopPollResultingCallParams(glExecutorService);
      }
      catch (InterruptedException e) {
        new Exception(S.sprintf("Failed to load texture '%s'.", identifier), e).printStackTrace();
      }
    }
   
    return textureID;
  }
 
  public void bindTexture(String identifier) {
    //S.funcArgs(identifier);
    Integer textureID;
    synchronized (idMap) {
      textureID = idMap.get(identifier);
    }
   
    if (textureID == null) {
//      S.eprintfn("Cannot bind texture '%s', no matching identifier found. Binding placeholder texture instead.", identifier);
      GL11.glBindTexture(GL11.GL_TEXTURE_2D, placeholderTextureID);
    }
    else {
      GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
    }
  }

  public int getTextureID(String identifier) {
    Integer textureID;
   
    synchronized (idMap) {
      textureID = idMap.get(identifier);
    }
   
    if (textureID == null) {
//      S.eprintfn("Cannot find texture '%s', no matching identifier found. Returning placeholder texture ID.", identifier);
      return placeholderTextureID;
    }
    else {
      return textureID;
    }
  }
 
  // thread works
 
  private final ThreadWork loadImageWork = new ThreadWork() {
    @SuppressWarnings("unused")
    public void call(ThreadWorkRecipe recipe, InputStream inputStream) throws IOException {
      BufferedImage loadedImage = ImageIO.read(inputStream);
      recipe.nextWork(recipe, loadedImage);
    }
  };
 
  private final ThreadWork imageReducingWork = new ThreadWork() {
    @SuppressWarnings("unused")
    public void call(ThreadWorkRecipe recipe, BufferedImage bufferedImage, int newWidth, int newHeight, ScaleParams scaleParams) throws IOException {
      BufferedImage reducedImage = ImageScaler.scaleImage(bufferedImage, newWidth, newHeight, scaleParams, ImageScaler.QualityParams.FAST);
      recipe.nextWork(recipe, reducedImage);
    }
  };
 
  private final ThreadWork imageConversionWork = new ThreadWork() {
    @SuppressWarnings("unused")
    public void call(ThreadWorkRecipe recipe, BufferedImage bufferedImage) throws IOException {
      byte[] convertedImageData = ImageConversions.convertBIToBGRABytes(bufferedImage);
      recipe.nextWork(recipe, convertedImageData, bufferedImage);
    }
  };
 
  private final ThreadWork glTextureUploadWork = new ThreadWork() {
    @SuppressWarnings("unused")
    public void call(ThreadWorkRecipe recipe, byte[] imageData, BufferedImage bufferedImage, int glTextureID) throws IOException {
      GLTextureRoutines.initializeTexture(glTextureID, imageData, bufferedImage.getWidth(), bufferedImage.getHeight());
      recipe.nextWork(recipe);
    }
  };
 
  private final ThreadWork idMapUpdateWork = new ThreadWork() {
    @SuppressWarnings("unused")
    public void call(ThreadWorkRecipe recipe, String identifier, int glTextureID) throws IOException {
      synchronized (idMap) {
        idMap.put(identifier, glTextureID);
      }
      recipe.nextWork(glTextureID);
    }
  };
 
}
TOP

Related Classes of ae.gl.texture.GLTextureManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.