From 6794b5852481b102fc60503e8f7738780f9d08e6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 3 Mar 2018 14:31:10 +0100 Subject: [PATCH 01/12] Add .blend export --- .../com/replaymod/core/LoadingPlugin.java | 1 + .../com/replaymod/core/versions/MCVer.java | 7 + .../ScreenshotRenderer.java | 10 +- .../com/replaymod/render/RenderSettings.java | 4 +- .../render/blend/BlendFrameCapturer.java | 48 +++ .../render/blend/BlendMaterials.java | 70 +++++ .../render/blend/BlendMeshBuilder.java | 215 +++++++++++++ .../replaymod/render/blend/BlendState.java | 170 ++++++++++ .../com/replaymod/render/blend/Exporter.java | 10 + .../com/replaymod/render/blend/ToJson.java | 209 +++++++++++++ .../java/com/replaymod/render/blend/Util.java | 181 +++++++++++ .../replaymod/render/blend/data/DAction.java | 53 ++++ .../com/replaymod/render/blend/data/DId.java | 17 + .../replaymod/render/blend/data/DImage.java | 34 ++ .../render/blend/data/DMaterial.java | 70 +++++ .../replaymod/render/blend/data/DMesh.java | 295 ++++++++++++++++++ .../replaymod/render/blend/data/DObject.java | 270 ++++++++++++++++ .../render/blend/data/DPackedFile.java | 24 ++ .../replaymod/render/blend/data/DScene.java | 64 ++++ .../replaymod/render/blend/data/DTexture.java | 32 ++ .../render/blend/data/Serializer.java | 137 ++++++++ .../render/blend/exporters/ChunkExporter.java | 185 +++++++++++ .../blend/exporters/EntityExporter.java | 83 +++++ .../render/blend/exporters/ItemExporter.java | 111 +++++++ .../exporters/ModelRendererExporter.java | 106 +++++++ .../blend/exporters/ParticlesExporter.java | 142 +++++++++ .../render/blend/exporters/RenderState.java | 143 +++++++++ .../blend/exporters/TileEntityExporter.java | 102 ++++++ .../blend/mixin/MixinChunkRenderWorker.java | 30 ++ .../blend/mixin/MixinEffectRenderer.java | 46 +++ .../blend/mixin/MixinModelRenderer.java | 65 ++++ .../render/blend/mixin/MixinRenderGlobal.java | 60 ++++ .../render/blend/mixin/MixinRenderItem.java | 23 ++ .../blend/mixin/MixinRenderManager.java | 35 +++ .../MixinTileEntityRendererDispatcher.java | 32 ++ .../render/mixin/MixinEffectRenderer.java | 6 + .../render/processor/DummyProcessor.java | 10 + .../replaymod/render/rendering/Pipelines.java | 42 ++- .../render/rendering/VideoRenderer.java | 35 ++- .../mixins.render.blend.replaymod.json | 18 ++ versions/common.gradle | 2 + 41 files changed, 3180 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java create mode 100644 src/main/java/com/replaymod/render/blend/BlendMaterials.java create mode 100644 src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java create mode 100644 src/main/java/com/replaymod/render/blend/BlendState.java create mode 100644 src/main/java/com/replaymod/render/blend/Exporter.java create mode 100644 src/main/java/com/replaymod/render/blend/ToJson.java create mode 100644 src/main/java/com/replaymod/render/blend/Util.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DAction.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DId.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DImage.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DMaterial.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DMesh.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DObject.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DPackedFile.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DScene.java create mode 100644 src/main/java/com/replaymod/render/blend/data/DTexture.java create mode 100644 src/main/java/com/replaymod/render/blend/data/Serializer.java create mode 100644 src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java create mode 100644 src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java create mode 100644 src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java create mode 100644 src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java create mode 100644 src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java create mode 100644 src/main/java/com/replaymod/render/blend/exporters/RenderState.java create mode 100644 src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java create mode 100644 src/main/java/com/replaymod/render/processor/DummyProcessor.java create mode 100644 src/main/resources/mixins.render.blend.replaymod.json diff --git a/src/main/java/com/replaymod/core/LoadingPlugin.java b/src/main/java/com/replaymod/core/LoadingPlugin.java index a633a6bf..af5af130 100755 --- a/src/main/java/com/replaymod/core/LoadingPlugin.java +++ b/src/main/java/com/replaymod/core/LoadingPlugin.java @@ -18,6 +18,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin { MixinBootstrap.init(); Mixins.addConfiguration("mixins.recording.replaymod.json"); Mixins.addConfiguration("mixins.render.replaymod.json"); + Mixins.addConfiguration("mixins.render.blend.replaymod.json"); Mixins.addConfiguration("mixins.replay.replaymod.json"); Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json"); Mixins.addConfiguration("mixins.compat.shaders.replaymod.json"); diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 3c3f3a9b..0f2ed434 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -7,6 +7,8 @@ import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.multiplayer.ServerData; import net.minecraft.client.multiplayer.ServerList; import net.minecraft.client.multiplayer.WorldClient; @@ -236,6 +238,11 @@ public class MCVer { return chunk.getEntityLists(); } + @SuppressWarnings("unchecked") + public static List cubeList(ModelRenderer modelRenderer) { + return modelRenderer.cubeList; + } + @SuppressWarnings("unchecked") public static List playerEntities(World world) { return world.playerEntities; diff --git a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java index 6fe7af62..f7f29e77 100644 --- a/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java +++ b/src/main/java/com/replaymod/extras/advancedscreenshots/ScreenshotRenderer.java @@ -1,6 +1,7 @@ package com.replaymod.extras.advancedscreenshots; import com.replaymod.render.RenderSettings; +import com.replaymod.render.blend.BlendState; import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.hooks.ChunkLoadingRenderGlobal; import com.replaymod.render.rendering.Pipelines; @@ -27,8 +28,13 @@ public class ScreenshotRenderer implements RenderInfo { ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal); - Pipelines.newPipeline(settings.getRenderMethod(),this, - new ScreenshotWriter(settings.getOutputFile())).run(); + if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) { + BlendState.setState(new BlendState(settings.getOutputFile())); + Pipelines.newBlendPipeline(this).run(); + } else { + Pipelines.newPipeline(settings.getRenderMethod(), this, + new ScreenshotWriter(settings.getOutputFile())).run(); + } clrg.uninstall(); diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index 37977dda..60fff513 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -11,7 +11,7 @@ import java.io.File; @Data public class RenderSettings { public enum RenderMethod { - DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS; + DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS, BLEND; @Override public String toString() { @@ -36,6 +36,8 @@ public class RenderSettings { MKV_LOSSLESS("-an -c:v libx264 -preset ultrafast -qp 0 \"%FILENAME%\"", "mkv"), + BLEND(null, "blend"), + PNG("\"%FILENAME%-%06d.png\"", "png"); private final String preset; diff --git a/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java b/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java new file mode 100644 index 00000000..71378bc9 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java @@ -0,0 +1,48 @@ +package com.replaymod.render.blend; + +import com.replaymod.render.capturer.RenderInfo; +import com.replaymod.render.capturer.WorldRenderer; +import com.replaymod.render.frame.RGBFrame; +import com.replaymod.render.rendering.FrameCapturer; +import com.replaymod.render.utils.ByteBufferPool; +import net.minecraft.client.Minecraft; +import org.lwjgl.util.Dimension; + +import java.io.IOException; + +public class BlendFrameCapturer implements FrameCapturer { + protected final WorldRenderer worldRenderer; + protected final RenderInfo renderInfo; + protected int framesDone; + + public BlendFrameCapturer(WorldRenderer worldRenderer, RenderInfo renderInfo) { + this.worldRenderer = worldRenderer; + this.renderInfo = renderInfo; + } + + @Override + public boolean isDone() { + return framesDone >= renderInfo.getTotalFrames(); + } + + @Override + public RGBFrame process() { + if (framesDone == 0) { + BlendState.getState().setup(); + } + + renderInfo.updateForNextFrame(); + + BlendState.getState().preFrame(framesDone); + worldRenderer.renderWorld(Minecraft.getMinecraft().timer.renderPartialTicks, null); + BlendState.getState().postFrame(framesDone); + + return new RGBFrame(framesDone++, new Dimension(0, 0), ByteBufferPool.allocate(0)); + } + + @Override + public void close() throws IOException { + BlendState.getState().tearDown(); + BlendState.setState(null); + } +} diff --git a/src/main/java/com/replaymod/render/blend/BlendMaterials.java b/src/main/java/com/replaymod/render/blend/BlendMaterials.java new file mode 100644 index 00000000..4570d30b --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/BlendMaterials.java @@ -0,0 +1,70 @@ +package com.replaymod.render.blend; + +import com.replaymod.render.blend.data.DImage; +import com.replaymod.render.blend.data.DMaterial; +import com.replaymod.render.blend.data.DPackedFile; +import com.replaymod.render.blend.data.DTexture; +import net.minecraft.client.renderer.GLAllocation; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +public class BlendMaterials { + private final Map materials = new HashMap<>(); + + public DMaterial getActiveMaterial() { + int textureId = GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D); + DMaterial material = materials.get(textureId); + if (material == null) { + // Read raw image data from GL + int width = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH); + int height = GL11.glGetTexLevelParameteri(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT); + ByteBuffer buffer = GLAllocation.createDirectByteBuffer(width * height * 4); + GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); + + // Convert to BufferedImage + BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR); + byte[] data = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData(); + for (int i = 0; i < data.length; i += 4) { + data[i + 3] = buffer.get(); + data[i + 2] = buffer.get(); + data[i + 1] = buffer.get(); + data[i ] = buffer.get(); + } + + // Encode as png image + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + ImageIO.write(bufferedImage, "png", stream); + } catch (IOException e) { + throw new RuntimeException(e); // never happens unless ImageIO is bugged + } + byte[] bytes = stream.toByteArray(); + + // Wrap into blender structs + DImage image = new DImage(); + image.id.name = "texture.png"; + image.filePath = "texture.png"; + image.packedFiles.add(Pair.of("texture.png", new DPackedFile(bytes))); + + DTexture texture = new DTexture(); + texture.image = image; + + DMaterial.DMTex mTex = new DMaterial.DMTex(); + mTex.texture = texture; + + material = new DMaterial(); + material.textures.add(mTex); + materials.put(textureId, material); + } + return material; + } +} diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java new file mode 100644 index 00000000..fcbb8380 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -0,0 +1,215 @@ +package com.replaymod.render.blend; + +import com.replaymod.render.blend.data.DMaterial; +import com.replaymod.render.blend.data.DMesh; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Vector2f; +import org.lwjgl.util.vector.Vector3f; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.util.ArrayList; +import java.util.List; + +public class BlendMeshBuilder extends WorldRenderer { + private final DMesh mesh; + private final List vertices = new ArrayList<>(); + private final List uvs = new ArrayList<>(); + private final List colors = new ArrayList<>(); + private Vector3f offset = new Vector3f(0, 0, 0); + private boolean isDrawing; + private boolean wellBehaved; + private int mode; + private float u, v; + private int color = 0xffffffff; // Default not in parent class but probably set implicitly somewhere due to re-use + + public BlendMeshBuilder(DMesh mesh) { + super(0); + this.mesh = mesh; + } + + public void setWellBehaved(boolean wellBehaved) { + this.wellBehaved = wellBehaved; + } + + public void setOffset(Vector3f offset) { + this.offset = offset; + } + + @Override + public void startDrawing(int mode) { + if (isDrawing) { + if (!wellBehaved) { + // Someone probably finished drawing with the global instance instead of this one, + // let's just assume that what's happened and finish our last draw by ourselves + // (might miss correct texture though) + doFinish(); + } else { + throw new IllegalStateException("Already drawing!"); + } + } + this.isDrawing = true; + this.mode = mode; + + if (!wellBehaved) { + // In case the calling code finishes with Tessellator.getInstance().draw() + Tessellator.getInstance().getWorldRenderer().startDrawingQuads(); + } + } + + public void maybeFinishDrawing() { + if (isDrawing) { + doFinish(); + } + } + + @Override + public int finishDrawing() { + if (!isDrawing) { + throw new IllegalStateException("Not building!"); + } else { + if (!wellBehaved) { + Tessellator.getInstance().getWorldRenderer().finishDrawing(); + } + + doFinish(); + return -1; + } + } + + private void doFinish() { + this.isDrawing = false; + + DMaterial activeMaterial = BlendState.getState().getMaterials().getActiveMaterial(); + int materialSlot = mesh.materials.indexOf(activeMaterial); + if (materialSlot < 0) { + materialSlot = mesh.materials.size(); + mesh.materials.add(activeMaterial); + } + + switch (mode) { + case GL11.GL_TRIANGLES: + for (int i = 0; i < vertices.size(); i+=3) { + mesh.addTriangle( + vertices.get(i ), + vertices.get(i + 1), + vertices.get(i + 2), + uvs.get(i ), + uvs.get(i + 1), + uvs.get(i + 2), + colors.get(i ), + colors.get(i + 1), + colors.get(i + 2), + materialSlot + ); + } + break; + case GL11.GL_QUADS: + for (int i = 0; i < vertices.size(); i+=4) { + mesh.addQuad( + vertices.get(i ), + vertices.get(i + 1), + vertices.get(i + 2), + vertices.get(i + 3), + uvs.get(i ), + uvs.get(i + 1), + uvs.get(i + 2), + uvs.get(i + 3), + colors.get(i ), + colors.get(i + 1), + colors.get(i + 2), + colors.get(i + 3), + materialSlot + ); + } + break; + default: + throw new UnsupportedOperationException("Unsupported mode: " + mode); + } + } + + @Override + public void setTextureUV(double u, double v) { + this.u = (float) u; + this.v = (float) (1 - v); + } + + @Override + public void setColorRGBA(int r, int g, int b, int a) { + this.color = r | (g << 8) | (b << 16) | (a << 24); + } + + @Override + public void addVertex(double x, double y, double z) { + x -= offset.x; + y -= offset.y; + z -= offset.z; + vertices.add(new DMesh.Vertex((float) x, (float) -z, (float) y)); + uvs.add(new Vector2f(u, v)); + colors.add(color); + } + + @Override + @SuppressWarnings("unchecked") + public void addVertexData(int[] ints) { + ByteBuffer buffer = ByteBuffer.allocate(ints.length * 4).order(ByteOrder.nativeOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + intBuffer.put(ints); + + VertexFormat vertexFormat = getVertexFormat(); + int posOffset = -1, colorOffset = -1, uvOffset = -1; + List elements = vertexFormat.getElements(); + for (VertexFormatElement element : elements) { + switch (element.getUsage()) { + case POSITION: posOffset = element.getOffset(); break; + case COLOR: colorOffset = element.getOffset(); break; + case UV: if (element.getIndex() == 0) uvOffset = element.getOffset(); break; + } + } + if (posOffset == -1) throw new IllegalStateException("No position element in " + vertexFormat); + if (uvOffset == -1) throw new IllegalStateException("No uv element in " + vertexFormat); + + for (int offset = 0; offset < buffer.remaining(); offset += vertexFormat.getNextOffset()) { + // TODO doesn't check buffer element types (works for vanilla because they're always the same) + if (colorOffset != -1) { + color = buffer.getInt(offset + colorOffset); + } + setTextureUV( + buffer.getFloat(offset + uvOffset), + buffer.getFloat(offset + uvOffset + 4) + ); + addVertex( + buffer.getFloat(offset + posOffset ), + buffer.getFloat(offset + posOffset + 4), + buffer.getFloat(offset + posOffset + 8) + ); + } + } + + @Override + public int getVertexCount() { + return vertices.size(); + } + + public void putColorRGBA(int byteIndex, int r, int g, int b, int a) { + int color = r | (g << 8) | (b << 16) | (a << 24); + putColor(color, -1); // FIXME: reverse index calculation + } + + private void putColor(int color, int reverseIndex) { + colors.set(colors.size() - reverseIndex, color); + } + + public void putColor4(int color) { + for (int i = 0; i < 4; i++) { + putColor(color, i + 1); + } + } + + // FIXME overwrite putX and more +} diff --git a/src/main/java/com/replaymod/render/blend/BlendState.java b/src/main/java/com/replaymod/render/blend/BlendState.java new file mode 100644 index 00000000..2c7ba4f0 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/BlendState.java @@ -0,0 +1,170 @@ +package com.replaymod.render.blend; + +import com.replaymod.render.blend.data.DScene; +import com.replaymod.render.blend.data.Serializer; +import com.replaymod.render.blend.exporters.ChunkExporter; +import com.replaymod.render.blend.exporters.EntityExporter; +import com.replaymod.render.blend.exporters.ItemExporter; +import com.replaymod.render.blend.exporters.ParticlesExporter; +import com.replaymod.render.blend.exporters.RenderState; +import com.replaymod.render.blend.exporters.TileEntityExporter; +import net.minecraft.crash.CrashReport; +import net.minecraft.crash.CrashReportCategory; +import net.minecraft.util.ReportedException; +import org.apache.commons.io.output.NullOutputStream; +import org.blender.utils.BlenderFactory; +import org.cakelab.blender.io.BlenderFile; + +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; + +import static com.replaymod.render.ReplayModRender.LOGGER; + +// Note: +// - Chunk exporter currently assumes VBO are enabled and in use +public class BlendState implements Exporter { + private static BlendState currentState; + + public static void setState(BlendState state) { + currentState = state; + } + + public static BlendState getState() { + return currentState; + } + + private final List exporters = new ArrayList<>(); + private final BlenderFile blenderFile; + private final BlenderFactory factory; + private final DScene scene = new DScene(); + private final BlendMaterials materials = new BlendMaterials(); + + public BlendState(File file) throws IOException { + this.blenderFile = BlenderFactory.newBlenderFile(file); + this.factory = new BlenderFactory(blenderFile); + + RenderState renderState = new RenderState(this); + register(renderState); + register(new ChunkExporter()); + register(new EntityExporter(renderState)); + register(new TileEntityExporter(renderState)); + register(new ParticlesExporter(renderState)); + register(new ItemExporter(renderState)); + } + + public void register(Exporter exporter) { + exporters.add(exporter); + } + + public T get(Class clazz) { + for (Exporter exporter : exporters) { + if (clazz.isInstance(exporter)) { + return clazz.cast(exporter); + } + } + throw new NoSuchElementException("No exporter of type " + clazz); + } + + @Override + public void setup() { + for (Exporter exporter : exporters) { + try { + exporter.setup(); + } catch (IOException e) { + CrashReport report = CrashReport.makeCrashReport(e, "Setup of blend exporter"); + CrashReportCategory category = report.makeCategory("Exporter"); + category.addCrashSectionCallable("Exporter", exporter::toString); + throw new ReportedException(report); + } + } + } + + @Override + public void tearDown() { + for (Exporter exporter : exporters) { + try { + exporter.tearDown(); + } catch (IOException e) { + CrashReport report = CrashReport.makeCrashReport(e, "Tear down of blend exporter"); + CrashReportCategory category = report.makeCategory("Exporter"); + category.addCrashSectionCallable("Exporter", exporter::toString); + throw new ReportedException(report); + } + } + + try { + Serializer serializer = new Serializer(); + this.scene.serialize(serializer); + // TODO pre-configure render settings serializer.writeMajor(new Object(), new DId(BlockCodes.ID_REND)) + + //noinspection UseOfSystemOutOrSystemErr + PrintStream sysout = System.out; + try { + System.setOut(new PrintStream(new NullOutputStream())); + blenderFile.write(); + } finally { + System.setOut(sysout); + } + } catch (IOException e) { + LOGGER.error("Exception writing blend file: ", e); + } finally { + try { + blenderFile.close(); + } catch (IOException e) { + LOGGER.error("Exception closing blend file: ", e); + } + } + } + + @Override + public void preFrame(int frame) { + for (Exporter exporter : exporters) { + try { + exporter.preFrame(frame); + } catch (IOException e) { + CrashReport report = CrashReport.makeCrashReport(e, "Pre frame of blend exporter"); + CrashReportCategory category = report.makeCategory("Exporter"); + category.addCrashSectionCallable("Exporter", exporter::toString); + category.addCrashSection("Frame", frame); + throw new ReportedException(report); + } + } + } + + @Override + public void postFrame(int frame) { + for (Exporter exporter : exporters) { + try { + exporter.postFrame(frame); + } catch (IOException e) { + CrashReport report = CrashReport.makeCrashReport(e, "Post frame of blend exporter"); + CrashReportCategory category = report.makeCategory("Exporter"); + category.addCrashSectionCallable("Exporter", exporter::toString); + category.addCrashSection("Frame", frame); + throw new ReportedException(report); + } + } + + scene.endFrame = frame; + } + + public BlenderFile getBlenderFile() { + return blenderFile; + } + + public BlenderFactory getFactory() { + return factory; + } + + public DScene getScene() { + return scene; + } + + public BlendMaterials getMaterials() { + return materials; + } +} diff --git a/src/main/java/com/replaymod/render/blend/Exporter.java b/src/main/java/com/replaymod/render/blend/Exporter.java new file mode 100644 index 00000000..ce5f96c6 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/Exporter.java @@ -0,0 +1,10 @@ +package com.replaymod.render.blend; + +import java.io.IOException; + +public interface Exporter { + default void setup() throws IOException {} + default void tearDown() throws IOException {} + default void preFrame(int frame) throws IOException {} + default void postFrame(int frame) throws IOException {} +} diff --git a/src/main/java/com/replaymod/render/blend/ToJson.java b/src/main/java/com/replaymod/render/blend/ToJson.java new file mode 100644 index 00000000..063e0d41 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/ToJson.java @@ -0,0 +1,209 @@ +package com.replaymod.render.blend; + +import org.blender.utils.MainLib; +import org.cakelab.blender.generator.typemap.Renaming; +import org.cakelab.blender.io.BlenderFile; +import org.cakelab.blender.io.FileVersionInfo; +import org.cakelab.blender.io.block.Block; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.io.block.BlockTable; +import org.cakelab.blender.metac.CMetaModel; +import org.cakelab.blender.metac.CStruct; +import org.cakelab.blender.nio.CArrayFacade; +import org.cakelab.blender.nio.CFacade; +import org.cakelab.blender.nio.CPointer; +import org.cakelab.json.JSONArray; +import org.cakelab.json.JSONObject; +import org.cakelab.json.codec.JSONCodec; +import org.cakelab.json.codec.JSONCodecConfiguration; +import org.cakelab.json.codec.JSONCodecException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class ToJson { + + private static final String PACKAGE = "org.blender.dna"; + private static JSONCodec codec; + private static CMetaModel model; + private static BlenderFile blend; + private static BlockTable blockTable; + + public static void main(String[] args) throws IOException, JSONCodecException { + File fBlend = new File("/home/user/1.blend"); + //File fBlend = new File("test.blend"); + blend = new BlenderFile(fBlend); + + FileVersionInfo versions = blend.readFileGlobal(); + if (!MainLib.doVersionCheck(versions)) { + System.err.println("Warning: Conversion will probably fail due to version mismatch!"); + } + + blockTable = blend.getBlockTable(); + model = blend.getMetaModel(); + codec = new JSONCodec(new JSONCodecConfiguration(false)); + + JSONObject json = new JSONObject(); + JSONObject oHeader = createHeader(blend); + json.put("header", oHeader); + JSONArray aBlocks = new JSONArray(); + json.put("blocks", aBlocks); + for (Block b : blend.getBlocks()) { + addBlock(aBlocks, b); + } + blend.close(); + + File fJsonOut = new File(fBlend.getParentFile(), fBlend.getName().replace(".blend", ".json")); + FileOutputStream fout = new FileOutputStream(fJsonOut); + codec.encodeObject(json, fout); + fout.close(); + System.out.println("Finished"); + } + + private static JSONObject createHeader(BlenderFile blend) { + JSONObject oHeader = new JSONObject(); + oHeader.put("MAGIC", "BLENDER"); + oHeader.put("addressWidth", blend.getEncoding().getAddressWidth()); + oHeader.put("endianess", blend.getEncoding().getByteOrder().toString()); + oHeader.put("version", blend.getVersion().toString()); + return oHeader; + } + + private static void addBlock(JSONArray aBlocks, Block b) throws JSONCodecException, IOException { + JSONObject oBlock = new JSONObject(); + aBlocks.add(oBlock); + JSONObject header = (JSONObject) codec.encodeObjectJSON(b.header); + oBlock.put("header", header); + header.put("code", b.header.getCode().toString()); + CStruct struct = model.getStruct(b.header.getSdnaIndex()); + header.put("sdnaIndex", struct.getSignature() + "(" + b.header.getSdnaIndex() + ")"); + + System.out.print("[" + b.header.getAddress() + ", " + (b.header.getAddress() + b.header.getSize()) + "] "); + if (b.header.getCode().equals(BlockCodes.ID_DATA) && b.header.getSdnaIndex() == 0) { + System.out.println(b.header.getCode().toString() + ": Link(0) or undef"); + byte[] buffer = new byte[b.header.getSize()]; + b.data.readFully(buffer); + String str = toHexStr(buffer); + oBlock.put("raw", str); + int requiredSize = b.header.getCount() * struct.sizeof(blend.getEncoding().getAddressWidth()); + if (requiredSize == b.header.getSize()) { + addStruct(oBlock, b, struct); + } + } else { + System.out.println(b.header.getCode().toString() + ": " + struct.getSignature()); + addStruct(oBlock, b, struct); + } + } + + private static String toHexStr(byte[] buffer) { + StringBuffer str = new StringBuffer(); + for (byte v : buffer) { + String s = Integer.toHexString(v&0xff); + if (s.length() == 1) s = "0"+s; + str.append(s); + } + + return str.toString(); + } + + private static void addStruct(JSONObject oBlock, Block b, CStruct struct) { + if (b.header.getCount() == 1) { + oBlock.put(struct.getSignature(), createStruct(b, 0, struct)); + } else { + JSONArray aStructs = new JSONArray(); + oBlock.put(struct.getSignature() + "_array", aStructs); + for (int i = 0; i < b.header.getCount(); i++) { + aStructs.add(createStruct(b, i, struct)); + } + } + } + + private static Object createStruct(Block b, int index, CStruct struct) { + JSONObject oStruct = null; + + try { + Class cStruct = Class.forName(PACKAGE + "." + Renaming.mapStruct2Class(struct.getSignature())); + long address = b.header.getAddress() + index * struct.sizeof(blend.getEncoding().getAddressWidth()); + Constructor constructor = cStruct.getDeclaredConstructor(long.class, Block.class, BlockTable.class); + Object object = constructor.newInstance(address, b, blockTable); + + oStruct = (JSONObject) toJson(cStruct, object); + + } catch (Throwable e) { + oStruct = new JSONObject(); + e.printStackTrace(); + oStruct.put("error", e.getClass().getSimpleName() + ": " + e.getMessage()); + } + + return oStruct; + } + + private static Object toJson(Class type, Object value) throws Throwable { + try { + assert(value != null); + if (isPrimitive(type)) { + return codec.encodeObjectJSON(value); + } else if (value instanceof CArrayFacade){ + CArrayFacade carray = ((CArrayFacade)value); + JSONArray array = new JSONArray(); + boolean hasString = false; + for (int i = 0; i < carray.length(); i++) { + Object elem = carray.get(i); + if (elem instanceof Byte) { + hasString = true; + } + array.add(toJson(elem.getClass(), elem)); + } + if (hasString) { + JSONObject debugArray = new JSONObject(); + debugArray.put("str", carray.asString()); + debugArray.put("data", array); + return debugArray; + } else { + return array; + } + } else if (value instanceof CPointer) { + return ((CPointer)value).getAddress(); + } else if (value instanceof CFacade) { + JSONObject oStruct = new JSONObject(); + try { + for (Method getter : type.getDeclaredMethods()) { + if (getter.getName().startsWith("get")) { + Object result = getter.invoke(value); + Class rType = getter.getReturnType(); + oStruct.put(getter.getName(), toJson(rType, result)); + } + } + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof NullPointerException) { + throw (NullPointerException)cause; + } else { + throw e; + } + } + return oStruct; + } else { + return codec.encodeObjectJSON(value); + } + } catch (NullPointerException e) { + // caught when data from an address, that was assumed to + // be stored in the file, was not found. This happens in two cases: + // 1. The sdna index stored in the block header is not correct. In many + // cases index 0 (Link) is used for raw data. + // 2. A pointer references non-persistent data which was not stored in the file. + JSONObject o = new JSONObject(); + o.put("error", "data not found"); + return o; + } + } + + private static boolean isPrimitive(Class type) { + return type.isPrimitive() || type.equals(String.class); + } + +} diff --git a/src/main/java/com/replaymod/render/blend/Util.java b/src/main/java/com/replaymod/render/blend/Util.java new file mode 100644 index 00000000..f438f87e --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/Util.java @@ -0,0 +1,181 @@ +package com.replaymod.render.blend; + +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import org.blender.dna.Link; +import org.blender.dna.ListBase; +import org.blender.utils.BlenderFactory; +import org.cakelab.blender.nio.CPointer; +import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.Matrix3f; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Quaternion; +import org.lwjgl.util.vector.Vector3f; + +import java.io.IOException; +import java.nio.FloatBuffer; + +public class Util { + public static BlenderFactory factory() { + return BlendState.getState().getFactory(); + } + + public static int align4(int size) { + return align(size, 4); + } + + public static int align(int size, int alignment) { + int misalignment = size % alignment; + if (misalignment > 0) { + return size + (alignment - misalignment); + } else { + return size; + } + } + + private static FloatBuffer floatBuffer = GLAllocation.createDirectFloatBuffer(16); + public static Matrix4f getGlMatrix(int matrix) { + floatBuffer.clear(); + GL11.glGetFloat(matrix, floatBuffer); + floatBuffer.rewind(); + Matrix4f mat = new Matrix4f(); + mat.load(floatBuffer); + return mat; + } + + public static Matrix4f getGlModelViewMatrix() { + return getGlMatrix(GL11.GL_MODELVIEW_MATRIX); + } + + public static Matrix4f getGlTextureMatrix() { + return getGlMatrix(GL11.GL_TEXTURE_MATRIX); + } + + public static boolean isGlTextureMatrixIdentity() { + Matrix4f mat = getGlTextureMatrix(); + // Assumes that glLoadIdentity uses positive zero floating point value (seems to be the case, at least on Mesa) + return mat.m00 == 1 && mat.m01 == 0 && mat.m02 == 0 && mat.m03 == 0 && + mat.m10 == 0 && mat.m11 == 1 && mat.m12 == 0 && mat.m13 == 0 && + mat.m20 == 0 && mat.m21 == 0 && mat.m22 == 1 && mat.m23 == 0 && + mat.m30 == 0 && mat.m31 == 0 && mat.m32 == 0 && mat.m33 == 1; + } + + public static Vector3f scaleFromMat(Matrix4f mat, Vector3f scale) { + if (scale == null) scale = new Vector3f(); + scale.set( + new Vector3f(mat.m00, mat.m01, mat.m02).length(), + new Vector3f(mat.m10, mat.m11, mat.m12).length(), + new Vector3f(mat.m20, mat.m21, mat.m22).length() + ); + Matrix3f m3 = new Matrix3f(); + m3.m00 = mat.m00; + m3.m01 = mat.m01; + m3.m02 = mat.m02; + m3.m10 = mat.m10; + m3.m11 = mat.m11; + m3.m12 = mat.m12; + m3.m20 = mat.m20; + m3.m21 = mat.m21; + m3.m22 = mat.m22; + if (m3.determinant() < 0) { + scale.x = -scale.x; + } + return scale; + } + + public static void scaleMat3(Matrix4f mat, Vector3f scale) { + mat.m00 /= scale.x; + mat.m01 /= scale.x; + mat.m02 /= scale.x; + mat.m10 /= scale.y; + mat.m11 /= scale.y; + mat.m12 /= scale.y; + mat.m20 /= scale.z; + mat.m21 /= scale.z; + mat.m22 /= scale.z; + } + + public static Vector3f posFromMat(Matrix4f mat, Vector3f pos) { + if (pos == null) pos = new Vector3f(); + pos.set(mat.m30, mat.m31, mat.m32); + return pos; + } + + public static Quaternion rotFromMat(Matrix4f mat, Quaternion rot) { + Quaternion result = Quaternion.setFromMatrix(mat, rot); + result.normalise(); + return result; + } + + public static void glToBlend(Vector3f vec) { + float tmp = vec.y; + vec.y = -vec.z; + vec.z = tmp; + } + + public static void glScaleToBlend(Vector3f vec) { + float tmp = vec.y; + vec.y = vec.z; + vec.z = tmp; + } + + public static void glToBlend(Quaternion q) { + float tmp = q.y; + q.y = -q.z; + q.z = tmp; + q.w = -q.w; + } + + public static Vector3f rotate(Quaternion rot, Vector3f vec, Vector3f dest) { + if (dest == null) dest = new Vector3f(); + Quaternion vecQ = new Quaternion(vec.x, vec.y, vec.z, 0); + Quaternion.mul(rot, vecQ, vecQ); + Quaternion.mulInverse(vecQ, rot, vecQ); + dest.set(vecQ); + return dest; + } + + // Original CPointer.plus method is broken, this one works with any non-negative numbers + public static CPointer plus(CPointer lhs, int rhs) throws IOException { + while (rhs > 0) { + lhs = lhs.plus(1); // 1 is the only value that can be passed to the original plus + rhs--; + } + return lhs; + } + + public static void insert(ListBase list, CPointer element) throws IOException { + CPointer oldFirst = list.getFirst().cast(Link.class); + if (oldFirst.isValid()) { + oldFirst.get().setPrev(element); + } + element.get().setNext(oldFirst); + list.setFirst(element.cast(Object.class)); + if (list.getLast().isNull()) { + list.setLast(element.cast(Object.class)); + } + } + + public static String getTileEntityId(TileEntity tileEntity) { + NBTTagCompound nbt = new NBTTagCompound(); + tileEntity.writeToNBT(nbt); + return nbt.getString("id"); + } + + public interface IOCallable { + R call() throws IOException; + } + + public interface IOConsumer { + void accept(T t) throws IOException; + } + + public interface IOBiConsumer { + void accept(T t, U u) throws IOException; + } + + public interface IOFunction { + R apply(T t) throws IOException; + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DAction.java b/src/main/java/com/replaymod/render/blend/data/DAction.java new file mode 100644 index 00000000..e99fddbc --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DAction.java @@ -0,0 +1,53 @@ +package com.replaymod.render.blend.data; + +import org.blender.dna.BezTriple; +import org.blender.dna.FCurve; +import org.blender.dna.bAction; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CArrayFacade; +import org.cakelab.blender.nio.CPointer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class DAction { + public final DId id = new DId(BlockCodes.ID_AC); + public List curves = new ArrayList<>(); + + public CPointer serialize(Serializer serializer) throws IOException { + return serializer.maybeMajor(this, id, bAction.class, () -> { + return bAction -> { + serializer.writeDataList(FCurve.class, bAction.getCurves(), curves.size(), (i, fCurve) -> { + DFCurve dfCurve = curves.get(i); + fCurve.setRna_path(serializer.writeString0(dfCurve.rnaPath)); + fCurve.setArray_index(dfCurve.rnaArrayIndex); + fCurve.setTotvert(dfCurve.keyframes.size()); + fCurve.setBezt(serializer.writeData(BezTriple.class, dfCurve.keyframes.size(), (j, fBezTriple) -> { + DKeyframe dKeyframe = dfCurve.keyframes.get(j); + fBezTriple.setIpo((byte) dKeyframe.interpolationType.ordinal()); + CArrayFacade vec = fBezTriple.getVec().get(1); + vec.set(0, (float) dKeyframe.frame); + vec.set(1, dKeyframe.value); + })); + }); + }; + }); + } + + public static class DFCurve { + public String rnaPath; + public int rnaArrayIndex; + public List keyframes = new ArrayList<>(); + } + + public static class DKeyframe { + public InterpolationType interpolationType = InterpolationType.CONSTANT; + public int frame; + public float value; + } + + public enum InterpolationType { + CONSTANT, LINEAR; + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DId.java b/src/main/java/com/replaymod/render/blend/data/DId.java new file mode 100644 index 00000000..287329d6 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DId.java @@ -0,0 +1,17 @@ +package com.replaymod.render.blend.data; + +import org.cakelab.blender.io.util.Identifier; + +public class DId { + public final Identifier code; + public String name; + + public DId(Identifier code) { + this.code = code; + } + + public DId(Identifier code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DImage.java b/src/main/java/com/replaymod/render/blend/data/DImage.java new file mode 100644 index 00000000..52b6f68b --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DImage.java @@ -0,0 +1,34 @@ +package com.replaymod.render.blend.data; + +import org.apache.commons.lang3.tuple.Pair; +import org.blender.dna.Image; +import org.blender.dna.ImagePackedFile; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CPointer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class DImage { + public final DId id = new DId(BlockCodes.ID_IM); + public String filePath; + public List> packedFiles = new ArrayList<>(); + + public CPointer serialize(Serializer serializer) throws IOException { + return serializer.maybeMajor(this, id, Image.class, () -> { + return image -> { + image.getName().fromString(String.valueOf(filePath)); + image.setSource((short) 1); + image.getColorspace_settings().getName().fromString("sRGB"); + image.setAspx(1); + image.setAspy(1); + serializer.writeDataList(ImagePackedFile.class, image.getPackedfiles(), packedFiles.size(), (i, pf) -> { + Pair pair = packedFiles.get(i); + pf.getFilepath().fromString(pair.getLeft()); + pf.setPackedfile(pair.getRight().serialize(serializer)); + }); + }; + }); + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DMaterial.java b/src/main/java/com/replaymod/render/blend/data/DMaterial.java new file mode 100644 index 00000000..3474ebef --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DMaterial.java @@ -0,0 +1,70 @@ +package com.replaymod.render.blend.data; + +import com.replaymod.render.blend.Util; +import org.blender.dna.MTex; +import org.blender.dna.Material; +import org.blender.dna.Tex; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CArrayFacade; +import org.cakelab.blender.nio.CPointer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class DMaterial { + public final DId id = new DId(BlockCodes.ID_MA); + public List textures = new ArrayList<>(); + + public CPointer serialize(Serializer serializer) throws IOException { + return serializer.maybeMajor(this, id, Material.class, () -> { + List>> textures = new ArrayList<>(); + for (DMTex texture : this.textures) { + textures.add(texture.serialize(serializer)); + } + return material -> { + material.setMode( + 0x10000 /* MA_TRANSP */ | 0x40 /* MA_ZTRANS */ | 0x80 /* MA_VERTEXCOLP */ + ); + material.setAlpha(1); + material.setRef(1); + material.setR(1); + material.setG(1); + material.setB(1); + CArrayFacade> mTexPointers = material.getMtex(); + for (int i = 0; i < textures.size(); i++) { + mTexPointers.set(i, textures.get(i).call()); + } + }; + }); + } + + public static class DMTex { + public DTexture texture; + + public Util.IOCallable> serialize(Serializer serializer) throws IOException { + CPointer texture = this.texture.serialize(serializer); + return () -> { + MTex mTex = serializer.writeData(MTex.class); + mTex.setTex(texture); + mTex.getUvname().fromString("UVMap"); + mTex.setMapto((short) ( + 0x1 /* MAP_COL */ | 0x80 /* MAP_ALPHA */ + )); + mTex.setBlendtype((short) 0x1 /* MTEX_MUL */); + mTex.setColfac(1); + mTex.setAlphafac(1); + mTex.setDef_var(1); + mTex.setTexco((short) 16); + mTex.setProjx((byte) 1); + mTex.setProjy((byte) 2); + mTex.setProjz((byte) 3); + CArrayFacade size = mTex.getSize(); + size.set(0, 1f); + size.set(1, 1f); + size.set(2, 1f); + return mTex.__io__addressof(); + }; + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DMesh.java b/src/main/java/com/replaymod/render/blend/data/DMesh.java new file mode 100644 index 00000000..70aaf174 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DMesh.java @@ -0,0 +1,295 @@ +package com.replaymod.render.blend.data; + +import net.minecraft.util.Vec3i; +import org.blender.dna.CustomData; +import org.blender.dna.CustomDataLayer; +import org.blender.dna.Image; +import org.blender.dna.MEdge; +import org.blender.dna.MFace; +import org.blender.dna.MLoop; +import org.blender.dna.MLoopCol; +import org.blender.dna.MLoopUV; +import org.blender.dna.MPoly; +import org.blender.dna.MTexPoly; +import org.blender.dna.MVert; +import org.blender.dna.Material; +import org.blender.dna.Mesh; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CArrayFacade; +import org.cakelab.blender.nio.CPointer; +import org.lwjgl.util.vector.Vector2f; +import org.lwjgl.util.vector.Vector3f; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class DMesh { + public final DId id = new DId(BlockCodes.ID_ME); + public final List vertices = new ArrayList<>(); + public final List edges = new ArrayList<>(); + public final List faces = new ArrayList<>(); + public final List loops = new ArrayList<>(); + public final List polys = new ArrayList<>(); + public final List materials = new ArrayList<>(); + + public CPointer serialize(Serializer serializer) throws IOException { + return serializer.maybeMajor(this, id, Mesh.class, () -> { + List> materials = new ArrayList<>(); + List> images = new ArrayList<>(); + for (DMaterial material : this.materials) { + materials.add(material.serialize(serializer)); + images.add(material.textures.isEmpty() ? null : material.textures.get(0).texture.image.serialize(serializer)); + } + return mesh -> { + mesh.setDrawflag(3 /* Edges & Faces */); + CArrayFacade> mat = serializer.writeDataPArray(Material.class, materials.size(), materials::get); + mesh.setMat(mat); + mesh.setTotcol((short) materials.size()); + + if (!vertices.isEmpty()) { + CArrayFacade mVerts = serializer.writeData(MVert.class, vertices.size(), + (i, mVert) -> vertices.get(i).serialize(mVert)); + + CustomDataLayer vDataLayer = serializer.writeData(CustomDataLayer.class); + vDataLayer.setType(0 /* CD_MVERT */); + vDataLayer.setData(mVerts.cast(Object.class)); + + CustomData vData = mesh.getVdata(); + vData.setMaxlayer(1); + vData.setTotlayer(1); + vData.setLayers(vDataLayer.__io__addressof()); + + mesh.setMvert(mVerts); + mesh.setTotvert(vertices.size()); + } + if (!edges.isEmpty()) { + CArrayFacade mEdges = serializer.writeData(MEdge.class, edges.size(), + (i, mEdge) -> edges.get(i).serialize(mEdge)); + + CustomDataLayer eDataLayer = serializer.writeData(CustomDataLayer.class); + eDataLayer.setType(3 /* CD_MEDGE */); + eDataLayer.setData(mEdges.cast(Object.class)); + + CustomData eData = mesh.getEdata(); + eData.setMaxlayer(1); + eData.setTotlayer(1); + eData.setLayers(eDataLayer.__io__addressof()); + + mesh.setMedge(mEdges); + mesh.setTotedge(edges.size()); + + + mesh.setMface(serializer.writeData(MFace.class, faces.size(), + (i, mFace) -> faces.get(i).serialize(mFace))); + mesh.setTotface(faces.size()); + } + if (!loops.isEmpty()) { + CArrayFacade mLoops = serializer.writeData(MLoop.class, loops.size(), + (i, mLoop) -> loops.get(i).serialize(mLoop)); + CArrayFacade mLoopUVs = serializer.writeData(MLoopUV.class, loops.size(), + (i, mLoopUV) -> loops.get(i).serialize(mLoopUV)); + CArrayFacade mLoopCols = serializer.writeData(MLoopCol.class, loops.size(), + (i, mLoopCol) -> loops.get(i).serialize(mLoopCol)); + + CArrayFacade dataLayers = serializer.writeData(CustomDataLayer.class, 3); + int i = 0; + + CustomDataLayer luvDataLayer = dataLayers.get(i++); + luvDataLayer.setType(16 /* CD_MLOOPUV */); + luvDataLayer.setData(mLoopUVs.cast(Object.class)); + + CustomDataLayer lcolDataLayer = dataLayers.get(i++); + lcolDataLayer.setType(17 /* CD_MLOOPCOL */); + lcolDataLayer.setData(mLoopCols.cast(Object.class)); + + CustomDataLayer lDataLayer = dataLayers.get(i++); + lDataLayer.setType(26 /* CD_MLOOP */); + lDataLayer.setData(mLoops.cast(Object.class)); + + CustomData lData = mesh.getLdata(); + lData.setMaxlayer(i); + lData.setTotlayer(i); + lData.setLayers(dataLayers); + + mesh.setMloop(mLoops); + mesh.setMloopuv(mLoopUVs); + mesh.setTotloop(loops.size()); + } + if (!polys.isEmpty()) { + CArrayFacade mPolys = serializer.writeData(MPoly.class, polys.size(), + (i, mPoly) -> polys.get(i).serialize(mPoly)); + CArrayFacade mTexPolys = serializer.writeData(MTexPoly.class, polys.size(), + (i, mTexPoly) -> mTexPoly.setTpage(images.get(polys.get(i).materialSlot))); + + CArrayFacade dataLayers = serializer.writeData(CustomDataLayer.class, mTexPolys != null ? 2 : 1); + int i = 0; + + if (mTexPolys != null) { + CustomDataLayer pTexDataLayer = dataLayers.get(i++); + pTexDataLayer.getName().fromString("UVMap"); + pTexDataLayer.setType(15 /* CD_MTEXPOLY */); + pTexDataLayer.setData(mTexPolys.cast(Object.class)); + } + + CustomDataLayer pDataLayer = dataLayers.get(i++); + pDataLayer.setType(25 /* CD_MPOLY */); + pDataLayer.setData(mPolys.cast(Object.class)); + + CustomData pData = mesh.getPdata(); + pData.setMaxlayer(i); + pData.setTotlayer(i); + pData.setLayers(dataLayers); + + mesh.setMpoly(mPolys); + mesh.setMtpoly(mTexPolys); + mesh.setTotpoly(polys.size()); + } + }; + }); + } + + public void addTriangle(DMesh.Vertex v1, DMesh.Vertex v2, DMesh.Vertex v3, + Vector2f uv1, Vector2f uv2, Vector2f uv3, + int c1, int c2, int c3, + int materialSlot) { + int vOffset = vertices.size(); + int eOffset = edges.size(); + int lOffset = loops.size(); + vertices.add(v1); + vertices.add(v2); + vertices.add(v3); + edges.add(new Edge(vOffset , vOffset + 1)); + edges.add(new Edge(vOffset + 1, vOffset + 2)); + edges.add(new Edge(vOffset + 2, vOffset )); + loops.add(new Loop(vOffset , eOffset , uv1.x, uv1.y, c1)); + loops.add(new Loop(vOffset + 1, eOffset + 1, uv2.x, uv2.y, c2)); + loops.add(new Loop(vOffset + 2, eOffset + 2, uv3.x, uv3.y, c3)); + polys.add(new Poly(lOffset, 3, materialSlot)); + } + + public void addQuad(DMesh.Vertex v1, DMesh.Vertex v2, DMesh.Vertex v3, DMesh.Vertex v4, + Vector2f uv1, Vector2f uv2, Vector2f uv3, Vector2f uv4, + int c1, int c2, int c3, int c4, + int materialSlot) { + int vOffset = vertices.size(); + int eOffset = edges.size(); + int lOffset = loops.size(); + vertices.add(v1); + vertices.add(v2); + vertices.add(v3); + vertices.add(v4); + edges.add(new Edge(vOffset , vOffset + 1)); + edges.add(new Edge(vOffset + 1, vOffset + 2)); + edges.add(new Edge(vOffset + 2, vOffset + 3)); + edges.add(new Edge(vOffset + 3, vOffset )); + loops.add(new Loop(vOffset , eOffset , uv1.x, uv1.y, c1)); + loops.add(new Loop(vOffset + 1, eOffset + 1, uv2.x, uv2.y, c2)); + loops.add(new Loop(vOffset + 2, eOffset + 2, uv3.x, uv3.y, c3)); + loops.add(new Loop(vOffset + 3, eOffset + 3, uv4.x, uv4.y, c4)); + polys.add(new Poly(lOffset, 4, materialSlot)); + } + + public static class Vertex { + public Vector3f pos; + public Vec3i norm = Vec3i.NULL_VECTOR; + + public Vertex(float x, float y, float z) { + this.pos = new Vector3f(x, y, z); + } + + public void serialize(MVert mVert) throws IOException { + CArrayFacade pos = mVert.getCo(); + pos.set(0, this.pos.x); + pos.set(1, this.pos.y); + pos.set(2, this.pos.z); + CArrayFacade norm = mVert.getNo(); + norm.set(0, (short) this.norm.getX()); + norm.set(1, (short) this.norm.getY()); + norm.set(2, (short) this.norm.getZ()); + } + } + + public static class Edge { + public int v1, v2; + + public Edge(int v1, int v2) { + this.v1 = v1; + this.v2 = v2; + } + + public void serialize(MEdge mEdge) throws IOException { + mEdge.setV1(v1); + mEdge.setV2(v2); + } + } + + public static class Loop { + public int vertex, edge; + public float u, v; + public int col; + + public Loop(int vertex, int edge, + float u, float v, + int col) { + this.vertex = vertex; + this.edge = edge; + this.u = u; + this.v = v; + this.col = col; + } + + public void serialize(MLoop mLoop) throws IOException { + mLoop.setV(vertex); + mLoop.setE(edge); + } + + public void serialize(MLoopUV mLoop) throws IOException { + CArrayFacade uv = mLoop.getUv(); + uv.set(0, u); + uv.set(1, v); + } + + public void serialize(MLoopCol mLoop) throws IOException { + mLoop.setR((byte) ((col ) & 0xff)); + mLoop.setG((byte) ((col >> 8) & 0xff)); + mLoop.setB((byte) ((col >> 16) & 0xff)); + mLoop.setA((byte) ((col >> 24) & 0xff)); + } + } + + public static class Poly { + public int loopStart, size; + public short materialSlot; + + public Poly(int loopStart, int size, int materialSlot) { + this.loopStart = loopStart; + this.size = size; + this.materialSlot = (short) materialSlot; + } + + public void serialize(MPoly mPoly) throws IOException { + mPoly.setLoopstart(loopStart); + mPoly.setTotloop(size); + mPoly.setMat_nr(materialSlot); + } + } + + public static class Face { + public int v1, v2, v3, v4; + + public Face(int v1, int v2, int v3, int v4) { + this.v1 = v1; + this.v2 = v2; + this.v3 = v3; + this.v4 = v4; + } + + public void serialize(MFace mFace) throws IOException { + mFace.setV1(v1); + mFace.setV2(v2); + mFace.setV3(v3); + mFace.setV4(v4); + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DObject.java b/src/main/java/com/replaymod/render/blend/data/DObject.java new file mode 100644 index 00000000..2ea96831 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DObject.java @@ -0,0 +1,270 @@ +package com.replaymod.render.blend.data; + +import com.replaymod.render.blend.Util; +import org.blender.dna.AnimData; +import org.blender.dna.BlenderObject; +import org.blender.dna.Material; +import org.blender.dna.Mesh; +import org.blender.dna.bAction; +import org.blender.dna.bConstraint; +import org.blender.dna.bTrackToConstraint; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CArrayFacade; +import org.cakelab.blender.nio.CPointer; +import org.lwjgl.util.vector.Quaternion; +import org.lwjgl.util.vector.Vector3f; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class DObject { + public final DId id = new DId(BlockCodes.ID_OB); + public Vector3f loc = new Vector3f(0, 0, 0); + public Vector3f scale = new Vector3f(1, 1, 1); + public Quaternion rot = new Quaternion(); + private DObject parent; + private List children = new ArrayList<>(); + private List unmodifiableChildren; + public DAction action; + public DMesh mesh; + public Type type; + public int layers = 1; + public DObject pointAt; + public int lastFrame; + private int lastVisibleFrame = -2; + + public DObject(Type type) { + this.type = type; + } + + public DObject(DMesh mesh) { + this(Type.OB_MESH); + this.mesh = mesh; + } + + public boolean isValid() { + return true; + } + + public void setVisible(int frame) { + if (frame < lastVisibleFrame) throw new IllegalStateException("Already at frame " + lastVisibleFrame); + if (lastVisibleFrame < frame - 1) { + if (lastVisibleFrame < 0) { + if (frame > 0) { + keyframe("hide", 0, 0, 1); + } + } else { + keyframe("hide", 0, lastVisibleFrame + 1, 1); + } + keyframe("hide", 0, frame, 0); + } + lastVisibleFrame = frame; + } + + public void setParent(DObject parent) { + if (this.parent != null) { + this.parent.children.remove(this); + } + this.parent = parent; + parent.children.add(this); + } + + public DObject getParent() { + return parent; + } + + public List getChildren() { + if (unmodifiableChildren == null) { + unmodifiableChildren = Collections.unmodifiableList(children); + } + return unmodifiableChildren; + } + + public void keyframeLocRotScale(int frame) { + keyframeLoc(frame); + keyframeRot(frame); + keyframeScale(frame); + } + + public void keyframeLoc(int frame) { + keyframe("location", frame, loc); + } + + public void keyframeRot(int frame) { + keyframe("rotation_quaternion", frame, rot); + } + + public void keyframeScale(int frame) { + keyframe("scale", frame, scale); + } + + public void keyframe(String rnaPath, int frame, Quaternion q) { + keyframe(rnaPath, 0, frame, q.w); + keyframe(rnaPath, 1, frame, q.x); + keyframe(rnaPath, 2, frame, q.y); + keyframe(rnaPath, 3, frame, q.z); + } + + public void keyframe(String rnaPath, int frame, Vector3f vec) { + keyframe(rnaPath, 0, frame, vec.x); + keyframe(rnaPath, 1, frame, vec.y); + keyframe(rnaPath, 2, frame, vec.z); + } + + public void keyframe(String rnaPath, int rnaArrayIndex, int frame, float value) { + if (frame < 0) return; + DAction.DKeyframe keyframe = new DAction.DKeyframe(); + keyframe.frame = frame; + keyframe.value = value; + keyframe(rnaPath, rnaArrayIndex, keyframe, rnaPath.startsWith("hide")); + if (rnaPath.equals("hide")) { + keyframe("hide_render", rnaArrayIndex, frame, value); + } + } + + public void keyframe(String rnaPath, int rnaArrayIndex, DAction.DKeyframe keyframe, boolean constant) { + if (action == null) { + action = new DAction(); + } + DAction.DFCurve theCurve = null; + for (DAction.DFCurve curve : action.curves) { + if (curve.rnaArrayIndex == rnaArrayIndex && curve.rnaPath.equals(rnaPath)) { + theCurve = curve; + break; + } + } + if (theCurve == null) { + theCurve = new DAction.DFCurve(); + theCurve.rnaPath = rnaPath; + theCurve.rnaArrayIndex = rnaArrayIndex; + action.curves.add(theCurve); + } + keyframe.interpolationType = constant ? DAction.InterpolationType.CONSTANT : DAction.InterpolationType.LINEAR; + if (constant) { + if (!theCurve.keyframes.isEmpty()) { + DAction.DKeyframe prev = theCurve.keyframes.get(theCurve.keyframes.size() - 1); + if (Math.abs(prev.value - keyframe.value) < 1e-4) { + return; + } + } + } else { + if (theCurve.keyframes.size() >= 2) { + DAction.DKeyframe prev = theCurve.keyframes.get(theCurve.keyframes.size() - 1); + DAction.DKeyframe prev2 = theCurve.keyframes.get(theCurve.keyframes.size() - 2); + float m = (prev.value - prev2.value) / (prev.frame - prev2.frame); + float interpolatedValue = prev.value + m * (keyframe.frame - prev.frame); + if (Math.abs(interpolatedValue - keyframe.value) < 1e-4) { + theCurve.keyframes.remove(theCurve.keyframes.size() - 1); + } + } + } + theCurve.keyframes.add(keyframe); + } + + public CPointer serialize(Serializer serializer) throws IOException { + return serializer.maybeMajor(this, id, BlenderObject.class, () -> { + if (lastVisibleFrame >= 0) { + keyframe("hide", 0, lastVisibleFrame + 1, 1); + } + + CPointer parent = this.parent == null ? null : this.parent.serialize(serializer); + CPointer mesh = this.mesh == null ? null : this.mesh.serialize(serializer); + CPointer action = this.action == null ? null : this.action.serialize(serializer); + CPointer pointAt = this.pointAt == null ? null : this.pointAt.serialize(serializer); + + return object -> { + object.setParent(parent); + if (parent != null) { + CArrayFacade> parentinv = object.getParentinv(); + parentinv.get(0).set(0, 1f); + parentinv.get(1).set(1, 1f); + parentinv.get(2).set(2, 1f); + parentinv.get(3).set(3, 1f); + } + if (mesh != null) { + object.setData(mesh.cast(Object.class)); + Mesh meshObj = mesh.get(); + short totcol = meshObj.getTotcol(); + if (totcol > 0) { + byte[] matbits = new byte[totcol]; + Arrays.fill(matbits, (byte) 1); + object.setMatbits(serializer.writeBytes(matbits)); + object.setMat(serializer.writeDataPArray(Material.class, totcol, i -> Util.plus(meshObj.getMat(), i).get())); + object.setTotcol(totcol); + } + } + object.setType((short) type.ordinal()); + object.setLay(layers); + object.setDt((byte) 5); + CArrayFacade loc = object.getLoc(); + loc.set(0, this.loc.x); + loc.set(1, this.loc.y); + loc.set(2, this.loc.z); + CArrayFacade size = object.getSize(); + size.set(0, scale.x); + size.set(1, scale.y); + size.set(2, scale.z); + CArrayFacade quat = object.getQuat(); + quat.set(0, rot.w); + quat.set(1, rot.x); + quat.set(2, rot.y); + quat.set(3, rot.z); + CArrayFacade dquat = object.getDquat(); + dquat.set(0, 1f); + dquat.set(1, 0f); + dquat.set(2, 0f); + dquat.set(3, 0f); + + object.getDscale().fromArray(new float[]{1, 1, 1}); + + AnimData animData = serializer.writeData(AnimData.class); + animData.setAction(action); + object.setAdt(animData.__io__addressof()); + + if (pointAt != null) { + serializer.writeDataList(bConstraint.class, object.getConstraints(), 1, (i, bConstraint) -> { + bConstraint.setEnforce(1); + bConstraint.setType((short) 2 /* CONSTRAINT_TYPE_TRACKTO */); + bTrackToConstraint constraint = serializer.writeData(bTrackToConstraint.class); + constraint.setTar(pointAt); + constraint.setReserved1(1 /* TRACK_Y */); + constraint.setReserved2(2 /* UP_Z */); + bConstraint.setData(constraint.__io__addressof().cast(Object.class)); + }); + } + }; + }); + } + + public enum Type { + OB_EMPTY, + OB_MESH, + OB_CURVE, + OB_SURF, + OB_FONT, + OB_MBALL, + OB_6, + OB_7, + OB_8, + OB_9, + OB_LAMP, + OB_CAMERA, + OB_SPEAKER, + OB_13, + OB_14, + OB_15, + OB_16, + OB_17, + OB_18, + OB_19, + OB_20, + OB_WAVE, + OB_LATTICE, + OB_23, + OB_24, + OB_ARMATURE + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DPackedFile.java b/src/main/java/com/replaymod/render/blend/data/DPackedFile.java new file mode 100644 index 00000000..a5460827 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DPackedFile.java @@ -0,0 +1,24 @@ +package com.replaymod.render.blend.data; + +import org.blender.dna.PackedFile; +import org.cakelab.blender.nio.CPointer; + +import java.io.IOException; + +public class DPackedFile { + public byte[] data; + + public DPackedFile() {} + + public DPackedFile(byte[] data) { + this.data = data; + } + + public CPointer serialize(Serializer serializer) throws IOException { + PackedFile packedFile = serializer.writeData(PackedFile.class); + packedFile.setSize(data.length); + packedFile.setSeek(0); + packedFile.setData(serializer.writeBytes(data).cast(Object.class)); + return packedFile.__io__addressof(); + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DScene.java b/src/main/java/com/replaymod/render/blend/data/DScene.java new file mode 100644 index 00000000..ad5d8e23 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DScene.java @@ -0,0 +1,64 @@ +package com.replaymod.render.blend.data; + +import org.blender.dna.Base; +import org.blender.dna.BlenderObject; +import org.blender.dna.RenderData; +import org.blender.dna.Scene; +import org.blender.dna.ToolSettings; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CPointer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public class DScene { + public final DId id = new DId(BlockCodes.ID_SCE, "Scene"); + public final List base = new ArrayList<>(); + public int endFrame; + + private Set findAllObjects(DObject curr, Set set) { + for (DObject child : curr == null ? base : curr.getChildren()) { + if (child.isValid()) { + findAllObjects(child, set); + set.add(child); + } + } + return set; + } + + public CPointer serialize(Serializer serializer) throws IOException { + return serializer.maybeMajor(this, id, Scene.class, () -> { + Set allObjects = findAllObjects(null, new LinkedHashSet<>()); + List> bases = new ArrayList<>(allObjects.size()); + for (DObject dObject : allObjects) { + bases.add(dObject.serialize(serializer)); + } + return scene -> { + serializer.writeDataList(Base.class, scene.getBase(), bases.size(), (i, base) -> { + CPointer objPointer = bases.get(i); + base.setLay(objPointer.get().getLay()); + base.setObject(objPointer); + }); + + RenderData renderData = scene.getR(); + renderData.setXsch(1920); + renderData.setYsch(1080); + renderData.setSize((short) 100); + renderData.setXasp(1); + renderData.setYasp(1); + renderData.setTilex(64); + renderData.setTiley(64); + renderData.setEfra(endFrame); + renderData.setFrame_step(1); + renderData.setFramapto(100); + renderData.setImages(100); + + ToolSettings toolSettings = serializer.writeData(ToolSettings.class); + scene.setToolsettings(toolSettings.__io__addressof()); + }; + }); + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/DTexture.java b/src/main/java/com/replaymod/render/blend/data/DTexture.java new file mode 100644 index 00000000..a7273627 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/DTexture.java @@ -0,0 +1,32 @@ +package com.replaymod.render.blend.data; + +import org.blender.dna.Image; +import org.blender.dna.Tex; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CPointer; + +import java.io.IOException; + +public class DTexture { + public final DId id = new DId(BlockCodes.ID_TE); + public DImage image; + + public CPointer serialize(Serializer serializer) throws IOException { + return serializer.maybeMajor(this, id, Tex.class, () -> { + CPointer image = this.image.serialize(serializer); + return tex -> { + tex.setIma(image); + tex.setType((short) 8 /* TEX_IMAGE */); + tex.setImaflag((short) 2 /* TEX_USEALPHA */); + tex.setCropxmax(1); + tex.setCropymax(1); + tex.setRfac(1); + tex.setGfac(1); + tex.setBfac(1); + tex.setBright(1); + tex.setContrast(1); + tex.setSaturation(1); + }; + }); + } +} diff --git a/src/main/java/com/replaymod/render/blend/data/Serializer.java b/src/main/java/com/replaymod/render/blend/data/Serializer.java new file mode 100644 index 00000000..63b28a50 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/data/Serializer.java @@ -0,0 +1,137 @@ +package com.replaymod.render.blend.data; + +import com.replaymod.render.blend.Util; +import com.replaymod.render.blend.Util.IOBiConsumer; +import com.replaymod.render.blend.Util.IOCallable; +import com.replaymod.render.blend.Util.IOConsumer; +import org.blender.dna.ID; +import org.blender.dna.Link; +import org.blender.dna.ListBase; +import org.cakelab.blender.io.block.BlockCodes; +import org.cakelab.blender.nio.CArrayFacade; +import org.cakelab.blender.nio.CFacade; +import org.cakelab.blender.nio.CPointer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static com.replaymod.render.blend.Util.align4; +import static com.replaymod.render.blend.Util.factory; +import static org.cakelab.blender.io.block.BlockCodes.ID_DATA; + +public class Serializer { + private final Map> serialized = new HashMap<>(); + private final Set usedNames = new HashSet<>(); + + public CPointer getMajor(Object obj, Class clazz) { + CPointer pointer = serialized.get(obj); + if (pointer == null) { + return null; + } + return pointer.cast(clazz); + } + + public CPointer writeMajor(Object obj, DId id, Class clazz) throws IOException { + if (serialized.containsKey(obj)) { + throw new IllegalStateException("Object " + obj + " already serialized."); + } + + T val = factory().newCStructBlock(id.code, clazz); + CPointer pointer = CFacade.__io__addressof(val); + + serialized.put(obj, pointer.cast(Object.class)); + + if (id.code != ID_DATA) { + ID asID = pointer.cast(ID.class).get(); + String name = id.code.toString().substring(0, 2) + id.name; + String fullName = name; + int i = 0; + while (usedNames.contains(fullName)) { + fullName = name + "." + i; + i++; + } + usedNames.add(fullName); + asID.getName().fromString(fullName); + } + + return pointer; + } + + public CPointer maybeMajor(Object obj, DId id, Class clazz, IOCallable> prepare) throws IOException { + CPointer result = getMajor(obj, clazz); + if (result == null) { + IOConsumer configure = prepare.call(); + result = writeMajor(obj, id, clazz); + configure.accept(result.get()); + } + return result; + } + + public CArrayFacade writeString0(String str) throws IOException { + byte[] bytes = (str + '\0').getBytes(); + CArrayFacade pointer = factory().newCArrayBlock(BlockCodes.ID_DATA, Byte.class, align4(bytes.length)); + pointer.fromArray(bytes); + return pointer; + } + + public CPointer writeBytes(byte[] bytes) throws IOException { + CArrayFacade pointer = factory().newCArrayBlock(BlockCodes.ID_DATA, Byte.class, align4(bytes.length)); + pointer.fromArray(bytes); + return pointer; + } + + public T writeData(Class clazz) throws IOException { + return factory().newCStructBlock(ID_DATA, clazz); + } + + public CArrayFacade writeData(Class clazz, int count) throws IOException { + return factory().newCStructBlock(ID_DATA, clazz, count); + } + + public CArrayFacade writeData(Class clazz, int count, IOBiConsumer forElem) throws IOException { + if (count == 0) return null; + CArrayFacade arrayFacade = writeData(clazz, count); + CPointer pointer = arrayFacade; + for (int i = 0; i < count; i++) { + forElem.accept(i, pointer.get()); + pointer = Util.plus(pointer, 1); + } + return arrayFacade; + } + + public CArrayFacade> writeDataPArray(Class clazz, int count, Util.IOFunction> forElem) throws IOException { + if (count == 0) return null; + CArrayFacade> arrayFacade = factory().newCPointerBlock(ID_DATA, new Class[]{CPointer.class, clazz}, count); + for (int i = 0; i < count; i++) { + arrayFacade.set(i, forElem.apply(i)); + } + return arrayFacade; + } + + public void writeDataList(Class clazz, ListBase listBase, int size, IOBiConsumer forElem) throws IOException { + CPointer prevPointer = null; + Link prev = null; + for (int i = 0; i < size; i++) { + CPointer pointer = CFacade.__io__addressof(writeData(clazz)); + CPointer linkPointer = pointer.cast(Link.class); + Link linkElem = linkPointer.get(); + if (prevPointer == null) { + listBase.setFirst(pointer.cast(Object.class)); + } else { + prev.setNext(linkPointer); + linkElem.setPrev(prevPointer); + } + + forElem.accept(i, pointer.get()); + + prevPointer = linkPointer; + prev = linkElem; + } + if (prevPointer != null) { + listBase.setLast(prevPointer.cast(Object.class)); + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java new file mode 100644 index 00000000..c6f28601 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java @@ -0,0 +1,185 @@ +package com.replaymod.render.blend.exporters; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.Exporter; +import com.replaymod.render.blend.data.DMaterial; +import com.replaymod.render.blend.data.DMesh; +import com.replaymod.render.blend.data.DObject; +import com.replaymod.replaystudio.us.myles.ViaVersion.util.ReflectionUtil; +import lombok.SneakyThrows; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.chunk.CompiledChunk; +import net.minecraft.client.renderer.chunk.RenderChunk; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.vertex.VertexBuffer; +import net.minecraft.util.BlockPos; +import net.minecraft.util.EnumWorldBlockLayer; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL15; +import org.lwjgl.util.vector.Vector2f; +import org.lwjgl.util.vector.Vector3f; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ChunkExporter implements Exporter { + private final Map chunkObjects = new HashMap<>(); + private final Map> chunkLayerObjects = new HashMap<>(); + private final List> chunks = new ArrayList<>(); + private DObject chunksObject; + private DMaterial material; + private int frame; + + public void addChunkUpdate(RenderChunk chunk, EnumWorldBlockLayer layer) { + chunks.add(Pair.of(chunk, layer)); + } + + @Override + @SneakyThrows + public void setup() throws IOException { + + Minecraft mc = Minecraft.getMinecraft(); + @SuppressWarnings("unchecked") + List renderInfos = mc.renderGlobal.renderInfos; + for (RenderGlobal.ContainerLocalRenderInformation renderInfo : renderInfos) { + RenderChunk renderChunk = ReflectionUtil.get(renderInfo, "renderChunk", RenderChunk.class); // SneakyThrows + CompiledChunk compiledChunk = renderChunk.getCompiledChunk(); + if (!compiledChunk.isEmpty()) { + for (EnumWorldBlockLayer layer : EnumWorldBlockLayer.values()) { + addChunkUpdate(renderChunk, layer); + } + } + } + + chunksObject = new DObject(DObject.Type.OB_EMPTY); + chunksObject.id.name = "Chunks"; + chunksObject.layers = 1 << 1; + BlendState.getState().getScene().base.add(chunksObject); + } + + @Override + public void tearDown() throws IOException { + chunks.clear(); + chunkObjects.clear(); + chunksObject = null; + } + + @Override + public void preFrame(int frame) throws IOException { + this.frame = frame; + } + + @Override + public void postFrame(int frame) throws IOException { + Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture); + material = BlendState.getState().getMaterials().getActiveMaterial(); + + for (Pair pair : chunks) { + RenderChunk chunk = pair.getLeft(); + EnumWorldBlockLayer layer = pair.getRight(); + DObject chunkObject = chunkObjects.get(chunk.getPosition()); + if (chunkObject == null) { + chunkObject = buildChunkObject(chunk); + chunkObjects.put(chunk.getPosition(), chunkObject); + chunkLayerObjects.put(chunk.getPosition(), new EnumMap<>(EnumWorldBlockLayer.class)); + } + DObject layerObject = buildChunkLayerObject(chunkObject, chunk, layer); + if (layerObject == null) continue; + Map layerObjects = chunkLayerObjects.get(chunk.getPosition()); + DObject oldLayerObject = layerObjects.get(layer); + if (oldLayerObject != null) { + oldLayerObject.keyframe("hide", 0, frame, 1f); + } + if (frame > 0) { + layerObject.keyframe("hide", 0, frame - 1, 1f); + layerObject.keyframe("hide", 0, frame, 0f); + } else { + layerObject.keyframe("hide", 0, frame, 0f); + } + layerObjects.put(layer, layerObject); + } + chunks.clear(); + } + + private DObject buildChunkObject(RenderChunk renderChunk) { + BlockPos pos = renderChunk.getPosition(); + DObject chunkObject = new DObject(DObject.Type.OB_EMPTY); + chunkObject.setParent(chunksObject); + chunkObject.id.name = "Chunk[" + pos.getX()/16 + "/" + pos.getY()/16 + "/" + pos.getZ()/16 + "]"; + chunkObject.loc = new Vector3f(pos.getX(), -pos.getZ(), pos.getY()); + return chunkObject; + } + + private DObject buildChunkLayerObject(DObject chunkObject, RenderChunk renderChunk, EnumWorldBlockLayer layer) { + VertexBuffer vertexBuffer = renderChunk.getVertexBufferByLayer(layer.ordinal()); + if (vertexBuffer == null) return null; + + DObject layerObject = new DObject(buildChunkLayerMesh(vertexBuffer)); + layerObject.setParent(chunkObject); + layerObject.id.name = chunkObject.id.name + " - " + layer + " - Frame " + frame; + return layerObject; + } + + private DMesh buildChunkLayerMesh(VertexBuffer vertexBuffer) { + vertexBuffer.bindBuffer(); + int size = GL15.glGetBufferParameteri(OpenGlHelper.GL_ARRAY_BUFFER, GL15.GL_BUFFER_SIZE); + ByteBuffer byteBuffer = GLAllocation.createDirectByteBuffer(size); + GL15.glGetBufferSubData(OpenGlHelper.GL_ARRAY_BUFFER, 0, byteBuffer); + vertexBuffer.unbindBuffer(); + + DMesh mesh = new DMesh(); + mesh.materials.add(material); + DMesh.Vertex v1 = null, v2 = null, v3 = null; + Vector2f uv1 = new Vector2f(), + uv2 = new Vector2f(), + uv3 = new Vector2f(), + uv4 = new Vector2f(); + int c1 = 0, c2 = 0, c3 = 0; + for (int i = 0; i < size / STRIDE; i++) { + // See VboRenderList.setupArrayPointers for offsets + DMesh.Vertex vert = new DMesh.Vertex( + byteBuffer.getFloat(STRIDE * i), + -byteBuffer.getFloat(STRIDE * i + 8), + byteBuffer.getFloat(STRIDE * i + 4) + ); + float u = byteBuffer.getFloat(STRIDE * i + 16); + float v = 1 - byteBuffer.getFloat(STRIDE * i + 20); + int c = byteBuffer.getInt(STRIDE * i + 12); + // TODO tex, norm, etc. + if (v1 == null) { + v1 = vert; + uv1.set(u, v); + c1 = c; + } else if (v2 == null) { + v2 = vert; + uv2.set(u, v); + c2 = c; + } else if (v3 == null) { + v3 = vert; + uv3.set(u, v); + c3 = c; + } else { + uv4.set(u, v); + mesh.addQuad( + v1, v2, v3, vert, + uv1, uv2, uv3, uv4, + c1, c2, c3, c, + 0 + ); + v1 = v2 = v3 = null; + } + } + + return mesh; + } + + private static final int STRIDE = 28; +} diff --git a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java new file mode 100644 index 00000000..1fa342e8 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java @@ -0,0 +1,83 @@ +package com.replaymod.render.blend.exporters; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.Exporter; +import com.replaymod.render.blend.data.DObject; +import lombok.SneakyThrows; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector3f; + +import java.io.IOException; +import java.util.IdentityHashMap; +import java.util.Map; + +import static com.replaymod.render.blend.Util.getGlModelViewMatrix; + +public class EntityExporter implements Exporter { + private final Minecraft mc = Minecraft.getMinecraft(); + private final RenderState renderState; + private DObject entitiesObject; + private Map entityObjects; + + public EntityExporter(RenderState renderState) { + this.renderState = renderState; + } + + @Override + @SneakyThrows + public void setup() throws IOException { + entitiesObject = new DObject(DObject.Type.OB_EMPTY); + entitiesObject.id.name = "Entities"; + entitiesObject.layers = 1 << 1; + BlendState.getState().getScene().base.add(entitiesObject); + + entityObjects = new IdentityHashMap<>(); + } + + public void preEntitiesRender() { + Matrix4f modelView = getGlModelViewMatrix(); + // Entities are rendered relative to the viewer location. + // We however want our Entities object to not move when the viewer does, + // so we position it at 0/0/0 and instead have the entities themselves move more + Matrix4f.translate(new Vector3f( + (float) -mc.getRenderManager().viewerPosX, + (float) -mc.getRenderManager().viewerPosY, + (float) -mc.getRenderManager().viewerPosZ + ), modelView, modelView); + renderState.push(entitiesObject, modelView); + } + + public void postEntitiesRender() { + renderState.pop(); + } + + public void preRender(Entity entity, double dx, double dy, double dz, float yaw, float renderPartialTicks) { + DObject entityObject = entityObjects.get(entity); + if (entityObject == null) { + entityObject = new DObject(DObject.Type.OB_EMPTY); + entityObject.setParent(renderState.peekObject()); + entityObject.id.name = entity.getName(); + entityObjects.put(entity, entityObject); + } + renderState.pushObject(entityObject); + + // Normally the entity renderer will translate to dx/dy/dz but we want that translation outside of + // the entity object (on the entity object itself). + // So, we translate there, then store the model-view-matrix and then translate back to let the + // renderer translate there again. + // Instead of actually translating, we just add the translation on the current model-view-matrix. + Matrix4f modelView = getGlModelViewMatrix(); + Matrix4f.translate(new Vector3f((float) dx, (float) dy, (float) dz), modelView, modelView); + renderState.pushModelView(modelView); + renderState.applyLastModelViewTransformToObject(); + + entityObject.keyframeLocRotScale(renderState.getFrame()); + entityObject.setVisible(renderState.getFrame()); + } + + public void postRender(Entity entity, double dx, double dy, double dz, float yaw, float renderPartialTicks) { + renderState.pop(); + } +} diff --git a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java new file mode 100644 index 00000000..c420ef03 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java @@ -0,0 +1,111 @@ +package com.replaymod.render.blend.exporters; + +import com.replaymod.render.blend.BlendMeshBuilder; +import com.replaymod.render.blend.Exporter; +import com.replaymod.render.blend.data.DMesh; +import com.replaymod.render.blend.data.DObject; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.resources.model.IBakedModel; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.client.model.pipeline.LightUtil; + +import java.util.List; + +public class ItemExporter implements Exporter { + private final RenderState renderState; + + public ItemExporter(RenderState renderState) { + this.renderState = renderState; + } + + public void onRender(IBakedModel model, ItemStack stack) { + DObject object = getObjectForItemStack(model, stack); + + renderState.pushObject(object); + renderState.pushModelView(); + renderState.applyLastModelViewTransformToObject(); + + object.setVisible(renderState.getFrame()); + object.keyframeLocRotScale(renderState.getFrame()); + + renderState.pop(); + } + + private DObject getObjectForItemStack(IBakedModel model, ItemStack stack) { + int frame = renderState.getFrame(); + DObject parent = renderState.peekObject(); + DObject object = null; + for (DObject child : parent.getChildren()) { + if (child.lastFrame < frame + && child instanceof ItemBasedDObject + && ((ItemBasedDObject) child).isBasedOn(model, stack)) { + object = child; + break; + } + } + if (object == null) { + object = new ItemBasedDObject(model, stack); + object.id.name = stack.getDisplayName(); + object.setParent(parent); + } + object.lastFrame = frame; + return object; + } + + @SuppressWarnings("unchecked") + private static DMesh generateMeshForItemStack(IBakedModel model, ItemStack stack) { + DMesh mesh = new DMesh(); + BlendMeshBuilder builder = new BlendMeshBuilder(mesh); + builder.setWellBehaved(true); + builder.startDrawingQuads(); + builder.setVertexFormat(DefaultVertexFormats.ITEM); + + for (EnumFacing face : EnumFacing.values()) { + renderQuads(builder, model.getFaceQuads(face), stack); + } + renderQuads(builder, model.getGeneralQuads(), stack); + + builder.finishDrawing(); + return mesh; + } + + private static void renderQuads(WorldRenderer buffer, List quads, ItemStack stack) { + for (BakedQuad quad : quads) { + int color = stack != null && quad.hasTintIndex() + ? stack.getItem().getColorFromItemStack(stack, quad.getTintIndex()) | 0xff000000 + : 0xffffffff; + LightUtil.renderQuadColor(buffer, quad, color); + } + + } + + private static class ItemBasedDObject extends DObject { + private final IBakedModel model; + private final ItemStack stack; + private boolean valid; + + public ItemBasedDObject(IBakedModel model, ItemStack stack) { + super(generateMeshForItemStack(model, stack)); + this.model = model; + this.stack = stack; + } + + public boolean isBasedOn(IBakedModel model, ItemStack scale) { + return this.model == model; // FIXME ignores color of stack + } + + @Override + public void setVisible(int frame) { + valid = true; + super.setVisible(frame); + } + + @Override + public boolean isValid() { + return valid; + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java new file mode 100644 index 00000000..5f6cfcd2 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java @@ -0,0 +1,106 @@ +package com.replaymod.render.blend.exporters; + +import com.replaymod.render.blend.BlendMeshBuilder; +import com.replaymod.render.blend.Exporter; +import com.replaymod.render.blend.data.DMesh; +import com.replaymod.render.blend.data.DObject; +import net.minecraft.client.model.ModelBox; +import net.minecraft.client.model.ModelRenderer; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; + +import static com.replaymod.core.versions.MCVer.*; +import static com.replaymod.render.blend.Util.isGlTextureMatrixIdentity; + +public class ModelRendererExporter implements Exporter { + private final RenderState renderState; + + public ModelRendererExporter(RenderState renderState) { + this.renderState = renderState; + } + + @Override + public void setup() throws IOException { + } + + public void preRenderModel(ModelRenderer model, float scale) { + DObject object = getObjectForModel(model, scale); + renderState.pushObject(object); + renderState.pushModelView(); + } + + public void onRenderModel() { + if (!GL11.glIsEnabled(GL11.GL_TEXTURE_2D) || !isGlTextureMatrixIdentity()) { + return; + } + renderState.popModelView(); + renderState.pushModelView(); + renderState.applyLastModelViewTransformToObject(); + DObject object = renderState.peekObject(); + object.setVisible(renderState.getFrame()); + object.keyframeLocRotScale(renderState.getFrame()); + } + + public void postRenderModel() { + renderState.pop(); + } + + private DObject getObjectForModel(ModelRenderer model, float scale) { + int frame = renderState.getFrame(); + DObject parent = renderState.peekObject(); + DObject object = null; + for (DObject child : parent.getChildren()) { + if (child.lastFrame < frame + && child instanceof ModelBasedDObject + && ((ModelBasedDObject) child).isBasedOn(model, scale)) { + object = child; + break; + } + } + if (object == null) { + object = new ModelBasedDObject(model, scale); + object.id.name = model.boxName; + object.setParent(parent); + } + object.lastFrame = frame; + return object; + } + + private static DMesh generateMesh(ModelRenderer model, float scale) { + DMesh mesh = new DMesh(); + BlendMeshBuilder builder = new BlendMeshBuilder(mesh); + for (ModelBox box : cubeList(model)) { + box.render(builder, scale); + } + builder.maybeFinishDrawing(); + return mesh; + } + + private static class ModelBasedDObject extends DObject { + private final ModelRenderer model; + private final float scale; + private boolean valid; + + public ModelBasedDObject(ModelRenderer model, float scale) { + super(generateMesh(model, scale)); + this.model = model; + this.scale = scale; + } + + public boolean isBasedOn(ModelRenderer model, float scale) { + return this.model == model && Math.abs(this.scale - scale) < 1e-4; + } + + @Override + public void setVisible(int frame) { + valid = true; + super.setVisible(frame); + } + + @Override + public boolean isValid() { + return valid; + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java new file mode 100644 index 00000000..32aa6fe4 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -0,0 +1,142 @@ +package com.replaymod.render.blend.exporters; + +import com.replaymod.render.blend.BlendMeshBuilder; +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.Exporter; +import com.replaymod.render.blend.data.DMesh; +import com.replaymod.render.blend.data.DObject; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.entity.Entity; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector3f; + +import java.io.IOException; +import java.util.IdentityHashMap; +import java.util.Map; + +import static com.replaymod.render.blend.Util.getGlModelViewMatrix; + +public class ParticlesExporter implements Exporter { + private final Minecraft mc = Minecraft.getMinecraft(); + private final RenderState renderState; + private DObject pointAtObject; + private DObject particlesObject; + private DObject litParticlesObject; + private Map particleObjects; + private Map particleObjectsSeen; + + public ParticlesExporter(RenderState renderState) { + this.renderState = renderState; + } + + @Override + public void setup() throws IOException { + if (true) return; // FIXME make configurable (also other methods below) + // FIXME replace with camera + pointAtObject = new DObject(DObject.Type.OB_EMPTY); + pointAtObject.id.name = "Particles Target"; + pointAtObject.layers = 1 << 2; + BlendState.getState().getScene().base.add(pointAtObject); + + particlesObject = new DObject(DObject.Type.OB_EMPTY); + particlesObject.id.name = "Particles"; + particlesObject.layers = 1 << 1; + BlendState.getState().getScene().base.add(particlesObject); + + litParticlesObject = new DObject(DObject.Type.OB_EMPTY); + litParticlesObject.id.name = "Lit Particles"; + litParticlesObject.layers = 1 << 1; + BlendState.getState().getScene().base.add(litParticlesObject); + + particleObjects = new IdentityHashMap<>(); + particleObjectsSeen = new IdentityHashMap<>(); + } + + public void preParticlesRender(boolean lit) { + if (true) return; + Matrix4f modelView = getGlModelViewMatrix(); + // Particles are rendered relative to the viewer location. + // We however want our Particles object to not move when the viewer does, + // so we position it at 0/0/0 and instead have the particles themselves move more + Matrix4f.translate(new Vector3f( + (float) -mc.getRenderManager().viewerPosX, + (float) -mc.getRenderManager().viewerPosY, + (float) -mc.getRenderManager().viewerPosZ + ), modelView, modelView); + renderState.push(lit ? litParticlesObject : particlesObject, modelView); + } + + public void postParticlesRender() { + if (true) return; + renderState.pop(); + } + + public void onRender(EntityFX particle, float renderPartialTicks) { + if (true) return; + DObject particleObject = particleObjects.get(particle); + if (particleObject == null) { + particleObject = new DObject(DObject.Type.OB_EMPTY); + particleObject.setParent(renderState.peekObject()); + particleObject.pointAt = pointAtObject; + particleObject.layers = 1 << 2; + particleObject.id.name = particle.getClass().getSimpleName(); + particleObject.keyframe("hide", 0, renderState.getFrame() - 1, 1f); + particleObject.keyframe("hide", 0, renderState.getFrame(), 0f); + particleObjects.put(particle, particleObject); + } + particleObjectsSeen.put(particle, particleObject); + renderState.pushObject(particleObject); + + // Normally the particle renderer will translate to dx/dy/dz but we want that translation outside of + // the particle object (on the particle object itself). + // So, we translate there, then store the model-view-matrix and then translate back to let the + // renderer translate there again. + // Instead of actually translating, we just add the translation on the current model-view-matrix. + Matrix4f modelView = getGlModelViewMatrix(); + double dx = particle.prevPosX + (particle.posX - particle.prevPosX) * renderPartialTicks - EntityFX.interpPosX; + double dy = particle.prevPosY + (particle.posY - particle.prevPosY) * renderPartialTicks - EntityFX.interpPosY; + double dz = particle.prevPosZ + (particle.posZ - particle.prevPosZ) * renderPartialTicks - EntityFX.interpPosZ; + Vector3f offset = new Vector3f((float) dx, (float) dy, (float) dz); + Matrix4f.translate(offset, modelView, modelView); + renderState.pushModelView(modelView); + renderState.applyLastModelViewTransformToObject(); + + particleObject.keyframeLoc(renderState.getFrame()); + particleObject.keyframeScale(renderState.getFrame()); + + DObject frameObject = new DObject(generateMeshForParticle(particle, offset)); + frameObject.setParent(particleObject); + frameObject.layers = 1 << 2; + frameObject.id.name = particleObject.id.name + " - Frame " + renderState.getFrame(); + frameObject.keyframe("hide", 0, renderState.getFrame() - 1, 1f); + frameObject.keyframe("hide", 0, renderState.getFrame(), 0f); + frameObject.keyframe("hide", 0, renderState.getFrame() + 1, 1f); + + renderState.pop(); + } + + private DMesh generateMeshForParticle(EntityFX particle, Vector3f offset) { + DMesh mesh = new DMesh(); + BlendMeshBuilder builder = new BlendMeshBuilder(mesh); + builder.setOffset(offset); + builder.setWellBehaved(true); + builder.startDrawingQuads(); + particle.func_180434_a(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); + builder.finishDrawing(); + return mesh; + } + + @Override + public void postFrame(int frame) throws IOException { + if (true) return; + for (Map.Entry entry : particleObjects.entrySet()) { + if (!particleObjectsSeen.containsKey(entry.getKey())) { + DObject object = entry.getValue(); + object.keyframe("hide", 0, renderState.getFrame(), 1f); + } + } + particleObjects = particleObjectsSeen; + particleObjectsSeen = new IdentityHashMap<>(); + } +} diff --git a/src/main/java/com/replaymod/render/blend/exporters/RenderState.java b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java new file mode 100644 index 00000000..4604cb58 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java @@ -0,0 +1,143 @@ +package com.replaymod.render.blend.exporters; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.Exporter; +import com.replaymod.render.blend.data.DMaterial; +import com.replaymod.render.blend.data.DObject; +import org.lwjgl.util.vector.Matrix4f; + +import java.io.IOException; +import java.util.Deque; +import java.util.Iterator; +import java.util.LinkedList; + +import static com.replaymod.render.ReplayModRender.LOGGER; +import static com.replaymod.render.blend.Util.getGlModelViewMatrix; +import static com.replaymod.render.blend.Util.glScaleToBlend; +import static com.replaymod.render.blend.Util.glToBlend; +import static com.replaymod.render.blend.Util.posFromMat; +import static com.replaymod.render.blend.Util.rotFromMat; +import static com.replaymod.render.blend.Util.scaleFromMat; +import static com.replaymod.render.blend.Util.scaleMat3; + +public class RenderState implements Exporter { + + private final BlendState blendState; + private final ModelRendererExporter modelExporter = new ModelRendererExporter(this); + private final Deque objectStack = new LinkedList<>(); + private final Deque modelViewStack = new LinkedList<>(); + + private int frame; + + public RenderState(BlendState blendState) { + this.blendState = blendState; + + blendState.register(modelExporter); + } + + public int getFrame() { + return frame; + } + + public DMaterial getCurrentMaterial() { + return blendState.getMaterials().getActiveMaterial(); + } + + public ModelRendererExporter getModelExporter() { + return modelExporter; + } + + public Deque getObjectStack() { + return objectStack; + } + + public void push(DObject object, Matrix4f modelView) { + pushObject(object); + pushModelView(modelView); + } + + public void pushObject(DObject object) { + objectStack.push(object); + } + + public void pushModelView() { + pushModelView(getGlModelViewMatrix()); + } + + public void pushModelView(Matrix4f modelView) { + modelViewStack.push(modelView); + } + + public void pop() { + popObject(); + popModelView(); + } + + public DObject popObject() { + return objectStack.pop(); + } + + public Matrix4f popModelView() { + return modelViewStack.pop(); + } + + public DObject peekObject() { + return objectStack.peek(); + } + + public Matrix4f peekModelView() { + return modelViewStack.peek(); + } + + public void applyLastModelViewTransformToObject() { + applyLastModelViewTransformToObject(peekObject()); + } + + public void applyLastModelViewTransformToObject(DObject object) { + Matrix4f mat = calcLastModelViewTransform(); + + posFromMat(mat, object.loc); + scaleFromMat(mat, object.scale); + scaleMat3(mat, object.scale); + rotFromMat(mat, object.rot); + + glToBlend(object.loc); + glScaleToBlend(object.scale); + glToBlend(object.rot); + } + + public Matrix4f calcLastModelViewTransform() { + Iterator iter = modelViewStack.iterator(); + Matrix4f newModelView = iter.next(); + Matrix4f prevModelView = iter.next(); + // We need to apply the same transformation T to the object that has transformed the old into the new matrix: + // O * T = N <=> T = O^{-1} * N + return Matrix4f.mul(Matrix4f.invert(prevModelView, null), newModelView, null); + } + + @Override + public void setup() throws IOException { + } + + @Override + public void preFrame(int frame) throws IOException { + this.frame = frame; + } + + @Override + public void postFrame(int frame) throws IOException { + if (!objectStack.isEmpty()) { + LOGGER.warn("Post frame with non-empty object stack! ({} remaining)", objectStack.size()); + objectStack.clear(); + } + if (!modelViewStack.isEmpty()) { + LOGGER.warn("Post frame with non-empty model-view stack! ({} remaining)", modelViewStack.size()); + modelViewStack.clear(); + } + } + + @Override + public void tearDown() throws IOException { + + } +} diff --git a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java new file mode 100644 index 00000000..aceeefd9 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java @@ -0,0 +1,102 @@ +package com.replaymod.render.blend.exporters; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.Exporter; +import com.replaymod.render.blend.data.DObject; +import lombok.SneakyThrows; +import net.minecraft.client.Minecraft; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockPos; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector3f; + +import java.io.IOException; +import java.util.IdentityHashMap; +import java.util.Map; + +import static com.replaymod.render.blend.Util.getGlModelViewMatrix; +import static com.replaymod.render.blend.Util.getTileEntityId; + +public class TileEntityExporter implements Exporter { + private final Minecraft mc = Minecraft.getMinecraft(); + private final RenderState renderState; + private DObject tileEntitiesObject; + private Map tileEntityObjects; + private Map tileEntityObjectsSeen; + + public TileEntityExporter(RenderState renderState) { + this.renderState = renderState; + } + + @Override + @SneakyThrows + public void setup() throws IOException { + tileEntitiesObject = new DObject(DObject.Type.OB_EMPTY); + tileEntitiesObject.id.name = "TileEntities"; + tileEntitiesObject.layers = 1 << 1; + BlendState.getState().getScene().base.add(tileEntitiesObject); + + tileEntityObjects = new IdentityHashMap<>(); + tileEntityObjectsSeen = new IdentityHashMap<>(); + } + + public void preTileEntitiesRender() { + Matrix4f modelView = getGlModelViewMatrix(); + // Tile entities are rendered relative to the viewer location. + // We however want our TileEntities object to not move when the viewer does, + // so we position it at 0/0/0 and instead have the tile entities themselves move more + Matrix4f.translate(new Vector3f( + (float) -mc.getRenderManager().viewerPosX, + (float) -mc.getRenderManager().viewerPosY, + (float) -mc.getRenderManager().viewerPosZ + ), modelView, modelView); + renderState.push(tileEntitiesObject, modelView); + } + + public void postTileEntitiesRender() { + renderState.pop(); + } + + public void preRender(TileEntity tileEntity, double dx, double dy, double dz, float renderPartialTicks, int destroyStage) { + DObject tileEntityObject = tileEntityObjects.get(tileEntity); + if (tileEntityObject == null) { + tileEntityObject = new DObject(DObject.Type.OB_EMPTY); + tileEntityObject.setParent(renderState.peekObject()); + BlockPos pos = tileEntity.getPos(); + tileEntityObject.id.name = getTileEntityId(tileEntity) + "( " + pos.getX() + "/" + pos.getY() + "/" + pos.getZ() + ")"; + tileEntityObject.keyframe("hide", 0, renderState.getFrame() - 1, 1f); + tileEntityObject.keyframe("hide", 0, renderState.getFrame(), 0f); + tileEntityObjects.put(tileEntity, tileEntityObject); + } + tileEntityObjectsSeen.put(tileEntity, tileEntityObject); + renderState.pushObject(tileEntityObject); + + // Normally the tile entity renderer will translate to dx/dy/dz but we want that translation outside of + // the tile entity object (on the tile entity object itself). + // So, we translate there, then store the model-view-matrix and then translate back to let the + // renderer translate there again. + // Instead of actually translating, we just add the translation on the current model-view-matrix. + Matrix4f modelView = getGlModelViewMatrix(); + Matrix4f.translate(new Vector3f((float) dx, (float) dy, (float) dz), modelView, modelView); + renderState.pushModelView(modelView); + renderState.applyLastModelViewTransformToObject(); + + tileEntityObject.keyframeLocRotScale(renderState.getFrame()); + } + + public void postRender() { + renderState.pop(); + } + + @Override + public void postFrame(int frame) throws IOException { + for (Map.Entry entry : tileEntityObjects.entrySet()) { + if (!tileEntityObjectsSeen.containsKey(entry.getKey())) { + DObject object = entry.getValue(); + object.keyframe("hide", 0, renderState.getFrame(), 1f); + } + } + tileEntityObjects = tileEntityObjectsSeen; + tileEntityObjectsSeen = new IdentityHashMap<>(); + } +} diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java new file mode 100644 index 00000000..0c0d5d8a --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java @@ -0,0 +1,30 @@ +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.ChunkExporter; +import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator; +import net.minecraft.client.renderer.chunk.ChunkRenderWorker; +import net.minecraft.util.EnumWorldBlockLayer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ChunkRenderWorker.class) +public abstract class MixinChunkRenderWorker { + + @Inject(method = "processTask", at = @At("RETURN")) + public void afterChunkUpdate(ChunkCompileTaskGenerator task, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + if (task.getStatus() == ChunkCompileTaskGenerator.Status.DONE + && task.getType() == ChunkCompileTaskGenerator.Type.REBUILD_CHUNK) { + for (EnumWorldBlockLayer layer : EnumWorldBlockLayer.values()) { + if (task.getCompiledChunk().isLayerStarted(layer)) { + blendState.get(ChunkExporter.class).addChunkUpdate(task.getRenderChunk(), layer); + } + } + } + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java b/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java new file mode 100644 index 00000000..f9557d97 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java @@ -0,0 +1,46 @@ +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.ParticlesExporter; +import net.minecraft.client.particle.EffectRenderer; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EffectRenderer.class) +public abstract class MixinEffectRenderer { + + @Inject(method = "renderParticles", at = @At("HEAD")) + public void preRender(Entity view, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ParticlesExporter.class).preParticlesRender(false); + } + } + + @Inject(method = "renderParticles", at = @At("RETURN")) + public void postRender(Entity view, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ParticlesExporter.class).postParticlesRender(); + } + } + + @Inject(method = "renderLitParticles", at = @At("HEAD")) + public void preLitRender(Entity view, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ParticlesExporter.class).preParticlesRender(true); + } + } + + @Inject(method = "renderLitParticles", at = @At("RETURN")) + public void postLitRender(Entity view, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ParticlesExporter.class).postParticlesRender(); + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java b/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java new file mode 100644 index 00000000..f470ba4f --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java @@ -0,0 +1,65 @@ +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.ModelRendererExporter; +import net.minecraft.client.model.ModelRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ModelRenderer.class) +public abstract class MixinModelRenderer { + @Inject(method = "render", at = @At("HEAD")) + public void preRender(float scale, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ModelRendererExporter.class).preRenderModel((ModelRenderer)(Object)this, scale); + } + } + + @Inject(method = "renderWithRotation", at = @At("HEAD")) + public void preRenderWithRotation(float scale, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ModelRendererExporter.class).preRenderModel((ModelRenderer)(Object)this, scale); + } + } + + @Inject(method = "render", at = @At("RETURN")) + public void postRender(float scale, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ModelRendererExporter.class).postRenderModel(); + } + } + + @Inject(method = "renderWithRotation", at = @At("RETURN")) + public void postRenderWithRotation(float scale, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ModelRendererExporter.class).postRenderModel(); + } + } + + @Inject(method = "render", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/GlStateManager;callList(I)V"), + expect = 3) + public void onRender(float scale, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ModelRendererExporter.class).onRenderModel(); + } + } + + @Inject(method = "renderWithRotation", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/GlStateManager;callList(I)V")) + public void onRenderWithRotation(float scale, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ModelRendererExporter.class).onRenderModel(); + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java new file mode 100644 index 00000000..4dd38130 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java @@ -0,0 +1,60 @@ +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.EntityExporter; +import com.replaymod.render.blend.exporters.TileEntityExporter; +import net.minecraft.client.renderer.RenderGlobal; +import net.minecraft.client.renderer.culling.ICamera; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(RenderGlobal.class) +public abstract class MixinRenderGlobal { + + // FIXME wither skull ._. mojang pls + + @Inject(method = "renderEntities", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V")) + public void preEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(EntityExporter.class).preEntitiesRender(); + } + } + + @Inject(method = "renderEntities", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V", + shift = At.Shift.AFTER)) + public void postEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(EntityExporter.class).postEntitiesRender(); + } + } + + @Inject(method = "renderEntities", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V")) + public void preTileEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(TileEntityExporter.class).preTileEntitiesRender(); + } + } + + @Inject(method = "renderEntities", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V", + shift = At.Shift.AFTER)) + public void postTileEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(TileEntityExporter.class).postTileEntitiesRender(); + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java new file mode 100644 index 00000000..943915ac --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java @@ -0,0 +1,23 @@ +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.ItemExporter; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.resources.model.IBakedModel; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(RenderItem.class) +public abstract class MixinRenderItem { + @Inject(method = "renderModel(Lnet/minecraft/client/resources/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", + at = @At("HEAD")) + private void onRenderModel(IBakedModel model, ItemStack stack, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ItemExporter.class).onRender(model, stack); + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java new file mode 100644 index 00000000..450f39e8 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java @@ -0,0 +1,35 @@ +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.EntityExporter; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(RenderManager.class) +public abstract class MixinRenderManager { + + @Inject(method = "doRenderEntity", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFFZ)V")) + public void preRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, CallbackInfoReturnable ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(EntityExporter.class).preRender(entity, x, y, z, yaw, renderPartialTicks); + } + } + + @Inject(method = "doRenderEntity", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFFZ)V", + shift = At.Shift.AFTER)) + public void postRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, CallbackInfoReturnable ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(EntityExporter.class).postRender(entity, x, y, z, yaw, renderPartialTicks); + } + } +} diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java new file mode 100644 index 00000000..74fe86d3 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java @@ -0,0 +1,32 @@ +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.TileEntityExporter; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.tileentity.TileEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(TileEntityRendererDispatcher.class) +public abstract class MixinTileEntityRendererDispatcher { + + @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", + at = @At("HEAD")) + public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(TileEntityExporter.class).preRender(tileEntity, x, y, z, renderPartialTicks, destroyStage); + } + } + + @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", + at = @At("RETURN")) + public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(TileEntityExporter.class).postRender(); + } + } +} diff --git a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java index f6a483cb..6dad7f05 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java @@ -1,6 +1,8 @@ package com.replaymod.render.mixin; //#if MC<10904 +//$$ import com.replaymod.render.blend.BlendState; +//$$ import com.replaymod.render.blend.exporters.ParticlesExporter; //$$ import com.replaymod.render.hooks.EntityRendererHandler; //$$ import net.minecraft.client.Minecraft; //$$ import net.minecraft.client.particle.EffectRenderer; @@ -50,6 +52,10 @@ package com.replaymod.render.mixin; //$$ //$$ rotYZ = (float) (-rotZ * Math.sin(pitch)); //$$ rotXY = (float) (rotX * Math.sin(pitch)); +//$$ } +//$$ BlendState blendState = BlendState.getState(); +//$$ if (blendState != null) { +//$$ blendState.get(ParticlesExporter.class).onRender(fx, partialTicks); //$$ } //#if MC>=10809 //$$ fx.renderParticle(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); diff --git a/src/main/java/com/replaymod/render/processor/DummyProcessor.java b/src/main/java/com/replaymod/render/processor/DummyProcessor.java new file mode 100644 index 00000000..f8320459 --- /dev/null +++ b/src/main/java/com/replaymod/render/processor/DummyProcessor.java @@ -0,0 +1,10 @@ +package com.replaymod.render.processor; + +import com.replaymod.render.rendering.Frame; + +public class DummyProcessor extends AbstractFrameProcessor { + @Override + public F process(F rawFrame) { + return rawFrame; + } +} diff --git a/src/main/java/com/replaymod/render/rendering/Pipelines.java b/src/main/java/com/replaymod/render/rendering/Pipelines.java index f16ba7df..0d4fd80c 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipelines.java +++ b/src/main/java/com/replaymod/render/rendering/Pipelines.java @@ -1,13 +1,32 @@ package com.replaymod.render.rendering; import com.replaymod.render.RenderSettings; -import com.replaymod.render.capturer.*; -import com.replaymod.render.frame.*; +import com.replaymod.render.blend.BlendFrameCapturer; +import com.replaymod.render.capturer.CubicOpenGlFrameCapturer; +import com.replaymod.render.capturer.CubicPboOpenGlFrameCapturer; +import com.replaymod.render.capturer.ODSFrameCapturer; +import com.replaymod.render.capturer.RenderInfo; +import com.replaymod.render.capturer.SimpleOpenGlFrameCapturer; +import com.replaymod.render.capturer.SimplePboOpenGlFrameCapturer; +import com.replaymod.render.capturer.StereoscopicOpenGlFrameCapturer; +import com.replaymod.render.capturer.StereoscopicPboOpenGlFrameCapturer; +import com.replaymod.render.frame.CubicOpenGlFrame; +import com.replaymod.render.frame.ODSOpenGlFrame; +import com.replaymod.render.frame.OpenGlFrame; +import com.replaymod.render.frame.RGBFrame; +import com.replaymod.render.frame.StereoscopicOpenGlFrame; import com.replaymod.render.hooks.EntityRendererHandler; -import com.replaymod.render.processor.*; +import com.replaymod.render.processor.CubicToRGBProcessor; +import com.replaymod.render.processor.DummyProcessor; +import com.replaymod.render.processor.EquirectangularToRGBProcessor; +import com.replaymod.render.processor.ODSToRGBProcessor; +import com.replaymod.render.processor.OpenGlToRGBProcessor; +import com.replaymod.render.processor.StereoscopicToRGBProcessor; import com.replaymod.render.utils.PixelBufferObject; import lombok.experimental.UtilityClass; +import java.io.IOException; + @UtilityClass public class Pipelines { public static Pipeline newPipeline(RenderSettings.RenderMethod method, RenderInfo renderInfo, FrameConsumer consumer) { @@ -22,6 +41,8 @@ public class Pipelines { return newEquirectangularPipeline(renderInfo, consumer); case ODS: return newODSPipeline(renderInfo, consumer); + case BLEND: + throw new UnsupportedOperationException("Use newBlendPipeline instead!"); } throw new UnsupportedOperationException("Unknown method: " + method); } @@ -76,4 +97,19 @@ public class Pipelines { new ODSFrameCapturer(new EntityRendererHandler(settings), renderInfo, settings.getVideoWidth() / 4); return new Pipeline<>(capturer, new ODSToRGBProcessor(settings.getVideoWidth() / 4), consumer); } + + public static Pipeline newBlendPipeline(RenderInfo renderInfo) throws IOException { + RenderSettings settings = renderInfo.getRenderSettings(); + FrameCapturer capturer = new BlendFrameCapturer(new EntityRendererHandler(settings), renderInfo); + FrameConsumer consumer = new FrameConsumer() { + @Override + public void consume(RGBFrame frame) { + } + + @Override + public void close() throws IOException { + } + }; + return new Pipeline<>(capturer, new DummyProcessor<>(), consumer); + } } diff --git a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java index 2854fd9e..cb3286ec 100644 --- a/src/main/java/com/replaymod/render/rendering/VideoRenderer.java +++ b/src/main/java/com/replaymod/render/rendering/VideoRenderer.java @@ -7,6 +7,7 @@ import com.replaymod.pathing.properties.TimestampProperty; import com.replaymod.render.RenderSettings; import com.replaymod.render.ReplayModRender; import com.replaymod.render.VideoWriter; +import com.replaymod.render.blend.BlendState; import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.events.ReplayRenderEvent; import com.replaymod.render.frame.RGBFrame; @@ -46,7 +47,10 @@ import java.util.concurrent.FutureTask; import static com.google.common.collect.Iterables.getLast; import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.render.ReplayModRender.LOGGER; -import static net.minecraft.client.renderer.GlStateManager.*; +import static net.minecraft.client.renderer.GlStateManager.clear; +import static net.minecraft.client.renderer.GlStateManager.enableTexture2D; +import static net.minecraft.client.renderer.GlStateManager.popMatrix; +import static net.minecraft.client.renderer.GlStateManager.pushMatrix; import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; @@ -87,14 +91,21 @@ public class VideoRenderer implements RenderInfo { this.replayHandler = replayHandler; this.timeline = timeline; this.gui = new GuiVideoRenderer(this); - this.renderingPipeline = Pipelines.newPipeline(settings.getRenderMethod(), this, - videoWriter = new VideoWriter(this) { - @Override - public void consume(RGBFrame frame) { - gui.updatePreview(frame); - super.consume(frame); - } - }); + if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) { + BlendState.setState(new BlendState(settings.getOutputFile())); + + this.renderingPipeline = Pipelines.newBlendPipeline(this); + this.videoWriter = null; + } else { + this.renderingPipeline = Pipelines.newPipeline(settings.getRenderMethod(), this, + videoWriter = new VideoWriter(this) { + @Override + public void consume(RGBFrame frame) { + gui.updatePreview(frame); + super.consume(frame); + } + }); + } } /** @@ -284,7 +295,7 @@ public class VideoRenderer implements RenderInfo { new SoundHandler().playRenderSuccessSound(); try { - if (!hasFailed()) { + if (!hasFailed() && videoWriter != null) { new GuiRenderingDone(ReplayModRender.instance, videoWriter.getVideoFile(), totalFrames, settings).display(); } } catch (VideoWriter.FFmpegStartupException e) { @@ -401,7 +412,9 @@ public class VideoRenderer implements RenderInfo { } public void cancel() { - videoWriter.abort(); + if (videoWriter != null) { + videoWriter.abort(); + } this.cancelled = true; renderingPipeline.cancel(); } diff --git a/src/main/resources/mixins.render.blend.replaymod.json b/src/main/resources/mixins.render.blend.replaymod.json new file mode 100644 index 00000000..3dcc3306 --- /dev/null +++ b/src/main/resources/mixins.render.blend.replaymod.json @@ -0,0 +1,18 @@ +{ + "required": true, + "package": "com.replaymod.render.blend.mixin", + "mixins": [], + "server": [], + "client": [ + "MixinChunkRenderWorker", + "MixinEffectRenderer", + "MixinModelRenderer", + "MixinRenderGlobal", + "MixinRenderItem", + "MixinRenderManager", + "MixinTileEntityRendererDispatcher" + ], + "compatibilityLevel": "JAVA_8", + "minVersion": "0.6.11", + "refmap": "mixins.replaymod.refmap.json" +} \ No newline at end of file diff --git a/versions/common.gradle b/versions/common.gradle index 81d78a7f..3c1b79f6 100644 --- a/versions/common.gradle +++ b/versions/common.gradle @@ -77,6 +77,8 @@ dependencies { shade 'org.aspectj:aspectjrt:1.8.2' + shade 'com.github.ReplayMod.JavaBlend:2.79.0:e0a1b9a' + def studioVersion = project.name if (studioVersion == '1.8.9') studioVersion = '1.8' shade("com.github.ReplayMod.ReplayStudio:$studioVersion:9fd96a7"){ From 1bdf7da525f763f2939c6c871fbf257977d103e2 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sat, 3 Mar 2018 18:40:52 +0100 Subject: [PATCH 02/12] Update blend export to 1.12.2 --- .../com/replaymod/core/versions/MCVer.java | 52 ++++++++ .../render/blend/BlendMeshBuilder.java | 125 +++++++++++++++--- .../replaymod/render/blend/BlendState.java | 9 +- .../replaymod/render/blend/data/DMesh.java | 7 +- .../render/blend/exporters/ChunkExporter.java | 65 ++++++--- .../render/blend/exporters/ItemExporter.java | 59 ++++++--- .../blend/exporters/ParticlesExporter.java | 70 +++++++--- .../blend/exporters/TileEntityExporter.java | 10 +- .../blend/mixin/MixinChunkRenderWorker.java | 13 +- .../blend/mixin/MixinEffectRenderer.java | 13 +- .../render/blend/mixin/MixinRenderGlobal.java | 12 +- .../render/blend/mixin/MixinRenderItem.java | 19 ++- .../blend/mixin/MixinRenderManager.java | 21 ++- .../MixinTileEntityRendererDispatcher.java | 23 +++- .../render/mixin/MixinParticleManager.java | 6 + src/main/resources/META-INF/replaymod_at.cfg | 5 + 16 files changed, 407 insertions(+), 102 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 0f2ed434..4af23393 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -15,6 +15,7 @@ import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.resources.ResourcePackRepository; import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.Entity; @@ -22,6 +23,7 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.Packet; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraft.world.WorldType; import net.minecraft.world.chunk.Chunk; @@ -37,8 +39,10 @@ import net.minecraft.client.renderer.BufferBuilder; //#else //$$ import net.minecraft.client.renderer.VertexBuffer; //#endif +import net.minecraft.client.particle.Particle; import net.minecraft.util.math.MathHelper; //#else +//$$ import net.minecraft.client.particle.EntityFX; //$$ import net.minecraft.client.renderer.WorldRenderer; //$$ import net.minecraft.util.MathHelper; //#endif @@ -188,6 +192,13 @@ public class MCVer { //$$ = WorldType.DEBUG_WORLD; //#endif + public static ResourceLocation LOCATION_BLOCKS_TEXTURE + //#if MC>=10904 + = TextureMap.LOCATION_BLOCKS_TEXTURE; + //#else + //$$ = TextureMap.locationBlocksTexture; + //#endif + public static EntityPlayerSP player(Minecraft mc) { //#if MC>=11102 return mc.player; @@ -396,6 +407,23 @@ public class MCVer { //$$ worldRenderer.addVertexWithUV(x, y, z, u, v); //#endif } + + //#if MC>=11200 + public static BufferBuilder getBuffer(Tessellator tessellator) { + //#else + //$$ public static WorldRenderer getBuffer(Tessellator tessellator) { + //#endif + //#if MC>=10904 + //#if MC>=11200 + return Tessellator.getInstance().getBuffer(); + //#else + //$$ return Tessellator.getInstance().getBuffer(); + //#endif + //#else + //$$ return Tessellator.getInstance().getWorldRenderer(); + //#endif + } + public static int floor(double val) { //#if MC>=11102 return MathHelper.floor(val); @@ -411,4 +439,28 @@ public class MCVer { public static float sin(float val) { return MathHelper.sin(val); } + + public static double interpPosX() { + //#if MC>=10904 + return Particle.interpPosX; + //#else + //$$ return EntityFX.interpPosX; + //#endif + } + + public static double interpPosY() { + //#if MC>=10904 + return Particle.interpPosY; + //#else + //$$ return EntityFX.interpPosY; + //#endif + } + + public static double interpPosZ() { + //#if MC>=10904 + return Particle.interpPosZ; + //#else + //$$ return EntityFX.interpPosZ; + //#endif + } } diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index fcbb8380..945f108b 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -3,20 +3,33 @@ package com.replaymod.render.blend; import com.replaymod.render.blend.data.DMaterial; import com.replaymod.render.blend.data.DMesh; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormatElement; import org.lwjgl.opengl.GL11; import org.lwjgl.util.vector.Vector2f; import org.lwjgl.util.vector.Vector3f; +//#if MC>=11200 +import net.minecraft.client.renderer.BufferBuilder; +//#else +//$$ import net.minecraft.client.renderer.WorldRenderer; +//#endif + import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.List; -public class BlendMeshBuilder extends WorldRenderer { +import static com.replaymod.core.versions.MCVer.*; + +public class BlendMeshBuilder + //#if MC>=11200 + extends BufferBuilder + //#else + //$$ extends WorldRenderer + //#endif +{ private final DMesh mesh; private final List vertices = new ArrayList<>(); private final List uvs = new ArrayList<>(); @@ -25,6 +38,9 @@ public class BlendMeshBuilder extends WorldRenderer { private boolean isDrawing; private boolean wellBehaved; private int mode; + //#if MC>=11200 + private double x, y, z; + //#endif private float u, v; private int color = 0xffffffff; // Default not in parent class but probably set implicitly somewhere due to re-use @@ -42,7 +58,11 @@ public class BlendMeshBuilder extends WorldRenderer { } @Override - public void startDrawing(int mode) { + //#if MC>=11200 + public void begin(int mode, VertexFormat vertexFormat) { + //#else + //$$ public void startDrawing(int mode) { + //#endif if (isDrawing) { if (!wellBehaved) { // Someone probably finished drawing with the global instance instead of this one, @@ -58,7 +78,7 @@ public class BlendMeshBuilder extends WorldRenderer { if (!wellBehaved) { // In case the calling code finishes with Tessellator.getInstance().draw() - Tessellator.getInstance().getWorldRenderer().startDrawingQuads(); + BufferBuilder_beginPosTexCol(mode); } } @@ -69,16 +89,22 @@ public class BlendMeshBuilder extends WorldRenderer { } @Override - public int finishDrawing() { + //#if MC>=11200 + public void finishDrawing() { + //#else + //$$ public int finishDrawing() { + //#endif if (!isDrawing) { throw new IllegalStateException("Not building!"); } else { if (!wellBehaved) { - Tessellator.getInstance().getWorldRenderer().finishDrawing(); + getBuffer(Tessellator.getInstance()).finishDrawing(); } doFinish(); - return -1; + //#if MC<11200 + //$$ return -1; + //#endif } } @@ -133,26 +159,70 @@ public class BlendMeshBuilder extends WorldRenderer { } } + //#if MC>=11200 + // TODO these should all behave differently depending on the order in which they're called + // e.g. tex may be called multiple times, if there are multiple active texture units @Override - public void setTextureUV(double u, double v) { + public BlendMeshBuilder tex(double u, double v) { this.u = (float) u; this.v = (float) (1 - v); + return this; } @Override - public void setColorRGBA(int r, int g, int b, int a) { + public BufferBuilder lightmap(int p_187314_1_, int p_187314_2_) { + // TODO we probably do care about this + return this; + } + + @Override + public BlendMeshBuilder color(int r, int g, int b, int a) { this.color = r | (g << 8) | (b << 16) | (a << 24); + return this; } @Override - public void addVertex(double x, double y, double z) { - x -= offset.x; - y -= offset.y; - z -= offset.z; + public BufferBuilder normal(float x, float y, float z) { + // TODO do we care about normals? + return this; + } + + @Override + public BlendMeshBuilder pos(double x, double y, double z) { + this.x = x - offset.x; + this.y = y - offset.y; + this.z = z - offset.z; + return this; + } + + @Override + public void endVertex() { vertices.add(new DMesh.Vertex((float) x, (float) -z, (float) y)); uvs.add(new Vector2f(u, v)); colors.add(color); } + //#else + //$$ @Override + //$$ public void setTextureUV(double u, double v) { + //$$ this.u = (float) u; + //$$ this.v = (float) (1 - v); + //$$ } + //$$ + //$$ @Override + //$$ public void setColorRGBA(int r, int g, int b, int a) { + //$$ this.color = r | (g << 8) | (b << 16) | (a << 24); + //$$ } + //$$ + //$$ @Override + //$$ public void addVertex(double x, double y, double z) { + //$$ x -= offset.x; + //$$ y -= offset.y; + //$$ z -= offset.z; + //$$ vertices.add(new DMesh.Vertex((float) x, (float) -z, (float) y)); + //$$ uvs.add(new Vector2f(u, v)); + //$$ colors.add(color); + //$$ } + //#endif @Override @SuppressWarnings("unchecked") @@ -164,12 +234,19 @@ public class BlendMeshBuilder extends WorldRenderer { VertexFormat vertexFormat = getVertexFormat(); int posOffset = -1, colorOffset = -1, uvOffset = -1; List elements = vertexFormat.getElements(); + int index = 0; for (VertexFormatElement element : elements) { + //#if MC>11200 + int offset = vertexFormat.getOffset(index); + //#else + //$$ int offset = element.getOffset(); + //#endif switch (element.getUsage()) { - case POSITION: posOffset = element.getOffset(); break; - case COLOR: colorOffset = element.getOffset(); break; - case UV: if (element.getIndex() == 0) uvOffset = element.getOffset(); break; + case POSITION: posOffset = offset; break; + case COLOR: colorOffset = offset; break; + case UV: if (element.getIndex() == 0) uvOffset = offset; break; } + index++; } if (posOffset == -1) throw new IllegalStateException("No position element in " + vertexFormat); if (uvOffset == -1) throw new IllegalStateException("No uv element in " + vertexFormat); @@ -179,15 +256,27 @@ public class BlendMeshBuilder extends WorldRenderer { if (colorOffset != -1) { color = buffer.getInt(offset + colorOffset); } - setTextureUV( + //#if MC>11200 + tex( + //#else + //$$ setTextureUV( + //#endif buffer.getFloat(offset + uvOffset), buffer.getFloat(offset + uvOffset + 4) ); - addVertex( + //#if MC>11200 + pos( + //#else + //$$ addVertex( + //#endif buffer.getFloat(offset + posOffset ), buffer.getFloat(offset + posOffset + 4), buffer.getFloat(offset + posOffset + 8) ); + + //#if MC>11200 + endVertex(); + //#endif } } diff --git a/src/main/java/com/replaymod/render/blend/BlendState.java b/src/main/java/com/replaymod/render/blend/BlendState.java index 2c7ba4f0..e84ab3ff 100644 --- a/src/main/java/com/replaymod/render/blend/BlendState.java +++ b/src/main/java/com/replaymod/render/blend/BlendState.java @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; +import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.render.ReplayModRender.LOGGER; // Note: @@ -77,7 +78,7 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.makeCrashReport(e, "Setup of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); - category.addCrashSectionCallable("Exporter", exporter::toString); + addDetail(category, "Exporter", exporter::toString); throw new ReportedException(report); } } @@ -91,7 +92,7 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.makeCrashReport(e, "Tear down of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); - category.addCrashSectionCallable("Exporter", exporter::toString); + addDetail(category, "Exporter", exporter::toString); throw new ReportedException(report); } } @@ -128,7 +129,7 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.makeCrashReport(e, "Pre frame of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); - category.addCrashSectionCallable("Exporter", exporter::toString); + addDetail(category, "Exporter", exporter::toString); category.addCrashSection("Frame", frame); throw new ReportedException(report); } @@ -143,7 +144,7 @@ public class BlendState implements Exporter { } catch (IOException e) { CrashReport report = CrashReport.makeCrashReport(e, "Post frame of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); - category.addCrashSectionCallable("Exporter", exporter::toString); + addDetail(category, "Exporter", exporter::toString); category.addCrashSection("Frame", frame); throw new ReportedException(report); } diff --git a/src/main/java/com/replaymod/render/blend/data/DMesh.java b/src/main/java/com/replaymod/render/blend/data/DMesh.java index 70aaf174..18d6366c 100644 --- a/src/main/java/com/replaymod/render/blend/data/DMesh.java +++ b/src/main/java/com/replaymod/render/blend/data/DMesh.java @@ -1,6 +1,5 @@ package com.replaymod.render.blend.data; -import net.minecraft.util.Vec3i; import org.blender.dna.CustomData; import org.blender.dna.CustomDataLayer; import org.blender.dna.Image; @@ -20,6 +19,12 @@ import org.cakelab.blender.nio.CPointer; import org.lwjgl.util.vector.Vector2f; import org.lwjgl.util.vector.Vector3f; +//#if MC>=10904 +import net.minecraft.util.math.Vec3i; +//#else +//$$ import net.minecraft.util.Vec3i; +//#endif + import java.io.IOException; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java index c6f28601..536149d4 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java @@ -13,15 +13,20 @@ import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.chunk.CompiledChunk; import net.minecraft.client.renderer.chunk.RenderChunk; -import net.minecraft.client.renderer.texture.TextureMap; import net.minecraft.client.renderer.vertex.VertexBuffer; -import net.minecraft.util.BlockPos; -import net.minecraft.util.EnumWorldBlockLayer; import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL15; import org.lwjgl.util.vector.Vector2f; import org.lwjgl.util.vector.Vector3f; +//#if MC>=10904 +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.math.BlockPos; +//#else +//$$ import net.minecraft.util.BlockPos; +//$$ import net.minecraft.util.EnumWorldBlockLayer; +//#endif + import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -30,16 +35,31 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.replaymod.core.versions.MCVer.*; + public class ChunkExporter implements Exporter { private final Map chunkObjects = new HashMap<>(); - private final Map> chunkLayerObjects = new HashMap<>(); - private final List> chunks = new ArrayList<>(); + //#if MC>=10904 + private final Map> chunkLayerObjects = new HashMap<>(); + private final List> chunks = new ArrayList<>(); + //#else + //$$ private final Map> chunkLayerObjects = new HashMap<>(); + //$$ private final List> chunks = new ArrayList<>(); + //#endif private DObject chunksObject; private DMaterial material; private int frame; - public void addChunkUpdate(RenderChunk chunk, EnumWorldBlockLayer layer) { - chunks.add(Pair.of(chunk, layer)); + public void addChunkUpdate(RenderChunk chunk, CompiledChunk compiledChunk) { + //#if MC>=10904 + for (BlockRenderLayer layer : BlockRenderLayer.values()) { + //#else + //$$ for (EnumWorldBlockLayer layer : EnumWorldBlockLayer.values()) { + //#endif + if (compiledChunk == null || compiledChunk.isLayerStarted(layer)) { + chunks.add(Pair.of(chunk, layer)); + } + } } @Override @@ -53,9 +73,7 @@ public class ChunkExporter implements Exporter { RenderChunk renderChunk = ReflectionUtil.get(renderInfo, "renderChunk", RenderChunk.class); // SneakyThrows CompiledChunk compiledChunk = renderChunk.getCompiledChunk(); if (!compiledChunk.isEmpty()) { - for (EnumWorldBlockLayer layer : EnumWorldBlockLayer.values()) { - addChunkUpdate(renderChunk, layer); - } + addChunkUpdate(renderChunk, null); } } @@ -79,21 +97,31 @@ public class ChunkExporter implements Exporter { @Override public void postFrame(int frame) throws IOException { - Minecraft.getMinecraft().getTextureManager().bindTexture(TextureMap.locationBlocksTexture); + Minecraft.getMinecraft().getTextureManager().bindTexture(LOCATION_BLOCKS_TEXTURE); material = BlendState.getState().getMaterials().getActiveMaterial(); - for (Pair pair : chunks) { + //#if MC>=10904 + for (Pair pair : chunks) { + BlockRenderLayer layer = pair.getRight(); + //#else + //$$ for (Pair pair : chunks) { + //$$ EnumWorldBlockLayer layer = pair.getRight(); + //#endif RenderChunk chunk = pair.getLeft(); - EnumWorldBlockLayer layer = pair.getRight(); DObject chunkObject = chunkObjects.get(chunk.getPosition()); if (chunkObject == null) { chunkObject = buildChunkObject(chunk); chunkObjects.put(chunk.getPosition(), chunkObject); - chunkLayerObjects.put(chunk.getPosition(), new EnumMap<>(EnumWorldBlockLayer.class)); + chunkLayerObjects.put(chunk.getPosition(), new EnumMap<>(layer.getDeclaringClass())); } DObject layerObject = buildChunkLayerObject(chunkObject, chunk, layer); if (layerObject == null) continue; - Map layerObjects = chunkLayerObjects.get(chunk.getPosition()); + //#if MC>=10904 + Map layerObjects + //#else + //$$ Map layerObjects + //#endif + = chunkLayerObjects.get(chunk.getPosition()); DObject oldLayerObject = layerObjects.get(layer); if (oldLayerObject != null) { oldLayerObject.keyframe("hide", 0, frame, 1f); @@ -118,7 +146,12 @@ public class ChunkExporter implements Exporter { return chunkObject; } - private DObject buildChunkLayerObject(DObject chunkObject, RenderChunk renderChunk, EnumWorldBlockLayer layer) { + private DObject buildChunkLayerObject(DObject chunkObject, RenderChunk renderChunk, + //#if MC>=10904 + BlockRenderLayer layer) { + //#else + //$$ EnumWorldBlockLayer layer) { + //#endif VertexBuffer vertexBuffer = renderChunk.getVertexBufferByLayer(layer.ordinal()); if (vertexBuffer == null) return null; diff --git a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java index c420ef03..279d18ed 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java @@ -4,14 +4,20 @@ import com.replaymod.render.blend.BlendMeshBuilder; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMesh; import com.replaymod.render.blend.data.DObject; -import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.client.resources.model.IBakedModel; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraftforge.client.model.pipeline.LightUtil; +//#if MC>=10904 +import net.minecraft.client.renderer.block.model.IBakedModel; +import org.lwjgl.opengl.GL11; +//#else +//$$ import net.minecraft.client.resources.model.IBakedModel; +//#endif + import java.util.List; public class ItemExporter implements Exporter { @@ -21,8 +27,8 @@ public class ItemExporter implements Exporter { this.renderState = renderState; } - public void onRender(IBakedModel model, ItemStack stack) { - DObject object = getObjectForItemStack(model, stack); + public void onRender(RenderItem renderItem, IBakedModel model, ItemStack stack) { + DObject object = getObjectForItemStack(renderItem, model, stack); renderState.pushObject(object); renderState.pushModelView(); @@ -34,20 +40,20 @@ public class ItemExporter implements Exporter { renderState.pop(); } - private DObject getObjectForItemStack(IBakedModel model, ItemStack stack) { + private DObject getObjectForItemStack(RenderItem renderItem, IBakedModel model, ItemStack stack) { int frame = renderState.getFrame(); DObject parent = renderState.peekObject(); DObject object = null; for (DObject child : parent.getChildren()) { if (child.lastFrame < frame && child instanceof ItemBasedDObject - && ((ItemBasedDObject) child).isBasedOn(model, stack)) { + && ((ItemBasedDObject) child).isBasedOn(renderItem, model, stack)) { object = child; break; } } if (object == null) { - object = new ItemBasedDObject(model, stack); + object = new ItemBasedDObject(renderItem, model, stack); object.id.name = stack.getDisplayName(); object.setParent(parent); } @@ -56,26 +62,41 @@ public class ItemExporter implements Exporter { } @SuppressWarnings("unchecked") - private static DMesh generateMeshForItemStack(IBakedModel model, ItemStack stack) { + private static DMesh generateMeshForItemStack(RenderItem renderItem, IBakedModel model, ItemStack stack) { DMesh mesh = new DMesh(); BlendMeshBuilder builder = new BlendMeshBuilder(mesh); builder.setWellBehaved(true); - builder.startDrawingQuads(); - builder.setVertexFormat(DefaultVertexFormats.ITEM); + //#if MC>=10809 + builder.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM); + //#else + //$$ builder.startDrawingQuads(); + //$$ builder.setVertexFormat(DefaultVertexFormats.ITEM); + //#endif + //#if MC>=10904 for (EnumFacing face : EnumFacing.values()) { - renderQuads(builder, model.getFaceQuads(face), stack); + renderQuads(renderItem, builder, model.getQuads(null, face, 0), stack); } - renderQuads(builder, model.getGeneralQuads(), stack); + renderQuads(renderItem, builder, model.getQuads(null, null, 0), stack); + //#else + //$$ for (EnumFacing face : EnumFacing.values()) { + //$$ renderQuads(renderItem, builder, model.getFaceQuads(face), stack); + //$$ } + //$$ renderQuads(renderItem, builder, model.getGeneralQuads(), stack); + //#endif builder.finishDrawing(); return mesh; } - private static void renderQuads(WorldRenderer buffer, List quads, ItemStack stack) { + private static void renderQuads(RenderItem renderItem, BlendMeshBuilder buffer, List quads, ItemStack stack) { for (BakedQuad quad : quads) { int color = stack != null && quad.hasTintIndex() - ? stack.getItem().getColorFromItemStack(stack, quad.getTintIndex()) | 0xff000000 + //#if MC>=11200 + ? renderItem.itemColors.getColorFromItemstack(stack, quad.getTintIndex()) | 0xff000000 + //#else + //$$ ? stack.getItem().getColorFromItemStack(stack, quad.getTintIndex()) | 0xff000000 + //#endif : 0xffffffff; LightUtil.renderQuadColor(buffer, quad, color); } @@ -83,18 +104,20 @@ public class ItemExporter implements Exporter { } private static class ItemBasedDObject extends DObject { + private final RenderItem renderItem; private final IBakedModel model; private final ItemStack stack; private boolean valid; - public ItemBasedDObject(IBakedModel model, ItemStack stack) { - super(generateMeshForItemStack(model, stack)); + public ItemBasedDObject(RenderItem renderItem, IBakedModel model, ItemStack stack) { + super(generateMeshForItemStack(renderItem, model, stack)); + this.renderItem = renderItem; this.model = model; this.stack = stack; } - public boolean isBasedOn(IBakedModel model, ItemStack scale) { - return this.model == model; // FIXME ignores color of stack + public boolean isBasedOn(RenderItem renderItem, IBakedModel model, ItemStack stack) { + return this.renderItem == renderItem && this.model == model && this.stack == stack; } @Override diff --git a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java index 32aa6fe4..80acae4f 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -6,15 +6,25 @@ import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMesh; import com.replaymod.render.blend.data.DObject; import net.minecraft.client.Minecraft; -import net.minecraft.client.particle.EntityFX; import net.minecraft.entity.Entity; import org.lwjgl.util.vector.Matrix4f; import org.lwjgl.util.vector.Vector3f; +//#if MC>=10904 +import net.minecraft.client.particle.Particle; +//#else +//$$ import net.minecraft.client.particle.EntityFX; +//#endif + +//#if MC>=10809 +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +//#endif + import java.io.IOException; import java.util.IdentityHashMap; import java.util.Map; +import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.render.blend.Util.getGlModelViewMatrix; public class ParticlesExporter implements Exporter { @@ -23,8 +33,13 @@ public class ParticlesExporter implements Exporter { private DObject pointAtObject; private DObject particlesObject; private DObject litParticlesObject; - private Map particleObjects; - private Map particleObjectsSeen; + //#if MC>=10904 + private Map particleObjects; + private Map particleObjectsSeen; + //#else + //$$ private Map particleObjects; + //$$ private Map particleObjectsSeen; + //#endif public ParticlesExporter(RenderState renderState) { this.renderState = renderState; @@ -32,7 +47,7 @@ public class ParticlesExporter implements Exporter { @Override public void setup() throws IOException { - if (true) return; // FIXME make configurable (also other methods below) + if (false) return; // FIXME make configurable (also other methods below) // FIXME replace with camera pointAtObject = new DObject(DObject.Type.OB_EMPTY); pointAtObject.id.name = "Particles Target"; @@ -54,7 +69,7 @@ public class ParticlesExporter implements Exporter { } public void preParticlesRender(boolean lit) { - if (true) return; + if (false) return; Matrix4f modelView = getGlModelViewMatrix(); // Particles are rendered relative to the viewer location. // We however want our Particles object to not move when the viewer does, @@ -68,12 +83,16 @@ public class ParticlesExporter implements Exporter { } public void postParticlesRender() { - if (true) return; + if (false) return; renderState.pop(); } - public void onRender(EntityFX particle, float renderPartialTicks) { - if (true) return; + //#if MC>=10904 + public void onRender(Particle particle, float renderPartialTicks) { + //#else + //$$ public void onRender(EntityFX particle, float renderPartialTicks) { + //#endif + if (false) return; DObject particleObject = particleObjects.get(particle); if (particleObject == null) { particleObject = new DObject(DObject.Type.OB_EMPTY); @@ -94,9 +113,9 @@ public class ParticlesExporter implements Exporter { // renderer translate there again. // Instead of actually translating, we just add the translation on the current model-view-matrix. Matrix4f modelView = getGlModelViewMatrix(); - double dx = particle.prevPosX + (particle.posX - particle.prevPosX) * renderPartialTicks - EntityFX.interpPosX; - double dy = particle.prevPosY + (particle.posY - particle.prevPosY) * renderPartialTicks - EntityFX.interpPosY; - double dz = particle.prevPosZ + (particle.posZ - particle.prevPosZ) * renderPartialTicks - EntityFX.interpPosZ; + double dx = particle.prevPosX + (particle.posX - particle.prevPosX) * renderPartialTicks - interpPosX(); + double dy = particle.prevPosY + (particle.posY - particle.prevPosY) * renderPartialTicks - interpPosY(); + double dz = particle.prevPosZ + (particle.posZ - particle.prevPosZ) * renderPartialTicks - interpPosZ(); Vector3f offset = new Vector3f((float) dx, (float) dy, (float) dz); Matrix4f.translate(offset, modelView, modelView); renderState.pushModelView(modelView); @@ -116,26 +135,35 @@ public class ParticlesExporter implements Exporter { renderState.pop(); } - private DMesh generateMeshForParticle(EntityFX particle, Vector3f offset) { + //#if MC>=10904 + private DMesh generateMeshForParticle(Particle particle, Vector3f offset) { + //#else + //$$ private DMesh generateMeshForParticle(EntityFX particle, Vector3f offset) { + //#endif DMesh mesh = new DMesh(); BlendMeshBuilder builder = new BlendMeshBuilder(mesh); builder.setOffset(offset); builder.setWellBehaved(true); - builder.startDrawingQuads(); - particle.func_180434_a(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); + //#if MC>=10809 + builder.begin(7, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); + //#else + //$$ builder.startDrawingQuads(); + //#endif + //#if MC>=10904 + particle.renderParticle(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); + //#else + //$$ particle.func_180434_a(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); + //#endif builder.finishDrawing(); return mesh; } @Override public void postFrame(int frame) throws IOException { - if (true) return; - for (Map.Entry entry : particleObjects.entrySet()) { - if (!particleObjectsSeen.containsKey(entry.getKey())) { - DObject object = entry.getValue(); - object.keyframe("hide", 0, renderState.getFrame(), 1f); - } - } + if (false) return; + particleObjects.entrySet().stream() + .filter(entry -> !particleObjectsSeen.containsKey(entry.getKey())) + .forEach(entry -> entry.getValue().keyframe("hide", 0, renderState.getFrame(), 1f)); particleObjects = particleObjectsSeen; particleObjectsSeen = new IdentityHashMap<>(); } diff --git a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java index aceeefd9..180b3364 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java @@ -6,10 +6,15 @@ import com.replaymod.render.blend.data.DObject; import lombok.SneakyThrows; import net.minecraft.client.Minecraft; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.BlockPos; import org.lwjgl.util.vector.Matrix4f; import org.lwjgl.util.vector.Vector3f; +//#if MC>=10904 +import net.minecraft.util.math.BlockPos; +//#else +//$$ import net.minecraft.util.BlockPos; +//#endif + import java.io.IOException; import java.util.IdentityHashMap; import java.util.Map; @@ -57,7 +62,8 @@ public class TileEntityExporter implements Exporter { renderState.pop(); } - public void preRender(TileEntity tileEntity, double dx, double dy, double dz, float renderPartialTicks, int destroyStage) { + public void preRender(TileEntity tileEntity, double dx, double dy, double dz, float renderPartialTicks, int destroyStage, float alpha) { + // FIXME: handle alpha DObject tileEntityObject = tileEntityObjects.get(tileEntity); if (tileEntityObject == null) { tileEntityObject = new DObject(DObject.Type.OB_EMPTY); diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java index 0c0d5d8a..85fc7c50 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java @@ -4,12 +4,17 @@ import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.exporters.ChunkExporter; import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator; import net.minecraft.client.renderer.chunk.ChunkRenderWorker; -import net.minecraft.util.EnumWorldBlockLayer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=10904 +import net.minecraft.util.BlockRenderLayer; +//#else +//$$ import net.minecraft.util.EnumWorldBlockLayer; +//#endif + @Mixin(ChunkRenderWorker.class) public abstract class MixinChunkRenderWorker { @@ -19,11 +24,7 @@ public abstract class MixinChunkRenderWorker { if (blendState != null) { if (task.getStatus() == ChunkCompileTaskGenerator.Status.DONE && task.getType() == ChunkCompileTaskGenerator.Type.REBUILD_CHUNK) { - for (EnumWorldBlockLayer layer : EnumWorldBlockLayer.values()) { - if (task.getCompiledChunk().isLayerStarted(layer)) { - blendState.get(ChunkExporter.class).addChunkUpdate(task.getRenderChunk(), layer); - } - } + blendState.get(ChunkExporter.class).addChunkUpdate(task.getRenderChunk(), task.getCompiledChunk()); } } } diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java b/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java index f9557d97..1270525e 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java @@ -2,14 +2,23 @@ package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.exporters.ParticlesExporter; -import net.minecraft.client.particle.EffectRenderer; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(EffectRenderer.class) +//#if MC>=10904 +import net.minecraft.client.particle.ParticleManager; +//#else +//$$ import net.minecraft.client.particle.EffectRenderer; +//#endif + +//#if MC>=10904 +@Mixin(ParticleManager.class) +//#else +//$$ @Mixin(EffectRenderer.class) +//#endif public abstract class MixinEffectRenderer { @Inject(method = "renderParticles", at = @At("HEAD")) diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java index 4dd38130..af1a356e 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java @@ -18,7 +18,11 @@ public abstract class MixinRenderGlobal { @Inject(method = "renderEntities", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V")) + //#if MC>=10904 + target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntityStatic(Lnet/minecraft/entity/Entity;FZ)V")) + //#else + //$$ target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V")) + //#endif public void preEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { BlendState blendState = BlendState.getState(); if (blendState != null) { @@ -28,7 +32,11 @@ public abstract class MixinRenderGlobal { @Inject(method = "renderEntities", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V", + //#if MC>=10904 + target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntityStatic(Lnet/minecraft/entity/Entity;FZ)V", + //#else + //$$ target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V", + //#endif shift = At.Shift.AFTER)) public void postEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { BlendState blendState = BlendState.getState(); diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java index 943915ac..07959a3e 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java @@ -2,22 +2,33 @@ package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.exporters.ItemExporter; -import net.minecraft.client.renderer.entity.RenderItem; -import net.minecraft.client.resources.model.IBakedModel; import net.minecraft.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=10904 +import net.minecraft.client.renderer.RenderItem; +import net.minecraft.client.renderer.block.model.IBakedModel; +//#else +//$$ import net.minecraft.client.renderer.entity.RenderItem; +//$$ import net.minecraft.client.resources.model.IBakedModel; +//#endif + @Mixin(RenderItem.class) public abstract class MixinRenderItem { - @Inject(method = "renderModel(Lnet/minecraft/client/resources/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", + //#if MC>=10904 + @Inject(method = "renderModel(Lnet/minecraft/client/renderer/block/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", at = @At("HEAD")) + //#else + //$$ @Inject(method = "renderModel(Lnet/minecraft/client/resources/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", + //$$ at = @At("HEAD")) + //#endif private void onRenderModel(IBakedModel model, ItemStack stack, CallbackInfo ci) { BlendState blendState = BlendState.getState(); if (blendState != null) { - blendState.get(ItemExporter.class).onRender(model, stack); + blendState.get(ItemExporter.class).onRender((RenderItem)(Object)this, model, stack); } } } diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java index 450f39e8..a52f74e8 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java @@ -7,7 +7,12 @@ import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +//#if MC>=10904 +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#else +//$$ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +//#endif @Mixin(RenderManager.class) public abstract class MixinRenderManager { @@ -15,7 +20,12 @@ public abstract class MixinRenderManager { @Inject(method = "doRenderEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFFZ)V")) - public void preRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, CallbackInfoReturnable ci) { + public void preRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, + //#if MC>=10904 + CallbackInfo ci) { + //#else + //$$ CallbackInfoReturnable ci) { + //#endif BlendState blendState = BlendState.getState(); if (blendState != null) { blendState.get(EntityExporter.class).preRender(entity, x, y, z, yaw, renderPartialTicks); @@ -26,7 +36,12 @@ public abstract class MixinRenderManager { at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFFZ)V", shift = At.Shift.AFTER)) - public void postRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, CallbackInfoReturnable ci) { + public void postRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, + //#if MC>=10904 + CallbackInfo ci) { + //#else + //$$ CallbackInfoReturnable ci) { + //#endif BlendState blendState = BlendState.getState(); if (blendState != null) { blendState.get(EntityExporter.class).postRender(entity, x, y, z, yaw, renderPartialTicks); diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java index 74fe86d3..abe563b9 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java @@ -12,18 +12,31 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(TileEntityRendererDispatcher.class) public abstract class MixinTileEntityRendererDispatcher { - @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", + //#if MC>=11200 + @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFIF)V", at = @At("HEAD")) - public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { + public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, float alpha, CallbackInfo ci) { + //#else + //$$ @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", + //$$ at = @At("HEAD")) + //$$ public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { + //$$ float alpha = 1; + //#endif BlendState blendState = BlendState.getState(); if (blendState != null) { - blendState.get(TileEntityExporter.class).preRender(tileEntity, x, y, z, renderPartialTicks, destroyStage); + blendState.get(TileEntityExporter.class).preRender(tileEntity, x, y, z, renderPartialTicks, destroyStage, alpha); } } - @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", + //#if MC>=11200 + @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFIF)V", at = @At("RETURN")) - public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { + public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, float alpha, CallbackInfo ci) { + //#else + //$$ @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", + //$$ at = @At("RETURN")) + //$$ public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { + //#endif BlendState blendState = BlendState.getState(); if (blendState != null) { blendState.get(TileEntityExporter.class).postRender(); diff --git a/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java b/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java index 5cf6df2c..2092239b 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java +++ b/src/main/java/com/replaymod/render/mixin/MixinParticleManager.java @@ -1,6 +1,8 @@ package com.replaymod.render.mixin; //#if MC>=10904 +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.ParticlesExporter; import com.replaymod.render.hooks.EntityRendererHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.particle.Particle; @@ -62,6 +64,10 @@ public abstract class MixinParticleManager { rotYZ = (float) (-rotZ * Math.sin(pitch)); rotXY = (float) (rotX * Math.sin(pitch)); } + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(ParticlesExporter.class).onRender(particle, partialTicks); + } particle.renderParticle(vertexBuffer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); } } diff --git a/src/main/resources/META-INF/replaymod_at.cfg b/src/main/resources/META-INF/replaymod_at.cfg index 54ec438e..8b0fbfb6 100644 --- a/src/main/resources/META-INF/replaymod_at.cfg +++ b/src/main/resources/META-INF/replaymod_at.cfg @@ -97,6 +97,11 @@ public net.minecraft.client.renderer.entity.RenderManager field_178636_l # skinM public net.minecraft.client.renderer.ItemRenderer * public net.minecraft.client.renderer.ItemRenderer *() +# RenderItem +##if MC>=10904 +public net.minecraft.client.renderer.RenderItem field_184395_f # itemColors +##endif + # EntityPlayer public net.minecraft.entity.player.EntityPlayer * From 40da0d10c85ffc26813bd22e3c69932601f834c6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 4 Mar 2018 12:02:30 +0100 Subject: [PATCH 03/12] Parse raw buffer instead of intercepting all BufferBuilder calls --- .../render/blend/BlendMeshBuilder.java | 275 +++++++----------- .../render/blend/exporters/ChunkExporter.java | 53 +--- 2 files changed, 117 insertions(+), 211 deletions(-) diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index 945f108b..14717875 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -6,6 +6,7 @@ import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormatElement; import org.lwjgl.opengl.GL11; +import org.lwjgl.util.vector.ReadableVector3f; import org.lwjgl.util.vector.Vector2f; import org.lwjgl.util.vector.Vector3f; @@ -16,8 +17,6 @@ import net.minecraft.client.renderer.BufferBuilder; //#endif import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.IntBuffer; import java.util.ArrayList; import java.util.List; @@ -30,22 +29,14 @@ public class BlendMeshBuilder //$$ extends WorldRenderer //#endif { + private static final ReadableVector3f VEC3F_ZERO = new Vector3f(0, 0, 0); private final DMesh mesh; - private final List vertices = new ArrayList<>(); - private final List uvs = new ArrayList<>(); - private final List colors = new ArrayList<>(); - private Vector3f offset = new Vector3f(0, 0, 0); + private Vector3f offset; private boolean isDrawing; private boolean wellBehaved; - private int mode; - //#if MC>=11200 - private double x, y, z; - //#endif - private float u, v; - private int color = 0xffffffff; // Default not in parent class but probably set implicitly somewhere due to re-use public BlendMeshBuilder(DMesh mesh) { - super(0); + super(1024); this.mesh = mesh; } @@ -68,23 +59,31 @@ public class BlendMeshBuilder // Someone probably finished drawing with the global instance instead of this one, // let's just assume that what's happened and finish our last draw by ourselves // (might miss correct texture though) - doFinish(); + super.finishDrawing(); + addBufferToMesh(); } else { throw new IllegalStateException("Already drawing!"); } } this.isDrawing = true; - this.mode = mode; if (!wellBehaved) { // In case the calling code finishes with Tessellator.getInstance().draw() BufferBuilder_beginPosTexCol(mode); } + + //#if MC>=11200 + super.begin(mode, vertexFormat); + //#else + //$$ super.startDrawing(mode); + //#endif } public void maybeFinishDrawing() { if (isDrawing) { - doFinish(); + isDrawing = false; + super.finishDrawing(); + addBufferToMesh(); } } @@ -101,16 +100,106 @@ public class BlendMeshBuilder getBuffer(Tessellator.getInstance()).finishDrawing(); } - doFinish(); //#if MC<11200 - //$$ return -1; + //$$ int ret = + //#endif + super.finishDrawing(); + + addBufferToMesh(); + + //#if MC<11200 + //$$ return ret; //#endif } } - private void doFinish() { - this.isDrawing = false; + private void addBufferToMesh() { + addBufferToMesh(this, mesh, offset); + } + //#if MC>=11200 + public static DMesh addBufferToMesh(BufferBuilder bufferBuilder, DMesh mesh, ReadableVector3f vertOffset) { + //#else + //$$ public static DMesh addBufferToMesh(WorldRenderer bufferBuilder, DMesh mesh, Vector3f vertOffset) { + //#endif + return addBufferToMesh(bufferBuilder.getByteBuffer(), bufferBuilder.getDrawMode(), bufferBuilder.getVertexFormat(), mesh, vertOffset); + } + + public static DMesh addBufferToMesh(ByteBuffer buffer, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { + return addBufferToMesh(buffer, buffer.remaining() / vertexFormat.getNextOffset(), mode, vertexFormat, mesh, vertOffset); + } + + public static DMesh addBufferToMesh(ByteBuffer buffer, int vertexCount, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { + if (mesh == null) { + mesh = new DMesh(); + } + if (vertOffset == null) { + vertOffset = VEC3F_ZERO; + } + + // Determine offset of vertex components + int posOffset = -1, colorOffset = -1, uvOffset = -1; + int index = 0; + for (VertexFormatElement element : vertexFormat.getElements()) { + //#if MC>11200 + int offset = vertexFormat.getOffset(index); + //#else + //$$ int offset = element.getOffset(); + //#endif + switch (element.getUsage()) { + case POSITION: + if (element.getType() != VertexFormatElement.EnumType.FLOAT) { + throw new UnsupportedOperationException("Only float is supported for position elements!"); + } + posOffset = offset; + break; + case COLOR: + if (element.getType() != VertexFormatElement.EnumType.UBYTE) { + throw new UnsupportedOperationException("Only unsigned byte is supported for color elements!"); + } + colorOffset = offset; + break; + case UV: + if (element.getIndex() != 0) break; + if (element.getType() != VertexFormatElement.EnumType.FLOAT) { + throw new UnsupportedOperationException("Only float is supported for UV elements!"); + } + uvOffset = offset; + break; + } + index++; + } + if (posOffset == -1) throw new IllegalStateException("No position element in " + vertexFormat); + + // Extract vertex components from byte buffer + List vertices = new ArrayList<>(vertexCount); + List uvs = new ArrayList<>(vertexCount); + List colors = new ArrayList<>(vertexCount); + int step = vertexFormat.getNextOffset(); + for (int offset = 0; offset < vertexCount * step; offset += step) { + vertices.add(new DMesh.Vertex( + buffer.getFloat(offset ) - vertOffset.getX(), + -buffer.getFloat(offset + 8) + vertOffset.getZ(), + buffer.getFloat(offset + 4) - vertOffset.getY() + )); + + if (colorOffset != -1) { + colors.add(buffer.getInt(offset + colorOffset)); + } else { + colors.add(0xffffffff); + } + + if (uvOffset != -1) { + uvs.add(new Vector2f( + buffer.getFloat(offset + uvOffset), + 1 - buffer.getFloat(offset + uvOffset + 4) + )); + } else { + uvs.add(new Vector2f(0, 0)); + } + } + + // Determine and store current material DMaterial activeMaterial = BlendState.getState().getMaterials().getActiveMaterial(); int materialSlot = mesh.materials.indexOf(activeMaterial); if (materialSlot < 0) { @@ -118,6 +207,7 @@ public class BlendMeshBuilder mesh.materials.add(activeMaterial); } + // Bundle vertices into shapes and add them to the mesh switch (mode) { case GL11.GL_TRIANGLES: for (int i = 0; i < vertices.size(); i+=3) { @@ -157,148 +247,7 @@ public class BlendMeshBuilder default: throw new UnsupportedOperationException("Unsupported mode: " + mode); } + + return mesh; } - - //#if MC>=11200 - // TODO these should all behave differently depending on the order in which they're called - // e.g. tex may be called multiple times, if there are multiple active texture units - @Override - public BlendMeshBuilder tex(double u, double v) { - this.u = (float) u; - this.v = (float) (1 - v); - return this; - } - - @Override - public BufferBuilder lightmap(int p_187314_1_, int p_187314_2_) { - // TODO we probably do care about this - return this; - } - - @Override - public BlendMeshBuilder color(int r, int g, int b, int a) { - this.color = r | (g << 8) | (b << 16) | (a << 24); - return this; - } - - @Override - public BufferBuilder normal(float x, float y, float z) { - // TODO do we care about normals? - return this; - } - - @Override - public BlendMeshBuilder pos(double x, double y, double z) { - this.x = x - offset.x; - this.y = y - offset.y; - this.z = z - offset.z; - return this; - } - - @Override - public void endVertex() { - vertices.add(new DMesh.Vertex((float) x, (float) -z, (float) y)); - uvs.add(new Vector2f(u, v)); - colors.add(color); - } - //#else - //$$ @Override - //$$ public void setTextureUV(double u, double v) { - //$$ this.u = (float) u; - //$$ this.v = (float) (1 - v); - //$$ } - //$$ - //$$ @Override - //$$ public void setColorRGBA(int r, int g, int b, int a) { - //$$ this.color = r | (g << 8) | (b << 16) | (a << 24); - //$$ } - //$$ - //$$ @Override - //$$ public void addVertex(double x, double y, double z) { - //$$ x -= offset.x; - //$$ y -= offset.y; - //$$ z -= offset.z; - //$$ vertices.add(new DMesh.Vertex((float) x, (float) -z, (float) y)); - //$$ uvs.add(new Vector2f(u, v)); - //$$ colors.add(color); - //$$ } - //#endif - - @Override - @SuppressWarnings("unchecked") - public void addVertexData(int[] ints) { - ByteBuffer buffer = ByteBuffer.allocate(ints.length * 4).order(ByteOrder.nativeOrder()); - IntBuffer intBuffer = buffer.asIntBuffer(); - intBuffer.put(ints); - - VertexFormat vertexFormat = getVertexFormat(); - int posOffset = -1, colorOffset = -1, uvOffset = -1; - List elements = vertexFormat.getElements(); - int index = 0; - for (VertexFormatElement element : elements) { - //#if MC>11200 - int offset = vertexFormat.getOffset(index); - //#else - //$$ int offset = element.getOffset(); - //#endif - switch (element.getUsage()) { - case POSITION: posOffset = offset; break; - case COLOR: colorOffset = offset; break; - case UV: if (element.getIndex() == 0) uvOffset = offset; break; - } - index++; - } - if (posOffset == -1) throw new IllegalStateException("No position element in " + vertexFormat); - if (uvOffset == -1) throw new IllegalStateException("No uv element in " + vertexFormat); - - for (int offset = 0; offset < buffer.remaining(); offset += vertexFormat.getNextOffset()) { - // TODO doesn't check buffer element types (works for vanilla because they're always the same) - if (colorOffset != -1) { - color = buffer.getInt(offset + colorOffset); - } - //#if MC>11200 - tex( - //#else - //$$ setTextureUV( - //#endif - buffer.getFloat(offset + uvOffset), - buffer.getFloat(offset + uvOffset + 4) - ); - //#if MC>11200 - pos( - //#else - //$$ addVertex( - //#endif - buffer.getFloat(offset + posOffset ), - buffer.getFloat(offset + posOffset + 4), - buffer.getFloat(offset + posOffset + 8) - ); - - //#if MC>11200 - endVertex(); - //#endif - } - } - - @Override - public int getVertexCount() { - return vertices.size(); - } - - public void putColorRGBA(int byteIndex, int r, int g, int b, int a) { - int color = r | (g << 8) | (b << 16) | (a << 24); - putColor(color, -1); // FIXME: reverse index calculation - } - - private void putColor(int color, int reverseIndex) { - colors.set(colors.size() - reverseIndex, color); - } - - public void putColor4(int color) { - for (int i = 0; i < 4; i++) { - putColor(color, i + 1); - } - } - - // FIXME overwrite putX and more } diff --git a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java index 536149d4..a523fe0a 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java @@ -1,5 +1,6 @@ package com.replaymod.render.blend.exporters; +import com.replaymod.render.blend.BlendMeshBuilder; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMaterial; @@ -13,10 +14,11 @@ import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.chunk.CompiledChunk; import net.minecraft.client.renderer.chunk.RenderChunk; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexBuffer; import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; -import org.lwjgl.util.vector.Vector2f; import org.lwjgl.util.vector.Vector3f; //#if MC>=10904 @@ -47,7 +49,6 @@ public class ChunkExporter implements Exporter { //$$ private final List> chunks = new ArrayList<>(); //#endif private DObject chunksObject; - private DMaterial material; private int frame; public void addChunkUpdate(RenderChunk chunk, CompiledChunk compiledChunk) { @@ -97,9 +98,6 @@ public class ChunkExporter implements Exporter { @Override public void postFrame(int frame) throws IOException { - Minecraft.getMinecraft().getTextureManager().bindTexture(LOCATION_BLOCKS_TEXTURE); - material = BlendState.getState().getMaterials().getActiveMaterial(); - //#if MC>=10904 for (Pair pair : chunks) { BlockRenderLayer layer = pair.getRight(); @@ -168,50 +166,9 @@ public class ChunkExporter implements Exporter { GL15.glGetBufferSubData(OpenGlHelper.GL_ARRAY_BUFFER, 0, byteBuffer); vertexBuffer.unbindBuffer(); - DMesh mesh = new DMesh(); - mesh.materials.add(material); - DMesh.Vertex v1 = null, v2 = null, v3 = null; - Vector2f uv1 = new Vector2f(), - uv2 = new Vector2f(), - uv3 = new Vector2f(), - uv4 = new Vector2f(); - int c1 = 0, c2 = 0, c3 = 0; - for (int i = 0; i < size / STRIDE; i++) { - // See VboRenderList.setupArrayPointers for offsets - DMesh.Vertex vert = new DMesh.Vertex( - byteBuffer.getFloat(STRIDE * i), - -byteBuffer.getFloat(STRIDE * i + 8), - byteBuffer.getFloat(STRIDE * i + 4) - ); - float u = byteBuffer.getFloat(STRIDE * i + 16); - float v = 1 - byteBuffer.getFloat(STRIDE * i + 20); - int c = byteBuffer.getInt(STRIDE * i + 12); - // TODO tex, norm, etc. - if (v1 == null) { - v1 = vert; - uv1.set(u, v); - c1 = c; - } else if (v2 == null) { - v2 = vert; - uv2.set(u, v); - c2 = c; - } else if (v3 == null) { - v3 = vert; - uv3.set(u, v); - c3 = c; - } else { - uv4.set(u, v); - mesh.addQuad( - v1, v2, v3, vert, - uv1, uv2, uv3, uv4, - c1, c2, c3, c, - 0 - ); - v1 = v2 = v3 = null; - } - } + Minecraft.getMinecraft().getTextureManager().bindTexture(LOCATION_BLOCKS_TEXTURE); - return mesh; + return BlendMeshBuilder.addBufferToMesh(byteBuffer, GL11.GL_QUADS, DefaultVertexFormats.BLOCK, null, null); } private static final int STRIDE = 28; From e7b5ba9e723c607569041fc73ac0eb29622bc318 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Sun, 4 Mar 2018 16:28:04 +0100 Subject: [PATCH 04/12] Update blend export for all remaining MC versions --- .../com/replaymod/core/versions/MCVer.java | 15 ++++++++--- .../render/blend/BlendMeshBuilder.java | 26 ++++++++++++++----- .../render/blend/exporters/ItemExporter.java | 7 ++--- .../blend/exporters/ParticlesExporter.java | 2 +- .../render/blend/mixin/MixinRenderGlobal.java | 4 +-- .../blend/mixin/MixinRenderManager.java | 4 +-- 6 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 4af23393..6de9133e 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -16,6 +16,8 @@ import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; import net.minecraft.client.resources.ResourcePackRepository; import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.Entity; @@ -408,22 +410,27 @@ public class MCVer { //#endif } + //#if MC>=10904 //#if MC>=11200 public static BufferBuilder getBuffer(Tessellator tessellator) { //#else + //$$ public static VertexBuffer getBuffer(Tessellator tessellator) { + //#endif + //#else //$$ public static WorldRenderer getBuffer(Tessellator tessellator) { //#endif //#if MC>=10904 - //#if MC>=11200 return Tessellator.getInstance().getBuffer(); //#else - //$$ return Tessellator.getInstance().getBuffer(); - //#endif - //#else //$$ return Tessellator.getInstance().getWorldRenderer(); //#endif } + @SuppressWarnings("unchecked") + public static List getElements(VertexFormat vertexFormat) { + return vertexFormat.getElements(); + } + public static int floor(double val) { //#if MC>=11102 return MathHelper.floor(val); diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index 14717875..1a91e697 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -10,9 +10,13 @@ import org.lwjgl.util.vector.ReadableVector3f; import org.lwjgl.util.vector.Vector2f; import org.lwjgl.util.vector.Vector3f; +//#if MC>=10904 //#if MC>=11200 import net.minecraft.client.renderer.BufferBuilder; //#else +//$$ import net.minecraft.client.renderer.VertexBuffer; +//#endif +//#else //$$ import net.minecraft.client.renderer.WorldRenderer; //#endif @@ -23,9 +27,13 @@ import java.util.List; import static com.replaymod.core.versions.MCVer.*; public class BlendMeshBuilder + //#if MC>=10904 //#if MC>=11200 extends BufferBuilder //#else + //$$ extends VertexBuffer + //#endif + //#else //$$ extends WorldRenderer //#endif { @@ -49,7 +57,7 @@ public class BlendMeshBuilder } @Override - //#if MC>=11200 + //#if MC>=10809 public void begin(int mode, VertexFormat vertexFormat) { //#else //$$ public void startDrawing(int mode) { @@ -72,7 +80,7 @@ public class BlendMeshBuilder BufferBuilder_beginPosTexCol(mode); } - //#if MC>=11200 + //#if MC>=10809 super.begin(mode, vertexFormat); //#else //$$ super.startDrawing(mode); @@ -88,7 +96,7 @@ public class BlendMeshBuilder } @Override - //#if MC>=11200 + //#if MC>=10809 public void finishDrawing() { //#else //$$ public int finishDrawing() { @@ -100,14 +108,14 @@ public class BlendMeshBuilder getBuffer(Tessellator.getInstance()).finishDrawing(); } - //#if MC<11200 + //#if MC<10809 //$$ int ret = //#endif super.finishDrawing(); addBufferToMesh(); - //#if MC<11200 + //#if MC<10809 //$$ return ret; //#endif } @@ -117,9 +125,13 @@ public class BlendMeshBuilder addBufferToMesh(this, mesh, offset); } + //#if MC>=10904 //#if MC>=11200 public static DMesh addBufferToMesh(BufferBuilder bufferBuilder, DMesh mesh, ReadableVector3f vertOffset) { //#else + //$$ public static DMesh addBufferToMesh(VertexBuffer bufferBuilder, DMesh mesh, Vector3f vertOffset) { + //#endif + //#else //$$ public static DMesh addBufferToMesh(WorldRenderer bufferBuilder, DMesh mesh, Vector3f vertOffset) { //#endif return addBufferToMesh(bufferBuilder.getByteBuffer(), bufferBuilder.getDrawMode(), bufferBuilder.getVertexFormat(), mesh, vertOffset); @@ -140,8 +152,8 @@ public class BlendMeshBuilder // Determine offset of vertex components int posOffset = -1, colorOffset = -1, uvOffset = -1; int index = 0; - for (VertexFormatElement element : vertexFormat.getElements()) { - //#if MC>11200 + for (VertexFormatElement element : getElements(vertexFormat)) { + //#if MC>=10809 int offset = vertexFormat.getOffset(index); //#else //$$ int offset = element.getOffset(); diff --git a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java index 279d18ed..7ad96a85 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java @@ -4,17 +4,18 @@ import com.replaymod.render.blend.BlendMeshBuilder; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMesh; import com.replaymod.render.blend.data.DObject; -import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraftforge.client.model.pipeline.LightUtil; +import org.lwjgl.opengl.GL11; //#if MC>=10904 +import net.minecraft.client.renderer.RenderItem; import net.minecraft.client.renderer.block.model.IBakedModel; -import org.lwjgl.opengl.GL11; //#else +//$$ import net.minecraft.client.renderer.entity.RenderItem; //$$ import net.minecraft.client.resources.model.IBakedModel; //#endif @@ -92,7 +93,7 @@ public class ItemExporter implements Exporter { private static void renderQuads(RenderItem renderItem, BlendMeshBuilder buffer, List quads, ItemStack stack) { for (BakedQuad quad : quads) { int color = stack != null && quad.hasTintIndex() - //#if MC>=11200 + //#if MC>=10904 ? renderItem.itemColors.getColorFromItemstack(stack, quad.getTintIndex()) | 0xff000000 //#else //$$ ? stack.getItem().getColorFromItemStack(stack, quad.getTintIndex()) | 0xff000000 diff --git a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java index 80acae4f..b4a129aa 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -149,7 +149,7 @@ public class ParticlesExporter implements Exporter { //#else //$$ builder.startDrawingQuads(); //#endif - //#if MC>=10904 + //#if MC>=10809 particle.renderParticle(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); //#else //$$ particle.func_180434_a(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java index af1a356e..93832e02 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java @@ -21,7 +21,7 @@ public abstract class MixinRenderGlobal { //#if MC>=10904 target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntityStatic(Lnet/minecraft/entity/Entity;FZ)V")) //#else - //$$ target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V")) + //$$ target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z")) //#endif public void preEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { BlendState blendState = BlendState.getState(); @@ -35,7 +35,7 @@ public abstract class MixinRenderGlobal { //#if MC>=10904 target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntityStatic(Lnet/minecraft/entity/Entity;FZ)V", //#else - //$$ target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)V", + //$$ target = "Lnet/minecraft/client/renderer/entity/RenderManager;renderEntitySimple(Lnet/minecraft/entity/Entity;F)Z", //#endif shift = At.Shift.AFTER)) public void postEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java index a52f74e8..e2867302 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java @@ -19,7 +19,7 @@ public abstract class MixinRenderManager { @Inject(method = "doRenderEntity", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFFZ)V")) + target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V")) public void preRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, //#if MC>=10904 CallbackInfo ci) { @@ -34,7 +34,7 @@ public abstract class MixinRenderManager { @Inject(method = "doRenderEntity", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFFZ)V", + target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V", shift = At.Shift.AFTER)) public void postRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, //#if MC>=10904 From c48187e784c46dac475d73e5caca96cb4ed10f17 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Mon, 11 Jun 2018 00:27:45 +0200 Subject: [PATCH 05/12] Disable .blend export for 1.7.10 --- .../java/com/replaymod/core/versions/MCVer.java | 6 ++++-- .../replaymod/render/blend/BlendMeshBuilder.java | 2 ++ .../com/replaymod/render/blend/BlendState.java | 4 ++++ .../com/replaymod/render/blend/data/DMesh.java | 14 ++++---------- .../render/blend/exporters/ChunkExporter.java | 2 ++ .../render/blend/exporters/EntityExporter.java | 2 ++ .../render/blend/exporters/ItemExporter.java | 2 ++ .../blend/exporters/ModelRendererExporter.java | 2 ++ .../render/blend/exporters/ParticlesExporter.java | 2 ++ .../render/blend/exporters/RenderState.java | 2 ++ .../render/blend/exporters/TileEntityExporter.java | 2 ++ .../render/blend/mixin/MixinChunkRenderWorker.java | 2 ++ .../render/blend/mixin/MixinEffectRenderer.java | 2 ++ .../render/blend/mixin/MixinModelRenderer.java | 2 ++ .../render/blend/mixin/MixinRenderGlobal.java | 2 ++ .../render/blend/mixin/MixinRenderItem.java | 2 ++ .../render/blend/mixin/MixinRenderManager.java | 2 ++ .../mixin/MixinTileEntityRendererDispatcher.java | 2 ++ .../replaymod/render/gui/GuiRenderSettings.java | 5 +++++ .../render/mixin/MixinEffectRenderer.java | 12 +++++++----- .../resources/mixins.render.blend.replaymod.json | 2 ++ 21 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/replaymod/core/versions/MCVer.java b/src/main/java/com/replaymod/core/versions/MCVer.java index 32fd7c85..d5b05e7f 100644 --- a/src/main/java/com/replaymod/core/versions/MCVer.java +++ b/src/main/java/com/replaymod/core/versions/MCVer.java @@ -16,8 +16,6 @@ import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.client.renderer.texture.TextureMap; -import net.minecraft.client.renderer.vertex.VertexFormat; -import net.minecraft.client.renderer.vertex.VertexFormatElement; import net.minecraft.client.resources.ResourcePackRepository; import net.minecraft.client.settings.KeyBinding; import net.minecraft.crash.CrashReportCategory; @@ -62,6 +60,8 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats; //#if MC>=10800 import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.GlStateManager.BooleanState; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.vertex.VertexFormatElement; import net.minecraft.world.WorldType; import net.minecraftforge.fml.common.eventhandler.EventBus; //#else @@ -533,6 +533,7 @@ public class MCVer { //#endif } + //#if MC>=10800 //#if MC>=10904 //#if MC>=11200 public static BufferBuilder getBuffer(Tessellator tessellator) { @@ -553,6 +554,7 @@ public class MCVer { public static List getElements(VertexFormat vertexFormat) { return vertexFormat.getElements(); } + //#endif public static Tessellator Tessellator_getInstance() { //#if MC>=10800 diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index 1a91e697..48fdd148 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend; import com.replaymod.render.blend.data.DMaterial; @@ -263,3 +264,4 @@ public class BlendMeshBuilder return mesh; } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/BlendState.java b/src/main/java/com/replaymod/render/blend/BlendState.java index e84ab3ff..19133842 100644 --- a/src/main/java/com/replaymod/render/blend/BlendState.java +++ b/src/main/java/com/replaymod/render/blend/BlendState.java @@ -2,12 +2,14 @@ package com.replaymod.render.blend; import com.replaymod.render.blend.data.DScene; import com.replaymod.render.blend.data.Serializer; +//#if MC>=10800 import com.replaymod.render.blend.exporters.ChunkExporter; import com.replaymod.render.blend.exporters.EntityExporter; import com.replaymod.render.blend.exporters.ItemExporter; import com.replaymod.render.blend.exporters.ParticlesExporter; import com.replaymod.render.blend.exporters.RenderState; import com.replaymod.render.blend.exporters.TileEntityExporter; +//#endif import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.util.ReportedException; @@ -48,6 +50,7 @@ public class BlendState implements Exporter { this.blenderFile = BlenderFactory.newBlenderFile(file); this.factory = new BlenderFactory(blenderFile); + //#if MC>=10800 RenderState renderState = new RenderState(this); register(renderState); register(new ChunkExporter()); @@ -55,6 +58,7 @@ public class BlendState implements Exporter { register(new TileEntityExporter(renderState)); register(new ParticlesExporter(renderState)); register(new ItemExporter(renderState)); + //#endif } public void register(Exporter exporter) { diff --git a/src/main/java/com/replaymod/render/blend/data/DMesh.java b/src/main/java/com/replaymod/render/blend/data/DMesh.java index 18d6366c..e9f29879 100644 --- a/src/main/java/com/replaymod/render/blend/data/DMesh.java +++ b/src/main/java/com/replaymod/render/blend/data/DMesh.java @@ -19,12 +19,6 @@ import org.cakelab.blender.nio.CPointer; import org.lwjgl.util.vector.Vector2f; import org.lwjgl.util.vector.Vector3f; -//#if MC>=10904 -import net.minecraft.util.math.Vec3i; -//#else -//$$ import net.minecraft.util.Vec3i; -//#endif - import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -197,7 +191,7 @@ public class DMesh { public static class Vertex { public Vector3f pos; - public Vec3i norm = Vec3i.NULL_VECTOR; + public short normX, normY, normZ; public Vertex(float x, float y, float z) { this.pos = new Vector3f(x, y, z); @@ -209,9 +203,9 @@ public class DMesh { pos.set(1, this.pos.y); pos.set(2, this.pos.z); CArrayFacade norm = mVert.getNo(); - norm.set(0, (short) this.norm.getX()); - norm.set(1, (short) this.norm.getY()); - norm.set(2, (short) this.norm.getZ()); + norm.set(0, this.normX); + norm.set(1, this.normY); + norm.set(2, this.normZ); } } diff --git a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java index a523fe0a..2f7a5d18 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendMeshBuilder; @@ -173,3 +174,4 @@ public class ChunkExporter implements Exporter { private static final int STRIDE = 28; } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java index 1fa342e8..4d32339a 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendState; @@ -81,3 +82,4 @@ public class EntityExporter implements Exporter { renderState.pop(); } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java index 7ad96a85..8493b78c 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendMeshBuilder; @@ -133,3 +134,4 @@ public class ItemExporter implements Exporter { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java index 5f6cfcd2..601e8de3 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ModelRendererExporter.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendMeshBuilder; @@ -104,3 +105,4 @@ public class ModelRendererExporter implements Exporter { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java index b4a129aa..565e63f7 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendMeshBuilder; @@ -168,3 +169,4 @@ public class ParticlesExporter implements Exporter { particleObjectsSeen = new IdentityHashMap<>(); } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/exporters/RenderState.java b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java index 4604cb58..fbf4ab9b 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/RenderState.java +++ b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendState; @@ -141,3 +142,4 @@ public class RenderState implements Exporter { } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java index 180b3364..7f77f858 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.exporters; import com.replaymod.render.blend.BlendState; @@ -106,3 +107,4 @@ public class TileEntityExporter implements Exporter { tileEntityObjectsSeen = new IdentityHashMap<>(); } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java index 85fc7c50..4c59e6cd 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; @@ -29,3 +30,4 @@ public abstract class MixinChunkRenderWorker { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java b/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java index 1270525e..2a78b54c 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinEffectRenderer.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; @@ -53,3 +54,4 @@ public abstract class MixinEffectRenderer { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java b/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java index f470ba4f..9a540bad 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; @@ -63,3 +64,4 @@ public abstract class MixinModelRenderer { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java index 93832e02..44256e49 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; @@ -66,3 +67,4 @@ public abstract class MixinRenderGlobal { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java index 07959a3e..09f38a1d 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; @@ -32,3 +33,4 @@ public abstract class MixinRenderItem { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java index e2867302..ca777c2b 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; @@ -48,3 +49,4 @@ public abstract class MixinRenderManager { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java index abe563b9..65d95761 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java @@ -1,3 +1,4 @@ +//#if MC>=10800 package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; @@ -43,3 +44,4 @@ public abstract class MixinTileEntityRendererDispatcher { } } } +//#endif diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index a07f801e..028f7198 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -359,6 +359,11 @@ public class GuiRenderSettings extends GuiScreen implements Closeable { && videoWidth != videoHeight) { return "replaymod.gui.rendersettings.customresolution.warning.ods"; } + //#if MC<10800 + //$$ if (method == RenderSettings.RenderMethod.BLEND) { + //$$ return "replaymod.gui.rendersettings.no_blend_on_1_7_10"; + //$$ } + //#endif return null; } diff --git a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java index e542e409..9a9269f8 100644 --- a/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java +++ b/src/main/java/com/replaymod/render/mixin/MixinEffectRenderer.java @@ -2,7 +2,6 @@ package com.replaymod.render.mixin; //#if MC<10904 //$$ import com.replaymod.render.blend.BlendState; -//$$ import com.replaymod.render.blend.exporters.ParticlesExporter; //$$ import com.replaymod.render.hooks.EntityRendererHandler; //$$ import net.minecraft.client.Minecraft; //$$ import net.minecraft.client.particle.EffectRenderer; @@ -13,6 +12,7 @@ package com.replaymod.render.mixin; //$$ import org.spongepowered.asm.mixin.injection.Redirect; //$$ //#if MC>=10800 +//$$ import com.replaymod.render.blend.exporters.ParticlesExporter; //$$ import net.minecraft.client.renderer.WorldRenderer; //#else //$$ import net.minecraft.client.renderer.Tessellator; @@ -83,10 +83,12 @@ package com.replaymod.render.mixin; //$$ rotYZ = (float) (-rotZ * Math.sin(pitch)); //$$ rotXY = (float) (rotX * Math.sin(pitch)); //$$ } -//$$ BlendState blendState = BlendState.getState(); -//$$ if (blendState != null) { -//$$ blendState.get(ParticlesExporter.class).onRender(fx, partialTicks); -//$$ } + //#if MC>=10800 + //$$ BlendState blendState = BlendState.getState(); + //$$ if (blendState != null) { + //$$ blendState.get(ParticlesExporter.class).onRender(fx, partialTicks); + //$$ } + //#endif //#if MC>=10809 //$$ fx.renderParticle(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY); //#else diff --git a/src/main/resources/mixins.render.blend.replaymod.json b/src/main/resources/mixins.render.blend.replaymod.json index 3dcc3306..acc97473 100644 --- a/src/main/resources/mixins.render.blend.replaymod.json +++ b/src/main/resources/mixins.render.blend.replaymod.json @@ -4,6 +4,7 @@ "mixins": [], "server": [], "client": [ + //#if MC>=10800 "MixinChunkRenderWorker", "MixinEffectRenderer", "MixinModelRenderer", @@ -11,6 +12,7 @@ "MixinRenderItem", "MixinRenderManager", "MixinTileEntityRendererDispatcher" + //#endif ], "compatibilityLevel": "JAVA_8", "minVersion": "0.6.11", From 4eb5d2d9cfc1f7de378ca85f8c50b7a2aeec7bf6 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 13 Mar 2019 17:43:33 +0100 Subject: [PATCH 06/12] Preshadow lwjgl_util instead of copying source of specific classes --- jGui | 2 +- versions/common.gradle | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/jGui b/jGui index 79b0aaf3..85b7fa24 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 79b0aaf3e9b5c70739c30a9ce1af9efa8adb26dc +Subproject commit 85b7fa242482cc1743c80a0c01b07ec898ea4b2d diff --git a/versions/common.gradle b/versions/common.gradle index f9de860b..ac5c198d 100644 --- a/versions/common.gradle +++ b/versions/common.gradle @@ -192,6 +192,9 @@ dependencies { transitive = false // FG 1.2 puts all MC deps into the compile configuration and we don't want to shade those exclude group: 'org.projectlombok', module: 'lombok' // runtime only for @SneakyThrows which isn't used } + project(":jGui:$jGuiVersion").afterEvaluate { + shade files(project(":jGui:$jGuiVersion").tasks.preshadowJar.archivePath) // include pre-shadowed lwjgl_util + } if (!gradle.gradleVersion.startsWith('3.')) { annotationProcessor 'org.projectlombok:lombok:1.16.6' From 22ab39c2db7fe2ca4ddcad5a830f0d0a079b5e26 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 13 Mar 2019 19:10:44 +0100 Subject: [PATCH 07/12] Get blend export running on 1.13 --- .../render/blend/BlendFrameCapturer.java | 6 +-- .../render/blend/BlendMeshBuilder.java | 19 +++++-- .../replaymod/render/blend/BlendState.java | 13 +++-- .../java/com/replaymod/render/blend/Util.java | 20 ++++--- .../replaymod/render/blend/data/DMesh.java | 10 ++-- .../replaymod/render/blend/data/DObject.java | 4 +- .../render/blend/exporters/ChunkExporter.java | 19 ++++--- .../blend/exporters/EntityExporter.java | 13 +++-- .../render/blend/exporters/ItemExporter.java | 52 +++++++++++++------ .../blend/exporters/ParticlesExporter.java | 11 ++-- .../render/blend/exporters/RenderState.java | 2 +- .../blend/exporters/TileEntityExporter.java | 7 +-- .../blend/mixin/MixinChunkRenderWorker.java | 25 ++++++--- .../blend/mixin/MixinModelRenderer.java | 7 ++- .../render/blend/mixin/MixinRenderGlobal.java | 37 +++++++++---- .../render/blend/mixin/MixinRenderItem.java | 25 ++++++--- .../blend/mixin/MixinRenderManager.java | 14 ++++- .../MixinTileEntityRendererDispatcher.java | 24 ++++++--- src/main/resources/META-INF/replaymod_at.cfg | 7 ++- versions/common.gradle | 2 +- 20 files changed, 220 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java b/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java index 71378bc9..3627c9d0 100644 --- a/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java +++ b/src/main/java/com/replaymod/render/blend/BlendFrameCapturer.java @@ -1,12 +1,12 @@ package com.replaymod.render.blend; +import com.replaymod.core.versions.MCVer; import com.replaymod.render.capturer.RenderInfo; import com.replaymod.render.capturer.WorldRenderer; import com.replaymod.render.frame.RGBFrame; import com.replaymod.render.rendering.FrameCapturer; import com.replaymod.render.utils.ByteBufferPool; -import net.minecraft.client.Minecraft; -import org.lwjgl.util.Dimension; +import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; import java.io.IOException; @@ -34,7 +34,7 @@ public class BlendFrameCapturer implements FrameCapturer { renderInfo.updateForNextFrame(); BlendState.getState().preFrame(framesDone); - worldRenderer.renderWorld(Minecraft.getMinecraft().timer.renderPartialTicks, null); + worldRenderer.renderWorld(MCVer.getMinecraft().timer.renderPartialTicks, null); BlendState.getState().postFrame(framesDone); return new RGBFrame(framesDone++, new Dimension(0, 0), ByteBufferPool.allocate(0)); diff --git a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java index 48fdd148..62c6c876 100644 --- a/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java +++ b/src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java @@ -3,13 +3,13 @@ package com.replaymod.render.blend; import com.replaymod.render.blend.data.DMaterial; import com.replaymod.render.blend.data.DMesh; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.ReadableVector3f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector2f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.client.renderer.vertex.VertexFormatElement; import org.lwjgl.opengl.GL11; -import org.lwjgl.util.vector.ReadableVector3f; -import org.lwjgl.util.vector.Vector2f; -import org.lwjgl.util.vector.Vector3f; //#if MC>=10904 //#if MC>=11200 @@ -139,7 +139,12 @@ public class BlendMeshBuilder } public static DMesh addBufferToMesh(ByteBuffer buffer, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { - return addBufferToMesh(buffer, buffer.remaining() / vertexFormat.getNextOffset(), mode, vertexFormat, mesh, vertOffset); + //#if MC>=11300 + int vertexCount = buffer.remaining() / vertexFormat.getSize(); + //#else + //$$ int vertexCount = buffer.remaining() / vertexFormat.getNextOffset(); + //#endif + return addBufferToMesh(buffer, vertexCount, mode, vertexFormat, mesh, vertOffset); } public static DMesh addBufferToMesh(ByteBuffer buffer, int vertexCount, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f vertOffset) { @@ -188,7 +193,11 @@ public class BlendMeshBuilder List vertices = new ArrayList<>(vertexCount); List uvs = new ArrayList<>(vertexCount); List colors = new ArrayList<>(vertexCount); - int step = vertexFormat.getNextOffset(); + //#if MC>=11300 + int step = vertexFormat.getSize(); + //#else + //$$ int step = vertexFormat.getNextOffset(); + //#endif for (int offset = 0; offset < vertexCount * step; offset += step) { vertices.add(new DMesh.Vertex( buffer.getFloat(offset ) - vertOffset.getX(), diff --git a/src/main/java/com/replaymod/render/blend/BlendState.java b/src/main/java/com/replaymod/render/blend/BlendState.java index 19133842..1eab7fd4 100644 --- a/src/main/java/com/replaymod/render/blend/BlendState.java +++ b/src/main/java/com/replaymod/render/blend/BlendState.java @@ -12,7 +12,6 @@ import com.replaymod.render.blend.exporters.TileEntityExporter; //#endif import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; -import net.minecraft.util.ReportedException; import org.apache.commons.io.output.NullOutputStream; import org.blender.utils.BlenderFactory; import org.cakelab.blender.io.BlenderFile; @@ -83,7 +82,7 @@ public class BlendState implements Exporter { CrashReport report = CrashReport.makeCrashReport(e, "Setup of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); addDetail(category, "Exporter", exporter::toString); - throw new ReportedException(report); + throw newReportedException(report); } } } @@ -97,7 +96,7 @@ public class BlendState implements Exporter { CrashReport report = CrashReport.makeCrashReport(e, "Tear down of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); addDetail(category, "Exporter", exporter::toString); - throw new ReportedException(report); + throw newReportedException(report); } } @@ -134,8 +133,8 @@ public class BlendState implements Exporter { CrashReport report = CrashReport.makeCrashReport(e, "Pre frame of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); addDetail(category, "Exporter", exporter::toString); - category.addCrashSection("Frame", frame); - throw new ReportedException(report); + addDetail(category, "Frame", () -> String.valueOf(frame)); + throw newReportedException(report); } } } @@ -149,8 +148,8 @@ public class BlendState implements Exporter { CrashReport report = CrashReport.makeCrashReport(e, "Post frame of blend exporter"); CrashReportCategory category = report.makeCategory("Exporter"); addDetail(category, "Exporter", exporter::toString); - category.addCrashSection("Frame", frame); - throw new ReportedException(report); + addDetail(category, "Frame", () -> String.valueOf(frame)); + throw newReportedException(report); } } diff --git a/src/main/java/com/replaymod/render/blend/Util.java b/src/main/java/com/replaymod/render/blend/Util.java index f438f87e..4f10c55c 100644 --- a/src/main/java/com/replaymod/render/blend/Util.java +++ b/src/main/java/com/replaymod/render/blend/Util.java @@ -1,5 +1,9 @@ package com.replaymod.render.blend; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix3f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Quaternion; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; @@ -8,10 +12,6 @@ import org.blender.dna.ListBase; import org.blender.utils.BlenderFactory; import org.cakelab.blender.nio.CPointer; import org.lwjgl.opengl.GL11; -import org.lwjgl.util.vector.Matrix3f; -import org.lwjgl.util.vector.Matrix4f; -import org.lwjgl.util.vector.Quaternion; -import org.lwjgl.util.vector.Vector3f; import java.io.IOException; import java.nio.FloatBuffer; @@ -37,7 +37,11 @@ public class Util { private static FloatBuffer floatBuffer = GLAllocation.createDirectFloatBuffer(16); public static Matrix4f getGlMatrix(int matrix) { floatBuffer.clear(); - GL11.glGetFloat(matrix, floatBuffer); + //#if MC>=11300 + GL11.glGetFloatv(matrix, floatBuffer); + //#else + //$$ GL11.glGetFloat(matrix, floatBuffer); + //#endif floatBuffer.rewind(); Matrix4f mat = new Matrix4f(); mat.load(floatBuffer); @@ -159,7 +163,11 @@ public class Util { public static String getTileEntityId(TileEntity tileEntity) { NBTTagCompound nbt = new NBTTagCompound(); - tileEntity.writeToNBT(nbt); + //#if MC>=11300 + tileEntity.write(nbt); + //#else + //$$ tileEntity.writeToNBT(nbt); + //#endif return nbt.getString("id"); } diff --git a/src/main/java/com/replaymod/render/blend/data/DMesh.java b/src/main/java/com/replaymod/render/blend/data/DMesh.java index e9f29879..c281fa0e 100644 --- a/src/main/java/com/replaymod/render/blend/data/DMesh.java +++ b/src/main/java/com/replaymod/render/blend/data/DMesh.java @@ -1,5 +1,7 @@ package com.replaymod.render.blend.data; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector2f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import org.blender.dna.CustomData; import org.blender.dna.CustomDataLayer; import org.blender.dna.Image; @@ -16,8 +18,6 @@ import org.blender.dna.Mesh; import org.cakelab.blender.io.block.BlockCodes; import org.cakelab.blender.nio.CArrayFacade; import org.cakelab.blender.nio.CPointer; -import org.lwjgl.util.vector.Vector2f; -import org.lwjgl.util.vector.Vector3f; import java.io.IOException; import java.util.ArrayList; @@ -199,9 +199,9 @@ public class DMesh { public void serialize(MVert mVert) throws IOException { CArrayFacade pos = mVert.getCo(); - pos.set(0, this.pos.x); - pos.set(1, this.pos.y); - pos.set(2, this.pos.z); + pos.set(0, this.pos.getX()); + pos.set(1, this.pos.getY()); + pos.set(2, this.pos.getZ()); CArrayFacade norm = mVert.getNo(); norm.set(0, this.normX); norm.set(1, this.normY); diff --git a/src/main/java/com/replaymod/render/blend/data/DObject.java b/src/main/java/com/replaymod/render/blend/data/DObject.java index 2ea96831..c375dfc3 100644 --- a/src/main/java/com/replaymod/render/blend/data/DObject.java +++ b/src/main/java/com/replaymod/render/blend/data/DObject.java @@ -1,6 +1,8 @@ package com.replaymod.render.blend.data; import com.replaymod.render.blend.Util; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Quaternion; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import org.blender.dna.AnimData; import org.blender.dna.BlenderObject; import org.blender.dna.Material; @@ -11,8 +13,6 @@ import org.blender.dna.bTrackToConstraint; import org.cakelab.blender.io.block.BlockCodes; import org.cakelab.blender.nio.CArrayFacade; import org.cakelab.blender.nio.CPointer; -import org.lwjgl.util.vector.Quaternion; -import org.lwjgl.util.vector.Vector3f; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java index 2f7a5d18..ef0d4a65 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ChunkExporter.java @@ -1,18 +1,18 @@ //#if MC>=10800 package com.replaymod.render.blend.exporters; +import com.replaymod.core.versions.MCVer; import com.replaymod.render.blend.BlendMeshBuilder; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.Exporter; -import com.replaymod.render.blend.data.DMaterial; import com.replaymod.render.blend.data.DMesh; import com.replaymod.render.blend.data.DObject; import com.replaymod.replaystudio.us.myles.ViaVersion.util.ReflectionUtil; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import lombok.SneakyThrows; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.chunk.CompiledChunk; import net.minecraft.client.renderer.chunk.RenderChunk; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; @@ -20,7 +20,12 @@ import net.minecraft.client.renderer.vertex.VertexBuffer; import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL15; -import org.lwjgl.util.vector.Vector3f; + +//#if MC>=11300 +import net.minecraft.client.renderer.WorldRenderer.ContainerLocalRenderInformation; +//#else +//$$ import net.minecraft.client.renderer.RenderGlobal.ContainerLocalRenderInformation; +//#endif //#if MC>=10904 import net.minecraft.util.BlockRenderLayer; @@ -68,10 +73,10 @@ public class ChunkExporter implements Exporter { @SneakyThrows public void setup() throws IOException { - Minecraft mc = Minecraft.getMinecraft(); + Minecraft mc = MCVer.getMinecraft(); @SuppressWarnings("unchecked") - List renderInfos = mc.renderGlobal.renderInfos; - for (RenderGlobal.ContainerLocalRenderInformation renderInfo : renderInfos) { + List renderInfos = mc.renderGlobal.renderInfos; + for (ContainerLocalRenderInformation renderInfo : renderInfos) { RenderChunk renderChunk = ReflectionUtil.get(renderInfo, "renderChunk", RenderChunk.class); // SneakyThrows CompiledChunk compiledChunk = renderChunk.getCompiledChunk(); if (!compiledChunk.isEmpty()) { @@ -167,7 +172,7 @@ public class ChunkExporter implements Exporter { GL15.glGetBufferSubData(OpenGlHelper.GL_ARRAY_BUFFER, 0, byteBuffer); vertexBuffer.unbindBuffer(); - Minecraft.getMinecraft().getTextureManager().bindTexture(LOCATION_BLOCKS_TEXTURE); + MCVer.getMinecraft().getTextureManager().bindTexture(LOCATION_BLOCKS_TEXTURE); return BlendMeshBuilder.addBufferToMesh(byteBuffer, GL11.GL_QUADS, DefaultVertexFormats.BLOCK, null, null); } diff --git a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java index 4d32339a..a8146885 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java @@ -1,14 +1,15 @@ //#if MC>=10800 package com.replaymod.render.blend.exporters; +import com.replaymod.core.versions.MCVer; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DObject; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import lombok.SneakyThrows; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; -import org.lwjgl.util.vector.Matrix4f; -import org.lwjgl.util.vector.Vector3f; import java.io.IOException; import java.util.IdentityHashMap; @@ -17,7 +18,7 @@ import java.util.Map; import static com.replaymod.render.blend.Util.getGlModelViewMatrix; public class EntityExporter implements Exporter { - private final Minecraft mc = Minecraft.getMinecraft(); + private final Minecraft mc = MCVer.getMinecraft(); private final RenderState renderState; private DObject entitiesObject; private Map entityObjects; @@ -59,7 +60,11 @@ public class EntityExporter implements Exporter { if (entityObject == null) { entityObject = new DObject(DObject.Type.OB_EMPTY); entityObject.setParent(renderState.peekObject()); - entityObject.id.name = entity.getName(); + //#if MC>=11300 + entityObject.id.name = entity.getName().getString(); + //#else + //$$ entityObject.id.name = entity.getName(); + //#endif entityObjects.put(entity, entityObject); } renderState.pushObject(entityObject); diff --git a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java index 8493b78c..7f7a9178 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java @@ -5,22 +5,29 @@ import com.replaymod.render.blend.BlendMeshBuilder; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMesh; import com.replaymod.render.blend.data.DObject; -import net.minecraft.client.renderer.block.model.BakedQuad; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; import net.minecraftforge.client.model.pipeline.LightUtil; import org.lwjgl.opengl.GL11; +//#if MC>=11300 +import net.minecraft.client.renderer.model.IBakedModel; +//#else +//$$ import net.minecraft.client.renderer.block.model.BakedQuad; //#if MC>=10904 -import net.minecraft.client.renderer.RenderItem; -import net.minecraft.client.renderer.block.model.IBakedModel; +//$$ import net.minecraft.client.renderer.RenderItem; +//$$ import net.minecraft.client.renderer.block.model.IBakedModel; //#else //$$ import net.minecraft.client.renderer.entity.RenderItem; //$$ import net.minecraft.client.resources.model.IBakedModel; //#endif +//#endif import java.util.List; +import java.util.Random; public class ItemExporter implements Exporter { private final RenderState renderState; @@ -29,7 +36,7 @@ public class ItemExporter implements Exporter { this.renderState = renderState; } - public void onRender(RenderItem renderItem, IBakedModel model, ItemStack stack) { + public void onRender(Object renderItem, IBakedModel model, ItemStack stack) { DObject object = getObjectForItemStack(renderItem, model, stack); renderState.pushObject(object); @@ -42,7 +49,7 @@ public class ItemExporter implements Exporter { renderState.pop(); } - private DObject getObjectForItemStack(RenderItem renderItem, IBakedModel model, ItemStack stack) { + private DObject getObjectForItemStack(Object renderItem, IBakedModel model, ItemStack stack) { int frame = renderState.getFrame(); DObject parent = renderState.peekObject(); DObject object = null; @@ -56,7 +63,11 @@ public class ItemExporter implements Exporter { } if (object == null) { object = new ItemBasedDObject(renderItem, model, stack); - object.id.name = stack.getDisplayName(); + //#if MC>=11300 + object.id.name = stack.getDisplayName().getString(); + //#else + //$$ object.id.name = stack.getDisplayName(); + //#endif object.setParent(parent); } object.lastFrame = frame; @@ -64,7 +75,7 @@ public class ItemExporter implements Exporter { } @SuppressWarnings("unchecked") - private static DMesh generateMeshForItemStack(RenderItem renderItem, IBakedModel model, ItemStack stack) { + private static DMesh generateMeshForItemStack(Object renderItem, IBakedModel model, ItemStack stack) { DMesh mesh = new DMesh(); BlendMeshBuilder builder = new BlendMeshBuilder(mesh); builder.setWellBehaved(true); @@ -75,30 +86,41 @@ public class ItemExporter implements Exporter { //$$ builder.setVertexFormat(DefaultVertexFormats.ITEM); //#endif - //#if MC>=10904 + //#if MC>=11300 for (EnumFacing face : EnumFacing.values()) { - renderQuads(renderItem, builder, model.getQuads(null, face, 0), stack); + renderQuads(renderItem, builder, model.getQuads(null, face, new Random()), stack); } - renderQuads(renderItem, builder, model.getQuads(null, null, 0), stack); + renderQuads(renderItem, builder, model.getQuads(null, null, new Random()), stack); + //#else + //#if MC>=10904 + //$$ for (EnumFacing face : EnumFacing.values()) { + //$$ renderQuads(renderItem, builder, model.getQuads(null, face, 0), stack); + //$$ } + //$$ renderQuads(renderItem, builder, model.getQuads(null, null, 0), stack); //#else //$$ for (EnumFacing face : EnumFacing.values()) { //$$ renderQuads(renderItem, builder, model.getFaceQuads(face), stack); //$$ } //$$ renderQuads(renderItem, builder, model.getGeneralQuads(), stack); //#endif + //#endif builder.finishDrawing(); return mesh; } - private static void renderQuads(RenderItem renderItem, BlendMeshBuilder buffer, List quads, ItemStack stack) { + private static void renderQuads(Object renderItem, BlendMeshBuilder buffer, List quads, ItemStack stack) { for (BakedQuad quad : quads) { int color = stack != null && quad.hasTintIndex() //#if MC>=10904 - ? renderItem.itemColors.getColorFromItemstack(stack, quad.getTintIndex()) | 0xff000000 + ? ((ItemRenderer) renderItem).itemColors.getColor(stack, quad.getTintIndex()) | 0xff000000 + //#else + //#if MC>=10904 + //$$ ? ((RenderItem) renderItem).itemColors.getColorFromItemstack(stack, quad.getTintIndex()) | 0xff000000 //#else //$$ ? stack.getItem().getColorFromItemStack(stack, quad.getTintIndex()) | 0xff000000 //#endif + //#endif : 0xffffffff; LightUtil.renderQuadColor(buffer, quad, color); } @@ -106,19 +128,19 @@ public class ItemExporter implements Exporter { } private static class ItemBasedDObject extends DObject { - private final RenderItem renderItem; + private final Object renderItem; private final IBakedModel model; private final ItemStack stack; private boolean valid; - public ItemBasedDObject(RenderItem renderItem, IBakedModel model, ItemStack stack) { + public ItemBasedDObject(Object renderItem, IBakedModel model, ItemStack stack) { super(generateMeshForItemStack(renderItem, model, stack)); this.renderItem = renderItem; this.model = model; this.stack = stack; } - public boolean isBasedOn(RenderItem renderItem, IBakedModel model, ItemStack stack) { + public boolean isBasedOn(Object renderItem, IBakedModel model, ItemStack stack) { return this.renderItem == renderItem && this.model == model && this.stack == stack; } diff --git a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java index 565e63f7..5b06caa4 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -1,20 +1,21 @@ //#if MC>=10800 package com.replaymod.render.blend.exporters; +import com.replaymod.core.versions.MCVer; import com.replaymod.render.blend.BlendMeshBuilder; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMesh; import com.replaymod.render.blend.data.DObject; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import net.minecraft.client.Minecraft; -import net.minecraft.entity.Entity; -import org.lwjgl.util.vector.Matrix4f; -import org.lwjgl.util.vector.Vector3f; //#if MC>=10904 import net.minecraft.client.particle.Particle; //#else //$$ import net.minecraft.client.particle.EntityFX; +//$$ import net.minecraft.entity.Entity; //#endif //#if MC>=10809 @@ -29,7 +30,7 @@ import static com.replaymod.core.versions.MCVer.*; import static com.replaymod.render.blend.Util.getGlModelViewMatrix; public class ParticlesExporter implements Exporter { - private final Minecraft mc = Minecraft.getMinecraft(); + private final Minecraft mc = MCVer.getMinecraft(); private final RenderState renderState; private DObject pointAtObject; private DObject particlesObject; @@ -151,7 +152,7 @@ public class ParticlesExporter implements Exporter { //$$ builder.startDrawingQuads(); //#endif //#if MC>=10809 - particle.renderParticle(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); + particle.renderParticle(builder, MCVer.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); //#else //$$ particle.func_180434_a(builder, Minecraft.getMinecraft().getRenderViewEntity(), 0, 1, 1, 0, 0, 0); //#endif diff --git a/src/main/java/com/replaymod/render/blend/exporters/RenderState.java b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java index fbf4ab9b..9f385ce3 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/RenderState.java +++ b/src/main/java/com/replaymod/render/blend/exporters/RenderState.java @@ -5,7 +5,7 @@ import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMaterial; import com.replaymod.render.blend.data.DObject; -import org.lwjgl.util.vector.Matrix4f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; import java.io.IOException; import java.util.Deque; diff --git a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java index 7f77f858..b6fd2c59 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/TileEntityExporter.java @@ -1,14 +1,15 @@ //#if MC>=10800 package com.replaymod.render.blend.exporters; +import com.replaymod.core.versions.MCVer; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DObject; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Matrix4f; +import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import lombok.SneakyThrows; import net.minecraft.client.Minecraft; import net.minecraft.tileentity.TileEntity; -import org.lwjgl.util.vector.Matrix4f; -import org.lwjgl.util.vector.Vector3f; //#if MC>=10904 import net.minecraft.util.math.BlockPos; @@ -24,7 +25,7 @@ import static com.replaymod.render.blend.Util.getGlModelViewMatrix; import static com.replaymod.render.blend.Util.getTileEntityId; public class TileEntityExporter implements Exporter { - private final Minecraft mc = Minecraft.getMinecraft(); + private final Minecraft mc = MCVer.getMinecraft(); private final RenderState renderState; private DObject tileEntitiesObject; private Map tileEntityObjects; diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java index 4c59e6cd..1ef82647 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java @@ -3,31 +3,42 @@ package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.exporters.ChunkExporter; -import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator; import net.minecraft.client.renderer.chunk.ChunkRenderWorker; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -//#if MC>=10904 -import net.minecraft.util.BlockRenderLayer; +//#if MC>=11300 +import net.minecraft.client.renderer.chunk.ChunkRenderTask; //#else -//$$ import net.minecraft.util.EnumWorldBlockLayer; +//$$ import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator; //#endif @Mixin(ChunkRenderWorker.class) public abstract class MixinChunkRenderWorker { @Inject(method = "processTask", at = @At("RETURN")) - public void afterChunkUpdate(ChunkCompileTaskGenerator task, CallbackInfo ci) { + //if MC>=11300 + public void afterChunkUpdate(ChunkRenderTask task, CallbackInfo ci) { BlendState blendState = BlendState.getState(); if (blendState != null) { - if (task.getStatus() == ChunkCompileTaskGenerator.Status.DONE - && task.getType() == ChunkCompileTaskGenerator.Type.REBUILD_CHUNK) { + if (task.getStatus() == ChunkRenderTask.Status.DONE + && task.getType() == ChunkRenderTask.Type.REBUILD_CHUNK) { blendState.get(ChunkExporter.class).addChunkUpdate(task.getRenderChunk(), task.getCompiledChunk()); } } } + //#else + //$$ public void afterChunkUpdate(ChunkCompileTaskGenerator task, CallbackInfo ci) { + //$$ BlendState blendState = BlendState.getState(); + //$$ if (blendState != null) { + //$$ if (task.getStatus() == ChunkCompileTaskGenerator.Status.DONE + //$$ && task.getType() == ChunkCompileTaskGenerator.Type.REBUILD_CHUNK) { + //$$ blendState.get(ChunkExporter.class).addChunkUpdate(task.getRenderChunk(), task.getCompiledChunk()); + //$$ } + //$$ } + //$$ } + //#endif } //#endif diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java b/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java index 9a540bad..e452b1f5 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinModelRenderer.java @@ -3,12 +3,17 @@ package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.exporters.ModelRendererExporter; -import net.minecraft.client.model.ModelRenderer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=11300 +import net.minecraft.client.renderer.entity.model.ModelRenderer; +//#else +//$$ import net.minecraft.client.model.ModelRenderer; +//#endif + @Mixin(ModelRenderer.class) public abstract class MixinModelRenderer { @Inject(method = "render", at = @At("HEAD")) diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java index 44256e49..b77e4e0d 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java @@ -4,7 +4,6 @@ package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.exporters.EntityExporter; import com.replaymod.render.blend.exporters.TileEntityExporter; -import net.minecraft.client.renderer.RenderGlobal; import net.minecraft.client.renderer.culling.ICamera; import net.minecraft.entity.Entity; import org.spongepowered.asm.mixin.Mixin; @@ -12,7 +11,17 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(RenderGlobal.class) +//#if MC>=11300 +import net.minecraft.client.renderer.WorldRenderer; +//#else +//$$ import net.minecraft.client.renderer.RenderGlobal; +//#endif + +//#if MC>=11300 +@Mixin(WorldRenderer.class) +//#else +//$$ @Mixin(RenderGlobal.class) +//#endif public abstract class MixinRenderGlobal { // FIXME wither skull ._. mojang pls @@ -46,9 +55,14 @@ public abstract class MixinRenderGlobal { } } - @Inject(method = "renderEntities", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V")) + @Inject(method = "renderEntities", at = @At( + value = "INVOKE", + //#if MC>=11300 + target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;render(Lnet/minecraft/tileentity/TileEntity;FI)V" + //#else + //$$ target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V") + //#endif + )) public void preTileEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { BlendState blendState = BlendState.getState(); if (blendState != null) { @@ -56,10 +70,15 @@ public abstract class MixinRenderGlobal { } } - @Inject(method = "renderEntities", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V", - shift = At.Shift.AFTER)) + @Inject(method = "renderEntities", at = @At( + value = "INVOKE", + //#if MC>=11300 + target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;render(Lnet/minecraft/tileentity/TileEntity;FI)V", + //#else + //$$ target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V"), + //#endif + shift = At.Shift.AFTER + )) public void postTileEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { BlendState blendState = BlendState.getState(); if (blendState != null) { diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java index 09f38a1d..083384c7 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java @@ -9,27 +9,40 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=11300 +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.model.IBakedModel; +//#else //#if MC>=10904 -import net.minecraft.client.renderer.RenderItem; -import net.minecraft.client.renderer.block.model.IBakedModel; +//$$ import net.minecraft.client.renderer.RenderItem; +//$$ import net.minecraft.client.renderer.block.model.IBakedModel; //#else //$$ import net.minecraft.client.renderer.entity.RenderItem; //$$ import net.minecraft.client.resources.model.IBakedModel; //#endif -@Mixin(RenderItem.class) +//#if MC>=11300 +@Mixin(ItemRenderer.class) +//#else +//$$ @Mixin(RenderItem.class) +//#endif public abstract class MixinRenderItem { - //#if MC>=10904 - @Inject(method = "renderModel(Lnet/minecraft/client/renderer/block/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", + //#if MC>=11300 + @Inject(method = "renderModel(Lnet/minecraft/client/renderer/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", at = @At("HEAD")) //#else + //#if MC>=10904 + //$$ @Inject(method = "renderModel(Lnet/minecraft/client/renderer/block/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", + //$$ at = @At("HEAD")) + //#else //$$ @Inject(method = "renderModel(Lnet/minecraft/client/resources/model/IBakedModel;Lnet/minecraft/item/ItemStack;)V", //$$ at = @At("HEAD")) //#endif + //#endif private void onRenderModel(IBakedModel model, ItemStack stack, CallbackInfo ci) { BlendState blendState = BlendState.getState(); if (blendState != null) { - blendState.get(ItemExporter.class).onRender((RenderItem)(Object)this, model, stack); + blendState.get(ItemExporter.class).onRender(this, model, stack); } } } diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java index ca777c2b..17931095 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderManager.java @@ -18,7 +18,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(RenderManager.class) public abstract class MixinRenderManager { - @Inject(method = "doRenderEntity", + @Inject( + //#if MC>=11300 + method = "renderEntity", + //#else + //$$ method = "doRenderEntity", + //#endif at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V")) public void preRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box, @@ -33,7 +38,12 @@ public abstract class MixinRenderManager { } } - @Inject(method = "doRenderEntity", + @Inject( + //#if MC>=11300 + method = "renderEntity", + //#else + //$$ method = "doRenderEntity", + //#endif at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/Render;doRender(Lnet/minecraft/entity/Entity;DDDFF)V", shift = At.Shift.AFTER)) diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java index 65d95761..089ecea7 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java @@ -13,15 +13,22 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(TileEntityRendererDispatcher.class) public abstract class MixinTileEntityRendererDispatcher { - //#if MC>=11200 - @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFIF)V", + //#if MC>=11300 + @Inject(method = "render(Lnet/minecraft/tileentity/TileEntity;DDDFIZ)V", at = @At("HEAD")) - public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, float alpha, CallbackInfo ci) { + public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, boolean hasNoBlock, CallbackInfo ci) { + float alpha = 1; + //#else + //#if MC>=11200 + //$$ @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFIF)V", + //$$ at = @At("HEAD")) + //$$ public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, float alpha, CallbackInfo ci) { //#else //$$ @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", //$$ at = @At("HEAD")) //$$ public void preRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { //$$ float alpha = 1; + //#endif //#endif BlendState blendState = BlendState.getState(); if (blendState != null) { @@ -29,14 +36,19 @@ public abstract class MixinTileEntityRendererDispatcher { } } - //#if MC>=11200 - @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFIF)V", + //#if MC>=11300 + @Inject(method = "render(Lnet/minecraft/tileentity/TileEntity;DDDFIZ)V", at = @At("RETURN")) - public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, float alpha, CallbackInfo ci) { + public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, boolean hasNoBlock, CallbackInfo ci) { + //#if MC>=11200 + //$$ @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFIF)V", + //$$ at = @At("RETURN")) + //$$ public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, float alpha, CallbackInfo ci) { //#else //$$ @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFI)V", //$$ at = @At("RETURN")) //$$ public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, CallbackInfo ci) { + //#endif //#endif BlendState blendState = BlendState.getState(); if (blendState != null) { diff --git a/src/main/resources/META-INF/replaymod_at.cfg b/src/main/resources/META-INF/replaymod_at.cfg index 866e5a48..0df2108e 100644 --- a/src/main/resources/META-INF/replaymod_at.cfg +++ b/src/main/resources/META-INF/replaymod_at.cfg @@ -110,8 +110,11 @@ public net.minecraft.client.renderer.WorldRenderer field_72740_G # renderEntitie ##endif ##endif -public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation -#public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation field_178553_a # renderChunk +##if MC>=11300 +public net.minecraft.client.renderer.WorldRenderer$ContainerLocalRenderInformation +##else +#$$ public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation +##endif # ChunkRenderDispatcher public-f net.minecraft.client.renderer.chunk.ChunkRenderDispatcher field_178519_d # queueChunkUpdates diff --git a/versions/common.gradle b/versions/common.gradle index ac5c198d..0b90624c 100644 --- a/versions/common.gradle +++ b/versions/common.gradle @@ -179,7 +179,7 @@ dependencies { shade 'org.aspectj:aspectjrt:1.8.2' - shade 'com.github.ReplayMod.JavaBlend:2.79.0:e0a1b9a' + shade 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8' def studioVersion = mcVersionStr if (studioVersion == '1.8.9') studioVersion = '1.8' From cd16e014d1730ba7d48bc342e5baef97ff82b6c7 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Wed, 13 Mar 2019 22:03:03 +0100 Subject: [PATCH 08/12] Vastly improve performance of major block name generation --- .../com/replaymod/render/blend/data/Serializer.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/replaymod/render/blend/data/Serializer.java b/src/main/java/com/replaymod/render/blend/data/Serializer.java index 63b28a50..fb54292e 100644 --- a/src/main/java/com/replaymod/render/blend/data/Serializer.java +++ b/src/main/java/com/replaymod/render/blend/data/Serializer.java @@ -24,7 +24,7 @@ import static org.cakelab.blender.io.block.BlockCodes.ID_DATA; public class Serializer { private final Map> serialized = new HashMap<>(); - private final Set usedNames = new HashSet<>(); + private final Map usedNames = new HashMap<>(); public CPointer getMajor(Object obj, Class clazz) { CPointer pointer = serialized.get(obj); @@ -47,13 +47,8 @@ public class Serializer { if (id.code != ID_DATA) { ID asID = pointer.cast(ID.class).get(); String name = id.code.toString().substring(0, 2) + id.name; - String fullName = name; - int i = 0; - while (usedNames.contains(fullName)) { - fullName = name + "." + i; - i++; - } - usedNames.add(fullName); + int counter = usedNames.compute(name, (n, i) -> i == null ? 0 : i + 1); + String fullName = counter == 0 ? name : name + "." + counter; asID.getName().fromString(fullName); } From dc6de5bd5f19286550f8f892e11107d6aa0cd151 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 14 Mar 2019 11:30:40 +0100 Subject: [PATCH 09/12] Apply rotation and scale to entity (livingbase), not its parts Reduces amount of keyframes per entity and makes it easier to work with. --- .../blend/exporters/EntityExporter.java | 22 +++++++++++---- .../blend/mixin/MixinRenderLivingBase.java | 27 +++++++++++++++++++ .../mixins.render.blend.replaymod.json | 1 + 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java diff --git a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java index a8146885..c671e3f9 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/EntityExporter.java @@ -10,6 +10,7 @@ import de.johni0702.minecraft.gui.utils.lwjgl.vector.Vector3f; import lombok.SneakyThrows; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; import java.io.IOException; import java.util.IdentityHashMap; @@ -74,15 +75,26 @@ public class EntityExporter implements Exporter { // So, we translate there, then store the model-view-matrix and then translate back to let the // renderer translate there again. // Instead of actually translating, we just add the translation on the current model-view-matrix. - Matrix4f modelView = getGlModelViewMatrix(); - Matrix4f.translate(new Vector3f((float) dx, (float) dy, (float) dz), modelView, modelView); - renderState.pushModelView(modelView); - renderState.applyLastModelViewTransformToObject(); + if (!(entity instanceof EntityLivingBase)) { // except for EntityLivingBase which get special (better) treatment + Matrix4f modelView = getGlModelViewMatrix(); + Matrix4f.translate(new Vector3f((float) dx, (float) dy, (float) dz), modelView, modelView); + renderState.pushModelView(modelView); + renderState.applyLastModelViewTransformToObject(); - entityObject.keyframeLocRotScale(renderState.getFrame()); + entityObject.keyframeLocRotScale(renderState.getFrame()); + } entityObject.setVisible(renderState.getFrame()); } + public void postEntityLivingSetup() { + // For any entity which extends EntityLivingBase, we capture its rotation and scale after it has been setup + // in addition to its position (which we capture in preRender for other entities). + // We could add custom hooks for various other entities types as well but it's probably not worth it. + renderState.pushModelView(); + renderState.applyLastModelViewTransformToObject(); + renderState.peekObject().keyframeLocRotScale(renderState.getFrame()); + } + public void postRender(Entity entity, double dx, double dy, double dz, float yaw, float renderPartialTicks) { renderState.pop(); } diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java new file mode 100644 index 00000000..289a1136 --- /dev/null +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java @@ -0,0 +1,27 @@ +//#if MC>=10800 +package com.replaymod.render.blend.mixin; + +import com.replaymod.render.blend.BlendState; +import com.replaymod.render.blend.exporters.EntityExporter; +import net.minecraft.client.renderer.entity.RenderLivingBase; +import net.minecraft.entity.EntityLivingBase; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(RenderLivingBase.class) +public abstract class MixinRenderLivingBase { + @Inject(method = "doRender", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/renderer/entity/RenderLivingBase;prepareScale(Lnet/minecraft/entity/EntityLivingBase;F)F", + shift = At.Shift.AFTER + )) + private void recordModelMatrix(EntityLivingBase entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) { + BlendState blendState = BlendState.getState(); + if (blendState != null) { + blendState.get(EntityExporter.class).postEntityLivingSetup(); + } + } +} +//#endif diff --git a/src/main/resources/mixins.render.blend.replaymod.json b/src/main/resources/mixins.render.blend.replaymod.json index acc97473..f4eb4a6a 100644 --- a/src/main/resources/mixins.render.blend.replaymod.json +++ b/src/main/resources/mixins.render.blend.replaymod.json @@ -10,6 +10,7 @@ "MixinModelRenderer", "MixinRenderGlobal", "MixinRenderItem", + "MixinRenderLivingBase", "MixinRenderManager", "MixinTileEntityRendererDispatcher" //#endif From 3cb1d8189beaad73511b4556b5c7d8cb3e03bab4 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 14 Mar 2019 16:08:28 +0100 Subject: [PATCH 10/12] Preshadow lwjgl_util instead of copying source of specific classes --- jGui | 2 +- .../replaymod/render/blend/data/DMesh.java | 26 ++++++++++++ .../blend/exporters/ParticlesExporter.java | 40 ++++++++++++------- 3 files changed, 53 insertions(+), 15 deletions(-) diff --git a/jGui b/jGui index 85b7fa24..3a35a5f9 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 85b7fa242482cc1743c80a0c01b07ec898ea4b2d +Subproject commit 3a35a5f9b724a74cd3ade2bdc58c623fac7727ad diff --git a/src/main/java/com/replaymod/render/blend/data/DMesh.java b/src/main/java/com/replaymod/render/blend/data/DMesh.java index c281fa0e..677f8ad8 100644 --- a/src/main/java/com/replaymod/render/blend/data/DMesh.java +++ b/src/main/java/com/replaymod/render/blend/data/DMesh.java @@ -189,6 +189,32 @@ public class DMesh { polys.add(new Poly(lOffset, 4, materialSlot)); } + public float getSizeX() { + float minX = Float.POSITIVE_INFINITY, maxX = Float.NEGATIVE_INFINITY; + for (Vertex vertex : vertices) { + if (vertex.pos.x < minX) { + minX = vertex.pos.x; + } + if (vertex.pos.x > maxX) { + maxX = vertex.pos.x; + } + } + return maxX - minX; + } + + public boolean hasZeroLengthEdge(float delta) { + float deltaSquared = delta * delta; + Vector3f dst = new Vector3f(); + for (Edge edge : edges) { + Vertex v1 = vertices.get(edge.v1); + Vertex v2 = vertices.get(edge.v2); + if (Vector3f.sub(v1.pos, v2.pos, dst).lengthSquared() < deltaSquared) { + return true; + } + } + return false; + } + public static class Vertex { public Vector3f pos; public short normX, normY, normZ; diff --git a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java index 5b06caa4..25b90fb1 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ParticlesExporter.java @@ -49,7 +49,6 @@ public class ParticlesExporter implements Exporter { @Override public void setup() throws IOException { - if (false) return; // FIXME make configurable (also other methods below) // FIXME replace with camera pointAtObject = new DObject(DObject.Type.OB_EMPTY); pointAtObject.id.name = "Particles Target"; @@ -71,7 +70,6 @@ public class ParticlesExporter implements Exporter { } public void preParticlesRender(boolean lit) { - if (false) return; Matrix4f modelView = getGlModelViewMatrix(); // Particles are rendered relative to the viewer location. // We however want our Particles object to not move when the viewer does, @@ -85,7 +83,6 @@ public class ParticlesExporter implements Exporter { } public void postParticlesRender() { - if (false) return; renderState.pop(); } @@ -94,10 +91,9 @@ public class ParticlesExporter implements Exporter { //#else //$$ public void onRender(EntityFX particle, float renderPartialTicks) { //#endif - if (false) return; DObject particleObject = particleObjects.get(particle); if (particleObject == null) { - particleObject = new DObject(DObject.Type.OB_EMPTY); + particleObject = new DObject(DObject.Type.OB_EMPTY); // mesh generation is delayed, see below particleObject.setParent(renderState.peekObject()); particleObject.pointAt = pointAtObject; particleObject.layers = 1 << 2; @@ -124,15 +120,32 @@ public class ParticlesExporter implements Exporter { renderState.applyLastModelViewTransformToObject(); particleObject.keyframeLoc(renderState.getFrame()); - particleObject.keyframeScale(renderState.getFrame()); - DObject frameObject = new DObject(generateMeshForParticle(particle, offset)); - frameObject.setParent(particleObject); - frameObject.layers = 1 << 2; - frameObject.id.name = particleObject.id.name + " - Frame " + renderState.getFrame(); - frameObject.keyframe("hide", 0, renderState.getFrame() - 1, 1f); - frameObject.keyframe("hide", 0, renderState.getFrame(), 0f); - frameObject.keyframe("hide", 0, renderState.getFrame() + 1, 1f); + DMesh mesh = generateMeshForParticle(particle, offset); + if (mesh.vertices.isEmpty()) { + renderState.pop(); + return; // no particle to be found? + } + if (particleObject.mesh == null) { + // Some particles start out as single points, so we can never scale those first meshes to other sizes + if (mesh.hasZeroLengthEdge(0.1f)) { + // therefore we must further delay mesh generation in these cases and assume a current model scale of 0 + particleObject.scale.set(0, 0, 0); + } else { + // until we find one proper mesh which we can then use as the "unit" mesh + particleObject.type = DObject.Type.OB_MESH; + particleObject.mesh = mesh; + particleObject.scale.set(1, 1, 1); + } + } else { + // Determine relative scale of current mesh to stored "unit" mesh + // Note: currently assumes the same scale on all relevant axes (should be true for most particles?). + float unitSize = particleObject.mesh.getSizeX(); + float currentSize = mesh.getSizeX(); + float relativeScale = currentSize / unitSize; + particleObject.scale.set(relativeScale, relativeScale, relativeScale); + } + particleObject.keyframeScale(renderState.getFrame()); renderState.pop(); } @@ -162,7 +175,6 @@ public class ParticlesExporter implements Exporter { @Override public void postFrame(int frame) throws IOException { - if (false) return; particleObjects.entrySet().stream() .filter(entry -> !particleObjectsSeen.containsKey(entry.getKey())) .forEach(entry -> entry.getValue().keyframe("hide", 0, renderState.getFrame(), 1f)); From 7cc62b13c180f1d7870bf12dd84943462dbd0f10 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 14 Mar 2019 17:00:44 +0100 Subject: [PATCH 11/12] Fix blend compilation on pre-1.13 --- jGui | 2 +- .../render/blend/exporters/ItemExporter.java | 4 ++-- .../blend/mixin/MixinChunkRenderWorker.java | 2 +- .../render/blend/mixin/MixinRenderGlobal.java | 4 ++-- .../render/blend/mixin/MixinRenderItem.java | 1 + .../render/blend/mixin/MixinRenderLivingBase.java | 15 ++++++++++++++- .../mixin/MixinTileEntityRendererDispatcher.java | 1 + 7 files changed, 22 insertions(+), 7 deletions(-) diff --git a/jGui b/jGui index 3a35a5f9..8019dfd1 160000 --- a/jGui +++ b/jGui @@ -1 +1 @@ -Subproject commit 3a35a5f9b724a74cd3ade2bdc58c623fac7727ad +Subproject commit 8019dfd11a0afb87e4ed19fc4056b0fb3973788f diff --git a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java index 7f7a9178..1f6eb509 100644 --- a/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java +++ b/src/main/java/com/replaymod/render/blend/exporters/ItemExporter.java @@ -6,7 +6,6 @@ import com.replaymod.render.blend.Exporter; import com.replaymod.render.blend.data.DMesh; import com.replaymod.render.blend.data.DObject; import net.minecraft.client.renderer.ItemRenderer; -import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; import net.minecraft.util.EnumFacing; @@ -14,6 +13,7 @@ import net.minecraftforge.client.model.pipeline.LightUtil; import org.lwjgl.opengl.GL11; //#if MC>=11300 +import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; //#else //$$ import net.minecraft.client.renderer.block.model.BakedQuad; @@ -112,7 +112,7 @@ public class ItemExporter implements Exporter { private static void renderQuads(Object renderItem, BlendMeshBuilder buffer, List quads, ItemStack stack) { for (BakedQuad quad : quads) { int color = stack != null && quad.hasTintIndex() - //#if MC>=10904 + //#if MC>=11300 ? ((ItemRenderer) renderItem).itemColors.getColor(stack, quad.getTintIndex()) | 0xff000000 //#else //#if MC>=10904 diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java index 1ef82647..46ea9cde 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinChunkRenderWorker.java @@ -19,7 +19,7 @@ import net.minecraft.client.renderer.chunk.ChunkRenderTask; public abstract class MixinChunkRenderWorker { @Inject(method = "processTask", at = @At("RETURN")) - //if MC>=11300 + //#if MC>=11300 public void afterChunkUpdate(ChunkRenderTask task, CallbackInfo ci) { BlendState blendState = BlendState.getState(); if (blendState != null) { diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java index b77e4e0d..bd1384b2 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderGlobal.java @@ -60,7 +60,7 @@ public abstract class MixinRenderGlobal { //#if MC>=11300 target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;render(Lnet/minecraft/tileentity/TileEntity;FI)V" //#else - //$$ target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V") + //$$ target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V" //#endif )) public void preTileEntityRender(Entity view, ICamera camera, float renderPartialTicks, CallbackInfo ci) { @@ -75,7 +75,7 @@ public abstract class MixinRenderGlobal { //#if MC>=11300 target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;render(Lnet/minecraft/tileentity/TileEntity;FI)V", //#else - //$$ target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V"), + //$$ target = "Lnet/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher;renderTileEntity(Lnet/minecraft/tileentity/TileEntity;FI)V", //#endif shift = At.Shift.AFTER )) diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java index 083384c7..016695b3 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderItem.java @@ -20,6 +20,7 @@ import net.minecraft.client.renderer.model.IBakedModel; //$$ import net.minecraft.client.renderer.entity.RenderItem; //$$ import net.minecraft.client.resources.model.IBakedModel; //#endif +//#endif //#if MC>=11300 @Mixin(ItemRenderer.class) diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java index 289a1136..a470219a 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinRenderLivingBase.java @@ -3,18 +3,31 @@ package com.replaymod.render.blend.mixin; import com.replaymod.render.blend.BlendState; import com.replaymod.render.blend.exporters.EntityExporter; -import net.minecraft.client.renderer.entity.RenderLivingBase; import net.minecraft.entity.EntityLivingBase; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +//#if MC>=10904 +import net.minecraft.client.renderer.entity.RenderLivingBase; +//#else +//$$ import net.minecraft.client.renderer.entity.RendererLivingEntity; +//#endif + +//#if MC>=10904 @Mixin(RenderLivingBase.class) +//#else +//$$ @Mixin(RendererLivingEntity.class) +//#endif public abstract class MixinRenderLivingBase { @Inject(method = "doRender", at = @At( value = "INVOKE", + //#if MC>=10904 target = "Lnet/minecraft/client/renderer/entity/RenderLivingBase;prepareScale(Lnet/minecraft/entity/EntityLivingBase;F)F", + //#else + //$$ target = "Lnet/minecraft/client/renderer/entity/RendererLivingEntity;preRenderCallback(Lnet/minecraft/entity/EntityLivingBase;F)V", + //#endif shift = At.Shift.AFTER )) private void recordModelMatrix(EntityLivingBase entity, double x, double y, double z, float entityYaw, float partialTicks, CallbackInfo ci) { diff --git a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java index 089ecea7..b0688fa0 100644 --- a/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java +++ b/src/main/java/com/replaymod/render/blend/mixin/MixinTileEntityRendererDispatcher.java @@ -40,6 +40,7 @@ public abstract class MixinTileEntityRendererDispatcher { @Inject(method = "render(Lnet/minecraft/tileentity/TileEntity;DDDFIZ)V", at = @At("RETURN")) public void postRender(TileEntity tileEntity, double x, double y, double z, float renderPartialTicks, int destroyStage, boolean hasNoBlock, CallbackInfo ci) { + //#else //#if MC>=11200 //$$ @Inject(method = "renderTileEntityAt(Lnet/minecraft/tileentity/TileEntity;DDDFIF)V", //$$ at = @At("RETURN")) From 1e1104f4d312f2b2a99085fd2a684032987cc723 Mon Sep 17 00:00:00 2001 From: Jonas Herzig Date: Thu, 14 Mar 2019 18:14:47 +0100 Subject: [PATCH 12/12] Add blend export to GuiRenderSettings --- .../com/replaymod/render/RenderSettings.java | 4 ++-- .../render/gui/GuiRenderSettings.java | 23 +++++++++++++++++++ src/main/resources/assets/replaymod/lang | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index 59e2b336..5ff3f058 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -82,10 +82,10 @@ public class RenderSettings { } public boolean hasBitrateSetting() { - return preset.contains("%BITRATE%"); + return preset != null && preset.contains("%BITRATE%"); } - public boolean isYuv420() { return preset.contains("-pix_fmt yuv420p"); } + public boolean isYuv420() { return preset != null && preset.contains("-pix_fmt yuv420p"); } @Override public String toString() { diff --git a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java index 2aadeedd..15d23d9c 100644 --- a/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java +++ b/src/main/java/com/replaymod/render/gui/GuiRenderSettings.java @@ -59,6 +59,14 @@ public class GuiRenderSettings extends GuiScreen implements Closeable { new GuiDropdownMenu().onSelection(new Consumer() { @Override public void consume(Integer old) { + if (renderMethodDropdown.getSelectedValue() == RenderSettings.RenderMethod.BLEND + ^ encodingPresetDropdown.getSelectedValue() == RenderSettings.EncodingPreset.BLEND) { + if (renderMethodDropdown.getSelectedValue() == RenderSettings.RenderMethod.BLEND) { + encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.BLEND); + } else { + encodingPresetDropdown.setSelected(RenderSettings.EncodingPreset.MP4_DEFAULT); + } + } updateInputs(); } }).setMinSize(new Dimension(0, 20)).setValues(RenderSettings.RenderMethod.values()); @@ -75,6 +83,10 @@ public class GuiRenderSettings extends GuiScreen implements Closeable { @Override public void consume(Integer old) { RenderSettings.EncodingPreset newPreset = encodingPresetDropdown.getSelectedValue(); + if (newPreset == RenderSettings.EncodingPreset.BLEND + && encodingPresetDropdown.getSelectedValue() == RenderSettings.EncodingPreset.BLEND) { + renderMethodDropdown.setSelected(RenderSettings.RenderMethod.BLEND); + } // Update export arguments to match new Preset exportArguments.setText(newPreset.getValue()); // If the user hasn't changed the output file by themselves, @@ -361,6 +373,17 @@ public class GuiRenderSettings extends GuiScreen implements Closeable { injectSphericalMetadata.setDisabled().setTooltip(new GuiTooltip().setColor(Colors.RED) .setI18nText("replaymod.gui.rendersettings.sphericalmetadata.error")); } + + // Enable/Disable various options for blend export + boolean isBlend = renderMethod == RenderSettings.RenderMethod.BLEND; + if (isBlend) { + videoWidth.setDisabled(); + videoHeight.setDisabled(); + } + encodingPresetDropdown.setEnabled(!isBlend); + exportCommand.setEnabled(!isBlend); + exportArguments.setEnabled(!isBlend); + antiAliasingDropdown.setEnabled(!isBlend); } protected String updateResolution() { diff --git a/src/main/resources/assets/replaymod/lang b/src/main/resources/assets/replaymod/lang index 37de62cf..874fd801 160000 --- a/src/main/resources/assets/replaymod/lang +++ b/src/main/resources/assets/replaymod/lang @@ -1 +1 @@ -Subproject commit 37de62cf8edae480b2a78cb6f5ed307aec351a69 +Subproject commit 874fd8016db8209e6a4e8822c435c9641bcc18f6