Merge branch 'johni/blend' into johni/1.13-pre
This commit is contained in:
2
jGui
2
jGui
Submodule jGui updated: 79b0aaf3e9...8019dfd11a
@@ -31,6 +31,7 @@ package com.replaymod.core;
|
|||||||
//$$ MixinBootstrap.init();
|
//$$ MixinBootstrap.init();
|
||||||
//$$ Mixins.addConfiguration("mixins.recording.replaymod.json");
|
//$$ Mixins.addConfiguration("mixins.recording.replaymod.json");
|
||||||
//$$ Mixins.addConfiguration("mixins.render.replaymod.json");
|
//$$ Mixins.addConfiguration("mixins.render.replaymod.json");
|
||||||
|
//$$ Mixins.addConfiguration("mixins.render.blend.replaymod.json");
|
||||||
//$$ Mixins.addConfiguration("mixins.replay.replaymod.json");
|
//$$ Mixins.addConfiguration("mixins.replay.replaymod.json");
|
||||||
//$$ Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json");
|
//$$ Mixins.addConfiguration("mixins.compat.mapwriter.replaymod.json");
|
||||||
//$$ Mixins.addConfiguration("mixins.compat.shaders.replaymod.json");
|
//$$ Mixins.addConfiguration("mixins.compat.shaders.replaymod.json");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import net.minecraft.client.multiplayer.WorldClient;
|
|||||||
import net.minecraft.client.network.NetHandlerPlayClient;
|
import net.minecraft.client.network.NetHandlerPlayClient;
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
import net.minecraft.client.renderer.entity.RenderManager;
|
import net.minecraft.client.renderer.entity.RenderManager;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureMap;
|
||||||
import net.minecraft.client.settings.KeyBinding;
|
import net.minecraft.client.settings.KeyBinding;
|
||||||
import net.minecraft.crash.CrashReport;
|
import net.minecraft.crash.CrashReport;
|
||||||
import net.minecraft.crash.CrashReportCategory;
|
import net.minecraft.crash.CrashReportCategory;
|
||||||
@@ -31,11 +32,15 @@ import net.minecraftforge.common.MinecraftForge;
|
|||||||
|
|
||||||
//#if MC>=11300
|
//#if MC>=11300
|
||||||
import net.minecraft.client.MainWindow;
|
import net.minecraft.client.MainWindow;
|
||||||
|
import net.minecraft.client.renderer.entity.model.ModelBox;
|
||||||
|
import net.minecraft.client.renderer.entity.model.ModelRenderer;
|
||||||
import net.minecraft.client.util.InputMappings;
|
import net.minecraft.client.util.InputMappings;
|
||||||
import net.minecraft.crash.ReportedException;
|
import net.minecraft.crash.ReportedException;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
//#else
|
//#else
|
||||||
//$$ import net.minecraft.client.gui.ScaledResolution;
|
//$$ import net.minecraft.client.gui.ScaledResolution;
|
||||||
|
//$$ import net.minecraft.client.model.ModelBox;
|
||||||
|
//$$ import net.minecraft.client.model.ModelRenderer;
|
||||||
//$$ import net.minecraft.client.resources.ResourcePackRepository;
|
//$$ import net.minecraft.client.resources.ResourcePackRepository;
|
||||||
//$$ import net.minecraft.util.ReportedException;
|
//$$ import net.minecraft.util.ReportedException;
|
||||||
//$$ import org.apache.logging.log4j.LogManager;
|
//$$ import org.apache.logging.log4j.LogManager;
|
||||||
@@ -50,8 +55,10 @@ import net.minecraft.client.renderer.BufferBuilder;
|
|||||||
//#else
|
//#else
|
||||||
//$$ import net.minecraft.client.renderer.VertexBuffer;
|
//$$ import net.minecraft.client.renderer.VertexBuffer;
|
||||||
//#endif
|
//#endif
|
||||||
|
import net.minecraft.client.particle.Particle;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
//#else
|
//#else
|
||||||
|
//$$ import net.minecraft.client.particle.EntityFX;
|
||||||
//#if MC>=10800
|
//#if MC>=10800
|
||||||
//$$ import net.minecraft.client.renderer.WorldRenderer;
|
//$$ import net.minecraft.client.renderer.WorldRenderer;
|
||||||
//#endif
|
//#endif
|
||||||
@@ -70,6 +77,8 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
|||||||
//#if MC>=10800
|
//#if MC>=10800
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraft.client.renderer.GlStateManager.BooleanState;
|
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.minecraft.world.WorldType;
|
||||||
//#if MC>=11300
|
//#if MC>=11300
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
@@ -287,6 +296,13 @@ public class MCVer {
|
|||||||
//$$ }
|
//$$ }
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
|
public static ResourceLocation LOCATION_BLOCKS_TEXTURE
|
||||||
|
//#if MC>=10904
|
||||||
|
= TextureMap.LOCATION_BLOCKS_TEXTURE;
|
||||||
|
//#else
|
||||||
|
//$$ = TextureMap.locationBlocksTexture;
|
||||||
|
//#endif
|
||||||
|
|
||||||
public static EntityPlayerSP player(Minecraft mc) {
|
public static EntityPlayerSP player(Minecraft mc) {
|
||||||
//#if MC>=11102
|
//#if MC>=11102
|
||||||
return mc.player;
|
return mc.player;
|
||||||
@@ -341,6 +357,11 @@ public class MCVer {
|
|||||||
//#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static List<ModelBox> cubeList(ModelRenderer modelRenderer) {
|
||||||
|
return modelRenderer.cubeList;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static List<EntityPlayer> playerEntities(World world) {
|
public static List<EntityPlayer> playerEntities(World world) {
|
||||||
return world.playerEntities;
|
return world.playerEntities;
|
||||||
@@ -590,6 +611,29 @@ public class MCVer {
|
|||||||
//#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#if MC>=10800
|
||||||
|
//#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
|
||||||
|
return Tessellator.getInstance().getBuffer();
|
||||||
|
//#else
|
||||||
|
//$$ return Tessellator.getInstance().getWorldRenderer();
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static List<VertexFormatElement> getElements(VertexFormat vertexFormat) {
|
||||||
|
return vertexFormat.getElements();
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
|
||||||
public static Tessellator Tessellator_getInstance() {
|
public static Tessellator Tessellator_getInstance() {
|
||||||
//#if MC>=10800
|
//#if MC>=10800
|
||||||
return Tessellator.getInstance();
|
return Tessellator.getInstance();
|
||||||
@@ -654,6 +698,30 @@ public class MCVer {
|
|||||||
return MathHelper.sin(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
|
||||||
|
}
|
||||||
|
|
||||||
public static ReportedException newReportedException(CrashReport crashReport) {
|
public static ReportedException newReportedException(CrashReport crashReport) {
|
||||||
return new ReportedException(crashReport);
|
return new ReportedException(crashReport);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.replaymod.extras.advancedscreenshots;
|
|||||||
|
|
||||||
import com.replaymod.core.versions.MCVer;
|
import com.replaymod.core.versions.MCVer;
|
||||||
import com.replaymod.render.RenderSettings;
|
import com.replaymod.render.RenderSettings;
|
||||||
|
import com.replaymod.render.blend.BlendState;
|
||||||
import com.replaymod.render.capturer.RenderInfo;
|
import com.replaymod.render.capturer.RenderInfo;
|
||||||
import com.replaymod.render.rendering.Pipelines;
|
import com.replaymod.render.rendering.Pipelines;
|
||||||
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
|
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
|
||||||
@@ -40,8 +41,13 @@ public class ScreenshotRenderer implements RenderInfo {
|
|||||||
ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal);
|
ChunkLoadingRenderGlobal clrg = new ChunkLoadingRenderGlobal(mc.renderGlobal);
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
Pipelines.newPipeline(settings.getRenderMethod(),this,
|
if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) {
|
||||||
new ScreenshotWriter(settings.getOutputFile())).run();
|
BlendState.setState(new BlendState(settings.getOutputFile()));
|
||||||
|
Pipelines.newBlendPipeline(this).run();
|
||||||
|
} else {
|
||||||
|
Pipelines.newPipeline(settings.getRenderMethod(), this,
|
||||||
|
new ScreenshotWriter(settings.getOutputFile())).run();
|
||||||
|
}
|
||||||
|
|
||||||
//#if MC>=10800
|
//#if MC>=10800
|
||||||
clrg.uninstall();
|
clrg.uninstall();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.apache.maven.artifact.versioning.ComparableVersion;
|
|||||||
@Data
|
@Data
|
||||||
public class RenderSettings {
|
public class RenderSettings {
|
||||||
public enum RenderMethod {
|
public enum RenderMethod {
|
||||||
DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS;
|
DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS, BLEND;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@@ -61,6 +61,8 @@ public class RenderSettings {
|
|||||||
|
|
||||||
MKV_LOSSLESS("-an -c:v libx264 -preset ultrafast -qp 0 \"%FILENAME%\"", "mkv"),
|
MKV_LOSSLESS("-an -c:v libx264 -preset ultrafast -qp 0 \"%FILENAME%\"", "mkv"),
|
||||||
|
|
||||||
|
BLEND(null, "blend"),
|
||||||
|
|
||||||
PNG("\"%FILENAME%-%06d.png\"", "png");
|
PNG("\"%FILENAME%-%06d.png\"", "png");
|
||||||
|
|
||||||
private final String preset;
|
private final String preset;
|
||||||
@@ -80,10 +82,10 @@ public class RenderSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasBitrateSetting() {
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
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 de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class BlendFrameCapturer implements FrameCapturer<RGBFrame> {
|
||||||
|
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(MCVer.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/main/java/com/replaymod/render/blend/BlendMaterials.java
Normal file
70
src/main/java/com/replaymod/render/blend/BlendMaterials.java
Normal file
@@ -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<Integer, DMaterial> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
276
src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java
Normal file
276
src/main/java/com/replaymod/render/blend/BlendMeshBuilder.java
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
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;
|
||||||
|
|
||||||
|
//#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
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
private static final ReadableVector3f VEC3F_ZERO = new Vector3f(0, 0, 0);
|
||||||
|
private final DMesh mesh;
|
||||||
|
private Vector3f offset;
|
||||||
|
private boolean isDrawing;
|
||||||
|
private boolean wellBehaved;
|
||||||
|
|
||||||
|
public BlendMeshBuilder(DMesh mesh) {
|
||||||
|
super(1024);
|
||||||
|
this.mesh = mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWellBehaved(boolean wellBehaved) {
|
||||||
|
this.wellBehaved = wellBehaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOffset(Vector3f offset) {
|
||||||
|
this.offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
//#if MC>=10809
|
||||||
|
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,
|
||||||
|
// let's just assume that what's happened and finish our last draw by ourselves
|
||||||
|
// (might miss correct texture though)
|
||||||
|
super.finishDrawing();
|
||||||
|
addBufferToMesh();
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Already drawing!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.isDrawing = true;
|
||||||
|
|
||||||
|
if (!wellBehaved) {
|
||||||
|
// In case the calling code finishes with Tessellator.getInstance().draw()
|
||||||
|
BufferBuilder_beginPosTexCol(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//#if MC>=10809
|
||||||
|
super.begin(mode, vertexFormat);
|
||||||
|
//#else
|
||||||
|
//$$ super.startDrawing(mode);
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void maybeFinishDrawing() {
|
||||||
|
if (isDrawing) {
|
||||||
|
isDrawing = false;
|
||||||
|
super.finishDrawing();
|
||||||
|
addBufferToMesh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
//#if MC>=10809
|
||||||
|
public void finishDrawing() {
|
||||||
|
//#else
|
||||||
|
//$$ public int finishDrawing() {
|
||||||
|
//#endif
|
||||||
|
if (!isDrawing) {
|
||||||
|
throw new IllegalStateException("Not building!");
|
||||||
|
} else {
|
||||||
|
if (!wellBehaved) {
|
||||||
|
getBuffer(Tessellator.getInstance()).finishDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
//#if MC<10809
|
||||||
|
//$$ int ret =
|
||||||
|
//#endif
|
||||||
|
super.finishDrawing();
|
||||||
|
|
||||||
|
addBufferToMesh();
|
||||||
|
|
||||||
|
//#if MC<10809
|
||||||
|
//$$ return ret;
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBufferToMesh() {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DMesh addBufferToMesh(ByteBuffer buffer, int mode, VertexFormat vertexFormat, DMesh mesh, ReadableVector3f 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) {
|
||||||
|
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 : getElements(vertexFormat)) {
|
||||||
|
//#if MC>=10809
|
||||||
|
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<DMesh.Vertex> vertices = new ArrayList<>(vertexCount);
|
||||||
|
List<Vector2f> uvs = new ArrayList<>(vertexCount);
|
||||||
|
List<Integer> colors = new ArrayList<>(vertexCount);
|
||||||
|
//#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(),
|
||||||
|
-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) {
|
||||||
|
materialSlot = mesh.materials.size();
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
174
src/main/java/com/replaymod/render/blend/BlendState.java
Normal file
174
src/main/java/com/replaymod/render/blend/BlendState.java
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
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 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.core.versions.MCVer.*;
|
||||||
|
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<Exporter> 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);
|
||||||
|
|
||||||
|
//#if MC>=10800
|
||||||
|
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));
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register(Exporter exporter) {
|
||||||
|
exporters.add(exporter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Exporter> T get(Class<T> 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");
|
||||||
|
addDetail(category, "Exporter", exporter::toString);
|
||||||
|
throw newReportedException(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");
|
||||||
|
addDetail(category, "Exporter", exporter::toString);
|
||||||
|
throw newReportedException(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");
|
||||||
|
addDetail(category, "Exporter", exporter::toString);
|
||||||
|
addDetail(category, "Frame", () -> String.valueOf(frame));
|
||||||
|
throw newReportedException(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");
|
||||||
|
addDetail(category, "Exporter", exporter::toString);
|
||||||
|
addDetail(category, "Frame", () -> String.valueOf(frame));
|
||||||
|
throw newReportedException(report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.endFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlenderFile getBlenderFile() {
|
||||||
|
return blenderFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlenderFactory getFactory() {
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DScene getScene() {
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlendMaterials getMaterials() {
|
||||||
|
return materials;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main/java/com/replaymod/render/blend/Exporter.java
Normal file
10
src/main/java/com/replaymod/render/blend/Exporter.java
Normal file
@@ -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 {}
|
||||||
|
}
|
||||||
209
src/main/java/com/replaymod/render/blend/ToJson.java
Normal file
209
src/main/java/com/replaymod/render/blend/ToJson.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
189
src/main/java/com/replaymod/render/blend/Util.java
Normal file
189
src/main/java/com/replaymod/render/blend/Util.java
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
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;
|
||||||
|
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 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();
|
||||||
|
//#if MC>=11300
|
||||||
|
GL11.glGetFloatv(matrix, floatBuffer);
|
||||||
|
//#else
|
||||||
|
//$$ GL11.glGetFloat(matrix, floatBuffer);
|
||||||
|
//#endif
|
||||||
|
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 <T> CPointer<T> plus(CPointer<T> 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<Link> element) throws IOException {
|
||||||
|
CPointer<Link> 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();
|
||||||
|
//#if MC>=11300
|
||||||
|
tileEntity.write(nbt);
|
||||||
|
//#else
|
||||||
|
//$$ tileEntity.writeToNBT(nbt);
|
||||||
|
//#endif
|
||||||
|
return nbt.getString("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IOCallable<R> {
|
||||||
|
R call() throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IOConsumer<T> {
|
||||||
|
void accept(T t) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IOBiConsumer<T, U> {
|
||||||
|
void accept(T t, U u) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IOFunction<T, R> {
|
||||||
|
R apply(T t) throws IOException;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/main/java/com/replaymod/render/blend/data/DAction.java
Normal file
53
src/main/java/com/replaymod/render/blend/data/DAction.java
Normal file
@@ -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<DFCurve> curves = new ArrayList<>();
|
||||||
|
|
||||||
|
public CPointer<bAction> 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<Float> 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<DKeyframe> keyframes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DKeyframe {
|
||||||
|
public InterpolationType interpolationType = InterpolationType.CONSTANT;
|
||||||
|
public int frame;
|
||||||
|
public float value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum InterpolationType {
|
||||||
|
CONSTANT, LINEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/com/replaymod/render/blend/data/DId.java
Normal file
17
src/main/java/com/replaymod/render/blend/data/DId.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/main/java/com/replaymod/render/blend/data/DImage.java
Normal file
34
src/main/java/com/replaymod/render/blend/data/DImage.java
Normal file
@@ -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<Pair<String, DPackedFile>> packedFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
public CPointer<Image> 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<String, DPackedFile> pair = packedFiles.get(i);
|
||||||
|
pf.getFilepath().fromString(pair.getLeft());
|
||||||
|
pf.setPackedfile(pair.getRight().serialize(serializer));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/main/java/com/replaymod/render/blend/data/DMaterial.java
Normal file
70
src/main/java/com/replaymod/render/blend/data/DMaterial.java
Normal file
@@ -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<DMTex> textures = new ArrayList<>();
|
||||||
|
|
||||||
|
public CPointer<Material> serialize(Serializer serializer) throws IOException {
|
||||||
|
return serializer.maybeMajor(this, id, Material.class, () -> {
|
||||||
|
List<Util.IOCallable<CPointer<MTex>>> 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<CPointer<MTex>> 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<CPointer<MTex>> serialize(Serializer serializer) throws IOException {
|
||||||
|
CPointer<Tex> 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<Float> size = mTex.getSize();
|
||||||
|
size.set(0, 1f);
|
||||||
|
size.set(1, 1f);
|
||||||
|
size.set(2, 1f);
|
||||||
|
return mTex.__io__addressof();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
320
src/main/java/com/replaymod/render/blend/data/DMesh.java
Normal file
320
src/main/java/com/replaymod/render/blend/data/DMesh.java
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
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;
|
||||||
|
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 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<Vertex> vertices = new ArrayList<>();
|
||||||
|
public final List<Edge> edges = new ArrayList<>();
|
||||||
|
public final List<Face> faces = new ArrayList<>();
|
||||||
|
public final List<Loop> loops = new ArrayList<>();
|
||||||
|
public final List<Poly> polys = new ArrayList<>();
|
||||||
|
public final List<DMaterial> materials = new ArrayList<>();
|
||||||
|
|
||||||
|
public CPointer<Mesh> serialize(Serializer serializer) throws IOException {
|
||||||
|
return serializer.maybeMajor(this, id, Mesh.class, () -> {
|
||||||
|
List<CPointer<Material>> materials = new ArrayList<>();
|
||||||
|
List<CPointer<Image>> 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<CPointer<Material>> mat = serializer.writeDataPArray(Material.class, materials.size(), materials::get);
|
||||||
|
mesh.setMat(mat);
|
||||||
|
mesh.setTotcol((short) materials.size());
|
||||||
|
|
||||||
|
if (!vertices.isEmpty()) {
|
||||||
|
CArrayFacade<MVert> 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<MEdge> 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<MLoop> mLoops = serializer.writeData(MLoop.class, loops.size(),
|
||||||
|
(i, mLoop) -> loops.get(i).serialize(mLoop));
|
||||||
|
CArrayFacade<MLoopUV> mLoopUVs = serializer.writeData(MLoopUV.class, loops.size(),
|
||||||
|
(i, mLoopUV) -> loops.get(i).serialize(mLoopUV));
|
||||||
|
CArrayFacade<MLoopCol> mLoopCols = serializer.writeData(MLoopCol.class, loops.size(),
|
||||||
|
(i, mLoopCol) -> loops.get(i).serialize(mLoopCol));
|
||||||
|
|
||||||
|
CArrayFacade<CustomDataLayer> 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<MPoly> mPolys = serializer.writeData(MPoly.class, polys.size(),
|
||||||
|
(i, mPoly) -> polys.get(i).serialize(mPoly));
|
||||||
|
CArrayFacade<MTexPoly> mTexPolys = serializer.writeData(MTexPoly.class, polys.size(),
|
||||||
|
(i, mTexPoly) -> mTexPoly.setTpage(images.get(polys.get(i).materialSlot)));
|
||||||
|
|
||||||
|
CArrayFacade<CustomDataLayer> 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 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;
|
||||||
|
|
||||||
|
public Vertex(float x, float y, float z) {
|
||||||
|
this.pos = new Vector3f(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serialize(MVert mVert) throws IOException {
|
||||||
|
CArrayFacade<Float> pos = mVert.getCo();
|
||||||
|
pos.set(0, this.pos.getX());
|
||||||
|
pos.set(1, this.pos.getY());
|
||||||
|
pos.set(2, this.pos.getZ());
|
||||||
|
CArrayFacade<Short> norm = mVert.getNo();
|
||||||
|
norm.set(0, this.normX);
|
||||||
|
norm.set(1, this.normY);
|
||||||
|
norm.set(2, this.normZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Float> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
270
src/main/java/com/replaymod/render/blend/data/DObject.java
Normal file
270
src/main/java/com/replaymod/render/blend/data/DObject.java
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
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;
|
||||||
|
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 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<DObject> children = new ArrayList<>();
|
||||||
|
private List<DObject> 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<DObject> 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<BlenderObject> serialize(Serializer serializer) throws IOException {
|
||||||
|
return serializer.maybeMajor(this, id, BlenderObject.class, () -> {
|
||||||
|
if (lastVisibleFrame >= 0) {
|
||||||
|
keyframe("hide", 0, lastVisibleFrame + 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPointer<BlenderObject> parent = this.parent == null ? null : this.parent.serialize(serializer);
|
||||||
|
CPointer<Mesh> mesh = this.mesh == null ? null : this.mesh.serialize(serializer);
|
||||||
|
CPointer<bAction> action = this.action == null ? null : this.action.serialize(serializer);
|
||||||
|
CPointer<BlenderObject> pointAt = this.pointAt == null ? null : this.pointAt.serialize(serializer);
|
||||||
|
|
||||||
|
return object -> {
|
||||||
|
object.setParent(parent);
|
||||||
|
if (parent != null) {
|
||||||
|
CArrayFacade<CArrayFacade<Float>> 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<Float> loc = object.getLoc();
|
||||||
|
loc.set(0, this.loc.x);
|
||||||
|
loc.set(1, this.loc.y);
|
||||||
|
loc.set(2, this.loc.z);
|
||||||
|
CArrayFacade<Float> size = object.getSize();
|
||||||
|
size.set(0, scale.x);
|
||||||
|
size.set(1, scale.y);
|
||||||
|
size.set(2, scale.z);
|
||||||
|
CArrayFacade<Float> quat = object.getQuat();
|
||||||
|
quat.set(0, rot.w);
|
||||||
|
quat.set(1, rot.x);
|
||||||
|
quat.set(2, rot.y);
|
||||||
|
quat.set(3, rot.z);
|
||||||
|
CArrayFacade<Float> 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<PackedFile> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/main/java/com/replaymod/render/blend/data/DScene.java
Normal file
64
src/main/java/com/replaymod/render/blend/data/DScene.java
Normal file
@@ -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<DObject> base = new ArrayList<>();
|
||||||
|
public int endFrame;
|
||||||
|
|
||||||
|
private Set<DObject> findAllObjects(DObject curr, Set<DObject> set) {
|
||||||
|
for (DObject child : curr == null ? base : curr.getChildren()) {
|
||||||
|
if (child.isValid()) {
|
||||||
|
findAllObjects(child, set);
|
||||||
|
set.add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPointer<Scene> serialize(Serializer serializer) throws IOException {
|
||||||
|
return serializer.maybeMajor(this, id, Scene.class, () -> {
|
||||||
|
Set<DObject> allObjects = findAllObjects(null, new LinkedHashSet<>());
|
||||||
|
List<CPointer<BlenderObject>> 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<BlenderObject> 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());
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/main/java/com/replaymod/render/blend/data/DTexture.java
Normal file
32
src/main/java/com/replaymod/render/blend/data/DTexture.java
Normal file
@@ -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<Tex> serialize(Serializer serializer) throws IOException {
|
||||||
|
return serializer.maybeMajor(this, id, Tex.class, () -> {
|
||||||
|
CPointer<Image> 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);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
132
src/main/java/com/replaymod/render/blend/data/Serializer.java
Normal file
132
src/main/java/com/replaymod/render/blend/data/Serializer.java
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
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<Object, CPointer<Object>> serialized = new HashMap<>();
|
||||||
|
private final Map<String, Integer> usedNames = new HashMap<>();
|
||||||
|
|
||||||
|
public <T> CPointer<T> getMajor(Object obj, Class<T> clazz) {
|
||||||
|
CPointer<Object> pointer = serialized.get(obj);
|
||||||
|
if (pointer == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return pointer.cast(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends CFacade> CPointer<T> writeMajor(Object obj, DId id, Class<T> clazz) throws IOException {
|
||||||
|
if (serialized.containsKey(obj)) {
|
||||||
|
throw new IllegalStateException("Object " + obj + " already serialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
T val = factory().newCStructBlock(id.code, clazz);
|
||||||
|
CPointer<T> 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;
|
||||||
|
int counter = usedNames.compute(name, (n, i) -> i == null ? 0 : i + 1);
|
||||||
|
String fullName = counter == 0 ? name : name + "." + counter;
|
||||||
|
asID.getName().fromString(fullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends CFacade> CPointer<T> maybeMajor(Object obj, DId id, Class<T> clazz, IOCallable<IOConsumer<T>> prepare) throws IOException {
|
||||||
|
CPointer<T> result = getMajor(obj, clazz);
|
||||||
|
if (result == null) {
|
||||||
|
IOConsumer<T> configure = prepare.call();
|
||||||
|
result = writeMajor(obj, id, clazz);
|
||||||
|
configure.accept(result.get());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CArrayFacade<Byte> writeString0(String str) throws IOException {
|
||||||
|
byte[] bytes = (str + '\0').getBytes();
|
||||||
|
CArrayFacade<Byte> pointer = factory().newCArrayBlock(BlockCodes.ID_DATA, Byte.class, align4(bytes.length));
|
||||||
|
pointer.fromArray(bytes);
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPointer<Byte> writeBytes(byte[] bytes) throws IOException {
|
||||||
|
CArrayFacade<Byte> pointer = factory().newCArrayBlock(BlockCodes.ID_DATA, Byte.class, align4(bytes.length));
|
||||||
|
pointer.fromArray(bytes);
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends CFacade> T writeData(Class<T> clazz) throws IOException {
|
||||||
|
return factory().newCStructBlock(ID_DATA, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends CFacade> CArrayFacade<T> writeData(Class<T> clazz, int count) throws IOException {
|
||||||
|
return factory().newCStructBlock(ID_DATA, clazz, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends CFacade> CArrayFacade<T> writeData(Class<T> clazz, int count, IOBiConsumer<Integer, T> forElem) throws IOException {
|
||||||
|
if (count == 0) return null;
|
||||||
|
CArrayFacade<T> arrayFacade = writeData(clazz, count);
|
||||||
|
CPointer<T> pointer = arrayFacade;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
forElem.accept(i, pointer.get());
|
||||||
|
pointer = Util.plus(pointer, 1);
|
||||||
|
}
|
||||||
|
return arrayFacade;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> CArrayFacade<CPointer<T>> writeDataPArray(Class<T> clazz, int count, Util.IOFunction<Integer, CPointer<T>> forElem) throws IOException {
|
||||||
|
if (count == 0) return null;
|
||||||
|
CArrayFacade<CPointer<T>> 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 <T extends CFacade> void writeDataList(Class<T> clazz, ListBase listBase, int size, IOBiConsumer<Integer, T> forElem) throws IOException {
|
||||||
|
CPointer<Link> prevPointer = null;
|
||||||
|
Link prev = null;
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
CPointer<T> pointer = CFacade.__io__addressof(writeData(clazz));
|
||||||
|
CPointer<Link> 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
//#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 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.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;
|
||||||
|
|
||||||
|
//#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;
|
||||||
|
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;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
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<BlockPos, DObject> chunkObjects = new HashMap<>();
|
||||||
|
//#if MC>=10904
|
||||||
|
private final Map<BlockPos, Map<BlockRenderLayer, DObject>> chunkLayerObjects = new HashMap<>();
|
||||||
|
private final List<Pair<RenderChunk, BlockRenderLayer>> chunks = new ArrayList<>();
|
||||||
|
//#else
|
||||||
|
//$$ private final Map<BlockPos, Map<EnumWorldBlockLayer, DObject>> chunkLayerObjects = new HashMap<>();
|
||||||
|
//$$ private final List<Pair<RenderChunk, EnumWorldBlockLayer>> chunks = new ArrayList<>();
|
||||||
|
//#endif
|
||||||
|
private DObject chunksObject;
|
||||||
|
private int frame;
|
||||||
|
|
||||||
|
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
|
||||||
|
@SneakyThrows
|
||||||
|
public void setup() throws IOException {
|
||||||
|
|
||||||
|
Minecraft mc = MCVer.getMinecraft();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<ContainerLocalRenderInformation> renderInfos = mc.renderGlobal.renderInfos;
|
||||||
|
for (ContainerLocalRenderInformation renderInfo : renderInfos) {
|
||||||
|
RenderChunk renderChunk = ReflectionUtil.get(renderInfo, "renderChunk", RenderChunk.class); // SneakyThrows
|
||||||
|
CompiledChunk compiledChunk = renderChunk.getCompiledChunk();
|
||||||
|
if (!compiledChunk.isEmpty()) {
|
||||||
|
addChunkUpdate(renderChunk, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
//#if MC>=10904
|
||||||
|
for (Pair<RenderChunk, BlockRenderLayer> pair : chunks) {
|
||||||
|
BlockRenderLayer layer = pair.getRight();
|
||||||
|
//#else
|
||||||
|
//$$ for (Pair<RenderChunk, EnumWorldBlockLayer> pair : chunks) {
|
||||||
|
//$$ EnumWorldBlockLayer layer = pair.getRight();
|
||||||
|
//#endif
|
||||||
|
RenderChunk chunk = pair.getLeft();
|
||||||
|
DObject chunkObject = chunkObjects.get(chunk.getPosition());
|
||||||
|
if (chunkObject == null) {
|
||||||
|
chunkObject = buildChunkObject(chunk);
|
||||||
|
chunkObjects.put(chunk.getPosition(), chunkObject);
|
||||||
|
chunkLayerObjects.put(chunk.getPosition(), new EnumMap<>(layer.getDeclaringClass()));
|
||||||
|
}
|
||||||
|
DObject layerObject = buildChunkLayerObject(chunkObject, chunk, layer);
|
||||||
|
if (layerObject == null) continue;
|
||||||
|
//#if MC>=10904
|
||||||
|
Map<BlockRenderLayer, DObject> layerObjects
|
||||||
|
//#else
|
||||||
|
//$$ Map<EnumWorldBlockLayer, DObject> layerObjects
|
||||||
|
//#endif
|
||||||
|
= 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,
|
||||||
|
//#if MC>=10904
|
||||||
|
BlockRenderLayer layer) {
|
||||||
|
//#else
|
||||||
|
//$$ EnumWorldBlockLayer layer) {
|
||||||
|
//#endif
|
||||||
|
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();
|
||||||
|
|
||||||
|
MCVer.getMinecraft().getTextureManager().bindTexture(LOCATION_BLOCKS_TEXTURE);
|
||||||
|
|
||||||
|
return BlendMeshBuilder.addBufferToMesh(byteBuffer, GL11.GL_QUADS, DefaultVertexFormats.BLOCK, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int STRIDE = 28;
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
//#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 net.minecraft.entity.EntityLivingBase;
|
||||||
|
|
||||||
|
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 = MCVer.getMinecraft();
|
||||||
|
private final RenderState renderState;
|
||||||
|
private DObject entitiesObject;
|
||||||
|
private Map<Entity, DObject> 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());
|
||||||
|
//#if MC>=11300
|
||||||
|
entityObject.id.name = entity.getName().getString();
|
||||||
|
//#else
|
||||||
|
//$$ entityObject.id.name = entity.getName();
|
||||||
|
//#endif
|
||||||
|
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.
|
||||||
|
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.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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
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.ItemRenderer;
|
||||||
|
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.BakedQuad;
|
||||||
|
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;
|
||||||
|
//#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;
|
||||||
|
|
||||||
|
public ItemExporter(RenderState renderState) {
|
||||||
|
this.renderState = renderState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRender(Object renderItem, IBakedModel model, ItemStack stack) {
|
||||||
|
DObject object = getObjectForItemStack(renderItem, model, stack);
|
||||||
|
|
||||||
|
renderState.pushObject(object);
|
||||||
|
renderState.pushModelView();
|
||||||
|
renderState.applyLastModelViewTransformToObject();
|
||||||
|
|
||||||
|
object.setVisible(renderState.getFrame());
|
||||||
|
object.keyframeLocRotScale(renderState.getFrame());
|
||||||
|
|
||||||
|
renderState.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DObject getObjectForItemStack(Object 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(renderItem, model, stack)) {
|
||||||
|
object = child;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (object == null) {
|
||||||
|
object = new ItemBasedDObject(renderItem, model, stack);
|
||||||
|
//#if MC>=11300
|
||||||
|
object.id.name = stack.getDisplayName().getString();
|
||||||
|
//#else
|
||||||
|
//$$ object.id.name = stack.getDisplayName();
|
||||||
|
//#endif
|
||||||
|
object.setParent(parent);
|
||||||
|
}
|
||||||
|
object.lastFrame = frame;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static DMesh generateMeshForItemStack(Object renderItem, IBakedModel model, ItemStack stack) {
|
||||||
|
DMesh mesh = new DMesh();
|
||||||
|
BlendMeshBuilder builder = new BlendMeshBuilder(mesh);
|
||||||
|
builder.setWellBehaved(true);
|
||||||
|
//#if MC>=10809
|
||||||
|
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM);
|
||||||
|
//#else
|
||||||
|
//$$ builder.startDrawingQuads();
|
||||||
|
//$$ builder.setVertexFormat(DefaultVertexFormats.ITEM);
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
//#if MC>=11300
|
||||||
|
for (EnumFacing face : EnumFacing.values()) {
|
||||||
|
renderQuads(renderItem, builder, model.getQuads(null, face, new Random()), 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(Object renderItem, BlendMeshBuilder buffer, List<BakedQuad> quads, ItemStack stack) {
|
||||||
|
for (BakedQuad quad : quads) {
|
||||||
|
int color = stack != null && quad.hasTintIndex()
|
||||||
|
//#if MC>=11300
|
||||||
|
? ((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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ItemBasedDObject extends DObject {
|
||||||
|
private final Object renderItem;
|
||||||
|
private final IBakedModel model;
|
||||||
|
private final ItemStack stack;
|
||||||
|
private boolean valid;
|
||||||
|
|
||||||
|
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(Object renderItem, IBakedModel model, ItemStack stack) {
|
||||||
|
return this.renderItem == renderItem && this.model == model && this.stack == stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setVisible(int frame) {
|
||||||
|
valid = true;
|
||||||
|
super.setVisible(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
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 org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
//#if MC>=11300
|
||||||
|
import net.minecraft.client.renderer.entity.model.ModelBox;
|
||||||
|
import net.minecraft.client.renderer.entity.model.ModelRenderer;
|
||||||
|
//#else
|
||||||
|
//$$ import net.minecraft.client.model.ModelBox;
|
||||||
|
//$$ import net.minecraft.client.model.ModelRenderer;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
//#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;
|
||||||
|
|
||||||
|
//#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
|
||||||
|
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 {
|
||||||
|
private final Minecraft mc = MCVer.getMinecraft();
|
||||||
|
private final RenderState renderState;
|
||||||
|
private DObject pointAtObject;
|
||||||
|
private DObject particlesObject;
|
||||||
|
private DObject litParticlesObject;
|
||||||
|
//#if MC>=10904
|
||||||
|
private Map<Particle, DObject> particleObjects;
|
||||||
|
private Map<Particle, DObject> particleObjectsSeen;
|
||||||
|
//#else
|
||||||
|
//$$ private Map<Entity, DObject> particleObjects;
|
||||||
|
//$$ private Map<Entity, DObject> particleObjectsSeen;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
public ParticlesExporter(RenderState renderState) {
|
||||||
|
this.renderState = renderState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setup() throws IOException {
|
||||||
|
// 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) {
|
||||||
|
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() {
|
||||||
|
renderState.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//#if MC>=10904
|
||||||
|
public void onRender(Particle particle, float renderPartialTicks) {
|
||||||
|
//#else
|
||||||
|
//$$ public void onRender(EntityFX particle, float renderPartialTicks) {
|
||||||
|
//#endif
|
||||||
|
DObject particleObject = particleObjects.get(particle);
|
||||||
|
if (particleObject == null) {
|
||||||
|
particleObject = new DObject(DObject.Type.OB_EMPTY); // mesh generation is delayed, see below
|
||||||
|
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 - 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);
|
||||||
|
renderState.applyLastModelViewTransformToObject();
|
||||||
|
|
||||||
|
particleObject.keyframeLoc(renderState.getFrame());
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
//#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);
|
||||||
|
//#if MC>=10809
|
||||||
|
builder.begin(7, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP);
|
||||||
|
//#else
|
||||||
|
//$$ builder.startDrawingQuads();
|
||||||
|
//#endif
|
||||||
|
//#if MC>=10809
|
||||||
|
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
|
||||||
|
builder.finishDrawing();
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postFrame(int frame) throws IOException {
|
||||||
|
particleObjects.entrySet().stream()
|
||||||
|
.filter(entry -> !particleObjectsSeen.containsKey(entry.getKey()))
|
||||||
|
.forEach(entry -> entry.getValue().keyframe("hide", 0, renderState.getFrame(), 1f));
|
||||||
|
particleObjects = particleObjectsSeen;
|
||||||
|
particleObjectsSeen = new IdentityHashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
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 de.johni0702.minecraft.gui.utils.lwjgl.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<DObject> objectStack = new LinkedList<>();
|
||||||
|
private final Deque<Matrix4f> 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<DObject> 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<Matrix4f> 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 {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
//#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;
|
||||||
|
|
||||||
|
//#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;
|
||||||
|
|
||||||
|
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 = MCVer.getMinecraft();
|
||||||
|
private final RenderState renderState;
|
||||||
|
private DObject tileEntitiesObject;
|
||||||
|
private Map<TileEntity, DObject> tileEntityObjects;
|
||||||
|
private Map<TileEntity, DObject> 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, float alpha) {
|
||||||
|
// FIXME: handle alpha
|
||||||
|
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<TileEntity, DObject> entry : tileEntityObjects.entrySet()) {
|
||||||
|
if (!tileEntityObjectsSeen.containsKey(entry.getKey())) {
|
||||||
|
DObject object = entry.getValue();
|
||||||
|
object.keyframe("hide", 0, renderState.getFrame(), 1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tileEntityObjects = tileEntityObjectsSeen;
|
||||||
|
tileEntityObjectsSeen = new IdentityHashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
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.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>=11300
|
||||||
|
import net.minecraft.client.renderer.chunk.ChunkRenderTask;
|
||||||
|
//#else
|
||||||
|
//$$ import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
@Mixin(ChunkRenderWorker.class)
|
||||||
|
public abstract class MixinChunkRenderWorker {
|
||||||
|
|
||||||
|
@Inject(method = "processTask", at = @At("RETURN"))
|
||||||
|
//#if MC>=11300
|
||||||
|
public void afterChunkUpdate(ChunkRenderTask task, CallbackInfo ci) {
|
||||||
|
BlendState blendState = BlendState.getState();
|
||||||
|
if (blendState != null) {
|
||||||
|
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
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
package com.replaymod.render.blend.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.render.blend.BlendState;
|
||||||
|
import com.replaymod.render.blend.exporters.ParticlesExporter;
|
||||||
|
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;
|
||||||
|
|
||||||
|
//#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"))
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
package com.replaymod.render.blend.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.render.blend.BlendState;
|
||||||
|
import com.replaymod.render.blend.exporters.ModelRendererExporter;
|
||||||
|
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"))
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
//#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
|
||||||
|
|
||||||
|
@Inject(method = "renderEntities",
|
||||||
|
at = @At(value = "INVOKE",
|
||||||
|
//#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)Z"))
|
||||||
|
//#endif
|
||||||
|
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",
|
||||||
|
//#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)Z",
|
||||||
|
//#endif
|
||||||
|
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",
|
||||||
|
//#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) {
|
||||||
|
blendState.get(TileEntityExporter.class).preTileEntitiesRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
blendState.get(TileEntityExporter.class).postTileEntitiesRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
package com.replaymod.render.blend.mixin;
|
||||||
|
|
||||||
|
import com.replaymod.render.blend.BlendState;
|
||||||
|
import com.replaymod.render.blend.exporters.ItemExporter;
|
||||||
|
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>=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;
|
||||||
|
//#else
|
||||||
|
//$$ import net.minecraft.client.renderer.entity.RenderItem;
|
||||||
|
//$$ import net.minecraft.client.resources.model.IBakedModel;
|
||||||
|
//#endif
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
//#if MC>=11300
|
||||||
|
@Mixin(ItemRenderer.class)
|
||||||
|
//#else
|
||||||
|
//$$ @Mixin(RenderItem.class)
|
||||||
|
//#endif
|
||||||
|
public abstract class MixinRenderItem {
|
||||||
|
//#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(this, model, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
//#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.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) {
|
||||||
|
BlendState blendState = BlendState.getState();
|
||||||
|
if (blendState != null) {
|
||||||
|
blendState.get(EntityExporter.class).postEntityLivingSetup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
//#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.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;
|
||||||
|
|
||||||
|
//#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 {
|
||||||
|
|
||||||
|
@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,
|
||||||
|
//#if MC>=10904
|
||||||
|
CallbackInfo ci) {
|
||||||
|
//#else
|
||||||
|
//$$ CallbackInfoReturnable<Boolean> ci) {
|
||||||
|
//#endif
|
||||||
|
BlendState blendState = BlendState.getState();
|
||||||
|
if (blendState != null) {
|
||||||
|
blendState.get(EntityExporter.class).preRender(entity, x, y, z, yaw, renderPartialTicks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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))
|
||||||
|
public void postRender(Entity entity, double x, double y, double z, float yaw, float renderPartialTicks, boolean box,
|
||||||
|
//#if MC>=10904
|
||||||
|
CallbackInfo ci) {
|
||||||
|
//#else
|
||||||
|
//$$ CallbackInfoReturnable<Boolean> ci) {
|
||||||
|
//#endif
|
||||||
|
BlendState blendState = BlendState.getState();
|
||||||
|
if (blendState != null) {
|
||||||
|
blendState.get(EntityExporter.class).postRender(entity, x, y, z, yaw, renderPartialTicks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
//#if MC>=10800
|
||||||
|
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 {
|
||||||
|
|
||||||
|
//#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, 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) {
|
||||||
|
blendState.get(TileEntityExporter.class).preRender(tileEntity, x, y, z, renderPartialTicks, destroyStage, alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//#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, boolean hasNoBlock, CallbackInfo ci) {
|
||||||
|
//#else
|
||||||
|
//#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) {
|
||||||
|
blendState.get(TileEntityExporter.class).postRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
@@ -59,6 +59,14 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
|||||||
new GuiDropdownMenu<RenderSettings.RenderMethod>().onSelection(new Consumer<Integer>() {
|
new GuiDropdownMenu<RenderSettings.RenderMethod>().onSelection(new Consumer<Integer>() {
|
||||||
@Override
|
@Override
|
||||||
public void consume(Integer old) {
|
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();
|
updateInputs();
|
||||||
}
|
}
|
||||||
}).setMinSize(new Dimension(0, 20)).setValues(RenderSettings.RenderMethod.values());
|
}).setMinSize(new Dimension(0, 20)).setValues(RenderSettings.RenderMethod.values());
|
||||||
@@ -75,6 +83,10 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
|||||||
@Override
|
@Override
|
||||||
public void consume(Integer old) {
|
public void consume(Integer old) {
|
||||||
RenderSettings.EncodingPreset newPreset = encodingPresetDropdown.getSelectedValue();
|
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
|
// Update export arguments to match new Preset
|
||||||
exportArguments.setText(newPreset.getValue());
|
exportArguments.setText(newPreset.getValue());
|
||||||
// If the user hasn't changed the output file by themselves,
|
// 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)
|
injectSphericalMetadata.setDisabled().setTooltip(new GuiTooltip().setColor(Colors.RED)
|
||||||
.setI18nText("replaymod.gui.rendersettings.sphericalmetadata.error"));
|
.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() {
|
protected String updateResolution() {
|
||||||
@@ -400,6 +423,12 @@ public class GuiRenderSettings extends GuiScreen implements Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#if MC<10800
|
||||||
|
//$$ if (method == RenderSettings.RenderMethod.BLEND) {
|
||||||
|
//$$ return "replaymod.gui.rendersettings.no_blend_on_1_7_10";
|
||||||
|
//$$ }
|
||||||
|
//#endif
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.replaymod.render.mixin;
|
package com.replaymod.render.mixin;
|
||||||
|
|
||||||
//#if MC<10904
|
//#if MC<10904
|
||||||
|
//$$ import com.replaymod.render.blend.BlendState;
|
||||||
//$$ import com.replaymod.render.hooks.EntityRendererHandler;
|
//$$ import com.replaymod.render.hooks.EntityRendererHandler;
|
||||||
//$$ import net.minecraft.client.Minecraft;
|
//$$ import net.minecraft.client.Minecraft;
|
||||||
//$$ import net.minecraft.client.particle.EffectRenderer;
|
//$$ import net.minecraft.client.particle.EffectRenderer;
|
||||||
@@ -11,6 +12,7 @@ package com.replaymod.render.mixin;
|
|||||||
//$$ import org.spongepowered.asm.mixin.injection.Redirect;
|
//$$ import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
//$$
|
//$$
|
||||||
//#if MC>=10800
|
//#if MC>=10800
|
||||||
|
//$$ import com.replaymod.render.blend.exporters.ParticlesExporter;
|
||||||
//$$ import net.minecraft.client.renderer.WorldRenderer;
|
//$$ import net.minecraft.client.renderer.WorldRenderer;
|
||||||
//#else
|
//#else
|
||||||
//$$ import net.minecraft.client.renderer.Tessellator;
|
//$$ import net.minecraft.client.renderer.Tessellator;
|
||||||
@@ -81,6 +83,12 @@ package com.replaymod.render.mixin;
|
|||||||
//$$ rotYZ = (float) (-rotZ * Math.sin(pitch));
|
//$$ rotYZ = (float) (-rotZ * Math.sin(pitch));
|
||||||
//$$ rotXY = (float) (rotX * Math.sin(pitch));
|
//$$ rotXY = (float) (rotX * Math.sin(pitch));
|
||||||
//$$ }
|
//$$ }
|
||||||
|
//#if MC>=10800
|
||||||
|
//$$ BlendState blendState = BlendState.getState();
|
||||||
|
//$$ if (blendState != null) {
|
||||||
|
//$$ blendState.get(ParticlesExporter.class).onRender(fx, partialTicks);
|
||||||
|
//$$ }
|
||||||
|
//#endif
|
||||||
//#if MC>=10809
|
//#if MC>=10809
|
||||||
//$$ fx.renderParticle(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY);
|
//$$ fx.renderParticle(worldRenderer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY);
|
||||||
//#else
|
//#else
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.replaymod.render.mixin;
|
|||||||
|
|
||||||
//#if MC>=10904
|
//#if MC>=10904
|
||||||
import com.replaymod.core.versions.MCVer;
|
import com.replaymod.core.versions.MCVer;
|
||||||
|
import com.replaymod.render.blend.BlendState;
|
||||||
|
import com.replaymod.render.blend.exporters.ParticlesExporter;
|
||||||
import com.replaymod.render.hooks.EntityRendererHandler;
|
import com.replaymod.render.hooks.EntityRendererHandler;
|
||||||
import net.minecraft.client.particle.Particle;
|
import net.minecraft.client.particle.Particle;
|
||||||
import net.minecraft.client.particle.ParticleManager;
|
import net.minecraft.client.particle.ParticleManager;
|
||||||
@@ -62,6 +64,10 @@ public abstract class MixinParticleManager {
|
|||||||
rotYZ = (float) (-rotZ * Math.sin(pitch));
|
rotYZ = (float) (-rotZ * Math.sin(pitch));
|
||||||
rotXY = (float) (rotX * 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);
|
particle.renderParticle(vertexBuffer, view, partialTicks, rotX, rotXZ, rotZ, rotYZ, rotXY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.replaymod.render.processor;
|
||||||
|
|
||||||
|
import com.replaymod.render.rendering.Frame;
|
||||||
|
|
||||||
|
public class DummyProcessor<F extends Frame> extends AbstractFrameProcessor<F, F> {
|
||||||
|
@Override
|
||||||
|
public F process(F rawFrame) {
|
||||||
|
return rawFrame;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,32 @@
|
|||||||
package com.replaymod.render.rendering;
|
package com.replaymod.render.rendering;
|
||||||
|
|
||||||
import com.replaymod.render.RenderSettings;
|
import com.replaymod.render.RenderSettings;
|
||||||
import com.replaymod.render.capturer.*;
|
import com.replaymod.render.blend.BlendFrameCapturer;
|
||||||
import com.replaymod.render.frame.*;
|
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.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 com.replaymod.render.utils.PixelBufferObject;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class Pipelines {
|
public class Pipelines {
|
||||||
public static Pipeline newPipeline(RenderSettings.RenderMethod method, RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
public static Pipeline newPipeline(RenderSettings.RenderMethod method, RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
@@ -22,6 +41,8 @@ public class Pipelines {
|
|||||||
return newEquirectangularPipeline(renderInfo, consumer);
|
return newEquirectangularPipeline(renderInfo, consumer);
|
||||||
case ODS:
|
case ODS:
|
||||||
return newODSPipeline(renderInfo, consumer);
|
return newODSPipeline(renderInfo, consumer);
|
||||||
|
case BLEND:
|
||||||
|
throw new UnsupportedOperationException("Use newBlendPipeline instead!");
|
||||||
}
|
}
|
||||||
throw new UnsupportedOperationException("Unknown method: " + method);
|
throw new UnsupportedOperationException("Unknown method: " + method);
|
||||||
}
|
}
|
||||||
@@ -84,4 +105,19 @@ public class Pipelines {
|
|||||||
new ODSFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize());
|
new ODSFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo, processor.getFrameSize());
|
||||||
return new Pipeline<>(capturer, processor, consumer);
|
return new Pipeline<>(capturer, processor, consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Pipeline<RGBFrame, RGBFrame> newBlendPipeline(RenderInfo renderInfo) {
|
||||||
|
RenderSettings settings = renderInfo.getRenderSettings();
|
||||||
|
FrameCapturer<RGBFrame> capturer = new BlendFrameCapturer(new EntityRendererHandler(settings, renderInfo), renderInfo);
|
||||||
|
FrameConsumer<RGBFrame> consumer = new FrameConsumer<RGBFrame>() {
|
||||||
|
@Override
|
||||||
|
public void consume(RGBFrame frame) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new Pipeline<>(capturer, new DummyProcessor<>(), consumer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.replaymod.pathing.properties.TimestampProperty;
|
|||||||
import com.replaymod.render.RenderSettings;
|
import com.replaymod.render.RenderSettings;
|
||||||
import com.replaymod.render.ReplayModRender;
|
import com.replaymod.render.ReplayModRender;
|
||||||
import com.replaymod.render.VideoWriter;
|
import com.replaymod.render.VideoWriter;
|
||||||
|
import com.replaymod.render.blend.BlendState;
|
||||||
import com.replaymod.render.capturer.RenderInfo;
|
import com.replaymod.render.capturer.RenderInfo;
|
||||||
import com.replaymod.render.events.ReplayRenderEvent;
|
import com.replaymod.render.events.ReplayRenderEvent;
|
||||||
import com.replaymod.render.frame.RGBFrame;
|
import com.replaymod.render.frame.RGBFrame;
|
||||||
@@ -100,14 +101,21 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
this.replayHandler = replayHandler;
|
this.replayHandler = replayHandler;
|
||||||
this.timeline = timeline;
|
this.timeline = timeline;
|
||||||
this.gui = new GuiVideoRenderer(this);
|
this.gui = new GuiVideoRenderer(this);
|
||||||
this.renderingPipeline = Pipelines.newPipeline(settings.getRenderMethod(), this,
|
if (settings.getRenderMethod() == RenderSettings.RenderMethod.BLEND) {
|
||||||
videoWriter = new VideoWriter(this) {
|
BlendState.setState(new BlendState(settings.getOutputFile()));
|
||||||
@Override
|
|
||||||
public void consume(RGBFrame frame) {
|
this.renderingPipeline = Pipelines.newBlendPipeline(this);
|
||||||
gui.updatePreview(frame);
|
this.videoWriter = null;
|
||||||
super.consume(frame);
|
} else {
|
||||||
}
|
this.renderingPipeline = Pipelines.newPipeline(settings.getRenderMethod(), this,
|
||||||
});
|
videoWriter = new VideoWriter(this) {
|
||||||
|
@Override
|
||||||
|
public void consume(RGBFrame frame) {
|
||||||
|
gui.updatePreview(frame);
|
||||||
|
super.consume(frame);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -353,7 +361,7 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
new SoundHandler().playRenderSuccessSound();
|
new SoundHandler().playRenderSuccessSound();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!hasFailed()) {
|
if (!hasFailed() && videoWriter != null) {
|
||||||
new GuiRenderingDone(ReplayModRender.instance, videoWriter.getVideoFile(), totalFrames, settings).display();
|
new GuiRenderingDone(ReplayModRender.instance, videoWriter.getVideoFile(), totalFrames, settings).display();
|
||||||
}
|
}
|
||||||
} catch (VideoWriter.FFmpegStartupException e) {
|
} catch (VideoWriter.FFmpegStartupException e) {
|
||||||
@@ -531,7 +539,9 @@ public class VideoRenderer implements RenderInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
videoWriter.abort();
|
if (videoWriter != null) {
|
||||||
|
videoWriter.abort();
|
||||||
|
}
|
||||||
this.cancelled = true;
|
this.cancelled = true;
|
||||||
renderingPipeline.cancel();
|
renderingPipeline.cancel();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,8 +110,11 @@ public net.minecraft.client.renderer.WorldRenderer field_72740_G # renderEntitie
|
|||||||
##endif
|
##endif
|
||||||
##endif
|
##endif
|
||||||
|
|
||||||
public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation
|
##if MC>=11300
|
||||||
#public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation field_178553_a # renderChunk
|
public net.minecraft.client.renderer.WorldRenderer$ContainerLocalRenderInformation
|
||||||
|
##else
|
||||||
|
#$$ public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation
|
||||||
|
##endif
|
||||||
|
|
||||||
# ChunkRenderDispatcher
|
# ChunkRenderDispatcher
|
||||||
public-f net.minecraft.client.renderer.chunk.ChunkRenderDispatcher field_178519_d # queueChunkUpdates
|
public-f net.minecraft.client.renderer.chunk.ChunkRenderDispatcher field_178519_d # queueChunkUpdates
|
||||||
@@ -128,6 +131,11 @@ public net.minecraft.client.renderer.entity.RenderManager field_178636_l # skinM
|
|||||||
public net.minecraft.client.renderer.ItemRenderer *
|
public net.minecraft.client.renderer.ItemRenderer *
|
||||||
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
|
# EntityPlayer
|
||||||
public net.minecraft.entity.player.EntityPlayer *
|
public net.minecraft.entity.player.EntityPlayer *
|
||||||
|
|
||||||
|
|||||||
Submodule src/main/resources/assets/replaymod/lang updated: 37de62cf8e...874fd8016d
21
src/main/resources/mixins.render.blend.replaymod.json
Normal file
21
src/main/resources/mixins.render.blend.replaymod.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"required": true,
|
||||||
|
"package": "com.replaymod.render.blend.mixin",
|
||||||
|
"mixins": [],
|
||||||
|
"server": [],
|
||||||
|
"client": [
|
||||||
|
//#if MC>=10800
|
||||||
|
"MixinChunkRenderWorker",
|
||||||
|
"MixinEffectRenderer",
|
||||||
|
"MixinModelRenderer",
|
||||||
|
"MixinRenderGlobal",
|
||||||
|
"MixinRenderItem",
|
||||||
|
"MixinRenderLivingBase",
|
||||||
|
"MixinRenderManager",
|
||||||
|
"MixinTileEntityRendererDispatcher"
|
||||||
|
//#endif
|
||||||
|
],
|
||||||
|
"compatibilityLevel": "JAVA_8",
|
||||||
|
"minVersion": "0.6.11",
|
||||||
|
"refmap": "mixins.replaymod.refmap.json"
|
||||||
|
}
|
||||||
@@ -179,6 +179,8 @@ dependencies {
|
|||||||
|
|
||||||
shade 'org.aspectj:aspectjrt:1.8.2'
|
shade 'org.aspectj:aspectjrt:1.8.2'
|
||||||
|
|
||||||
|
shade 'com.github.ReplayMod.JavaBlend:2.79.0:a0696f8'
|
||||||
|
|
||||||
def studioVersion = mcVersionStr
|
def studioVersion = mcVersionStr
|
||||||
if (studioVersion == '1.8.9') studioVersion = '1.8'
|
if (studioVersion == '1.8.9') studioVersion = '1.8'
|
||||||
shade "com.github.ReplayMod.ReplayStudio:$studioVersion:c41d016", shadeExclusions
|
shade "com.github.ReplayMod.ReplayStudio:$studioVersion:c41d016", shadeExclusions
|
||||||
@@ -190,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
|
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
|
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.')) {
|
if (!gradle.gradleVersion.startsWith('3.')) {
|
||||||
annotationProcessor 'org.projectlombok:lombok:1.16.6'
|
annotationProcessor 'org.projectlombok:lombok:1.16.6'
|
||||||
|
|||||||
Reference in New Issue
Block a user