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 }