/** * This class was created by <Vazkii>. It's distributed as * part of the Botania Mod. Get the Source Code in github: * https://github.com/Vazkii/Botania * * Botania is Open Source and distributed under the * Botania License: http://botaniamod.net/license.php * * File Created @ [Jun 27, 2015, 7:28:29 PM (GMT)] */ package vazkii.botania.client.core.handler; import net.minecraft.util.EnumActionResult; import org.lwjgl.opengl.ARBShaderObjects; import org.lwjgl.opengl.GL11; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockRendererDispatcher; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.block.model.IBakedModel; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.text.Style; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextFormatting; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import vazkii.botania.api.lexicon.multiblock.IMultiblockRenderHook; import vazkii.botania.api.lexicon.multiblock.Multiblock; import vazkii.botania.api.lexicon.multiblock.MultiblockSet; import vazkii.botania.api.lexicon.multiblock.component.MultiblockComponent; import vazkii.botania.client.core.helper.ShaderHelper; import vazkii.botania.common.block.ModBlocks; public final class MultiblockRenderHandler { private MultiblockRenderHandler() {} private static final MultiblockBlockAccess blockAccess = new MultiblockBlockAccess(); private static int dimension; public static boolean rendering = false; public static MultiblockSet currentMultiblock; public static BlockPos anchor; public static EnumFacing angle; static { // todo 1.8.8 temporary shim, because cannot renderBlockBrightness directly, see MinecraftForge issue 2353 IMultiblockRenderHook.renderHooks.put(ModBlocks.pylon, new IMultiblockRenderHook() { @Override public void renderBlockForMultiblock(IBlockAccess world, Multiblock mb, IBlockState state, MultiblockComponent comp) { // Steal itemstack model since it has the proper group visibilities configured ItemStack stack = new ItemStack(ModBlocks.pylon, 1, state.getBlock().getMetaFromState(state)); IBakedModel model = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getItemModel(stack); GlStateManager.scale(0.65F, 0.65, 0.65F); GlStateManager.translate(0.5F, -0.75F, 0.5F); Minecraft.getMinecraft().getBlockRendererDispatcher().getBlockModelRenderer().renderModelBrightness(model, state, 1.0F, false); } @Override public boolean needsTranslate(IBlockState state) { return true; } }); } public static void setMultiblock(MultiblockSet set) { currentMultiblock = set; anchor = null; angle = EnumFacing.SOUTH; Minecraft mc = Minecraft.getMinecraft(); if(mc.world != null) dimension = mc.world.provider.getDimension(); } @SubscribeEvent public static void onWorldRenderLast(RenderWorldLastEvent event) { Minecraft mc = Minecraft.getMinecraft(); if(mc.player != null && mc.objectMouseOver != null && mc.objectMouseOver.getBlockPos() != null && (!mc.player.isSneaking() || anchor != null)) { renderPlayerLook(mc.player, mc.objectMouseOver); } } @SubscribeEvent public static void onPlayerInteract(PlayerInteractEvent.RightClickBlock event) { if(currentMultiblock != null && anchor == null && event.getEntityPlayer() == Minecraft.getMinecraft().player) { anchor = event.getPos(); angle = event.getEntityPlayer().getHorizontalFacing(); event.setCanceled(true); event.setCancellationResult(EnumActionResult.SUCCESS); } } private static void renderPlayerLook(EntityPlayer player, RayTraceResult src) { if(currentMultiblock != null && dimension == player.world.provider.getDimension()) { BlockPos anchorPos = anchor != null ? anchor : src.getBlockPos(); GlStateManager.pushMatrix(); GL11.glPushAttrib(GL11.GL_LIGHTING_BIT); GlStateManager.enableBlend(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GlStateManager.disableLighting(); rendering = true; Multiblock mb = anchor != null ? currentMultiblock.getForFacing(angle) : currentMultiblock.getForEntity(player); boolean didAny = false; blockAccess.update(player.world, mb, anchorPos); ShaderHelper.useShader(ShaderHelper.alpha, shader -> { int alpha = ARBShaderObjects.glGetUniformLocationARB(shader, "alpha"); ARBShaderObjects.glUniform1fARB(alpha, 0.4F); }); for(MultiblockComponent comp : mb.getComponents()) { if(renderComponentInWorld(player.world, mb, comp, anchorPos)) didAny = true; } ShaderHelper.releaseShader(); rendering = false; GL11.glPopAttrib(); GlStateManager.popMatrix(); if(!didAny) { setMultiblock(null); player.sendMessage(new TextComponentTranslation("botaniamisc.structureComplete").setStyle(new Style().setColor(TextFormatting.GREEN))); } } } private static boolean renderComponentInWorld(World world, Multiblock mb, MultiblockComponent comp, BlockPos anchorPos) { double renderPosX, renderPosY, renderPosZ; try { renderPosX = (double) ClientMethodHandles.renderPosX_getter.invokeExact(Minecraft.getMinecraft().getRenderManager()); renderPosY = (double) ClientMethodHandles.renderPosY_getter.invokeExact(Minecraft.getMinecraft().getRenderManager()); renderPosZ = (double) ClientMethodHandles.renderPosZ_getter.invokeExact(Minecraft.getMinecraft().getRenderManager()); } catch (Throwable t) { return true; } BlockPos pos = comp.getRelativePosition(); BlockPos pos_ = pos.add(anchorPos); if(anchor != null && comp.matches(world, pos_)) return false; GlStateManager.pushMatrix(); GlStateManager.translate(-renderPosX, -renderPosY, -renderPosZ); GlStateManager.disableDepth(); doRenderComponent(mb, comp, pos_); GlStateManager.popMatrix(); return true; } public static void renderMultiblockOnPage(Multiblock mb) { GlStateManager.translate(-0.5, -0.5, -0.5); blockAccess.update(null, mb, mb.offPos); for(MultiblockComponent comp : mb.getComponents()) { BlockPos pos = comp.getRelativePosition(); doRenderComponent(mb, comp, pos.add(mb.offPos)); } } private static void doRenderComponent(Multiblock mb, MultiblockComponent comp, BlockPos pos) { GlStateManager.pushMatrix(); GlStateManager.enableBlend(); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); IBlockState state = comp.getBlockState(); Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); if(state == null) return; if(IMultiblockRenderHook.renderHooks.containsKey(state.getBlock())) { GlStateManager.color(1F, 1F, 1F, 1F); IMultiblockRenderHook renderHook = IMultiblockRenderHook.renderHooks.get(state.getBlock()); if(renderHook.needsTranslate(state)) { GlStateManager.translate(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); } renderHook.renderBlockForMultiblock(blockAccess, mb, state, comp); } else { BlockRendererDispatcher brd = Minecraft.getMinecraft().getBlockRendererDispatcher(); GlStateManager.translate(pos.getX(), pos.getY(), pos.getZ() + 1); GlStateManager.color(1, 1, 1, 1); brd.renderBlockBrightness(state, 1.0F); } GlStateManager.color(1F, 1F, 1F, 1F); GlStateManager.enableDepth(); GlStateManager.popMatrix(); } }