Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,25 @@ abstract class AbstractDumpFormat implements DumpFormat {
* Read samples from the stream.
*
* @param inputStream Stream to read samples from.
* @param scene Scene this dump is a part of. Do not modify.
* @param header Header of the dump that is being read.
* @param consumer Pixel consumer. Does not need to be in order.
* @param pixelProgress Progress consumer. Inputs to this must be increasing and end at
* {@code scene.width * scene.height}.
*/
protected abstract void readSamples(DataInputStream inputStream, Scene scene,
protected abstract void readSamples(DataInputStream inputStream, DumpMetadata header,
PixelConsumer consumer, IntConsumer pixelProgress)
throws IOException;
throws IOException;

/**
* Write sample buffer to the stream.
*
* @param outputStream Stream to write to.
* @param scene Scene to take the sample buffer from. Do not modify.
* @param dump Render dump.
* @param pixelProgress Progress consumer. Inputs must be increasing and end at
* {@code scene.width * scene.height}.
*/
protected abstract void writeSamples(DataOutputStream outputStream, Scene scene,
IntConsumer pixelProgress)
throws IOException;
protected abstract void writeSamples(DataOutputStream outputStream, RenderDump dump, IntConsumer pixelProgress)
throws IOException;

public abstract int getVersion();

Expand All @@ -62,71 +61,85 @@ protected abstract void writeSamples(DataOutputStream outputStream, Scene scene,

@Override
public void load(DataInputStream inputStream, Scene scene, TaskTracker taskTracker)
throws IOException, IllegalStateException {
throws IOException, IllegalStateException {
double[] samples = scene.getSampleBuffer();
try (TaskTracker.Task task = taskTracker.task("Loading render dump", samples.length / 3)) {
DumpMetadata header = readHeader(inputStream);
if (header.width() != scene.canvasConfig.getWidth() || header.height() != scene.canvasConfig.getHeight()) {
throw new IllegalStateException("Scene size does not match dump size");
}
scene.spp = header.spp();
scene.renderTime = header.renderTime();
readSamples(inputStream, header, (index, r, g, b) -> {
int offset = index * 3;
samples[offset + 0] = r;
samples[offset + 1] = g;
samples[offset + 2] = b;
}, i -> task.updateInterval(i, header.width()));
}
}

try (TaskTracker.Task task = taskTracker.task("Loading render dump", scene.canvasConfig.getPixelCount())) {
readHeader(inputStream, scene);
readSamples(inputStream, scene, (index, r, g, b) -> {
@Override
public RenderDump load(DataInputStream inputStream, TaskTracker taskTracker) throws IOException {
DumpMetadata header = readHeader(inputStream);
double[] samples = new double[header.width() * header.height() * 3];
try (TaskTracker.Task task = taskTracker.task("Loading render dump", header.width() * header.height())) {
readSamples(inputStream, header, (index, r, g, b) -> {
int offset = index * 3;
samples[offset + 0] = r;
samples[offset + 1] = g;
samples[offset + 2] = b;
}, i -> task.updateInterval(i, scene.canvasConfig.getWidth()));
}, i -> task.updateInterval(i, header.width()));
}
return new RenderDump(header, samples);
}

@Override
public void save(DataOutputStream outputStream, Scene scene, TaskTracker taskTracker)
throws IOException {
try (TaskTracker.Task task = taskTracker.task("Saving render dump", scene.canvasConfig.getPixelCount())) {
writeHeader(outputStream, scene);
writeSamples(outputStream, scene, i -> task.updateInterval(i, scene.canvasConfig.getWidth()));
public void save(DataOutputStream outputStream, RenderDump dump, TaskTracker taskTracker)
throws IOException {
try (TaskTracker.Task task = taskTracker.task("Saving render dump", dump.getMetadata().width() * dump.getMetadata().height())) {
writeHeader(outputStream, dump.getMetadata());
writeSamples(outputStream, dump, i -> task.updateInterval(i, dump.getMetadata().width()));
}
}

@Override
public void merge(DataInputStream inputStream, Scene scene, TaskTracker taskTracker)
throws IOException, IllegalStateException {
throws IOException, IllegalStateException {
try (TaskTracker.Task task = taskTracker.task("Merging render dump", scene.canvasConfig.getPixelCount())) {
int sceneSpp = scene.spp;
long previousRenderTime = scene.renderTime;

double[] samples = scene.getSampleBuffer();

readHeader(inputStream, scene);
DumpMetadata header = readHeader(inputStream);

double dumpSpp = scene.spp;
double dumpSpp = header.spp();
double sinv = 1.0 / (sceneSpp + dumpSpp);

readSamples(inputStream, scene, (index, r, g, b) -> {
readSamples(inputStream, header, (index, r, g, b) -> {
int offset = index * 3;
samples[offset + 0] = (samples[offset + 0] * sceneSpp + r * dumpSpp) * sinv;
samples[offset + 1] = (samples[offset + 1] * sceneSpp + g * dumpSpp) * sinv;
samples[offset + 2] = (samples[offset + 2] * sceneSpp + b * dumpSpp) * sinv;
}, i -> task.updateInterval(i, scene.canvasConfig.getWidth()));

scene.spp += sceneSpp;
scene.renderTime += previousRenderTime;
scene.spp += header.spp();
scene.renderTime += header.renderTime();
}
}

protected void readHeader(DataInputStream inputStream, Scene scene) throws IOException, IllegalStateException {
int width = inputStream.readInt();
int height = inputStream.readInt();

if (width != scene.canvasConfig.getWidth() || height != scene.canvasConfig.getHeight()) {
throw new IllegalStateException("Scene size does not match dump size");
}

scene.spp = inputStream.readInt();
scene.renderTime = inputStream.readLong();
protected DumpMetadata readHeader(DataInputStream inputStream) throws IOException {
return new DumpMetadata(
inputStream.readInt(),
inputStream.readInt(),
inputStream.readInt(),
inputStream.readLong());
}

protected void writeHeader(DataOutputStream outputStream, Scene scene) throws IOException {
outputStream.writeInt(scene.canvasConfig.getWidth());
outputStream.writeInt(scene.canvasConfig.getHeight());
outputStream.writeInt(scene.spp);
outputStream.writeLong(scene.renderTime);
protected void writeHeader(DataOutputStream outputStream, DumpMetadata header) throws IOException {
outputStream.writeInt(header.width());
outputStream.writeInt(header.height());
outputStream.writeInt(header.spp());
outputStream.writeLong(header.renderTime());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package se.llbit.chunky.renderer.renderdump;

import se.llbit.chunky.renderer.scene.Scene;
import se.llbit.util.io.IsolatedOutputStream;
import se.llbit.util.TaskTracker;
import se.llbit.util.io.IsolatedOutputStream;

import java.io.DataInputStream;
import java.io.DataOutputStream;
Expand All @@ -38,7 +38,8 @@
public class ClassicDumpFormat extends AbstractDumpFormat {
public static final ClassicDumpFormat INSTANCE = new ClassicDumpFormat();

private ClassicDumpFormat() {}
private ClassicDumpFormat() {
}

@Override
public int getVersion() {
Expand All @@ -61,17 +62,17 @@ public String getId() {
}

@Override
protected void readSamples(DataInputStream inputStream, Scene scene,
protected void readSamples(DataInputStream inputStream, DumpMetadata header,
PixelConsumer consumer, IntConsumer pixelProgress)
throws IOException {
throws IOException {
int pixelIndex;
int done = 0;
double r, g, b;

// Warning: This format writes in column major order
for (int x = 0; x < scene.canvasConfig.getWidth(); x++) {
for (int y = 0; y < scene.canvasConfig.getHeight(); y++) {
pixelIndex = (y * scene.canvasConfig.getWidth() + x);
for (int x = 0; x < header.width(); x++) {
for (int y = 0; y < header.height(); y++) {
pixelIndex = (y * header.width() + x);
r = inputStream.readDouble();
g = inputStream.readDouble();
b = inputStream.readDouble();
Expand All @@ -82,17 +83,16 @@ protected void readSamples(DataInputStream inputStream, Scene scene,
}

@Override
protected void writeSamples(DataOutputStream outputStream, Scene scene,
IntConsumer pixelProgress)
throws IOException {
double[] samples = scene.getSampleBuffer();
protected void writeSamples(DataOutputStream outputStream, RenderDump dump, IntConsumer pixelProgress) throws IOException {
DumpMetadata header = dump.getMetadata();
double[] samples = dump.getSampleBuffer();
int offset;
int done = 0;

// Warning: This format writes in column major order
for (int x = 0; x < scene.canvasConfig.getWidth(); ++x) {
for (int y = 0; y < scene.canvasConfig.getHeight(); ++y) {
offset = (y * scene.canvasConfig.getWidth() + x) * 3;
for (int x = 0; x < header.width(); ++x) {
for (int y = 0; y < header.height(); ++y) {
offset = (y * header.width() + x) * 3;
outputStream.writeDouble(samples[offset + 0]);
outputStream.writeDouble(samples[offset + 1]);
outputStream.writeDouble(samples[offset + 2]);
Expand All @@ -103,7 +103,7 @@ protected void writeSamples(DataOutputStream outputStream, Scene scene,

@Override
public void load(DataInputStream inputStream, Scene scene, TaskTracker taskTracker)
throws IOException, IllegalStateException {
throws IOException, IllegalStateException {
DataInputStream stream = new DataInputStream(new GZIPInputStream(inputStream));
super.load(stream, scene, taskTracker);
}
Expand All @@ -117,7 +117,7 @@ public void save(DataOutputStream outputStream, Scene scene, TaskTracker taskTra

@Override
public void merge(DataInputStream inputStream, Scene scene, TaskTracker taskTracker)
throws IOException, IllegalStateException {
throws IOException, IllegalStateException {
DataInputStream stream = new DataInputStream(new GZIPInputStream(inputStream));
super.merge(stream, scene, taskTracker);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/**
* A dump format reads a render dump from a DataInputStream into the scene/ writes a render dump from the scene into a
* DataOutputStream.
*
* <p>
* The input stream
* The input stream is expected to <i>not</i> contain the magic number and version number - they should have been read
* before calling load (logic for that in RenderDump class). The output stream is expected to contain the magic number
Expand All @@ -38,21 +38,39 @@ public interface DumpFormat extends Registerable {
*
* @throws IllegalStateException If the render dump is invalid.
*/
void load(DataInputStream inputStream, Scene scene, TaskTracker taskTracker)
throws IOException, IllegalStateException;
void load(DataInputStream inputStream, Scene scene, TaskTracker taskTracker) throws IOException, IllegalStateException;

/**
* Read a render dump from an input stream. The stream will only contain the payload of the Chunky render dump
* container format.
* <p>
* Most render dumps will contain a "header" containing the width, height, spp, and renderTime followed by
* the sample buffer in some compressed format.
*
* @return The loaded render dump
*/
RenderDump load(DataInputStream inputStream, TaskTracker taskTracker) throws IOException;

/**
* Save a render dump to the output stream. This should only write the payload of the Chunky render dump
* container format.
*/
default void save(DataOutputStream outputStream, Scene scene, TaskTracker taskTracker)
throws IOException {
save(outputStream, new RenderDump(scene), taskTracker);
}

/**
* Save a render dump to the output stream. This should only write the payload of the Chunky render dump
* container format.
*/
void save(DataOutputStream outputStream, Scene scene, TaskTracker taskTracker)
throws IOException;
void save(DataOutputStream outputStream, RenderDump dump, TaskTracker taskTracker) throws IOException;

/**
* Merge a render dump into the provided scene.
*
* @throws IllegalStateException If the render dump is invalid.
*/
void merge(DataInputStream inputStream, Scene scene, TaskTracker taskTracker)
throws IOException, IllegalStateException;
throws IOException, IllegalStateException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package se.llbit.chunky.renderer.renderdump;

public record DumpMetadata(int width, int height, int spp, long renderTime) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
*/
package se.llbit.chunky.renderer.renderdump;

import se.llbit.chunky.renderer.scene.Scene;

import java.io.*;
import java.util.function.IntConsumer;

Expand All @@ -29,7 +27,8 @@
public class FloatingPointCompressorDumpFormat extends AbstractDumpFormat {
public static final FloatingPointCompressorDumpFormat INSTANCE = new FloatingPointCompressorDumpFormat();

private FloatingPointCompressorDumpFormat() {}
private FloatingPointCompressorDumpFormat() {
}

@Override
public int getVersion() {
Expand All @@ -52,17 +51,13 @@ public String getId() {
}

@Override
protected void readSamples(DataInputStream inputStream, Scene scene,
PixelConsumer consumer, IntConsumer pixelProgress)
throws IOException {
decompress(inputStream, scene.getSampleBuffer().length, consumer, pixelProgress);
protected void readSamples(DataInputStream inputStream, DumpMetadata header, PixelConsumer consumer, IntConsumer pixelProgress) throws IOException {
decompress(inputStream, header.width() * header.height() * 3, consumer, pixelProgress);
}

@Override
protected void writeSamples(DataOutputStream outputStream, Scene scene,
IntConsumer pixelProgress)
throws IOException {
double[] samples = scene.getSampleBuffer();
protected void writeSamples(DataOutputStream outputStream, RenderDump dump, IntConsumer pixelProgress) throws IOException {
double[] samples = dump.getSampleBuffer();
assert samples.length % 3 == 0;

int pixels = samples.length / 3;
Expand Down Expand Up @@ -92,7 +87,7 @@ protected void writeSamples(DataOutputStream outputStream, Scene scene,

private void decompress(InputStream inputStream, int bufferLength,
PixelConsumer consumer, IntConsumer pixelProgress)
throws IOException {
throws IOException {
assert bufferLength % 3 == 0;

int pixels = bufferLength / 3;
Expand Down Expand Up @@ -122,7 +117,7 @@ private void decompress(InputStream inputStream, int bufferLength,
double b2 = bDecoder.decodeSingle(bSecondHeader, inputStream);

consumer.consume(i, r1, g1, b1);
consumer.consume(i+1, r2, g2, b2);
consumer.consume(i + 1, r2, g2, b2);
pixelProgress.accept(i);
}

Expand Down
Loading
Loading