abstract Image
This commit is contained in:
parent
1080711229
commit
87a7fbfcff
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
21
src/main/java/eu/jonahbauer/raytracing/render/Canvas.java
Normal file
21
src/main/java/eu/jonahbauer/raytracing/render/Canvas.java
Normal 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());
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user