#[cfg(feature = "nostd")]
use alloc::{string::ToString, vec::Vec};
#[cfg(not(feature = "nostd"))]
use std::{string::ToString, vec::Vec};
use crate::pipeline::{tag_processor::ProcessedTags, text_segmenter::TextSegment};
use super::types::{RunCtx, TextDefaults};
pub(super) fn split_into_logical_lines(segments: Vec<TextSegment>) -> Vec<Vec<TextSegment>> {
let mut logical_lines: Vec<Vec<TextSegment>> = Vec::new();
let mut current_line_segments: Vec<TextSegment> = Vec::new();
for segment in segments {
if segment.text.is_empty() {
continue;
}
if segment.text.contains('\n') {
let parts: Vec<&str> = segment.text.split('\n').collect();
for (i, part) in parts.iter().enumerate() {
if i > 0 && !current_line_segments.is_empty() {
logical_lines.push(current_line_segments.clone());
current_line_segments.clear();
}
if !part.is_empty() {
let sub_segment = TextSegment {
text: part.to_string(),
start: segment.start,
end: segment.end,
tags: segment.tags.clone(),
};
current_line_segments.push(sub_segment);
}
}
} else {
current_line_segments.push(segment);
}
}
if !current_line_segments.is_empty() {
logical_lines.push(current_line_segments);
}
logical_lines
}
pub(super) fn resolve_run_colors(
tags: &ProcessedTags,
defaults: &TextDefaults,
ctx: &RunCtx,
) -> ([u8; 4], [u8; 4], [u8; 4]) {
let default_primary_color = defaults.primary_color;
let default_outline_color = defaults.outline_color;
let default_back_color = defaults.back_color;
let event = ctx.event;
let time_cs = ctx.time_cs;
let mut color = tags.colors.primary.unwrap_or(default_primary_color);
let mut outline_color = tags.colors.outline.unwrap_or(default_outline_color);
let mut shadow_color = tags.colors.shadow.unwrap_or(default_back_color);
color[3] = default_primary_color[3];
outline_color[3] = default_outline_color[3];
shadow_color[3] = default_back_color[3];
if let Some(alpha) = tags.colors.alpha1.or(tags.colors.alpha) {
color[3] = alpha;
}
if let Some(alpha) = tags.colors.alpha3 {
outline_color[3] = alpha;
}
if let Some(alpha) = tags.colors.alpha4 {
shadow_color[3] = alpha;
}
if let Some(fade) = &tags.fade {
let event_start = event.start_time_cs().unwrap_or(0);
let event_end = event.end_time_cs().unwrap_or(u32::MAX);
let fade_alpha = if let Some(alpha_mid) = fade.alpha_middle {
let (a1, a2, a3) = (
fade.alpha_start as f32,
alpha_mid as f32,
fade.alpha_end as f32,
);
let t1 = event_start + fade.time_start;
let t2 = t1 + fade.time_fade_in.unwrap_or(0);
let t4 = event_start + fade.time_end;
let t3 = t4.saturating_sub(fade.time_fade_out.unwrap_or(0));
let ass_alpha = if time_cs <= t1 {
a1
} else if time_cs < t2 {
a1 + (a2 - a1) * (time_cs - t1) as f32 / (t2 - t1).max(1) as f32
} else if time_cs <= t3 {
a2
} else if time_cs < t4 {
a2 + (a3 - a2) * (time_cs - t3) as f32 / (t4 - t3).max(1) as f32
} else {
a3
};
255.0 - ass_alpha
} else {
let fade_in_end = event_start + fade.time_start;
let fade_out_start = event_end.saturating_sub(fade.time_end);
if time_cs < fade_in_end {
let progress =
(time_cs.saturating_sub(event_start)) as f32 / fade.time_start.max(1) as f32;
255.0 * progress.min(1.0)
} else if time_cs >= fade_out_start && fade_out_start < event_end {
let progress =
(event_end.saturating_sub(time_cs)) as f32 / fade.time_end.max(1) as f32;
255.0 * progress.min(1.0)
} else {
255.0
}
};
let fade_factor = fade_alpha / 255.0;
color[3] = (color[3] as f32 * fade_factor) as u8;
outline_color[3] = (outline_color[3] as f32 * fade_factor) as u8;
shadow_color[3] = (shadow_color[3] as f32 * fade_factor) as u8;
}
(color, outline_color, shadow_color)
}