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