use crate::core::shader::object::{Object, ObjectState};
use crate::core::*;
use crate::core::shader::object::{circle::Circle, rect::Rect, text::Text, texture::Texture};
use crate::core::color::Color;
use crate::core::resource::font::Font;
use crate::core::math::collision;
use crate::core::shader::object::TextureCoordinate;
enum InstancedComponentState {
NotLoaded,
Ok,
}
pub struct InstancedShader {
pub transform: Transform,
object_data: Vec<ObjectData>,
object: Box<dyn Object>,
state: InstancedComponentState,
}
impl InstancedShader {
pub fn rect() -> Result<Self, String> {
let rect = Rect::new();
let component = Self {
object: Box::new(rect),
object_data: vec![],
transform: Transform::default(),
state: InstancedComponentState::NotLoaded,
};
Ok(component)
}
pub fn circle() -> Result<Self, String> {
let circle = Circle::new();
let component = Self {
object: Box::new(circle),
object_data: vec![],
transform: Transform::default(),
state: InstancedComponentState::NotLoaded,
};
Ok(component)
}
pub fn texture(image: &Image) -> Result<Self, String> {
let texture = Texture::new(image);
let component = Self {
object: Box::new(texture),
object_data: vec![],
transform: Transform::default(),
state: InstancedComponentState::NotLoaded,
};
Ok(component)
}
pub fn text(text: &str, font: &Font, font_size: i32) -> Result<Self, String> {
let image = font.snapshot(text, font_size as f32)?;
let image = Image::from(image);
let text = Text::new(&image)?;
let component = Self {
object: Box::new(text),
object_data: vec![],
transform: Transform::default(),
state: InstancedComponentState::NotLoaded,
};
Ok(component)
}
pub fn add(&mut self, object_data: &ObjectData) {
self.object_data.push(object_data.clone());
self.object.add(object_data);
self.object.set_state(ObjectState::Reload);
}
pub fn remove(&mut self, i: usize) -> Result<(), String> {
self.index_oob(i)?;
self.object_data.remove(i);
self.object.remove(i);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn remove_all(&mut self) {
self.object_data = vec![];
self.object.remove_all();
self.object.set_state(ObjectState::Reload);
}
pub fn load(&mut self) -> Result<(), String> {
self.object.load()?;
self.state = InstancedComponentState::Ok;
Ok(())
}
pub fn draw(&mut self, draw: &Draw, camera: &Transform) -> Result<(), String> {
match self.state {
InstancedComponentState::NotLoaded => return Err("Cannot render without creating the model data. Please call load on the InstancedComponent.".to_string()),
_ => (),
}
self.object.draw(draw, camera, &self.transform)?;
Ok(())
}
pub fn set_dim(&mut self, i: usize, width: f32, height: f32) -> Result<(), String> {
self.index_oob(i)?;
self.object_data[i].dim.0 = width;
self.object_data[i].dim.1 = height;
self.object.set(i, &self.object_data[i]);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn dim(&self, i: usize) -> Result<(f32, f32), String> {
self.index_oob(i)?;
Ok(self.object_data[i].dim)
}
pub fn set_width(&mut self, i: usize, width: f32) -> Result<(), String> {
self.index_oob(i)?;
self.object_data[i].dim.0 = width;
self.object.set(i, &self.object_data[i]);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn width(&self, i: usize) -> Result<f32, String> {
self.index_oob(i)?;
Ok(self.object_data[i].dim.0)
}
pub fn set_height(&mut self, i: usize, height: f32) -> Result<(), String> {
self.index_oob(i)?;
self.object_data[i].dim.1 = height;
self.object.set(i, &self.object_data[i]);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn height(&self, i: usize) -> Result<f32, String> {
self.index_oob(i)?;
Ok(self.object_data[i].dim.1)
}
pub fn set_color(&mut self, i: usize, color: &Color) -> Result<(), String> {
self.index_oob(i)?;
self.object_data[i].color = color.clone();
self.object.set(i, &self.object_data[i]);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn color(&self, i: usize) -> Result<Color, String> {
self.index_oob(i)?;
Ok(self.object_data[i].color)
}
pub fn set_opacity(&mut self, i: usize, opacity: f32) -> Result<(), String> {
self.index_oob(i)?;
self.object_data[i].opacity = opacity;
self.object.set(i, &self.object_data[i]);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn opacity(&self, i: usize) -> Result<f32, String> {
self.index_oob(i)?;
Ok(self.object_data[i].opacity)
}
pub fn set_offset(&mut self, i: usize, x_offset: f32, y_offset: f32) -> Result<(), String> {
self.index_oob(i)?;
self.object_data[i].offset = (x_offset, y_offset);
self.object.set(i, &self.object_data[i]);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn offset(&self, i: usize) -> Result<(f32, f32), String> {
self.index_oob(i)?;
Ok(self.object_data[i].offset)
}
pub fn set_texcoord(&mut self, i: usize, texcoord: TextureCoordinate) -> Result<(), String> {
self.index_oob(i)?;
self.object_data[i].texcoord = texcoord;
self.object.set(i, &self.object_data[i]);
self.object.set_state(ObjectState::Reload);
Ok(())
}
pub fn texcoord(&self, i: usize) -> Result<TextureCoordinate, String> {
self.index_oob(i)?;
Ok(self.object_data[i].texcoord)
}
pub fn instance_collides(&self, i: usize, x: f32, y: f32) -> Result<bool, String> {
let (tx, ty, _) = self.transform.pos();
let (x_offset, y_offset) = self.offset(i)?;
let (width, height) = self.dim(i)?;
let collides = collision::point_in_rect(x, y, tx + x_offset, ty + y_offset, width, height);
Ok(collides)
}
pub fn collides(&self, x: f32, y: f32) -> Result<Option<usize>, String> {
for i in 0..self.object_data.len() {
let collides = self.instance_collides(i, x, y)?;
if collides {
return Ok(Some(i));
}
}
Ok(None)
}
fn index_oob(&self, i: usize) -> Result<(), String> {
if i >= self.object_data.len() {
Err(format!("Component Data with index '{}' not found.", i))
} else {
Ok(())
}
}
}