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