package electroblob.wizardry.client.renderer; import electroblob.wizardry.Wizardry; import electroblob.wizardry.block.BlockStatue; import electroblob.wizardry.registry.WizardryPotions; import net.minecraft.client.Minecraft; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.model.ModelPlayer; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager.DestFactor; import net.minecraft.client.renderer.GlStateManager.SourceFactor; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.entity.RenderLivingBase; import net.minecraft.client.renderer.entity.RenderPlayer; import net.minecraft.client.renderer.entity.layers.LayerRenderer; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import org.lwjgl.opengl.GL11; /** * Layer used to render the frost texture on a creature with the frostbite effect. Handles dynamic tiling of the texture. * * @author Electroblob * @since Wizardry 1.2 */ public class LayerFrost implements LayerRenderer { protected ModelBase model; private final RenderLivingBase renderer; private static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/entity/frost_overlay.png"); public static void initialiseLayers(){ for(Render renderer : Minecraft.getMinecraft().getRenderManager().entityRenderMap.values()){ // Because the zombie classes are now split properly, their renderers play nicely like everything else. if(renderer instanceof RenderLivingBase){ // Adds a frost layer to all the living entity renderers in the game. Whether it is actually rendered // is decided in doRenderLayer below on a per-entity basis. ((RenderLivingBase)renderer).addLayer(new LayerFrost((RenderLivingBase)renderer)); } } for(RenderPlayer renderer : Minecraft.getMinecraft().getRenderManager().getSkinMap().values()){ renderer.addLayer(new LayerFrost(renderer)); } } public LayerFrost(RenderLivingBase renderer){ this.renderer = renderer; this.model = renderer.getMainModel(); } @Override public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){ if(entity.isPotionActive(WizardryPotions.frost) || entity.getEntityData().getBoolean(BlockStatue.FROZEN_NBT_KEY)){ GlStateManager.enableLighting(); int i = this.getBlockBrightnessForEntity(entity, partialTicks); int j = i % 65536; int k = i / 65536; OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); // Frost texture GlStateManager.enableBlend(); GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); this.renderer.bindTexture(texture); this.renderEntityModel(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale); GlStateManager.disableBlend(); } } private int getBlockBrightnessForEntity(Entity entity, float partialTicks){ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(MathHelper.floor(entity.posX), 0, MathHelper.floor(entity.posZ)); if(entity.world.isBlockLoaded(pos)){ pos.setY(MathHelper.floor(entity.posY + (double)entity.getEyeHeight())); return entity.world.getCombinedLight(pos, 0); }else{ return 0; } } private void renderEntityModel(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch, float scale){ GlStateManager.pushMatrix(); // Enables tiling (Also used for guardian beam, beacon beam and ender crystal beam) GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GlStateManager.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); GlStateManager.depthMask(true); // Some entities set depth mask to false (i.e. no sorting of faces by depth) // In particular, LayerSpiderEyes sets it to false when the spider is invisible, for some reason. // Changes the scale at which the texture is applied to the model. See LayerCreeper for a similar example, // but with translation instead of scaling. // NOTE: You can do all sorts of fun stuff with this, just by applying transformations in the 2D texture space. GlStateManager.matrixMode(GL11.GL_TEXTURE); GlStateManager.loadIdentity(); double scaleX = 1, scaleY = 1; // It's more logical to use the model's texture size, but some classes don't bother setting it properly // (e.g. ModelVillager), so to get the correct dimensions I'm getting them from the first box instead. if(model.boxList != null && model.boxList.size() >= 1 && model.boxList.get(0) != null){ scaleX = (double)model.boxList.get(0).textureWidth / 16d; scaleY = (double)model.boxList.get(0).textureHeight / 16d; }else{ // Fallback to model fields; should never be needed scaleX = (double)model.textureWidth / 16d; scaleY = (double)model.textureHeight / 16d; } GlStateManager.scale(scaleX, scaleY, 1); GlStateManager.matrixMode(GL11.GL_MODELVIEW); boolean headWearHidden = false; boolean bodyWearHidden = false; boolean leftArmWearHidden = false; boolean rightArmWearHidden = false; boolean leftLegWearHidden = false; boolean rightLegWearHidden = false; // Hides the hat layer for bipeds if(this.model instanceof ModelBiped){ headWearHidden = ((ModelBiped)this.model).bipedHeadwear.isHidden; ((ModelBiped)this.model).bipedHeadwear.isHidden = true; } if(this.model instanceof ModelPlayer){ bodyWearHidden = ((ModelPlayer)this.model).bipedBodyWear.isHidden; leftArmWearHidden = ((ModelPlayer)this.model).bipedLeftArmwear.isHidden; rightArmWearHidden = ((ModelPlayer)this.model).bipedRightArmwear.isHidden; leftLegWearHidden = ((ModelPlayer)this.model).bipedLeftLegwear.isHidden; rightLegWearHidden = ((ModelPlayer)this.model).bipedRightLegwear.isHidden; ((ModelPlayer)this.model).bipedBodyWear.isHidden = true; ((ModelPlayer)this.model).bipedLeftArmwear.isHidden = true; ((ModelPlayer)this.model).bipedRightArmwear.isHidden = true; ((ModelPlayer)this.model).bipedLeftLegwear.isHidden = true; ((ModelPlayer)this.model).bipedRightLegwear.isHidden = true; } this.model.setLivingAnimations(entity, limbSwing, limbSwingAmount, partialTicks); this.model.render(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale); if(this.model instanceof ModelBiped) ((ModelBiped)this.model).bipedHeadwear.isHidden = headWearHidden; if(this.model instanceof ModelPlayer){ ((ModelPlayer)this.model).bipedBodyWear.isHidden = bodyWearHidden; ((ModelPlayer)this.model).bipedLeftArmwear.isHidden = leftArmWearHidden; ((ModelPlayer)this.model).bipedRightArmwear.isHidden = rightArmWearHidden; ((ModelPlayer)this.model).bipedLeftLegwear.isHidden = leftLegWearHidden; ((ModelPlayer)this.model).bipedRightLegwear.isHidden = rightLegWearHidden; } // Undoes the texture scaling GlStateManager.matrixMode(GL11.GL_TEXTURE); GlStateManager.loadIdentity(); GlStateManager.matrixMode(GL11.GL_MODELVIEW); GlStateManager.popMatrix(); } @Override public boolean shouldCombineTextures(){ return false; } }