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 }