Add PBO frame capturer for stereoscopic, cubic and equirectangular rendering
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
package eu.crushedpixel.replaymod.video.capturer;
|
||||||
|
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.CubicOpenGlFrame;
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.OpenGlFrame;
|
||||||
|
|
||||||
|
public class CubicPboOpenGlFrameCapturer extends
|
||||||
|
MultiFramePboOpenGlFrameCapturer<CubicOpenGlFrame, CubicOpenGlFrameCapturer.Data> {
|
||||||
|
|
||||||
|
private final int frameSize;
|
||||||
|
public CubicPboOpenGlFrameCapturer(WorldRenderer<CubicOpenGlFrameCapturer.Data> worldRenderer,
|
||||||
|
RenderInfo renderInfo, int frameSize) {
|
||||||
|
super(worldRenderer, renderInfo, CubicOpenGlFrameCapturer.Data.class, frameSize * frameSize);
|
||||||
|
this.frameSize = frameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getFrameWidth() {
|
||||||
|
return frameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getFrameHeight() {
|
||||||
|
return frameSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CubicOpenGlFrame create(OpenGlFrame[] from) {
|
||||||
|
return new CubicOpenGlFrame(from[0], from[1], from[2], from[3], from[4], from[5]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package eu.crushedpixel.replaymod.video.capturer;
|
||||||
|
|
||||||
|
import eu.crushedpixel.replaymod.opengl.PixelBufferObject;
|
||||||
|
import eu.crushedpixel.replaymod.utils.ByteBufferPool;
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.OpenGlFrame;
|
||||||
|
import eu.crushedpixel.replaymod.video.rendering.Frame;
|
||||||
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public abstract class MultiFramePboOpenGlFrameCapturer<F extends Frame, D extends Enum<D> & CaptureData>
|
||||||
|
extends OpenGlFrameCapturer<F, D> {
|
||||||
|
private final D[] data;
|
||||||
|
private PixelBufferObject pbo, otherPBO;
|
||||||
|
|
||||||
|
public MultiFramePboOpenGlFrameCapturer(WorldRenderer<D> worldRenderer, RenderInfo renderInfo, Class<D> type, int framePixels) {
|
||||||
|
super(worldRenderer, renderInfo);
|
||||||
|
|
||||||
|
data = type.getEnumConstants();
|
||||||
|
int bufferSize = framePixels * 3 * data.length;
|
||||||
|
pbo = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
|
||||||
|
otherPBO = new PixelBufferObject(bufferSize, PixelBufferObject.Usage.READ);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract F create(OpenGlFrame[] from);
|
||||||
|
|
||||||
|
private void swapPBOs() {
|
||||||
|
PixelBufferObject old = pbo;
|
||||||
|
pbo = otherPBO;
|
||||||
|
otherPBO = old;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return framesDone >= renderInfo.getTotalFrames() + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public F process() {
|
||||||
|
F frame = null;
|
||||||
|
|
||||||
|
if (framesDone > 1) {
|
||||||
|
// Read pbo to memory
|
||||||
|
pbo.bind();
|
||||||
|
ByteBuffer pboBuffer = pbo.mapReadOnly();
|
||||||
|
|
||||||
|
OpenGlFrame[] frames = new OpenGlFrame[data.length];
|
||||||
|
int frameBufferSize = getFrameWidth() * getFrameHeight() * 3;
|
||||||
|
for (int i = 0; i < frames.length; i++) {
|
||||||
|
ByteBuffer frameBuffer = ByteBufferPool.allocate(frameBufferSize);
|
||||||
|
pboBuffer.limit(pboBuffer.position() + frameBufferSize);
|
||||||
|
frameBuffer.put(pboBuffer);
|
||||||
|
frameBuffer.rewind();
|
||||||
|
frames[i] = new OpenGlFrame(framesDone - 2, frameSize, frameBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pbo.unmap();
|
||||||
|
pbo.unbind();
|
||||||
|
|
||||||
|
frame = create(frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (framesDone < renderInfo.getTotalFrames()) {
|
||||||
|
float partialTicks = renderInfo.updateForNextFrame();
|
||||||
|
// Then fill it again
|
||||||
|
for (D data : this.data) {
|
||||||
|
renderFrame(framesDone, partialTicks, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
framesDone++;
|
||||||
|
swapPBOs();
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected OpenGlFrame captureFrame(int frameId, D captureData) {
|
||||||
|
pbo.bind();
|
||||||
|
|
||||||
|
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
||||||
|
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
int offset = captureData.ordinal() * getFrameWidth() * getFrameHeight() * 3;
|
||||||
|
if (OpenGlHelper.isFramebufferEnabled()) {
|
||||||
|
frameBuffer().bindFramebufferTexture();
|
||||||
|
GL11.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, offset);
|
||||||
|
frameBuffer().unbindFramebufferTexture();
|
||||||
|
} else {
|
||||||
|
GL11.glReadPixels(0, 0, getFrameWidth(), getFrameHeight(), GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
pbo.unbind();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
pbo.delete();
|
||||||
|
otherPBO.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,10 +82,10 @@ public abstract class OpenGlFrameCapturer<F extends Frame, D extends CaptureData
|
|||||||
frameBuffer().unbindFramebuffer();
|
frameBuffer().unbindFramebuffer();
|
||||||
popMatrix();
|
popMatrix();
|
||||||
|
|
||||||
return captureFrame(frameId);
|
return captureFrame(frameId, captureData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OpenGlFrame captureFrame(int frameId) {
|
protected OpenGlFrame captureFrame(int frameId, D captureData) {
|
||||||
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
||||||
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class SimplePboOpenGlFrameCapturer extends OpenGlFrameCapturer<OpenGlFram
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected OpenGlFrame captureFrame(int frameId) {
|
protected OpenGlFrame captureFrame(int frameId, CaptureData data) {
|
||||||
pbo.bind();
|
pbo.bind();
|
||||||
|
|
||||||
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1);
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package eu.crushedpixel.replaymod.video.capturer;
|
||||||
|
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.OpenGlFrame;
|
||||||
|
import eu.crushedpixel.replaymod.video.frame.StereoscopicOpenGlFrame;
|
||||||
|
|
||||||
|
public class StereoscopicPboOpenGlFrameCapturer
|
||||||
|
extends MultiFramePboOpenGlFrameCapturer<StereoscopicOpenGlFrame, StereoscopicOpenGlFrameCapturer.Data> {
|
||||||
|
|
||||||
|
public StereoscopicPboOpenGlFrameCapturer(WorldRenderer<StereoscopicOpenGlFrameCapturer.Data> worldRenderer,
|
||||||
|
RenderInfo renderInfo) {
|
||||||
|
super(worldRenderer, renderInfo, StereoscopicOpenGlFrameCapturer.Data.class,
|
||||||
|
renderInfo.getFrameSize().getWidth() / 2 * renderInfo.getFrameSize().getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getFrameWidth() {
|
||||||
|
return super.getFrameWidth() / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected StereoscopicOpenGlFrame create(OpenGlFrame[] from) {
|
||||||
|
return new StereoscopicOpenGlFrame(from[0], from[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,28 +49,34 @@ public class Pipelines {
|
|||||||
|
|
||||||
public static Pipeline<StereoscopicOpenGlFrame, RGBFrame> newStereoscopicPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
public static Pipeline<StereoscopicOpenGlFrame, RGBFrame> newStereoscopicPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
RenderOptions options = renderInfo.getRenderOptions();
|
RenderOptions options = renderInfo.getRenderOptions();
|
||||||
return new Pipeline<StereoscopicOpenGlFrame, RGBFrame>(
|
FrameCapturer<StereoscopicOpenGlFrame> capturer;
|
||||||
new StereoscopicOpenGlFrameCapturer(new StereoscopicEntityRenderer(options), renderInfo),
|
if (PixelBufferObject.SUPPORTED) {
|
||||||
new StereoscopicToRGBProcessor(),
|
capturer = new StereoscopicPboOpenGlFrameCapturer(new StereoscopicEntityRenderer(options), renderInfo);
|
||||||
consumer
|
} else {
|
||||||
);
|
capturer = new StereoscopicOpenGlFrameCapturer(new StereoscopicEntityRenderer(options), renderInfo);
|
||||||
|
}
|
||||||
|
return new Pipeline<StereoscopicOpenGlFrame, RGBFrame>(capturer, new StereoscopicToRGBProcessor(), consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pipeline<CubicOpenGlFrame, RGBFrame> newCubicPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
public static Pipeline<CubicOpenGlFrame, RGBFrame> newCubicPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
RenderOptions options = renderInfo.getRenderOptions();
|
RenderOptions options = renderInfo.getRenderOptions();
|
||||||
return new Pipeline<CubicOpenGlFrame, RGBFrame>(
|
FrameCapturer<CubicOpenGlFrame> capturer;
|
||||||
new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4),
|
if (PixelBufferObject.SUPPORTED) {
|
||||||
new CubicToRGBProcessor(),
|
capturer = new CubicPboOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4);
|
||||||
consumer
|
} else {
|
||||||
);
|
capturer = new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4);
|
||||||
|
}
|
||||||
|
return new Pipeline<CubicOpenGlFrame, RGBFrame>(capturer, new CubicToRGBProcessor(), consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pipeline<CubicOpenGlFrame, RGBFrame> newEquirectangularPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
public static Pipeline<CubicOpenGlFrame, RGBFrame> newEquirectangularPipeline(RenderInfo renderInfo, FrameConsumer<RGBFrame> consumer) {
|
||||||
RenderOptions options = renderInfo.getRenderOptions();
|
RenderOptions options = renderInfo.getRenderOptions();
|
||||||
return new Pipeline<CubicOpenGlFrame, RGBFrame>(
|
FrameCapturer<CubicOpenGlFrame> capturer;
|
||||||
new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4),
|
if (PixelBufferObject.SUPPORTED) {
|
||||||
new EquirectangularToRGBProcessor(options.getWidth() / 4),
|
capturer = new CubicPboOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4);
|
||||||
consumer
|
} else {
|
||||||
);
|
capturer = new CubicOpenGlFrameCapturer(new CubicEntityRenderer(options), renderInfo, options.getWidth() / 4);
|
||||||
|
}
|
||||||
|
return new Pipeline<CubicOpenGlFrame, RGBFrame>(capturer, new EquirectangularToRGBProcessor(options.getWidth() / 4), consumer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user