dan200.billund.client.BillundProxyClient.java Source code

Java tutorial

Introduction

Here is the source code for dan200.billund.client.BillundProxyClient.java

Source

/**
 * This file is part of Billund - http://www.computercraft.info/billund
 * Copyright Daniel Ratcliffe, 2013-2014. See LICENSE for license details.
 */

package dan200.billund.client;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraft.util.Icon;

import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.IItemRenderer;
import net.minecraftforge.client.MinecraftForgeClient;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;

import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.client.TextureFXManager;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.ITickHandler;
import cpw.mods.fml.common.TickType;
import cpw.mods.fml.common.network.Player;
import cpw.mods.fml.common.registry.TickRegistry;
import cpw.mods.fml.relauncher.Side;

import dan200.Billund;
import dan200.billund.shared.BillundProxyCommon;
import dan200.billund.shared.BlockBillund;
import dan200.billund.shared.TileEntityBillund;
import dan200.billund.shared.Stud;
import dan200.billund.shared.StudColour;
import dan200.billund.shared.Brick;
import dan200.billund.shared.ItemBrick;
import dan200.billund.shared.ItemOrderForm;
import dan200.billund.shared.EntityAirDrop;

import org.lwjgl.opengl.GL11;

public class BillundProxyClient extends BillundProxyCommon {
    public BillundProxyClient() {
    }

    // IBillundProxy implementation

    @Override
    public void load() {
        super.load();

        // Setup renderers
        Billund.Blocks.billund.blockRenderID = RenderingRegistry.getNextAvailableRenderId();

        // Setup client forge handlers
        registerForgeHandlers();
    }

    @Override
    public boolean isClient() {
        return true;
    }

    @Override
    public void openOrderFormGUI(EntityPlayer player) {
        GuiScreen gui = new GuiOrderForm(player);
        FMLClientHandler.instance().displayGuiScreen(player, gui);
    }

    private void registerForgeHandlers() {
        ForgeHandlers handlers = new ForgeHandlers();
        MinecraftForge.EVENT_BUS.register(handlers);
        TickRegistry.registerTickHandler(handlers, Side.CLIENT);

        BillundBlockRenderingHandler billundHandler = new BillundBlockRenderingHandler();
        RenderingRegistry.registerBlockHandler(billundHandler);

        BrickRenderer brickHandler = new BrickRenderer();
        MinecraftForgeClient.registerItemRenderer(Billund.Items.brick.itemID, brickHandler);

        RenderingRegistry.registerEntityRenderingHandler(EntityAirDrop.class, new RenderAirDrop());
    }

    public class ForgeHandlers implements ITickHandler {
        public ForgeHandlers() {
        }

        // ITickHandler implementation

        @Override
        public void tickStart(EnumSet<TickType> type, Object... tickData) {
            // See what brick is in front of the player
            float f = ((Float) tickData[0]).floatValue();
            EntityPlayer player = Minecraft.getMinecraft().thePlayer;
            World world = Minecraft.getMinecraft().theWorld;

            Brick hoverBrick = null;
            if (player != null && world != null) {
                BlockBillund.setHoverBrick(ItemBrick.getExistingBrick(world, player, f));
            } else {
                BlockBillund.setHoverBrick(null);
            }
        }

        @Override
        public void tickEnd(EnumSet<TickType> type, Object... tickData) {
        }

        @Override
        public EnumSet<TickType> ticks() {
            return EnumSet.of(TickType.RENDER);
        }

        @Override
        public String getLabel() {
            return "Billund";
        }

        // Forge event responses 

        @ForgeSubscribe
        public void onRenderWorldLast(RenderWorldLastEvent event) {
            // Draw the preview brick
            float f = event.partialTicks;
            EntityPlayer player = Minecraft.getMinecraft().thePlayer;
            World world = Minecraft.getMinecraft().theWorld;
            if (player != null && world != null) {
                ItemStack currentStack = player.inventory.getCurrentItem();
                if (currentStack != null && currentStack.getItem() instanceof ItemBrick) {
                    Brick brick = ItemBrick.getPotentialBrick(currentStack, player.worldObj, player, f);
                    if (brick != null) {
                        // Setup
                        GL11.glPushMatrix();
                        GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ZERO);
                        GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
                        GL11.glDisable(GL11.GL_LIGHTING);

                        translateToWorldCoords(Minecraft.getMinecraft().renderViewEntity, f);
                        renderBrick(world, brick);

                        // Teardown
                        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
                        GL11.glEnable(GL11.GL_LIGHTING);
                        GL11.glPopMatrix();
                    }
                }
            }
        }

        private void translateToWorldCoords(Entity entity, float frame) {
            double interpPosX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * frame;
            double interpPosY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * frame;
            double interpPosZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * frame;
            GL11.glTranslated(-interpPosX, -interpPosY, -interpPosZ);
        }

        // Tick handler
    }

    private static class BillundBlockRenderingHandler implements ISimpleBlockRenderingHandler {
        public BillundBlockRenderingHandler() {
        }

        // ISimpleBlockRenderingHandler implementation

        @Override
        public boolean shouldRender3DInInventory() {
            return false;
        }

        @Override
        public int getRenderId() {
            return Billund.Blocks.billund.blockRenderID;
        }

        @Override
        public boolean renderWorldBlock(IBlockAccess world, int i, int j, int k, Block block, int modelID,
                RenderBlocks renderblocks) {
            if (modelID == getRenderId()) {
                TileEntity entity = world.getBlockTileEntity(i, j, k);
                if (entity != null && entity instanceof TileEntityBillund) {
                    TileEntityBillund billund = (TileEntityBillund) entity;
                    for (int x = 0; x < TileEntityBillund.STUDS_PER_ROW; ++x) {
                        for (int y = 0; y < TileEntityBillund.STUDS_PER_COLUMN; ++y) {
                            for (int z = 0; z < TileEntityBillund.STUDS_PER_ROW; ++z) {
                                Stud stud = billund.getStudLocal(x, y, z);
                                if (stud != null) {
                                    int sx = i * TileEntityBillund.STUDS_PER_ROW + x;
                                    int sy = j * TileEntityBillund.STUDS_PER_COLUMN + y;
                                    int sz = k * TileEntityBillund.STUDS_PER_ROW + z;
                                    if (stud.XOrigin == sx && stud.YOrigin == sy && stud.ZOrigin == sz) {
                                        // Draw the brick         
                                        int brightness = block.getMixedBrightnessForBlock(world, i, j, k);
                                        renderBrick(world, brightness, stud.Colour, sx, sy, sz, stud.BrickWidth,
                                                stud.BrickHeight, stud.BrickDepth);
                                    }
                                }
                            }
                        }
                    }
                }
                return true;
            }
            return false;
        }

        @Override
        public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderblocks) {
        }
    }

    public static class BrickRenderer implements IItemRenderer {
        public void BrickRenderer() {
        }

        // IItemRenderer implementation
        @Override
        public boolean handleRenderType(ItemStack item, IItemRenderer.ItemRenderType type) {
            switch (type) {
            case ENTITY:
            case EQUIPPED:
            case EQUIPPED_FIRST_PERSON:
            case INVENTORY: {
                return true;
            }
            case FIRST_PERSON_MAP:
            default: {
                return false;
            }
            }
        }

        @Override
        public boolean shouldUseRenderHelper(IItemRenderer.ItemRenderType type, ItemStack item,
                IItemRenderer.ItemRendererHelper helper) {
            switch (helper) {
            case ENTITY_ROTATION:
            case ENTITY_BOBBING:
            case EQUIPPED_BLOCK:
            case BLOCK_3D:
            case INVENTORY_BLOCK: {
                return true;
            }
            default: {
                return false;
            }
            }
        }

        @Override
        public void renderItem(ItemRenderType type, ItemStack item, Object[] data) {
            int damage = item.getItemDamage();
            switch (type) {
            case ENTITY: {
                renderBrick(item, false, true);
                break;
            }
            case EQUIPPED: {
                GL11.glPushMatrix();
                GL11.glTranslatef(0.6f, 0.6f, 0.6f);
                renderBrick(item, false, true);
                GL11.glPopMatrix();
                break;
            }
            case INVENTORY: {
                GL11.glPushMatrix();
                GL11.glTranslatef(0.5f, 0.5f, 0.5f);
                renderBrick(item, true, true);
                GL11.glPopMatrix();
                break;
            }
            case EQUIPPED_FIRST_PERSON:
            default: {
                break;
            }
            }
        }
    }

    public static void renderBrick(ItemStack brick, boolean scale, boolean center) {
        Tessellator tessellator = Tessellator.instance;
        int brightness = 15;

        int colour = ItemBrick.getColour(brick);
        int width = ItemBrick.getWidth(brick);
        int height = ItemBrick.getHeight(brick);
        int depth = ItemBrick.getDepth(brick);

        // Setup      
        GL11.glPushMatrix();

        if (scale) {
            float scaleValue = ((float) TileEntityBillund.LAYERS_PER_BLOCK)
                    / Math.max(2.0f, (float) Math.max(width, depth) - 0.5f);
            GL11.glScalef(scaleValue, scaleValue, scaleValue);
        }
        if (center) {
            GL11.glTranslatef(-0.5f * ((float) width / (float) TileEntityBillund.ROWS_PER_BLOCK),
                    -0.5f * ((float) height / (float) TileEntityBillund.LAYERS_PER_BLOCK),
                    -0.5f * ((float) depth / (float) TileEntityBillund.ROWS_PER_BLOCK));
        }

        GL11.glDisable(GL11.GL_LIGHTING);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

        Minecraft mc = Minecraft.getMinecraft();
        mc.getTextureManager().bindTexture(mc.getTextureManager().getResourceLocation(0)); // bind the terrain texture

        tessellator.startDrawingQuads();
        tessellator.setNormal(0.0f, -1.0f, 0.0f);
        renderBrick(null, brightness, colour, 0, 0, 0, width, height, depth);
        tessellator.draw();

        // Teardown
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glEnable(GL11.GL_LIGHTING);
        GL11.glPopMatrix();
    }

    public static void renderBrick(IBlockAccess world, Brick brick) {
        int localX = (brick.XOrigin % TileEntityBillund.ROWS_PER_BLOCK + TileEntityBillund.ROWS_PER_BLOCK)
                % TileEntityBillund.ROWS_PER_BLOCK;
        int localY = (brick.YOrigin % TileEntityBillund.LAYERS_PER_BLOCK + TileEntityBillund.LAYERS_PER_BLOCK)
                % TileEntityBillund.LAYERS_PER_BLOCK;
        int localZ = (brick.ZOrigin % TileEntityBillund.ROWS_PER_BLOCK + TileEntityBillund.ROWS_PER_BLOCK)
                % TileEntityBillund.ROWS_PER_BLOCK;
        int blockX = (brick.XOrigin - localX) / TileEntityBillund.ROWS_PER_BLOCK;
        int blockY = (brick.YOrigin - localY) / TileEntityBillund.LAYERS_PER_BLOCK;
        int blockZ = (brick.ZOrigin - localZ) / TileEntityBillund.ROWS_PER_BLOCK;

        Tessellator tessellator = Tessellator.instance;
        int brightness = Billund.Blocks.billund.getMixedBrightnessForBlock(world, blockX, blockY, blockZ);

        Minecraft mc = Minecraft.getMinecraft();
        mc.getTextureManager().bindTexture(mc.getTextureManager().getResourceLocation(0)); // bind the terrain texture

        tessellator.startDrawingQuads();
        tessellator.setNormal(0.0f, -1.0f, 0.0f);
        renderBrick(world, brightness, brick.Colour, brick.XOrigin, brick.YOrigin, brick.ZOrigin, brick.Width,
                brick.Height, brick.Depth);
        tessellator.draw();
    }

    private static void renderBrick(IBlockAccess world, int brightness, int colour, int sx, int sy, int sz,
            int width, int height, int depth) {
        // Draw the brick
        Icon icon = BlockBillund.getIcon(colour);
        if (world != null) {
            Tessellator tessellator = Tessellator.instance;
            tessellator.setBrightness(brightness);
        }

        float pixel = 1.0f / 96.0f;
        float xBlockSize = (float) TileEntityBillund.STUDS_PER_ROW;
        float yBlockSize = (float) TileEntityBillund.STUDS_PER_COLUMN;
        float zBlockSize = (float) TileEntityBillund.STUDS_PER_ROW;

        float startX = (float) sx / xBlockSize;
        float startY = (float) sy / yBlockSize;
        float startZ = (float) sz / zBlockSize;
        float endX = startX + ((float) width / xBlockSize);
        float endY = startY + ((float) height / yBlockSize);
        float endZ = startZ + ((float) depth / zBlockSize);
        renderBox(icon, brightness, startX, startY, startZ, endX, endY, endZ, true);

        // Draw the studs
        int sny = sy + height;
        startY = (float) sny / yBlockSize;
        endY = startY + (0.1666f / yBlockSize);
        for (int snx = sx; snx < sx + width; ++snx) {
            startX = (float) snx / xBlockSize;
            endX = startX + (1.0f / xBlockSize);
            for (int snz = sz; snz < sz + depth; ++snz) {
                boolean drawStud;
                if (world != null) {
                    Stud above = TileEntityBillund.getStud(world, snx, sny, snz);
                    drawStud = (above == null) || (above.Colour == StudColour.TranslucentWall);
                } else {
                    drawStud = true;
                }

                if (drawStud) {
                    startZ = (float) snz / zBlockSize;
                    endZ = startZ + (1.0f / zBlockSize);
                    renderBox(icon, brightness, startX + pixel * 2.0f, startY, startZ + pixel * 4.0f,
                            startX + pixel * 4.0f, endY, endZ - pixel * 4.0f, false);
                    renderBox(icon, brightness, startX + pixel * 4.0f, startY, startZ + pixel * 2.0f,
                            endX - pixel * 4.0f, endY, endZ - pixel * 2.0f, false);
                    renderBox(icon, brightness, endX - pixel * 4.0f, startY, startZ + pixel * 4.0f,
                            endX - pixel * 2.0f, endY, endZ - pixel * 4.0f, false);
                }
            }
        }
    }

    private static void renderBox(Icon icon, int brightness, float startX, float startY, float startZ, float endX,
            float endY, float endZ, boolean bottom) {
        // X faces
        renderFaceXNeg(icon, startX, startY, startZ, endX, endY, endZ);
        renderFaceXPos(icon, startX, startY, startZ, endX, endY, endZ);

        // Y faces
        if (bottom) {
            renderFaceYNeg(icon, startX, startY, startZ, endX, endY, endZ);
        }
        renderFaceYPos(icon, startX, startY, startZ, endX, endY, endZ);

        // Z faces
        renderFaceZNeg(icon, startX, startY, startZ, endX, endY, endZ);
        renderFaceZPos(icon, startX, startY, startZ, endX, endY, endZ);
    }

    private static void renderFaceXNeg(Icon icon, float startX, float startY, float startZ, float endX, float endY,
            float endZ) {
        Tessellator tessellator = Tessellator.instance;
        tessellator.setColorOpaque_F(0.6f, 0.6f, 0.6f);
        tessellator.addVertexWithUV(startX, endY, endZ, icon.getMinU(), icon.getMaxV());
        tessellator.addVertexWithUV(startX, endY, startZ, icon.getMinU(), icon.getMinV());
        tessellator.addVertexWithUV(startX, startY, startZ, icon.getMaxU(), icon.getMinV());
        tessellator.addVertexWithUV(startX, startY, endZ, icon.getMaxU(), icon.getMaxV());
    }

    private static void renderFaceXPos(Icon icon, float startX, float startY, float startZ, float endX, float endY,
            float endZ) {
        Tessellator tessellator = Tessellator.instance;
        tessellator.setColorOpaque_F(0.6f, 0.6f, 0.6f);
        tessellator.addVertexWithUV(endX, startY, endZ, icon.getMaxU(), icon.getMaxV());
        tessellator.addVertexWithUV(endX, startY, startZ, icon.getMaxU(), icon.getMinV());
        tessellator.addVertexWithUV(endX, endY, startZ, icon.getMinU(), icon.getMinV());
        tessellator.addVertexWithUV(endX, endY, endZ, icon.getMinU(), icon.getMaxV());
    }

    private static void renderFaceYNeg(Icon icon, float startX, float startY, float startZ, float endX, float endY,
            float endZ) {
        Tessellator tessellator = Tessellator.instance;
        tessellator.setColorOpaque_F(0.5f, 0.5f, 0.5f);
        tessellator.addVertexWithUV(startX, startY, endZ, icon.getMinU(), icon.getMaxV());
        tessellator.addVertexWithUV(startX, startY, startZ, icon.getMinU(), icon.getMinV());
        tessellator.addVertexWithUV(endX, startY, startZ, icon.getMaxU(), icon.getMinV());
        tessellator.addVertexWithUV(endX, startY, endZ, icon.getMaxU(), icon.getMaxV());
    }

    private static void renderFaceYPos(Icon icon, float startX, float startY, float startZ, float endX, float endY,
            float endZ) {
        Tessellator tessellator = Tessellator.instance;
        tessellator.setColorOpaque_F(1.0f, 1.0f, 1.0f);
        tessellator.addVertexWithUV(endX, endY, endZ, icon.getMaxU(), icon.getMaxV());
        tessellator.addVertexWithUV(endX, endY, startZ, icon.getMaxU(), icon.getMinV());
        tessellator.addVertexWithUV(startX, endY, startZ, icon.getMinU(), icon.getMinV());
        tessellator.addVertexWithUV(startX, endY, endZ, icon.getMinU(), icon.getMaxV());
    }

    private static void renderFaceZNeg(Icon icon, float startX, float startY, float startZ, float endX, float endY,
            float endZ) {
        Tessellator tessellator = Tessellator.instance;
        tessellator.setColorOpaque_F(0.8f, 0.8f, 0.8f);
        tessellator.addVertexWithUV(startX, endY, startZ, icon.getMaxU(), icon.getMaxV());
        tessellator.addVertexWithUV(endX, endY, startZ, icon.getMaxU(), icon.getMinV());
        tessellator.addVertexWithUV(endX, startY, startZ, icon.getMinU(), icon.getMinV());
        tessellator.addVertexWithUV(startX, startY, startZ, icon.getMinU(), icon.getMaxV());
    }

    private static void renderFaceZPos(Icon icon, float startX, float startY, float startZ, float endX, float endY,
            float endZ) {
        Tessellator tessellator = Tessellator.instance;
        tessellator.setColorOpaque_F(0.8f, 0.8f, 0.8f);
        tessellator.addVertexWithUV(startX, startY, endZ, icon.getMinU(), icon.getMaxV());
        tessellator.addVertexWithUV(endX, startY, endZ, icon.getMinU(), icon.getMinV());
        tessellator.addVertexWithUV(endX, endY, endZ, icon.getMaxU(), icon.getMinV());
        tessellator.addVertexWithUV(startX, endY, endZ, icon.getMaxU(), icon.getMaxV());
    }
}