cotis-raylib 0.1.0-alpha

Raylib-backed renderer for Cotis
Documentation
//! Scaled rendering wrapper for tests and fixed logical-resolution snapshots.
//!
//! Enabled by the `test-render` feature. `RayTestRender` wraps [`crate::renderer::RaylibRender`]
//! to report logical window dimensions to layout while drawing into a smaller physical framebuffer.
//!
//! For interactive applications, use [`RaylibRender`](crate::renderer::RaylibRender) directly.

use crate::drawables::{RaylibDrawContext, RaylibDrawable};
use crate::renderer::RaylibRender;
use cotis::renders::{CotisRenderer, CotisRendererAsync, RenderCompatibleWith};
use cotis_defaults::render_commands::render_t_list::{IsRenderList, RenderTList};
use cotis_utils::math::Dimensions;
use cotis_utils::traits::{CotisFrameContext, CotisWindowContext};
use raylib::prelude::RaylibDraw;

pub mod interactivity;

/// Logical-resolution renderer wrapper around [`RaylibRender`].
///
/// Resizes the physical window to `dimensions / scale` and scales all drawables by `1/scale`
/// before drawing so layout sees `dimensions` pixels.
pub struct RayTestRender {
    #[allow(dead_code)]
    resolution: Dimensions,
    scale: f32,
    render: RaylibRender,
}

impl<Manager> RenderCompatibleWith<Manager> for RayTestRender {
    fn init(&mut self, _layout_manager: &mut Manager) {}
}

impl RayTestRender {
    /// Creates a scaled test renderer.
    ///
    /// Resizes the inner window to `(dimensions.width / scale, dimensions.height / scale)`.
    pub fn new(dimensions: Dimensions, scale: f32, render: RaylibRender) -> Self {
        render.lock_handle().set_window_size(
            (dimensions.width / scale) as i32,
            (dimensions.height / scale) as i32,
        );
        Self {
            resolution: dimensions,
            scale,
            render,
        }
    }

    /// Returns mutable access to the inner [`RaylibRender`].
    pub fn get_render(&mut self) -> &mut RaylibRender {
        &mut self.render
    }
}

impl CotisWindowContext for RayTestRender {
    fn window_dimensions(&self) -> Dimensions {
        let dim = self.render.window_dimensions();
        Dimensions {
            width: dim.width * self.scale,
            height: dim.height * self.scale,
        }
    }
}

impl CotisFrameContext for RayTestRender {
    fn get_delta_time(&self) -> f32 {
        self.render.get_delta_time()
    }
}

impl<'b> CotisRenderer<Box<dyn RaylibDrawable + 'b>> for RayTestRender {
    fn draw_frame(&mut self, render_commands: impl Iterator<Item = Box<dyn RaylibDrawable + 'b>>) {
        let scale = 1.0 / self.scale;
        self.render.load_new_font_sizes();
        let mut rl = self.render.lock_handle();
        let mut d = rl.begin_drawing(self.render.thread());
        d.clear_background(self.render.background_color);
        let mut clip_stack = Vec::new();
        let mut ctx = RaylibDrawContext {
            d: &mut d,
            fonts: self.render.fonts(),
            clip_stack: &mut clip_stack,
            image_cache: None,
        };
        for mut cmd in render_commands {
            cmd.scale_by(scale);
            cmd.draw(&mut ctx);
        }
    }
}

impl<'b> CotisRendererAsync<Box<dyn RaylibDrawable + 'b>> for RayTestRender {
    async fn draw_frame(
        &mut self,
        render_commands: impl Iterator<Item = Box<dyn RaylibDrawable + 'b>>,
    ) {
        let scale = 1.0 / self.scale;
        self.render.load_new_font_sizes();
        let mut rl = self.render.lock_handle();
        let mut d = rl.begin_drawing(self.render.thread());
        d.clear_background(self.render.background_color);
        let mut clip_stack = Vec::new();
        let mut ctx = RaylibDrawContext {
            d: &mut d,
            fonts: self.render.fonts(),
            clip_stack: &mut clip_stack,
            image_cache: None,
        };
        for mut cmd in render_commands {
            cmd.scale_by(scale);
            cmd.draw(&mut ctx);
        }
    }
}

impl<T: RaylibDrawable, L: RaylibDrawable + IsRenderList> CotisRenderer<RenderTList<T, L>>
    for RayTestRender
{
    fn draw_frame(&mut self, render_commands: impl Iterator<Item = RenderTList<T, L>>) {
        let scale = 1.0 / self.scale;
        self.render.load_new_font_sizes();
        let commands: Vec<_> = render_commands.collect();
        for cmd in &commands {
            cmd.preload_generic_images(&mut self.render);
        }
        let mut rl = self.render.lock_handle();
        let mut d = rl.begin_drawing(self.render.thread());
        d.clear_background(self.render.background_color);
        let mut clip_stack = Vec::new();
        let mut ctx = RaylibDrawContext {
            d: &mut d,
            fonts: self.render.fonts(),
            clip_stack: &mut clip_stack,
            image_cache: Some(self.render.image_cache()),
        };
        for mut cmd in commands {
            cmd.scale_by(scale);
            Box::new(cmd).draw(&mut ctx);
        }
    }
}

impl<T: RaylibDrawable, L: RaylibDrawable + IsRenderList> CotisRendererAsync<RenderTList<T, L>>
    for RayTestRender
{
    async fn draw_frame(&mut self, render_commands: impl Iterator<Item = RenderTList<T, L>>) {
        CotisRenderer::draw_frame(self, render_commands);
    }
}

impl<T: RaylibDrawable> CotisRenderer<RenderTList<T, ()>> for RayTestRender {
    fn draw_frame(&mut self, render_commands: impl Iterator<Item = RenderTList<T, ()>>) {
        let scale = 1.0 / self.scale;
        self.render.load_new_font_sizes();
        let commands: Vec<_> = render_commands.collect();
        for cmd in &commands {
            cmd.preload_generic_images(&mut self.render);
        }
        let mut rl = self.render.lock_handle();
        let mut d = rl.begin_drawing(self.render.thread());
        d.clear_background(self.render.background_color);
        let mut clip_stack = Vec::new();
        let mut ctx = RaylibDrawContext {
            d: &mut d,
            fonts: self.render.fonts(),
            clip_stack: &mut clip_stack,
            image_cache: Some(self.render.image_cache()),
        };
        for mut cmd in commands {
            cmd.scale_by(scale);
            Box::new(cmd).draw(&mut ctx);
        }
    }
}

impl<T: RaylibDrawable> CotisRendererAsync<RenderTList<T, ()>> for RayTestRender {
    async fn draw_frame(&mut self, render_commands: impl Iterator<Item = RenderTList<T, ()>>) {
        CotisRenderer::draw_frame(self, render_commands);
    }
}