    001package net.minecraftforge.client;
    002
    003import java.util.HashMap;
    004import java.util.Random;
    005import java.util.TreeSet;
    006
    007import org.lwjgl.opengl.GL11;
    008import org.lwjgl.opengl.GL12;
    009
    010import cpw.mods.fml.client.FMLClientHandler;
    011
    012import net.minecraft.client.Minecraft;
    013import net.minecraft.block.Block;
    014import net.minecraft.entity.item.EntityItem;
    015import net.minecraft.entity.EntityLiving;
    016import net.minecraft.entity.player.EntityPlayer;
    017import net.minecraft.client.texturepacks.ITexturePack;
    018import net.minecraft.item.Item;
    019import net.minecraft.item.ItemBlock;
    020import net.minecraft.item.ItemStack;
    021import net.minecraft.util.MathHelper;
    022import net.minecraft.util.MovingObjectPosition;
    023import net.minecraft.client.renderer.RenderBlocks;
    024import net.minecraft.client.renderer.RenderEngine;
    025import net.minecraft.client.renderer.RenderGlobal;
    026import net.minecraft.client.renderer.Tessellator;
    027import net.minecraft.client.renderer.entity.RenderItem;
    028import net.minecraftforge.client.event.DrawBlockHighlightEvent;
    029import net.minecraftforge.client.event.RenderWorldLastEvent;
    030import net.minecraftforge.client.event.TextureLoadEvent;
    031import net.minecraftforge.common.IArmorTextureProvider;
    032import net.minecraftforge.common.MinecraftForge;
    033import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
    034import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
    035
    036public class ForgeHooksClient
    037{
    038    private static class TesKey implements Comparable<TesKey>
    039    {
    040        public final int texture, subid;
    041        public TesKey(int textureID, int subID)
    042        {
    043            texture = textureID;
    044            subid = subID;
    045        }
    046
    047        public int compareTo(TesKey key)
    048        {
    049            if (subid == key.subid)
    050            {
    051                return texture - key.texture;
    052            }
    053            return subid - key.subid;
    054        }
    055
    056        public boolean equals(Object obj)
    057        {
    058            return compareTo((TesKey)obj) == 0;
    059        }
    060
    061        public int hashCode()
    062        {
    063            return texture + 31 * subid;
    064        }
    065    }
    066
    067    public static HashMap<TesKey, Tessellator> tessellators = new HashMap<TesKey, Tessellator>();
    068    public static HashMap<String, Integer> textures = new HashMap<String, Integer>();
    069    public static TreeSet<TesKey> renderTextures = new TreeSet<TesKey>();
    070    public static Tessellator defaultTessellator = null;
    071    public static boolean inWorld = false;
    072    public static HashMap<TesKey, IRenderContextHandler> renderHandlers = new HashMap<TesKey, IRenderContextHandler>();
    073    public static IRenderContextHandler unbindContext = null;
    074
    075    protected static void registerRenderContextHandler(String texture, int subID, IRenderContextHandler handler)
    076    {
    077        Integer texID = textures.get(texture);
    078        if (texID == null)
    079        {
    080            texID = engine().getTexture(texture);
    081            textures.put(texture, texID);
    082        }
    083        renderHandlers.put(new TesKey(texID, subID), handler);
    084    }
    085
    086    static RenderEngine engine()
    087    {
    088        return FMLClientHandler.instance().getClient().renderEngine;
    089    }
    090    public static void bindTexture(String texture, int subID)
    091    {
    092        Integer texID = textures.get(texture);
    093        if (texID == null)
    094        {
    095            texID = engine().getTexture(texture);
    096            textures.put(texture, texID);
    097        }
    098        if (!inWorld)
    099        {
    100            if (unbindContext != null)
    101            {
    102                unbindContext.afterRenderContext();
    103                unbindContext = null;
    104            }
    105            if (Tessellator.instance.isDrawing)
    106            {
    107                int mode = Tessellator.instance.drawMode;
    108                Tessellator.instance.draw();
    109                Tessellator.instance.startDrawing(mode);
    110            }
    111            GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID);
    112            unbindContext = renderHandlers.get(new TesKey(texID, subID));
    113            if (unbindContext != null)
    114            {
    115                unbindContext.beforeRenderContext();
    116            }
    117            return;
    118        }
    119        bindTessellator(texID, subID);
    120    }
    121
    122    public static void unbindTexture()
    123    {
    124        if (inWorld)
    125        {
    126            Tessellator.instance = defaultTessellator;
    127        }
    128        else
    129        {
    130            if (Tessellator.instance.isDrawing)
    131            {
    132                int mode = Tessellator.instance.drawMode;
    133                Tessellator.instance.draw();
    134                if (unbindContext != null)
    135                {
    136                    unbindContext.afterRenderContext();
    137                    unbindContext = null;
    138                }
    139                Tessellator.instance.startDrawing(mode);
    140            }
    141            GL11.glBindTexture(GL11.GL_TEXTURE_2D, engine().getTexture("/terrain.png"));
    142            return;
    143        }
    144    }
    145
    146    protected static void bindTessellator(int texture, int subID)
    147    {
    148        TesKey key = new TesKey(texture, subID);
    149        Tessellator tess = tessellators.get(key);
    150
    151        if (tess == null)
    152        {
    153            tess = new Tessellator();
    154            tess.textureID = texture;
    155            tessellators.put(key, tess);
    156        }
    157
    158        if (inWorld && !renderTextures.contains(key))
    159        {
    160            renderTextures.add(key);
    161            tess.startDrawingQuads();
    162            tess.setTranslation(defaultTessellator.xOffset, defaultTessellator.yOffset, defaultTessellator.zOffset);
    163        }
    164
    165        Tessellator.instance = tess;
    166    }
    167
    168    static int renderPass = -1;
    169    public static void beforeRenderPass(int pass)
    170    {
    171        renderPass = pass;
    172        defaultTessellator = Tessellator.instance;
    173        Tessellator.renderingWorldRenderer = true;
    174        GL11.glBindTexture(GL11.GL_TEXTURE_2D, engine().getTexture("/terrain.png"));
    175        renderTextures.clear();
    176        inWorld = true;
    177    }
    178
    179    public static void afterRenderPass(int pass)
    180    {
    181        renderPass = -1;
    182        inWorld = false;
    183        for (TesKey info : renderTextures)
    184        {
    185            IRenderContextHandler handler = renderHandlers.get(info);
    186            GL11.glBindTexture(GL11.GL_TEXTURE_2D, info.texture);
    187            Tessellator tess = tessellators.get(info);
    188            if (handler == null)
    189            {
    190                tess.draw();
    191            }
    192            else
    193            {
    194                Tessellator.instance = tess;
    195                handler.beforeRenderContext();
    196                tess.draw();
    197                handler.afterRenderContext();
    198            }
    199        }
    200        GL11.glBindTexture(GL11.GL_TEXTURE_2D, engine().getTexture("/terrain.png"));
    201        Tessellator.renderingWorldRenderer = false;
    202        Tessellator.instance = defaultTessellator;
    203    }
    204
    205    public static void beforeBlockRender(Block block, RenderBlocks render)
    206    {
    207        if (!block.isDefaultTexture && render.overrideBlockTexture == -1)
    208        {
    209            bindTexture(block.getTextureFile(), 0);
    210        }
    211    }
    212
    213    public static void afterBlockRender(Block block, RenderBlocks render)
    214    {
    215        if (!block.isDefaultTexture && render.overrideBlockTexture == -1)
    216        {
    217            unbindTexture();
    218        }
    219    }
    220
    221    public static String getArmorTexture(ItemStack armor, String _default)
    222    {
    223        if (armor.getItem() instanceof IArmorTextureProvider)
    224        {
    225            return ((IArmorTextureProvider)armor.getItem()).getArmorTextureFile(armor);
    226        }
    227        return _default;
    228    }
    229
    230    public static boolean renderEntityItem(EntityItem entity, ItemStack item, float bobing, float rotation, Random random, RenderEngine engine, RenderBlocks renderBlocks)
    231    {
    232        IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, ENTITY);
    233        if (customRenderer == null)
    234        {
    235            return false;
    236        }
    237
    238        if (customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_ROTATION))
    239        {
    240            GL11.glRotatef(rotation, 0.0F, 1.0F, 0.0F);
    241        }
    242        if (!customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_BOBBING))
    243        {
    244            GL11.glTranslatef(0.0F, -bobing, 0.0F);
    245        }
    246        boolean is3D = customRenderer.shouldUseRenderHelper(ENTITY, item, BLOCK_3D);
    247
    248        if (item.getItem() instanceof ItemBlock && (is3D || RenderBlocks.renderItemIn3d(Block.blocksList[item.itemID].getRenderType())))
    249        {
    250            engine.bindTexture(engine.getTexture(item.getItem().getTextureFile()));
    251            int renderType = Block.blocksList[item.itemID].getRenderType();
    252            float scale = (renderType == 1 || renderType == 19 || renderType == 12 || renderType == 2 ? 0.5F : 0.25F);
    253
    254            if (RenderItem.field_82407_g)
    255            {
    256                GL11.glScalef(1.25F, 1.25F, 1.25F);
    257                GL11.glTranslatef(0.0F, 0.05F, 0.0F);
    258                GL11.glRotatef(-90.0F, 0.0F, 1.0F, 0.0F);
    259            }
    260
    261            GL11.glScalef(scale, scale, scale);
    262
    263            int size = item.stackSize;
    264            int count = (size > 20 ? 4 : (size > 5 ? 3 : (size > 1 ? 2 : 1)));
    265
    266            for(int j = 0; j < count; j++)
    267            {
    268                GL11.glPushMatrix();
    269                if (j > 0)
    270                {
    271                    GL11.glTranslatef(
    272                        ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F,
    273                        ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F,
    274                        ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F);
    275                }
    276                customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
    277                GL11.glPopMatrix();
    278            }
    279        }
    280        else
    281        {
    282                engine.bindTexture(engine.getTexture(item.getItem().getTextureFile()));
    283            GL11.glScalef(0.5F, 0.5F, 0.5F);
    284            customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
    285        }
    286        return true;
    287    }
    288
    289    public static boolean renderInventoryItem(RenderBlocks renderBlocks, RenderEngine engine, ItemStack item, boolean inColor, float zLevel, float x, float y)
    290    {
    291        IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, INVENTORY);
    292        if (customRenderer == null)
    293        {
    294                return false;
    295        }
    296
    297        engine.bindTexture(engine.getTexture(Item.itemsList[item.itemID].getTextureFile()));
    298        if (customRenderer.shouldUseRenderHelper(INVENTORY, item, INVENTORY_BLOCK))
    299        {
    300            GL11.glPushMatrix();
    301            GL11.glTranslatef(x - 2, y + 3, -3.0F + zLevel);
    302            GL11.glScalef(10F, 10F, 10F);
    303            GL11.glTranslatef(1.0F, 0.5F, 1.0F);
    304            GL11.glScalef(1.0F, 1.0F, -1F);
    305            GL11.glRotatef(210F, 1.0F, 0.0F, 0.0F);
    306            GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
    307
    308            if(inColor)
    309            {
    310                int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
    311                float r = (float)(color >> 16 & 0xff) / 255F;
    312                float g = (float)(color >> 8 & 0xff) / 255F;
    313                float b = (float)(color & 0xff) / 255F;
    314                GL11.glColor4f(r, g, b, 1.0F);
    315            }
    316
    317            GL11.glRotatef(-90F, 0.0F, 1.0F, 0.0F);
    318            renderBlocks.useInventoryTint = inColor;
    319            customRenderer.renderItem(INVENTORY, item, renderBlocks);
    320            renderBlocks.useInventoryTint = true;
    321            GL11.glPopMatrix();
    322        }
    323        else
    324        {
    325            GL11.glDisable(GL11.GL_LIGHTING);
    326            GL11.glPushMatrix();
    327            GL11.glTranslatef(x, y, -3.0F + zLevel);
    328
    329            if (inColor)
    330            {
    331                int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
    332                float r = (float)(color >> 16 & 255) / 255.0F;
    333                float g = (float)(color >> 8 & 255) / 255.0F;
    334                float b = (float)(color & 255) / 255.0F;
    335                GL11.glColor4f(r, g, b, 1.0F);
    336            }
    337
    338            customRenderer.renderItem(INVENTORY, item, renderBlocks);
    339            GL11.glPopMatrix();
    340            GL11.glEnable(GL11.GL_LIGHTING);
    341        }
    342        return true;
    343    }
    344
    345    public static void renderEquippedItem(IItemRenderer customRenderer, RenderBlocks renderBlocks, EntityLiving entity, ItemStack item)
    346    {
    347        if (customRenderer.shouldUseRenderHelper(EQUIPPED, item, EQUIPPED_BLOCK))
    348        {
    349            GL11.glPushMatrix();
    350            GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
    351            customRenderer.renderItem(EQUIPPED, item, renderBlocks, entity);
    352            GL11.glPopMatrix();
    353        }
    354        else
    355        {
    356            GL11.glPushMatrix();
    357            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
    358            GL11.glTranslatef(0.0F, -0.3F, 0.0F);
    359            GL11.glScalef(1.5F, 1.5F, 1.5F);
    360            GL11.glRotatef(50.0F, 0.0F, 1.0F, 0.0F);
    361            GL11.glRotatef(335.0F, 0.0F, 0.0F, 1.0F);
    362            GL11.glTranslatef(-0.9375F, -0.0625F, 0.0F);
    363            customRenderer.renderItem(EQUIPPED, item, renderBlocks, entity);
    364            GL11.glDisable(GL12.GL_RESCALE_NORMAL);
    365            GL11.glPopMatrix();
    366        }
    367    }
    368
    369    //Optifine Helper Functions u.u, these are here specifically for Optifine
    370    //Note: When using Optfine, these methods are invoked using reflection, which
    371    //incurs a major performance penalty.
    372    public static void orientBedCamera(Minecraft mc, EntityLiving entity)
    373    {
    374        int x = MathHelper.floor_double(entity.posX);
    375        int y = MathHelper.floor_double(entity.posY);
    376        int z = MathHelper.floor_double(entity.posZ);
    377        Block block = Block.blocksList[mc.theWorld.getBlockId(x, y, z)];
    378
    379        if (block != null && block.isBed(mc.theWorld, x, y, z, entity))
    380        {
    381            int var12 = block.getBedDirection(mc.theWorld, x, y, z);
    382            GL11.glRotatef((float)(var12 * 90), 0.0F, 1.0F, 0.0F);
    383        }
    384    }
    385
    386    public static boolean onDrawBlockHighlight(RenderGlobal context, EntityPlayer player, MovingObjectPosition target, int subID, ItemStack currentItem, float partialTicks)
    387    {
    388        return MinecraftForge.EVENT_BUS.post(new DrawBlockHighlightEvent(context, player, target, subID, currentItem, partialTicks));
    389    }
    390
    391    public static void dispatchRenderLast(RenderGlobal context, float partialTicks)
    392    {
    393        MinecraftForge.EVENT_BUS.post(new RenderWorldLastEvent(context, partialTicks));
    394    }
    395
    396    public static void onTextureLoad(String texture, ITexturePack pack)
    397    {
    398        MinecraftForge.EVENT_BUS.post(new TextureLoadEvent(texture, pack));
    399    }
    400
    401    /**
    402     * This is added for Optifine's convenience. And to explode if a ModMaker is developing.
    403     * @param texture
    404     */
    405    public static void onTextureLoadPre(String texture)
    406    {
    407        if (Tessellator.renderingWorldRenderer)
    408        {
    409            String msg = String.format("Warning: Texture %s not preloaded, will cause render glitches!", texture);
    410            System.out.println(msg);
    411            if (Tessellator.class.getPackage() != null)
    412            {
    413                if (Tessellator.class.getPackage().getName().startsWith("net.minecraft."))
    414                {
    415                    Minecraft mc = FMLClientHandler.instance().getClient();
    416                    if (mc.ingameGUI != null)
    417                    {
    418                        mc.ingameGUI.getChatGUI().printChatMessage(msg);
    419                    }
    420                }
    421            }
    422        }
    423    }
    424
    425    public static void setRenderPass(int pass)
    426    {
    427        renderPass = pass;
    428    }
    429}