abstract Image

This commit is contained in:
jbb01 2024-08-04 01:28:12 +02:00
parent 1080711229
commit 87a7fbfcff
5 changed files with 93 additions and 27 deletions

View File

@ -0,0 +1,39 @@
package eu.jonahbauer.raytracing.render;
import org.jetbrains.annotations.NotNull;
import java.awt.image.BufferedImage;
public class BufferedImageCanvas implements Canvas {
private final @NotNull BufferedImage image;
public BufferedImageCanvas(int width, int height) {
this.image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
public @NotNull BufferedImage getImage() {
return image;
}
@Override
public int width() {
return image.getWidth();
}
@Override
public int height() {
return image.getHeight();
}
@Override
public @NotNull Color get(int x, int y) {
var rgb = image.getRGB(x, y);
return new Color((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF);
}
@Override
public void set(int x, int y, @NotNull Color color) {
var rgb = color.red() << 16 | color.green() << 8 | color.blue();
image.setRGB(x, y, rgb);
}
}

View File

@ -8,6 +8,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public final class Camera {
// image size
@ -72,8 +74,16 @@ public final class Camera {
public @NotNull Image render(@NotNull Scene scene) {
var image = new Image(width, height);
render(scene, image);
return image;
}
for (int y = 0; y < height; y++) {
public void render(@NotNull Scene scene, @NotNull Canvas canvas) {
if (canvas.width() != width || canvas.height() != height) throw new IllegalArgumentException();
var lines = new AtomicInteger();
IntStream.range(0, height).parallel().forEach(y -> {
System.out.println(lines.incrementAndGet());
for (int x = 0; x < width; x++) {
var r = 0d;
var g = 0d;
@ -87,15 +97,13 @@ public final class Camera {
b += color.b();
}
image.set(x, y, new Color(
canvas.set(x, y, new Color(
Math.pow(r / samplesPerPixel, 1 / gamma),
Math.pow(g / samplesPerPixel, 1 / gamma),
Math.pow(b / samplesPerPixel, 1 / gamma)
));
}
}
return image;
});
}
private @NotNull Ray getRay(int x, int y) {
@ -150,6 +158,14 @@ public final class Camera {
return Color.lerp(Color.WHITE, Color.SKY, alt / Math.PI + 0.5);
}
public int width() {
return width;
}
public int height() {
return height;
}
public static class Builder {
private int imageWidth = 1920;
private int imageHeight = 1080;

View File

@ -0,0 +1,21 @@
package eu.jonahbauer.raytracing.render;
import org.jetbrains.annotations.NotNull;
import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public interface Canvas {
int width();
int height();
void set(int x, int y, @NotNull Color color);
@NotNull Color get(int x, int y);
default @NotNull Stream<Color> pixels() {
return IntStream.range(0, height())
.mapToObj(y -> IntStream.range(0, width()).mapToObj(x -> get(x, y)))
.flatMap(Function.identity());
}
}

View File

@ -2,11 +2,9 @@ package eu.jonahbauer.raytracing.render;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Stream;
public final class Image {
public final class Image implements Canvas {
private final int width;
private final int height;
@ -22,35 +20,27 @@ public final class Image {
this.data = new Color[height][width];
}
@Override
public int width() {
return width;
}
@Override
public int height() {
return height;
}
@Override
public @NotNull Color get(int x, int y) {
Objects.checkIndex(x, width);
Objects.checkIndex(y, height);
return Objects.requireNonNullElse(this.data[y][x], Color.BLACK);
}
public @NotNull Stream<Color> pixels() {
return Arrays.stream(data).flatMap(Arrays::stream).map(c -> Objects.requireNonNullElse(c, Color.BLACK));
}
@Override
public void set(int x, int y, @NotNull Color color) {
Objects.checkIndex(x, width);
Objects.checkIndex(y, height);
this.data[y][x] = Objects.requireNonNull(color);
}
public void set(int x, int y, int red, int green, int blue) {
set(x, y, new Color(red, green, blue));
}
public void set(int x, int y, double r, double g, double b) {
set(x, y, new Color(r, g, b));
}
}

View File

@ -13,7 +13,7 @@ import java.util.zip.DeflaterOutputStream;
public enum ImageFormat {
PPM {
@Override
public void write(@NotNull Image image, @NotNull OutputStream out) throws IOException {
public void write(@NotNull Canvas image, @NotNull OutputStream out) throws IOException {
try (var writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.US_ASCII))) {
writer.write("P3\n");
writer.write(String.valueOf(image.width()));
@ -42,7 +42,7 @@ public enum ImageFormat {
private static final int IEND_TYPE = 0x49454E44;
@Override
public void write(@NotNull Image image, @NotNull OutputStream out) throws IOException {
public void write(@NotNull Canvas image, @NotNull OutputStream out) throws IOException {
try (var data = new NoCloseDataOutputStream(out); var _ = data.closeable()) {
data.write(MAGIC);
@ -52,7 +52,7 @@ public enum ImageFormat {
}
}
private void writeIHDR(@NotNull Image image, @NotNull DataOutputStream data) throws IOException {
private void writeIHDR(@NotNull Canvas image, @NotNull DataOutputStream data) throws IOException {
data.writeInt(IHDR_LENGTH);
try (
var crc = new CheckedOutputStream(data, new CRC32());
@ -71,7 +71,7 @@ public enum ImageFormat {
}
}
private void writeIDAT(@NotNull Image image, @NotNull DataOutputStream data) throws IOException {
private void writeIDAT(@NotNull Canvas image, @NotNull DataOutputStream data) throws IOException {
try (
var baos = new ByteArrayOutputStream();
var crc = new CheckedOutputStream(baos, new CRC32());
@ -97,7 +97,7 @@ public enum ImageFormat {
}
}
private void writeIEND(@NotNull Image image, @NotNull DataOutputStream data) throws IOException {
private void writeIEND(@NotNull Canvas image, @NotNull DataOutputStream data) throws IOException {
data.writeInt(0);
data.writeInt(IEND_TYPE);
data.writeInt(0);
@ -120,11 +120,11 @@ public enum ImageFormat {
},
;
public void write(@NotNull Image image, @NotNull Path path) throws IOException {
public void write(@NotNull Canvas image, @NotNull Path path) throws IOException {
try (var out = Files.newOutputStream(path)) {
write(image, out);
}
}
public abstract void write(@NotNull Image image, @NotNull OutputStream out) throws IOException;
public abstract void write(@NotNull Canvas image, @NotNull OutputStream out) throws IOException;
}