diff options
Diffstat (limited to 'src/main/java/makamys/neodymium')
24 files changed, 3558 insertions, 0 deletions
diff --git a/src/main/java/makamys/neodymium/LODMod.java b/src/main/java/makamys/neodymium/LODMod.java new file mode 100644 index 0000000..47c948b --- /dev/null +++ b/src/main/java/makamys/neodymium/LODMod.java @@ -0,0 +1,239 @@ +package makamys.neodymium; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; +import net.minecraftforge.client.event.EntityViewRenderEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.event.world.WorldEvent; + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.Mod.EventHandler; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.common.gameevent.TickEvent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import makamys.neodymium.renderer.LODRenderer; +import makamys.neodymium.util.SpriteUtil; + +@Mod(modid = LODMod.MODID, version = LODMod.VERSION) +public class LODMod +{ + public static final String MODID = "lodmod"; + public static final String VERSION = "0.0"; + + public static final Logger LOGGER = LogManager.getLogger("lodmod"); + + public static LODRenderer renderer; + + public static boolean enabled; + public static int chunkLoadsPerTick; + public static List<Class> blockClassBlacklist; + public static double fogStart; + public static double fogEnd; + public static double farPlaneDistanceMultiplier; + public static float maxSimpleMeshHeight; + public static boolean forceVanillaBiomeTemperature; + public static boolean hideUnderVanillaChunks; + public static boolean disableChunkMeshes; + public static boolean disableSimpleMeshes; + public static boolean saveMeshes; + public static boolean optimizeChunkMeshes; + public static int maxMeshesPerFrame; + public static int sortFrequency; + public static int gcRate; + public static int VRAMSize; + public static int debugPrefix; + + private File configFile; + + public static boolean fogEventWasPosted; + + public static boolean ofFastRender; + public static boolean enableFog; + + @EventHandler + public void preInit(FMLPreInitializationEvent event) + { + configFile = event.getSuggestedConfigurationFile(); + reloadConfig(); + } + + private void reloadConfig() { + Configuration config = new Configuration(configFile); + + config.load(); + enabled = config.get("General", "enabled", true).getBoolean(); + chunkLoadsPerTick = config.get("General", "chunkLoadsPerTick", 64).getInt(); + blockClassBlacklist = Arrays.stream(config.get("General", "blockClassBlacklist", "net.minecraft.block.BlockRotatedPillar;biomesoplenty.common.blocks.BlockBOPLog;gregapi.block.multitileentity.MultiTileEntityBlock").getString().split(";")) + .map(className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + fogStart = config.get("Fog", "fogStart", "0.4").getDouble(); + fogEnd = config.get("Fog", "fogEnd", "0.8").getDouble(); + farPlaneDistanceMultiplier = config.get("Fog", "farPlaneDistanceMultiplier", "1.0").getDouble(); + + maxSimpleMeshHeight = (float)config.get("Debug", "maxSimpleMeshHeight", 1000.0).getDouble(); + + forceVanillaBiomeTemperature = config.get("Simple mesh generation", "forceVanillaBiomeTemperature", true).getBoolean(); + + hideUnderVanillaChunks = config.getBoolean("hideUnderVanillaChunks", "render", true, ""); + disableChunkMeshes = config.getBoolean("disableChunkMeshes", "render", true, ""); + disableSimpleMeshes = config.getBoolean("disableSimpleMeshes", "render", false, ""); + optimizeChunkMeshes = config.getBoolean("optimizeChunkMeshes", "render", true, ""); + saveMeshes = config.getBoolean("saveMeshes", "render", false, ""); + maxMeshesPerFrame = config.getInt("maxMeshesPerFrame", "render", -1, -1, Integer.MAX_VALUE, ""); + sortFrequency = config.getInt("sortFrequency", "render", 1, 1, Integer.MAX_VALUE, ""); + gcRate = config.getInt("gcRate", "render", 1, 1, Integer.MAX_VALUE, "Maximum number of meshes to relocate each frame."); + VRAMSize = config.getInt("VRAMSize", "render", 1024, 1, Integer.MAX_VALUE, "VRAM buffer size (MB)."); + enableFog = config.getBoolean("enableFog", "render", true, ""); + debugPrefix = config.getInt("debugPrefix", "debug", Keyboard.KEY_F4, -1, Integer.MAX_VALUE, "This key has to be held down while pressing the debug keybinds. LWJGL keycode. Setting this to 0 will make the keybinds usable without holding anything else down. Setting this to -1 will disable debug keybinds entirely."); + + if(config.hasChanged()) { + config.save(); + } + } + + @EventHandler + public void init(FMLInitializationEvent event) + { + FMLCommonHandler.instance().bus().register(this); + MinecraftForge.EVENT_BUS.register(this); + } + + private void onPlayerWorldChanged(World newWorld) { + if(getRendererWorld() == null && newWorld != null) { + reloadConfig(); + if(enabled) { + SpriteUtil.init(); + } + } + if(renderer != null) { + renderer.destroy(); + renderer = null; + } + if(enabled && newWorld != null) { + renderer = new LODRenderer(newWorld); + } + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public void onWorldUnload(WorldEvent.Unload event) { + if(event.world == getRendererWorld()) { + onPlayerWorldChanged(null); + } + } + + @SubscribeEvent + public void onChunkLoad(ChunkEvent.Load event) { + if(!event.world.isRemote) return; + + if(isActive()) { + renderer.onChunkLoad(event); + } + } + + public static boolean isActive() { + return renderer != null && renderer.hasInited && !renderer.destroyPending; + } + + private World getRendererWorld() { + return renderer != null ? renderer.world : null; + } + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event) { + if(event.phase == TickEvent.Phase.START) { + EntityPlayer player = Minecraft.getMinecraft().thePlayer; + World world = player != null ? player.worldObj : null; + if(world != getRendererWorld()) { + onPlayerWorldChanged(world); + } + + if(MixinConfigPlugin.isOptiFinePresent()) { + try { + ofFastRender = (boolean)Class.forName("Config").getMethod("isFastRender").invoke(null); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException + | SecurityException | ClassNotFoundException e) { + // oops + } + } + } + } + + @SubscribeEvent + public void onServerTick(TickEvent.ServerTickEvent event) { + if(event.phase == TickEvent.Phase.START) { + if(isActive()) { + renderer.serverTick(); + } + } + } + + @SubscribeEvent + public void onRenderTick(TickEvent.RenderTickEvent event) { + if(event.phase == TickEvent.Phase.END) { + if(isActive()) { + renderer.onRenderTickEnd(); + } + } + } + + @SubscribeEvent + public void onRenderOverlay(RenderGameOverlayEvent event) { + FontRenderer fontRenderer = RenderManager.instance.getFontRenderer(); + if(isActive() && event.type == ElementType.TEXT && fontRenderer != null && Minecraft.getMinecraft().gameSettings.showDebugInfo) + { + Minecraft mc = Minecraft.getMinecraft(); + ScaledResolution scaledresolution = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + int w = scaledresolution.getScaledWidth(); + int h = scaledresolution.getScaledHeight(); + + int yOffset = 0; + for(String s : renderer.getDebugText()) { + fontRenderer.drawStringWithShadow(s, w - fontRenderer.getStringWidth(s) - 10, 80 + yOffset, 0xFFFFFF); + yOffset += 10; + } + } + } + + + @SubscribeEvent + public void onRenderFog(EntityViewRenderEvent.RenderFogEvent event) { + fogEventWasPosted = true; + } + + public static boolean shouldRenderVanillaWorld() { + return !isActive() || (isActive() && renderer.renderWorld && !renderer.rendererActive); + } + +} diff --git a/src/main/java/makamys/neodymium/MixinConfigPlugin.java b/src/main/java/makamys/neodymium/MixinConfigPlugin.java new file mode 100644 index 0000000..cc4bc30 --- /dev/null +++ b/src/main/java/makamys/neodymium/MixinConfigPlugin.java @@ -0,0 +1,72 @@ +package makamys.neodymium; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; + +import org.spongepowered.asm.lib.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +public class MixinConfigPlugin implements IMixinConfigPlugin { + + private static boolean isOptiFinePresent = MixinConfigPlugin.class.getResource("/optifine/OptiFineTweaker.class") != null; + + @Override + public void onLoad(String mixinPackage) { + // TODO Auto-generated method stub + + } + + @Override + public String getRefMapperConfig() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return true; + } + + @Override + public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) { + // TODO Auto-generated method stub + + } + + @Override + public List<String> getMixins() { + List<String> mixins = new ArrayList<>(); + mixins.addAll(Arrays.asList("MixinChunkCache", + "MixinEntityRenderer", + "MixinRenderGlobal", + "MixinWorldRenderer", + "MixinRenderBlocks")); + + if (isOptiFinePresent()) { + System.out.println("Detected OptiFine"); + mixins.add("MixinRenderGlobal_OptiFine"); + } + + return mixins; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + // TODO Auto-generated method stub + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + // TODO Auto-generated method stub + + } + + public static boolean isOptiFinePresent() { + return isOptiFinePresent; + } + +} diff --git a/src/main/java/makamys/neodymium/ducks/IWorldRenderer.java b/src/main/java/makamys/neodymium/ducks/IWorldRenderer.java new file mode 100644 index 0000000..4525cda --- /dev/null +++ b/src/main/java/makamys/neodymium/ducks/IWorldRenderer.java @@ -0,0 +1,13 @@ +package makamys.neodymium.ducks; + +import java.util.List; + +import org.spongepowered.asm.mixin.Mixin; + +import makamys.neodymium.renderer.ChunkMesh; +import net.minecraft.client.renderer.WorldRenderer; + +public interface IWorldRenderer { + public List<ChunkMesh> getChunkMeshes(); + public boolean isDrawn(); +} diff --git a/src/main/java/makamys/neodymium/mixin/MixinChunkCache.java b/src/main/java/makamys/neodymium/mixin/MixinChunkCache.java new file mode 100644 index 0000000..b4a7368 --- /dev/null +++ b/src/main/java/makamys/neodymium/mixin/MixinChunkCache.java @@ -0,0 +1,29 @@ +package makamys.neodymium.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import makamys.neodymium.LODMod; +import makamys.neodymium.renderer.FarChunkCache; +import makamys.neodymium.renderer.LODRenderer; +import net.minecraft.world.ChunkCache; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +@Mixin(ChunkCache.class) +abstract class MixinChunkCache { + + @Redirect(method = "<init>*", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getChunkFromChunkCoords(II)Lnet/minecraft/world/chunk/Chunk;")) + private Chunk redirectGetChunkFromChunkCoords(World world, int p1, int p2) { + Chunk chunk = world.getChunkFromChunkCoords(p1, p2); + if(LODMod.isActive() && FarChunkCache.class.isInstance(this.getClass()) && chunk.isEmpty()) { + Chunk myChunk = LODMod.renderer.getChunkFromChunkCoords(p1, p2); + if(myChunk != null) { + chunk = myChunk; + } + } + return chunk; + } + +} diff --git a/src/main/java/makamys/neodymium/mixin/MixinEntityRenderer.java b/src/main/java/makamys/neodymium/mixin/MixinEntityRenderer.java new file mode 100644 index 0000000..66d95ae --- /dev/null +++ b/src/main/java/makamys/neodymium/mixin/MixinEntityRenderer.java @@ -0,0 +1,35 @@ +package makamys.neodymium.mixin; + +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import makamys.neodymium.LODMod; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.EntityRenderer; +import net.minecraft.entity.EntityLivingBase; + +@Mixin(EntityRenderer.class) +abstract class MixinEntityRenderer { + + @Shadow + private float farPlaneDistance; + + @Inject(method = "setupCameraTransform", at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/EntityRenderer;farPlaneDistance:F", shift = At.Shift.AFTER, ordinal = 1)) + private void onConstructed(CallbackInfo ci) { + if(LODMod.isActive()) { + farPlaneDistance *= LODMod.renderer.getFarPlaneDistanceMultiplier(); + } + } + + @Inject(method = "setupFog", at = @At(value = "RETURN")) + private void afterSetupFog(int mode, float alpha, CallbackInfo ci) { + if(LODMod.isActive()) { + LODMod.renderer.afterSetupFog(mode, alpha, farPlaneDistance); + } + } +} diff --git a/src/main/java/makamys/neodymium/mixin/MixinRenderBlocks.java b/src/main/java/makamys/neodymium/mixin/MixinRenderBlocks.java new file mode 100644 index 0000000..0f8ff41 --- /dev/null +++ b/src/main/java/makamys/neodymium/mixin/MixinRenderBlocks.java @@ -0,0 +1,29 @@ +package makamys.neodymium.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import makamys.neodymium.LODMod; +import makamys.neodymium.renderer.FarChunkCache; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +@Mixin(RenderBlocks.class) +abstract class MixinRenderBlocks { + + @Redirect(method = "renderBlockLiquid", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;shouldSideBeRendered(Lnet/minecraft/world/IBlockAccess;IIII)Z")) + public boolean shouldSideBeRendered(Block block, IBlockAccess ba, int x, int y, int z, int w) { + if(LODMod.isActive()) { + return LODMod.renderer.shouldSideBeRendered(block, ba, x, y, z, w); + } else { + return block.shouldSideBeRendered(ba, x, y, z, w); + } + } + +} diff --git a/src/main/java/makamys/neodymium/mixin/MixinRenderGlobal.java b/src/main/java/makamys/neodymium/mixin/MixinRenderGlobal.java new file mode 100644 index 0000000..dc561a2 --- /dev/null +++ b/src/main/java/makamys/neodymium/mixin/MixinRenderGlobal.java @@ -0,0 +1,40 @@ +package makamys.neodymium.mixin; + +import java.nio.IntBuffer; + +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import makamys.neodymium.LODMod; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.entity.Entity; + +@Mixin(RenderGlobal.class) +abstract class MixinRenderGlobal { + + @Shadow + private WorldRenderer[] sortedWorldRenderers; + + @Redirect(method = "renderSortedRenderers", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;renderAllRenderLists(ID)V")) + private void redirectRenderAllRenderLists(RenderGlobal thiz, int p1, double p2) { + if(LODMod.shouldRenderVanillaWorld()) { + thiz.renderAllRenderLists(p1, p2); + } + } + + @Inject(method = "renderSortedRenderers", at = @At(value = "HEAD")) + public void preRenderSortedRenderers(int startRenderer, int numRenderers, int renderPass, double partialTickTime, CallbackInfoReturnable cir) { + if(LODMod.isActive()) { + LODMod.renderer.preRenderSortedRenderers(renderPass, partialTickTime, sortedWorldRenderers); + } + } +} diff --git a/src/main/java/makamys/neodymium/mixin/MixinRenderGlobal_OptiFine.java b/src/main/java/makamys/neodymium/mixin/MixinRenderGlobal_OptiFine.java new file mode 100644 index 0000000..dad164c --- /dev/null +++ b/src/main/java/makamys/neodymium/mixin/MixinRenderGlobal_OptiFine.java @@ -0,0 +1,25 @@ +package makamys.neodymium.mixin; + +import java.nio.IntBuffer; + +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import makamys.neodymium.LODMod; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.RenderGlobal; + +@Mixin(RenderGlobal.class) +abstract class MixinRenderGlobal_OptiFine { + + // for OptiFine's Fast Render option + @Redirect(method = "renderSortedRenderersFast", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glCallLists(Ljava/nio/IntBuffer;)V"), remap=false) + private void redirectRenderAllRenderLists(IntBuffer buffer) { + if(LODMod.shouldRenderVanillaWorld()) { + GL11.glCallLists(buffer); + } + } + +} diff --git a/src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java b/src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java new file mode 100644 index 0000000..47450c3 --- /dev/null +++ b/src/main/java/makamys/neodymium/mixin/MixinWorldRenderer.java @@ -0,0 +1,181 @@ +package makamys.neodymium.mixin; + +import java.util.ArrayList; +import java.util.List; + +import org.lwjgl.opengl.GL11; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import makamys.neodymium.LODMod; +import makamys.neodymium.ducks.IWorldRenderer; +import makamys.neodymium.renderer.ChunkMesh; +import makamys.neodymium.renderer.FarChunkCache; +import makamys.neodymium.renderer.FarWorldRenderer; +import makamys.neodymium.renderer.LODRenderer; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.ChunkCache; +import net.minecraft.world.World; + +@Mixin(WorldRenderer.class) +abstract class MixinWorldRenderer implements IWorldRenderer { + + @Shadow + public int posX; + @Shadow + public int posY; + @Shadow + public int posZ; + + @Shadow + private boolean isInFrustum; + @Shadow + public boolean[] skipRenderPass; + @Shadow + private int glRenderList; + + @Shadow + public boolean needsUpdate; + + boolean savedDrawnStatus; + + public List<ChunkMesh> chunkMeshes; + + @Redirect(method = "setPosition", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/RenderItem;renderAABB(Lnet/minecraft/util/AxisAlignedBB;)V")) + private void redirectRenderAABB(AxisAlignedBB p1) { + if(!FarWorldRenderer.class.isInstance(this.getClass())) { + RenderItem.renderAABB(p1); + } + } + + @Redirect(method = "updateRenderer", at = @At(value = "NEW", target = "Lnet/minecraft/world/ChunkCache;")) + private ChunkCache redirectConstructChunkCache(World p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8) { + if(!FarWorldRenderer.class.isInstance(this.getClass())) { + return new ChunkCache(p1, p2, p3, p4, p5, p6, p7, p8); + } else { + return new FarChunkCache(p1, p2, p3, p4, p5, p6, p7, p8); + } + } + + @Inject(method = "updateRenderer", at = @At(value = "HEAD")) + private void preUpdateRenderer(CallbackInfo ci) { + saveDrawnStatus(); + + if(LODMod.isActive()) { + if(needsUpdate) { + if(chunkMeshes != null) { + chunkMeshes.clear(); + } else { + chunkMeshes = new ArrayList<>(); + } + } else { + chunkMeshes = null; + } + } + } + + @Inject(method = "updateRenderer", at = @At(value = "RETURN")) + private void postUpdateRenderer(CallbackInfo ci) { + notifyIfDrawnStatusChanged(); + + if(LODMod.isActive()) { + if(chunkMeshes != null) { + LODMod.renderer.onWorldRendererPost(WorldRenderer.class.cast(this)); + chunkMeshes.clear(); + } + } + } + + @Inject(method = "postRenderBlocks", at = @At(value = "HEAD")) + private void prePostRenderBlocks(int pass, EntityLivingBase entity, CallbackInfo ci) { + if(LODMod.isActive() && !LODMod.disableChunkMeshes) { + if(chunkMeshes != null) { + chunkMeshes.add(ChunkMesh.fromTessellator(pass, WorldRenderer.class.cast(this), Tessellator.instance)); + } + } + } + + @Redirect(method = "postRenderBlocks", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/Tessellator;draw()I")) + private int redirectPostRenderBlocksDraw() { + if(!FarWorldRenderer.class.isInstance(this.getClass())) { + return Tessellator.instance.draw(); + } else { + Tessellator.instance.reset(); + return 0; + } + } + + // There's probably a nicer way to do this + + @Redirect(method = "postRenderBlocks", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glPopMatrix()V")) + private void redirectPostRenderBlocksGL1() { + if(!FarWorldRenderer.class.isInstance(this.getClass())) { + GL11.glPopMatrix(); + } + } + + @Redirect(method = "postRenderBlocks", at = @At(value = "INVOKE", target = "Lorg/lwjgl/opengl/GL11;glEndList()V")) + private void redirectPostRenderBlocksGL2() { + if(!FarWorldRenderer.class.isInstance(this.getClass())) { + GL11.glEndList(); + } + } + + // XXX this is inconsistent, Forge callbacks are preserved in postRenderBlocks but not preRenderBlocks + + @Inject(method = "preRenderBlocks", at = @At(value = "HEAD")) + private void preRenderBlocksInjector(CallbackInfo ci) { + if(FarWorldRenderer.class.isInstance(this.getClass())) { + Tessellator.instance.setTranslation((double)(-this.posX), (double)(-this.posY), (double)(-this.posZ)); + ci.cancel(); + } + } + + @Inject(method = "setDontDraw", at = @At(value = "HEAD")) + private void preSetDontDraw(CallbackInfo ci) { + if(LODMod.isActive()) { + LODMod.renderer.onWorldRendererChanged(WorldRenderer.class.cast(this), LODRenderer.WorldRendererChange.DELETED); + } + } + + @Override + public List<ChunkMesh> getChunkMeshes() { + return chunkMeshes; + } + + @Inject(method = "updateInFrustum", at = @At(value = "HEAD")) + private void preUpdateInFrustum(CallbackInfo ci) { + saveDrawnStatus(); + } + + @Inject(method = "updateInFrustum", at = @At(value = "RETURN")) + private void postUpdateInFrustum(CallbackInfo ci) { + notifyIfDrawnStatusChanged(); + } + + private void saveDrawnStatus() { + savedDrawnStatus = isDrawn(); + } + + private void notifyIfDrawnStatusChanged() { + boolean drawn = isDrawn(); + if(LODMod.isActive() && drawn != savedDrawnStatus) { + LODMod.renderer.onWorldRendererChanged(WorldRenderer.class.cast(this), drawn ? LODRenderer.WorldRendererChange.VISIBLE : LODRenderer.WorldRendererChange.INVISIBLE); + } + } + + @Override + public boolean isDrawn() { + return isInFrustum && (!skipRenderPass[0] || !skipRenderPass[1]); + } +} diff --git a/src/main/java/makamys/neodymium/renderer/ChunkMesh.java b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java new file mode 100644 index 0000000..6c4cd59 --- /dev/null +++ b/src/main/java/makamys/neodymium/renderer/ChunkMesh.java @@ -0,0 +1,455 @@ +package makamys.neodymium.renderer; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.lwjgl.BufferUtils; + +import makamys.neodymium.LODMod; +import makamys.neodymium.MixinConfigPlugin; +import makamys.neodymium.ducks.IWorldRenderer; +import makamys.neodymium.util.BufferWriter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.Entity; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagByteArray; +import net.minecraft.tileentity.TileEntity; + +public class ChunkMesh extends Mesh { + + Flags flags; + + // TODO move this somewhere else + List<String> nameList = (List<String>) ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).mapUploadedSprites.keySet().stream().collect(Collectors.toList()); + + public static int usedRAM = 0; + public static int instances = 0; + + public ChunkMesh(int x, int y, int z, Flags flags, int quadCount, ByteBuffer buffer, int pass) { + this.x = x; + this.y = y; + this.z = z; + this.flags = flags; + this.quadCount = quadCount; + this.pass = pass; |
