package de.take_weiland.mods.commons.client; import de.take_weiland.mods.commons.util.SCReflector; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBlocks; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.texture.TextureObject; import net.minecraft.util.Icon; import net.minecraft.util.MathHelper; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.IFluidTank; import javax.annotation.Nullable; import static net.minecraftforge.common.ForgeDirection.*; import static org.lwjgl.opengl.GL11.*; /** * <p>Helpful utilities for various rendering tasks.</p> * * @author diesieben07 */ public final class Rendering { /** * <p>Fills a specified area on the screen with the provided {@link net.minecraft.util.Icon Icon}.</p> * * @param icon The {@link net.minecraft.util.Icon Icon} to be displayed * @param x The X coordinate to start drawing from * @param y The Y coordinate to start drawing form * @param width The width of the provided icon to draw on the screen * @param height The height of the provided icon to draw on the screen */ public static void fillAreaWithIcon(Icon icon, int x, int y, int width, int height) { Tessellator t = Tessellator.instance; t.startDrawingQuads(); float zLevel = getZLevel(); int iconWidth = icon.getIconWidth(); int iconHeight = icon.getIconHeight(); // number of rows & cols of "full" icons (full size) int fullCols = MathHelper.floor_float(width / (float) iconWidth); int fullRows = MathHelper.floor_float(height / (float) iconHeight); float minU = icon.getMinU(); float maxU = icon.getMaxU(); float minV = icon.getMinV(); float maxV = icon.getMaxV(); // interpolated max u/v for the excess row / col float partialMaxU = minU + (maxU - minU) * ((width - fullCols * iconWidth) / (float) width); float partialMaxV = minV + (maxV - minV) * ((height - fullRows * iconHeight) / (float) height); boolean excessCol = (width % iconWidth) != 0; boolean excessRow = (height % iconHeight) != 0; int xNow; int yNow; for (int row = 0; row < fullRows; row++) { yNow = y + row * iconHeight; for (int col = 0; col < fullCols; col++) { // main part, only full icons xNow = x + col * iconWidth; t.addVertexWithUV(xNow, yNow + iconHeight, zLevel, minU, maxV); t.addVertexWithUV(xNow + iconWidth, yNow + iconHeight, zLevel, maxU, maxV); t.addVertexWithUV(xNow + iconWidth, yNow, zLevel, maxU, minV); t.addVertexWithUV(xNow, yNow, zLevel, minU, minV); } if (excessCol) { // excess part in every row at the end of the columns xNow = x + fullCols * iconWidth; t.addVertexWithUV(xNow, yNow + iconHeight, zLevel, minU, maxV); t.addVertexWithUV(x + width, yNow + iconHeight, zLevel, partialMaxU, maxV); t.addVertexWithUV(x + width, yNow, zLevel, partialMaxU, minV); t.addVertexWithUV(xNow, yNow, zLevel, minU, minV); } } if (excessRow) { // last "excess" row for (int col = 0; col < fullCols; col++) { xNow = x + col * iconWidth; yNow = y + fullRows * iconHeight; t.addVertexWithUV(xNow, y + height, zLevel, minU, partialMaxV); t.addVertexWithUV(xNow + iconWidth, y + height, zLevel, maxU, partialMaxV); t.addVertexWithUV(xNow + iconWidth, yNow, zLevel, maxU, minV); t.addVertexWithUV(xNow, yNow, zLevel, minU, minV); } if (excessCol) { // missing quad in the bottom right corner when excess row & col xNow = x + fullCols * iconWidth; yNow = y + fullRows * iconHeight; t.addVertexWithUV(xNow, y + height, zLevel, minU, partialMaxV); t.addVertexWithUV(x + width, y + height, zLevel, partialMaxU, partialMaxV); t.addVertexWithUV(x + width, yNow, zLevel, partialMaxU, minV); t.addVertexWithUV(xNow, yNow, zLevel, minU, minV); } } t.draw(); } /** * <p>Draw a vertical bar representing the fullness of a Tank filled with the given FluidStack and of the given capacity.</p> * * @param fluidStack the FluidStack * @param tankCapacity the capacity of the tank (maximum amount of fluid in the FluidStack) * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle to draw * @param fullHeight the height of the rectangle when the tank is full */ public static void drawFluidStack(@Nullable FluidStack fluidStack, int tankCapacity, int x, int y, int width, int fullHeight) { TextureManager renderEngine = Minecraft.getMinecraft().renderEngine; if (fluidStack != null) { Fluid fluid = fluidStack.getFluid(); Icon fluidIcon = fluid.getStillIcon(); int fluidHeight = MathHelper.ceiling_float_int((fluidStack.amount / (float) tankCapacity) * fullHeight); glColor3f(1, 1, 1); renderEngine.bindTexture(renderEngine.getResourceLocation(fluid.getSpriteNumber())); fillAreaWithIcon(fluidIcon, x, y + fullHeight - fluidHeight, width, fluidHeight); } } /** * <p>Draw a horizontal bar representing the fullness of a Tank filled with the given FluidStack and of the given capacity.</p> * * @param fluidStack the FluidStack * @param tankCapacity the capacity of the tank (maximum amount of fluid in the FluidStack) * @param x the x coordinate * @param y the y coordinate * @param fullWidth the width of the rectangle when the tank is full * @param height the height of the rectangle */ public static void drawFluidStackHorizontal(@Nullable FluidStack fluidStack, int tankCapacity, int x, int y, int fullWidth, int height) { TextureManager renderEngine = Minecraft.getMinecraft().renderEngine; if (fluidStack != null) { Fluid fluid = fluidStack.getFluid(); Icon fluidIcon = fluid.getStillIcon(); int fluidWidth = MathHelper.ceiling_float_int((fluidStack.amount / (float) tankCapacity) * fullWidth); glColor3f(1, 1, 1); renderEngine.bindTexture(renderEngine.getResourceLocation(fluid.getSpriteNumber())); fillAreaWithIcon(fluidIcon, x, y, fluidWidth, height); } } /** * <p>Draw a vertical bar representing the fullness of the given {@code IFluidTank}.</p> * * @param tank the tank * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle to draw * @param fullHeight the height of the rectangle, if the tank is full */ public static void drawTank(IFluidTank tank, int x, int y, int width, int fullHeight) { drawFluidStack(tank.getFluid(), tank.getCapacity(), x, y, width, fullHeight); } /** * <p>Draw a horizontal bar representing the fullness of the given {@code IFluidTank}.</p> * * @param tank the tank * @param x the x coordinate * @param y the y coordinate * @param fullWidth the width of the rectangle when the tank is full * @param height the height of the rectangle */ public static void drawTankHorizontal(IFluidTank tank, int x, int y, int fullWidth, int height) { drawFluidStackHorizontal(tank.getFluid(), tank.getCapacity(), x, y, fullWidth, height); } /** * <p>Draw a simple inventory block. This method draws a cuboid based on the current block dimensions.</p> * * @param block the Block to draw * @param meta the Block metadata * @param renderer the RenderBlocks instance */ public static void drawInventoryBlock(Block block, int meta, RenderBlocks renderer) { Tessellator t = Tessellator.instance; t.startDrawingQuads(); t.setNormal(-1, 0, 0); renderer.renderFaceXNeg(block, 0, 0, 0, renderer.getBlockIconFromSideAndMetadata(block, WEST.ordinal(), meta)); t.draw(); t.startDrawingQuads(); t.setNormal(1, 0, 0); renderer.renderFaceXPos(block, 0, 0, 0, renderer.getBlockIconFromSideAndMetadata(block, EAST.ordinal(), meta)); t.draw(); t.startDrawingQuads(); t.setNormal(0, 0, -1); renderer.renderFaceZNeg(block, 0, 0, 0, renderer.getBlockIconFromSideAndMetadata(block, NORTH.ordinal(), meta)); t.draw(); t.startDrawingQuads(); t.setNormal(0, 0, 1); renderer.renderFaceZPos(block, 0, 0, 0, renderer.getBlockIconFromSideAndMetadata(block, SOUTH.ordinal(), meta)); t.draw(); t.startDrawingQuads(); t.setNormal(0, -1, 0); renderer.renderFaceYNeg(block, 0, 0, 0, renderer.getBlockIconFromSideAndMetadata(block, DOWN.ordinal(), meta)); t.draw(); t.startDrawingQuads(); t.setNormal(0, 1, 0); renderer.renderFaceYPos(block, 0, 0, 0, renderer.getBlockIconFromSideAndMetadata(block, UP.ordinal(), meta)); t.draw(); } /** * <p>Draw a colored rectangle.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param color the color (in RGB format, e.g. {@code 0xFF0000}) */ public static void drawColoredQuad(int x, int y, int width, int height, int color) { drawColoredQuad(x, y, width, height, color, 0xFF, getZLevel()); } /** * <p>Draw a colored rectangle.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param color the color (in RGB format, e.g. {@code 0xFF0000}) * @param alpha the opacity of the rectangle (0 = completely transparent, 255 = completely opaque) */ public static void drawColoredQuad(int x, int y, int width, int height, int color, int alpha) { drawColoredQuad(x, y, width, height, color, alpha, getZLevel()); } /** * <p>Draw a colored rectangle.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param color the color (in RGB format, e.g. {@code 0xFF0000}) * @param alpha the opacity of the rectangle (0 = completely transparent, 255 = completely opaque) * @param zLevel the z-level to draw at */ public static void drawColoredQuad(int x, int y, int width, int height, int color, int alpha, float zLevel) { if (alpha == 0) { return; } float r = (float) (color >> 16 & 0xFF) / 255.0F; float g = (float) (color >> 8 & 0xFF) / 255.0F; float b = (float) (color & 0xFF) / 255.0F; glDisable(GL_TEXTURE_2D); if (alpha != 255) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glColor4f(r, g, b, alpha / 255F); Tessellator t = Tessellator.instance; t.startDrawingQuads(); t.addVertex(x, y + height, zLevel); t.addVertex(x + width, y + height, zLevel); t.addVertex(x + width, y, zLevel); t.addVertex(x, y, zLevel); t.draw(); glEnable(GL_TEXTURE_2D); if (alpha != 255) { glDisable(GL_BLEND); } } /** * <p>Draw a vertical gradient.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param toColor the end color in RGB format */ public static void verticalGradient(int x, int y, int width, int height, int fromColor, int toColor) { drawGradient(false, x, y, width, height, fromColor, toColor); } /** * <p>Draw a vertical gradient.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param fromAlpha the alpha value for the start color (0-255) * @param toColor the end color in RGB format * @param toAlpha the alpha value for the end color (0-255) */ public static void verticalGradient(int x, int y, int width, int height, int fromColor, int fromAlpha, int toColor, int toAlpha) { drawGradient(false, x, y, width, height, fromColor, fromAlpha, toColor, toAlpha); } /** * <p>Draw a vertical gradient.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param fromAlpha the alpha value for the start color (0-255) * @param toColor the end color in RGB format * @param toAlpha the alpha value for the end color (0-255) * @param zLevel the z-level to draw at */ public static void verticalGradient(int x, int y, int width, int height, int fromColor, int fromAlpha, int toColor, int toAlpha, float zLevel) { drawGradient(false, x, y, width, height, fromColor, fromAlpha, toColor, toAlpha, zLevel); } /** * <p>Draw a horizontal gradient.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param toColor the end color in RGB format */ public static void horizontalGradient(int x, int y, int width, int height, int fromColor, int toColor) { drawGradient(true, x, y, width, height, fromColor, toColor); } /** * <p>Draw a horizontal gradient.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param fromAlpha the alpha value for the start color (0-255) * @param toColor the end color in RGB format * @param toAlpha the alpha value for the end color (0-255) */ public static void horizontalGradient(int x, int y, int width, int height, int fromColor, int fromAlpha, int toColor, int toAlpha) { drawGradient(true, x, y, width, height, fromColor, fromAlpha, toColor, toAlpha); } /** * <p>Draw a horizontal gradient.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param fromAlpha the alpha value for the start color (0-255) * @param toColor the end color in RGB format * @param toAlpha the alpha value for the end color (0-255) * @param zLevel the z-level to draw at */ public static void horizontalGradient(int x, int y, int width, int height, int fromColor, int fromAlpha, int toColor, int toAlpha, float zLevel) { drawGradient(true, x, y, width, height, fromColor, fromAlpha, toColor, toAlpha, zLevel); } /** * <p>Draw a gradient.</p> * * @param horizontal if a horizontal or vertical gradient should be drawn * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param toColor the end color in RGB format */ public static void drawGradient(boolean horizontal, int x, int y, int width, int height, int fromColor, int toColor) { drawGradient(horizontal, x, y, width, height, fromColor, 0xFF, toColor, 0xFF, getZLevel()); } /** * <p>Draw a gradient.</p> * * @param horizontal if a horizontal or vertical gradient should be drawn * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param fromAlpha the alpha value for the start color (0-255) * @param toColor the end color in RGB format * @param toAlpha the alpha value for the end color (0-255) */ public static void drawGradient(boolean horizontal, int x, int y, int width, int height, int fromColor, int fromAlpha, int toColor, int toAlpha) { drawGradient(horizontal, x, y, width, height, fromColor, fromAlpha, toColor, toAlpha, getZLevel()); } /** * <p>Draw a gradient.</p> * * @param horizontal if a horizontal or vertical gradient should be drawn * @param x the x coordinate * @param y the y coordinate * @param width the width of the gradient * @param height the height of the gradient * @param fromColor the start color in RGB format * @param fromAlpha the alpha value for the start color (0-255) * @param toColor the end color in RGB format * @param toAlpha the alpha value for the end color (0-255) * @param zLevel the z-level to draw at */ public static void drawGradient(boolean horizontal, int x, int y, int width, int height, int fromColor, int fromAlpha, int toColor, int toAlpha, float zLevel) { if (fromAlpha == 0 && toAlpha == 0) { return; } boolean needBlending = fromAlpha != 255 || toAlpha != 255; float r1 = (float) (fromColor >> 16 & 0xFF) / 255.0F; float g1 = (float) (fromColor >> 8 & 0xFF) / 255.0F; float b1 = (float) (fromColor & 0xFF) / 255.0F; float r2 = (float) (toColor >> 16 & 0xFF) / 255.0F; float g2 = (float) (toColor >> 8 & 0xFF) / 255.0F; float b2 = (float) (toColor & 0xFF) / 255.0F; if (needBlending) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glDisable(GL_TEXTURE_2D); glDisable(GL_ALPHA_TEST); glShadeModel(GL_SMOOTH); Tessellator t = Tessellator.instance; t.startDrawingQuads(); if (horizontal) { horizontalGradient0(x, y, width, height, fromAlpha, toAlpha, zLevel, r1, g1, b1, r2, g2, b2); } else { verticalGradient0(x, y, width, height, fromAlpha, toAlpha, zLevel, r1, g1, b1, r2, g2, b2); } t.draw(); glShadeModel(GL_FLAT); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); if (needBlending) { glDisable(GL_BLEND); } } private static void verticalGradient0(int x, int y, int width, int height, int fromAlpha, int toAlpha, float zLevel, float r1, float g1, float b1, float r2, float g2, float b2) { Tessellator t = Tessellator.instance; t.setColorRGBA_F(r1, g1, b1, fromAlpha / 255F); t.addVertex(x, y + height, zLevel); t.addVertex(x + width, y + height, zLevel); t.setColorRGBA_F(r2, g2, b2, toAlpha / 255F); t.addVertex(x + width, y, zLevel); t.addVertex(x, y, zLevel); } private static void horizontalGradient0(int x, int y, int width, int height, int fromAlpha, int toAlpha, float zLevel, float r1, float g1, float b1, float r2, float g2, float b2) { Tessellator t = Tessellator.instance; t.setColorRGBA_F(r1, g1, b1, fromAlpha / 255F); t.addVertex(x, y + height, zLevel); t.setColorRGBA_F(r2, g2, b2, toAlpha / 255F); t.addVertex(x + width, y + height, zLevel); t.setColorRGBA_F(r2, g2, b2, toAlpha / 255F); t.addVertex(x + width, y, zLevel); t.setColorRGBA_F(r1, g1, b1, fromAlpha / 255F); t.addVertex(x, y, zLevel); } /** * <p>Draw a textured rectangle.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param u the x coordinate in the texture * @param v the y coordinate in the texture * @param uSize the width of the rectangle in the texture * @param vSize the height of the rectangle in the texture * @param texSize the dimensions of the texture (width & height) * @param zLevel the z-level to draw at */ public static void drawTexturedQuad(int x, int y, int width, int height, int u, int v, int uSize, int vSize, int texSize, float zLevel) { drawTexturedQuad(x, y, width, height, u, v, uSize, vSize, texSize, texSize, zLevel); } /** * <p>Draw a textured rectangle.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param u the x coordinate in the texture * @param v the y coordinate in the texture * @param uSize the width of the rectangle in the texture * @param vSize the height of the rectangle in the texture * @param texSize the dimensions of the texture (width & height) */ public static void drawTexturedQuad(int x, int y, int width, int height, int u, int v, int uSize, int vSize, int texSize) { drawTexturedQuad(x, y, width, height, u, v, uSize, vSize, texSize, texSize, getZLevel()); } /** * <p>Draw a textured rectangle.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param u the x coordinate in the texture * @param v the y coordinate in the texture * @param uSize the width of the rectangle in the texture * @param vSize the height of the rectangle in the texture * @param texWidth the width of the texture * @param texHeight the height of the texture */ public static void drawTexturedQuad(int x, int y, int width, int height, int u, int v, int uSize, int vSize, int texWidth, int texHeight) { drawTexturedQuad(x, y, width, height, u, v, uSize, vSize, texWidth, texHeight, getZLevel()); } /** * <p>Draw a textured rectangle.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param u the x coordinate in the texture * @param v the y coordinate in the texture * @param uSize the width of the rectangle in the texture * @param vSize the height of the rectangle in the texture * @param texWidth the width of the texture * @param texHeight the height of the texture * @param zLevel the z-level to draw at */ public static void drawTexturedQuad(int x, int y, int width, int height, int u, int v, int uSize, int vSize, int texWidth, int texHeight, float zLevel) { float uFact = 1f / texWidth; float vFact = 1f / texHeight; int uEnd = u + uSize; int vEnd = v + vSize; Tessellator t = Tessellator.instance; t.startDrawingQuads(); t.addVertexWithUV(x, y + height, zLevel, u * uFact, vEnd * vFact); t.addVertexWithUV(x + width, y + height, zLevel, uEnd * uFact, vEnd * vFact); t.addVertexWithUV(x + width, y, zLevel, uEnd * uFact, v * vFact); t.addVertexWithUV(x, y, zLevel, u * uFact, v * vFact); t.draw(); } /** * <p>Draw a textured rectangle with the entire texture scaled to the given dimensions.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle */ public static void drawTexturedQuadFit(int x, int y, int width, int height) { drawTexturedQuadFit(x, y, width, height, getZLevel()); } /** * <p>Draw a textured rectangle with the entire texture scaled to the given dimensions.</p> * * @param x the x coordinate * @param y the y coordinate * @param width the width of the rectangle * @param height the height of the rectangle * @param zLevel the z-level to draw at */ public static void drawTexturedQuadFit(int x, int y, int width, int height, float zLevel) { Tessellator t = Tessellator.instance; t.startDrawingQuads(); t.addVertexWithUV(x, y + height, zLevel, 0, 1); t.addVertexWithUV(x + width, y + height, zLevel, 1, 1); t.addVertexWithUV(x + width, y, zLevel, 1, 0); t.addVertexWithUV(x, y, zLevel, 0, 0); t.draw(); } /** * <p>Unload the texture specified by the given ResourceLocation.</p> * * @param loc the ResourceLocation */ public static void unloadTexture(ResourceLocation loc) { TextureObject tex = SCReflector.instance.getTexturesMap(Minecraft.getMinecraft().renderEngine).remove(loc); if (tex != null) { glDeleteTextures(tex.getGlTextureId()); } } private static float getZLevel() { return SCReflector.instance.getZLevel(Minecraft.getMinecraft().currentScreen); } private Rendering() { } }