Separate rendering into its own module
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package com.replaymod.render.hooks;
|
||||
|
||||
import eu.crushedpixel.replaymod.utils.JailingQueue;
|
||||
import net.minecraft.client.renderer.RegionRenderCacheBuilder;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.client.renderer.chunk.ChunkCompileTaskGenerator;
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher;
|
||||
import net.minecraft.client.renderer.chunk.ChunkRenderWorker;
|
||||
import net.minecraft.client.renderer.chunk.RenderChunk;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
public class ChunkLoadingRenderGlobal {
|
||||
|
||||
private final RenderGlobal hooked;
|
||||
private final ChunkRenderDispatcher renderDispatcher;
|
||||
private final JailingQueue<?> workerJailingQueue;
|
||||
private final CustomChunkRenderWorker renderWorker;
|
||||
private int frame;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ChunkLoadingRenderGlobal(RenderGlobal renderGlobal) {
|
||||
this.hooked = renderGlobal;
|
||||
this.renderDispatcher = renderGlobal.renderDispatcher;
|
||||
this.renderWorker = new CustomChunkRenderWorker(renderDispatcher, new RegionRenderCacheBuilder());
|
||||
|
||||
int workerThreads = renderDispatcher.listThreadedWorkers.size();
|
||||
BlockingQueue<Object> queueChunkUpdates = renderDispatcher.queueChunkUpdates;
|
||||
workerJailingQueue = new JailingQueue<>(queueChunkUpdates);
|
||||
renderDispatcher.queueChunkUpdates = workerJailingQueue;
|
||||
ChunkCompileTaskGenerator element = new ChunkCompileTaskGenerator(null, null);
|
||||
element.finish();
|
||||
for (int i = 0; i < workerThreads; i++) {
|
||||
queueChunkUpdates.add(element);
|
||||
}
|
||||
|
||||
// Temporary workaround for dead lock, will be replaced by a new (ShaderMod compatible) mechanism later
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (renderDispatcher.runChunkUploads(0)) {}
|
||||
|
||||
workerJailingQueue.jail(workerThreads);
|
||||
renderDispatcher.queueChunkUpdates = queueChunkUpdates;
|
||||
|
||||
try {
|
||||
Field hookField = RenderGlobal.class.getField("replayModRender_hook");
|
||||
hookField.set(hooked, this);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void updateChunks() {
|
||||
while (renderDispatcher.runChunkUploads(0)) {
|
||||
hooked.displayListEntitiesDirty = true;
|
||||
}
|
||||
|
||||
while (!renderDispatcher.queueChunkUpdates.isEmpty()) {
|
||||
try {
|
||||
renderWorker.processTask((ChunkCompileTaskGenerator) renderDispatcher.queueChunkUpdates.poll());
|
||||
} catch (InterruptedException ignored) { }
|
||||
}
|
||||
|
||||
Iterator<RenderChunk> iterator = hooked.chunksToUpdate.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
RenderChunk renderchunk = iterator.next();
|
||||
|
||||
renderDispatcher.updateChunkNow(renderchunk);
|
||||
|
||||
renderchunk.setNeedsUpdate(false);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public void uninstall() {
|
||||
workerJailingQueue.freeAll();
|
||||
|
||||
try {
|
||||
Field hookField = RenderGlobal.class.getField("replayModRender_hook");
|
||||
hookField.set(hooked, null);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int nextFrameId() {
|
||||
return frame++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom ChunkRenderWorker class providing access to the protected processTask method
|
||||
*/
|
||||
private static class CustomChunkRenderWorker extends ChunkRenderWorker {
|
||||
public CustomChunkRenderWorker(ChunkRenderDispatcher p_i46202_1_, RegionRenderCacheBuilder p_i46202_2_) {
|
||||
super(p_i46202_1_, p_i46202_2_);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processTask(ChunkCompileTaskGenerator p_178474_1_) throws InterruptedException {
|
||||
super.processTask(p_178474_1_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.replaymod.render.hooks;
|
||||
|
||||
import com.replaymod.render.RenderSettings;
|
||||
import com.replaymod.render.capturer.CaptureData;
|
||||
import com.replaymod.render.capturer.WorldRenderer;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.culling.ClippingHelper;
|
||||
import org.lwjgl.util.ReadableDimension;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static net.minecraft.client.renderer.GlStateManager.*;
|
||||
|
||||
public class EntityRendererHandler implements WorldRenderer {
|
||||
public final Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
@Getter
|
||||
protected final RenderSettings settings;
|
||||
|
||||
public CaptureData data;
|
||||
|
||||
public EntityRendererHandler(RenderSettings settings) {
|
||||
this.settings = settings;
|
||||
|
||||
((IEntityRenderer) mc.entityRenderer).replayModRender_setHandler(this);
|
||||
}
|
||||
|
||||
public void withDisplaySize(int displayWidth, int displayHeight, Runnable runnable) {
|
||||
final int prevWidth = mc.displayWidth;
|
||||
final int prevHeight = mc.displayHeight;
|
||||
mc.displayWidth = displayWidth;
|
||||
mc.displayHeight = displayHeight;
|
||||
|
||||
runnable.run();
|
||||
|
||||
mc.displayWidth = prevWidth;
|
||||
mc.displayHeight = prevHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWorld(ReadableDimension displaySize, final float partialTicks, CaptureData data) {
|
||||
this.data = data;
|
||||
withDisplaySize(displaySize.getWidth(), displaySize.getHeight(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
renderWorld(partialTicks, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void renderWorld(float partialTicks, long finishTimeNano) {
|
||||
mc.entityRenderer.updateLightmap(partialTicks);
|
||||
|
||||
enableDepth();
|
||||
enableAlpha();
|
||||
alphaFunc(516, 0.5F);
|
||||
|
||||
mc.entityRenderer.renderWorldPass(2, partialTicks, finishTimeNano);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
((IEntityRenderer) mc.entityRenderer).replayModRender_setHandler(null);
|
||||
}
|
||||
|
||||
public static final class NoCullingClippingHelper extends ClippingHelper {
|
||||
@Override
|
||||
public boolean isBoxInFrustum(double p_78553_1_, double p_78553_3_, double p_78553_5_, double p_78553_7_, double p_78553_9_, double p_78553_11_) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public interface GluPerspective {
|
||||
void replayModRender_gluPerspective(float fovY, float aspect, float zNear, float zFar);
|
||||
}
|
||||
|
||||
public interface IEntityRenderer {
|
||||
void replayModRender_setHandler(EntityRendererHandler handler);
|
||||
EntityRendererHandler replayModRender_getHandler();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.replaymod.render.hooks;
|
||||
|
||||
import com.replaymod.core.utils.WrappedTimer;
|
||||
import net.minecraft.util.Timer;
|
||||
|
||||
/**
|
||||
* Wrapper around the current timer that prevents the timer from advancing by itself.
|
||||
*/
|
||||
public class RenderReplayTimer extends WrappedTimer {
|
||||
private final Timer state = new Timer(0);
|
||||
|
||||
public RenderReplayTimer(Timer wrapped) {
|
||||
super(wrapped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTimer() {
|
||||
copy(this, state); // Save our current state
|
||||
super.updateTimer(); // Update current state
|
||||
copy(state, this); // Restore our old state
|
||||
}
|
||||
|
||||
public Timer getWrapped() {
|
||||
return wrapped;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user