use std::{collections::{hash_map::Entry, HashMap},
fmt::Debug,
ops::{AddAssign, Deref, DerefMut}};
use serde::{Deserialize, Serialize};
use super::*;
use crate::{tui::DEBUG_TUI_SHOW_PIPELINE_EXPANDED, *};
#[macro_export]
macro_rules! render_pipeline {
() => {
RenderPipeline::default()
};
(
@new
$arg_z_order: expr
=> $( /* Start a repetition. */
$arg_render_op: expr /* Expression. */
) /* End repetition. */
, /* Comma separated. */
* /* Zero or more times. */
$(,)* /* Optional trailing comma https://stackoverflow.com/a/43143459/2085356. */
) => {
{
let mut render_ops = RenderOps::default();
$(
render_ops.push($arg_render_op);
)*
let mut render_pipeline = RenderPipeline::default();
render_pipeline.push($arg_z_order, render_ops);
render_pipeline
}
};
(
@push_into
$arg_pipeline: ident
at $arg_z_order: expr
=> $($arg_render_op: expr),+
) => {
let mut render_ops = RenderOps::default();
$(
render_ops.push($arg_render_op);
)*
$arg_pipeline.push($arg_z_order, render_ops);
};
(
@join_and_drop
$($arg_other_pipeline: expr),+
) => {{
let mut pipeline = render_pipeline!();
$(
pipeline.join_into($arg_other_pipeline);
)*
pipeline
}};
(
@push_styled_texts_into
$arg_pipeline: ident
at $arg_z_order: expr
=> $arg_styled_texts: expr
) => {
let mut render_ops = RenderOps::default();
$arg_styled_texts.render_into(&mut render_ops);
$arg_pipeline.push($arg_z_order, render_ops);
};
}
#[derive(Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RenderPipeline {
pub pipeline_map: PipelineMap,
}
type PipelineMap = HashMap<ZOrder, Vec<RenderOps>>;
mod render_pipeline_impl {
use super::*;
impl RenderPipeline {
pub fn join_into(&mut self, mut rhs: RenderPipeline) {
for (z_order, mut rhs_render_ops_vec) in rhs.drain() {
match self.entry(z_order) {
Entry::Occupied(mut self_existing_entry) => {
let self_render_ops_vec = self_existing_entry.get_mut();
rhs_render_ops_vec.drain(..).for_each(|render_ops| {
self_render_ops_vec.push(render_ops);
});
}
Entry::Vacant(self_new_entry) => {
self_new_entry.insert(rhs_render_ops_vec);
}
}
}
}
pub fn push(&mut self, z_order: ZOrder, render_ops: RenderOps) {
match self.pipeline_map.entry(z_order) {
Entry::Occupied(mut existing_entry) => {
let render_ops_vec = existing_entry.get_mut();
render_ops_vec.push(render_ops);
}
Entry::Vacant(new_entry) => {
new_entry.insert(vec![render_ops]);
}
}
}
pub fn get_all_render_op_in(&self, z_order: ZOrder) -> Option<Vec<RenderOp>> {
let vec_render_ops = self.pipeline_map.get(&z_order)?;
let mut vec_render_op: Vec<RenderOp> = vec![];
for render_ops in vec_render_ops {
for render_op in render_ops.iter() {
vec_render_op.push(render_op.clone());
}
}
Some(vec_render_op)
}
pub async fn paint(
&self,
flush_kind: FlushKind,
shared_global_data: &SharedGlobalData,
) {
paint(self, flush_kind, shared_global_data).await;
}
pub fn hoist(&mut self, z_order_from: ZOrder, z_order_to: ZOrder) {
if !self.pipeline_map.contains_key(&z_order_from) {
return;
}
let mut from = self.pipeline_map.remove(&z_order_from).unwrap_or_default();
match self.pipeline_map.entry(z_order_to) {
Entry::Occupied(mut to_existing_entry) => {
let to = to_existing_entry.get_mut();
from.drain(..).for_each(|render_ops| {
to.push(render_ops);
});
}
Entry::Vacant(to_new_entry) => {
to_new_entry.insert(from);
}
}
}
}
impl Deref for RenderPipeline {
type Target = PipelineMap;
fn deref(&self) -> &Self::Target { &self.pipeline_map }
}
impl DerefMut for RenderPipeline {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.pipeline_map }
}
impl Debug for RenderPipeline {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut vec_lines: Vec<String> = vec![];
if DEBUG_TUI_SHOW_PIPELINE_EXPANDED {
for (z_order, render_ops) in &**self {
let line: String = format!("[{z_order:?}] {render_ops:?}");
vec_lines.push(line);
}
} else {
for (z_order, vec_render_ops) in &**self {
let line: String =
format!("[{z_order:?}] {:?} RenderOps", vec_render_ops.len());
vec_lines.push(line);
}
}
write!(f, " - {}", vec_lines.join("\n - "))
}
}
impl AddAssign for RenderPipeline {
fn add_assign(&mut self, other: RenderPipeline) { self.join_into(other); }
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum ZOrder {
Normal,
High,
Glass,
}
mod z_order_impl {
use super::*;
impl ZOrder {
pub fn get_render_order() -> [ZOrder; 3] {
[ZOrder::Normal, ZOrder::High, ZOrder::Glass]
}
}
impl Default for ZOrder {
fn default() -> Self { Self::Normal }
}
}