Package com.prupe.mcpatcher.hd

Source Code of com.prupe.mcpatcher.hd.MipmapHelper

package com.prupe.mcpatcher.hd;

import com.prupe.mcpatcher.Config;
import com.prupe.mcpatcher.MCLogger;
import com.prupe.mcpatcher.TexturePackAPI;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.ImageObserver;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import net.minecraft.src.ResourceLocation;
import net.minecraft.src.TextureAtlasSprite;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.util.glu.GLU;

public class MipmapHelper {
  private static final MCLogger logger = MCLogger.getLogger("Mipmap");
  private static final ResourceLocation MIPMAP_PROPERTIES = TexturePackAPI.newMCPatcherResourceLocation("mipmap.properties");
  private static final int TEX_FORMAT = 32993;
  private static final int TEX_DATA_TYPE = 33639;
  private static final int MIN_ALPHA = 26;
  private static final int MAX_ALPHA = 229;
  private static final boolean mipmapSupported = GLContext.getCapabilities().OpenGL12;
  static final boolean mipmapEnabled = Config.getBoolean("Extended HD", "mipmap", false);
  static final int maxMipmapLevel = Config.getInt("Extended HD", "maxMipmapLevel", 3);
  private static final boolean useMipmap = mipmapSupported && mipmapEnabled && maxMipmapLevel > 0;
  private static final int mipmapAlignment = (1 << Config.getInt("Extended HD", "mipmapAlignment", 3)) - 1;
  private static final boolean anisoSupported = GLContext.getCapabilities().GL_EXT_texture_filter_anisotropic;
  static final int anisoLevel;
  private static final int anisoMax;
  private static final boolean lodSupported;
  private static final int lodBias;
  private static final Map<String, Reference<BufferedImage>> imagePool = new HashMap();
  private static final Map<Integer, Reference<ByteBuffer>> bufferPool = new HashMap();
  private static final Map<String, Boolean> mipmapType = new HashMap();

  private static void setupTexture(int width, int height, boolean blur, boolean clamp, String textureName) {
    int mipmaps = useMipmapsForTexture(textureName) ? getMipmapLevels(width, height, 1) : 0;
    logger.finer("setupTexture(%s) %dx%d %d mipmaps", new Object[] {textureName, Integer.valueOf(width), Integer.valueOf(height), Integer.valueOf(mipmaps)});
    int magFilter = blur ? 9729 : 9728;
    int minFilter = mipmaps > 0 ? 9986 : magFilter;
    int wrap = clamp ? 10496 : 10497;

    if (mipmaps > 0) {
      GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, mipmaps);
      checkGLError("%s: set GL_TEXTURE_MAX_LEVEL = %d", new Object[] {textureName, Integer.valueOf(mipmaps)});

      if (anisoSupported && anisoLevel > 1) {
        GL11.glTexParameterf(GL11.GL_TEXTURE_2D, 34046, (float)anisoLevel);
        checkGLError("%s: set GL_TEXTURE_MAX_ANISOTROPY_EXT = %f", new Object[] {textureName, Integer.valueOf(anisoLevel)});
      }

      if (lodSupported) {
        GL11.glTexEnvi(GL14.GL_TEXTURE_FILTER_CONTROL, GL14.GL_TEXTURE_LOD_BIAS, lodBias);
        checkGLError("%s: set GL_TEXTURE_LOD_BIAS_EXT = %d", new Object[] {textureName, Integer.valueOf(lodBias)});
      }
    }

    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap);

    for (int level = 0; level <= mipmaps; ++level) {
      GL11.glTexImage2D(GL11.GL_TEXTURE_2D, level, GL11.GL_RGBA, width, height, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (IntBuffer)null);
      checkGLError("%s: glTexImage2D %dx%d level %d", new Object[] {textureName, Integer.valueOf(width), Integer.valueOf(height), Integer.valueOf(level)});
      width >>= 1;
      height >>= 1;
    }
  }

  public static void setupTexture(int[] rgb, int width, int height, int x, int y, boolean blur, boolean clamp, String textureName) {
    setupTexture(width, height, blur, clamp, textureName);
    copySubTexture(rgb, width, height, x, y, textureName);
  }

  public static int setupTexture(int glTexture, BufferedImage image, boolean blur, boolean clamp, ResourceLocation textureName) {
    int width = image.getWidth();
    int height = image.getHeight();
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTexture);
    logger.finer("setupTexture(%s, %d, %dx%d, %s, %s)", new Object[] {textureName, Integer.valueOf(glTexture), Integer.valueOf(width), Integer.valueOf(height), Boolean.valueOf(blur), Boolean.valueOf(clamp)});
    int[] rgb = new int[width * height];
    image.getRGB(0, 0, width, height, rgb, 0, width);
    setupTexture(rgb, width, height, 0, 0, blur, clamp, textureName.getResourcePath());
    return glTexture;
  }

  public static void setupTexture(int glTexture, int width, int height, String textureName) {
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, glTexture);
    logger.finer("setupTexture(tilesheet %s, %d, %dx%d)", new Object[] {textureName, Integer.valueOf(glTexture), Integer.valueOf(width), Integer.valueOf(height)});
    setupTexture(width, height, false, false, textureName);
  }

  public static void copySubTexture(int[] rgb, int width, int height, int x, int y, String textureName) {
    if (rgb == null) {
      logger.error("copySubTexture %s %d,%d %dx%d: rgb data is null", new Object[] {textureName, Integer.valueOf(x), Integer.valueOf(y), Integer.valueOf(width), Integer.valueOf(height)});
    } else {
      IntBuffer buffer = getPooledBuffer(width * height * 4).asIntBuffer();
      buffer.put(rgb).position(0);
      int mipmaps = getMipmapLevelsForCurrentTexture();
      logger.finest("copySubTexture %s %d,%d %dx%d %d mipmaps", new Object[] {textureName, Integer.valueOf(x), Integer.valueOf(y), Integer.valueOf(width), Integer.valueOf(height), Integer.valueOf(mipmaps)});

      for (int level = 0; width > 0 && height > 0; height >>= 1) {
        GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, level, x, y, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
        checkGLError("%s: glTexSubImage2D(%d, %d, %d, %d, %d)", new Object[] {textureName, Integer.valueOf(level), Integer.valueOf(x), Integer.valueOf(y), Integer.valueOf(width), Integer.valueOf(height)});

        if (level >= mipmaps) {
          break;
        }

        IntBuffer newBuffer = getPooledBuffer(width * height).asIntBuffer();
        scaleHalf(buffer, width, height, newBuffer, 0);
        buffer = newBuffer;
        ++level;
        x >>= 1;
        y >>= 1;
        width >>= 1;
      }
    }
  }

  public static void copySubTexture(TextureAtlasSprite texture, int index) {
    int width = texture.getIconWidth();
    int height = texture.getIconHeight();
    int x;
    int y;

    if (texture.mipmaps == null || texture.mipmaps.size() != texture.framesTextureData.size()) {
      texture.mipmaps = new ArrayList(texture.framesTextureData.size());
      x = getMipmapLevelsForCurrentTexture();

      if (x > 0) {
        logger.fine("generating %d mipmaps for tile %s", new Object[] {Integer.valueOf(x), texture.getIconName()});
      }

      for (y = 0; y < texture.framesTextureData.size(); ++y) {
        texture.mipmaps.add(generateMipmaps((int[])texture.framesTextureData.get(y), width, height, x));
      }
    }

    x = texture.getOriginX();
    y = texture.getOriginY();
    IntBuffer[] mipmapData = (IntBuffer[])texture.mipmaps.get(index);

    if (mipmapData != null) {
      for (int level = 0; level < mipmapData.length; ++level) {
        GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, level, x, y, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, mipmapData[level]);
        x >>= 1;
        y >>= 1;
        width >>= 1;
        height >>= 1;
      }
    }
  }

  private static IntBuffer[] generateMipmaps(int[] rgb, int width, int height, int mipmaps) {
    if (rgb == null) {
      return null;
    } else {
      ArrayList mipmapData = new ArrayList();
      IntBuffer buffer = newIntBuffer(width * height * 4);
      buffer.put(rgb).position(0);
      int level = 0;

      while (true) {
        mipmapData.add(buffer);

        if (width <= 0 || height <= 0 || level >= mipmaps) {
          return (IntBuffer[])mipmapData.toArray(new IntBuffer[mipmapData.size()]);
        }

        IntBuffer newBuffer = newIntBuffer(width * height);
        scaleHalf(buffer, width, height, newBuffer, 0);
        buffer = newBuffer;
        ++level;
        width >>= 1;
        height >>= 1;
      }
    }
  }

  static BufferedImage fixTransparency(ResourceLocation name, BufferedImage image) {
    if (image == null) {
      return image;
    } else {
      long s1 = System.currentTimeMillis();
      image = convertToARGB(image);
      int width = image.getWidth();
      int height = image.getHeight();
      IntBuffer buffer = getImageAsARGBIntBuffer(image);
      IntBuffer scaledBuffer = buffer;
      label33:

      while (width % 2 == 0 && height % 2 == 0) {
        int s2 = 0;

        while (true) {
          if (s2 >= scaledBuffer.limit()) {
            break label33;
          }

          if (scaledBuffer.get(s2) >>> 24 == 0) {
            IntBuffer newBuffer = getPooledBuffer(width * height).asIntBuffer();
            scaleHalf(scaledBuffer, width, height, newBuffer, 8);
            scaledBuffer = newBuffer;
            width >>= 1;
            height >>= 1;
            break;
          }

          ++s2;
        }
      }

      long var12 = System.currentTimeMillis();

      if (scaledBuffer != buffer) {
        setBackgroundColor(buffer, image.getWidth(), image.getHeight(), scaledBuffer, image.getWidth() / width);
      }

      long s3 = System.currentTimeMillis();
      logger.finer("bg fix (tile %s): scaling %dms, setbg %dms", new Object[] {name, Long.valueOf(var12 - s1), Long.valueOf(s3 - var12)});
      return image;
    }
  }

  static void reset() {
    mipmapType.clear();
    mipmapType.put("terrain", Boolean.valueOf(true));
    mipmapType.put("items", Boolean.valueOf(false));
    Properties properties = TexturePackAPI.getProperties(MIPMAP_PROPERTIES);

    if (properties != null) {
      Iterator i$ = properties.entrySet().iterator();

      while (i$.hasNext()) {
        Entry entry = (Entry)i$.next();

        if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
          String key = ((String)entry.getKey()).trim();
          boolean value = Boolean.parseBoolean(((String)entry.getValue()).trim().toLowerCase());

          if (key.endsWith(".png")) {
            mipmapType.put(key, Boolean.valueOf(value));
          }
        }
      }
    }
  }

  static boolean useMipmapsForTexture(String texture) {
    return useMipmap && texture != null ? (mipmapType.containsKey(texture) ? ((Boolean)mipmapType.get(texture)).booleanValue() : !texture.contains("item") && !texture.startsWith("textures/colormap/") && !texture.startsWith("textures/environment/") && !texture.startsWith("textures/font/") && !texture.startsWith("textures/gui/") && !texture.startsWith("textures/map/") && !texture.startsWith("textures/misc/") && !texture.startsWith("mcpatcher/colormap/") && !texture.startsWith("mcpatcher/cit/") && !texture.startsWith("mcpatcher/dial/") && !texture.startsWith("mcpatcher/font/") && !texture.startsWith("mcpatcher/lightmap/") && !texture.startsWith("mcpatcher/sky/")) : false;
  }

  static int getMipmapLevelsForCurrentTexture() {
    int filter = GL11.glGetTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER);
    return filter != 9986 && filter != 9984 ? 0 : Math.min(maxMipmapLevel, GL11.glGetTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL));
  }

  private static int gcd(int a, int b) {
    return BigInteger.valueOf((long)a).gcd(BigInteger.valueOf((long)b)).intValue();
  }

  private static int getMipmapLevels(int width, int height, int minSize) {
    int size = gcd(width, height);
    int mipmap;

    for (mipmap = 0; size >= minSize && (size & 1) == 0 && mipmap < maxMipmapLevel; ++mipmap) {
      size >>= 1;
    }

    return mipmap;
  }

  private static BufferedImage getPooledImage(int width, int height, int index) {
    String key = String.format("%dx%d#%d", new Object[] {Integer.valueOf(width), Integer.valueOf(height), Integer.valueOf(index)});
    Reference ref = (Reference)imagePool.get(key);
    BufferedImage image = ref == null ? null : (BufferedImage)ref.get();

    if (image == null) {
      image = new BufferedImage(width, height, 2);
      imagePool.put(key, new SoftReference(image));
    }

    return image;
  }

  private static IntBuffer newIntBuffer(int size) {
    ByteBuffer buffer = ByteBuffer.allocateDirect(size);
    buffer.order(ByteOrder.LITTLE_ENDIAN);
    return buffer.asIntBuffer();
  }

  private static ByteBuffer getPooledBuffer(int size) {
    Reference ref = (Reference)bufferPool.get(Integer.valueOf(size));
    ByteBuffer buffer = ref == null ? null : (ByteBuffer)ref.get();

    if (buffer == null) {
      buffer = ByteBuffer.allocateDirect(size);
      bufferPool.put(Integer.valueOf(size), new SoftReference(buffer));
    }

    buffer.order(ByteOrder.LITTLE_ENDIAN);
    buffer.position(0);
    return buffer;
  }

  private static BufferedImage convertToARGB(BufferedImage image) {
    if (image == null) {
      return null;
    } else if (image.getType() == 2) {
      return image;
    } else {
      int width = image.getWidth();
      int height = image.getHeight();
      logger.finest("converting %dx%d image to ARGB", new Object[] {Integer.valueOf(width), Integer.valueOf(height)});
      BufferedImage newImage = getPooledImage(width, height, 0);
      Graphics2D graphics = newImage.createGraphics();
      Arrays.fill(getImageAsARGBIntBuffer(newImage).array(), 0);
      graphics.drawImage(image, 0, 0, (ImageObserver)null);
      return newImage;
    }
  }

  private static IntBuffer getImageAsARGBIntBuffer(BufferedImage image) {
    DataBuffer buffer = image.getRaster().getDataBuffer();

    if (buffer instanceof DataBufferInt) {
      return IntBuffer.wrap(((DataBufferInt)buffer).getData());
    } else if (buffer instanceof DataBufferByte) {
      return ByteBuffer.wrap(((DataBufferByte)buffer).getData()).order(ByteOrder.BIG_ENDIAN).asIntBuffer();
    } else {
      int width = image.getWidth();
      int height = image.getHeight();
      int[] pixels = new int[width * height];
      image.getRGB(0, 0, width, height, pixels, 0, width);
      return IntBuffer.wrap(pixels);
    }
  }

  private static void setBackgroundColor(IntBuffer buffer, int width, int height, IntBuffer scaledBuffer, int scale) {
    for (int i = 0; i < width; ++i) {
      for (int j = 0; j < height; ++j) {
        int k = width * j + i;
        int pixel = buffer.get(k);

        if ((pixel & -16777216) == 0) {
          pixel = scaledBuffer.get(j / scale * (width / scale) + i / scale);
          buffer.put(k, pixel & 16777215);
        }
      }
    }
  }

  static void scaleHalf(IntBuffer in, int w, int h, IntBuffer out, int rotate) {
    for (int i = 0; i < w / 2; ++i) {
      for (int j = 0; j < h / 2; ++j) {
        int k = w * 2 * j + 2 * i;
        int pixel00 = in.get(k);
        int pixel01 = in.get(k + 1);
        int pixel10 = in.get(k + w);
        int pixel11 = in.get(k + w + 1);

        if (rotate != 0) {
          pixel00 = Integer.rotateLeft(pixel00, rotate);
          pixel01 = Integer.rotateLeft(pixel01, rotate);
          pixel10 = Integer.rotateLeft(pixel10, rotate);
          pixel11 = Integer.rotateLeft(pixel11, rotate);
        }

        int pixel = average4RGBA(pixel00, pixel01, pixel10, pixel11);

        if (rotate != 0) {
          pixel = Integer.rotateRight(pixel, rotate);
        }

        out.put(w / 2 * j + i, pixel);
      }
    }
  }

  private static int average4RGBA(int pixel00, int pixel01, int pixel10, int pixel11) {
    int a00 = pixel00 & 255;
    int a01 = pixel01 & 255;
    int a10 = pixel10 & 255;
    int a11 = pixel11 & 255;

    switch (a00 << 24 | a01 << 16 | a10 << 8 | a11) {
      case -16777216:
        return pixel00;

      case -16776961:
        return average2RGBA(pixel00, pixel11);

      case -16711936:
        return average2RGBA(pixel00, pixel10);

      case -65536:
        return average2RGBA(pixel00, pixel01);

      case -1:
      case 0:
        return average2RGBA(average2RGBA(pixel00, pixel11), average2RGBA(pixel01, pixel10));

      case 255:
        return pixel11;

      case 65280:
        return pixel10;

      case 65535:
        return average2RGBA(pixel10, pixel11);

      case 16711680:
        return pixel01;

      case 16711935:
        return average2RGBA(pixel01, pixel11);

      case 16776960:
        return average2RGBA(pixel01, pixel10);

      default:
        int a = a00 + a01 + a10 + a11;
        int pixel = a >> 2;

        for (int i = 8; i < 32; i += 8) {
          int average = (a00 * (pixel00 >> i & 255) + a01 * (pixel01 >> i & 255) + a10 * (pixel10 >> i & 255) + a11 * (pixel11 >> i & 255)) / a;
          pixel |= average << i;
        }

        return pixel;
    }
  }

  private static int average2RGBA(int a, int b) {
    return ((a & -16843010) >>> 1) + ((b & -16843010) >>> 1) | a & b & 16843009;
  }

  private static void checkGLError(String format, Object ... params) {
    int error = GL11.glGetError();

    if (error != 0) {
      String message = GLU.gluErrorString(error) + ": " + String.format(format, params);
      (new RuntimeException(message)).printStackTrace();
    }
  }

  static {
    if (anisoSupported) {
      anisoMax = (int)GL11.glGetFloat(34047);
      checkGLError("glGetFloat(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT)", new Object[0]);
      anisoLevel = Math.max(Math.min(Config.getInt("Extended HD", "anisotropicFiltering", 1), anisoMax), 1);
    } else {
      anisoLevel = 1;
      anisoMax = 1;
    }

    lodSupported = GLContext.getCapabilities().GL_EXT_texture_lod_bias;

    if (lodSupported) {
      lodBias = Config.getInt("Extended HD", "lodBias", 0);
    } else {
      lodBias = 0;
    }

    logger.config("mipmap: supported=%s, enabled=%s, level=%d", new Object[] {Boolean.valueOf(mipmapSupported), Boolean.valueOf(mipmapEnabled), Integer.valueOf(maxMipmapLevel)});
    logger.config("anisotropic: supported=%s, level=%d, max=%d", new Object[] {Boolean.valueOf(anisoSupported), Integer.valueOf(anisoLevel), Integer.valueOf(anisoMax)});
    logger.config("lod bias: supported=%s, bias=%d", new Object[] {Boolean.valueOf(lodSupported), Integer.valueOf(lodBias)});
  }
}
TOP

Related Classes of com.prupe.mcpatcher.hd.MipmapHelper

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.