From 794ff1d1b48c17c70103e4ee9f6e7247a3daba9a Mon Sep 17 00:00:00 2001 From: RainWarrior Date: Sat, 25 Apr 2015 05:12:02 +0300 Subject: [PATCH] Loading screen: logo rotation is now optional; initial support for animated textures - animation rate is fixed for now. --- .../cpw/mods/fml/client/SplashProgress.java | 355 ++++++++++++------ .../resources/assets/fml/splash.properties | 3 + 2 files changed, 243 insertions(+), 115 deletions(-) diff --git a/fml/src/main/java/cpw/mods/fml/client/SplashProgress.java b/fml/src/main/java/cpw/mods/fml/client/SplashProgress.java index 8da1e9345..2d4354a44 100644 --- a/fml/src/main/java/cpw/mods/fml/client/SplashProgress.java +++ b/fml/src/main/java/cpw/mods/fml/client/SplashProgress.java @@ -1,19 +1,25 @@ package cpw.mods.fml.client; +import static org.lwjgl.opengl.GL11.*; +import static org.lwjgl.opengl.GL12.*; + +import java.awt.image.BufferedImage; 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.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.client.renderer.texture.TextureUtil; import net.minecraft.client.resources.FileResourcePack; import net.minecraft.client.resources.FolderResourcePack; import net.minecraft.client.resources.IResourcePack; @@ -22,11 +28,13 @@ import net.minecraft.util.ResourceLocation; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.Level; +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 cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLLog; @@ -53,17 +61,16 @@ public class SplashProgress private static final IResourcePack mcPack = Minecraft.getMinecraft().mcDefaultResourcePack; private static final IResourcePack fmlPack = createFmlResourcePack(); - private static int fontTexture; - private static ResourceLocation fontLocation = new ResourceLocation("textures/font/ascii.png"); - private static int logoTexture; - private static ResourceLocation logoLocation = new ResourceLocation("textures/gui/title/mojang.png"); - private static int forgeTexture; - private static ResourceLocation forgeLocation = new ResourceLocation("fml", "textures/gui/forge.png"); + private static Texture fontTexture; + private static Texture logoTexture; + private static Texture forgeTexture; private static ResourceLocation configLocation = new ResourceLocation("fml", "splash.properties"); private static final Properties config = loadConfig(); private static final boolean enabled = Boolean.parseBoolean(config.getProperty("enabled")); + private static final boolean rotate = Boolean.parseBoolean(config.getProperty("rotate")); + private static final int logoOffset = getInt("logoOffset"); private static final int backgroundColor = getInt("background"); private static final int fontColor = getInt("font"); private static final int barBorderColor = getInt("barBorder"); @@ -78,9 +85,9 @@ public class SplashProgress { public String call() throws Exception { - return "' Vendor: '" + GL11.glGetString(GL11.GL_VENDOR) + - "' Version: '" + GL11.glGetString(GL11.GL_VERSION) + - "' Renderer: '" + GL11.glGetString(GL11.GL_RENDERER) + + return "' Vendor: '" + glGetString(GL_VENDOR) + + "' Version: '" + glGetString(GL_VERSION) + + "' Renderer: '" + glGetString(GL_RENDERER) + "'"; } @@ -91,12 +98,6 @@ public class SplashProgress }); CrashReport report = CrashReport.makeCrashReport(new Throwable(), "Loading screen debug info"); System.out.println(report.getCompleteReport()); - fontTexture = GL11.glGenTextures(); - loadTexture(mcPack, fontTexture, fontLocation); - logoTexture = GL11.glGenTextures(); - loadTexture(mcPack, logoTexture, logoLocation); - forgeTexture = GL11.glGenTextures(); - loadTexture(fmlPack, forgeTexture, forgeLocation); try { @@ -120,6 +121,12 @@ public class SplashProgress public void run() { setGL(); + fontTexture = new Texture(mcPack, new ResourceLocation("textures/font/ascii.png")); + logoTexture = new Texture(mcPack, new ResourceLocation("textures/gui/title/mojang.png")); + forgeTexture = new Texture(fmlPack, new ResourceLocation(config.getProperty("forgeTexture"))); + glEnable(GL_TEXTURE_2D); + fontRenderer = new SplashFontRenderer(); + glDisable(GL_TEXTURE_2D); while(!done) { ProgressBar first = null, penult = null, last = null; @@ -134,72 +141,83 @@ public class SplashProgress } } - GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT); // matrix setup int w = Display.getWidth(); int h = Display.getHeight(); - GL11.glViewport(0, 0, w, h); - GL11.glMatrixMode(GL11.GL_PROJECTION); - GL11.glLoadIdentity(); - GL11.glOrtho(320 - w/2, 320 + w/2, 240 + h/2, 240 - h/2, -1, 1); - GL11.glMatrixMode(GL11.GL_MODELVIEW); - GL11.glLoadIdentity(); + 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); - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, logoTexture); - GL11.glBegin(GL11.GL_QUADS); - GL11.glTexCoord2f(0, 0); - GL11.glVertex2f(320 - 256, 240 - 256); - GL11.glTexCoord2f(0, 1); - GL11.glVertex2f(320 - 256, 240 + 256); - GL11.glTexCoord2f(1, 1); - GL11.glVertex2f(320 + 256, 240 + 256); - GL11.glTexCoord2f(1, 0); - GL11.glVertex2f(320 + 256, 240 - 256); - GL11.glEnd(); - GL11.glDisable(GL11.GL_TEXTURE_2D); + 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) { - GL11.glPushMatrix(); - GL11.glTranslatef(320 - (float)barWidth / 2, 310, 0); + glPushMatrix(); + glTranslatef(320 - (float)barWidth / 2, 310, 0); drawBar(first); if(penult != null) { - GL11.glTranslatef(0, barOffset, 0); + glTranslatef(0, barOffset, 0); drawBar(penult); } if(last != null) { - GL11.glTranslatef(0, barOffset, 0); + glTranslatef(0, barOffset, 0); drawBar(last); } - GL11.glPopMatrix(); + glPopMatrix(); } angle += 1; // forge logo setColor(backgroundColor); - GL11.glTranslatef(680, 420, 0); - GL11.glRotatef(angle, 0, 0, 1); - GL11.glEnable(GL11.GL_TEXTURE_2D); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, forgeTexture); - GL11.glBegin(GL11.GL_QUADS); - GL11.glTexCoord2f(0, 0); - GL11.glVertex2f(-50, -50); - GL11.glTexCoord2f(0, 1); - GL11.glVertex2f(-50, 50); - GL11.glTexCoord2f(1, 1); - GL11.glVertex2f(50, 50); - GL11.glTexCoord2f(1, 0); - GL11.glVertex2f(50, -50); - GL11.glEnd(); - GL11.glDisable(GL11.GL_TEXTURE_2D); + float fw = (float)forgeTexture.getWidth() / 2; + float fh = (float)forgeTexture.getHeight() / 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); Display.update(); if(pause) @@ -207,64 +225,56 @@ public class SplashProgress clearGL(); setGL(); } - try - { - Thread.sleep(10); - } - catch (InterruptedException e) - { - e.printStackTrace(); - throw new RuntimeException(e); - } + Display.sync(100); } clearGL(); } private void setColor(int color) { - GL11.glColor3ub((byte)((color >> 16) & 0xFF), (byte)((color >> 8) & 0xFF), (byte)(color & 0xFF)); + glColor3ub((byte)((color >> 16) & 0xFF), (byte)((color >> 8) & 0xFF), (byte)(color & 0xFF)); } private void drawBox(int w, int h) { - GL11.glBegin(GL11.GL_QUADS); - GL11.glVertex2f(0, 0); - GL11.glVertex2f(0, h); - GL11.glVertex2f(w, h); - GL11.glVertex2f(w, 0); - GL11.glEnd(); + glBegin(GL_QUADS); + glVertex2f(0, 0); + glVertex2f(0, h); + glVertex2f(w, h); + glVertex2f(w, 0); + glEnd(); } private void drawBar(ProgressBar b) { - GL11.glPushMatrix(); + glPushMatrix(); // title - message setColor(fontColor); - GL11.glScalef(2, 2, 1); - GL11.glEnable(GL11.GL_TEXTURE_2D); + glScalef(2, 2, 1); + glEnable(GL_TEXTURE_2D); fontRenderer.drawString(b.getTitle() + " - " + b.getMessage(), 0, 0, 0x000000); - GL11.glDisable(GL11.GL_TEXTURE_2D); - GL11.glPopMatrix(); + glDisable(GL_TEXTURE_2D); + glPopMatrix(); // border - GL11.glPushMatrix(); - GL11.glTranslatef(0, textHeight2, 0); + glPushMatrix(); + glTranslatef(0, textHeight2, 0); setColor(barBorderColor); drawBox(barWidth, barHeight); // interior setColor(barBackgroundColor); - GL11.glTranslatef(1, 1, 0); + 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(); - GL11.glTranslatef(((float)barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0); + glTranslatef(((float)barWidth - 2) / 2 - fontRenderer.getStringWidth(progress), 2, 0); setColor(fontColor); - GL11.glScalef(2, 2, 1); - GL11.glEnable(GL11.GL_TEXTURE_2D); + glScalef(2, 2, 1); + glEnable(GL_TEXTURE_2D); fontRenderer.drawString(progress, 0, 0, 0x000000); - GL11.glPopMatrix(); + glPopMatrix(); } private void setGL() @@ -279,17 +289,11 @@ public class SplashProgress e.printStackTrace(); throw new RuntimeException(e); } - GL11.glClearColor((float)((backgroundColor >> 16) & 0xFF) / 0xFF, (float)((backgroundColor >> 8) & 0xFF) / 0xFF, (float)(backgroundColor & 0xFF) / 0xFF, 1); - GL11.glDisable(GL11.GL_LIGHTING); - GL11.glDisable(GL11.GL_DEPTH_TEST); - GL11.glEnable(GL11.GL_BLEND); - GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); - GL11.glEnable(GL11.GL_TEXTURE_2D); - if(fontRenderer == null) - { - fontRenderer = new SplashFontRenderer(); - } - GL11.glDisable(GL11.GL_TEXTURE_2D); + 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() @@ -298,11 +302,11 @@ public class SplashProgress mc.displayWidth = Display.getWidth(); mc.displayHeight = Display.getHeight(); mc.resize(mc.displayWidth, mc.displayHeight); - GL11.glClearColor(1, 1, 1, 1); - GL11.glEnable(GL11.GL_DEPTH_TEST); - GL11.glDepthFunc(GL11.GL_LEQUAL); - GL11.glEnable(GL11.GL_ALPHA_TEST); - GL11.glAlphaFunc(GL11.GL_GREATER, .1f); + glClearColor(1, 1, 1, 1); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, .1f); try { Display.getDrawable().releaseContext(); @@ -394,9 +398,9 @@ public class SplashProgress thread.join(); d.releaseContext(); Display.getDrawable().makeCurrent(); - GL11.glDeleteTextures(fontTexture); - GL11.glDeleteTextures(logoTexture); - GL11.glDeleteTextures(forgeTexture); + fontTexture.delete(); + logoTexture.delete(); + forgeTexture.delete(); } catch (Exception e) { @@ -443,22 +447,134 @@ public class SplashProgress return Integer.decode(config.getProperty(name)); } - private static void loadTexture(IResourcePack pack, int name, ResourceLocation location) + private static final IntBuffer buf = BufferUtils.createIntBuffer(4 * 1024 * 1024); + + private static class Texture { - InputStream s = null; - try + 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(IResourcePack pack, ResourceLocation location) { - s = pack.getInputStream(location); - TextureUtil.uploadTextureImageAllocate(name, ImageIO.read(pack.getInputStream(location)), false, false); + InputStream s = null; + try + { + this.location = location; + s = pack.getInputStream(location); + ImageInputStream stream = ImageIO.createImageInputStream(s); + Iterator 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; + name = glGenTextures(); + glEnable(GL_TEXTURE_2D); + 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++) + { + FMLLog.info("loc: %s, i: %s, j: %s, size: %s, width: %s, height: %s", location, i, j, size, width, height); + 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); + } } - catch(IOException e) + + public ResourceLocation getLocation() { - e.printStackTrace(); - throw new RuntimeException(e); + return location; } - finally + + public int getName() { - IOUtils.closeQuietly(s); + return name; + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } + + public int getFrames() + { + return frames; + } + + 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)); } } @@ -466,7 +582,7 @@ public class SplashProgress { public SplashFontRenderer() { - super(Minecraft.getMinecraft().gameSettings, fontLocation, null, false); + super(Minecraft.getMinecraft().gameSettings, fontTexture.getLocation(), null, false); super.onResourceManagerReload(null); } @@ -474,7 +590,7 @@ public class SplashProgress protected void bindTexture(ResourceLocation location) { if(location != locationFontTexture) throw new IllegalArgumentException(); - GL11.glBindTexture(GL11.GL_TEXTURE_2D, fontTexture); + fontTexture.bind(); } @Override @@ -499,4 +615,13 @@ public class SplashProgress renderEngine.deleteTexture(mojangLogo); } } + + public static void checkGLError(String where) + { + int err = GL11.glGetError(); + if (err != 0) + { + throw new IllegalStateException(where + ": " + GLU.gluErrorString(err)); + } + } } diff --git a/fml/src/main/resources/assets/fml/splash.properties b/fml/src/main/resources/assets/fml/splash.properties index 84ec35672..4cfb4f5d8 100644 --- a/fml/src/main/resources/assets/fml/splash.properties +++ b/fml/src/main/resources/assets/fml/splash.properties @@ -1,5 +1,8 @@ enabled = true +rotate = true +forgeTexture = fml:textures/gui/forge.png +logoOffset = 10 background = 0xFFFFFF font = 0x000000 barBorder = 0xC0C0C0