From 646577e97f0249db2b031d010a61bde0bdc74432 Mon Sep 17 00:00:00 2001 From: DIvan2000 Date: Tue, 30 Jun 2026 11:44:24 +0400 Subject: [PATCH] test worked --- .../com/replaymod/render/RenderSettings.java | 2 +- .../capturer/RealLensCameraContext.java | 21 ++++ .../capturer/RealLensOpenGlFrameCapturer.java | 70 ++++++++++++ .../render/frame/RealLensOpenGlFrame.java | 39 +++++++ .../render/mixin/Mixin_RealLens_Camera.java | 55 ++++++++++ .../processor/RealLensToBitmapProcessor.java | 101 ++++++++++++++++++ .../replaymod/render/rendering/Pipelines.java | 14 +++ .../resources/mixins.render.replaymod.json | 1 + versions/1.21.11/logs/latest.log | 0 9 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/replaymod/render/capturer/RealLensCameraContext.java create mode 100644 src/main/java/com/replaymod/render/capturer/RealLensOpenGlFrameCapturer.java create mode 100644 src/main/java/com/replaymod/render/frame/RealLensOpenGlFrame.java create mode 100644 src/main/java/com/replaymod/render/mixin/Mixin_RealLens_Camera.java create mode 100644 src/main/java/com/replaymod/render/processor/RealLensToBitmapProcessor.java create mode 100644 versions/1.21.11/logs/latest.log diff --git a/src/main/java/com/replaymod/render/RenderSettings.java b/src/main/java/com/replaymod/render/RenderSettings.java index f5e92ffb..54217056 100644 --- a/src/main/java/com/replaymod/render/RenderSettings.java +++ b/src/main/java/com/replaymod/render/RenderSettings.java @@ -25,7 +25,7 @@ import static com.replaymod.render.ReplayModRender.LOGGER; public class RenderSettings { public enum RenderMethod { - DEFAULT, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS, BLEND; + DEFAULT, REALLENS, STEREOSCOPIC, CUBIC, EQUIRECTANGULAR, ODS, BLEND; @Override public String toString() { diff --git a/src/main/java/com/replaymod/render/capturer/RealLensCameraContext.java b/src/main/java/com/replaymod/render/capturer/RealLensCameraContext.java new file mode 100644 index 00000000..8d8fd1ab --- /dev/null +++ b/src/main/java/com/replaymod/render/capturer/RealLensCameraContext.java @@ -0,0 +1,21 @@ +package com.replaymod.render.capturer; + +public final class RealLensCameraContext { + + private static final ThreadLocal CURRENT = + new ThreadLocal<>(); + + private RealLensCameraContext() {} + + public static void set(RealLensOpenGlFrameCapturer.Data data) { + CURRENT.set(data); + } + + public static RealLensOpenGlFrameCapturer.Data get() { + return CURRENT.get(); + } + + public static void clear() { + CURRENT.remove(); + } +} \ No newline at end of file diff --git a/src/main/java/com/replaymod/render/capturer/RealLensOpenGlFrameCapturer.java b/src/main/java/com/replaymod/render/capturer/RealLensOpenGlFrameCapturer.java new file mode 100644 index 00000000..71b57365 --- /dev/null +++ b/src/main/java/com/replaymod/render/capturer/RealLensOpenGlFrameCapturer.java @@ -0,0 +1,70 @@ +package com.replaymod.render.capturer; + +import com.replaymod.render.frame.OpenGlFrame; +import com.replaymod.render.frame.RealLensOpenGlFrame; +import com.replaymod.render.rendering.Channel; + +import java.util.Collections; +import java.util.Map; + +public class RealLensOpenGlFrameCapturer + extends OpenGlFrameCapturer { + + public static class Data implements CaptureData { + + public final float dx, dy, dz; + public final float yaw, pitch; + + public Data(float dx, float dy, float dz, + float yaw, float pitch) { + this.dx = dx; + this.dy = dy; + this.dz = dz; + this.yaw = yaw; + this.pitch = pitch; + } + } + + private static final Data[] CAMERAS = { + new Data( 0.25f, 0.00f, 0f, 0f, 0f), + new Data( 0.00f, 0.25f, 0f, 0f, 0f), + new Data(-0.25f, 0.00f, 0f, 0f, 0f), + new Data( 0.00f, -0.25f, 0f, 0f, 0f) + }; + + public RealLensOpenGlFrameCapturer( + WorldRenderer worldRenderer, + RenderInfo renderInfo + ) { + super(worldRenderer, renderInfo); + } + + @Override + public Map process() { + + float partialTicks = renderInfo.updateForNextFrame(); + int frameId = framesDone++; + + OpenGlFrame[] frames = new OpenGlFrame[CAMERAS.length]; + + try { + for (int i = 0; i < CAMERAS.length; i++) { + + RealLensCameraContext.set(CAMERAS[i]); + + frames[i] = renderFrame( + frameId, + partialTicks, + CAMERAS[i] + ); + } + } finally { + RealLensCameraContext.clear(); + } + + return Collections.singletonMap( + Channel.BRGA, + new RealLensOpenGlFrame(frames) + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/replaymod/render/frame/RealLensOpenGlFrame.java b/src/main/java/com/replaymod/render/frame/RealLensOpenGlFrame.java new file mode 100644 index 00000000..9e4e2b42 --- /dev/null +++ b/src/main/java/com/replaymod/render/frame/RealLensOpenGlFrame.java @@ -0,0 +1,39 @@ +package com.replaymod.render.frame; + +import com.replaymod.render.rendering.Frame; +import org.apache.commons.lang3.Validate; + +public class RealLensOpenGlFrame implements Frame { + + private final OpenGlFrame[] frames; + + public RealLensOpenGlFrame(OpenGlFrame[] frames) { + Validate.notNull(frames, "frames"); + Validate.isTrue(frames.length > 0, "frames must not be empty"); + + int frameId = frames[0].getFrameId(); + int remaining = frames[0].getByteBuffer().remaining(); + + for (OpenGlFrame frame : frames) { + Validate.isTrue( + frame.getFrameId() == frameId, + "Frame ids do not match." + ); + Validate.isTrue( + frame.getByteBuffer().remaining() == remaining, + "Buffer sizes do not match." + ); + } + + this.frames = frames; + } + + @Override + public int getFrameId() { + return frames[0].getFrameId(); + } + + public OpenGlFrame[] getFrames() { + return frames; + } +} \ No newline at end of file diff --git a/src/main/java/com/replaymod/render/mixin/Mixin_RealLens_Camera.java b/src/main/java/com/replaymod/render/mixin/Mixin_RealLens_Camera.java new file mode 100644 index 00000000..b2d515be --- /dev/null +++ b/src/main/java/com/replaymod/render/mixin/Mixin_RealLens_Camera.java @@ -0,0 +1,55 @@ +package com.replaymod.render.mixin; + +import com.replaymod.render.capturer.RealLensOpenGlFrameCapturer; +import com.replaymod.render.capturer.RealLensCameraContext; +import com.replaymod.render.hooks.EntityRendererHandler; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.Matrix4f; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +//#if MC>=12005 +//$$ import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +//$$ import org.joml.Matrix4f; +//#endif + +@Mixin(GameRenderer.class) +public abstract class Mixin_RealLens_Camera { + + //#if MC>=12005 + //#if MC>=12100 + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotation(Lorg/joml/Quaternionfc;)Lorg/joml/Matrix4f;")) + //#else + //$$ @ModifyExpressionValue(method = "renderWorld", at = @At(value = "INVOKE", target = "Lorg/joml/Matrix4f;rotationXYZ(FFF)Lorg/joml/Matrix4f;")) + //#endif + //$$ private Matrix4f realLens_applyCameraTransform(Matrix4f matrix) { + //#else + @Inject(method = "renderWorld", at = @At("HEAD")) + private void realLens_applyCameraTransform(float partialTicks, long frameStartNano, MatrixStack matrixStack, CallbackInfo ci) { + //#endif + + RealLensOpenGlFrameCapturer.Data cam = RealLensCameraContext.get(); + if (cam == null) { + System.out.println("renderWorld WITHOUT camera context!"); + //#if MC>=12005 + //$$ return matrix; + //#else + return; + //#endif + } + + //#if MC>=12005 + //$$ matrix.translateLocal(cam.dx, cam.dy, cam.dz); + //#else + matrixStack.translate(cam.dx, cam.dy, cam.dz); + //#endif + + //#if MC>=12005 + //$$ return matrix; + //#endif + } +} \ No newline at end of file diff --git a/src/main/java/com/replaymod/render/processor/RealLensToBitmapProcessor.java b/src/main/java/com/replaymod/render/processor/RealLensToBitmapProcessor.java new file mode 100644 index 00000000..3ea277f1 --- /dev/null +++ b/src/main/java/com/replaymod/render/processor/RealLensToBitmapProcessor.java @@ -0,0 +1,101 @@ +package com.replaymod.render.processor; + +import com.replaymod.render.frame.BitmapFrame; +import com.replaymod.render.frame.OpenGlFrame; +import com.replaymod.render.frame.RealLensOpenGlFrame; +import com.replaymod.render.utils.ByteBufferPool; +import de.johni0702.minecraft.gui.utils.lwjgl.Dimension; + +import java.nio.ByteBuffer; + +import static com.replaymod.render.utils.Utils.openGlBytesToBitmap; + +public class RealLensToBitmapProcessor + extends AbstractFrameProcessor { + + @Override + public BitmapFrame process(RealLensOpenGlFrame rawFrame) { + + OpenGlFrame[] frames = rawFrame.getFrames(); + OpenGlFrame first = frames[0]; + + int width = first.getSize().getWidth(); + int height = first.getSize().getHeight(); + int bpp = first.getBytesPerPixel(); + + int totalBytes = width * height * bpp; + + int[] accumulator = new int[totalBytes]; + + ByteBuffer converted = ByteBufferPool.allocate(totalBytes); + + try { + + for (OpenGlFrame frame : frames) { + + converted.clear(); + + // BGRA -> bitmap layout (still BGRA at this point) + openGlBytesToBitmap( + frame, + 0, + 0, + converted, + width + ); + + converted.rewind(); + + // accumulate per channel with B <-> R swap + for (int i = 0; i < totalBytes; i += bpp) { + + int b = converted.get(i) & 0xFF; + int g = converted.get(i + 1) & 0xFF; + int r = converted.get(i + 2) & 0xFF; + int a = (bpp == 4) ? (converted.get(i + 3) & 0xFF) : 255; + + // swap R and B here + accumulator[i] += r; + accumulator[i + 1] += g; + accumulator[i + 2] += b; + + if (bpp == 4) { + accumulator[i + 3] += a; + } + } + } + + ByteBuffer output = ByteBufferPool.allocate(totalBytes); + + int samples = frames.length; + + for (int i = 0; i < totalBytes; i += bpp) { + + output.put((byte) (accumulator[i] / samples)); // R + output.put((byte) (accumulator[i + 1] / samples)); // G + output.put((byte) (accumulator[i + 2] / samples)); // B + + if (bpp == 4) { + output.put((byte) (accumulator[i + 3] / samples)); // A + } + } + + output.rewind(); + + return new BitmapFrame( + rawFrame.getFrameId(), + new Dimension(width, height), + bpp, + output + ); + + } finally { + + ByteBufferPool.release(converted); + + for (OpenGlFrame frame : frames) { + ByteBufferPool.release(frame.getByteBuffer()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/replaymod/render/rendering/Pipelines.java b/src/main/java/com/replaymod/render/rendering/Pipelines.java index bc65fba2..2a840949 100644 --- a/src/main/java/com/replaymod/render/rendering/Pipelines.java +++ b/src/main/java/com/replaymod/render/rendering/Pipelines.java @@ -24,6 +24,9 @@ import com.replaymod.render.processor.ODSToBitmapProcessor; import com.replaymod.render.processor.OpenGlToBitmapProcessor; import com.replaymod.render.processor.StereoscopicToBitmapProcessor; import com.replaymod.render.utils.PixelBufferObject; +import com.replaymod.render.capturer.RealLensOpenGlFrameCapturer; +import com.replaymod.render.frame.RealLensOpenGlFrame; +import com.replaymod.render.processor.RealLensToBitmapProcessor; import java.util.Map; @@ -32,6 +35,8 @@ public class Pipelines { switch (method) { case DEFAULT: return newDefaultPipeline(renderInfo, consumer); + case REALLENS: + return newRealLensPipeline(renderInfo, consumer); case STEREOSCOPIC: return newStereoscopicPipeline(renderInfo, consumer); case CUBIC: @@ -58,6 +63,15 @@ public class Pipelines { return new Pipeline<>(worldRenderer, capturer, new OpenGlToBitmapProcessor(), consumer); } + public static Pipeline newRealLensPipeline( + RenderInfo renderInfo, FrameConsumer consumer) { + RenderSettings settings = renderInfo.getRenderSettings(); + WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); + FrameCapturer capturer = + new RealLensOpenGlFrameCapturer(worldRenderer, renderInfo); + return new Pipeline<>(worldRenderer, capturer, new RealLensToBitmapProcessor(), consumer); + } + public static Pipeline newStereoscopicPipeline(RenderInfo renderInfo, FrameConsumer consumer) { RenderSettings settings = renderInfo.getRenderSettings(); WorldRenderer worldRenderer = new EntityRendererHandler(settings, renderInfo); diff --git a/src/main/resources/mixins.render.replaymod.json b/src/main/resources/mixins.render.replaymod.json index b53b2208..7f156b61 100644 --- a/src/main/resources/mixins.render.replaymod.json +++ b/src/main/resources/mixins.render.replaymod.json @@ -31,6 +31,7 @@ "Mixin_SkipBlockOutlinesDuringRender", "Mixin_SkipHudDuringRender", "Mixin_StabilizeCamera", + "Mixin_RealLens_Camera", "Mixin_Stereoscopic_Camera", "Mixin_Stereoscopic_HandRenderPass", "Mixin_SuppressFramebufferResizeDuringRender", diff --git a/versions/1.21.11/logs/latest.log b/versions/1.21.11/logs/latest.log new file mode 100644 index 00000000..e69de29b