use crate::prelude::*;
use avec;
use crate::core::{blendmodes, BlendMode, context, Color, Program, Vertex};
use crate::core::math::*;
static LAYER_COUNTER: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug)]
pub struct Layer {
view_matrix : Mutex<Mat4Stack<f32>>,
model_matrix : Mutex<Mat4Stack<f32>>,
blend : Mutex<BlendMode>,
color : Mutex<Color>,
contents : Arc<LayerContents>,
program : Option<Program>,
}
unsafe impl Send for Layer { }
unsafe impl Sync for Layer { }
impl Clone for Layer {
fn clone(self: &Self) -> Self {
self.create_clone(None)
}
}
struct LayerContents {
vertex_data : avec::AVec<Vertex>,
dirty : AtomicBool,
generation : AtomicUsize,
layer_id : usize,
}
impl Debug for LayerContents {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("LayerContents")
.field("num_sprites", &(self.vertex_data.len() / 4))
.field("dirty", &self.dirty)
.field("generation", &self.generation)
.field("layer_id", &self.layer_id)
.finish()
}
}
impl Layer {
pub fn new<T>(dimensions: T) -> Self where Point2<f32>: From<T> {
Self::create(dimensions, None)
}
pub fn with_program<T>(dimensions: T, program: Program) -> Self where Point2<f32>: From<T> {
Self::create(dimensions, Some(program))
}
pub fn clone_with_program(self: &Self, program: Program) -> Self {
self.create_clone(Some(program))
}
pub fn set_color(self: &Self, color: Color) -> &Self {
self.color().set(color);
self
}
pub fn color(self: &Self) -> MutexGuard<'_, Color> {
self.color.lock().unwrap()
}
pub fn set_view_matrix<T>(self: &Self, matrix: T) -> &Self where Mat4<f32>: From<T> {
self.view_matrix().set(&matrix.into());
self
}
pub fn view_matrix(self: &Self) -> MutexGuard<'_, Mat4Stack<f32>> {
self.view_matrix.lock().unwrap()
}
pub fn set_model_matrix<T>(self: &Self, matrix: T) -> &Self where Mat4<f32>: From<T> {
self.model_matrix().set(&matrix.into());
self
}
pub fn model_matrix(self: &Self) -> MutexGuard<'_, Mat4Stack<f32>> {
self.model_matrix.lock().unwrap()
}
pub fn set_blendmode(self: &Self, blendmode: BlendMode) -> &Self {
*self.blendmode() = blendmode;
self
}
pub fn blendmode(self: &Self) -> MutexGuard<'_, BlendMode> {
self.blend.lock().unwrap()
}
pub fn clear(self: &Self) -> &Self {
self.set_dirty(true);
self.set_generation(0);
self.contents.vertex_data.clear();
self
}
pub fn capacity(self: &Self) -> usize {
self.contents.vertex_data.capacity() / 4
}
pub fn len(self: &Self) -> usize {
self.contents.vertex_data.len() / 4
}
pub fn arc(self: Self) -> Arc<Self> {
Arc::new(self)
}
pub(crate) fn add_rect(self: &Self, generation: Option<usize>, bucket_id: u8, texture_id: u32, components: u8, uv: Rect, pos: Point2, anchor: Point2<f32>, dim: Point2, color: Color, rotation: f32, scale: Point2) {
self.set_dirty(true);
if generation.is_some() && !self.set_generation(generation.unwrap()) {
panic!("Layer contains garbage data. Note: Layers need to be cleared after performing a Context::prune().");
}
let offset_x0 = -anchor.0 * scale.0;
let offset_x1 = (dim.0 - anchor.0) * scale.0;
let offset_y0 = -anchor.1 * scale.1;
let offset_y1 = (dim.1 - anchor.1) * scale.1;
let bucket_id = bucket_id as u32;
let components = components as u32;
let map = self.contents.vertex_data.map(4);
map.set(0, Vertex {
position : [pos.0, pos.1],
offset : [offset_x0, offset_y0],
rotation : rotation,
color : color.into(),
bucket_id : bucket_id,
texture_id : texture_id,
texture_uv : uv.top_left().as_array(),
components : components,
});
map.set(1, Vertex {
position : [pos.0, pos.1],
offset : [offset_x1, offset_y0],
rotation : rotation,
color : color.into(),
bucket_id : bucket_id,
texture_id : texture_id,
texture_uv : uv.top_right().as_array(),
components : components,
});
map.set(2, Vertex {
position : [pos.0, pos.1],
offset : [offset_x0, offset_y1],
rotation : rotation,
color : color.into(),
bucket_id : bucket_id,
texture_id : texture_id,
texture_uv : uv.bottom_left().as_array(),
components : components,
});
map.set(3, Vertex {
position : [pos.0, pos.1],
offset : [offset_x1, offset_y1],
rotation : rotation,
color : color.into(),
bucket_id : bucket_id,
texture_id : texture_id,
texture_uv : uv.bottom_right().as_array(),
components : components,
});
}
pub fn program(self: &Self) -> Option<&Program> {
self.program.as_ref()
}
pub(crate) fn vertices(self: &Self) -> avec::AVecReadGuard<'_, Vertex> {
self.contents.vertex_data.get()
}
pub(crate) fn id(self: &Self) -> usize {
self.contents.layer_id
}
pub(crate) fn undirty(self: &Self) -> bool {
self.contents.dirty.swap(false, Ordering::Relaxed)
}
fn create<T>(dimensions: T, program: Option<Program>) -> Self where Point2<f32>: From<T> {
let dimensions = Point2::from(dimensions);
Layer {
view_matrix : Mutex::new(Mat4::viewport(dimensions.0, dimensions.1).into()),
model_matrix : Mutex::new(Mat4::identity().into()),
blend : Mutex::new(blendmodes::ALPHA),
color : Mutex::new(Color::WHITE),
contents : Arc::new(LayerContents {
vertex_data : avec::AVec::new(context::INITIAL_CAPACITY * 4),
dirty : AtomicBool::new(true),
generation : AtomicUsize::new(0),
layer_id : 1 + LAYER_COUNTER.fetch_add(1, Ordering::Relaxed),
}),
program : program,
}
}
fn create_clone(self: &Self, program: Option<Program>) -> Self {
Layer {
view_matrix : Mutex::new(self.view_matrix().clone().into()),
model_matrix : Mutex::new(self.model_matrix().clone().into()),
blend : Mutex::new(self.blendmode().clone()),
color : Mutex::new(self.color().clone()),
contents : self.contents.clone(),
program : program,
}
}
fn set_generation(self: &Self, generation: usize) -> bool {
let previous = self.contents.generation.swap(generation, Ordering::Relaxed);
previous == generation || generation == 0 || previous == 0
}
fn set_dirty(self: &Self, value: bool) {
self.contents.dirty.store(value, Ordering::Relaxed);
}
}