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    }