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().getName().startsWith("net.minecraft."))
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    }