From 62e4062cbf24615258fba630181c09385e1a29e9 Mon Sep 17 00:00:00 2001
From: zomseffen <steffen@tom.bi>
Date: Fri, 11 Apr 2025 11:35:57 +0200
Subject: [PATCH] add cuboid and handle empty compounds

---
 shaders/compiled/rt_compute.spv | Bin 33284 -> 37920 bytes
 shaders/rt_compute.comp         |  37 ++++++++
 src/buffer.rs                   |  12 +--
 src/scene/generators.rs         |   9 +-
 src/scene/volumetrics/mod.rs    | 157 ++++++++++++++++++++++++++++++--
 5 files changed, 200 insertions(+), 15 deletions(-)

diff --git a/shaders/compiled/rt_compute.spv b/shaders/compiled/rt_compute.spv
index 1cbfcfe558f3ecb8ab5d39926f5b0777a88cebbf..289f34304a9676a509af1ab4176ed618e2ec55c7 100644
GIT binary patch
delta 11782
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

delta 7152
zcmZ9Q37l3{8OAR&^D!igq&X@gsZ<&nrk05ah(%DgC?%SOG{T@mFyA;cpcZ*Cv4xb<
zp+(xXMG?aw+ALGbR(C{ADRBouL`B&~r2hYJ?mKgs%kOfY=Xsa&p7);b-0z#~mQ>B3
zUp1h*YG`ei^~(BY{j)u#6$6&kl&iD*YO<`HWmzffovj5=EzfE$H#Ic1O=)bJ)^Kq}
zU%!{$c1d$Xr~jtC^yYGFk>~Zj^p<j4MX$~JwXY~0l20u;%gl01MXkxE!<*|{>StAW
zDVqUrYpHK)MWhZYsL5K<TI#1Y&Snbv!Y+Png)i#j$H7b4V)(SimWHWqjpe3do@Etn
zdOjUq30i?Ly?$z&m6WpT>{fU<-vLf1+z9V3vL@TqgKzG^x9r7hv+eLRn;NH=TiPep
z?pG)EnpK|GFq5%2|F)OfFRiT`rl|^PPGiGGy7Z<twQ6v4OL<18R&l?*a5vfP)`ltP
zH<V{hX}zF+T0=`^K|3+bKCcX}%{of$duj*Ob?D1Ar#y4^tcKQ#+wRiJ;e7`6%C}+b
zjcp+J1ezR08Zx1%0+<c;Kdw|`W9=2!3!cWwjXQ-q;?$D3yfUFnPXpx!&f|_iwIr~s
zJ!zcnGHw-j#Hn@1b+(nQ+PR=!dAFm93?4{{<LP`nlks%LrXGRKEBN7^w8D2`w~Hor
z;^?^fyv(O&F~;wXd<Q3j2~D8G8>N-&_8DEu2f^<_v~35Xze-^L!tWsXYj8E=2J?SB
z&acz1Az7cwBJ@e`eeu=rF#LBg+F2JnvfwUO?a-`xOcpB}QmjC3;Om8xt1?jTsti1u
zUL3_zSwzRcAyv8U_sDV7*U@7q<sLV|-HRSGDff5@zJc8Rm@D{LY#uPd9X((Qo>zb;
zOgId{!P6z>o-Qf(bO~-ji+gZSmav=8gC)5B9xR=FLQSTFr%O0Edb$MH?&%WT1fDJ_
z-%?t6?g1Tx^Ii0K1s&K~jHBqNd+%<#unc`3`%iu^T+Qt>ny05t&G=i2_~ne+d^#r)
zqwRjMxgEEYdo|;O++NtnWNQis$C&&fut|bH3_d0)<`KBs%&dLL@x$`v)HoLNV@QTR
z%H6?S@&~w`(;CE)@;~4-<$vL76WMa%^LP)Rb#S$*)IOH3)ZzO?O_paPnEV7p9U}Ni
zFvctz_!QVl)Whd#u<Hz;XTbWY#{|!UBfs{DeGaT`be30F_P;_HH-P<2M3U#hkwjbg
zZ3Jucsri|ahwTNhIik4DV71ed)xQWI!Tgog>kz?Pz#8XfHI)<QC9qo9Uk0biUxBNg
zl_cK^kD|3l?5kjHkvo44q8JX_z-jXBaJBTg?SMye?Gd{ZtSyr70;`?Q^Y*Cg0J|9H
z)JEs>%JHHhlI#Yj1-t=Q^F1ApWDh(F&>pe>18a){e3hw%y%#*qT~*?(qc}TBUJZ}r
zRp1D&0c(roC9qo9dxO*DwQ#j-d1FN3ec+K>`>32}>=E%Mh{j014_GZ)*B9(+oK%~e
z&VyKeEC!FQ{$Mqa4~z2cGyqM#AG65!1^WimUt1o*10g+w-;Aan!TW&?Hj%a{Zh!Di
zY-E$`6FJ`k?wRudH1#59p4CAjsYW~E1P6k(MY4myJ(C@brXB?j0>|pKMS+KaEzq3$
zoI%H&W3bPEBL=S!55+;vM4=5SG~cPAy%o)sdxdsbp{22h7g`#71e!&$+V0??g_s7v
zt<VgP)w~^TFt>$TSm^HnTa-mOY3N6SozVQ|Q(w;lj{@f=Gf<~!^*h0~+S4jF(l9jj
zX!X0m(Q0iGdo;Lb?7Pv_BX&60SRO&1X^cvb0h`!orBft*54dO2W6{(j>2cs9X{Igq
z(eYqyk?XzS?p%52W_ur^hDde-I98`E3Vc7<gchhzJogj97Vj0>h(a?@XeSj~*Iw}X
zk3{TGyS>8k<U&h>M-^IEF#e;_EXpfl#}rx`drG0D`)Dj$Zsk^LWwFXr!4_o^P8#|L
zz)t7{CRBGLeGqIi<Mg>ED^>JyU^iLCj^?5BA-L`LWyRjgE1$#hh#I2(6Ts1aZSm|r
z3{HY8u^&NGkJ!_|#`^iz7R7%QY+mg?zRsNV|6>R}lYSgcJ(7L`97(ms<~kj$EebpX
z+`YLv_tr!-^~m)}a4c?O4v7jsCFa(_3gda63AcK$&?Xg{i9$Q8(9->JHkx_8!tc|C
zX6(2S&nd(-_%moXQ;1jieYViji6^&TKW_j0Tr8GqX_gYpngX^Ar*)RlKL>UOGfpma
zcT+vsT*m1WyXiczJ4(B+zkZBr#rrqUra{sda06Uz4YkG#_<VT0fVCIF*#%&2CZ5hH
zAHkOG!_phUeHqoYPi0h#*w2I4vXis;wl@<&@kD}R;#u&RSbGFFfwh@<2BSP|Ww75Y
zmr{t|(VO9FzTkJ@-vajX`+BoG=|XNrzp#rVQ5!hz%xt)tU)ZC-Iq)b@d&FJ@))wDP
zE(WVva4Vx+-`ol>f!x4obzcNWb?RT>R<k&<L4GTo3-&i=@GrsJ$#FTW)_y5mANBYQ
zxmb7LsfC@`&XZ&w2CKTQXxU|8oz<5xp+$ZftnN>&D9CXeKk~F+4z^%BsISGkS{J6x
zLiL*uR_n~m^S=T?(ba#I(aUF}{uORDS1)$*_-&;w_qUyPAEA@@#c%;Q-2>l%tNCtr
zo~yuK9Ue&<ujE!VkvI~46P)gWZ^6~lJ#aNV_JH<?y#}l;_CPyW&8{qDl;`36ZAd!N
zci?L0B%AHK@R&$@#C{K~Ehf4atmZ_E80GqUPJAESui$hl&wc<&C;lN^?PS^$yZlG+
zm{@yE{9~}TnD{!dTG+1#r@4OuS8MEA6wm*s2$5We2>uyZTO|KESS{=~fYanR!qqP9
zO3o&OM{eyAdlOjO+;}A|g($``do$S8IH|U)v(AszFTl1?yX{@fsAgh6cDI227zY0(
z+>dE|ESJOeQ8zwc22hNEUx7^;d?i?)MHJx6`PX25)WhdD;56p91&^5D!Szx9T9N1X
zU~=V|Mk`sts2EBA0Cr-z6aNvcPuOn*JL$rrGk*fB=@+ZL9c&(L&T%WFTI5{iF9|;i
zA^aKaBqnguzkrw0PW3Aa?N0D2Zfz0wSFk%h_}{?hiI~5G^-;g9$ny{Iot|<Ut?mv+
zMU!|^{SzF=@?Bsr4<_}0ajSV=h>h|2-wk$^apc|ujw4rF6nHP#`SLh&?}O;9A)M|9
zyNd960PI&B^&44*MXm-Lt1aRl1gCLp;A(a<;vRw%n`av1jDHxc!DBU6=NM=FBVbp5
zCAYq=+|Jo0Z5Cir{|0xT@%(uVuIACZmeI>jKI-#-3_;OWiqkV*Jw4;E>cKtxozye`
zact?Iw${Pb;_rvr)XW!uBV5fdnXamzz!=Z_DX^DSsz1rCW|88U^l9*LRvi2p_>l>J
z7Csq1pT}j9&%yOk_lr-ixE^96jge>rcmaX&?dW;9e(JV-Bcq!Beo|fl*W<5k6Iiaz
zP5C0&LrL3au)MJ4*-MZmg>eg5K7wy>oTAyw;5tSpGpWJ)*uv<BqkJJb?2cnB;uUP^
XBDTWS;*l(<ru|z>D<_?O*U0|^^$I$?

diff --git a/shaders/rt_compute.comp b/shaders/rt_compute.comp
index f1854b4..f0ec353 100644
--- a/shaders/rt_compute.comp
+++ b/shaders/rt_compute.comp
@@ -250,6 +250,25 @@ void main() {
                 continue;
             }
 
+            if (component_type == 2) {
+                // handle cone
+                vec3 size = vec3(uintBitsToFloat(compounds[component_index + 9]), uintBitsToFloat(compounds[component_index + 10]), uintBitsToFloat(compounds[component_index + 11]));
+                vec3 direction1 = component_rot_mat * vec3(size.x, 0.0, 0.0) / 2.0;
+                vec3 direction2 = component_rot_mat * vec3(0.0, size.y, 0.0) / 2.0;
+                vec3 direction3 = component_rot_mat * vec3(0.0, 0.0, size.z) / 2.0;
+
+                vec3 diff = check_pos - component_pos;
+                float factor1 = dot(direction1, diff) / dot(direction1, direction1);
+                float factor2 = dot(direction2, diff) / dot(direction2, direction2);
+                float factor3 = dot(direction3, diff) / dot(direction3, direction3);
+                render = (-1.0 <= factor1 && factor1 <= 1.0) && (-1.0 <= factor2 && factor2 <= 1.0) && (-1.0 <= factor3 && factor3 <= 1.0);
+                if (render) {
+                    color = vec3(float(component_color.x) / 255.0, float(component_color.y) / 255.0, float(component_color.z) / 255.0);
+                    break;
+                }
+                continue;
+            }
+
             
         }
         //handle excluded shapes
@@ -304,6 +323,24 @@ void main() {
                 }
                 continue;
             }
+
+            if (component_type == 2) {
+                // handle cone
+                vec3 size = vec3(uintBitsToFloat(compounds[component_index + 9]), uintBitsToFloat(compounds[component_index + 10]), uintBitsToFloat(compounds[component_index + 11]));
+                vec3 direction1 = component_rot_mat * vec3(size.x, 0.0, 0.0) / 2.0;
+                vec3 direction2 = component_rot_mat * vec3(0.0, size.y, 0.0) / 2.0;
+                vec3 direction3 = component_rot_mat * vec3(0.0, 0.0, size.z) / 2.0;
+
+                vec3 diff = check_pos - component_pos;
+                float factor1 = dot(direction1, diff) / dot(direction1, direction1);
+                float factor2 = dot(direction2, diff) / dot(direction2, direction2);
+                float factor3 = dot(direction3, diff) / dot(direction3, direction3);
+                render = render && !((-1.0 <= factor1 && factor1 <= 1.0) && (-1.0 <= factor2 && factor2 <= 1.0) && (-1.0 <= factor3 && factor3 <= 1.0));
+                if (!render) {
+                    break;
+                }
+                continue;
+            }
         }
 
         if (render) {
diff --git a/src/buffer.rs b/src/buffer.rs
index f8ee31d..61ce46d 100644
--- a/src/buffer.rs
+++ b/src/buffer.rs
@@ -313,7 +313,7 @@ pub unsafe fn create_storage_buffers(
             instance,
             device,
             data,
-            data.compute_task_one_out_buffer_size.max(1),
+            (size_of::<u32>() * 3) as u64 * data.compute_task_one_out_buffer_size.max(1),
             vk::BufferUsageFlags::STORAGE_BUFFER,
             vk::MemoryPropertyFlags::DEVICE_LOCAL,
         )?;
@@ -325,7 +325,7 @@ pub unsafe fn create_storage_buffers(
             instance,
             device,
             data,
-            (size_of::<vertex::SizedVertex>() * 8) as u64 * data.compute_task_one_out_size,
+            ((size_of::<vertex::SizedVertex>() * 8) as u64 * data.compute_task_one_out_size).max(1),
             vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::VERTEX_BUFFER,
             vk::MemoryPropertyFlags::DEVICE_LOCAL,
         )?;
@@ -337,7 +337,7 @@ pub unsafe fn create_storage_buffers(
             instance,
             device,
             data,
-            (size_of::<u32>() * 36) as u64 * data.compute_task_one_out_size,
+            ((size_of::<u32>() * 36) as u64 * data.compute_task_one_out_size).max(1),
             vk::BufferUsageFlags::STORAGE_BUFFER | vk::BufferUsageFlags::INDEX_BUFFER,
             vk::MemoryPropertyFlags::DEVICE_LOCAL,
         )?;
@@ -551,7 +551,7 @@ pub unsafe fn create_descriptor_sets(device: &Device, data: &mut app_data::AppDa
         let info = vk::DescriptorBufferInfo::builder()
             .buffer(data.compute_out_storage_buffers[i])
             .offset(0)
-            .range(data.compute_task_one_out_buffer_size);
+            .range((size_of::<u32>() * 3) as u64 * data.compute_task_one_out_buffer_size.max(1));
         let storage_info = &[info];
 
         let storage_write_compute_out = vk::WriteDescriptorSet::builder()
@@ -564,7 +564,7 @@ pub unsafe fn create_descriptor_sets(device: &Device, data: &mut app_data::AppDa
         let info = vk::DescriptorBufferInfo::builder()
             .buffer(data.compute_out_cuboid_buffers[i])
             .offset(0)
-            .range((size_of::<vertex::SizedVertex>() * 8) as u64 * data.compute_task_one_out_size);
+            .range(((size_of::<vertex::SizedVertex>() * 8) as u64 * data.compute_task_one_out_size).max(1));
         let storage_info = &[info];
 
         let storage_write_compute_cuboid_out = vk::WriteDescriptorSet::builder()
@@ -577,7 +577,7 @@ pub unsafe fn create_descriptor_sets(device: &Device, data: &mut app_data::AppDa
         let info = vk::DescriptorBufferInfo::builder()
             .buffer(data.compute_out_cuboid_index_buffers[i])
             .offset(0)
-            .range((size_of::<u32>() * 36) as u64 * data.compute_task_one_out_size);
+            .range(((size_of::<u32>() * 36) as u64 * data.compute_task_one_out_size).max(1));
         let storage_info = &[info];
 
         let storage_write_compute_cuboid_index_out = vk::WriteDescriptorSet::builder()
diff --git a/src/scene/generators.rs b/src/scene/generators.rs
index b86a385..3b7f372 100644
--- a/src/scene/generators.rs
+++ b/src/scene/generators.rs
@@ -4,7 +4,7 @@ use crate::primitives::cube::Cube;
 use crate::primitives::rec_cuboid::Cuboid;
 use crate::primitives::drawable::Drawable;
 use crate::app_data::AppData;
-use super::volumetrics::{Cone, ShapeComposition, Sphere};
+use super::volumetrics::{Cone, Rect, ShapeComposition, Sphere};
 
 extern crate rand;
 use rand::Rng;
@@ -118,7 +118,7 @@ pub fn generate_test_scene(scene: &mut Scene, data: &mut AppData) -> Result<(Poi
     let tree_ref_two = Rc::new(RefCell::new(oct_tree2.clone()));
     scene.oct_trees = vec![vec![vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_one.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()]], vec![vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_one.clone(), tree_ref_two.clone()], vec![tree_ref_two.clone(), tree_ref_two.clone(), tree_ref_two.clone()]]];
 
-    let mut comp = ShapeComposition::new(128);
+    let mut comp = ShapeComposition::new(64);
     comp.included_shapes.push(Rc::new(RefCell::new(Sphere::new(Vector3 { x: 5.0 + grid_size as f32, y: 5.0 + grid_size as f32, z: 10.0 }, Vector3 { x: 0.0, y: 0.0, z: 0.0 }, 2.0, Vector3 { x: 0, y: 255, z: 0 }, 64, false))));
     comp.included_shapes.push(Rc::new(RefCell::new(Sphere::new(Vector3 { x: 5.0 + grid_size as f32, y: 5.0 + grid_size as f32, z: 10.0 }, Vector3 { x: 0.0, y: 0.0, z: 0.0 }, 2.5, Vector3 { x: 255, y: 0, z: 0 }, 64, false))));
     comp.excluded_shapes.push(Rc::new(RefCell::new(Sphere::new(Vector3 { x: 5.0 + grid_size as f32, y: 5.0 + grid_size as f32, z: 11.5 }, Vector3 { x: 0.0, y: 0.0, z: 0.0 }, 1.5, Vector3 { x: 0, y: 255, z: 0 }, 64, false))));    
@@ -129,6 +129,11 @@ pub fn generate_test_scene(scene: &mut Scene, data: &mut AppData) -> Result<(Poi
     comp.excluded_shapes.push(Rc::new(RefCell::new(Cone::new(Vector3 { x: 20.0 + grid_size as f32, y: 5.0 + grid_size as f32, z: 10.0 }, Vector3 { x: 0.0, y: 0.0, z: 0.0 }, 0.0, 1.5, Vector3 { x: 0.0, y: 10.0, z: 0.0 },Vector3 { x: 0, y: 255, z: 0 }, 64, false))));
     scene.volumetrics.push(Rc::new(RefCell::new(comp)));
 
+    let mut comp = ShapeComposition::new(64);
+    comp.included_shapes.push(Rc::new(RefCell::new(Rect::new(Vector3 { x: -5.0 + grid_size as f32, y: 5.0 + grid_size as f32, z: 10.0 }, Vector3 { x: 0.0, y: 0.0, z: 0.0 }, Vector3 { x: 5.0, y: 10.0, z: 2.0 },Vector3 { x: 0, y: 0, z: 255 }, 64, false))));
+    comp.excluded_shapes.push(Rc::new(RefCell::new(Rect::new(Vector3 { x: -5.0 + grid_size as f32, y: 5.0 + grid_size as f32, z: 10.0 }, Vector3 { x: 0.0, y: 0.0, z: 0.0 }, Vector3 { x: 3.0, y: 8.0, z: 2.0 },Vector3 { x: 0, y: 0, z: 255 }, 64, false))));
+    scene.volumetrics.push(Rc::new(RefCell::new(comp)));
+
     Ok((cgmath::point3(5.0, 5.0, 10.0)))
 }
 
diff --git a/src/scene/volumetrics/mod.rs b/src/scene/volumetrics/mod.rs
index 7fbdf0b..8e7ade9 100644
--- a/src/scene/volumetrics/mod.rs
+++ b/src/scene/volumetrics/mod.rs
@@ -1,9 +1,10 @@
 use crate::app_data::AppData;
 
-use super::{memorizable::Memorizable, Scene, memorizable::CompoundMemorizable};
+use super::{Scene, memorizable::CompoundMemorizable};
 use cgmath::{InnerSpace, Vector3};
 use winit::dpi::Size;
 
+use super::memorizable::Memorizable;
 use std::cell::RefCell;
 use std::rc::Rc;
 
@@ -23,6 +24,7 @@ pub trait Volumetrics: Memorizable {
 enum ShapeTypes {
     SPHERE,
     CONE,
+    CUBOID,
 }
 
 
@@ -67,7 +69,15 @@ impl Memorizable for ShapeComposition {
     }
 
     fn is_dirty(&self) -> bool {
-        self.dirty
+        let mut dirty = self.dirty;
+        for volumetric in &self.included_shapes {
+            dirty = dirty || volumetric.borrow().is_dirty();
+        }
+
+        for volumetric in &self.excluded_shapes {
+            dirty = dirty || volumetric.borrow().is_dirty();
+        }
+        dirty
     }
 
     fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> {
@@ -185,6 +195,8 @@ impl Memorizable for Sphere {
 
         v[self.memory_start + 9] = u32::from_ne_bytes(self.radius.to_ne_bytes());
 
+        self.dirty = false;
+
         v
     }
 
@@ -202,6 +214,7 @@ impl Volumetrics for Sphere {
     }
 
     fn set_pos(&mut self, p: Vector3<f32>) {
+        self.dirty = true;
         self.pos = p;
     }
 
@@ -210,6 +223,7 @@ impl Volumetrics for Sphere {
     }
 
     fn set_rot(&mut self, p: Vector3<f32>) {
+        self.dirty = true;
         self.rot = p;
     }
 
@@ -290,6 +304,8 @@ impl Memorizable for Cone {
         v[self.memory_start + 12] = u32::from_ne_bytes(self.direction.y.to_ne_bytes());
         v[self.memory_start + 13] = u32::from_ne_bytes(self.direction.z.to_ne_bytes());
 
+        self.dirty = false;
+
         v
     }
 
@@ -307,6 +323,7 @@ impl Volumetrics for Cone {
     }
 
     fn set_pos(&mut self, p: Vector3<f32>) {
+        self.dirty = true;
         self.pos = p;
     }
 
@@ -315,11 +332,11 @@ impl Volumetrics for Cone {
     }
 
     fn set_rot(&mut self, p: Vector3<f32>) {
+        self.dirty = true;
         self.rot = p;
     }
 
     fn get_bbox(&self) -> (Vector3<f32>, Vector3<f32>) {
-        let max_rad = self.radius1.max(self.radius2);
         let rot = cgmath::Matrix3::from_angle_x(cgmath::Rad(self.rot.x)) * cgmath::Matrix3::from_angle_y(cgmath::Rad(self.rot.y)) * cgmath::Matrix3::from_angle_z(cgmath::Rad(self.rot.z));
         let dir = rot * self.direction;
         let vec_one;
@@ -331,11 +348,11 @@ impl Volumetrics for Cone {
         }
         vec_two = dir.cross(vec_one).normalize();
         
-        let pos_1_1 = self.pos + vec_one * max_rad + vec_two * max_rad;
-        let pos_1_2 = self.pos - vec_one * max_rad - vec_two * max_rad;
+        let pos_1_1 = self.pos + vec_one * self.radius1 + vec_two * self.radius1;
+        let pos_1_2 = self.pos - vec_one * self.radius1 - vec_two * self.radius1;
 
-        let pos_2_1 = self.pos + vec_one * max_rad + vec_two * max_rad + dir;
-        let pos_2_2 = self.pos - vec_one * max_rad - vec_two * max_rad + dir;
+        let pos_2_1 = self.pos + vec_one * self.radius2 + vec_two * self.radius2 + dir;
+        let pos_2_2 = self.pos - vec_one * self.radius2 - vec_two * self.radius2 + dir;
 
         let min = Vector3 {x: pos_1_1.x.min(pos_1_2.x.min(pos_2_1.x.min(pos_2_2.x))), y: pos_1_1.y.min(pos_1_2.y.min(pos_2_1.y.min(pos_2_2.y))), z: pos_1_1.z.min(pos_1_2.z.min(pos_2_1.z.min(pos_2_2.z)))};
         let max = Vector3 {x: pos_1_1.x.max(pos_1_2.x.max(pos_2_1.x.max(pos_2_2.x))), y: pos_1_1.y.max(pos_1_2.y.max(pos_2_1.y.max(pos_2_2.y))), z: pos_1_1.z.max(pos_1_2.z.max(pos_2_1.z.max(pos_2_2.z)))};
@@ -347,6 +364,132 @@ impl Volumetrics for Cone {
         self.transparent
     }
     
+    fn set_transparency(&mut self, transparent: bool) {
+        self.transparent = transparent;
+    }
+}
+
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct Rect {
+    pos: Vector3<f32>,
+    rot: Vector3<f32>,
+    color: Vector3<u8>, // color, either as pure color or texture modifier
+    transparent: bool,
+    size: Vector3<f32>,
+    roughness: u8,
+    memory_start: usize,
+    dirty: bool
+}
+
+impl Rect {
+    pub fn new(
+        pos: Vector3<f32>,
+        rot: Vector3<f32>, 
+        size: Vector3<f32>,
+        color: Vector3<u8>,
+        roughness: u8,
+        transparent: bool) -> Self {
+        Self { pos: pos, rot: rot, color: color, roughness: roughness, memory_start: 0, dirty: true, transparent: transparent, size }
+    }
+}
+
+impl Memorizable for Rect {
+    fn get_buffer_mem_size(&self, data: &AppData) -> u32 {
+        // type, pos, rot, (color + roughness), transparent, radius1, radius2, direction
+        1 + 3 + 3 + 1 + 1 + 3
+    }
+
+    fn get_prev_buffer_mem_size(&self) -> u32 {
+        // constant memory size
+        1 + 3 + 3 + 1 + 1 + 3
+    }
+    fn is_dirty(&self) -> bool {
+        self.dirty
+    }
+    fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> {
+        v[self.memory_start] = ShapeTypes::CUBOID 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] = u32::from_ne_bytes(self.rot.x.to_ne_bytes());
+        v[self.memory_start + 5] = u32::from_ne_bytes(self.rot.y.to_ne_bytes());
+        v[self.memory_start + 6] = u32::from_ne_bytes(self.rot.z.to_ne_bytes());
+
+        v[self.memory_start + 7] = u32::from_ne_bytes([self.color.x, self.color.y, self.color.z, self.roughness]);
+
+        v[self.memory_start + 8] = self.transparent as u32;
+
+        v[self.memory_start + 9] = u32::from_ne_bytes(self.size.x.to_ne_bytes());
+        v[self.memory_start + 10] = u32::from_ne_bytes(self.size.y.to_ne_bytes());
+        v[self.memory_start + 11] = u32::from_ne_bytes(self.size.z.to_ne_bytes());
+
+        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;
+    }
+}
+
+impl Volumetrics for Rect {
+    fn get_pos(&self) -> Vector3<f32> {
+        self.pos
+    }
+
+    fn set_pos(&mut self, p: Vector3<f32>) {
+        self.dirty = true;
+        self.pos = p;
+    }
+
+    fn get_rot(&self) -> Vector3<f32> {
+        self.rot
+    }
+
+    fn set_rot(&mut self, p: Vector3<f32>) {
+        self.dirty = true;
+        self.rot = p;
+    }
+
+    fn get_bbox(&self) -> (Vector3<f32>, Vector3<f32>) {
+        let rot = cgmath::Matrix3::from_angle_x(cgmath::Rad(self.rot.x)) * cgmath::Matrix3::from_angle_y(cgmath::Rad(self.rot.y)) * cgmath::Matrix3::from_angle_z(cgmath::Rad(self.rot.z));
+        let dir1 = rot * Vector3 { x: self.size.x / 2.0, y: 0.0, z: 0.0 };
+        let dir2 = rot * Vector3 { x: 0.0, y: self.size.y / 2.0, z: 0.0 };
+        let dir3 = rot * Vector3 { x: 0.0, y: 0.0, z: self.size.z / 2.0 };
+        
+        let pos1 = self.pos - dir1 - dir2 - dir3;
+        let pos2 = self.pos - dir1 - dir2 + dir3;
+        let pos3 = self.pos - dir1 + dir2 - dir3;
+        let pos4 = self.pos - dir1 + dir2 + dir3;
+        let pos5 = self.pos + dir1 - dir2 - dir3;
+        let pos6 = self.pos + dir1 - dir2 + dir3;
+        let pos7 = self.pos + dir1 + dir2 - dir3;
+        let pos8 = self.pos + dir1 + dir2 + dir3;
+
+        let min = Vector3 {
+            x: pos1.x.min(pos2.x.min(pos3.x.min(pos4.x.min(pos5.x.min(pos6.x.min(pos7.x.min(pos8.x))))))),
+            y: pos1.y.min(pos2.y.min(pos3.y.min(pos4.y.min(pos5.y.min(pos6.y.min(pos7.y.min(pos8.y))))))), 
+            z: pos1.z.min(pos2.z.min(pos3.z.min(pos4.z.min(pos5.z.min(pos6.z.min(pos7.z.min(pos8.z)))))))
+        };
+        let max = Vector3 {
+            x: pos1.x.max(pos2.x.max(pos3.x.max(pos4.x.max(pos5.x.max(pos6.x.max(pos7.x.max(pos8.x))))))),
+            y: pos1.y.max(pos2.y.max(pos3.y.max(pos4.y.max(pos5.y.max(pos6.y.max(pos7.y.max(pos8.y))))))), 
+            z: pos1.z.max(pos2.z.max(pos3.z.max(pos4.z.max(pos5.z.max(pos6.z.max(pos7.z.max(pos8.z)))))))
+        };
+
+        (min, max)
+    }
+    
+    fn is_transparent(&self) -> bool {
+        self.transparent
+    }
+    
     fn set_transparency(&mut self, transparent: bool) {
         self.transparent = transparent;
     }