ft (wip): deserialization

This commit is contained in:
2026-04-25 14:46:03 +02:00
parent ef8da70436
commit 430bdf63bc
15 changed files with 421 additions and 158 deletions

3
Cargo.lock generated
View File

@@ -1240,6 +1240,8 @@ dependencies = [
"ops",
"pretty_env_logger",
"rand 0.10.1",
"serde",
"serde_json",
]
[[package]]
@@ -1311,6 +1313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]

View File

@@ -11,3 +11,5 @@ log = "0.4.29"
ops = "0.6.0"
pretty_env_logger = "0.5.0"
rand = "0.10.1"
serde = {version = "1.0.228", features = ["derive"]}
serde_json = "1.0.149"

33
scenes/scene.json Normal file
View File

@@ -0,0 +1,33 @@
{
"camera": {
"image_width": 1920,
"image_height": 1080,
"anti_alias_rate": 3,
"max_depth": 50,
"fov": 90.0,
"look_from": { "x": 0, "y": 0, "z": 0 },
"look_at": { "x": 0.0, "y": 0.0, "z": -1.0 },
"vup": { "x": 0.0, "y": 1.0, "z": 0.0 }
},
"materials": [
{ "type": "metal", "albedo": { "x": 0.2, "y": 0.4, "z": 0.8 }, "prob": 1.0, "fuzz": 0.1 },
{ "type": "metal", "albedo": { "x": 0.7, "y": 0.4, "z": 0.2 }, "prob": 1.0, "fuzz": 0.1 },
{ "type": "lambertian", "albedo": { "x": 0.8, "y": 0.8, "z": 0.0 }, "prob": 1.0 },
{ "type": "lambertian", "albedo": { "x": 0.1, "y": 0.2, "z": 0.5 }, "prob": 1.0 },
{ "type": "dielectric", "refraction_index": 1.5},
{ "type": "dielectric", "refraction_index": 0.67},
{ "type": "metal", "albedo": { "x": 0.8, "y": 0.6, "z": 0.2 }, "prob": 1.0, "fuzz": 1.0 }
],
"objects": [
{ "type": "sphere", "center": { "x": 0, "y": 0.7, "z": -0.4 }, "radius": 0.2, "material": 0},
{ "type": "sphere", "center": { "x": 0.0, "y": 0.5, "z": -0.8 }, "radius": 0.1, "material": 1},
{ "type": "sphere", "center": { "x": 0.0, "y": -100.5, "z": -1.0 }, "radius": 100.0, "material": 2},
{ "type": "sphere", "center": { "x": 0.0, "y": 0.0, "z": -1.2 }, "radius": 0.5, "material": 3},
{ "type": "sphere", "center": { "x": -1, "y": 0, "z": -1 }, "radius": 0.4, "material": 5},
{ "type": "sphere", "center": { "x": 1, "y": 0, "z": -1 }, "radius": 0.5, "material": 6}
]
}

View File

@@ -1,6 +1,7 @@
use std::f32::consts::PI;
use std::{f32::consts::PI, sync::Arc};
use log::info;
use serde::Deserialize;
use crate::{
objects::{hit::Hit, traits::Hittable},
@@ -42,21 +43,50 @@ fn deg_to_rad(deg: f32) -> f32 {
impl Camera {
pub fn new(image_width: u32, image_height: u32) -> Self {
Self {
image_width: image_width,
image_height: image_height,
image_width,
image_height,
anti_alias_rate: 1,
max_depth: 10,
dirty: true,
fov: 60.,
pixel00_loc: Vec3::nil(),
pixel_delta_u: Vec3::nil(),
pixel_delta_v: Vec3::nil(),
pixel00_loc: Vec3::default(),
pixel_delta_u: Vec3::default(),
pixel_delta_v: Vec3::default(),
look_from: Vec3::nil(),
look_at: Vec3::new(0., 0., -1.),
vup: Vec3::new(0., 1., 0.),
u: Vec3::nil(),
v: Vec3::nil(),
w: Vec3::nil(),
u: Vec3::default(),
v: Vec3::default(),
w: Vec3::default(),
}
}
pub fn new_full(
image_width: u32,
image_height: u32,
anti_alias_rate: u32,
max_depth: u32,
fov: f32,
look_from: Vec3,
look_at: Vec3,
vup: Vec3,
) -> Self {
Self {
image_width,
image_height,
anti_alias_rate,
max_depth,
pixel00_loc: Vec3::default(),
pixel_delta_u: Vec3::default(),
pixel_delta_v: Vec3::default(),
dirty: true,
fov,
look_from,
look_at,
vup,
u: Vec3::default(),
v: Vec3::default(),
w: Vec3::default(),
}
}
@@ -125,7 +155,7 @@ impl Camera {
}
}
pub fn render<T: Hittable>(&mut self, hittables: &Vec<T>) {
pub fn render(&mut self, hittables: &Vec<Arc<dyn Hittable>>) {
if self.dirty {
self.init()
}
@@ -139,7 +169,7 @@ impl Camera {
let pixel_tl =
self.pixel00_loc + (i * self.pixel_delta_u) + (j * self.pixel_delta_v);
let mut pixel_colour = Colour::nil();
let mut pixel_colour = Colour::default();
for y in 1..(self.anti_alias_rate + 1) {
for x in 1..(self.anti_alias_rate + 1) {
let pixel_loc = pixel_tl
@@ -161,9 +191,9 @@ impl Camera {
imgbuf.save("output.png").unwrap();
}
fn ray_colour<T: Hittable>(&self, hittables: &Vec<T>, r: &Ray, depth: u32) -> Colour {
fn ray_colour(&self, hittables: &Vec<Arc<dyn Hittable>>, r: &Ray, depth: u32) -> Colour {
if depth <= 0 {
return Colour::nil();
return Colour::default();
}
let closest = Hit::hit_list(hittables, r);
@@ -171,7 +201,7 @@ impl Camera {
if let Some((scattered, att)) = hit.mat().scatter(&hit, r) {
return att * self.ray_colour(hittables, &scattered, depth - 1);
}
return Colour::nil();
return Colour::default();
}
// background

View File

@@ -3,17 +3,19 @@
mod camera;
mod objects;
mod ray;
mod scenes;
mod vec3;
use std::fs;
use std::sync::Arc;
use crate::camera::Camera;
use crate::objects::materials::dielectric::Dielectric;
use crate::objects::materials::lambertian::{Lambertian, Metal};
use crate::objects::materials::traits::Material;
use crate::objects::sphere::Sphere;
use crate::objects::traits::Hittable;
use crate::ray::Ray;
use crate::scenes::scene::Scene;
use crate::vec3::Vec3;
use dotenv::dotenv;
use log::info;
@@ -41,7 +43,7 @@ fn random_sphere_on_floor<T: Hittable>(
let r = rng.random_range(0.1..max_size);
let mut sphere = Sphere::xyz(
rng.random_range((-50.)..50.),
r,
rng.random_range(0.1..max_size),
rng.random_range((-50.)..50.),
r,
materials.choose(&mut rng).unwrap().clone(),
@@ -70,49 +72,40 @@ fn random_sphere_on_floor<T: Hittable>(
sphere
}
// FIXME: bunch of unwraps/expects in deserialization code
// TODO: implement scene serialization
fn main() {
dotenv().ok();
pretty_env_logger::init();
// setup objects
// let blue = Arc::new(Metal::rgb(0.2, 0.4, 0.8, 1., 0.1));
// let metal = Arc::new(Metal::rgb(0.7, 0.4, 0.2, 1., 0.1));
// let ground = Arc::new(Lambertian::rgb(0.8, 0.8, 0., 1.0));
// let center = Arc::new(Lambertian::rgb(0.1, 0.2, 0.5, 1.));
// let left = Arc::new(Dielectric::new(1.5));
// let bubble = Arc::new(Dielectric::new(1. / 1.5));
// let right = Arc::new(Metal::rgb(0.8, 0.6, 0.2, 1., 1.0));
// TODO: use cli arg for scenefile
let json_str = fs::read_to_string("./scenes/scene.json").expect("waddehell!");
let mut scene: Scene = serde_json::from_str(&json_str).unwrap();
scene.render();
// random spheres code; thought: make this available as cli flag?
// let mut materials: Vec<Arc<dyn Material>> = vec![Arc::new(Lambertian::rgb(0.1, 0.1, 0.2, 0.8))];
// for i in 0..15 {
// info!("Generating {}th material.", i + 1);
// materials.push(random_material());
// }
//
// let mut world = vec![Sphere::xyz(0., 0.5, -0.8, 0.1, metal.clone())];
// world.push(Sphere::xyz(0., -100.5, -1., 100., ground.clone()));
// world.push(Sphere::xyz(0., 0., -1.2, 0.5, center.clone()));
// world.push(Sphere::xyz(-1., 0., -1.0, 0.5, left.clone()));
// world.push(Sphere::xyz(-1., 0., -1.0, 0.4, bubble.clone()));
// world.push(Sphere::xyz(1., 0., -1.0, 0.5, right.clone()));
// world.push(Sphere::xyz(0., 0.7, -0.4, 0.2, blue.clone()));
let mut materials: Vec<Arc<dyn Material>> = vec![Arc::new(Lambertian::rgb(0.1, 0.2, 0.6, 1.))];
for i in 0..15 {
info!("Generating {}th material.", i + 1);
materials.push(random_material());
}
let mut world = vec![Sphere::xyz(0., -1000.5, -1., 1000., materials[0].clone())];
for i in 0..40 {
info!("Generating {}th sphere.", i + 1);
world.push(random_sphere_on_floor(
&materials,
&world,
(i + 1) as f32 / 3.,
));
}
// let mut c = Camera::new(400, 300);
let mut c = Camera::new(1920, 1080);
c.set_fov(90.);
c.set_anti_alias_rate(6);
c.set_max_depth(100);
c.set_look_from(Vec3::new(-60., 10., 1.));
c.set_look_at(Vec3::new(0., 0., 0.));
c.render(&world);
// let mut world = vec![Sphere::xyz(0., -1000.5, -1., 1000., materials[0].clone())];
// for i in 0..40 {
// info!("Generating {}th sphere.", i + 1);
// world.push(random_sphere_on_floor(
// &materials,
// &world,
// ((i + 1) as f32).ln() + (15. as f32).log(10.),
// ));
// }
//
// // let mut c = Camera::new(400, 300);
// let mut c = Camera::new(1920, 1080);
// c.set_fov(60.);
// c.set_anti_alias_rate(1);
// c.set_max_depth(10);
// c.set_look_from(Vec3::new(-60., 10., 1.));
// c.set_look_at(Vec3::new(0., 0., 0.));
// c.render(&world);
}

View File

@@ -45,7 +45,7 @@ impl Hit {
self.front_face
}
pub fn hit_list<T: Hittable>(hittables: &Vec<T>, r: &Ray) -> Option<Hit> {
pub fn hit_list(hittables: &Vec<Arc<dyn Hittable>>, r: &Ray) -> Option<Hit> {
let mut closest: Option<Hit> = None;
for hittable in hittables {
if let Some(hit) = hittable.hit(r) {

View File

@@ -1,6 +1,7 @@
use core::f32::math::sqrt;
use rand::RngExt;
use serde::Deserialize;
use crate::{
objects::{hit::Hit, materials::traits::Material},
@@ -8,6 +9,7 @@ use crate::{
vec3::{Colour, Vec3},
};
#[derive(Debug, Deserialize)]
pub struct Dielectric {
refraction_index: f32,
}

View File

@@ -1,4 +1,5 @@
use rand::RngExt;
use serde::Deserialize;
use crate::{
objects::{hit::Hit, materials::traits::Material},
@@ -6,6 +7,7 @@ use crate::{
vec3::{Colour, Vec3},
};
#[derive(Debug, Deserialize)]
pub struct Lambertian {
albedo: Colour,
prob: f32,
@@ -42,6 +44,7 @@ impl Material for Lambertian {
}
}
#[derive(Debug, Deserialize)]
pub struct Metal {
albedo: Colour,
prob: f32,

View File

@@ -1,5 +1,6 @@
use crate::{objects::hit::Hit, ray::Ray, vec3::Colour};
use std::fmt::Debug;
pub trait Material {
pub trait Material: Debug {
fn scatter(&self, hit: &Hit, ray: &Ray) -> Option<(Ray, Colour)>;
}

View File

@@ -1,6 +1,9 @@
use core::f32::math::sqrt;
use std::fmt::{self, Debug};
use std::sync::Arc;
use serde::Deserialize;
use crate::objects::hit::Hit;
use crate::objects::materials::traits::Material;
use crate::objects::traits::Hittable;
@@ -13,6 +16,16 @@ pub struct Sphere {
material: Arc<dyn Material>,
}
impl Debug for Sphere {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sphere")
.field("center", &self.center)
.field("radius", &self.radius)
.field("material", &self.material)
.finish()
}
}
impl Sphere {
pub fn new(center: Vec3, r: f32, mat: Arc<dyn Material>) -> Self {
Self {

View File

@@ -1,8 +1,10 @@
use std::fmt::Debug;
use crate::objects::hit::Hit;
use crate::Ray;
use crate::Vec3;
pub trait Hittable {
pub trait Hittable: Debug {
fn hit(&self, r: &Ray) -> Option<Hit>;
fn normal_at(&self, p: &Vec3) -> Vec3;
// fn intersect<H: Hittable>(&self, o: &H) -> bool;

2
src/scenes.rs Normal file
View File

@@ -0,0 +1,2 @@
pub mod raw_camera;
pub mod scene;

61
src/scenes/raw_camera.rs Normal file
View File

@@ -0,0 +1,61 @@
use serde::Deserialize;
use crate::{camera::Camera, vec3::Vec3};
#[derive(Deserialize)]
pub struct RawCamera {
// output
image_width: u32, // TODO: test these are now explicitly required (and that default impl does
// not make these optional)
image_height: u32,
// raytracing
#[serde(default)]
anti_alias_rate: u32,
#[serde(default)]
max_depth: u32,
// camera
#[serde(default)]
fov: f32,
#[serde(default)]
look_from: Vec3,
#[serde(default)]
look_at: Vec3,
#[serde(default)]
vup: Vec3,
}
impl Default for RawCamera {
fn default() -> Self {
Self {
image_width: 400,
image_height: 300,
anti_alias_rate: 1,
max_depth: 10,
fov: 70.,
look_from: Vec3::new(0., 0., 0.),
look_at: Vec3::new(0., 0., -1.),
vup: Vec3::new(0., 1., 0.),
}
}
}
impl TryFrom<RawCamera> for Camera {
type Error = String;
fn try_from(raw: RawCamera) -> Result<Self, Self::Error> {
let c = Camera::new_full(
raw.image_width,
raw.image_height,
raw.anti_alias_rate,
raw.max_depth,
raw.fov,
raw.look_from,
raw.look_at,
raw.vup,
);
Ok(c)
}
}

107
src/scenes/scene.rs Normal file
View File

@@ -0,0 +1,107 @@
use std::{
fmt::{self, Debug},
sync::Arc,
};
use serde::Deserialize;
use crate::{
camera::Camera,
objects::{
materials::{
dielectric::Dielectric,
lambertian::{Lambertian, Metal},
traits::Material,
},
sphere::Sphere,
traits::Hittable,
},
scenes::raw_camera::RawCamera,
vec3::Vec3,
};
pub struct Scene {
pub camera: Camera,
pub materials: Vec<Arc<dyn Material>>,
pub objects: Vec<Arc<dyn Hittable>>,
}
impl Scene {
pub fn render(&mut self) {
self.camera.render(&self.objects);
}
}
#[derive(Deserialize)]
struct SceneDef {
pub camera: RawCamera,
pub materials: Vec<MaterialDef>,
pub objects: Vec<HittableDef>,
}
impl<'de> Deserialize<'de> for Scene {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let conc = SceneDef::deserialize(deserializer)?;
let mats: Vec<Arc<dyn Material>> = conc
.materials
.into_iter()
.map(MaterialDef::into_arc)
.collect();
let objs: Vec<Arc<dyn Hittable>> = conc
.objects
.into_iter()
.map(|h| h.into_arc(&mats))
.collect();
Ok(Self {
camera: Camera::try_from(conc.camera).unwrap(),
materials: mats,
objects: objs,
})
}
}
#[derive(Deserialize)]
struct RawSphere {
pub center: Vec3,
pub radius: f32,
pub material: u32,
}
#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum HittableDef {
Sphere(RawSphere),
}
impl HittableDef {
fn into_arc(self, materials: &Vec<Arc<dyn Material>>) -> Arc<dyn Hittable> {
match self {
HittableDef::Sphere(s) => Arc::new(Sphere::new(
s.center,
s.radius,
materials.get(s.material as usize).unwrap().clone(),
)),
}
}
}
#[derive(Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
enum MaterialDef {
Lambertian(Lambertian),
Metal(Metal),
Dielectric(Dielectric),
}
impl MaterialDef {
fn into_arc(self) -> Arc<dyn Material> {
match self {
MaterialDef::Lambertian(l) => Arc::new(l),
MaterialDef::Metal(m) => Arc::new(m),
MaterialDef::Dielectric(d) => Arc::new(d),
}
}
}

View File

@@ -1,39 +1,40 @@
use core::f32::math::sqrt;
use is_close::default;
use rand::RngExt;
use serde::Deserialize;
use std::{
fmt::Display,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Deserialize)]
pub struct Vec3 {
r: f32,
g: f32,
b: f32,
x: f32,
y: f32,
z: f32,
}
pub type Colour = Vec3;
impl Vec3 {
pub fn new(r: f32, g: f32, b: f32) -> Self {
Self { r: r, g: g, b: b }
Self { x: r, y: g, z: b }
}
pub fn nil() -> Self {
Self {
r: 0.,
g: 0.,
b: 0.,
x: 0.,
y: 0.,
z: 0.,
}
}
pub fn random() -> Self {
let mut rng = rand::rng();
Self {
r: rng.random_range(-1.0..1.),
g: rng.random_range(-1.0..1.),
b: rng.random_range(-1.0..1.),
x: rng.random_range(-1.0..1.),
y: rng.random_range(-1.0..1.),
z: rng.random_range(-1.0..1.),
}
}
@@ -56,15 +57,15 @@ impl Vec3 {
}
pub fn x(&self) -> &f32 {
&self.r
&self.x
}
pub fn y(&self) -> &f32 {
&self.g
&self.y
}
pub fn z(&self) -> &f32 {
&self.b
&self.z
}
pub fn length(&self) -> f32 {
@@ -72,18 +73,18 @@ impl Vec3 {
}
pub fn length_squared(&self) -> f32 {
(self.r * self.r + self.g * self.g + self.b * self.b) as f32
(self.x * self.x + self.y * self.y + self.z * self.z) as f32
}
pub fn dot(&self, other: &Self) -> f32 {
self.r * other.r + self.g * other.g + self.b * other.b
self.x * other.x + self.y * other.y + self.z * other.z
}
pub fn cross(&self, other: &Self) -> Self {
Self {
r: self.g * other.b - self.b * other.g,
g: self.b * other.r - self.r * other.b,
b: self.r * other.g - self.g * other.r,
x: self.y * other.z - self.z * other.y,
y: self.z * other.x - self.x * other.z,
z: self.x * other.y - self.y * other.x,
}
}
@@ -96,9 +97,9 @@ impl Vec3 {
}
pub fn near_zero(&self) -> bool {
default().is_close(self.r, 0.)
&& default().is_close(self.g, 0.)
&& default().is_close(self.b, 0.)
default().is_close(self.x, 0.)
&& default().is_close(self.y, 0.)
&& default().is_close(self.z, 0.)
}
pub fn reflect(&self, n: &Self) -> Self {
@@ -117,18 +118,18 @@ impl Vec3 {
pub fn output(self) -> image::Rgb<u8> {
// gamma correction
let r = if self.r > 0. {
sqrt(self.r).clamp(0., 1.)
let r = if self.x > 0. {
sqrt(self.x).clamp(0., 1.)
} else {
0.
};
let g = if self.g > 0. {
sqrt(self.g).clamp(0., 1.)
let g = if self.y > 0. {
sqrt(self.y).clamp(0., 1.)
} else {
0.
};
let b = if self.b > 0. {
sqrt(self.b).clamp(0.1, 1.)
let b = if self.z > 0. {
sqrt(self.z).clamp(0.1, 1.)
} else {
0.
};
@@ -142,9 +143,19 @@ impl Vec3 {
pub fn clone(&self) -> Self {
Self {
r: self.r,
g: self.g,
b: self.b,
x: self.x,
y: self.y,
z: self.z,
}
}
}
impl Default for Vec3 {
fn default() -> Self {
Self {
x: 0.,
y: 0.,
z: 0.,
}
}
}
@@ -162,9 +173,9 @@ impl Neg for Vec3 {
fn neg(self) -> Self::Output {
Self {
r: -self.r,
g: -self.g,
b: -self.b,
x: -self.x,
y: -self.y,
z: -self.z,
}
}
}
@@ -174,9 +185,9 @@ impl Add<Vec3> for Vec3 {
fn add(self, _rhs: Self) -> Self {
Self {
r: self.r + _rhs.r,
g: self.g + _rhs.g,
b: self.b + _rhs.b,
x: self.x + _rhs.x,
y: self.y + _rhs.y,
z: self.z + _rhs.z,
}
}
}
@@ -186,9 +197,9 @@ impl Add<f32> for Vec3 {
fn add(self, f: f32) -> Self {
Self {
r: self.r + f,
g: self.g + f,
b: self.b + f,
x: self.x + f,
y: self.y + f,
z: self.z + f,
}
}
}
@@ -196,9 +207,9 @@ impl Add<f32> for Vec3 {
impl AddAssign<Vec3> for Vec3 {
fn add_assign(&mut self, other: Self) {
*self = Self {
r: self.r + other.r,
g: self.g + other.g,
b: self.b + other.b,
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
};
}
}
@@ -206,9 +217,9 @@ impl AddAssign<Vec3> for Vec3 {
impl AddAssign<f32> for Vec3 {
fn add_assign(&mut self, f: f32) {
*self = Self {
r: self.r + f,
g: self.g + f,
b: self.b + f,
x: self.x + f,
y: self.y + f,
z: self.z + f,
};
}
}
@@ -217,9 +228,9 @@ impl Sub<&Vec3> for Vec3 {
fn sub(self, rhs: &Self) -> Self {
Self {
r: self.r - rhs.r,
g: self.g - rhs.g,
b: self.b - rhs.b,
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
@@ -229,9 +240,9 @@ impl Sub<Vec3> for Vec3 {
fn sub(self, rhs: Self) -> Self {
Self {
r: self.r - rhs.r,
g: self.g - rhs.g,
b: self.b - rhs.b,
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
}
}
}
@@ -241,9 +252,9 @@ impl Sub<f32> for Vec3 {
fn sub(self, f: f32) -> Self {
Self {
r: self.r - f,
g: self.g - f,
b: self.b - f,
x: self.x - f,
y: self.y - f,
z: self.z - f,
}
}
}
@@ -251,9 +262,9 @@ impl Sub<f32> for Vec3 {
impl SubAssign<Vec3> for Vec3 {
fn sub_assign(&mut self, rhs: Self) {
*self = Self {
r: self.r - rhs.r,
g: self.g - rhs.g,
b: self.b - rhs.b,
x: self.x - rhs.x,
y: self.y - rhs.y,
z: self.z - rhs.z,
};
}
}
@@ -261,9 +272,9 @@ impl SubAssign<Vec3> for Vec3 {
impl SubAssign<f32> for Vec3 {
fn sub_assign(&mut self, f: f32) {
*self = Self {
r: self.r - f,
g: self.g - f,
b: self.b - f,
x: self.x - f,
y: self.y - f,
z: self.z - f,
};
}
}
@@ -273,9 +284,9 @@ impl Mul<Vec3> for Vec3 {
fn mul(self, rhs: Self) -> Self::Output {
Self {
r: self.r * rhs.r,
g: self.g * rhs.g,
b: self.b * rhs.b,
x: self.x * rhs.x,
y: self.y * rhs.y,
z: self.z * rhs.z,
}
}
}
@@ -286,9 +297,9 @@ impl Mul<Vec3> for u32 {
fn mul(self, rhs: Vec3) -> Self::Output {
let f = self as f32;
Vec3 {
r: rhs.r * f,
g: rhs.g * f,
b: rhs.b * f,
x: rhs.x * f,
y: rhs.y * f,
z: rhs.z * f,
}
}
}
@@ -298,9 +309,9 @@ impl Mul<f32> for Vec3 {
fn mul(self, f: f32) -> Self::Output {
Self {
r: self.r * f,
g: self.g * f,
b: self.b * f,
x: self.x * f,
y: self.y * f,
z: self.z * f,
}
}
}
@@ -310,9 +321,9 @@ impl Mul<Vec3> for f32 {
fn mul(self, rhs: Vec3) -> Self::Output {
Vec3 {
r: rhs.r * self,
g: rhs.g * self,
b: rhs.b * self,
x: rhs.x * self,
y: rhs.y * self,
z: rhs.z * self,
}
}
}
@@ -322,9 +333,9 @@ impl Mul<&Vec3> for f32 {
fn mul(self, rhs: &Vec3) -> Self::Output {
Vec3 {
r: rhs.r * self,
g: rhs.g * self,
b: rhs.b * self,
x: rhs.x * self,
y: rhs.y * self,
z: rhs.z * self,
}
}
}
@@ -332,9 +343,9 @@ impl Mul<&Vec3> for f32 {
impl MulAssign<Vec3> for Vec3 {
fn mul_assign(&mut self, rhs: Self) {
*self = Self {
r: self.r * rhs.r,
g: self.g * rhs.g,
b: self.b * rhs.b,
x: self.x * rhs.x,
y: self.y * rhs.y,
z: self.z * rhs.z,
};
}
}
@@ -342,9 +353,9 @@ impl MulAssign<Vec3> for Vec3 {
impl MulAssign<f32> for Vec3 {
fn mul_assign(&mut self, f: f32) {
*self = Self {
r: self.r * f,
g: self.g * f,
b: self.b * f,
x: self.x * f,
y: self.y * f,
z: self.z * f,
};
}
}
@@ -354,9 +365,9 @@ impl Div<Vec3> for Vec3 {
fn div(self, rhs: Self) -> Self::Output {
Self {
r: self.r / rhs.r,
g: self.g / rhs.g,
b: self.b / rhs.b,
x: self.x / rhs.x,
y: self.y / rhs.y,
z: self.z / rhs.z,
}
}
}
@@ -366,9 +377,9 @@ impl Div<i32> for Vec3 {
fn div(self, i: i32) -> Self::Output {
let f: f32 = i as f32;
Self {
r: self.r / f,
g: self.g / f,
b: self.b / f,
x: self.x / f,
y: self.y / f,
z: self.z / f,
}
}
}
@@ -378,9 +389,9 @@ impl Div<f32> for Vec3 {
fn div(self, f: f32) -> Self::Output {
Self {
r: self.r / f,
g: self.g / f,
b: self.b / f,
x: self.x / f,
y: self.y / f,
z: self.z / f,
}
}
}
@@ -388,9 +399,9 @@ impl Div<f32> for Vec3 {
impl DivAssign<Vec3> for Vec3 {
fn div_assign(&mut self, rhs: Self) {
*self = Self {
r: self.r / rhs.r,
g: self.g / rhs.g,
b: self.b / rhs.b,
x: self.x / rhs.x,
y: self.y / rhs.y,
z: self.z / rhs.z,
};
}
}
@@ -398,21 +409,21 @@ impl DivAssign<Vec3> for Vec3 {
impl DivAssign<f32> for Vec3 {
fn div_assign(&mut self, f: f32) {
*self = Self {
r: self.r / f,
g: self.g / f,
b: self.b / f,
x: self.x / f,
y: self.y / f,
z: self.z / f,
};
}
}
impl PartialEq for Vec3 {
fn eq(&self, other: &Self) -> bool {
self.r == other.r && self.g == other.g && self.b == other.b
self.x == other.x && self.y == other.y && self.z == other.z
}
}
impl Display for Vec3 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}, {}, {})", self.r, self.g, self.b)
write!(f, "({}, {}, {})", self.x, self.y, self.z)
}
}