use super::fill_state::*;
use super::layer_state::*;
use super::render_entity::*;
use super::renderer_layer::*;
use super::renderer_worker::*;
use super::stroke_settings::*;
use flo_canvas as canvas;
use flo_render as render;
use lyon::tessellation::{FillRule};
use std::mem;
use std::sync::*;
use std::collections::{HashMap};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct LayerHandle(pub u64);
#[derive(Clone, Copy)]
pub enum RenderTexture {
Loading(render::TextureId),
Ready(render::TextureId)
}
#[derive(Clone)]
pub enum RenderGradient {
Defined(Vec<canvas::GradientOp>),
Ready(render::TextureId, Vec<canvas::GradientOp>)
}
impl Into<render::TextureId> for &RenderTexture {
fn into(self) -> render::TextureId {
match self {
RenderTexture::Loading(texture_id) => *texture_id,
RenderTexture::Ready(texture_id) => *texture_id
}
}
}
pub struct RenderCore {
pub frame_starts: usize,
pub setup_actions: Vec<render::RenderAction>,
pub layers: Vec<LayerHandle>,
pub background_color: render::Rgba8,
pub sprites: HashMap<canvas::SpriteId, LayerHandle>,
pub used_textures: HashMap<render::TextureId, usize>,
pub canvas_textures: HashMap<canvas::TextureId, RenderTexture>,
pub canvas_gradients: HashMap<canvas::GradientId, RenderGradient>,
pub texture_alpha: HashMap<canvas::TextureId, f32>,
pub layer_definitions: Vec<Layer>,
pub free_layers: Vec<LayerHandle>,
pub unused_vertex_buffer: usize,
pub free_vertex_buffers: Vec<usize>,
pub unused_texture_id: usize,
pub free_textures: Vec<render::TextureId>
}
impl RenderCore {
pub fn free_layer_entities(&mut self, mut layer: Layer) {
for entity in layer.render_order.drain(..) {
self.free_entity(entity);
}
}
pub fn free_entity(&mut self, render_entity: RenderEntity) {
use self::RenderEntity::*;
match render_entity {
Missing => { }
Tessellating(_entity_id) => { }
VertexBuffer(_buffers, _) => { }
SetTransform(_) => { }
SetBlendMode(_) => { }
SetFlatColor => { }
SetDashPattern(_) => { }
RenderSprite(_, _) => { }
DisableClipping => { }
SetFillTexture(texture_id, _, _, _) => {
self.used_textures.get_mut(&texture_id)
.map(|usage_count| *usage_count -= 1);
}
SetFillGradient(texture_id, _, _, _) => {
self.used_textures.get_mut(&texture_id)
.map(|usage_count| *usage_count -= 1);
}
EnableClipping(render::VertexBufferId(vertex_id), render::IndexBufferId(index_id), _num_vertices) |
DrawIndexed(render::VertexBufferId(vertex_id), render::IndexBufferId(index_id), _num_vertices) => {
self.free_vertex_buffers.push(vertex_id);
if index_id != vertex_id {
self.free_vertex_buffers.push(index_id);
}
}
}
}
pub fn free_unused_textures(&mut self) -> Vec<render::RenderAction> {
let unused_textures = self.used_textures.iter()
.filter(|(_texture_id, count)| **count <= 0)
.map(|(texture_id, _count)| *texture_id)
.collect::<Vec<_>>();
let mut render_actions = vec![];
for free_texture_id in unused_textures.into_iter() {
self.used_textures.remove(&free_texture_id);
self.free_textures.push(free_texture_id);
render_actions.push(render::RenderAction::FreeTexture(free_texture_id));
}
render_actions
}
pub fn store_job_result(&mut self, entity_ref: LayerEntityRef, render_entity: RenderEntity) {
let LayerHandle(layer_idx) = entity_ref.layer_id;
let layer_idx = layer_idx as usize;
if self.layer_definitions.len() <= layer_idx {
self.free_entity(render_entity);
return;
}
if self.layer_definitions[layer_idx].render_order.len() <= entity_ref.entity_index {
self.free_entity(render_entity);
return;
}
let entity = &mut self.layer_definitions[layer_idx].render_order[entity_ref.entity_index];
if let RenderEntity::Tessellating(entity_id) = entity {
if *entity_id != entity_ref.entity_id {
self.free_entity(render_entity);
return;
}
} else {
return;
}
self.layer_definitions[layer_idx]
.render_order[entity_ref.entity_index] = render_entity;
}
pub fn allocate_vertex_buffer(&mut self) -> usize {
self.free_vertex_buffers.pop()
.unwrap_or_else(|| {
let buffer_id = self.unused_vertex_buffer;
self.unused_vertex_buffer += 1;
buffer_id
})
}
pub fn allocate_texture(&mut self) -> render::TextureId {
self.free_textures.pop()
.unwrap_or_else(|| {
let texture_id = self.unused_texture_id;
self.unused_texture_id += 1;
render::TextureId(texture_id)
})
}
pub fn send_layer_vertex_buffer(&mut self, layer_id: LayerHandle, render_index: usize) -> Vec<render::RenderAction> {
let LayerHandle(layer_idx) = layer_id;
let layer_idx = layer_idx as usize;
let mut vertex_action = RenderEntity::Missing;
mem::swap(&mut self.layer_definitions[layer_idx].render_order[render_index], &mut vertex_action);
match vertex_action {
RenderEntity::VertexBuffer(vertices, intent) => {
let buffer_id = self.allocate_vertex_buffer();
match intent {
VertexBufferIntent::Draw => {
self.layer_definitions[layer_idx].render_order[render_index] = RenderEntity::DrawIndexed(render::VertexBufferId(buffer_id), render::IndexBufferId(buffer_id), vertices.indices.len());
}
VertexBufferIntent::Clip => {
self.layer_definitions[layer_idx].render_order[render_index] = RenderEntity::EnableClipping(render::VertexBufferId(buffer_id), render::IndexBufferId(buffer_id), vertices.indices.len());
}
}
vec![
render::RenderAction::CreateIndexBuffer(render::IndexBufferId(buffer_id), vertices.indices),
render::RenderAction::CreateVertex2DBuffer(render::VertexBufferId(buffer_id), vertices.vertices),
]
}
_ => panic!("send_vertex_buffer must be used on a vertex buffer item")
}
}
pub fn send_vertex_buffers(&mut self, layer_handle: LayerHandle) -> Vec<render::RenderAction> {
use self::RenderEntity::*;
let mut send_vertex_buffers = vec![];
let mut layer = self.layer(layer_handle);
for render_idx in 0..layer.render_order.len() {
match &layer.render_order[render_idx] {
VertexBuffer(_buffers, _) => {
send_vertex_buffers.extend(self.send_layer_vertex_buffer(layer_handle, render_idx));
layer = self.layer(layer_handle);
},
RenderSprite(sprite_id, _sprite_transform) => {
let sprite_id = *sprite_id;
let sprite_layer_handle = self.sprites.get(&sprite_id).cloned();
if let Some(sprite_layer_handle) = sprite_layer_handle {
send_vertex_buffers.extend(self.send_vertex_buffers(sprite_layer_handle));
}
layer = self.layer(layer_handle);
},
_ => { }
}
}
send_vertex_buffers
}
pub fn texture_for_rendering(&mut self, texture_id: canvas::TextureId) -> Option<render::TextureId> {
match self.canvas_textures.get(&texture_id)? {
RenderTexture::Ready(render_texture) => Some(*render_texture),
RenderTexture::Loading(render_texture) => {
let render_texture = *render_texture;
self.setup_actions.push(render::RenderAction::CreateMipMaps(render_texture));
self.canvas_textures.get_mut(&texture_id)
.map(|texture| *texture = RenderTexture::Ready(render_texture));
Some(render_texture)
}
}
}
pub fn gradient_for_rendering(&mut self, gradient_id: canvas::GradientId) -> Option<render::TextureId> {
match self.canvas_gradients.get(&gradient_id)? {
RenderGradient::Ready(gradient_texture, _) => Some(*gradient_texture),
RenderGradient::Defined(definition) => {
let definition = definition.clone();
let texture_id = self.allocate_texture();
self.used_textures.insert(texture_id, 0);
let bytes = canvas::gradient_scale::<_, 256>(definition.clone());
let bytes = bytes.iter().flatten().cloned().collect::<Vec<_>>();
self.setup_actions.extend(vec![
render::RenderAction::Create1DTextureBgra(texture_id, 256),
render::RenderAction::WriteTexture1D(texture_id, 0, 256, Arc::new(bytes)),
render::RenderAction::CreateMipMaps(texture_id)
]);
self.canvas_gradients.insert(gradient_id, RenderGradient::Ready(texture_id, definition));
Some(texture_id)
}
}
}
pub fn allocate_layer_handle(&mut self, layer: Layer) -> LayerHandle {
if let Some(LayerHandle(idx)) = self.free_layers.pop() {
self.layer_definitions[idx as usize] = layer;
LayerHandle(idx)
} else {
self.layer_definitions.push(layer);
LayerHandle((self.layer_definitions.len()-1) as u64)
}
}
pub fn release_layer_handle(&mut self, layer_handle: LayerHandle) -> Layer {
let LayerHandle(layer_idx) = layer_handle;
let mut old_layer = Layer {
render_order: vec![RenderEntity::SetTransform(canvas::Transform2D::identity())],
state: LayerState {
is_sprite: false,
fill_color: FillState::Color(render::Rgba8([0, 0, 0, 255])),
winding_rule: FillRule::NonZero,
stroke_settings: StrokeSettings::new(),
current_matrix: canvas::Transform2D::identity(),
sprite_matrix: canvas::Transform2D::identity(),
scale_factor: 1.0,
blend_mode: canvas::BlendMode::SourceOver,
restore_point: None
},
stored_states: vec![]
};
mem::swap(&mut old_layer, &mut self.layer_definitions[layer_idx as usize]);
self.free_layers.push(layer_handle);
old_layer
}
#[inline] pub fn layer(&mut self, layer_handle: LayerHandle) -> &mut Layer {
let LayerHandle(layer_idx) = layer_handle;
let layer_idx = layer_idx as usize;
&mut self.layer_definitions[layer_idx]
}
}