Separate rendering into its own module
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.replaymod.render.processor;
|
||||
|
||||
import com.replaymod.render.rendering.Frame;
|
||||
import com.replaymod.render.rendering.FrameProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class AbstractFrameProcessor<R extends Frame, P extends Frame> implements FrameProcessor<R, P> {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.replaymod.render.processor;
|
||||
|
||||
import com.replaymod.render.frame.CubicOpenGlFrame;
|
||||
import com.replaymod.render.frame.RGBFrame;
|
||||
import com.replaymod.render.utils.ByteBufferPool;
|
||||
import org.lwjgl.util.Dimension;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.replaymod.render.utils.Utils.openGlBytesToRBG;
|
||||
|
||||
public class CubicToRGBProcessor extends AbstractFrameProcessor<CubicOpenGlFrame, RGBFrame> {
|
||||
@Override
|
||||
public RGBFrame process(CubicOpenGlFrame rawFrame) {
|
||||
int size = rawFrame.getLeft().getSize().getWidth();
|
||||
int width = size * 4;
|
||||
int height = size * 3;
|
||||
ByteBuffer result = ByteBufferPool.allocate(width * height * 3);
|
||||
openGlBytesToRBG(rawFrame.getLeft().getByteBuffer(), size, 0, size, result, width);
|
||||
openGlBytesToRBG(rawFrame.getFront().getByteBuffer(), size, size, size, result, width);
|
||||
openGlBytesToRBG(rawFrame.getRight().getByteBuffer(), size, size * 2, size, result, width);
|
||||
openGlBytesToRBG(rawFrame.getBack().getByteBuffer(), size, size * 3, size, result, width);
|
||||
openGlBytesToRBG(rawFrame.getTop().getByteBuffer(), size, size, 0, result, width);
|
||||
openGlBytesToRBG(rawFrame.getBottom().getByteBuffer(), size, size, size * 2, result, width);
|
||||
ByteBufferPool.release(rawFrame.getLeft().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getRight().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getFront().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getBack().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getTop().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getBottom().getByteBuffer());
|
||||
return new RGBFrame(rawFrame.getFrameId(), new Dimension(width, height), result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package com.replaymod.render.processor;
|
||||
|
||||
import com.replaymod.render.frame.CubicOpenGlFrame;
|
||||
import com.replaymod.render.frame.RGBFrame;
|
||||
import com.replaymod.render.utils.ByteBufferPool;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.lwjgl.util.Dimension;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static java.lang.Math.PI;
|
||||
|
||||
public class EquirectangularToRGBProcessor extends AbstractFrameProcessor<CubicOpenGlFrame, RGBFrame> {
|
||||
private static final byte IMAGE_BACK = 0;
|
||||
private static final byte IMAGE_FRONT = 1;
|
||||
private static final byte IMAGE_LEFT = 2;
|
||||
private static final byte IMAGE_RIGHT = 3;
|
||||
private static final byte IMAGE_TOP = 4;
|
||||
private static final byte IMAGE_BOTTOM = 5;
|
||||
|
||||
private final int frameSize;
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
private final byte[][] image;
|
||||
private final int[][] imageX;
|
||||
private final int[][] imageY;
|
||||
|
||||
|
||||
public EquirectangularToRGBProcessor(int frameSize) {
|
||||
this.frameSize = frameSize;
|
||||
|
||||
width = frameSize * 4;
|
||||
height = frameSize * 2;
|
||||
image = new byte[height][width];
|
||||
imageX = new int[height][width];
|
||||
imageY = new int[height][width];
|
||||
for (int i = 0; i < width; i++) {
|
||||
double yaw = PI * 2 * i / width;
|
||||
int piQuarter = 8 * i / width - 4;
|
||||
byte target;
|
||||
if (piQuarter < -3) {
|
||||
target = IMAGE_BACK;
|
||||
} else if (piQuarter < -1) {
|
||||
target = IMAGE_LEFT;
|
||||
} else if (piQuarter < 1) {
|
||||
target = IMAGE_FRONT;
|
||||
} else if (piQuarter < 3) {
|
||||
target = IMAGE_RIGHT;
|
||||
} else {
|
||||
target = IMAGE_BACK;
|
||||
}
|
||||
double fYaw = (yaw + PI/4) % (PI / 2) - PI/4;
|
||||
double d = 1 / Math.cos(fYaw);
|
||||
double gcXN = (Math.tan(fYaw) + 1) / 2;
|
||||
for (int j = 0; j < height; j++) {
|
||||
double cXN = gcXN;
|
||||
byte pt = target;
|
||||
double pitch = PI * j / height - PI / 2;
|
||||
double cYN = (Math.tan(pitch) * d + 1) / 2;
|
||||
|
||||
if (cYN >= 1) {
|
||||
double pd = Math.tan(PI/2 - pitch);
|
||||
cXN = (-Math.sin(yaw) * pd + 1) / 2;
|
||||
cYN = (Math.cos(yaw) * pd + 1) / 2;
|
||||
pt = IMAGE_BOTTOM;
|
||||
}
|
||||
if (cYN < 0) {
|
||||
double pd = Math.tan(PI/2 - pitch);
|
||||
cXN = (Math.sin(yaw) * pd + 1) / 2;
|
||||
cYN = (Math.cos(yaw) * pd + 1) / 2;
|
||||
pt = IMAGE_TOP;
|
||||
}
|
||||
|
||||
int imgX = (int) Math.min(frameSize - 1, (cXN * frameSize));
|
||||
int imgY = (int) Math.min(frameSize - 1, (cYN * frameSize));
|
||||
image[j][i] = pt;
|
||||
imageX[j][i] = imgX;
|
||||
imageY[j][i] = frameSize - imgY - 1; // The OpenGl buffer contains data flipped vertically
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RGBFrame process(CubicOpenGlFrame rawFrame) {
|
||||
Validate.isTrue(rawFrame.getLeft().getSize().getWidth() == frameSize, "Frame size must be %d but was %d",
|
||||
frameSize, rawFrame.getLeft().getSize().getWidth());
|
||||
ByteBuffer result = ByteBufferPool.allocate(width * height * 3);
|
||||
ByteBuffer[] images = {
|
||||
rawFrame.getBack().getByteBuffer(), rawFrame.getFront().getByteBuffer(),
|
||||
rawFrame.getLeft().getByteBuffer(), rawFrame.getRight().getByteBuffer(),
|
||||
rawFrame.getTop().getByteBuffer(), rawFrame.getBottom().getByteBuffer()
|
||||
};
|
||||
byte[] pixel = new byte[3];
|
||||
byte[] image;
|
||||
int[] imageX, imageY;
|
||||
for (int y = 0; y < height; y++) {
|
||||
image = this.image[y];
|
||||
imageX = this.imageX[y];
|
||||
imageY = this.imageY[y];
|
||||
for (int x = 0; x < width; x++) {
|
||||
ByteBuffer source = images[image[x]];
|
||||
source.position((imageX[x] + imageY[x] * frameSize) * 3);
|
||||
source.get(pixel);
|
||||
result.put(pixel);
|
||||
}
|
||||
}
|
||||
result.rewind();
|
||||
|
||||
ByteBufferPool.release(rawFrame.getLeft().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getRight().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getFront().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getBack().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getTop().getByteBuffer());
|
||||
ByteBufferPool.release(rawFrame.getBottom().getByteBuffer());
|
||||
return new RGBFrame(rawFrame.getFrameId(), new Dimension(width, height), result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.replaymod.render.processor;
|
||||
|
||||
import com.replaymod.render.frame.OpenGlFrame;
|
||||
import com.replaymod.render.frame.RGBFrame;
|
||||
import org.lwjgl.util.ReadableDimension;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class OpenGlToRGBProcessor extends AbstractFrameProcessor<OpenGlFrame, RGBFrame> {
|
||||
|
||||
private byte[] row, rowSwap;
|
||||
|
||||
@Override
|
||||
public RGBFrame process(OpenGlFrame rawFrame) {
|
||||
// Flip whole image in place
|
||||
|
||||
ReadableDimension size = rawFrame.getSize();
|
||||
int rowSize = size.getWidth() * 3;
|
||||
if (row == null || row.length < rowSize) {
|
||||
row = new byte[rowSize];
|
||||
rowSwap = new byte[rowSize];
|
||||
}
|
||||
ByteBuffer buffer = rawFrame.getByteBuffer();
|
||||
int rows = size.getHeight();
|
||||
byte[] row = this.row;
|
||||
byte[] rowSwap = this.rowSwap;
|
||||
for (int i = 0; i < rows / 2; i++) {
|
||||
int from = rowSize * i;
|
||||
int to = rowSize * (rows - i - 1);
|
||||
buffer.position(from);
|
||||
buffer.get(row);
|
||||
buffer.position(to);
|
||||
buffer.get(rowSwap);
|
||||
buffer.position(to);
|
||||
buffer.put(row);
|
||||
buffer.position(from);
|
||||
buffer.put(rowSwap);
|
||||
}
|
||||
buffer.rewind();
|
||||
return new RGBFrame(rawFrame.getFrameId(), size, buffer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.replaymod.render.processor;
|
||||
|
||||
import com.replaymod.render.frame.RGBFrame;
|
||||
import com.replaymod.render.frame.StereoscopicOpenGlFrame;
|
||||
import com.replaymod.render.utils.ByteBufferPool;
|
||||
import org.lwjgl.util.Dimension;
|
||||
import org.lwjgl.util.ReadableDimension;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.replaymod.render.utils.Utils.openGlBytesToRBG;
|
||||
|
||||
public class StereoscopicToRGBProcessor extends AbstractFrameProcessor<StereoscopicOpenGlFrame, RGBFrame> {
|
||||
@Override
|
||||
public RGBFrame process(StereoscopicOpenGlFrame rawFrame) {
|
||||
ReadableDimension size = rawFrame.getLeft().getSize();
|
||||
int width = size.getWidth();
|
||||
ByteBuffer leftBuffer = rawFrame.getLeft().getByteBuffer();
|
||||
ByteBuffer rightBuffer = rawFrame.getRight().getByteBuffer();
|
||||
ByteBuffer result = ByteBufferPool.allocate(width * 2 * size.getHeight() * 3);
|
||||
openGlBytesToRBG(leftBuffer, width, 0, 0, result, width * 2);
|
||||
openGlBytesToRBG(rightBuffer, width, size.getWidth(), 0, result, width * 2);
|
||||
ByteBufferPool.release(leftBuffer);
|
||||
ByteBufferPool.release(rightBuffer);
|
||||
return new RGBFrame(rawFrame.getFrameId(), new Dimension(width * 2, size.getHeight()), result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user