Java tutorial
/******************************************************************************* * HellFirePvP / Astral Sorcery 2017 * * This project is licensed under GNU GENERAL PUBLIC LICENSE Version 3. * The source code is available on github: https://github.com/HellFirePvP/AstralSorcery * For further details, see the License file there. ******************************************************************************/ package hellfirepvp.astralsorcery.client.sky; import hellfirepvp.astralsorcery.client.util.RenderConstellation; import hellfirepvp.astralsorcery.client.util.TextureHelper; import hellfirepvp.astralsorcery.client.util.mappings.ClientConstellationPositionMapping; import hellfirepvp.astralsorcery.client.util.resource.AssetLibrary; import hellfirepvp.astralsorcery.client.util.resource.AssetLoader; import hellfirepvp.astralsorcery.client.util.resource.BindableResource; import hellfirepvp.astralsorcery.common.constellation.CelestialEvent; import hellfirepvp.astralsorcery.common.constellation.IConstellation; import hellfirepvp.astralsorcery.common.constellation.distribution.ConstellationSkyHandler; import hellfirepvp.astralsorcery.common.constellation.distribution.WorldSkyHandler; import hellfirepvp.astralsorcery.common.data.research.ResearchManager; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.client.IRenderHandler; import org.lwjgl.opengl.GL11; import java.util.Map; import java.util.Random; /** * This class is part of the Astral Sorcery Mod * The complete source code for this mod can be found on github. * Class: RenderAstralSkybox * Created by HellFirePvP * Date: 07.05.2016 / 00:50 */ public class RenderAstralSkybox extends IRenderHandler { private long worldSeed; private boolean initialized = false; private static final ResourceLocation MC_DEF_SUN_PNG = new ResourceLocation("textures/environment/sun.png"); private static final ResourceLocation MC_DEF_MOON_PHASES_PNG = new ResourceLocation( "textures/environment/moon_phases.png"); public static final BindableResource TEX_STAR_1 = AssetLibrary .loadTexture(AssetLoader.TextureLocation.ENVIRONMENT, "star1"); public static final BindableResource TEX_STAR_2 = AssetLibrary .loadTexture(AssetLoader.TextureLocation.ENVIRONMENT, "star2"); public static final BindableResource TEX_STAR_3 = AssetLibrary .loadTexture(AssetLoader.TextureLocation.ENVIRONMENT, "star2"); public static final BindableResource TEX_STAR_4 = AssetLibrary .loadTexture(AssetLoader.TextureLocation.ENVIRONMENT, "star1"); public static final BindableResource TEX_CONNECTION = AssetLibrary .loadTexture(AssetLoader.TextureLocation.EFFECT, "connectionperks"); public static final BindableResource TEX_SOLAR_ECLIPSE = AssetLibrary .loadTexture(AssetLoader.TextureLocation.ENVIRONMENT, "solareclipse"); private static int glSkyList = -1; //Sky background vertices. private static int glSkyList2 = -1; // - "" - private static final int[] starAmountMap = new int[] { 200, 200, 100, 100, 100, /**/ 200, 100, 50, 50, 100, /**/ 50, 50, 100, 100, 100, /**/ 50, 50, 100, 100, 100 }; private static final double[] starSizeMap = new double[] { 1, 1, 1, 1.2, 1, /**/ 1, 1.1, 1.2, 1, 1, /**/ 1.2, 1.1, 1, 1, 1, /**/ 1.2, 1.3, 1, 1, 1 }; private static StarDList[] starLists = new StarDList[0]; @Override public void render(float partialTicks, WorldClient world, Minecraft mc) { if (!isInitialized()) return; //Avg 0,36-0,5ms rendering time. //long n = System.nanoTime(); //GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); //GL11.glPushMatrix(); renderSky(partialTicks); //GL11.glPopMatrix(); //GL11.glPopAttrib(); //AstralSorcery.log.info(System.nanoTime() - n); } public void refreshRender() { initialized = false; } public boolean isInitialized() { return initialized; } //Sets up skybox with given seed. public void setInitialized(long worldSeed) { this.worldSeed = worldSeed; setupSkybox(); setupStarVertices(); this.initialized = true; } private void setupStarVertices() { cleanStarVertices(); starLists = new StarDList[20]; for (int i = 0; i < starLists.length; i++) { starLists[i] = new StarDList(); } VertexBuffer vb = Tessellator.getInstance().getBuffer(); Random vRand = new Random(worldSeed); int list = GLAllocation.generateDisplayLists(20); for (int i = 0; i < starLists.length; i++) { StarDList l = starLists[i]; l.glList = list + i; l.sinDivisor = 10 + vRand.nextInt(15); switch (i / (starLists.length / 4)) { case 0: l.resource = TEX_STAR_1; break; case 1: l.resource = TEX_STAR_2; break; case 2: l.resource = TEX_STAR_3; break; case 3: l.resource = TEX_STAR_4; break; } GlStateManager.glNewList(l.glList, GL11.GL_COMPILE); l.resource.bind(); vb.begin(7, DefaultVertexFormats.POSITION_TEX); setupStars(vb, vRand, starAmountMap[i], starSizeMap[i]); Tessellator.getInstance().draw(); GlStateManager.glEndList(); } } private void cleanStarVertices() { for (StarDList list : starLists) { if (list.glList != -1) { GLAllocation.deleteDisplayLists(list.glList); list.glList = -1; } } } private void setupStars(VertexBuffer vb, Random random, int amount, double multiplier) { for (int i = 0; i < amount; ++i) { //Amount of stars. double x = (double) (random.nextFloat() * 2.0F - 1.0F); double y = (double) (random.nextFloat() * 2.0F - 1.0F); double z = (double) (random.nextFloat() * 2.0F - 1.0F); double ovrSize = (double) (0.15F + random.nextFloat() * 0.2F); //Size flat increase. double d4 = x * x + y * y + z * z; if (d4 < 1.0D && d4 > 0.01D) { //d4 = Vector3.fastInvSqrt(d4); d4 = 1.0D / Math.sqrt(d4); x *= d4; y *= d4; z *= d4; double d5 = x * 100.0D; double d6 = y * 100.0D; double d7 = z * 100.0D; double d8 = Math.atan2(x, z); double d9 = Math.sin(d8); double d10 = Math.cos(d8); double d11 = Math.atan2(Math.sqrt(x * x + z * z), y); double d12 = Math.sin(d11); double d13 = Math.cos(d11); //Sizes double d14 = random.nextDouble() * Math.PI * 2.0D; double size = Math.sin(d14) * 2; //Size percentage increase. double d16 = Math.cos(d14); size *= multiplier; //Set 2D vertices for (int j = 0; j < 4; ++j) { double d18 = (double) ((j & 2) - 1) * ovrSize; //0 = -1 * [0.15-0.25[ double d19 = (double) ((j + 1 & 2) - 1) * ovrSize; //0 = -1 * [0.15-0.25[ double d21 = d18 * d16 - d19 * size; double d22 = d19 * d16 + d18 * size; double d23 = d21 * d12 + 0.0D * d13; double d24 = 0.0D * d12 - d21 * d13; double d25 = d24 * d9 - d22 * d10; double d26 = d22 * d9 + d24 * d10; vb.pos(d5 + d25, d6 + d23, d7 + d26).tex(((j + 1) & 2) >> 1, ((j + 2) & 2) >> 1).endVertex(); } } } } private void setupSkybox() { if (glSkyList >= 0) { GLAllocation.deleteDisplayLists(glSkyList); glSkyList = -1; } glSkyList = GLAllocation.generateDisplayLists(1); GlStateManager.glNewList(glSkyList, GL11.GL_COMPILE); setupBackground(false); Tessellator.getInstance().draw(); GlStateManager.glEndList(); if (glSkyList2 >= 0) { GLAllocation.deleteDisplayLists(glSkyList2); glSkyList2 = -1; } glSkyList2 = GLAllocation.generateDisplayLists(1); GlStateManager.glNewList(glSkyList2, GL11.GL_COMPILE); setupBackground(true); Tessellator.getInstance().draw(); GlStateManager.glEndList(); } private void setupBackground(boolean invert) { VertexBuffer vb = Tessellator.getInstance().getBuffer(); vb.begin(7, DefaultVertexFormats.POSITION); for (int k = -384; k <= 384; k += 64) { for (int l = -384; l <= 384; l += 64) { float px = k + 64; float p = k; if (invert) { px = k; p = k + 64; } vb.pos(p, 16, l).endVertex(); vb.pos(px, 16, l).endVertex(); vb.pos(px, 16, l + 64).endVertex(); vb.pos(p, 16, l + 64).endVertex(); } } } private void renderSky(float partialTicks) { GlStateManager.disableTexture2D(); Vec3d vec3 = Minecraft.getMinecraft().world.getSkyColor(Minecraft.getMinecraft().getRenderViewEntity(), partialTicks); float f = (float) vec3.xCoord; float f1 = (float) vec3.yCoord; float f2 = (float) vec3.zCoord; if (Minecraft.getMinecraft().gameSettings.anaglyph) { float f3 = (f * 30.0F + f1 * 59.0F + f2 * 11.0F) / 100.0F; float f4 = (f * 30.0F + f1 * 70.0F) / 100.0F; float f5 = (f * 30.0F + f2 * 70.0F) / 100.0F; f = f3; f1 = f4; f2 = f5; } Tessellator tessellator = Tessellator.getInstance(); VertexBuffer vb = tessellator.getBuffer(); GlStateManager.depthMask(false); GlStateManager.enableFog(); GlStateManager.color(f, f1, f2); GlStateManager.callList(glSkyList); GlStateManager.disableFog(); GlStateManager.disableAlpha(); GlStateManager.enableBlend(); GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); RenderHelper.disableStandardItemLighting(); float[] sunsetColors = Minecraft.getMinecraft().world.provider.calcSunriseSunsetColors( Minecraft.getMinecraft().world.getCelestialAngle(partialTicks), partialTicks); if (sunsetColors != null) { renderSunsetToBackground(sunsetColors, partialTicks); } renderDefaultCelestials(partialTicks); double absPlayerHorizon = Minecraft.getMinecraft().player.getPositionEyes(partialTicks).yCoord - Minecraft.getMinecraft().world.getHorizon(); if (absPlayerHorizon < 0.0D) { GlStateManager.pushMatrix(); GlStateManager.translate(0.0F, 12.0F, 0.0F); GlStateManager.callList(glSkyList2); GlStateManager.popMatrix(); } if (Minecraft.getMinecraft().world.provider.isSkyColored()) { GlStateManager.color(f * 0.2F + 0.04F, f1 * 0.2F + 0.04F, f2 * 0.6F + 0.1F); } else { GlStateManager.color(f, f1, f2); } GlStateManager.pushMatrix(); GlStateManager.translate(0.0F, -((float) (absPlayerHorizon - 16.0D)), 0.0F); //GlStateManager.callList(glSkyList2); //TODO GlStateManager.popMatrix(); GlStateManager.enableTexture2D(); GlStateManager.depthMask(true); } private void renderDefaultCelestials(float partialTicks) { GlStateManager.enableTexture2D(); GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); GlStateManager.pushMatrix(); //Bind alpha according to rain strength - if it rains "completely", moon, sun and stars are not rendered. float alphaSubRain = 1.0F - Minecraft.getMinecraft().world.getRainStrength(partialTicks); GlStateManager.color(1.0F, 1.0F, 1.0F, alphaSubRain); GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F); GlStateManager.rotate(Minecraft.getMinecraft().world.getCelestialAngle(partialTicks) * 360.0F, 1.0F, 0.0F, 0.0F); WorldSkyHandler handle = ConstellationSkyHandler.getInstance() .getWorldHandler(Minecraft.getMinecraft().world); if (handle != null && handle.getCurrentlyActiveEvent() == CelestialEvent.SOLAR_ECLIPSE) { renderSolarEclipseSun(handle); } else { renderSun(); } if (handle != null && handle.getCurrentlyActiveEvent() == CelestialEvent.LUNAR_ECLIPSE) { int eclTick = handle.lunarEclipseTick; if (eclTick >= ConstellationSkyHandler.LUNAR_ECLIPSE_HALF_DUR) { //fading out eclTick -= ConstellationSkyHandler.LUNAR_ECLIPSE_HALF_DUR; } else { eclTick = ConstellationSkyHandler.LUNAR_ECLIPSE_HALF_DUR - eclTick; } float perc = ((float) eclTick) / ConstellationSkyHandler.LUNAR_ECLIPSE_HALF_DUR; GlStateManager.color(1F, 0.4F + (0.6F * perc), 0.4F + (0.6F * perc), alphaSubRain); renderMoon(); } else { renderMoon(); } renderStars(Minecraft.getMinecraft().world, partialTicks); renderConstellations(Minecraft.getMinecraft().world, partialTicks); /*Tessellator tes = Tessellator.getInstance(); VertexBuffer vb = tes.getBuffer(); List<double[]> poss = new LinkedList<>(); poss.add(new double[] { 0.2, -0.2, 0, 5}); poss.add(new double[] {-0.2, -0.2, -0.05, 5}); poss.add(new double[] { 0, -0.25, -0.2, 8}); poss.add(new double[] {-0.4, -0.6, 0.5, 18}); poss.add(new double[] { 0.3, -0.5, 0.5, 19}); poss.add(new double[] { 0.15, -0.2, -0.1, 5}); poss.add(new double[] {-0.05, -0.3, 0.4, 10}); poss.add(new double[] {-0.3, -0.3, 0.1, 10}); poss.add(new double[] {-0.3, -0.4, -0.35, 15}); poss.add(new double[] { 0.4, -0.4, 0.2, 15}); for (double[] position : poss) { double x = position[0]; double y = position[1]; double z = position[2]; double size = position[3]; double fx = x * 100.0D; double fy = y * 100.0D; double fz = z * 100.0D; double d8 = Math.atan2(x, z); // [-PI - PI] double d9 = Math.sin(d8); double d10 = Math.cos(d8); // pythagoras? double d11 = Math.atan2(Math.sqrt(x * x + z * z), y); // [-PI - PI] double d12 = Math.sin(d11); double d13 = Math.cos(d11); //double d14 = random.nextDouble() * Math.PI * 2.0D; //double d16 = Math.cos(d14); rotation! double rotation = 0; GL11.glColor4f(1F, 1F, 1F, 1F); TEX_DEBUG.bind(); vb.begin(7, DefaultVertexFormats.POSITION_TEX); for (int j = 0; j < 4; ++j) { double d18 = (double) ((j & 2) - 1) * 0.5; double d19 = (double) ((j + 1 & 2) - 1) * 0.5; double d21 = d18 * rotation - d19 * size; double d22 = d19 * rotation + d18 * size; double d23 = d21 * d12; double d24 = -(d21 * d13); double d25 = d24 * d9 - d22 * d10; double d26 = d22 * d9 + d24 * d10; vb.pos(fx + d25, fy + d23, fz + d26).tex(((j + 1) & 2) >> 1, ((j + 2) & 2) >> 1).endVertex(); } tes.draw(); } TextureHelper.refreshTextureBindState();*/ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); GlStateManager.enableFog(); GlStateManager.popMatrix(); GlStateManager.disableTexture2D(); GlStateManager.color(0.0F, 0.0F, 0.0F); } private void renderSolarEclipseSun(WorldSkyHandler handle) { double xzSize = 30F; float part = ((float) ConstellationSkyHandler.SOLAR_ECLIPSE_HALF_DUR * 2) / 7F; float u = 0; float tick = handle.solarEclipseTick; while (tick - part > 0) { tick -= part; u += 1; } GlStateManager.pushMatrix(); GlStateManager.rotate(-90, 0, 1, 0); Tessellator tessellator = Tessellator.getInstance(); VertexBuffer vb = tessellator.getBuffer(); TEX_SOLAR_ECLIPSE.bind(); vb.begin(7, DefaultVertexFormats.POSITION_TEX); vb.pos(-xzSize, 100.0D, -xzSize).tex(u / 7F, 0.0D).endVertex(); vb.pos(xzSize, 100.0D, -xzSize).tex((u + 1) / 7F, 0.0D).endVertex(); vb.pos(xzSize, 100.0D, xzSize).tex((u + 1) / 7F, 1.0D).endVertex(); vb.pos(-xzSize, 100.0D, xzSize).tex(u / 7F, 1.0D).endVertex(); tessellator.draw(); TextureHelper.refreshTextureBindState(); GlStateManager.popMatrix(); } public static void renderConstellationsWrapped(final World w, final float pticks) { GlStateManager.disableAlpha(); GlStateManager.enableBlend(); RenderHelper.disableStandardItemLighting(); GlStateManager.tryBlendFuncSeparate(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO); GlStateManager.pushMatrix(); float alphaSubRain = 1.0F - Minecraft.getMinecraft().world.getRainStrength(pticks); GlStateManager.color(1.0F, 1.0F, 1.0F, alphaSubRain); GlStateManager.rotate(-90F, 0F, 1F, 0F); GlStateManager.rotate(Minecraft.getMinecraft().world.getCelestialAngle(pticks) * 360.0F, 1.0F, 0.0F, 0.0F); GlStateManager.enableTexture2D(); GlStateManager.depthMask(false); renderConstellations(w, pticks); GlStateManager.depthMask(true); GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); GlStateManager.disableBlend(); GlStateManager.enableAlpha(); GlStateManager.popMatrix(); GlStateManager.color(0, 0, 0); } private static void renderConstellations(final World w, final float partialTicks) { long wTime = w.getWorldTime() % 24000; if (wTime < 12000) return; //Daytime. float rainDim = 1.0F - w.getRainStrength(partialTicks); final float brightness = w.getStarBrightness(partialTicks) * rainDim; if (brightness <= 0.0F) return; final Random flRand = new Random(w.getSeed()); WorldSkyHandler handle = ConstellationSkyHandler.getInstance().getWorldHandler(w); if (handle != null) { ClientConstellationPositionMapping mapping = handle.getConstellationPositionMapping(); if (mapping != null) { Map<IConstellation, ClientConstellationPositionMapping.RenderPosition> renderMap = mapping .getCurrentRenderPositions(); for (Map.Entry<IConstellation, ClientConstellationPositionMapping.RenderPosition> entry : renderMap .entrySet()) { IConstellation c = entry.getKey(); if (!ResearchManager.clientProgress.hasConstellationDiscovered(c.getUnlocalizedName())) continue; RenderConstellation.renderConstellation(c, entry.getValue(), new RenderConstellation.BrightnessFunction() { @Override public float getBrightness() { return RenderConstellation.conCFlicker(w.getWorldTime(), partialTicks, 5 + flRand.nextInt(10)) * (2 * brightness); } }); } } } } private void renderMoon() { double xzSize = 20F; Tessellator tessellator = Tessellator.getInstance(); VertexBuffer vb = tessellator.getBuffer(); Minecraft.getMinecraft().renderEngine.bindTexture(MC_DEF_MOON_PHASES_PNG); int i = Minecraft.getMinecraft().world.getMoonPhase(); int k = i % 4; int i1 = i / 4 % 2; float maxU = (float) (k) / 4.0F; float maxV = (float) (i1) / 2.0F; float minU = (float) (k + 1) / 4.0F; float minV = (float) (i1 + 1) / 2.0F; vb.begin(7, DefaultVertexFormats.POSITION_TEX); vb.pos(-xzSize, -100.0D, xzSize).tex((double) minU, (double) minV).endVertex(); vb.pos(xzSize, -100.0D, xzSize).tex((double) maxU, (double) minV).endVertex(); vb.pos(xzSize, -100.0D, -xzSize).tex((double) maxU, (double) maxV).endVertex(); vb.pos(-xzSize, -100.0D, -xzSize).tex((double) minU, (double) maxV).endVertex(); tessellator.draw(); } private void renderSun() { double xzSize = 30F; Tessellator tessellator = Tessellator.getInstance(); VertexBuffer vb = tessellator.getBuffer(); Minecraft.getMinecraft().renderEngine.bindTexture(MC_DEF_SUN_PNG); vb.begin(7, DefaultVertexFormats.POSITION_TEX); vb.pos(-xzSize, 100.0D, -xzSize).tex(0.0D, 0.0D).endVertex(); vb.pos(xzSize, 100.0D, -xzSize).tex(1.0D, 0.0D).endVertex(); vb.pos(xzSize, 100.0D, xzSize).tex(1.0D, 1.0D).endVertex(); vb.pos(-xzSize, 100.0D, xzSize).tex(0.0D, 1.0D).endVertex(); tessellator.draw(); } private void renderStars(World w, float partialTicks) { float rainDim = 1.0F - w.getRainStrength(partialTicks); float brightness = w.getStarBrightness(partialTicks) * rainDim; TextureHelper.refreshTextureBindState(); if (brightness > 0.0F) { Tessellator tes = Tessellator.getInstance(); VertexBuffer vb = tes.getBuffer(); for (StarDList list : starLists) { if (list.glList > 0) { float sinBr = RenderConstellation.stdFlicker(w.getWorldTime(), partialTicks, list.sinDivisor) - brightness; GlStateManager.color(brightness, brightness, brightness, sinBr < 0 ? 0 : sinBr); list.resource.bind(); vb.begin(7, DefaultVertexFormats.POSITION_TEX); GlStateManager.callList(list.glList); tes.draw(); TextureHelper.refreshTextureBindState(); } } } } private void renderSunsetToBackground(float[] sunsetColors, float partialTicks) { Tessellator tessellator = Tessellator.getInstance(); VertexBuffer vb = tessellator.getBuffer(); GlStateManager.disableTexture2D(); GlStateManager.shadeModel(GL11.GL_SMOOTH); GlStateManager.pushMatrix(); GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F); GlStateManager .rotate(MathHelper.sin(Minecraft.getMinecraft().world.getCelestialAngleRadians(partialTicks)) < 0.0F ? 180.0F : 0.0F, 0.0F, 0.0F, 1.0F); GlStateManager.rotate(90.0F, 0.0F, 0.0F, 1.0F); float f6 = sunsetColors[0]; float f7 = sunsetColors[1]; float f8 = sunsetColors[2]; if (Minecraft.getMinecraft().gameSettings.anaglyph) { float f9 = (f6 * 30.0F + f7 * 59.0F + f8 * 11.0F) / 100.0F; float f10 = (f6 * 30.0F + f7 * 70.0F) / 100.0F; float f11 = (f6 * 30.0F + f8 * 70.0F) / 100.0F; f6 = f9; f7 = f10; f8 = f11; } vb.begin(6, DefaultVertexFormats.POSITION_COLOR); vb.pos(0.0D, 100.0D, 0.0D).color(f6, f7, f8, sunsetColors[3]).endVertex(); //int j = 16; for (int l = 0; l <= 16; ++l) { float f21 = (float) l * (float) Math.PI * 2.0F / 16.0F; float f12 = MathHelper.sin(f21); float f13 = MathHelper.cos(f21); vb.pos((double) (f12 * 120.0F), (double) (f13 * 120.0F), (double) (-f13 * 40.0F * sunsetColors[3])) .color(sunsetColors[0], sunsetColors[1], sunsetColors[2], 0.0F).endVertex(); } tessellator.draw(); GlStateManager.popMatrix(); GlStateManager.shadeModel(GL11.GL_FLAT); } private static class StarDList { private int glList = -1; private BindableResource resource; private int sinDivisor = 1; } }