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.Entity;
016import net.minecraft.entity.EntityLiving;
017import net.minecraft.entity.player.EntityPlayer;
018import net.minecraft.client.texturepacks.ITexturePack;
019import net.minecraft.item.Item;
020import net.minecraft.item.ItemBlock;
021import net.minecraft.item.ItemStack;
022import net.minecraft.util.MathHelper;
023import net.minecraft.util.MovingObjectPosition;
024import net.minecraft.client.model.ModelBiped;
025import net.minecraft.client.renderer.RenderBlocks;
026import net.minecraft.client.renderer.RenderEngine;
027import net.minecraft.client.renderer.RenderGlobal;
028import net.minecraft.client.renderer.Tessellator;
029import net.minecraft.client.renderer.entity.RenderItem;
030import net.minecraft.client.renderer.texture.TextureMap;
031import net.minecraftforge.client.event.DrawBlockHighlightEvent;
032import net.minecraftforge.client.event.RenderWorldLastEvent;
033import net.minecraftforge.client.event.TextureLoadEvent;
034import net.minecraftforge.client.event.TextureStitchEvent;
035import net.minecraftforge.common.IArmorTextureProvider;
036import net.minecraftforge.common.MinecraftForge;
037import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
038import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
039
040public class ForgeHooksClient
041{
042    static RenderEngine engine()
043    {
044        return FMLClientHandler.instance().getClient().renderEngine;
045    }
046
047    @Deprecated //Deprecated in 1.5.1, move to the more detailed one below.
048    @SuppressWarnings("deprecation")
049    public static String getArmorTexture(ItemStack armor, String _default)
050    {
051        String result = null;
052        if (armor.getItem() instanceof IArmorTextureProvider)
053        {
054            result = ((IArmorTextureProvider)armor.getItem()).getArmorTextureFile(armor);
055        }
056        return result != null ? result : _default;
057    }
058
059    public static String getArmorTexture(Entity entity, ItemStack armor, String _default, int slot, int layer)
060    {
061        String result = armor.getItem().getArmorTexture(armor, entity, slot, layer);
062        return result != null ? result : _default;
063    }
064
065    public static boolean renderEntityItem(EntityItem entity, ItemStack item, float bobing, float rotation, Random random, RenderEngine engine, RenderBlocks renderBlocks)
066    {
067        IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, ENTITY);
068        if (customRenderer == null)
069        {
070            return false;
071        }
072
073        if (customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_ROTATION))
074        {
075            GL11.glRotatef(rotation, 0.0F, 1.0F, 0.0F);
076        }
077        if (!customRenderer.shouldUseRenderHelper(ENTITY, item, ENTITY_BOBBING))
078        {
079            GL11.glTranslatef(0.0F, -bobing, 0.0F);
080        }
081        boolean is3D = customRenderer.shouldUseRenderHelper(ENTITY, item, BLOCK_3D);
082
083        engine.bindTexture(item.getItemSpriteNumber() == 0 ? "/terrain.png" : "/gui/items.png");
084        if (is3D || (item.itemID < Block.blocksList.length && RenderBlocks.renderItemIn3d(Block.blocksList[item.itemID].getRenderType())))
085        {
086            int renderType = (item.itemID < Block.blocksList.length ? Block.blocksList[item.itemID].getRenderType() : 1);
087            float scale = (renderType == 1 || renderType == 19 || renderType == 12 || renderType == 2 ? 0.5F : 0.25F);
088
089            if (RenderItem.renderInFrame)
090            {
091                GL11.glScalef(1.25F, 1.25F, 1.25F);
092                GL11.glTranslatef(0.0F, 0.05F, 0.0F);
093                GL11.glRotatef(-90.0F, 0.0F, 1.0F, 0.0F);
094            }
095
096            GL11.glScalef(scale, scale, scale);
097            
098            int size = item.stackSize;
099            int count = (size > 20 ? 4 : (size > 5 ? 3 : (size > 1 ? 2 : 1)));
100
101            for(int j = 0; j < count; j++)
102            {
103                GL11.glPushMatrix();
104                if (j > 0)
105                {
106                    GL11.glTranslatef(
107                        ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F,
108                        ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F,
109                        ((random.nextFloat() * 2.0F - 1.0F) * 0.2F) / 0.5F);
110                }
111                customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
112                GL11.glPopMatrix();
113            }
114        }
115        else
116        {
117            GL11.glScalef(0.5F, 0.5F, 0.5F);
118            customRenderer.renderItem(ENTITY, item, renderBlocks, entity);
119        }
120        return true;
121    }
122
123    public static boolean renderInventoryItem(RenderBlocks renderBlocks, RenderEngine engine, ItemStack item, boolean inColor, float zLevel, float x, float y)
124    {
125        IItemRenderer customRenderer = MinecraftForgeClient.getItemRenderer(item, INVENTORY);
126        if (customRenderer == null)
127        {
128            return false;
129        }
130
131        engine.bindTexture(item.getItemSpriteNumber() == 0 ? "/terrain.png" : "/gui/items.png");
132        if (customRenderer.shouldUseRenderHelper(INVENTORY, item, INVENTORY_BLOCK))
133        {
134            GL11.glPushMatrix();
135            GL11.glTranslatef(x - 2, y + 3, -3.0F + zLevel);
136            GL11.glScalef(10F, 10F, 10F);
137            GL11.glTranslatef(1.0F, 0.5F, 1.0F);
138            GL11.glScalef(1.0F, 1.0F, -1F);
139            GL11.glRotatef(210F, 1.0F, 0.0F, 0.0F);
140            GL11.glRotatef(45F, 0.0F, 1.0F, 0.0F);
141
142            if(inColor)
143            {
144                int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
145                float r = (float)(color >> 16 & 0xff) / 255F;
146                float g = (float)(color >> 8 & 0xff) / 255F;
147                float b = (float)(color & 0xff) / 255F;
148                GL11.glColor4f(r, g, b, 1.0F);
149            }
150
151            GL11.glRotatef(-90F, 0.0F, 1.0F, 0.0F);
152            renderBlocks.useInventoryTint = inColor;
153            customRenderer.renderItem(INVENTORY, item, renderBlocks);
154            renderBlocks.useInventoryTint = true;
155            GL11.glPopMatrix();
156        }
157        else
158        {
159            GL11.glDisable(GL11.GL_LIGHTING);
160            GL11.glPushMatrix();
161            GL11.glTranslatef(x, y, -3.0F + zLevel);
162
163            if (inColor)
164            {
165                int color = Item.itemsList[item.itemID].getColorFromItemStack(item, 0);
166                float r = (float)(color >> 16 & 255) / 255.0F;
167                float g = (float)(color >> 8 & 255) / 255.0F;
168                float b = (float)(color & 255) / 255.0F;
169                GL11.glColor4f(r, g, b, 1.0F);
170            }
171
172            customRenderer.renderItem(INVENTORY, item, renderBlocks);
173            GL11.glPopMatrix();
174            GL11.glEnable(GL11.GL_LIGHTING);
175        }
176        return true;
177    }
178
179    public static void renderEquippedItem(IItemRenderer customRenderer, RenderBlocks renderBlocks, EntityLiving entity, ItemStack item)
180    {
181        if (customRenderer.shouldUseRenderHelper(EQUIPPED, item, EQUIPPED_BLOCK))
182        {
183            GL11.glPushMatrix();
184            GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
185            customRenderer.renderItem(EQUIPPED, item, renderBlocks, entity);
186            GL11.glPopMatrix();
187        }
188        else
189        {
190            GL11.glPushMatrix();
191            GL11.glEnable(GL12.GL_RESCALE_NORMAL);
192            GL11.glTranslatef(0.0F, -0.3F, 0.0F);
193            GL11.glScalef(1.5F, 1.5F, 1.5F);
194            GL11.glRotatef(50.0F, 0.0F, 1.0F, 0.0F);
195            GL11.glRotatef(335.0F, 0.0F, 0.0F, 1.0F);
196            GL11.glTranslatef(-0.9375F, -0.0625F, 0.0F);
197            customRenderer.renderItem(EQUIPPED, item, renderBlocks, entity);
198            GL11.glDisable(GL12.GL_RESCALE_NORMAL);
199            GL11.glPopMatrix();
200        }
201    }
202
203    //Optifine Helper Functions u.u, these are here specifically for Optifine
204    //Note: When using Optfine, these methods are invoked using reflection, which
205    //incurs a major performance penalty.
206    public static void orientBedCamera(Minecraft mc, EntityLiving entity)
207    {
208        int x = MathHelper.floor_double(entity.posX);
209        int y = MathHelper.floor_double(entity.posY);
210        int z = MathHelper.floor_double(entity.posZ);
211        Block block = Block.blocksList[mc.theWorld.getBlockId(x, y, z)];
212
213        if (block != null && block.isBed(mc.theWorld, x, y, z, entity))
214        {
215            int var12 = block.getBedDirection(mc.theWorld, x, y, z);
216            GL11.glRotatef((float)(var12 * 90), 0.0F, 1.0F, 0.0F);
217        }
218    }
219
220    public static boolean onDrawBlockHighlight(RenderGlobal context, EntityPlayer player, MovingObjectPosition target, int subID, ItemStack currentItem, float partialTicks)
221    {
222        return MinecraftForge.EVENT_BUS.post(new DrawBlockHighlightEvent(context, player, target, subID, currentItem, partialTicks));
223    }
224
225    public static void dispatchRenderLast(RenderGlobal context, float partialTicks)
226    {
227        MinecraftForge.EVENT_BUS.post(new RenderWorldLastEvent(context, partialTicks));
228    }
229
230    public static void onTextureLoad(String texture, ITexturePack pack)
231    {
232        MinecraftForge.EVENT_BUS.post(new TextureLoadEvent(texture, pack));
233    }
234
235    public static void onTextureStitchedPre(TextureMap map)
236    {
237        MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Pre(map));
238    }
239
240    public static void onTextureStitchedPost(TextureMap map)
241    {
242        MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Post(map));
243    }
244
245    /**
246     * This is added for Optifine's convenience. And to explode if a ModMaker is developing.
247     * @param texture
248     */
249    public static void onTextureLoadPre(String texture)
250    {
251        if (Tessellator.renderingWorldRenderer)
252        {
253            String msg = String.format("Warning: Texture %s not preloaded, will cause render glitches!", texture);
254            System.out.println(msg);
255            if (Tessellator.class.getPackage() != null)
256            {
257                if (Tessellator.class.getPackage().getName().startsWith("net.minecraft."))
258                {
259                    Minecraft mc = FMLClientHandler.instance().getClient();
260                    if (mc.ingameGUI != null)
261                    {
262                        mc.ingameGUI.getChatGUI().printChatMessage(msg);
263                    }
264                }
265            }
266        }
267    }
268
269    static int renderPass = -1;
270    public static void setRenderPass(int pass)
271    {
272        renderPass = pass;
273    }
274
275    public static ModelBiped getArmorModel(EntityLiving entityLiving, ItemStack itemStack, int slotID, ModelBiped _default)
276    {
277        ModelBiped modelbiped = itemStack.getItem().getArmorModel(entityLiving, itemStack, slotID);
278        return modelbiped == null ? _default : modelbiped;
279    }
280}