use crate::Assets;
use crate::{ColorRydit, RyditGfx};
use std::collections::VecDeque;
pub use v_shield::platform_sync::{PlatformSync, PlatformSyncMode};
#[derive(Debug, Clone)]
pub enum DrawCommand {
Circle {
x: i32,
y: i32,
radius: i32,
color: ColorRydit,
},
Rect {
x: i32,
y: i32,
w: i32,
h: i32,
color: ColorRydit,
},
Line {
x1: i32,
y1: i32,
x2: i32,
y2: i32,
color: ColorRydit,
},
Text {
text: String,
x: i32,
y: i32,
size: i32,
color: ColorRydit,
},
Triangle {
v1: (i32, i32),
v2: (i32, i32),
v3: (i32, i32),
color: ColorRydit,
},
Texture {
id: String,
x: f32,
y: f32,
scale: f32,
rotation: f32,
color: ColorRydit,
},
Clear { color: ColorRydit },
}
pub struct RenderQueue {
commands: VecDeque<DrawCommand>,
capacity: usize,
frame_count: usize,
total_executed: usize,
max_frame_count: usize,
}
impl RenderQueue {
pub fn new() -> Self {
Self::with_capacity(8192)
}
pub fn with_capacity(capacity: usize) -> Self {
println!(
"[RENDER QUEUE] Command Queue creada: capacidad={} (8192+ draw calls)",
capacity
);
Self {
commands: VecDeque::with_capacity(capacity),
capacity,
frame_count: 0,
total_executed: 0,
max_frame_count: 0,
}
}
pub fn push(&mut self, command: DrawCommand) {
if self.commands.len() >= self.capacity {
self.commands.pop_front();
#[cfg(debug_assertions)]
eprintln!(
"[RENDER QUEUE] WARNING: Buffer lleno ({}), removiendo comando antiguo",
self.capacity
);
}
self.commands.push_back(command);
self.frame_count += 1;
}
pub fn execute(&mut self, gfx: &mut RyditGfx, assets: &Assets) {
if self.commands.is_empty() {
return;
}
if self.frame_count > self.max_frame_count {
self.max_frame_count = self.frame_count;
}
self.total_executed += self.frame_count;
#[cfg(debug_assertions)]
eprintln!(
"[RENDER QUEUE] Ejecutando {} comandos (total: {}, max frame: {})",
self.frame_count, self.total_executed, self.max_frame_count
);
{
let mut d = gfx.begin_draw();
for command in self.commands.drain(..) {
match command {
DrawCommand::Circle {
x,
y,
radius,
color,
} => {
d.draw_circle(x, y, radius, color);
}
DrawCommand::Rect { x, y, w, h, color } => {
d.draw_rectangle(x, y, w, h, color);
}
DrawCommand::Line {
x1,
y1,
x2,
y2,
color,
} => {
d.draw_line(x1, y1, x2, y2, color);
}
DrawCommand::Text {
text,
x,
y,
size,
color,
} => {
d.draw_text(&text, x, y, size, color);
}
DrawCommand::Triangle { v1, v2, v3, color } => {
d.draw_triangle(v1, v2, v3, color);
}
DrawCommand::Texture {
id,
x,
y,
scale,
rotation,
color,
} => {
assets.draw_texture_ex_by_id(
&mut d.draw,
&id,
x,
y,
scale,
rotation,
color,
);
}
DrawCommand::Clear { color } => {
d.clear(color);
}
}
}
drop(d);
}
self.frame_count = 0;
}
pub fn execute_with_handle(&mut self, d: &mut crate::DrawHandle, assets: &Assets) {
if self.commands.is_empty() {
return;
}
if self.frame_count > self.max_frame_count {
self.max_frame_count = self.frame_count;
}
self.total_executed += self.frame_count;
for command in self.commands.drain(..) {
match command {
DrawCommand::Circle {
x,
y,
radius,
color,
} => {
d.draw_circle(x, y, radius, color);
}
DrawCommand::Rect { x, y, w, h, color } => {
d.draw_rectangle(x, y, w, h, color);
}
DrawCommand::Line {
x1,
y1,
x2,
y2,
color,
} => {
d.draw_line(x1, y1, x2, y2, color);
}
DrawCommand::Text {
text,
x,
y,
size,
color,
} => {
d.draw_text(&text, x, y, size, color);
}
DrawCommand::Triangle { v1, v2, v3, color } => {
d.draw_triangle(v1, v2, v3, color);
}
DrawCommand::Texture {
id,
x,
y,
scale,
rotation,
color,
} => {
assets.draw_texture_ex_by_id(&mut d.draw, &id, x, y, scale, rotation, color);
}
DrawCommand::Clear { color } => {
d.clear(color);
}
}
}
self.frame_count = 0;
}
pub fn clear(&mut self) {
self.commands.clear();
self.frame_count = 0;
}
pub fn len(&self) -> usize {
self.commands.len()
}
pub fn is_empty(&self) -> bool {
self.commands.is_empty()
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn stats(&self) -> RenderQueueStats {
RenderQueueStats {
pending: self.commands.len(),
frame_count: self.frame_count,
total_executed: self.total_executed,
max_frame_count: self.max_frame_count,
capacity: self.capacity,
}
}
}
impl Default for RenderQueue {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Default)]
pub struct RenderQueueStats {
pub pending: usize,
pub frame_count: usize,
pub total_executed: usize,
pub max_frame_count: usize,
pub capacity: usize,
}
impl std::fmt::Display for RenderQueueStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"RenderQueue {{ pending: {}, frame: {}, total: {}, max: {}, capacity: {} }}",
self.pending,
self.frame_count,
self.total_executed,
self.max_frame_count,
self.capacity
)
}
}
pub struct DoubleBuffer {
front: RenderQueue,
back: RenderQueue,
frame: u64,
}
impl DoubleBuffer {
pub fn new(capacity: usize) -> Self {
println!("[DOUBLE BUFFER] Creado con capacidad={}", capacity);
Self {
front: RenderQueue::with_capacity(capacity),
back: RenderQueue::with_capacity(capacity),
frame: 0,
}
}
pub fn push(&mut self, command: DrawCommand) {
self.front.push(command);
}
pub fn swap(&mut self) {
self.frame += 1;
std::mem::swap(&mut self.front, &mut self.back);
#[cfg(debug_assertions)]
eprintln!(
"[DOUBLE BUFFER] Frame {} - Swap completado (back: {} comandos)",
self.frame,
self.back.len()
);
}
pub fn execute(&mut self, gfx: &mut RyditGfx, assets: &Assets) {
self.back.execute(gfx, assets);
self.back.clear();
}
pub fn swap_and_execute(&mut self, gfx: &mut RyditGfx, assets: &Assets) {
self.swap();
self.execute(gfx, assets);
}
pub fn frame(&self) -> u64 {
self.frame
}
pub fn stats(&self) -> (RenderQueueStats, RenderQueueStats) {
(self.front.stats(), self.back.stats())
}
}
pub trait RyditGfxExt {
fn execute_queue(&mut self, queue: &mut RenderQueue, assets: &Assets);
fn platform_sync(&mut self);
}
impl RyditGfxExt for RyditGfx {
fn execute_queue(&mut self, queue: &mut RenderQueue, assets: &Assets) {
queue.execute(self, assets);
}
fn platform_sync(&mut self) {
}
}