Package com.prupe.mcpatcher.hd

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

package com.prupe.mcpatcher.hd;

import com.prupe.mcpatcher.BlendMethod;
import com.prupe.mcpatcher.Config;
import com.prupe.mcpatcher.InputHandler;
import com.prupe.mcpatcher.MCLogger;
import com.prupe.mcpatcher.MCPatcherUtils;
import com.prupe.mcpatcher.TexturePackAPI;
import com.prupe.mcpatcher.hd.FancyDial$Layer;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import java.util.WeakHashMap;
import javax.imageio.ImageIO;
import net.minecraft.src.Icon;
import net.minecraft.src.ResourceLocation;
import net.minecraft.src.TextureAtlasSprite;
import net.minecraft.src.TextureClock;
import net.minecraft.src.TextureCompass;
import net.minecraft.src.TextureMap;
import net.minecraft.src.TextureObject;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.util.glu.GLU;

public class FancyDial {
  private static final MCLogger logger = MCLogger.getLogger("Custom Animations", "Animation");
  private static final ResourceLocation ITEMS_PNG = new ResourceLocation("textures/atlas/items.png");
  private static final double ANGLE_UNSET = Double.MAX_VALUE;
  private static final int NUM_SCRATCH_TEXTURES = 3;
  private static final boolean fboSupported = GLContext.getCapabilities().GL_EXT_framebuffer_object;
  private static final boolean gl13Supported = GLContext.getCapabilities().OpenGL13;
  private static final boolean enableCompass = Config.getBoolean("Extended HD", "fancyCompass", true);
  private static final boolean enableClock = Config.getBoolean("Extended HD", "fancyClock", true);
  private static final boolean useGL13 = gl13Supported && Config.getBoolean("Extended HD", "useGL13", true);
  private static final boolean useScratchTexture = Config.getBoolean("Extended HD", "useScratchTexture", true);
  private static final int glAttributes;
  private static boolean initialized;
  private static final int drawList = GL11.glGenLists(1);
  private static final Map<TextureAtlasSprite, ResourceLocation> setupInfo = new WeakHashMap();
  private static final Map<TextureAtlasSprite, FancyDial> instances = new WeakHashMap();
  private final TextureAtlasSprite icon;
  private final ResourceLocation resource;
  private final String name;
  private final int x0;
  private final int y0;
  private final int width;
  private final int height;
  private final int itemsTexture;
  private final int[] scratchTexture = new int[4];
  private final ByteBuffer scratchBuffer;
  private final int[] frameBuffer = new int[4];
  private int scratchIndex;
  private Map<Double, ByteBuffer> itemFrames = new TreeMap();
  private int outputFrames;
  private boolean ok;
  private double lastAngle = Double.MAX_VALUE;
  private boolean lastItemFrameRenderer;
  private final List<FancyDial$Layer> layers = new ArrayList();
  private InputHandler keyboard;
  private static final float STEP = 0.01F;
  private float scaleXDelta;
  private float scaleYDelta;
  private float offsetXDelta;
  private float offsetYDelta;

  public static void setup(TextureAtlasSprite icon) {
    if (fboSupported) {
      String name = icon.getIconName();

      if ("compass".equals(icon.getIconName())) {
        if (!enableCompass) {
          return;
        }
      } else {
        if (!"clock".equals(icon.getIconName())) {
          logger.warning("ignoring custom animation for %s not compass or clock", new Object[] {icon.getIconName()});
          return;
        }

        if (!enableClock) {
          return;
        }
      }

      ResourceLocation resource = TexturePackAPI.newMCPatcherResourceLocation("dial/" + name + ".properties");

      if (TexturePackAPI.hasResource(resource)) {
        logger.fine("found custom %s (%s)", new Object[] {name, resource});
        setupInfo.put(icon, resource);
      }
    }
  }

  public static boolean update(TextureAtlasSprite icon, boolean itemFrameRenderer) {
    if (!initialized) {
      logger.finer("deferring %s update until initialization finishes", new Object[] {icon.getIconName()});
      return false;
    } else {
      FancyDial instance = (FancyDial)instances.get(icon);

      if (instance == null) {
        instance = getInstance(icon);

        if (instance == null) {
          return false;
        }
      }

      return instance.render(itemFrameRenderer);
    }
  }

  static void clearAll() {
    logger.finer("FancyDial.clearAll", new Object[0]);
    Iterator i$ = instances.values().iterator();

    while (i$.hasNext()) {
      FancyDial instance = (FancyDial)i$.next();

      if (instance != null) {
        instance.finish();
      }
    }

    instances.clear();
    initialized = true;
  }

  static void registerAnimations() {
    TextureObject texture = TexturePackAPI.getTextureObject(ITEMS_PNG);

    if (texture instanceof TextureMap) {
      List animations = ((TextureMap)texture).listAnimatedSprites;
      Iterator i$ = instances.values().iterator();

      while (i$.hasNext()) {
        FancyDial instance = (FancyDial)i$.next();
        instance.registerAnimation(animations);
      }
    }
  }

  void registerAnimation(List<TextureAtlasSprite> animations) {
    if (!animations.contains(this.icon)) {
      animations.add(this.icon);

      if (this.icon.framesTextureData == null) {
        this.icon.framesTextureData = new ArrayList();
      }

      if (this.icon.framesTextureData.isEmpty()) {
        int[] dummyRGB = new int[this.width * this.height];
        Arrays.fill(dummyRGB, -65281);
        this.icon.framesTextureData.add(dummyRGB);
      }

      logger.fine("registered %s animation", new Object[] {this.name});
    }
  }

  private static FancyDial getInstance(TextureAtlasSprite icon) {
    ResourceLocation resource = (ResourceLocation)setupInfo.get(icon);
    Properties properties = TexturePackAPI.getProperties(resource);
    setupInfo.remove(icon);

    if (properties == null) {
      return null;
    } else {
      try {
        FancyDial e = new FancyDial(icon, resource, properties);

        if (e.ok) {
          instances.put(icon, e);
          return e;
        }

        e.finish();
      } catch (Throwable var4) {
        var4.printStackTrace();
      }

      return null;
    }
  }

  private FancyDial(TextureAtlasSprite icon, ResourceLocation resource, Properties properties) {
    this.icon = icon;
    this.resource = resource;
    this.name = icon.getIconName();
    this.x0 = icon.getOriginX();
    this.y0 = icon.getOriginY();
    this.width = icon.getIconWidth();
    this.height = icon.getIconHeight();
    this.scratchBuffer = ByteBuffer.allocateDirect(4 * this.width * this.height);
    this.itemsTexture = TexturePackAPI.getTextureIfLoaded(ITEMS_PNG);

    if (this.itemsTexture < 0) {
      logger.severe("could not get items texture", new Object[0]);
    } else {
      if (useScratchTexture) {
        logger.fine("rendering %s to %dx%d scratch texture", new Object[] {this.name, Integer.valueOf(this.width), Integer.valueOf(this.height)});
      } else {
        logger.fine("rendering %s directly to %s", new Object[] {this.name, ITEMS_PNG});
      }

      for (int debug = 0; debug < this.scratchTexture.length; ++debug) {
        this.scratchTexture[debug] = debug == 3 ? this.itemsTexture : this.setupScratchTexture(debug);
        this.frameBuffer[debug] = this.setupFrameBuffer(this.scratchTexture[debug]);
      }

      boolean var7 = false;
      int glError = 0;

      while (true) {
        FancyDial$Layer layer = this.newLayer(resource, properties, "." + glError);

        if (layer == null) {
          if (glError > 0) {
            this.keyboard = new InputHandler(this.name, var7);

            if (this.layers.size() < 2) {
              logger.error("custom %s needs at least two layers defined", new Object[] {this.name});
              return;
            }

            this.outputFrames = MCPatcherUtils.getIntProperty(properties, "outputFrames", 0);
            glError = GL11.glGetError();

            if (glError != 0) {
              logger.severe("%s during %s setup", new Object[] {GLU.gluErrorString(glError), this.name});
              return;
            }

            this.ok = true;
            return;
          }
        } else {
          this.layers.add(layer);
          var7 |= layer.debug;
          logger.fine("  new %s", new Object[] {layer});
        }

        ++glError;
      }
    }
  }

  private int setupScratchTexture(int i) {
    int targetTexture;

    if (useScratchTexture) {
      targetTexture = GL11.glGenTextures();
      MipmapHelper.setupTexture(targetTexture, this.width, this.height, TexturePackAPI.transformResourceLocation(this.resource, ".properties", "_scratch" + i).getResourcePath());
    } else {
      targetTexture = -1;
    }

    return targetTexture;
  }

  private int setupFrameBuffer(int texture) {
    if (texture < 0) {
      return -1;
    } else {
      int frameBuffer = EXTFramebufferObject.glGenFramebuffersEXT();

      if (frameBuffer < 0) {
        logger.severe("could not get framebuffer object", new Object[0]);
        this.ok = false;
        return -1;
      } else {
        EXTFramebufferObject.glBindFramebufferEXT(36160, frameBuffer);
        EXTFramebufferObject.glFramebufferTexture2DEXT(36160, 36064, 3553, texture, 0);
        EXTFramebufferObject.glBindFramebufferEXT(36160, 0);
        return frameBuffer;
      }
    }
  }

  private boolean render(boolean itemFrameRenderer) {
    if (!this.ok) {
      return false;
    } else {
      if (!itemFrameRenderer) {
        boolean angle = true;

        if (!this.keyboard.isEnabled()) {
          angle = false;
        } else if (this.keyboard.isKeyPressed(80)) {
          this.scaleYDelta -= 0.01F;
        } else if (this.keyboard.isKeyPressed(72)) {
          this.scaleYDelta += 0.01F;
        } else if (this.keyboard.isKeyPressed(75)) {
          this.scaleXDelta -= 0.01F;
        } else if (this.keyboard.isKeyPressed(77)) {
          this.scaleXDelta += 0.01F;
        } else if (this.keyboard.isKeyPressed(208)) {
          this.offsetYDelta += 0.01F;
        } else if (this.keyboard.isKeyPressed(200)) {
          this.offsetYDelta -= 0.01F;
        } else if (this.keyboard.isKeyPressed(203)) {
          this.offsetXDelta -= 0.01F;
        } else if (this.keyboard.isKeyPressed(205)) {
          this.offsetXDelta += 0.01F;
        } else if (this.keyboard.isKeyPressed(55)) {
          this.scaleXDelta = this.scaleYDelta = this.offsetXDelta = this.offsetYDelta = 0.0F;
        } else {
          angle = false;
        }

        if (angle) {
          logger.info("", new Object[0]);
          logger.info("scaleX  %+f", new Object[] {Float.valueOf(this.scaleXDelta)});
          logger.info("scaleY  %+f", new Object[] {Float.valueOf(this.scaleYDelta)});
          logger.info("offsetX %+f", new Object[] {Float.valueOf(this.offsetXDelta)});
          logger.info("offsetY %+f", new Object[] {Float.valueOf(this.offsetYDelta)});
          this.lastAngle = Double.MAX_VALUE;
        }

        if (this.outputFrames > 0) {
          this.writeCustomImage();
          this.outputFrames = 0;
        }
      }

      double var5 = getAngle(this.icon);
      int var6;

      if (!useScratchTexture) {
        if (var5 != this.lastAngle) {
          this.renderToItems(var5);
          this.lastAngle = var5;
        }
      } else if (itemFrameRenderer) {
        ByteBuffer glError = (ByteBuffer)this.itemFrames.get(Double.valueOf(var5));

        if (glError == null) {
          logger.fine("rendering %s at angle %f for item frame", new Object[] {this.name, Double.valueOf(var5)});
          glError = ByteBuffer.allocateDirect(this.width * this.height * 4);
          this.renderToItems(var5);
          this.readTextureToBuffer(glError);
          this.itemFrames.put(Double.valueOf(var5), glError);
        } else {
          this.copyBufferToItemsTexture(glError);
        }

        this.lastItemFrameRenderer = true;
      } else if (this.lastAngle == Double.MAX_VALUE) {
        for (var6 = 0; var6 < 3; ++var6) {
          this.renderToFB(var5, this.frameBuffer[var6]);
        }

        this.readTextureToBuffer(this.scratchTexture[0], this.scratchBuffer);
        this.copyBufferToItemsTexture(this.scratchBuffer);
        this.lastAngle = var5;
        this.scratchIndex = 0;
      } else if (this.lastItemFrameRenderer || var5 != this.lastAngle) {
        var6 = (this.scratchIndex + 1) % 3;

        if (var5 != this.lastAngle) {
          this.renderToFB(var5, this.frameBuffer[var6]);
          this.readTextureToBuffer(this.scratchTexture[this.scratchIndex], this.scratchBuffer);
        }

        this.copyBufferToItemsTexture(this.scratchBuffer);
        this.lastAngle = var5;
        this.scratchIndex = var6;
        this.lastItemFrameRenderer = false;
      }

      var6 = GL11.glGetError();

      if (var6 != 0) {
        logger.severe("%s during %s update", new Object[] {GLU.gluErrorString(var6), this.name});
        this.ok = false;
      }

      return this.ok;
    }
  }

  private void writeCustomImage() {
    try {
      BufferedImage e = new BufferedImage(this.width, this.outputFrames * this.height, 2);
      IntBuffer intBuffer = this.scratchBuffer.asIntBuffer();
      int[] argb = new int[this.width * this.height];
      File path = MCPatcherUtils.getGamePath(new String[] {"custom_" + this.name + ".png"});
      logger.info("generating %d %s frames", new Object[] {Integer.valueOf(this.outputFrames), this.name});

      for (int i = 0; i < this.outputFrames; ++i) {
        this.renderToItems((double)i * (360.0D / (double)this.outputFrames));
        this.readTextureToBuffer(this.scratchBuffer);
        intBuffer.position(0);

        for (int j = 0; j < argb.length; ++j) {
          argb[j] = Integer.rotateRight(intBuffer.get(j), 8);
        }

        e.setRGB(0, i * this.height, this.width, this.height, argb, 0, this.width);
      }

      ImageIO.write(e, "png", path);
      logger.info("wrote %dx%d %s", new Object[] {Integer.valueOf(e.getWidth()), Integer.valueOf(e.getHeight()), path.getPath()});
    } catch (Throwable var7) {
      var7.printStackTrace();
    }
  }

  private void renderToItems(double angle) {
    GL11.glPushAttrib(glAttributes);
    GL11.glViewport(this.x0, this.y0, this.width, this.height);
    GL11.glEnable(GL11.GL_SCISSOR_TEST);
    GL11.glScissor(this.x0, this.y0, this.width, this.height);
    EXTFramebufferObject.glBindFramebufferEXT(36160, this.frameBuffer[3]);
    this.renderImpl(angle);
  }

  private void renderToFB(double angle, int bindFB) {
    GL11.glPushAttrib(glAttributes);
    GL11.glViewport(0, 0, this.width, this.height);
    EXTFramebufferObject.glBindFramebufferEXT(36160, bindFB);
    this.renderImpl(angle);
  }

  private void renderImpl(double angle) {
    boolean lightmapEnabled = false;

    if (gl13Supported) {
      GL13.glActiveTexture(GL13.GL_TEXTURE1);
      lightmapEnabled = GL11.glIsEnabled(GL11.GL_TEXTURE_2D);

      if (lightmapEnabled) {
        GL11.glDisable(GL11.GL_TEXTURE_2D);
      }

      GL13.glActiveTexture(GL13.GL_TEXTURE0);
    }

    GL11.glEnable(GL11.GL_TEXTURE_2D);
    GL11.glDisable(GL11.GL_DEPTH_TEST);
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
    GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
    GL11.glDisable(GL11.GL_LIGHTING);

    if (useGL13) {
      GL11.glDisable(GL13.GL_MULTISAMPLE);
    }

    GL11.glClearColor(0.0F, 0.0F, 0.0F, 0.0F);
    GL11.glClear(16384);
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glPushMatrix();
    GL11.glLoadIdentity();
    GL11.glOrtho(-1.0D, 1.0D, -1.0D, 1.0D, -1.0D, 1.0D);
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glPushMatrix();
    GL11.glLoadIdentity();
    Iterator i$ = this.layers.iterator();

    while (i$.hasNext()) {
      FancyDial$Layer layer = (FancyDial$Layer)i$.next();
      layer.blendMethod.applyBlending();
      GL11.glPushMatrix();
      TexturePackAPI.bindTexture(layer.textureName);
      float offsetX = layer.offsetX;
      float offsetY = layer.offsetY;
      float scaleX = layer.scaleX;
      float scaleY = layer.scaleY;

      if (layer.debug) {
        offsetX += this.offsetXDelta;
        offsetY += this.offsetYDelta;
        scaleX += this.scaleXDelta;
        scaleY += this.scaleYDelta;
      }

      GL11.glTranslatef(offsetX, offsetY, 0.0F);
      GL11.glScalef(scaleX, scaleY, 1.0F);
      float layerAngle = (float)(angle * (double)layer.rotationMultiplier + (double)layer.rotationOffset);
      GL11.glRotatef(layerAngle, 0.0F, 0.0F, 1.0F);
      GL11.glCallList(drawList);
      GL11.glPopMatrix();
    }

    EXTFramebufferObject.glBindFramebufferEXT(36160, 0);
    GL11.glPopAttrib();
    GL11.glMatrixMode(GL11.GL_PROJECTION);
    GL11.glPopMatrix();
    GL11.glMatrixMode(GL11.GL_MODELVIEW);
    GL11.glPopMatrix();

    if (lightmapEnabled) {
      GL13.glActiveTexture(GL13.GL_TEXTURE1);
      GL11.glEnable(GL11.GL_TEXTURE_2D);
      GL13.glActiveTexture(GL13.GL_TEXTURE0);
    }

    GL11.glEnable(GL11.GL_BLEND);
    GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
  }

  private void readTextureToBuffer(int texture, ByteBuffer buffer) {
    TexturePackAPI.bindTexture(texture);
    buffer.position(0);
    GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
  }

  private void readTextureToBuffer(ByteBuffer buffer) {
    EXTFramebufferObject.glBindFramebufferEXT(36160, this.frameBuffer[3]);
    buffer.position(0);
    GL11.glReadPixels(this.x0, this.y0, this.width, this.height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
    EXTFramebufferObject.glBindFramebufferEXT(36160, 0);
  }

  private void copyBufferToItemsTexture(ByteBuffer buffer) {
    TexturePackAPI.bindTexture(this.itemsTexture);
    buffer.position(0);
    GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, this.x0, this.y0, this.width, this.height, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer);
  }

  private static void drawBox() {
    GL11.glBegin(GL11.GL_QUADS);
    GL11.glTexCoord2f(0.0F, 0.0F);
    GL11.glVertex3f(-1.0F, -1.0F, 0.0F);
    GL11.glTexCoord2f(1.0F, 0.0F);
    GL11.glVertex3f(1.0F, -1.0F, 0.0F);
    GL11.glTexCoord2f(1.0F, 1.0F);
    GL11.glVertex3f(1.0F, 1.0F, 0.0F);
    GL11.glTexCoord2f(0.0F, 1.0F);
    GL11.glVertex3f(-1.0F, 1.0F, 0.0F);
    GL11.glEnd();
  }

  private void finish() {
    for (int i = 0; i < this.frameBuffer.length; ++i) {
      if (this.frameBuffer[i] >= 0) {
        EXTFramebufferObject.glDeleteFramebuffersEXT(this.frameBuffer[i]);
        this.frameBuffer[i] = -1;
      }

      if (i < 3 && this.scratchTexture[i] >= 0) {
        TexturePackAPI.deleteTexture(this.scratchTexture[i]);
        this.scratchTexture[i] = -1;
      }
    }

    this.itemFrames.clear();
    this.layers.clear();
    this.ok = false;
  }

  public String toString() {
    return String.format("FancyDial{%s, %dx%d @ %d,%d}", new Object[] {this.name, Integer.valueOf(this.width), Integer.valueOf(this.height), Integer.valueOf(this.x0), Integer.valueOf(this.y0)});
  }

  protected void finalize() throws Throwable {
    this.finish();
    super.finalize();
  }

  private static double getAngle(Icon icon) {
    return icon instanceof TextureCompass ? ((TextureCompass)icon).currentAngle * 180.0D / Math.PI : (icon instanceof TextureClock ? ((TextureClock)icon).field_94239_h * 360.0D : 0.0D);
  }

  FancyDial$Layer newLayer(ResourceLocation resource, Properties properties, String suffix) {
    String textureName = MCPatcherUtils.getStringProperty(properties, "source" + suffix, "");

    if (textureName.isEmpty()) {
      return null;
    } else {
      ResourceLocation textureResource = TexturePackAPI.parseResourceLocation(resource, textureName);

      if (textureResource == null) {
        return null;
      } else if (!TexturePackAPI.hasResource(textureResource)) {
        logger.error("%s: could not read %s", new Object[] {resource, textureResource});
        return null;
      } else {
        float scaleX = MCPatcherUtils.getFloatProperty(properties, "scaleX" + suffix, 1.0F);
        float scaleY = MCPatcherUtils.getFloatProperty(properties, "scaleY" + suffix, 1.0F);
        float offsetX = MCPatcherUtils.getFloatProperty(properties, "offsetX" + suffix, 0.0F);
        float offsetY = MCPatcherUtils.getFloatProperty(properties, "offsetY" + suffix, 0.0F);
        float angleMultiplier = MCPatcherUtils.getFloatProperty(properties, "rotationSpeed" + suffix, 0.0F);
        float angleOffset = MCPatcherUtils.getFloatProperty(properties, "rotationOffset" + suffix, 0.0F);
        String blend = MCPatcherUtils.getStringProperty(properties, "blend" + suffix, "alpha");
        BlendMethod blendMethod = BlendMethod.parse(blend);

        if (blendMethod == null) {
          logger.error("%s: unknown blend method %s", new Object[] {resource, blend});
          return null;
        } else {
          boolean debug = MCPatcherUtils.getBooleanProperty(properties, "debug" + suffix, false);
          return new FancyDial$Layer(this, textureResource, scaleX, scaleY, offsetX, offsetY, angleMultiplier, angleOffset, blendMethod, debug);
        }
      }
    }
  }

  static {
    logger.config("fbo: supported=%s", new Object[] {Boolean.valueOf(fboSupported)});
    logger.config("GL13: supported=%s, enabled=%s", new Object[] {Boolean.valueOf(gl13Supported), Boolean.valueOf(useGL13)});
    int bits = 527702;

    if (useGL13) {
      bits |= 536870912;
    }

    glAttributes = bits;
    GL11.glNewList(drawList, GL11.GL_COMPILE);
    drawBox();
    GL11.glEndList();
  }
}
TOP

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

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.