278 lines
No EOL
8.4 KiB
Rust
278 lines
No EOL
8.4 KiB
Rust
use cgmath::AbsDiffEq;
|
|
use cgmath::{InnerSpace, MetricSpace, Vector3};
|
|
|
|
use crate::vertex;
|
|
use super::memorizable::Memorizable;
|
|
use super::AppData;
|
|
use super::Scene;
|
|
|
|
pub enum LightType {
|
|
POINT,
|
|
DIRECTION
|
|
}
|
|
|
|
pub trait Light {
|
|
fn get_light_type(&self) -> LightType;
|
|
fn weighted_distance(&self, pos: Vector3<f32>, size: Vector3<f32>) -> f32;
|
|
fn get_direction(&self, pos: Vector3<f32>) -> Vector3<f32>;
|
|
}
|
|
|
|
pub trait LightSource: Light + Memorizable {}
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct PointLight{
|
|
pos: vertex::Vec3,
|
|
color: vertex::Vec3,
|
|
pub memory_start: usize,
|
|
dirty: bool,
|
|
}
|
|
|
|
impl PointLight {
|
|
pub fn init(pos: vertex::Vec3, color: vertex::Vec3) -> Self {
|
|
Self { pos: pos, color: color, memory_start: 0, dirty: true }
|
|
}
|
|
|
|
pub fn set_pos(&mut self, pos: vertex::Vec3) {
|
|
self.pos = pos;
|
|
self.dirty = true;
|
|
}
|
|
}
|
|
|
|
impl Memorizable for PointLight {
|
|
fn get_buffer_mem_size(&self, data: &AppData) -> u32 {
|
|
1 + 3 + 3
|
|
}
|
|
|
|
fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> {
|
|
v[self.memory_start] = LightType::POINT as u32;
|
|
|
|
v[self.memory_start + 1] = u32::from_ne_bytes(self.pos.x.to_ne_bytes());
|
|
v[self.memory_start + 2] = u32::from_ne_bytes(self.pos.y.to_ne_bytes());
|
|
v[self.memory_start + 3] = u32::from_ne_bytes(self.pos.z.to_ne_bytes());
|
|
|
|
v[self.memory_start + 4] = (self.color.x * 255.0) as u32;
|
|
v[self.memory_start + 5] = (self.color.y * 255.0) as u32;
|
|
v[self.memory_start + 6] = (self.color.z * 255.0) as u32;
|
|
|
|
self.dirty = false;
|
|
|
|
v
|
|
}
|
|
|
|
fn get_memory_start(&self) -> usize {
|
|
self.memory_start
|
|
}
|
|
|
|
fn set_memory_start(&mut self, memory_start: usize) {
|
|
self.memory_start = memory_start;
|
|
}
|
|
|
|
fn get_prev_buffer_mem_size(&self) -> u32 {
|
|
1 + 3 + 3
|
|
}
|
|
fn is_dirty(&self) -> bool {
|
|
self.dirty
|
|
}
|
|
}
|
|
|
|
impl Light for PointLight {
|
|
fn get_light_type(&self) -> LightType {
|
|
LightType::POINT
|
|
}
|
|
|
|
fn weighted_distance(&self, pos: Vector3<f32>, size: Vector3<f32>) -> f32 {
|
|
let low_end = vertex::Vec3{x: pos.x as f32, y: pos.y as f32, z: pos.z as f32};
|
|
let high_end = pos + size;
|
|
let distance;
|
|
if low_end.x <= self.pos.x && self.pos.x <= high_end.x && low_end.y <= self.pos.y && self.pos.y <= high_end.y && low_end.z <= self.pos.z && self.pos.z <= high_end.z {
|
|
let diff_low = self.pos - low_end;
|
|
let diff_high = self.pos - high_end;
|
|
distance = diff_low.x.abs().min(diff_low.y.abs().min(diff_low.z.abs().min(diff_high.x.abs().min(diff_high.y.abs().min(diff_high.z.abs())))));
|
|
} else {
|
|
let mut offset_vec = vertex::Vec3 {x: 0.0, y: 0.0, z: 0.0};
|
|
|
|
while !(low_end.x <= self.pos.x + offset_vec.x && self.pos.x + offset_vec.x <= high_end.x && low_end.y <= self.pos.y + offset_vec.y && self.pos.y + offset_vec.y <= high_end.y && low_end.z <= self.pos.z + offset_vec.z && self.pos.z + offset_vec.z <= high_end.z) {
|
|
let diff_low = (self.pos + offset_vec) - low_end;
|
|
let diff_high = (self.pos + offset_vec) - high_end;
|
|
|
|
let mut new_diff = vertex::Vec3 {x: 0.0, y: 0.0, z: 0.0};
|
|
if diff_low.x.abs() < diff_high.x.abs() {
|
|
new_diff.x += diff_low.x;
|
|
} else {
|
|
new_diff.x += diff_high.x;
|
|
}
|
|
|
|
if diff_low.y.abs() < diff_high.y.abs() {
|
|
new_diff.y += diff_low.y;
|
|
} else {
|
|
new_diff.y += diff_high.y;
|
|
}
|
|
|
|
if diff_low.z.abs() < diff_high.z.abs() {
|
|
new_diff.z += diff_low.z;
|
|
} else {
|
|
new_diff.z += diff_high.z;
|
|
}
|
|
|
|
if ((new_diff.x < new_diff.y || new_diff.y == 0.0) && (new_diff.x < new_diff.z || new_diff.z == 0.0) && new_diff.x != 0.0) {
|
|
offset_vec.x -= new_diff.x;
|
|
} else {
|
|
if (new_diff.y < new_diff.z || new_diff.z == 0.0) && new_diff.y != 0.0 {
|
|
offset_vec.y -= new_diff.y;
|
|
} else {
|
|
offset_vec.z -= new_diff.z;
|
|
}
|
|
}
|
|
}
|
|
|
|
distance = offset_vec.magnitude();
|
|
}
|
|
let light_intensity = self.color.magnitude();
|
|
|
|
light_intensity / distance.powf(2.0)
|
|
}
|
|
|
|
fn get_direction(&self, pos: Vector3<f32>) -> Vector3<f32> {
|
|
(pos - self.pos).normalize()
|
|
}
|
|
}
|
|
|
|
impl LightSource for PointLight {}
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
pub struct DirectionalLight{
|
|
direction: vertex::Vec3,
|
|
color: vertex::Vec3,
|
|
pub memory_start: usize,
|
|
dirty: bool,
|
|
}
|
|
|
|
impl DirectionalLight {
|
|
pub fn init(direction: vertex::Vec3, color: vertex::Vec3) -> Self {
|
|
Self { direction: direction, color: color, memory_start: 0, dirty: true }
|
|
}
|
|
}
|
|
|
|
impl Memorizable for DirectionalLight {
|
|
fn get_buffer_mem_size(&self, data: &AppData) -> u32 {
|
|
1 + 3 + 3
|
|
}
|
|
|
|
fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> {
|
|
v[self.memory_start] = LightType::DIRECTION as u32;
|
|
|
|
v[self.memory_start + 1] = u32::from_ne_bytes(self.direction.x.to_ne_bytes());
|
|
v[self.memory_start + 2] = u32::from_ne_bytes(self.direction.y.to_ne_bytes());
|
|
v[self.memory_start + 3] = u32::from_ne_bytes(self.direction.z.to_ne_bytes());
|
|
|
|
v[self.memory_start + 4] = (self.color.x * 255.0) as u32;
|
|
v[self.memory_start + 5] = (self.color.y * 255.0) as u32;
|
|
v[self.memory_start + 6] = (self.color.z * 255.0) as u32;
|
|
|
|
self.dirty = false;
|
|
|
|
|
|
v
|
|
}
|
|
|
|
fn get_memory_start(&self) -> usize {
|
|
self.memory_start
|
|
}
|
|
|
|
fn set_memory_start(&mut self, memory_start: usize) {
|
|
self.memory_start = memory_start;
|
|
}
|
|
|
|
fn get_prev_buffer_mem_size(&self) -> u32 {
|
|
1 + 3 + 3
|
|
}
|
|
fn is_dirty(&self) -> bool {
|
|
self.dirty
|
|
}
|
|
}
|
|
|
|
impl Light for DirectionalLight {
|
|
fn get_light_type(&self) -> LightType {
|
|
LightType::DIRECTION
|
|
}
|
|
|
|
fn weighted_distance(&self, pos: Vector3<f32>, size: Vector3<f32>) -> f32 {
|
|
let light_intensity = self.color.magnitude();
|
|
|
|
light_intensity
|
|
}
|
|
|
|
fn get_direction(&self, pos: Vector3<f32>) -> Vector3<f32> {
|
|
self.direction.clone().normalize()
|
|
}
|
|
}
|
|
|
|
impl LightSource for DirectionalLight {}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_memorizable() {
|
|
let mut p = PointLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0});
|
|
let data= AppData::default();
|
|
let scene = Scene::default();
|
|
|
|
let mem_size = p.get_buffer_mem_size(&data);
|
|
assert!(mem_size == 7);
|
|
|
|
let mut memory = vec![0; 7];
|
|
assert!(!p.dirty);
|
|
p.insert_into_memory(memory, &data, &scene);
|
|
assert!(p.dirty);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn test_mem_size() {
|
|
let mut p = PointLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0});
|
|
let data= AppData::default();
|
|
let scene = Scene::default();
|
|
|
|
let mem_size = p.get_buffer_mem_size(&data);
|
|
assert!(mem_size == 7);
|
|
|
|
let mut memory = vec![0; 6];
|
|
assert!(!p.dirty);
|
|
p.insert_into_memory(memory, &data, &scene);
|
|
assert!(p.dirty);
|
|
}
|
|
|
|
#[test]
|
|
fn test_memorizable_directional_light() {
|
|
let mut p = DirectionalLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0});
|
|
let data= AppData::default();
|
|
let scene = Scene::default();
|
|
|
|
let mem_size = p.get_buffer_mem_size(&data);
|
|
assert!(mem_size == 7);
|
|
|
|
let mut memory = vec![0; 7];
|
|
assert!(!p.dirty);
|
|
p.insert_into_memory(memory, &data, &scene);
|
|
assert!(p.dirty);
|
|
}
|
|
|
|
#[test]
|
|
#[should_panic]
|
|
fn test_mem_size_directional_light() {
|
|
let mut p = DirectionalLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0});
|
|
let data= AppData::default();
|
|
let scene = Scene::default();
|
|
|
|
let mem_size = p.get_buffer_mem_size(&data);
|
|
assert!(mem_size == 7);
|
|
|
|
let mut memory = vec![0; 6];
|
|
assert!(!p.dirty);
|
|
p.insert_into_memory(memory, &data, &scene);
|
|
assert!(p.dirty);
|
|
}
|
|
} |