Java tutorial
/* Copyright (c) 2015 Lance Selga <lyonecro55@gmail.com> * * This work is free. You can redistribute it and/or modify it under the * terms of the Do What The Fuck You Want To Public License, Version 2, * as published by Sam Hocevar. See the COPYING file for more details. */ package lyonlancer5.xatrocore.lib.internal; import static org.lwjgl.opengl.GL11.GL_ALPHA_TEST; import static org.lwjgl.opengl.GL11.GL_BLEND; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST; import static org.lwjgl.opengl.GL11.GL_GREATER; import static org.lwjgl.opengl.GL11.GL_LEQUAL; import static org.lwjgl.opengl.GL11.GL_LIGHTING; import static org.lwjgl.opengl.GL11.GL_MODELVIEW; import static org.lwjgl.opengl.GL11.GL_NEAREST; import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA; import static org.lwjgl.opengl.GL11.GL_PROJECTION; import static org.lwjgl.opengl.GL11.GL_QUADS; import static org.lwjgl.opengl.GL11.GL_RENDERER; import static org.lwjgl.opengl.GL11.GL_RGBA; import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA; import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; import static org.lwjgl.opengl.GL11.GL_TEXTURE_MAG_FILTER; import static org.lwjgl.opengl.GL11.GL_TEXTURE_MIN_FILTER; import static org.lwjgl.opengl.GL11.GL_VENDOR; import static org.lwjgl.opengl.GL11.GL_VERSION; import static org.lwjgl.opengl.GL11.glAlphaFunc; import static org.lwjgl.opengl.GL11.glBegin; import static org.lwjgl.opengl.GL11.glBindTexture; import static org.lwjgl.opengl.GL11.glBlendFunc; import static org.lwjgl.opengl.GL11.glClear; import static org.lwjgl.opengl.GL11.glClearColor; import static org.lwjgl.opengl.GL11.glColor3ub; import static org.lwjgl.opengl.GL11.glDeleteTextures; import static org.lwjgl.opengl.GL11.glDepthFunc; import static org.lwjgl.opengl.GL11.glDisable; import static org.lwjgl.opengl.GL11.glEnable; import static org.lwjgl.opengl.GL11.glEnd; import static org.lwjgl.opengl.GL11.glGenTextures; import static org.lwjgl.opengl.GL11.glGetString; import static org.lwjgl.opengl.GL11.glLoadIdentity; import static org.lwjgl.opengl.GL11.glMatrixMode; import static org.lwjgl.opengl.GL11.glOrtho; import static org.lwjgl.opengl.GL11.glPopMatrix; import static org.lwjgl.opengl.GL11.glPushMatrix; import static org.lwjgl.opengl.GL11.glScalef; import static org.lwjgl.opengl.GL11.glTexCoord2f; import static org.lwjgl.opengl.GL11.glTexImage2D; import static org.lwjgl.opengl.GL11.glTexParameteri; import static org.lwjgl.opengl.GL11.glTexSubImage2D; import static org.lwjgl.opengl.GL11.glTranslatef; import static org.lwjgl.opengl.GL11.glVertex2f; import static org.lwjgl.opengl.GL11.glViewport; import static org.lwjgl.opengl.GL12.GL_BGRA; import static org.lwjgl.opengl.GL12.GL_UNSIGNED_INT_8_8_8_8_REV; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.lang.Thread.UncaughtExceptionHandler; import java.nio.IntBuffer; import java.util.Iterator; import java.util.Properties; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import lyonlancer5.xatrocore.lib.ClientLibrary; import lyonlancer5.xatrocore.lib.Constants; import lyonlancer5.xatrocore.lib.internal.ProgressManagerImpl.ProgressBarImpl; import lyonlancer5.xatrocore.logging.Logger; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.resources.FileResourcePack; import net.minecraft.client.resources.FolderResourcePack; import net.minecraft.client.resources.IResourcePack; import net.minecraft.util.ResourceLocation; import org.apache.commons.io.IOUtils; import org.lwjgl.BufferUtils; import org.lwjgl.LWJGLException; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Drawable; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.SharedDrawable; import org.lwjgl.util.glu.GLU; import com.google.common.annotations.Beta; import cpw.mods.fml.client.FMLClientHandler; import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.ICrashCallable; import cpw.mods.fml.common.asm.FMLSanityChecker; /** * SplashProgress - Progress displayer during client loading</br> * @deprecated Currently work-in-progress */ @Beta public class SplashProgress { protected static final Logger logger = Logger.getLogger("XC's 1.8 Splash Manager"); private static Drawable d; private static volatile boolean pause = false; private static volatile boolean done = false; private static Thread thread; private static volatile Throwable threadError; //private static int angle = 0; private static final Lock lock = new ReentrantLock(true); private static SplashFontRenderer fontRenderer; //private static FontRenderer fontRenderer; //private static final IResourcePack mcPack = Minecraft.getMinecraft().mcDefaultResourcePack; private static final IResourcePack mcPack = Minecraft.getMinecraft() .getResourcePackRepository().rprDefaultResourcePack; private static final IResourcePack fmlPack = createResourcePack(FMLSanityChecker.fmlLocation); private static IResourcePack miscPack; private static Texture fontTexture; private static Texture logoTexture; //private static Texture forgeTexture; private static Properties config; private static boolean enabled; //private static boolean rotate; //private static int logoOffset; private static int backgroundColor; private static int fontColor; private static int barBorderColor; private static int barColor; private static int barBackgroundColor; static final Semaphore mutex = new Semaphore(1); private static String getString(String name, String def) { String value = config.getProperty(name, def); config.setProperty(name, value); return value; } private static boolean getBool(String name, boolean def) { return Boolean.parseBoolean(getString(name, Boolean.toString(def))); } @SuppressWarnings("unused") private static int getInt(String name, int def) { return Integer.decode(getString(name, Integer.toString(def))); } private static int getHex(String name, int def) { return Integer.decode(getString(name, "0x" + Integer.toString(def, 16).toUpperCase())); } /**Starts an instance of this*/ static synchronized void start() { File configFile = new File(Constants.CONFIG_FILE, "splash.properties"); FileReader r = null; config = new Properties(); try { r = new FileReader(configFile); config.load(r); } catch (IOException e) { logger.info("Could not load splash.properties, will create a default one"); } finally { IOUtils.closeQuietly(r); } // Enable if we have the flag, and there's either no optifine, or optifine has added a key to the blackboard ("optifine.ForgeSplashCompatible") // Optifine authors - add this key to the blackboard if you feel your modifications are now compatible with this code. enabled = getBool("enabled", true) && !FMLClientHandler.instance().hasOptifine(); //&& ( (!FMLClientHandler.instance().hasOptifine()) || Launch.blackboard.containsKey("optifine.ForgeSplashCompatible")); //rotate = getBool("rotate", false); //logoOffset = getInt("logoOffset", 0); backgroundColor = getHex("background", 0xFFFFFF); fontColor = getHex("font", 0x000000); barBorderColor = getHex("barBorder", 0xC0C0C0); //barColor = getHex("bar", 0xCB3D35); barColor = getHex("bar", 0x003264); barBackgroundColor = getHex("barBackground", 0xFFFFFF); final ResourceLocation fontLoc = new ResourceLocation(getString("fontTexture", "textures/font/ascii.png")); final ResourceLocation logoLoc = new ResourceLocation( getString("logoTexture", "textures/gui/title/mojang.png")); //final ResourceLocation forgeLoc = new ResourceLocation(getString("forgeTexture", "fml:textures/gui/forge.gif")); File miscPackFile = new File(Minecraft.getMinecraft().mcDataDir, getString("resourcePackPath", "resources")); FileWriter w = null; try { w = new FileWriter(configFile); config.store(w, "Splash screen properties"); } catch (IOException e) { logger.error("Could not save the splash.properties file" + e.toString()); } finally { IOUtils.closeQuietly(w); } miscPack = createResourcePack(miscPackFile); if (!enabled) return; // getting debug info out of the way, while we still can FMLCommonHandler.instance().registerCrashCallable(new ICrashCallable() { public String call() throws Exception { return "' Vendor: '" + glGetString(GL_VENDOR) + "' Version: '" + glGetString(GL_VERSION) + "' Renderer: '" + glGetString(GL_RENDERER) + "'"; } public String getLabel() { return "GL info"; } }); /*CrashReport report = CrashReport.makeCrashReport(new Throwable() { @Override public String getMessage(){ return "This is just a prompt for computer specs to be printed. THIS IS NOT A ERROR"; } @Override public void printStackTrace(final PrintWriter s){ s.println(getMessage()); } @Override public void printStackTrace(final PrintStream s) { s.println(getMessage()); } }, "Loading screen debug info"); System.out.println(report.getCompleteReport());*/ try { d = new SharedDrawable(Display.getDrawable()); Display.getDrawable().releaseContext(); d.makeCurrent(); } catch (LWJGLException e) { e.printStackTrace(); throw new RuntimeException(e); } //Thread mainThread = Thread.currentThread(); thread = new Thread(new Runnable() { private final int barWidth = 512;//400 private final int barHeight = 20; private final int textHeight2 = 20; private final int barOffset = 55; public void run() { setGL(); fontTexture = new Texture(fontLoc); logoTexture = new Texture(logoLoc); //forgeTexture = new Texture(forgeLoc); glEnable(GL_TEXTURE_2D); fontRenderer = new SplashFontRenderer(); glDisable(GL_TEXTURE_2D); while (!done) { ProgressBarImpl first = null, penult = null, last = null; Iterator<ProgressBarImpl> i = ProgressManagerImpl.barIterator(); while (i.hasNext()) { if (first == null) first = i.next(); else { penult = last; last = i.next(); } } glClear(GL_COLOR_BUFFER_BIT); // matrix setup int w = Display.getWidth(); int h = Display.getHeight(); glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(320 - w / 2, 320 + w / 2, 240 + h / 2, 240 - h / 2, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // mojang logo setColor(backgroundColor); glEnable(GL_TEXTURE_2D); logoTexture.bind(); glBegin(GL_QUADS); logoTexture.texCoord(0, 0, 0); glVertex2f(320 - 256, 240 - 256); logoTexture.texCoord(0, 0, 1); glVertex2f(320 - 256, 240 + 256); logoTexture.texCoord(0, 1, 1); glVertex2f(320 + 256, 240 + 256); logoTexture.texCoord(0, 1, 0); glVertex2f(320 + 256, 240 - 256); glEnd(); glDisable(GL_TEXTURE_2D); // bars if (first != null) { glPushMatrix(); glTranslatef(320 - (float) barWidth / 2, 310, 0); drawBar(first); if (penult != null) { glTranslatef(0, barOffset, 0); drawBar(penult); } if (last != null) { glTranslatef(0, barOffset, 0); drawBar(last); } glPopMatrix(); } //angle += 1; /*// forge logo setColor(backgroundColor); float fw = (float)forgeTexture.getWidth() / 2 / 2; float fh = (float)forgeTexture.getHeight() / 2 / 2; if(rotate) { float sh = Math.max(fw, fh); glTranslatef(320 + w/2 - sh - logoOffset, 240 + h/2 - sh - logoOffset, 0); glRotatef(angle, 0, 0, 1); } else { glTranslatef(320 + w/2 - fw - logoOffset, 240 + h/2 - fh - logoOffset, 0); } int f = (angle / 10) % forgeTexture.getFrames(); glEnable(GL_TEXTURE_2D); forgeTexture.bind(); glBegin(GL_QUADS); forgeTexture.texCoord(f, 0, 0); glVertex2f(-fw, -fh); forgeTexture.texCoord(f, 0, 1); glVertex2f(-fw, fh); forgeTexture.texCoord(f, 1, 1); glVertex2f(fw, fh); forgeTexture.texCoord(f, 1, 0); glVertex2f(fw, -fh); glEnd(); glDisable(GL_TEXTURE_2D); */ // We use mutex to indicate safely to the main thread that we're taking the display global lock // So the main thread can skip processing messages while we're updating. // There are system setups where this call can pause for a while, because the GL implementation // is trying to impose a framerate or other thing is occurring. Without the mutex, the main // thread would delay waiting for the same global display lock mutex.acquireUninterruptibly(); Display.update(); // As soon as we're done, we release the mutex. The other thread can now ping the process messages // call as often as it wants until we get get back here again mutex.release(); if (pause) { clearGL(); setGL(); } Display.sync(100); } clearGL(); } private void setColor(int color) { glColor3ub((byte) ((color >> 16) & 0xFF), (byte) ((color >> 8) & 0xFF), (byte) (color & 0xFF)); } private void drawBox(int w, int h) { glBegin(GL_QUADS); glVertex2f(0, 0); glVertex2f(0, h); glVertex2f(w, h); glVertex2f(w, 0); glEnd(); } private void drawBar(ProgressBarImpl b) { glPushMatrix(); // title - message setColor(fontColor); glScalef(2, 2, 1); glEnable(GL_TEXTURE_2D); fontRenderer.drawString(b.getTitle() + " - " + b.getMessage(), 0, 0, 0x000000); glDisable(GL_TEXTURE_2D); glPopMatrix(); // border glPushMatrix(); glTranslatef(0, textHeight2, 0); setColor(barBorderColor); drawBox(barWidth, barHeight); // interior setColor(barBackgroundColor); glTranslatef(1, 1, 0); drawBox(barWidth - 2, barHeight - 2); // slidy part setColor(barColor); drawBox((barWidth - 2) * b.getStep() / b.getSteps(), barHeight - 2); // progress text String progress = "" + b.getStep() + "/" + b.getSteps(); glTranslatef(((float) barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0); setColor(fontColor); glScalef(2, 2, 1); glEnable(GL_TEXTURE_2D); fontRenderer.drawString(progress, 0, 0, 0x000000); glPopMatrix(); } private void setGL() { lock.lock(); try { Display.getDrawable().makeCurrent(); } catch (LWJGLException e) { e.printStackTrace(); throw new RuntimeException(e); } glClearColor((float) ((backgroundColor >> 16) & 0xFF) / 0xFF, (float) ((backgroundColor >> 8) & 0xFF) / 0xFF, (float) (backgroundColor & 0xFF) / 0xFF, 1); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } private void clearGL() { Minecraft mc = Minecraft.getMinecraft(); mc.displayWidth = Display.getWidth(); mc.displayHeight = Display.getHeight(); //mc.resize(mc.displayWidth, mc.displayHeight); MCv18.resize(mc, mc.displayWidth, mc.displayHeight); glClearColor(1, 1, 1, 1); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, .1f); try { Display.getDrawable().releaseContext(); } catch (LWJGLException e) { e.printStackTrace(); throw new RuntimeException(e); } finally { lock.unlock(); } } }); thread.setName("XC's Splash progress bars"); thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { logger.error("Splash thread Exception : " + e.toString()); threadError = e; } }); thread.start(); checkThreadState(); } private static void checkThreadState() { if (thread.getState() == Thread.State.TERMINATED || threadError != null) { throw new IllegalStateException("Splash thread", threadError); } } /** * Call before you need to explicitly modify GL context state during loading. * Resource loading doesn't usually require this call. * Call {@link #resume()} when you're done. * @deprecated not a stable API, will break, don't use this yet */ @Deprecated static void pause() { if (!enabled) return; checkThreadState(); pause = true; lock.lock(); try { d.releaseContext(); Display.getDrawable().makeCurrent(); } catch (LWJGLException e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * @deprecated not a stable API, will break, don't use this yet */ @Deprecated static void resume() { if (!enabled) return; checkThreadState(); pause = false; try { Display.getDrawable().releaseContext(); d.makeCurrent(); } catch (LWJGLException e) { e.printStackTrace(); throw new RuntimeException(e); } lock.unlock(); } @SuppressWarnings("serial") static synchronized void finish() { if (!enabled) return; checkThreadState(); try { done = true; thread.join(); d.releaseContext(); Display.getDrawable().makeCurrent(); fontTexture.delete(); logoTexture.delete(); //forgeTexture.delete(); } catch (Exception e) { e.printStackTrace(); if (disableSplash()) { throw new EnhancedRuntimeException(e) { @Override protected void printStackTrace(WrappedPrintStream stream) { stream.println("SplashProgress has detected a error loading Minecraft."); stream.println("This can sometimes be caused by bad video drivers."); stream.println( "We have automatically disabled the new Splash Screen in config/splash.properties."); stream.println("Try reloading minecraft before reporting any errors."); } }; } else { throw new EnhancedRuntimeException(e) { @Override protected void printStackTrace(WrappedPrintStream stream) { stream.println("SplashProgress has detected a error loading Minecraft."); stream.println("This can sometimes be caused by bad video drivers."); stream.println("Please try disabeling the new Splash Screen in config/splash.properties."); stream.println("After doing so, try reloading minecraft before reporting any errors."); } }; } } } private static boolean disableSplash() { //File configFile = new File(Minecraft.getMinecraft().mcDataDir, "config/splash.properties"); File configFile = new File(Constants.CONFIG_FILE, "splash.properties"); //FileReader r = null; enabled = false; config.setProperty("enabled", "false"); FileWriter w = null; try { w = new FileWriter(configFile); config.store(w, "Splash screen properties"); } catch (IOException e) { logger.error("Could not save the splash.properties file : " + e.toString()); return false; } finally { IOUtils.closeQuietly(w); } return true; } private static IResourcePack createResourcePack(File file) { if (file.isDirectory()) { return new FolderResourcePack(file); } else { return new FileResourcePack(file); } } private static final IntBuffer buf = BufferUtils.createIntBuffer(4 * 1024 * 1024); private static class Texture { private final ResourceLocation location; private final int name; private final int width; private final int height; private final int frames; private final int size; public Texture(ResourceLocation location) { InputStream s = null; try { this.location = location; s = open(location); ImageInputStream stream = ImageIO.createImageInputStream(s); Iterator<ImageReader> readers = ImageIO.getImageReaders(stream); if (!readers.hasNext()) throw new IOException("No suitable reader found for image" + location); ImageReader reader = readers.next(); reader.setInput(stream); frames = reader.getNumImages(true); BufferedImage[] images = new BufferedImage[frames]; for (int i = 0; i < frames; i++) { images[i] = reader.read(i); } reader.dispose(); int size = 1; width = images[0].getWidth(); height = images[0].getHeight(); while ((size / width) * (size / height) < frames) size *= 2; this.size = size; glEnable(GL_TEXTURE_2D); synchronized (SplashProgress.class) { name = glGenTextures(); glBindTexture(GL_TEXTURE_2D, name); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, (IntBuffer) null); checkGLError("Texture creation"); for (int i = 0; i * (size / width) < frames; i++) { for (int j = 0; i * (size / width) + j < frames && j < size / width; j++) { buf.clear(); BufferedImage image = images[i * (size / width) + j]; for (int k = 0; k < height; k++) { for (int l = 0; l < width; l++) { buf.put(image.getRGB(l, k)); } } buf.position(0).limit(width * height); glTexSubImage2D(GL_TEXTURE_2D, 0, j * width, i * height, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buf); checkGLError("Texture uploading"); } } glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } finally { IOUtils.closeQuietly(s); } } public ResourceLocation getLocation() { return location; } @SuppressWarnings("unused") public int getName() { return name; } @SuppressWarnings("unused") public int getWidth() { return width; } @SuppressWarnings("unused") public int getHeight() { return height; } @SuppressWarnings("unused") public int getFrames() { return frames; } @SuppressWarnings("unused") public int getSize() { return size; } public void bind() { glBindTexture(GL_TEXTURE_2D, name); } public void delete() { glDeleteTextures(name); } public float getU(int frame, float u) { return width * (frame % (size / width) + u) / size; } public float getV(int frame, float v) { return height * (frame / (size / width) + v) / size; } public void texCoord(int frame, float u, float v) { glTexCoord2f(getU(frame, u), getV(frame, v)); } } private static class SplashFontRenderer extends FontRenderer { public SplashFontRenderer() { super(Minecraft.getMinecraft().gameSettings, fontTexture.getLocation(), ClientLibrary.getMinecraft().renderEngine, false); //super(Minecraft.getMinecraft().gameSettings, fontTexture.getLocation(), null, false); super.onResourceManagerReload(null); } //@Override //protected void bindTexture(ResourceLocation location) //{ // if(location != locationFontTexture) throw new IllegalArgumentException(); // fontTexture.bind(); //} //@Override //protected InputStream getResourceInputStream(ResourceLocation location) throws IOException //{ // return Minecraft.getMinecraft().mcDefaultResourcePack.getInputStream(location); //} } public static void drawVanillaScreen(TextureManager renderEngine) throws LWJGLException { if (!enabled) { //Minecraft.getMinecraft().drawSplashScreen(renderEngine); MCv18.drawSplashScreen(Minecraft.getMinecraft(), renderEngine); } } public static void clearVanillaResources(TextureManager renderEngine, ResourceLocation mojangLogo) { if (!enabled) { renderEngine.deleteTexture(mojangLogo); } } public static void checkGLError(String where) { int err = GL11.glGetError(); if (err != 0) { throw new IllegalStateException(where + ": " + GLU.gluErrorString(err)); } } private static InputStream open(ResourceLocation loc) throws IOException { if (miscPack.resourceExists(loc)) { return miscPack.getInputStream(loc); } else if (fmlPack.resourceExists(loc)) { return fmlPack.getInputStream(loc); } return mcPack.getInputStream(loc); } }