use crate::collision_world::ChunkCollision;
use crate::{Assets, BBox, Batch2D, Batch3D, BillboardAnimation, CompiledLight, Texture};
use rusteria::{Program, RenderBuffer, Rusteria};
use scenevm::GeoId;
use std::sync::{Arc, Mutex};
use uuid::Uuid;
use vek::{Vec2, Vec3};
#[derive(Clone, Debug)]
pub struct BillboardMetadata {
pub geo_id: GeoId,
pub tile_id: Uuid,
pub center: Vec3<f32>,
pub up: Vec3<f32>,
pub right: Vec3<f32>,
pub size: f32,
pub animation: BillboardAnimation,
pub repeat_mode: scenevm::RepeatMode,
}
pub struct Chunk {
pub origin: Vec2<i32>,
pub size: i32,
pub bbox: BBox,
pub batches2d: Vec<Batch2D>,
pub batches3d_opacity: Vec<Batch3D>,
pub batches3d: Vec<Batch3D>,
pub lights: Vec<CompiledLight>,
pub occluded_sectors: Vec<(BBox, f32)>,
pub collision: ChunkCollision,
pub billboards: Vec<BillboardMetadata>,
pub shaders: Vec<Program>,
pub shader_textures: Vec<Option<Texture>>,
pub shaders_with_opacity: Vec<bool>,
}
impl Chunk {
pub fn new(origin: Vec2<i32>, size: i32) -> Self {
let bbox = BBox::from_pos_size(origin.map(|v| v as f32), Vec2::broadcast(size as f32));
Self {
origin,
size,
bbox,
batches2d: vec![],
batches3d_opacity: vec![],
batches3d: vec![],
lights: vec![],
occluded_sectors: vec![],
collision: ChunkCollision::new(),
billboards: vec![],
shaders: vec![],
shader_textures: vec![],
shaders_with_opacity: vec![],
}
}
pub fn add_shader(&mut self, code: &str, assets: &Assets) -> Option<usize> {
if code.is_empty() {
return None;
};
let mut rs: Rusteria = Rusteria::default();
let _module = match rs.parse_str(code) {
Ok(module) => match rs.compile(&module) {
Ok(()) => module,
Err(e) => {
eprintln!("Error compiling module: {e}");
return None;
}
},
Err(e) => {
eprintln!("Error parsing module: {e}");
return None;
}
};
let width = 64;
let height = 64;
let mut texture = None;
if let Some(shade_index) = rs.context.program.shade_index {
let mut rbuffer = Arc::new(Mutex::new(RenderBuffer::new(width, height)));
rs.shade(&mut rbuffer, shade_index, &assets.palette);
let b = rbuffer.lock().unwrap().as_rgba_bytes();
let mut tex = Texture::new(b, width, height);
tex.generate_normals(true);
texture = Some(tex);
}
let index = self.shaders.len();
self.shaders_with_opacity
.push(rs.context.program.shader_supports_opacity());
self.shaders.push(rs.context.program.clone());
self.shader_textures.push(texture);
Some(index)
}
pub fn get_occlusion(&self, at: Vec2<f32>) -> f32 {
for (bbox, occlusion) in &self.occluded_sectors {
if bbox.contains(at) {
return *occlusion;
}
}
1.0
}
}