//! Graphics: the [`RenderBackend`] seam and its implementations.
//!
//! `RenderBackend` is the single most important abstraction for Mawida's future.
//! All drawing goes through it, which buys three things:
//!
//! 1. **Swappable backend.** Today the only implementation is wgpu. The course
//!    lineage (a `pixels` + `tiny-skia` CPU backend) or a future raw-Vulkan /
//!    `wgpu-hal` backend can slot in without touching game code.
//! 2. **Present behind an interface.** [`RenderBackend::end_frame`] is "present."
//!    For VR this becomes "submit to the XR compositor" with no change to the
//!    call sites, only a new backend.
//! 3. **Per-camera draw.** [`RenderBackend::draw`] takes a `&dyn Camera`, so
//!    stereo VR rendering is "draw the scene once per eye camera," a loop rather
//!    than a rewrite.
//!
//! See handoff.md for why these three seams, specifically, are what make the
//! 3D and VR pivots tractable.

use crate::camera::Camera;
use crate::color::Color;
use crate::drawable::Drawable;
use crate::error::Result;

pub mod backend;

#[cfg(feature = "runtime")]
pub mod gpu;

#[cfg(feature = "runtime")]
pub mod wgpu_backend;

#[cfg(feature = "runtime")]
pub use wgpu_backend::WgpuBackend;

/// Abstract rendering target. Implementations own the GPU (or CPU) resources and
/// translate Mawida draw calls into native commands.
///
/// Frame protocol, called by the runtime each frame:
/// ```text
/// backend.begin_frame(clear)?;
/// for drawable in scene { backend.draw(drawable, &camera)?; }
/// backend.end_frame()?;   // <- present / submit-to-compositor
/// ```
pub trait RenderBackend {
    /// Begin a frame and clear the target to `clear`.
    fn begin_frame(&mut self, clear: Color) -> Result<()>;

    /// Queue one drawable, viewed through `camera`. Calling with different
    /// cameras within a frame is supported and is how per-eye VR works.
    fn draw(&mut self, drawable: &dyn Drawable, camera: &dyn Camera) -> Result<()>;

    /// Finish the frame and present it (for VR: submit to the compositor).
    fn end_frame(&mut self) -> Result<()>;

    /// React to a surface/window resize.
    fn resize(&mut self, width: u32, height: u32);

    /// Current drawable size in physical pixels.
    fn size(&self) -> (u32, u32);
}
