|
|
|
@ -1,43 +1,18 @@
|
|
|
|
|
package eu.jonahbauer.raytracing.render.texture;
|
|
|
|
|
|
|
|
|
|
import eu.jonahbauer.raytracing.math.IVec3;
|
|
|
|
|
import eu.jonahbauer.raytracing.math.Ray;
|
|
|
|
|
import eu.jonahbauer.raytracing.math.Vec3;
|
|
|
|
|
import eu.jonahbauer.raytracing.scene.SkyBox;
|
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.Random;
|
|
|
|
|
|
|
|
|
|
import static eu.jonahbauer.raytracing.Main.DEBUG;
|
|
|
|
|
|
|
|
|
|
public record Color(double r, double g, double b) implements Texture, SkyBox {
|
|
|
|
|
public record Color(double r, double g, double b) implements Texture, SkyBox, IVec3<Color> {
|
|
|
|
|
public static final @NotNull Color BLACK = new Color(0.0, 0.0, 0.0);
|
|
|
|
|
public static final @NotNull Color WHITE = new Color(1.0, 1.0, 1.0);
|
|
|
|
|
public static final @NotNull Color RED = new Color(1.0, 0.0, 0.0);
|
|
|
|
|
public static final @NotNull Color GREEN = new Color(0.0, 1.0, 0.0);
|
|
|
|
|
public static final @NotNull Color BLUE = new Color(0.0, 0.0, 1.0);
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color lerp(@NotNull Color a, @NotNull Color b, double t) {
|
|
|
|
|
if (t < 0) return a;
|
|
|
|
|
if (t > 1) return b;
|
|
|
|
|
return new Color(
|
|
|
|
|
Math.fma(t, b.r, Math.fma(-t, a.r, a.r)),
|
|
|
|
|
Math.fma(t, b.g, Math.fma(-t, a.g, a.g)),
|
|
|
|
|
Math.fma(t, b.b, Math.fma(-t, a.b, a.b))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color multiply(@NotNull Color a, @NotNull Color b) {
|
|
|
|
|
return new Color(a.r() * b.r(), a.g() * b.g(), a.b() * b.b());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color multiply(@NotNull Color a, double b) {
|
|
|
|
|
return new Color(a.r() * b, a.g() * b, a.b() * b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color add(@NotNull Color a, @NotNull Color b) {
|
|
|
|
|
return new Color(a.r() + b.r(), a.g() + b.g(), a.b() + b.b());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color random(@NotNull Random random) {
|
|
|
|
|
return new Color(random.nextDouble(), random.nextDouble(), random.nextDouble());
|
|
|
|
@ -52,15 +27,6 @@ public record Color(double r, double g, double b) implements Texture, SkyBox {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color average(@NotNull Color current, @NotNull Color next, int index) {
|
|
|
|
|
var factor = 1d / index;
|
|
|
|
|
return new Color(
|
|
|
|
|
Math.fma(factor, next.r() - current.r(), current.r()),
|
|
|
|
|
Math.fma(factor, next.g() - current.g(), current.g()),
|
|
|
|
|
Math.fma(factor, next.b() - current.b(), current.b())
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color gamma(@NotNull Color color, double gamma) {
|
|
|
|
|
if (gamma == 1.0) {
|
|
|
|
|
return color;
|
|
|
|
@ -87,21 +53,75 @@ public record Color(double r, double g, double b) implements Texture, SkyBox {
|
|
|
|
|
this(red / 255f, green / 255f, blue / 255f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Color(@NotNull Vec3 vec) {
|
|
|
|
|
this(vec.x(), vec.y(), vec.z());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Color {
|
|
|
|
|
if (DEBUG) {
|
|
|
|
|
if (!Double.isFinite(r) || !Double.isFinite(g) || !Double.isFinite(b)) {
|
|
|
|
|
if (DEBUG && (!Double.isFinite(r) || !Double.isFinite(g) || !Double.isFinite(b))) {
|
|
|
|
|
throw new IllegalArgumentException("r, g and b must be finite");
|
|
|
|
|
}
|
|
|
|
|
if (r < 0 || g < 0 || b < 0) {
|
|
|
|
|
throw new IllegalArgumentException("r, g and b must be non-negative");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Math
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color average(@NotNull Color current, @NotNull Color next, int index) {
|
|
|
|
|
return lerp(current, next, 1d / index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color lerp(@NotNull Color a, @NotNull Color b, double t) {
|
|
|
|
|
if (t < 0) return a;
|
|
|
|
|
if (t > 1) return b;
|
|
|
|
|
return new Color(
|
|
|
|
|
Math.fma(t, b.r - a.r, a.r),
|
|
|
|
|
Math.fma(t, b.g - a.g, a.g),
|
|
|
|
|
Math.fma(t, b.b - a.b, a.b)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color fma(@NotNull Color a, @NotNull Color b, @NotNull Color c) {
|
|
|
|
|
return new Color(
|
|
|
|
|
Math.fma(a.r, b.r, c.r),
|
|
|
|
|
Math.fma(a.g, b.g, c.g),
|
|
|
|
|
Math.fma(a.b, b.b, c.b)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color plus(@NotNull Color other) {
|
|
|
|
|
return new Color(r + other.r, g + other.g, b + other.b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color minus(@NotNull Color other) {
|
|
|
|
|
return new Color(r - other.r, g - other.g, b - other.b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color times(double d) {
|
|
|
|
|
return new Color(r * d, g * d, b * d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color times(@NotNull Color other) {
|
|
|
|
|
return new Color(r * other.r, g * other.g, b * other.b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Vec3
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Vec3 toVec3() {
|
|
|
|
|
return new Vec3(r, g, b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static @NotNull Color fromVec3(@NotNull Vec3 vec) {
|
|
|
|
|
return new Color(vec.x(), vec.y(), vec.z());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Accessors
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
public int red() {
|
|
|
|
|
return toInt(r);
|
|
|
|
|
}
|
|
|
|
@ -114,22 +134,31 @@ public record Color(double r, double g, double b) implements Texture, SkyBox {
|
|
|
|
|
return toInt(b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public double component(int i) {
|
|
|
|
|
return switch (i) {
|
|
|
|
|
case 0 -> r;
|
|
|
|
|
case 1 -> g;
|
|
|
|
|
case 2 -> b;
|
|
|
|
|
default -> throw new IndexOutOfBoundsException(i);
|
|
|
|
|
};
|
|
|
|
|
private static int toInt(double value) {
|
|
|
|
|
return Math.clamp((int) (255.99 * value), 0, 255);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color get(double u, double v, @NotNull Vec3 p) {
|
|
|
|
|
return this;
|
|
|
|
|
public double component1() {
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color getColor(@NotNull Ray ray) {
|
|
|
|
|
public double component2() {
|
|
|
|
|
return g;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public double component3() {
|
|
|
|
|
return b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Texture
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color get(double u, double v, @NotNull Vec3 p) {
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -138,11 +167,12 @@ public record Color(double r, double g, double b) implements Texture, SkyBox {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public @NotNull Vec3 toVec3() {
|
|
|
|
|
return new Vec3(r, g, b);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* SkyBox
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
private static int toInt(double value) {
|
|
|
|
|
return Math.clamp((int) (255.99 * value), 0, 255);
|
|
|
|
|
@Override
|
|
|
|
|
public @NotNull Color getColor(@NotNull Ray ray) {
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|