diff --git a/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java b/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java index ed13444..a02c859 100644 --- a/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java +++ b/src/main/java/nl/requios/effortlessbuilding/BuildConfig.java @@ -57,5 +57,8 @@ public class BuildConfig { public static class Visuals { @Comment({"Show a block preview if you have a block in hand on build mode Normal"}) public boolean alwaysShowBlockPreview = false; + + @Comment({"Use fancy shaders while placing blocks"}) + public boolean useShaders = true; } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java index 9f09858..584e1b1 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Floor.java @@ -3,34 +3,136 @@ package nl.requios.effortlessbuilding.buildmode; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; +import nl.requios.effortlessbuilding.helper.ReachHelper; -import java.util.ArrayList; -import java.util.List; +import java.util.*; public class Floor implements IBuildMode { + Dictionary rightClickNrTable = new Hashtable<>(); + Dictionary firstPosTable = new Hashtable<>(); + Dictionary sideHitTable = new Hashtable<>(); + Dictionary hitVecTable = new Hashtable<>(); + @Override public void initialize(EntityPlayer player) { - + rightClickNrTable.put(player.getUniqueID(), 0); + firstPosTable.put(player.getUniqueID(), BlockPos.ORIGIN); + sideHitTable.put(player.getUniqueID(), EnumFacing.UP); + hitVecTable.put(player.getUniqueID(), Vec3d.ZERO); } @Override public List onRightClick(EntityPlayer player, BlockPos blockPos, EnumFacing sideHit, Vec3d hitVec) { - return new ArrayList<>(); + List list = new ArrayList<>(); + + int rightClickNr = rightClickNrTable.get(player.getUniqueID()); + rightClickNr++; + rightClickNrTable.put(player.getUniqueID(), rightClickNr); + + if (rightClickNr == 1) { + //If clicking in air, reset and try again + if (blockPos == null) { + rightClickNrTable.put(player.getUniqueID(), 0); + return list; + } + + //First click, remember starting position + firstPosTable.put(player.getUniqueID(), blockPos); + sideHitTable.put(player.getUniqueID(), sideHit); + hitVecTable.put(player.getUniqueID(), hitVec); + //Keep list empty, dont place any blocks yet + } else { + //Second click, place wall + + list = findCoordinates(player, blockPos); + rightClickNrTable.put(player.getUniqueID(), 0); + } + + return list; } @Override public List findCoordinates(EntityPlayer player, BlockPos blockPos) { - return new ArrayList<>(); + List list = new ArrayList<>(); + int rightClickNr = rightClickNrTable.get(player.getUniqueID()); + BlockPos firstPos = firstPosTable.get(player.getUniqueID()); + + if (rightClickNr == 0) { + if (blockPos != null) + list.add(blockPos); + } else { + Vec3d look = player.getLookVec(); + Vec3d start = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ); + + //try on z axis + double y = firstPos.getY(); + + //then x and z are + double x = (y - start.y) / look.y * look.x + start.x; + double z = (y - start.y) / look.y * look.z + start.z; + + Vec3d yBound = new Vec3d(x, y, z); + + //distance to player + double yDistSquared = yBound.subtract(start).lengthSquared(); + + + int reach = ReachHelper.getMaxReach(player); //4 times as much as normal placement reach + + //check if its not behind the player and its not too close and not too far + boolean yValid = yBound.subtract(start).dotProduct(look) > 0 && + yDistSquared > 4 && yDistSquared < reach * reach; + + //select the one that is closest to the player and is valid + Vec3d selected = null; + if (yValid) selected = yBound; + + if (selected == null) return list; + + //check if it doesnt go through blocks + RayTraceResult rayTraceResult = player.world.rayTraceBlocks(start, selected, false, false, false); + if (rayTraceResult != null && rayTraceResult.typeOfHit != RayTraceResult.Type.BLOCK) { + //return empty list + return list; + } + + BlockPos secondPos = new BlockPos(selected); + + //Add whole wall + //Limit amount of blocks you can place per row + int limit = ReachHelper.getMaxBlocksPlacedAtOnce(player); + + int x1 = firstPos.getX(), x2 = secondPos.getX(); + int y1 = firstPos.getY(), y2 = secondPos.getY(); + int z1 = firstPos.getZ(), z2 = secondPos.getZ(); + + for (int l = x1; x1 < x2 ? l <= x2 : l >= x2; l += x1 < x2 ? 1 : -1) { + + for (int n = z1; z1 < z2 ? n <= z2 : n >= z2; n += z1 < z2 ? 1 : -1) { + + //check if whole row fits within limit + if (Math.abs(y1 - y2) < limit - list.size()) { + + for (int m = y1; y1 < y2 ? m <= y2 : m >= y2; m += y1 < y2 ? 1 : -1) { + list.add(new BlockPos(l, m, n)); + } + } + } + } + } + + return list; } @Override public EnumFacing getSideHit(EntityPlayer player) { - return null; + return sideHitTable.get(player.getUniqueID()); } @Override public Vec3d getHitVec(EntityPlayer player) { - return null; + return hitVecTable.get(player.getUniqueID()); } } diff --git a/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java b/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java index 798c23c..88bc93f 100644 --- a/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java +++ b/src/main/java/nl/requios/effortlessbuilding/buildmode/Wall.java @@ -5,7 +5,6 @@ import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; -import nl.requios.effortlessbuilding.EffortlessBuilding; import nl.requios.effortlessbuilding.helper.ReachHelper; import java.util.*; diff --git a/src/main/java/nl/requios/effortlessbuilding/gui/RandomizerBagGuiContainer.java b/src/main/java/nl/requios/effortlessbuilding/gui/RandomizerBagGuiContainer.java index 327ea02..3777817 100644 --- a/src/main/java/nl/requios/effortlessbuilding/gui/RandomizerBagGuiContainer.java +++ b/src/main/java/nl/requios/effortlessbuilding/gui/RandomizerBagGuiContainer.java @@ -12,7 +12,7 @@ import nl.requios.effortlessbuilding.EffortlessBuilding; @SideOnly(Side.CLIENT) public class RandomizerBagGuiContainer extends GuiContainer { private static final ResourceLocation guiTextures = - new ResourceLocation(EffortlessBuilding.MODID + ":textures/gui/container/randomizerbag.png"); + new ResourceLocation(EffortlessBuilding.MODID, "textures/gui/container/randomizerbag.png"); private final InventoryPlayer inventoryPlayer; private final IItemHandler inventoryBag; diff --git a/src/main/java/nl/requios/effortlessbuilding/helper/RenderHelper.java b/src/main/java/nl/requios/effortlessbuilding/helper/RenderHelper.java index 4bc6d01..7937e9d 100644 --- a/src/main/java/nl/requios/effortlessbuilding/helper/RenderHelper.java +++ b/src/main/java/nl/requios/effortlessbuilding/helper/RenderHelper.java @@ -1,17 +1,21 @@ package nl.requios.effortlessbuilding.helper; import net.minecraft.block.Block; +import net.minecraft.block.BlockDirt; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.Gui; import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.AxisAlignedBB; @@ -35,13 +39,18 @@ import nl.requios.effortlessbuilding.buildmodifier.ModifierSettingsManager; import nl.requios.effortlessbuilding.buildmodifier.RadialMirror; import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.proxy.ClientProxy; +import org.lwjgl.opengl.ARBMultitexture; +import org.lwjgl.opengl.ARBShaderObjects; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL14; import org.lwjgl.util.Color; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.function.Consumer; @Mod.EventBusSubscriber(Side.CLIENT) public class RenderHelper implements IWorldEventListener { @@ -56,6 +65,8 @@ public class RenderHelper implements IWorldEventListener { private static List previousCoordinates; + private static final int secondaryTextureUnit = 7; + private static void begin(float partialTicks) { EntityPlayer player = Minecraft.getMinecraft().player; double playerX = player.prevPosX + (player.posX - player.prevPosX) * partialTicks; @@ -89,14 +100,17 @@ public class RenderHelper implements IWorldEventListener { GL11.glPushAttrib(GL11.GL_ENABLE_BIT); GL11.glEnable(GL11.GL_CULL_FACE); GL11.glEnable(GL11.GL_TEXTURE_2D); + Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_color.png")); + Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")); + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE); GlStateManager.enableBlend(); - GlStateManager.blendFunc(GL11.GL_CONSTANT_ALPHA, GL11.GL_ONE_MINUS_CONSTANT_ALPHA); + GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL14.glBlendColor(1F, 1F, 1F, 0.8f); } private static void endBlockPreviews() { - GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + ShaderHelper.releaseShader(); GlStateManager.disableBlend(); GL11.glPopAttrib(); } @@ -241,6 +255,9 @@ public class RenderHelper implements IWorldEventListener { if (sideHit != null) { BlockRendererDispatcher dispatcher = Minecraft.getMinecraft().getBlockRendererDispatcher(); + float percentile = ClientProxy.ticksInGame / 100f % 1f; + //TODO test + percentile = 1f; //get coordinates List startCoordinates = BuildModes.findCoordinates(player, startPos); @@ -253,6 +270,13 @@ public class RenderHelper implements IWorldEventListener { List newCoordinates = BuildModifiers.findCoordinates(player, startCoordinates); + Collections.sort(newCoordinates, (lhs, rhs) -> { + // -1 - less than, 1 - greater than, 0 - equal + double lhsDistanceToPlayer = new Vec3d(lhs).subtract(player.getPositionEyes(1f)).lengthSquared(); + double rhsDistanceToPlayer = new Vec3d(rhs).subtract(player.getPositionEyes(1f)).lengthSquared(); + return (int) Math.signum(lhsDistanceToPlayer - rhsDistanceToPlayer); + }); + //check if they are different from previous if (!BuildModifiers.compareCoordinates(previousCoordinates, newCoordinates)) { previousCoordinates = newCoordinates; @@ -275,6 +299,8 @@ public class RenderHelper implements IWorldEventListener { if (!itemstack.isEmpty() && SurvivalHelper.canPlayerEdit(player, player.world, blockPos, itemstack) && SurvivalHelper.mayPlace(player.world, Block.getBlockFromItem(itemstack.getItem()), blockState, blockPos, true, EnumFacing.UP, player) && SurvivalHelper.canReplace(player.world, player, blockPos)) { + + ShaderHelper.useShader(ShaderHelper.psiBar, generateCallback(percentile, new Vec3d(blockPos), i == 0 || i == newCoordinates.size() - 1)); renderBlockPreview(dispatcher, blockPos, blockState); } } @@ -395,6 +421,40 @@ public class RenderHelper implements IWorldEventListener { tessellator.draw(); } + private static Consumer generateCallback(final float percentile, final Vec3d blockpos, final boolean highlight) { + Minecraft mc = Minecraft.getMinecraft(); + return (Integer shader) -> { + int percentileUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "percentile"); + int highlightUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "highlight"); + int blockposUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "blockpos"); + int imageUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "image"); + int maskUniform = ARBShaderObjects.glGetUniformLocationARB(shader, "mask"); + + //image + OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB); + GL11.glBindTexture(GL11.GL_TEXTURE_2D, mc.renderEngine.getTexture(TextureMap.LOCATION_BLOCKS_TEXTURE/*new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_color.png")*/).getGlTextureId()); + ARBShaderObjects.glUniform1iARB(imageUniform, 0); + + OpenGlHelper.setActiveTexture(ARBMultitexture.GL_TEXTURE0_ARB + secondaryTextureUnit); + + GlStateManager.enableTexture2D(); + GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + + //mask + GL11.glBindTexture(GL11.GL_TEXTURE_2D, + mc.renderEngine.getTexture(new ResourceLocation(EffortlessBuilding.MODID, "textures/shader_mask.png")).getGlTextureId()); + ARBShaderObjects.glUniform1iARB(maskUniform, secondaryTextureUnit); + + //blockpos + ARBShaderObjects.glUniform3fARB(blockposUniform, (float) blockpos.x, (float) blockpos.y, (float) blockpos.z); + + //percentile + ARBShaderObjects.glUniform1fARB(percentileUniform, percentile); + //highlight + ARBShaderObjects.glUniform1iARB(highlightUniform, highlight ? 1 : 0); + }; + } + //IWORLDEVENTLISTENER IMPLEMENTATION @Override public void notifyBlockUpdate(World worldIn, BlockPos pos, IBlockState oldState, IBlockState newState, int flags) { diff --git a/src/main/java/nl/requios/effortlessbuilding/helper/ShaderHelper.java b/src/main/java/nl/requios/effortlessbuilding/helper/ShaderHelper.java new file mode 100644 index 0000000..32abe58 --- /dev/null +++ b/src/main/java/nl/requios/effortlessbuilding/helper/ShaderHelper.java @@ -0,0 +1,195 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Modified by Requios + * + * Botania is Open Source and distributed under the + * Botania License: http://botaniamod.net/license.php + * + * File Created @ [Apr 9, 2014, 11:20:26 PM (GMT)] + */ +package nl.requios.effortlessbuilding.helper; + +import net.minecraft.client.renderer.OpenGlHelper; +import nl.requios.effortlessbuilding.BuildConfig; +import nl.requios.effortlessbuilding.EffortlessBuilding; +import nl.requios.effortlessbuilding.proxy.ClientProxy; +import org.apache.logging.log4j.Level; +import org.lwjgl.opengl.ARBFragmentShader; +import org.lwjgl.opengl.ARBShaderObjects; +import org.lwjgl.opengl.ARBVertexShader; +import org.lwjgl.opengl.GL11; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; + +public final class ShaderHelper { + + private static final int VERT_ST = ARBVertexShader.GL_VERTEX_SHADER_ARB; + private static final int FRAG_ST = ARBFragmentShader.GL_FRAGMENT_SHADER_ARB; + + private static final int VERT = 1; + private static final int FRAG = 2; + + private static final String VERT_EXTENSION = ".vert"; + private static final String FRAG_EXTENSION = ".frag"; + + public static int rawColor; + public static int psiBar; + + public static void init() { + if(!doUseShaders()) + return; + + rawColor = createProgram("/assets/effortlessbuilding/shaders/raw_color", FRAG); + psiBar = createProgram("/assets/effortlessbuilding/shaders/dissolve", FRAG); + } + + public static void useShader(int shader, Consumer callback) { + if(!doUseShaders()) + return; + + ARBShaderObjects.glUseProgramObjectARB(shader); + + if(shader != 0) { + int time = ARBShaderObjects.glGetUniformLocationARB(shader, "time"); + ARBShaderObjects.glUniform1iARB(time, ClientProxy.ticksInGame); + + if(callback != null) + callback.accept(shader); + } + } + + public static void useShader(int shader) { + useShader(shader, null); + } + + public static void releaseShader() { + useShader(0); + } + + public static boolean doUseShaders() { + return BuildConfig.visuals.useShaders && OpenGlHelper.shadersSupported; + } + + private static int createProgram(String s, int sides) { + boolean vert = (sides & VERT) != 0; + boolean frag = (sides & FRAG) != 0; + + return createProgram(vert ? s + VERT_EXTENSION : null, frag ? s + FRAG_EXTENSION : null); + } + + // Most of the code taken from the LWJGL wiki + // http://lwjgl.org/wiki/index.php?title=GLSL_Shaders_with_LWJGL + + private static int createProgram(String vert, String frag) { + int vertId = 0, fragId = 0, program; + if(vert != null) + vertId = createShader(vert, VERT_ST); + if(frag != null) + fragId = createShader(frag, FRAG_ST); + + program = ARBShaderObjects.glCreateProgramObjectARB(); + if(program == 0) + return 0; + + if(vert != null) + ARBShaderObjects.glAttachObjectARB(program, vertId); + if(frag != null) + ARBShaderObjects.glAttachObjectARB(program, fragId); + + ARBShaderObjects.glLinkProgramARB(program); + if(ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) { + EffortlessBuilding.logger.log(Level.ERROR, getLogInfo(program)); + return 0; + } + + ARBShaderObjects.glValidateProgramARB(program); + if (ARBShaderObjects.glGetObjectParameteriARB(program, ARBShaderObjects.GL_OBJECT_VALIDATE_STATUS_ARB) == GL11.GL_FALSE) { + EffortlessBuilding.logger.log(Level.ERROR, getLogInfo(program)); + return 0; + } + + return program; + } + + private static int createShader(String filename, int shaderType){ + int shader = 0; + try { + shader = ARBShaderObjects.glCreateShaderObjectARB(shaderType); + + if(shader == 0) + return 0; + + ARBShaderObjects.glShaderSourceARB(shader, readFileAsString(filename)); + ARBShaderObjects.glCompileShaderARB(shader); + + if (ARBShaderObjects.glGetObjectParameteriARB(shader, ARBShaderObjects.GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE) + throw new RuntimeException("Error creating shader: " + getLogInfo(shader)); + + return shader; + } + catch(Exception e) { + ARBShaderObjects.glDeleteObjectARB(shader); + e.printStackTrace(); + return -1; + } + } + + private static String getLogInfo(int obj) { + return ARBShaderObjects.glGetInfoLogARB(obj, ARBShaderObjects.glGetObjectParameteriARB(obj, ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB)); + } + + private static String readFileAsString(String filename) throws Exception { + StringBuilder source = new StringBuilder(); + InputStream in = ShaderHelper.class.getResourceAsStream(filename); + Exception exception = null; + BufferedReader reader; + + if(in == null) + return ""; + + try { + reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); + + Exception innerExc= null; + try { + String line; + while((line = reader.readLine()) != null) + source.append(line).append('\n'); + } catch(Exception exc) { + exception = exc; + } finally { + try { + reader.close(); + } catch(Exception exc) { + innerExc = exc; + } + } + + if(innerExc != null) + throw innerExc; + } catch(Exception exc) { + exception = exc; + } finally { + try { + in.close(); + } catch(Exception exc) { + if(exception == null) + exception = exc; + else exc.printStackTrace(); + } + + if(exception != null) + throw exception; + } + + return source.toString(); + } + +} diff --git a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java index 2ad9dc4..57f06e5 100644 --- a/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java +++ b/src/main/java/nl/requios/effortlessbuilding/proxy/ClientProxy.java @@ -6,6 +6,7 @@ import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.texture.TextureMap; @@ -51,6 +52,7 @@ import nl.requios.effortlessbuilding.gui.buildmode.RadialMenu; import nl.requios.effortlessbuilding.gui.buildmodifier.ModifierSettingsGui; import nl.requios.effortlessbuilding.helper.ReachHelper; import nl.requios.effortlessbuilding.helper.RenderHelper; +import nl.requios.effortlessbuilding.helper.ShaderHelper; import nl.requios.effortlessbuilding.item.ItemRandomizerBag; import nl.requios.effortlessbuilding.network.BlockBrokenMessage; import nl.requios.effortlessbuilding.network.BlockPlacedMessage; @@ -70,10 +72,13 @@ public class ClientProxy implements IProxy { public static RayTraceResult currentLookAt; private static int breakCooldown = 0; + public static int ticksInGame = 0; + private static final HashMap buildModeIcons = new HashMap<>(); @Override public void preInit(FMLPreInitializationEvent event) { + ShaderHelper.init(); } @Override @@ -142,6 +147,10 @@ public class ClientProxy implements IProxy { } } + /** + * From Chisels and Bits by AlgorithmX2 + * https://github.com/AlgorithmX2/Chisels-and-Bits/blob/1.12/src/main/java/mod/chiselsandbits/core/ClientSide.java + */ private static void loadIcon(final TextureMap map, final BuildModes.BuildModeEnum mode) { final RadialMenu.SpriteIconPositioning sip = new RadialMenu.SpriteIconPositioning(); @@ -284,6 +293,11 @@ public class ClientProxy implements IProxy { //QuickReplace toggle if (keyBindings[1].isPressed()) { + //TODO testing + EffortlessBuilding.log(player, "ShaderHelper init"); + ShaderHelper.init(); + + ModifierSettingsManager.ModifierSettings modifierSettings = ModifierSettingsManager.getModifierSettings(player); modifierSettings.setQuickReplace(!modifierSettings.doQuickReplace()); EffortlessBuilding.log(player, "Set "+ TextFormatting.GOLD + "Quick Replace " + TextFormatting.RESET + ( @@ -304,29 +318,35 @@ public class ClientProxy implements IProxy { @SubscribeEvent public static void onClientTick(TickEvent.ClientTickEvent event) { - if (event.phase != TickEvent.Phase.START) return; + if (event.phase == TickEvent.Phase.START) { + RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver; + //Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS) + if (objectMouseOver == null) return; - RayTraceResult objectMouseOver = Minecraft.getMinecraft().objectMouseOver; - //Checking for null is necessary! Even in vanilla when looking down ladders it is occasionally null (instead of Type MISS) - if (objectMouseOver == null) return; - - if (currentLookAt == null) { - currentLookAt = objectMouseOver; - previousLookAt = objectMouseOver; - return; - } - - if (objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK) { - if (currentLookAt.typeOfHit != RayTraceResult.Type.BLOCK) { + if (currentLookAt == null) { currentLookAt = objectMouseOver; previousLookAt = objectMouseOver; - } else { - if (currentLookAt.getBlockPos() != objectMouseOver.getBlockPos()){ - previousLookAt = currentLookAt; + return; + } + + if (objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK) { + if (currentLookAt.typeOfHit != RayTraceResult.Type.BLOCK) { currentLookAt = objectMouseOver; + previousLookAt = objectMouseOver; + } else { + if (currentLookAt.getBlockPos() != objectMouseOver.getBlockPos()) { + previousLookAt = currentLookAt; + currentLookAt = objectMouseOver; + } } } + } else if (event.phase == TickEvent.Phase.END){ + GuiScreen gui = Minecraft.getMinecraft().currentScreen; + if(gui == null || !gui.doesGuiPauseGame()) { + ticksInGame++; + } } + } @SubscribeEvent diff --git a/src/main/resources/assets/effortlessbuilding/shaders/dissolve.frag b/src/main/resources/assets/effortlessbuilding/shaders/dissolve.frag new file mode 100644 index 0000000..44f8ce0 --- /dev/null +++ b/src/main/resources/assets/effortlessbuilding/shaders/dissolve.frag @@ -0,0 +1,134 @@ +#version 120 + +uniform int time; // Passed in, see ShaderHelper.java + +uniform float percentile; // Passed in via Callback +uniform int highlight; +uniform vec3 blockpos; +uniform sampler2D image; +uniform sampler2D mask; +// Simplex 3D Noise +// by Ian McEwan, Ashima Arts +// +vec4 permute(vec4 x) {return mod(((x*34.0)+1.0)*x, 289.0);} +vec4 taylorInvSqrt(vec4 r) {return 1.79284291400159 - 0.85373472095314 * r;} + +float snoise(vec3 v){ + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy) ); + vec3 x0 = v - i + dot(i, C.xxx) ; + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); + + // x0 = x0 - 0. + 0.0 * C + vec3 x1 = x0 - i1 + 1.0 * C.xxx; + vec3 x2 = x0 - i2 + 2.0 * C.xxx; + vec3 x3 = x0 - 1. + 3.0 * C.xxx; + + // Permutations + i = mod(i, 289.0 ); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + + // Gradients + // ( N*N points uniformly over a square, mapped onto an octahedron.) + float n_ = 1.0/7.0; // N=7 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) + + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); + + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; + + vec3 p0 = vec3(a0.xy,h.x); + vec3 p1 = vec3(a0.zw,h.y); + vec3 p2 = vec3(a1.xy,h.z); + vec3 p3 = vec3(a1.zw,h.w); + + //Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + dot(p2,x2), dot(p3,x3) ) ); +} + +void main() { + vec2 texcoord = vec2(gl_TexCoord[0]); + vec4 color = texture2D(image, texcoord); + + vec3 relBlockPos = mod(blockpos, 32.0) / 32.0; + vec2 maskcoord = texcoord + vec2(relBlockPos.x + relBlockPos.y, relBlockPos.z + relBlockPos.y); + vec4 maskColor = texture2D(mask, maskcoord); + float maskgs = maskColor.r; + //maskgs = snoise(blockpos / 32.0 + ); + + float r = color.r * gl_Color.r; + float g = color.g * gl_Color.g; + float b = color.b * gl_Color.b; + float a = color.a; // Ignore gl_Color.a as we don't want to make use of that for the dissolve effect + + float pulse = (sin(time / 10.0) + 1.0) / 2.0; + vec4 pulseColor = texture2D(mask, maskcoord + time / 1000.0); + vec4 pulseColor2 = texture2D(mask, vec2(maskcoord.x - time / 1300.0, maskcoord.y - time / 1300.0)); + float pulseGreyScale = pulseColor.r + pulseColor2.r / 2.0; + g += (1.0 - g) * pulseGreyScale * pulse * 0.2; + b += (1.0 - b) * pulseGreyScale * pulse; + +// float exr1 = sin(texcoord.x * 2 + texcoord.y * 10 + time * 0.035); +// float exr2 = sin(texcoord.x * 20 + texcoord.y * 2 + time * 0.15); +// float exr3 = sin(texcoord.x * 1 + texcoord.y * 90 + time * 0.75); + +// float w1 = (cos(time * 0.1) + 1) * 0.5; +// float w2 = (sin(time * 0.08) + 1) * 0.5; +// float w3 = (cos(time * 0.001) + 1) * 0.5; + +// float w = w1 + w2 + w3; +// float exr = (exr1 * w1 + exr2 * w2 + exr3 * w3) / w * 0.1; + +// r += exr; +// g -= exr; + + if(highlight == 1) { + r -= 0.2; + b -= 0.2; + g -= 0.2; + } + + r = max(0, min(1, r)); + g = max(0, min(1, g)); + b = max(0, min(1, b)); + + if(maskgs <= percentile) + gl_FragColor = vec4(r, g, b, a); + else gl_FragColor = vec4(r, g, b, 0); +} \ No newline at end of file diff --git a/src/main/resources/assets/effortlessbuilding/shaders/raw_color.frag b/src/main/resources/assets/effortlessbuilding/shaders/raw_color.frag new file mode 100644 index 0000000..41fcbdc --- /dev/null +++ b/src/main/resources/assets/effortlessbuilding/shaders/raw_color.frag @@ -0,0 +1,15 @@ +#version 120 + +uniform sampler2D bgl_RenderedTexture; + +void main() { + vec2 texcoord = vec2(gl_TexCoord[0]); + vec4 color = texture2D(bgl_RenderedTexture, texcoord); + + float r = color.b * gl_Color.r; + float g = color.g * gl_Color.g; + float b = color.r * gl_Color.b; + float a = color.a * gl_Color.a; + + gl_FragColor = vec4(r, g, b, a); +} \ No newline at end of file diff --git a/src/main/resources/assets/effortlessbuilding/textures/gui/container/randomizerbag.png b/src/main/resources/assets/effortlessbuilding/textures/gui/container/randomizerbag.png index 56f4b89..30bf132 100644 Binary files a/src/main/resources/assets/effortlessbuilding/textures/gui/container/randomizerbag.png and b/src/main/resources/assets/effortlessbuilding/textures/gui/container/randomizerbag.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/shader_color.png b/src/main/resources/assets/effortlessbuilding/textures/shader_color.png new file mode 100644 index 0000000..617d353 Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/shader_color.png differ diff --git a/src/main/resources/assets/effortlessbuilding/textures/shader_mask.png b/src/main/resources/assets/effortlessbuilding/textures/shader_mask.png new file mode 100644 index 0000000..2e8f584 Binary files /dev/null and b/src/main/resources/assets/effortlessbuilding/textures/shader_mask.png differ