diff --git a/dependencies.gradle b/dependencies.gradle index 7a6ef987..9181a98f 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,9 +1,9 @@ // Add your dependencies here dependencies { - api("com.github.GTNewHorizons:GTNHLib:0.3.2:dev") + api("com.github.GTNewHorizons:GTNHLib:0.4.0:dev") // Now a hard dep for the NEI Handlers - api("com.github.GTNewHorizons:NotEnoughItems:2.6.14-GTNH:dev") + api("com.github.GTNewHorizons:NotEnoughItems:2.6.22-GTNH:dev") compileOnly("com.github.GTNewHorizons:NotEnoughEnergistics:1.6.0:dev") testImplementation(platform('org.junit:junit-bom:5.9.2')) @@ -11,10 +11,16 @@ dependencies { // Temporary - api("com.github.GTNewHorizons:GT5-Unofficial:5.09.48.64:dev") { + api("com.github.GTNewHorizons:GT5-Unofficial:5.09.48.150:dev") { exclude group:"com.github.GTNewHorizons", module:"StructureLib" } runtimeOnlyNonPublishable("com.github.GTNewHorizons:StructureCompat:0.6.3:dev") { exclude group:"com.github.GTNewHorizons", module:"StructureLib" } + + compileOnly('org.jetbrains:annotations:24.0.1') + compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } + annotationProcessor("org.projectlombok:lombok:1.18.22") + + runtimeOnlyNonPublishable(rfg.deobf("CoreTweaks:CoreTweaks:0.3.3.2")) } diff --git a/gradle.properties b/gradle.properties index dabe0894..f6fb8fd0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -86,7 +86,7 @@ accessTransformersFile = structurelib_at.cfg usesMixins = true # Adds some debug arguments like verbose output and class export. -usesMixinDebug = false +usesMixinDebug = true # Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise. mixinPlugin = @@ -163,7 +163,7 @@ curseForgeRelations = # Optional parameter to have the build automatically fail if an illegal version is used. # This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'. -# The check is ONLY performed if the version is a git ta. +# The check is ONLY performed if the version is a git tag. # Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+ # versionPattern = diff --git a/repositories.gradle b/repositories.gradle index 45729e10..72fe253d 100644 --- a/repositories.gradle +++ b/repositories.gradle @@ -1,4 +1,22 @@ // Add any additional repositiroes for your dependencies here repositories { + exclusiveContent { + forRepository { + ivy { + name = 'CoreTweaks releases' + url = 'https://github.com/makamys/CoreTweaks/releases/download/' + patternLayout { + artifact '[revision]/[module]-1.7.10-[revision]+nomixin(-[classifier])(.[ext])' + } + metadataSources { + artifact() + } + } + } + filter { + includeGroup('CoreTweaks') + } + } + mavenLocal() } diff --git a/src/main/java/com/gtnewhorizon/structurelib/ClientProxy.java b/src/main/java/com/gtnewhorizon/structurelib/ClientProxy.java index 550af695..a049b796 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/ClientProxy.java +++ b/src/main/java/com/gtnewhorizon/structurelib/ClientProxy.java @@ -11,6 +11,7 @@ import java.util.Map; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.gui.GuiNewChat; import net.minecraft.client.particle.EntityFX; import net.minecraft.client.renderer.Tessellator; @@ -24,16 +25,20 @@ import net.minecraft.profiler.Profiler; import net.minecraft.util.ChatComponentText; import net.minecraft.util.IChatComponent; import net.minecraft.util.IIcon; +import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.event.world.WorldEvent; import org.lwjgl.opengl.GL11; import com.gtnewhorizon.structurelib.client.nei.IMCForNEI; import com.gtnewhorizon.structurelib.client.nei.InputHandler; +import com.gtnewhorizon.structurelib.client.renderer.RenderStructureGlobal; +import com.gtnewhorizon.structurelib.client.world.StructureWorld; import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX; import com.gtnewhorizon.structurelib.net.SetChannelDataMessage; @@ -48,9 +53,17 @@ import cpw.mods.fml.common.gameevent.TickEvent.Phase; public class ClientProxy extends CommonProxy { + // Structure Renderer + private static final Minecraft minecraft = Minecraft.getMinecraft(); + private static StructureWorld structureWorld = null; + private static final ThreadLocal renderStructureGlobal = ThreadLocal + .withInitial(RenderStructureGlobal::new); + + // End Structure Renderer private static final short[] RGBA_NO_TINT = { 255, 255, 255, 255 }; private static final short[] RGBA_RED_TINT = { 255, 128, 128, 0 }; private static final Map allHints = new HashMap<>(); + /** * All batches of hints. */ @@ -86,6 +99,14 @@ public class ClientProxy extends CommonProxy { */ private static final Map localThrottleMap = new HashMap<>(); + public static StructureWorld getStructureWorld() { + return structureWorld; + } + + public static void setStructureWorld(StructureWorld structureWorld) { + ClientProxy.structureWorld = structureWorld; + } + @Override public void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) { ensureHinting(); @@ -266,6 +287,27 @@ public class ClientProxy extends CommonProxy { MinecraftForge.EVENT_BUS.register(new EventHandler()); } + private static ForgeDirection getOrientation(EntityPlayer player) { + if (player.rotationPitch > 45) { + return ForgeDirection.DOWN; + } else if (player.rotationPitch < -45) { + return ForgeDirection.UP; + } else { + switch (MathHelper.floor_double(player.rotationYaw / 90.0 + 0.5) & 3) { + case 0: + return ForgeDirection.SOUTH; + case 1: + return ForgeDirection.WEST; + case 2: + return ForgeDirection.NORTH; + case 3: + return ForgeDirection.EAST; + } + } + + return ForgeDirection.UNKNOWN; + } + static void markTextureUsed(IIcon icon) { if (StructureLib.COMPAT instanceof IStructureCompat) ((IStructureCompat) StructureLib.COMPAT).markTextureUsed(icon); @@ -523,6 +565,29 @@ public class ClientProxy extends CommonProxy { @SubscribeEvent public void onRenderWorldLast(RenderWorldLastEvent e) { + renderParticlePreview(e); + renderNewPreview(e); + } + + private void renderNewPreview(RenderWorldLastEvent e) { + EntityPlayerSP player = minecraft.thePlayer; + if (player == null || structureWorld == null || !structureWorld.isRendering()) return; + + final RenderStructureGlobal renderStructureGlobal = ClientProxy.renderStructureGlobal.get(); + renderStructureGlobal.setPlayerPosition( + player.lastTickPosX + (player.posX - player.lastTickPosX) * e.partialTicks, + player.lastTickPosY + (player.posY - player.lastTickPosY) * e.partialTicks, + player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * e.partialTicks); + renderStructureGlobal.setOrientation(getOrientation(player)); + renderStructureGlobal.setRotationRender(MathHelper.floor_double(player.rotationYaw / 90) & 3); + + minecraft.mcProfiler.startSection("structlibRenderPreview"); + renderStructureGlobal.render(structureWorld); + + minecraft.mcProfiler.endSection(); + } + + private void renderParticlePreview(RenderWorldLastEvent e) { if (allHintsForRender.isEmpty()) return; // seriously, I'm not a OpenGL expert, so I'm probably doing a lot of very stupid stuff here. @@ -591,4 +656,5 @@ public class ClientProxy extends CommonProxy { p.endSection(); } } + } diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/nei/integration/gregtech/GT_GUI_MultiblockHandler.java b/src/main/java/com/gtnewhorizon/structurelib/client/nei/integration/gregtech/GT_GUI_MultiblockHandler.java new file mode 100644 index 00000000..e6d998d1 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/client/nei/integration/gregtech/GT_GUI_MultiblockHandler.java @@ -0,0 +1,71 @@ +package com.gtnewhorizon.structurelib.client.nei.integration.gregtech; + +import com.gtnewhorizon.structurelib.alignment.constructable.IConstructable; +import com.gtnewhorizon.structurelib.client.nei.GUI_MultiblockHandler; + +public class GT_GUI_MultiblockHandler extends GUI_MultiblockHandler { + + public GT_GUI_MultiblockHandler() { + super(); + } + + // spotless:off +// TODO: Move this into a non GUI multi block handler class +// @Override +// protected void placeMultiblock() { +// if (GT_Runnable_MachineBlockUpdate.isCurrentThreadEnabled()) { +// GT_Runnable_MachineBlockUpdate.setCurrentThreadEnabled(false); +// } +// +// IConstructable constructable = null; +// ItemStack copy = stackForm.copy(); +// copy.getItem().onItemUse( +// copy, +// renderer.world.getFakeMultiblockBuilder(), +// renderer.world, +// PLACE_POSITION.x, +// PLACE_POSITION.y, +// PLACE_POSITION.z, +// 0, +// PLACE_POSITION.x, +// PLACE_POSITION.y, +// PLACE_POSITION.z); +// +// TileEntity tTileEntity = renderer.world.getTileEntity(PLACE_POSITION.x, PLACE_POSITION.y, PLACE_POSITION.z); +// ((ITurnable) tTileEntity).setFrontFacing(ForgeDirection.SOUTH); +// IMetaTileEntity mte = ((IGregTechTileEntity) tTileEntity).getMetaTileEntity(); +// +// if (!StructureLibAPI.isInstrumentEnabled()) { +// StructureLibAPI.enableInstrument(StructureLibAPI.MOD_ID); +// } +// structureElements.clear(); +// +// This seems relevant because the .construct() call ignores hatches, etc. Needs an optimized CreativeItemSource +// if (mte instanceof ISurvivalConstructable survivalConstructable) { +// int result, iterations = 0; +// do { +// result = survivalConstructable.survivalConstruct( +// getBuildTriggerStack(), +// Integer.MAX_VALUE, +// ISurvivalBuildEnvironment.create(CreativeItemSource.instance, renderer.world.getFakeMultiblockBuilder())); +// iterations++; +// } while (result > 0 && iterations < MAX_PLACE_ROUNDS); +// } else if (tTileEntity instanceof IConstructableProvider iConstructableProvider) { +// constructable = iConstructableProvider.getConstructable(); +// } else if (tTileEntity instanceof IConstructable iConstructable) { +// constructable = iConstructable; +// } +// if (constructable != null) { +// constructable.construct(getBuildTriggerStack(), false); +// } +// +// if (StructureLibAPI.isInstrumentEnabled()) { +// StructureLibAPI.disableInstrument(); +// } +// +// if (!GT_Runnable_MachineBlockUpdate.isCurrentThreadEnabled()) { +// GT_Runnable_MachineBlockUpdate.setCurrentThreadEnabled(true); +// } +// } +// spotless:on +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/nei/integration/gregtech/GT_NEI_MultiblockHandler.java b/src/main/java/com/gtnewhorizon/structurelib/client/nei/integration/gregtech/GT_NEI_MultiblockHandler.java new file mode 100644 index 00000000..7e5ddef2 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/client/nei/integration/gregtech/GT_NEI_MultiblockHandler.java @@ -0,0 +1,57 @@ +package com.gtnewhorizon.structurelib.client.nei.integration.gregtech; + +import static com.gtnewhorizon.structurelib.client.nei.IMCForNEI.GT_NEI_MB_HANDLER_NAME; +import static gregtech.api.GregTech_API.METATILEENTITIES; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizon.structurelib.alignment.constructable.IConstructable; +import com.gtnewhorizon.structurelib.client.nei.MultiblockHandler; + +import codechicken.nei.NEIClientUtils; +import codechicken.nei.recipe.TemplateRecipeHandler; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; + +public class GT_NEI_MultiblockHandler extends MultiblockHandler { + + public static List multiblocksList = new ArrayList<>(); + private static final GT_GUI_MultiblockHandler baseHandler = new GT_GUI_MultiblockHandler(); + + public GT_NEI_MultiblockHandler() { + super(baseHandler); + for (IMetaTileEntity mte : METATILEENTITIES) { + if (mte instanceof IConstructable) { + multiblocksList.add((IConstructable) mte); + } + } + } + + @Override + public String getOverlayIdentifier() { + return GT_NEI_MB_HANDLER_NAME; + } + + @Override + public TemplateRecipeHandler newInstance() { + return new GT_NEI_MultiblockHandler(); + } + + @Override + protected void tryLoadingMultiblock(ItemStack candidate) { + for (IConstructable multiblock : multiblocksList) { + ItemStack stackForm = ((IMetaTileEntity) multiblock).getStackForm(1); + if (NEIClientUtils.areStacksSameType(stackForm, candidate)) { + baseHandler.setOnIngredientChanged(ingredients -> { + this.ingredients = ingredients; + resetPositionedIngredients(); + }); + baseHandler.setOnCandidateChanged(this::setResults); + baseHandler.loadMultiblock(multiblock, stackForm); + return; + } + } + } +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RenderHelper.java b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RenderHelper.java new file mode 100644 index 00000000..ce88531f --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RenderHelper.java @@ -0,0 +1,488 @@ +package com.gtnewhorizon.structurelib.client.renderer; + +import java.nio.FloatBuffer; + +import org.joml.Vector3f; +import org.lwjgl.BufferUtils; + +public class RenderHelper { + + public static final int QUAD_DOWN = 0x01; + public static final int QUAD_UP = 0x02; + public static final int QUAD_NORTH = 0x04; + public static final int QUAD_SOUTH = 0x08; + public static final int QUAD_WEST = 0x10; + public static final int QUAD_EAST = 0x20; + public static final int QUAD_ALL = QUAD_DOWN | QUAD_UP | QUAD_NORTH | QUAD_SOUTH | QUAD_WEST | QUAD_EAST; + + public static final int LINE_DOWN_WEST = 0x11; + public static final int LINE_UP_WEST = 0x12; + public static final int LINE_DOWN_EAST = 0x21; + public static final int LINE_UP_EAST = 0x22; + public static final int LINE_DOWN_NORTH = 0x05; + public static final int LINE_UP_NORTH = 0x06; + public static final int LINE_DOWN_SOUTH = 0x09; + public static final int LINE_UP_SOUTH = 0x0A; + public static final int LINE_NORTH_WEST = 0x14; + public static final int LINE_NORTH_EAST = 0x24; + public static final int LINE_SOUTH_WEST = 0x18; + public static final int LINE_SOUTH_EAST = 0x28; + public static final int LINE_ALL = LINE_DOWN_WEST | LINE_UP_WEST + | LINE_DOWN_EAST + | LINE_UP_EAST + | LINE_DOWN_NORTH + | LINE_UP_NORTH + | LINE_DOWN_SOUTH + | LINE_UP_SOUTH + | LINE_NORTH_WEST + | LINE_NORTH_EAST + | LINE_SOUTH_WEST + | LINE_SOUTH_EAST; + + public static final Vector3f VEC_ZERO = new Vector3f(0, 0, 0); + + private static int quadSize = 0; + private static float[] quadVertexBuffer = null; + private static float[] quadColorBuffer = null; + private static int quadVertexIndex = 0; + private static int quadColorIndex = 0; + private static int quadCount = 0; + + private static int lineSize = 0; + private static float[] lineVertexBuffer = null; + private static float[] lineColorBuffer = null; + private static int lineVertexIndex = 0; + private static int lineColorIndex = 0; + private static int lineCount = 0; + + private static final Vector3f vecZero = new Vector3f(); + private static final Vector3f vecSize = new Vector3f(); + + public static void createBuffers() { + quadSize = 240; + quadVertexBuffer = new float[quadSize * 3]; + quadColorBuffer = new float[quadSize * 4]; + + lineSize = 240; + lineVertexBuffer = new float[lineSize * 3]; + lineColorBuffer = new float[lineSize * 4]; + + initBuffers(); + } + + public static void initBuffers() { + quadVertexIndex = 0; + quadColorIndex = 0; + quadCount = 0; + + lineVertexIndex = 0; + lineColorIndex = 0; + lineCount = 0; + } + + public static void destroyBuffers() { + quadSize = 0; + quadVertexBuffer = null; + quadColorBuffer = null; + + lineSize = 0; + lineVertexBuffer = null; + lineColorBuffer = null; + } + + public static FloatBuffer getQuadVertexBuffer() { + FloatBuffer buffer = BufferUtils.createFloatBuffer(quadVertexBuffer.length).put(quadVertexBuffer); + buffer.flip(); + return buffer; + } + + public static FloatBuffer getQuadColorBuffer() { + FloatBuffer buffer = BufferUtils.createFloatBuffer(quadColorBuffer.length).put(quadColorBuffer); + buffer.flip(); + return buffer; + } + + public static int getQuadCount() { + return quadCount; + } + + public static FloatBuffer getLineVertexBuffer() { + FloatBuffer buffer = BufferUtils.createFloatBuffer(lineVertexBuffer.length).put(lineVertexBuffer); + buffer.flip(); + return buffer; + } + + public static FloatBuffer getLineColorBuffer() { + FloatBuffer buffer = BufferUtils.createFloatBuffer(lineColorBuffer.length).put(lineColorBuffer); + buffer.flip(); + return buffer; + } + + public static int getLineCount() { + return lineCount; + } + + private static float[] createAndCopyBuffer(int newSize, float[] oldBuffer) { + float[] tempBuffer = new float[newSize]; + System.arraycopy(oldBuffer, 0, tempBuffer, 0, oldBuffer.length); + return tempBuffer; + } + + final static double BLOCK_DELTA = 0.005; + + public static void drawCuboidSurface(Vector3f zero, Vector3f size, int sides, float red, float green, float blue, + float alpha) { + vecZero.set(zero.x - BLOCK_DELTA, zero.y - BLOCK_DELTA, zero.z - BLOCK_DELTA); + vecSize.set(size.x + BLOCK_DELTA, size.y + BLOCK_DELTA, size.z + BLOCK_DELTA); + + if (quadCount + 24 >= quadSize) { + quadSize *= 2; + + quadVertexBuffer = createAndCopyBuffer(quadSize * 3, quadVertexBuffer); + quadColorBuffer = createAndCopyBuffer(quadSize * 4, quadColorBuffer); + } + + int total = 0; + + if ((sides & QUAD_DOWN) != 0) { + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + total += 4; + } + + if ((sides & QUAD_UP) != 0) { + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + total += 4; + } + + if ((sides & QUAD_NORTH) != 0) { + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + total += 4; + } + + if ((sides & QUAD_SOUTH) != 0) { + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + total += 4; + } + + if ((sides & QUAD_WEST) != 0) { + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecZero.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + total += 4; + } + + if ((sides & QUAD_EAST) != 0) { + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecZero.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecZero.z; + quadCount++; + + quadVertexBuffer[quadVertexIndex++] = vecSize.x; + quadVertexBuffer[quadVertexIndex++] = vecSize.y; + quadVertexBuffer[quadVertexIndex++] = vecSize.z; + quadCount++; + + total += 4; + } + + for (int i = 0; i < total; i++) { + quadColorBuffer[quadColorIndex++] = red; + quadColorBuffer[quadColorIndex++] = green; + quadColorBuffer[quadColorIndex++] = blue; + quadColorBuffer[quadColorIndex++] = alpha; + } + } + + public static void drawCuboidOutline(Vector3f zero, Vector3f size, int sides, float red, float green, float blue, + float alpha) { + vecZero.set(zero.x - BLOCK_DELTA, zero.y - BLOCK_DELTA, zero.z - BLOCK_DELTA); + vecSize.set(size.x + BLOCK_DELTA, size.y + BLOCK_DELTA, size.z + BLOCK_DELTA); + + if (lineCount + 24 >= lineSize) { + lineSize *= 2; + + lineVertexBuffer = createAndCopyBuffer(lineSize * 3, lineVertexBuffer); + lineColorBuffer = createAndCopyBuffer(lineSize * 4, lineColorBuffer); + } + + int total = 0; + + if ((sides & LINE_DOWN_WEST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_UP_WEST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_DOWN_EAST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_UP_EAST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_DOWN_NORTH) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_UP_NORTH) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_DOWN_SOUTH) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_UP_SOUTH) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_NORTH_WEST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_NORTH_EAST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecZero.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_SOUTH_WEST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecZero.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + if ((sides & LINE_SOUTH_EAST) != 0) { + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecZero.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + lineVertexBuffer[lineVertexIndex++] = vecSize.x; + lineVertexBuffer[lineVertexIndex++] = vecSize.y; + lineVertexBuffer[lineVertexIndex++] = vecSize.z; + lineCount++; + + total += 2; + } + + for (int i = 0; i < total; i++) { + lineColorBuffer[lineColorIndex++] = red; + lineColorBuffer[lineColorIndex++] = green; + lineColorBuffer[lineColorIndex++] = blue; + lineColorBuffer[lineColorIndex++] = alpha; + } + } +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RenderStructureGlobal.java b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RenderStructureGlobal.java new file mode 100644 index 00000000..38b88448 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RenderStructureGlobal.java @@ -0,0 +1,182 @@ +package com.gtnewhorizon.structurelib.client.renderer; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.culling.Frustrum; +import net.minecraft.profiler.Profiler; +import net.minecraftforge.common.util.ForgeDirection; + +import org.joml.Vector3d; +import org.lwjgl.opengl.GL11; + +import com.gtnewhorizon.structurelib.client.world.StructureWorld; + +public class RenderStructureGlobal { + + private final Vector3d playerPosition = new Vector3d(); + private ForgeDirection orientation = ForgeDirection.UNKNOWN; + private int rotationRender = 0; + + private final Frustrum frustrum = new Frustrum(); + public RenderBlocks renderBlocks = null; + public final List sortedRendererStructureChunk = new ArrayList<>(); + private final RendererStructureChunkComparator rendererStructureChunkComparator = new RendererStructureChunkComparator(); + + public void setPlayerPosition(Vector3d playerPosistion) { + this.playerPosition.set(playerPosistion); + } + + public void setPlayerPosition(double x, double y, double z) { + this.playerPosition.set(x, y, z); + } + + public void setOrientation(ForgeDirection orientation) { + this.orientation = orientation; + } + + public void setRotationRender(int rotationRender) { + this.rotationRender = rotationRender; + } + + public void render(StructureWorld structureWorld) { + final Minecraft minecraft = Minecraft.getMinecraft(); + final Profiler profiler = minecraft.mcProfiler; + + GL11.glPushMatrix(); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glEnable(GL11.GL_BLEND); + + Vector3d extra = new Vector3d(); + if (structureWorld != null) { + extra.add( + structureWorld.renderPosition.x, + structureWorld.renderPosition.y, + structureWorld.renderPosition.z); + playerPosition.sub(extra); + } + + GL11.glTranslated(-playerPosition.x, -playerPosition.y, -playerPosition.z); + + profiler.startSection("schematic"); + if (structureWorld != null && structureWorld.isRendering()) { + profiler.startSection("updateFrustrum"); + updateFrustrum(structureWorld); + + profiler.endStartSection("sortAndUpdate"); + if (RendererStructureChunk.getCanUpdate()) { + sortAndUpdate(structureWorld); + } + + profiler.endStartSection("render"); + int pass; + for (pass = 0; pass < 3; pass++) { + for (RendererStructureChunk renderer : this.sortedRendererStructureChunk) { + renderer.render(playerPosition, pass); + } + } + profiler.endSection(); + } + + profiler.endStartSection("guide"); + + RenderHelper.createBuffers(); + + profiler.startSection("dataPrep"); + + int quadCount = RenderHelper.getQuadCount(); + int lineCount = RenderHelper.getLineCount(); + + if (quadCount > 0 || lineCount > 0) { + GL11.glDisable(GL11.GL_TEXTURE_2D); + + GL11.glLineWidth(1.5f); + + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); + + profiler.endStartSection("quad"); + if (quadCount > 0) { + GL11.glVertexPointer(3, 0, RenderHelper.getQuadVertexBuffer()); + GL11.glColorPointer(4, 0, RenderHelper.getQuadColorBuffer()); + GL11.glDrawArrays(GL11.GL_QUADS, 0, quadCount); + } + + profiler.endStartSection("line"); + if (lineCount > 0) { + GL11.glVertexPointer(3, 0, RenderHelper.getLineVertexBuffer()); + GL11.glColorPointer(4, 0, RenderHelper.getLineColorBuffer()); + GL11.glDrawArrays(GL11.GL_LINES, 0, lineCount); + } + + profiler.endSection(); + + GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); + GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); + + GL11.glEnable(GL11.GL_TEXTURE_2D); + } + + profiler.endSection(); + + GL11.glDisable(GL11.GL_BLEND); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glPopMatrix(); + } + + private void updateFrustrum(StructureWorld schematic) { + this.frustrum.setPosition( + playerPosition.x - schematic.renderPosition.x, + playerPosition.y - schematic.renderPosition.y, + playerPosition.z - schematic.renderPosition.z); + for (RendererStructureChunk RendererStructureChunk : this.sortedRendererStructureChunk) { + RendererStructureChunk.isInFrustrum = this.frustrum + .isBoundingBoxInFrustum(RendererStructureChunk.getBoundingBox()); + } + } + + private void sortAndUpdate(StructureWorld world) { + this.rendererStructureChunkComparator.setPosition(playerPosition, world.renderPosition); + this.sortedRendererStructureChunk.sort(this.rendererStructureChunkComparator); + + for (RendererStructureChunk RendererStructureChunk : this.sortedRendererStructureChunk) { + if (RendererStructureChunk.getDirty()) { + RendererStructureChunk.updateRenderer(renderBlocks); + break; + } + } + } + + public void createRendererStructureChunks(StructureWorld structureWorld) { + int width = (structureWorld.getWidth() - 1) / 16 + 1; + int height = (structureWorld.getHeight() - 1) / 16 + 1; + int length = (structureWorld.getLength() - 1) / 16 + 1; + + destroyRendererStructureChunks(); + + this.renderBlocks = new RenderBlocks(structureWorld); + for (int y = 0; y < height; y++) { + for (int z = 0; z < length; z++) { + for (int x = 0; x < width; x++) { + this.sortedRendererStructureChunk.add(new RendererStructureChunk(structureWorld, x, y, z)); + } + } + } + } + + public void destroyRendererStructureChunks() { + this.renderBlocks = null; + while (!this.sortedRendererStructureChunk.isEmpty()) { + this.sortedRendererStructureChunk.remove(0).delete(); + } + } + + public void refresh() { + for (RendererStructureChunk renderer : this.sortedRendererStructureChunk) { + renderer.setDirty(); + } + } + +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RendererStructureChunk.java b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RendererStructureChunk.java new file mode 100644 index 00000000..a4ddc1ec --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RendererStructureChunk.java @@ -0,0 +1,414 @@ +package com.gtnewhorizon.structurelib.client.renderer; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.profiler.Profiler; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.IBlockAccess; + +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL20; + +import com.gtnewhorizon.gtnhlib.client.renderer.shader.ShaderProgram; +import com.gtnewhorizon.structurelib.StructureLib; +import com.gtnewhorizon.structurelib.client.world.StructureWorld; + +public class RendererStructureChunk { + + private static final ShaderProgram alphaShader = initAlphaShader(); + private static final int alphaUniform = GL20.glGetUniformLocation(alphaShader.getProgram(), "alpha_multiplier"); + + private static boolean canUpdate = false; + + public boolean isInFrustrum = false; + + public final Vector3d centerPosition = new Vector3d(); + + private final Minecraft minecraft = Minecraft.getMinecraft(); + private final Profiler profiler = this.minecraft.mcProfiler; + private final StructureWorld world; + private final List tileEntities = new ArrayList<>(); + private final Vector3d distance = new Vector3d(); + + private final AxisAlignedBB boundingBox = AxisAlignedBB.getBoundingBox(0, 0, 0, 0, 0, 0); + + private boolean needsUpdate = true; + private int glList = -1; + // TODO: move this away from GL lists + private int glListHighlight = -1; + + private static ShaderProgram initAlphaShader() { + ShaderProgram shader; + try { + shader = new ShaderProgram("structurelib", null, "shaders/alpha.frag"); + shader.use(); + GL20.glUniform1i(GL20.glGetUniformLocation(shader.getProgram(), "texture"), 0); + ShaderProgram.clear(); + } catch (Exception e) { + shader = null; + } + return shader; + } + + private static final int SUBCHUNK_SIZE = 16; + + public RendererStructureChunk(StructureWorld world, int x, int y, int z) { + this.world = world; + + this.boundingBox.setBounds( + x * SUBCHUNK_SIZE, + y * SUBCHUNK_SIZE, + z * SUBCHUNK_SIZE, + (x + 1) * SUBCHUNK_SIZE, + (y + 1) * SUBCHUNK_SIZE, + (z + 1) * SUBCHUNK_SIZE); + this.centerPosition.set( + (int) ((x + 0.5) * SUBCHUNK_SIZE), + (int) ((y + 0.5) * SUBCHUNK_SIZE), + (int) ((z + 0.5) * SUBCHUNK_SIZE)); + + // TODO: Replace this with something less stupid + int tx, ty, tz; + for (TileEntity tileEntity : this.world.getTileEntities()) { + tx = tileEntity.xCoord; + ty = tileEntity.yCoord; + tz = tileEntity.zCoord; + + if (tx < this.boundingBox.minX || tx >= this.boundingBox.maxX) { + continue; + } else if (tz < this.boundingBox.minZ || tz >= this.boundingBox.maxZ) { + continue; + } else if (ty < this.boundingBox.minY || ty >= this.boundingBox.maxY) { + continue; + } + + this.tileEntities.add(tileEntity); + } + + } + + public void delete() { + // Deallocate VBOs + } + + public void updateRenderer(RenderBlocks renderBlocks) { + if (this.needsUpdate) { + this.needsUpdate = false; + setCanUpdate(false); + + RenderHelper.createBuffers(); + + for (int pass = 0; pass < 3; pass++) { + RenderHelper.initBuffers(); + + int minX, maxX, minY, maxY, minZ, maxZ; + + minX = (int) this.boundingBox.minX; + maxX = (int) this.boundingBox.maxX; + minY = (int) this.boundingBox.minY; + maxY = (int) this.boundingBox.maxY; + minZ = (int) this.boundingBox.minZ; + maxZ = (int) this.boundingBox.maxZ; + + // TODO: Rendering layer + // int renderingLayer = this.world.renderingLayer; + // if (this.world.isRenderingLayer) { + // if (renderingLayer >= minY && renderingLayer < maxY) { + // minY = renderingLayer; + // maxY = renderingLayer + 1; + // } else { + // minY = maxY = 0; + // } + // } + + GL11.glNewList(this.glList + pass, GL11.GL_COMPILE); + renderBlocks(renderBlocks, pass, minX, minY, minZ, maxX, maxY, maxZ); + GL11.glEndList(); + + GL11.glNewList(this.glListHighlight + pass, GL11.GL_COMPILE); + int quadCount = RenderHelper.getQuadCount(); + int lineCount = RenderHelper.getLineCount(); + + if (quadCount > 0 || lineCount > 0) { + GL11.glDisable(GL11.GL_TEXTURE_2D); + + GL11.glLineWidth(1.5f); + + GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); + GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); + + if (quadCount > 0) { + GL11.glVertexPointer(3, 0, RenderHelper.getQuadVertexBuffer()); + GL11.glColorPointer(4, 0, RenderHelper.getQuadColorBuffer()); + GL11.glDrawArrays(GL11.GL_QUADS, 0, quadCount); + } + + if (lineCount > 0) { + GL11.glVertexPointer(3, 0, RenderHelper.getLineVertexBuffer()); + GL11.glColorPointer(4, 0, RenderHelper.getLineColorBuffer()); + GL11.glDrawArrays(GL11.GL_LINES, 0, lineCount); + } + + GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); + GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); + + GL11.glEnable(GL11.GL_TEXTURE_2D); + } + + GL11.glEndList(); + } + + RenderHelper.destroyBuffers(); + } + } + + public void render(Vector3d playerPosition, int renderPass) { + if (!this.isInFrustrum) { + return; + } + + if (this.distance.set(playerPosition) + .sub(this.world.renderPosition.x, this.world.renderPosition.y, this.world.renderPosition.z) + .sub(this.centerPosition).lengthSquared() > 25600) { + return; + } + + // some mods enable this, beats me why - it's supposed to be disabled! + GL11.glDisable(GL11.GL_LIGHTING); + + this.profiler.startSection("blocks"); + this.minecraft.renderEngine.bindTexture(TextureMap.locationBlocksTexture); + + GL20.glUseProgram(alphaShader.getProgram()); + GL20.glUniform1f(alphaUniform, ALPHA); + + GL11.glCallList(this.glList + renderPass); + + GL20.glUseProgram(0); + + this.profiler.endStartSection("highlight"); + GL11.glCallList(this.glListHighlight + renderPass); + + this.profiler.endStartSection("tileEntities"); + renderTileEntities(renderPass); + + // re-enable blending... spawners disable it, somewhere... + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + + // re-set alpha func... beacons set it to (GL_GREATER, 0.5f) + // EntityRenderer sets it to (GL_GREATER, 0.1f) before dispatching the event + GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F); + + this.profiler.endSection(); + } + + public void renderBlocks(RenderBlocks renderBlocks, int renderPass, int minX, int minY, int minZ, int maxX, + int maxY, int maxZ) { + IBlockAccess mcWorld = this.minecraft.theWorld; + + int x, y, z, wx, wy, wz; + int sides; + Block block, mcBlock; + Vector3f zero = new Vector3f(); + Vector3f size = new Vector3f(); + + int ambientOcclusion = this.minecraft.gameSettings.ambientOcclusion; + this.minecraft.gameSettings.ambientOcclusion = 0; + + Tessellator.instance.startDrawingQuads(); + + for (y = minY; y < maxY; y++) { + for (z = minZ; z < maxZ; z++) { + for (x = minX; x < maxX; x++) { + try { + block = this.world.getBlock(x, y, z); + + wx = this.world.renderPosition.x + x; + wy = this.world.renderPosition.y + y; + wz = this.world.renderPosition.z + z; + + mcBlock = mcWorld.getBlock(wx, wy, wz); + + sides = 0; + if (block != null) { + if (block.shouldSideBeRendered(this.world, x, y - 1, z, 0)) { + sides |= RenderHelper.QUAD_DOWN; + } + + if (block.shouldSideBeRendered(this.world, x, y + 1, z, 1)) { + sides |= RenderHelper.QUAD_UP; + } + + if (block.shouldSideBeRendered(this.world, x, y, z - 1, 2)) { + sides |= RenderHelper.QUAD_NORTH; + } + + if (block.shouldSideBeRendered(this.world, x, y, z + 1, 3)) { + sides |= RenderHelper.QUAD_SOUTH; + } + + if (block.shouldSideBeRendered(this.world, x - 1, y, z, 4)) { + sides |= RenderHelper.QUAD_WEST; + } + + if (block.shouldSideBeRendered(this.world, x + 1, y, z, 5)) { + sides |= RenderHelper.QUAD_EAST; + } + } + + boolean isAirBlock = this.world.isAirBlock(x, y, z); + boolean isMcAirBlock = mcWorld.isAirBlock(wx, wy, wz); + + if (!isMcAirBlock) { + // if ConfigurationHandler.highlight + if (renderPass == 2) { + // if ConfigurationHandler.highlightAir + if (isAirBlock) { + zero.set(x, y, z); + size.set(x + 1, y + 1, z + 1); + // if (ConfigurationHandler.drawQuads) + RenderHelper.drawCuboidSurface( + zero, + size, + RenderHelper.QUAD_ALL, + 0.75f, + 0.0f, + 0.75f, + 0.25f); + // if (ConfigurationHandler.drawLines) + RenderHelper.drawCuboidOutline( + zero, + size, + RenderHelper.LINE_ALL, + 0.75f, + 0.0f, + 0.75f, + 0.25f); + } else if (block != mcBlock) { + zero.set(x, y, z); + size.set(x + 1, y + 1, z + 1); + // if (ConfigurationHandler.drawQuads) + RenderHelper.drawCuboidSurface(zero, size, sides, 1.0f, 0.0f, 0.0f, 0.25f); + // if (ConfigurationHandler.drawLines) + RenderHelper.drawCuboidOutline(zero, size, sides, 1.0f, 0.0f, 0.0f, 0.25f); + } else + if (this.world.getBlockMetadata(x, y, z) != mcWorld.getBlockMetadata(wx, wy, wz)) { + zero.set(x, y, z); + size.set(x + 1, y + 1, z + 1); + // if (ConfigurationHandler.drawQuads) + RenderHelper.drawCuboidSurface(zero, size, sides, 0.75f, 0.35f, 0.0f, 0.25f); + // if (ConfigurationHandler.drawLines) + RenderHelper.drawCuboidOutline(zero, size, sides, 0.75f, 0.35f, 0.0f, 0.25f); + } + } + } else if (!isAirBlock) { + // if ConfigurationHandler.highlight + if (renderPass == 2) { + zero.set(x, y, z); + size.set(x + 1, y + 1, z + 1); + // if (ConfigurationHandler.drawQuads) + RenderHelper.drawCuboidSurface(zero, size, sides, 0.0f, 0.75f, 1.0f, 0.25f); + // if (ConfigurationHandler.drawLines) + RenderHelper.drawCuboidOutline(zero, size, sides, 0.0f, 0.75f, 1.0f, 0.25f); + } + + if (block != null && block.canRenderInPass(renderPass)) { + renderBlocks.renderBlockByRenderType(block, x, y, z); + } + } + } catch (Exception e) { + StructureLib.LOGGER.error("Failed to render block!", e); + } + } + } + } + + Tessellator.instance.draw(); + + this.minecraft.gameSettings.ambientOcclusion = ambientOcclusion; + } + + public static float ALPHA = 0.75f; + + public void renderTileEntities(int renderPass) { + if (renderPass != 0) { + return; + } + + IBlockAccess mcWorld = this.minecraft.theWorld; + + int x, y, z; + + GL11.glColor4f(1.0f, 1.0f, 1.0f, ALPHA); + + try { + for (TileEntity tileEntity : this.tileEntities) { + x = tileEntity.xCoord; + y = tileEntity.yCoord; + z = tileEntity.zCoord; + + // TODO: Rendering layer + // if (this.world.isRenderingLayer && this.world.renderingLayer != y) { + // continue; + // } + + final boolean isAirBlock = mcWorld.isAirBlock( + x + this.world.renderPosition.x, + y + this.world.renderPosition.y, + z + this.world.renderPosition.z); + + if (isAirBlock) { + TileEntitySpecialRenderer tileEntitySpecialRenderer = TileEntityRendererDispatcher.instance + .getSpecialRenderer(tileEntity); + if (tileEntitySpecialRenderer != null) { + try { + tileEntitySpecialRenderer.renderTileEntityAt(tileEntity, x, y, z, 0); + + OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); + GL11.glDisable(GL11.GL_TEXTURE_2D); + OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); + } catch (Exception e) { + StructureLib.LOGGER.error("Failed to render a tile entity!", e); + } + GL11.glColor4f(1.0f, 1.0f, 1.0f, ALPHA); + } + } + } + } catch (Exception ex) { + StructureLib.LOGGER.error("Failed to render tile entities!", ex); + } + } + + public static void setCanUpdate(boolean parCanUpdate) { + canUpdate = parCanUpdate; + } + + public static boolean getCanUpdate() { + return canUpdate; + } + + public void setDirty() { + this.needsUpdate = true; + } + + public boolean getDirty() { + return this.needsUpdate; + } + + public AxisAlignedBB getBoundingBox() { + return boundingBox; + } +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RendererStructureChunkComparator.java b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RendererStructureChunkComparator.java new file mode 100644 index 00000000..71cd819b --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/client/renderer/RendererStructureChunkComparator.java @@ -0,0 +1,31 @@ +package com.gtnewhorizon.structurelib.client.renderer; + +import java.util.Comparator; + +import org.joml.Vector3d; +import org.joml.Vector3i; + +public class RendererStructureChunkComparator implements Comparator { + + private final Vector3d position = new Vector3d(); + private final Vector3d renderPosition = new Vector3d(); + + @Override + public int compare(RendererStructureChunk RendererStructureChunk1, RendererStructureChunk RendererStructureChunk2) { + if (RendererStructureChunk1.isInFrustrum && !RendererStructureChunk2.isInFrustrum) { + return -1; + } else if (!RendererStructureChunk1.isInFrustrum && RendererStructureChunk2.isInFrustrum) { + return 1; + } else { + final double dist1 = position.distanceSquared(RendererStructureChunk1.centerPosition); + final double dist2 = position.distanceSquared(RendererStructureChunk2.centerPosition); + return Double.compare(dist1, dist2); + } + } + + public void setPosition(Vector3d playerPosition, Vector3i position) { + this.renderPosition.set(position); + this.position.set(playerPosition).sub(this.renderPosition.set(position)); + } + +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/world/StructurePreviewUpdater.java b/src/main/java/com/gtnewhorizon/structurelib/client/world/StructurePreviewUpdater.java new file mode 100644 index 00000000..162b1b82 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/client/world/StructurePreviewUpdater.java @@ -0,0 +1,73 @@ +package com.gtnewhorizon.structurelib.client.world; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.IWorldAccess; + +import org.joml.Vector3i; + +import com.gtnewhorizon.structurelib.ClientProxy; + +public class StructurePreviewUpdater implements IWorldAccess { + + public static final StructurePreviewUpdater INSTANCE = new StructurePreviewUpdater(); + + @Override + public void markBlockForUpdate(int x, int y, int z) { + markBlocksForUpdate(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1); + } + + @Override + public void markBlockForRenderUpdate(int x, int y, int z) { + markBlocksForUpdate(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1); + } + + @Override + public void markBlockRangeForRenderUpdate(int x0, int y0, int z0, int x1, int y1, int z1) { + markBlocksForUpdate(x0 - 1, y0 - 1, z0 - 1, x1 + 1, y1 + 1, z1 + 1); + } + + private final AxisAlignedBB box = AxisAlignedBB.getBoundingBox(0, 0, 0, 0, 0, 0); + + private void markBlocksForUpdate(int x0, int y0, int z0, int x1, int y1, int z1) { + final StructureWorld structure = ClientProxy.getStructureWorld(); + if (structure == null) return; + + final Vector3i loc = structure.getRenderLocation(); + box.setBounds(x0 - loc.x, y0 - loc.y, z0 - loc.z, x1 - loc.x, y1 - loc.y, z1 - loc.z); + // TODO: Update chunk renderers + + } + + @Override + public void playSound(String soundName, double x, double y, double z, float volume, float pitch) {} + + @Override + public void playSoundToNearExcept(EntityPlayer player, String soundName, double x, double y, double z, float volume, + float piatch) {} + + @Override + public void spawnParticle(final String type, double x, double y, double z, double velX, double velY, double velZ) {} + + @Override + public void onEntityCreate(Entity entity) {} + + @Override + public void onEntityDestroy(Entity entity) {} + + @Override + public void playRecord(String recordName, int x, int y, int z) {} + + @Override + public void broadcastSound(int id, int x, int y, int z, int par5) {} + + @Override + public void playAuxSFX(EntityPlayer player, int od, int x, int y, int z, int par6) {} + + @Override + public void destroyBlockPartially(int id, int x, int y, int z, int partialDamage) {} + + @Override + public void onStaticEntitiesChanged() {} +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/client/world/StructureWorld.java b/src/main/java/com/gtnewhorizon/structurelib/client/world/StructureWorld.java index 311b1322..30dd7623 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/client/world/StructureWorld.java +++ b/src/main/java/com/gtnewhorizon/structurelib/client/world/StructureWorld.java @@ -1,6 +1,8 @@ package com.gtnewhorizon.structurelib.client.world; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.UUID; import net.minecraft.block.Block; @@ -42,6 +44,7 @@ public class StructureWorld extends World { // Static variables public static final Vector3i PLACE_POSITION = new Vector3i(0, 64, 0); public static final int MAX_PLACE_ROUNDS = 2000; + public final Vector3i renderPosition = new Vector3i(0, 0, 0); private static final ISaveHandler STRUCTURE_SAVE_HANDLER = new StructureSaveHandler(); private static final WorldSettings WORLD_SETTINGS = new WorldSettings( @@ -52,7 +55,9 @@ public class StructureWorld extends World { WorldType.FLAT); // Instance variables - private StructureFakePlayer fakeMultiblockBuilder; + private boolean rendering = false; + private final StructureFakePlayer fakeMultiblockBuilder; + private final Vector3i renderLocation = new Vector3i(); public final LongSet placedBlocks = new LongOpenHashSet(); private final Vector3f minPos = new Vector3f(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE); @@ -60,15 +65,52 @@ public class StructureWorld extends World { private final Vector3f size = new Vector3f(); + public boolean isRendering() { + return rendering; + } + + public void setRendering(boolean rendering) { + rendering = rendering; + } + public StructureFakePlayer getFakeMultiblockBuilder() { return fakeMultiblockBuilder; } + public List getTileEntities() { + // TODO: Replace this with something less stupid + return new ArrayList<>(); + } + private void updateSize() { size.set(maxPos.x - minPos.x + 1, maxPos.y - minPos.y + 1, maxPos.z - minPos.z + 1); } + public int getWidth() { + return (int) size.x; + } + + public int getHeight() { + return (int) size.y; + } + + public int getLength() { + return (int) size.z; + } + + public Vector3i getRenderLocation() { + return renderLocation; + } + + public void setRenderLocation(Vector3i renderLocation) { + this.renderLocation.set(renderLocation); + } + + public void setRenderLocation(int x, int y, int z) { + this.renderLocation.set(x, y, z); + } + public Vector3f getSize() { return size; } diff --git a/src/main/resources/assets/structurelib/shaders/alpha.frag b/src/main/resources/assets/structurelib/shaders/alpha.frag new file mode 100644 index 00000000..155116b9 --- /dev/null +++ b/src/main/resources/assets/structurelib/shaders/alpha.frag @@ -0,0 +1,9 @@ +#version 120 + +uniform sampler2D texture; +uniform float alpha_multiplier; + +void main() { + vec4 tex = texture2D(texture, gl_TexCoord[0].xy) * gl_Color; + gl_FragColor = vec4(tex.r, tex.g, tex.b, tex.a * alpha_multiplier); +}