    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
    255                int size = item.stackSize;
    256                int count = (size > 20 ? 4 : (size > 5 ? 3 : (size > 1 ? 2 : 1)));
    257
    258                for(int j = 0; j < count; j++)
    259                {
    260                    GL11.glPushMatrix();
    261                    if (j > 0)
    262                    {
    263                        GL11.glTranslatef(
    264                            ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F,
    265                            ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F,
    266                            ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F);
    267                    }
    268                    customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
    269                    GL11.glPopMatrix();
    270                }
    271            }
    272            else
    273            {
    274                    engine.bindTexture(engine.getTexture(item.getItem().getTextureFile()));
    275                GL11.glScalef(0.5F, 0.5F, 0.5F);
    276                customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
    277            }
    278            return true;
    279        }
    280
    281        public static boolean renderInventoryItem(RenderBlocks renderBlocks, RenderEngine engine, ItemStack item, boolean inColor, float zLevel, float x, float y)
    282        {
    283            IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, INVENTORY);
    284            if (customRenderer == null)
    285            {
    286                    return false;
    287            }
    288
    289            engine.bindTexture(engine.getTexture(Item.itemsList[item.itemID].getTextureFile()));
    290            if (customRenderer.shouldUseRenderHelper(INVENTORY, item, INVENTORY_BLOCK))
    291            {
    292                GL11.glPushMatrix();
    293                GL11.glTranslatef(x - 2, y + 3, -3.0F + zLevel);
    294                GL11.glScalef(10F, 10F, 10F);
    295                GL11.glTranslatef(1.0F, 0.5F, 1.0F);
    296                GL11.glScalef(1.0F, 1.0F, -1F);
    297                GL11.glRotatef(210F, 1.0F, 0.0F, 0.0F);
    298                GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
    299
    300                if(inColor)
    301                {
    302                    int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
    303                    float r = (float)(color >> 16 & 0xff) / 255F;
    304                    float g = (float)(color >> 8 & 0xff) / 255F;
    305                    float b = (float)(color & 0xff) / 255F;
    306                    GL11.glColor4f(r, g, b, 1.0F);
    307                }
    308
    309                GL11.glRotatef(-90F, 0.0F, 1.0F, 0.0F);
    310                renderBlocks.useInventoryTint = inColor;
    311                customRenderer.renderItem(INVENTORY, item, renderBlocks);
    312                renderBlocks.useInventoryTint = true;
    313                GL11.glPopMatrix();
    314            }
    315            else
    316            {
    317                GL11.glDisable(GL11.GL_LIGHTING);
    318                GL11.glPushMatrix();
    319                GL11.glTranslatef(x, y, -3.0F + zLevel);
    320
    321                if (inColor)
    322                {
    323                    int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
    324                    float r = (float)(color >> 16 & 255) / 255.0F;
    325                    float g = (float)(color >> 8 & 255) / 255.0F;
    326                    float b = (float)(color & 255) / 255.0F;
    327                    GL11.glColor4f(r, g, b, 1.0F);
    328                }
    329
    330                customRenderer.renderItem(INVENTORY, item, renderBlocks);
    331                GL11.glPopMatrix();
    332                GL11.glEnable(GL11.GL_LIGHTING);
    333            }
    334            return true;
    335        }
    336
    337        public static void renderEquippedItem(IItemRenderer customRenderer, RenderBlocks renderBlocks, EntityLiving entity, ItemStack item)
    338        {
    339            if (customRenderer.shouldUseRenderHelper(EQUIPPED, item, EQUIPPED_BLOCK))
    340            {
    341                GL11.glPushMatrix();
    342                GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
    343                customRenderer.renderItem(EQUIPPED, item, renderBlocks, entity);
    344                GL11.glPopMatrix();
    345            }
    346            else
    347            {
    348                GL11.glPushMatrix();
    349                GL11.glEnable(GL12.GL_RESCALE_NORMAL);
    350                GL11.glTranslatef(0.0F, -0.3F, 0.0F);
    351                GL11.glScalef(1.5F, 1.5F, 1.5F);
    352                GL11.glRotatef(50.0F, 0.0F, 1.0F, 0.0F);
    353                GL11.glRotatef(335.0F, 0.0F, 0.0F, 1.0F);
    354                GL11.glTranslatef(-0.9375F, -0.0625F, 0.0F);
    355                customRenderer.renderItem(EQUIPPED, item, renderBlocks, entity);
    356                GL11.glDisable(GL12.GL_RESCALE_NORMAL);
    357                GL11.glPopMatrix();
    358            }
    359        }
    360
    361        //Optifine Helper Functions u.u, these are here specifically for Optifine
    362        //Note: When using Optfine, these methods are invoked using reflection, which
    363        //incurs a major performance penalty.
    364        public static void orientBedCamera(Minecraft mc, EntityLiving entity)
    365        {
    366            int x = MathHelper.floor_double(entity.posX);
    367            int y = MathHelper.floor_double(entity.posY);
    368            int z = MathHelper.floor_double(entity.posZ);
    369            Block block = Block.blocksList[mc.theWorld.getBlockId(x, y, z)];
    370
    371            if (block != null && block.isBed(mc.theWorld, x, y, z, entity))
    372            {
    373                int var12 = block.getBedDirection(mc.theWorld, x, y, z);
    374                GL11.glRotatef((float)(var12 * 90), 0.0F, 1.0F, 0.0F);
    375            }
    376        }
    377
    378        public static boolean onDrawBlockHighlight(RenderGlobal context, EntityPlayer player, MovingObjectPosition target, int subID, ItemStack currentItem, float partialTicks)
    379        {
    380            return MinecraftForge.EVENT_BUS.post(new DrawBlockHighlightEvent(context, player, target, subID, currentItem, partialTicks));
    381        }
    382
    383        public static void dispatchRenderLast(RenderGlobal context, float partialTicks)
    384        {
    385            MinecraftForge.EVENT_BUS.post(new RenderWorldLastEvent(context, partialTicks));
    386        }
    387
    388        public static void onTextureLoad(String texture, ITexturePack pack)
    389        {
    390            MinecraftForge.EVENT_BUS.post(new TextureLoadEvent(texture, pack));
    391        }
    392
    393        /**
    394         * This is added for Optifine's convenience. And to explode if a ModMaker is developing.
    395         * @param texture
    396         */
    397        public static void onTextureLoadPre(String texture)
    398        {
    399            if (Tessellator.renderingWorldRenderer)
    400            {
    401                String msg = String.format("Warning: Texture %s not preloaded, will cause render glitches!", texture);
    402                System.out.println(msg);
    403                if (Tessellator.class.getPackage() != null)
    404                {
    405                    if (Tessellator.class.getPackage().equals("net.minecraft.src"))
    406                    {
    407                        Minecraft mc = FMLClientHandler.instance().getClient();
    408                        if (mc.ingameGUI != null)
    409                        {
    410                            mc.ingameGUI.getChatGUI().printChatMessage(msg);
    411                        }
    412                    }
    413                }
    414            }
    415        }
    416    }