hellfirepvp.astralsorcery.client.util.RenderConstellation.java Source code

Java tutorial

Introduction

Here is the source code for hellfirepvp.astralsorcery.client.util.RenderConstellation.java

Source

/*******************************************************************************
 * 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.util;

import hellfirepvp.astralsorcery.client.sky.RenderAstralSkybox;
import hellfirepvp.astralsorcery.client.util.mappings.ClientConstellationPositionMapping;
import hellfirepvp.astralsorcery.common.constellation.IConstellation;
import hellfirepvp.astralsorcery.common.constellation.star.StarConnection;
import hellfirepvp.astralsorcery.common.constellation.star.StarLocation;
import hellfirepvp.astralsorcery.common.util.data.Vector3;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;

/**
 * This class is part of the Astral Sorcery Mod
 * The complete source code for this mod can be found on github.
 * Class: RenderConstellation
 * Created by HellFirePvP
 * Date: 07.05.2016 / 17:38
 */
public class RenderConstellation {

    //TODO sometimes on certain sky positions, completely vertical or completely horizontal lines go invisible due to the crossproduct returning a NAN vec

    @SideOnly(Side.CLIENT)
    public static void renderConstellation(IConstellation c,
            ClientConstellationPositionMapping.RenderPosition renderPos, BrightnessFunction brFunc) {
        Tessellator tessellator = Tessellator.getInstance();
        VertexBuffer vb = tessellator.getBuffer();

        Vector3 renderOffset = renderPos.offset;
        Color rC = c.getRenderColor();

        //Now we build from the exact UV vectors a 31x31 grid and render the stars & connections.
        Vector3 dirU = renderPos.incU.clone().subtract(renderOffset).divide(31);
        Vector3 dirV = renderPos.incV.clone().subtract(renderOffset).divide(31);
        double uLength = dirU.length();
        RenderAstralSkybox.TEX_CONNECTION.bind();
        for (int j = 0; j < 2; j++) {
            for (StarConnection con : c.getStarConnections()) {
                vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
                float brightness = brFunc.getBrightness();
                GL11.glColor4f(((float) rC.getRed()) / 255F, ((float) rC.getGreen()) / 255F,
                        ((float) rC.getBlue()) / 255F, brightness < 0 ? 0 : brightness);
                Vector3 vecA = renderOffset.clone().add(dirU.clone().multiply(con.from.x + 1))
                        .add(dirV.clone().multiply(con.from.y + 1));
                Vector3 vecB = renderOffset.clone().add(dirU.clone().multiply(con.to.x + 1))
                        .add(dirV.clone().multiply(con.to.y + 1));
                Vector3 vecCV = vecB.subtract(vecA);
                Vector3 oPane = dirV.clone().crossProduct(vecCV);
                Vector3 vecAD = oPane.clone().crossProduct(vecCV).normalize().multiply(uLength);
                Vector3 offset00 = vecA.subtract(vecAD.clone().multiply(j == 0 ? 1 : -1));
                Vector3 vecU = vecAD.clone().multiply(j == 0 ? 2 : -2);

                for (int i = 0; i < 4; i++) {
                    Vector3 pos = offset00.clone().add(vecU.clone().multiply(((i + 1) & 2) >> 1))
                            .add(vecCV.clone().multiply(((i + 2) & 2) >> 1));
                    vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(((i + 2) & 2) >> 1, ((i + 3) & 2) >> 1)
                            .endVertex();
                }
                tessellator.draw();
            }
        }

        RenderAstralSkybox.TEX_STAR_1.bind();
        for (StarLocation star : c.getStars()) {
            vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
            float brightness = brFunc.getBrightness();
            GL11.glColor4f(((float) rC.getRed()) / 255F, ((float) rC.getGreen()) / 255F,
                    ((float) rC.getBlue()) / 255F, brightness < 0 ? 0 : brightness);
            int x = star.x;
            int y = star.y;
            Vector3 ofStar = renderOffset.clone().add(dirU.clone().multiply(x)).add(dirV.clone().multiply(y));
            for (int i = 0; i < 4; i++) {
                int u = ((i + 1) & 2) >> 1;
                int v = ((i + 2) & 2) >> 1;
                Vector3 pos = ofStar.clone().add(dirU.clone().multiply(u << 1)).add(dirV.clone().multiply(v << 1));
                vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(u, v).endVertex();
            }
            tessellator.draw();
        }
    }

    //non-rotating, builds into x/z space
    public static void renderConstellationIntoWorldFlat(IConstellation c, Color rC, Vector3 offsetPos, double scale,
            double lineBreadth, float br) {
        GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
        GL11.glPushMatrix();
        Tessellator tes = Tessellator.getInstance();
        VertexBuffer vb = tes.getBuffer();

        double s = 1D / 31D * scale;

        GL11.glTranslated(-15.5D * s, 0, -15.5D * s);

        GL11.glDisable(GL11.GL_CULL_FACE);
        GL11.glDisable(GL11.GL_ALPHA_TEST);
        GL11.glEnable(GL11.GL_BLEND);
        Blending.DEFAULT.apply();

        float fRed = ((float) rC.getRed()) / 255F;
        float fGreen = ((float) rC.getGreen()) / 255F;
        float fBlue = ((float) rC.getBlue()) / 255F;

        RenderAstralSkybox.TEX_CONNECTION.bind();
        vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
        for (StarConnection sc : c.getStarConnections()) {
            float brightness = br;
            brightness *= 0.8;
            float fAlpha = brightness < 0 ? 0 : brightness;

            Vector3 offset = offsetPos.clone().addX(sc.from.x * s).addZ(sc.from.y * s);
            Vector3 dirU = new Vector3(sc.to.x, 0, sc.to.y).subtract(sc.from.x, 0, sc.from.y).multiply(s);
            Vector3 dirV = dirU.clone().crossProduct(new Vector3(0, 1, 0)).setY(0).normalize()
                    .multiply(lineBreadth * s);
            Vector3 offsetRender = offset.subtract(dirV.clone().divide(2));

            Vector3 pos = offsetRender.clone().add(dirU.clone().multiply(0)).add(dirV.clone().multiply(1));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(1, 0).color(fRed, fGreen, fBlue, fAlpha).endVertex();
            pos = offsetRender.clone().add(dirU.clone().multiply(1)).add(dirV.clone().multiply(1));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(0, 0).color(fRed, fGreen, fBlue, fAlpha).endVertex();
            pos = offsetRender.clone().add(dirU.clone().multiply(1)).add(dirV.clone().multiply(0));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(0, 1).color(fRed, fGreen, fBlue, fAlpha).endVertex();
            pos = offsetRender.clone().add(dirU.clone().multiply(0)).add(dirV.clone().multiply(0));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(1, 1).color(fRed, fGreen, fBlue, fAlpha).endVertex();

        }
        tes.draw();

        RenderAstralSkybox.TEX_STAR_1.bind();
        vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
        for (StarLocation sl : c.getStars()) {
            float fAlpha = br < 0 ? 0 : br;

            Vector3 offsetRender = offsetPos.clone().add(sl.x * s - s, 0.005, sl.y * s - s);
            Vector3 dirU = new Vector3(s * 2, 0, 0);
            Vector3 dirV = new Vector3(0, 0, s * 2);

            Vector3 pos = offsetRender.clone().add(dirU.clone().multiply(0)).add(dirV.clone().multiply(1));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(1, 0).color(fRed, fGreen, fBlue, fAlpha).endVertex();
            pos = offsetRender.clone().add(dirU.clone().multiply(1)).add(dirV.clone().multiply(1));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(0, 0).color(fRed, fGreen, fBlue, fAlpha).endVertex();
            pos = offsetRender.clone().add(dirU.clone().multiply(1)).add(dirV.clone().multiply(0));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(0, 1).color(fRed, fGreen, fBlue, fAlpha).endVertex();
            pos = offsetRender.clone().add(dirU.clone().multiply(0)).add(dirV.clone().multiply(0));
            vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(1, 1).color(fRed, fGreen, fBlue, fAlpha).endVertex();
        }
        tes.draw();

        GL11.glPopMatrix();
        GL11.glPopAttrib();
    }

    public static void renderConstellationIntoWorld(IConstellation c, Color rC, Vector3 offsetPos,
            double lineBreadth, BrightnessFunction func) {
        GL11.glPushMatrix();
        Tessellator tes = Tessellator.getInstance();
        VertexBuffer vb = tes.getBuffer();

        Vector3 dirV = new Vector3(0, 0, 1);
        Vector3 dirU = new Vector3(1, 0, 0);

        RenderAstralSkybox.TEX_CONNECTION.bind();
        for (int j = 0; j < 2; j++) {
            for (StarConnection con : c.getStarConnections()) {
                vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
                float brightness = func.getBrightness();
                GL11.glColor4f(((float) rC.getRed()) / 255F, ((float) rC.getGreen()) / 255F,
                        ((float) rC.getBlue()) / 255F, brightness < 0 ? 0 : brightness);

                Vector3 vecA = offsetPos.clone().add(dirU.clone().multiply(con.from.x + 1))
                        .add(dirV.clone().multiply(con.from.y + 1));
                Vector3 vecB = offsetPos.clone().add(dirU.clone().multiply(con.to.x + 1))
                        .add(dirV.clone().multiply(con.to.y + 1));
                Vector3 vecCV = vecB.subtract(vecA);
                Vector3 oPane = dirV.clone().crossProduct(vecCV);
                Vector3 vecAD = oPane.clone().crossProduct(vecCV).normalize().multiply(lineBreadth);
                Vector3 offset00 = vecA.subtract(vecAD.clone().multiply(j == 0 ? 1 : -1));
                Vector3 vecU = vecAD.clone().multiply(j == 0 ? 2 : -2);

                for (int i = 0; i < 4; i++) {
                    Vector3 pos = offset00.clone().add(vecU.clone().multiply(((i + 1) & 2) >> 1))
                            .add(vecCV.clone().multiply(((i + 2) & 2) >> 1));
                    vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(((i + 2) & 2) >> 1, ((i + 3) & 2) >> 1)
                            .endVertex();
                }
                tes.draw();
            }
        }

        RenderAstralSkybox.TEX_STAR_1.bind();
        for (StarLocation star : c.getStars()) {
            vb.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
            float brightness = func.getBrightness();
            GL11.glColor4f(((float) rC.getRed()) / 255F, ((float) rC.getGreen()) / 255F,
                    ((float) rC.getBlue()) / 255F, brightness < 0 ? 0 : brightness);
            int x = star.x;
            int y = star.y;
            Vector3 ofStar = offsetPos.clone().add(dirU.clone().multiply(x)).add(dirV.clone().multiply(y));
            for (int i = 0; i < 4; i++) {
                int u = ((i + 1) & 2) >> 1;
                int v = ((i + 2) & 2) >> 1;
                Vector3 pos = ofStar.clone().add(dirU.clone().multiply(u << 1)).add(dirV.clone().multiply(v << 1));
                vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(u, v).endVertex();
            }
            tes.draw();
        }
        GL11.glPopMatrix();
    }

    /*public static Map<StarLocation, Rectangle> renderConstellationIntoGUI(IConstellation c, int offsetX, int offsetY, float zLevel, int width, int height, double linebreadth, BrightnessFunction func, boolean isKnown, boolean applyStarBrightness) {
    return renderConstellationIntoGUI(c.queryTier(), c, offsetX, offsetY, zLevel, width, height, linebreadth, func, isKnown, applyStarBrightness);
    }*/

    public static Map<StarLocation, Rectangle> renderConstellationIntoGUI(IConstellation c, int offsetX,
            int offsetY, float zLevel, int width, int height, double linebreadth, BrightnessFunction func,
            boolean isKnown, boolean applyStarBrightness) {
        return renderConstellationIntoGUI(c.getRenderColor(), c, offsetX, offsetY, zLevel, width, height,
                linebreadth, func, isKnown, applyStarBrightness);
    }

    public static Map<StarLocation, Rectangle> renderConstellationIntoGUI(Color col, IConstellation c, int offsetX,
            int offsetY, float zLevel, int width, int height, double linebreadth, BrightnessFunction func,
            boolean isKnown, boolean applyStarBrightness) {
        Tessellator tes = Tessellator.getInstance();
        VertexBuffer vb = tes.getBuffer();
        double ulength = ((double) width) / 31;
        double vlength = ((double) height) / 31;

        Vector3 offsetVec = new Vector3(offsetX, offsetY, zLevel);
        RenderAstralSkybox.TEX_CONNECTION.bind();
        if (isKnown) {
            for (int j = 0; j < 2; j++) {
                for (StarConnection sc : c.getStarConnections()) {
                    float brightness = func.getBrightness();
                    if (applyStarBrightness) {
                        float starBr = Minecraft.getMinecraft().world.getStarBrightness(1.0F);
                        if (starBr <= 0.23F) {
                            continue;
                        }
                        brightness *= (starBr * 2);
                    }
                    vb.begin(7, DefaultVertexFormats.POSITION_TEX);
                    GL11.glColor4f(((float) col.getRed()) / 255F, ((float) col.getGreen()) / 255F,
                            ((float) col.getBlue()) / 255F, brightness < 0 ? 0 : brightness);
                    Vector3 fromStar = new Vector3(offsetVec.getX() + sc.from.x * ulength,
                            offsetVec.getY() + sc.from.y * vlength, offsetVec.getZ());
                    Vector3 toStar = new Vector3(offsetVec.getX() + sc.to.x * ulength,
                            offsetVec.getY() + sc.to.y * vlength, offsetVec.getZ());

                    Vector3 dir = toStar.clone().subtract(fromStar);
                    Vector3 degLot = dir.clone().crossProduct(new Vector3(0, 0, 1)).normalize()
                            .multiply(linebreadth);//.multiply(j == 0 ? 1 : -1);

                    Vector3 vec00 = fromStar.clone().add(degLot);
                    Vector3 vecV = degLot.clone().multiply(-2);

                    for (int i = 0; i < 4; i++) {
                        int u = ((i + 1) & 2) >> 1;
                        int v = ((i + 2) & 2) >> 1;

                        Vector3 pos = vec00.clone().add(dir.clone().multiply(u)).add(vecV.clone().multiply(v));
                        vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(u, v).endVertex();
                    }

                    tes.draw();
                }
            }
        }

        Map<StarLocation, Rectangle> starRectangles = new HashMap<>();

        RenderAstralSkybox.TEX_STAR_1.bind();
        for (StarLocation sl : c.getStars()) {

            float brightness = func.getBrightness();
            if (applyStarBrightness) {
                float starBr = Minecraft.getMinecraft().world.getStarBrightness(1.0F);
                if (starBr <= 0.23F) {
                    continue;
                }
                brightness *= (starBr * 2);
            }

            vb.begin(7, DefaultVertexFormats.POSITION_TEX);
            if (isKnown) {
                GL11.glColor4f(((float) col.getRed()) / 255F, ((float) col.getGreen()) / 255F,
                        ((float) col.getBlue()) / 255F, brightness);
            } else {
                GL11.glColor4f(brightness, brightness, brightness, brightness < 0 ? 0 : brightness);
            }
            int starX = sl.x;
            int starY = sl.y;

            Vector3 starVec = offsetVec.clone().addX(starX * ulength - ulength).addY(starY * vlength - vlength);
            Point upperLeft = new Point(starVec.getBlockX(), starVec.getBlockY());

            for (int i = 0; i < 4; i++) {
                int u = ((i + 1) & 2) >> 1;
                int v = ((i + 2) & 2) >> 1;

                Vector3 pos = starVec.clone().addX(ulength * u * 2).addY(vlength * v * 2);
                vb.pos(pos.getX(), pos.getY(), pos.getZ()).tex(u, v).endVertex();
            }

            starRectangles.put(sl,
                    new Rectangle(upperLeft.x, upperLeft.y, (int) (ulength * 2), (int) (vlength * 2)));
            tes.draw();
        }

        GL11.glColor4f(1F, 1F, 1F, 1F);
        return starRectangles;
    }

    public static float stdFlicker(long wtime, float partialTicks, int divisor) {
        return flickerSin(wtime, partialTicks, divisor, 2F, 0.5F);
    }

    public static float conSFlicker(long wtime, float partialTicks, int divisor) {
        return flickerSin(wtime, partialTicks, divisor, 4F, 0.575F);
    }

    public static float conCFlicker(long wtime, float partialTicks, int divisor) {
        return flickerSin(wtime, partialTicks, divisor, 4F, 0.375F);
    }

    public static float flickerSin(long wtime, float partialTicks, int divisor, float div, float move) {
        double rad = (((double) wtime) + partialTicks) / divisor;
        float sin = MathHelper.sin((float) rad);
        return (sin / div) + move;
    }

    public static abstract class BrightnessFunction {

        public abstract float getBrightness();

    }

}