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 }