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