#![allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RenderTargetFormat {
Rgba8,
Rgba16F,
R32F,
Depth24,
}
#[derive(Debug, Clone)]
pub struct RenderTargetConfig {
pub width: u32,
pub height: u32,
pub format: RenderTargetFormat,
pub msaa_samples: u32,
pub generate_mipmaps: bool,
}
#[derive(Debug, Clone)]
pub struct RenderTarget {
pub config: RenderTargetConfig,
pub texture_id: u32,
pub framebuffer_id: u32,
pub is_valid: bool,
}
#[derive(Debug, Clone)]
pub struct BlitConfig {
pub src_x: u32,
pub src_y: u32,
pub dst_x: u32,
pub dst_y: u32,
pub width: u32,
pub height: u32,
}
#[allow(dead_code)]
pub fn default_render_target_config(width: u32, height: u32) -> RenderTargetConfig {
RenderTargetConfig {
width,
height,
format: RenderTargetFormat::Rgba8,
msaa_samples: 1,
generate_mipmaps: false,
}
}
#[allow(dead_code)]
pub fn new_render_target(cfg: RenderTargetConfig) -> RenderTarget {
RenderTarget {
config: cfg,
texture_id: 1,
framebuffer_id: 1,
is_valid: true,
}
}
#[allow(dead_code)]
pub fn render_target_width(rt: &RenderTarget) -> u32 {
rt.config.width
}
#[allow(dead_code)]
pub fn render_target_height(rt: &RenderTarget) -> u32 {
rt.config.height
}
#[allow(dead_code)]
pub fn render_target_format_name(rt: &RenderTarget) -> &'static str {
match rt.config.format {
RenderTargetFormat::Rgba8 => "RGBA8",
RenderTargetFormat::Rgba16F => "RGBA16F",
RenderTargetFormat::R32F => "R32F",
RenderTargetFormat::Depth24 => "DEPTH24",
}
}
#[allow(dead_code)]
pub fn render_target_pixel_count(rt: &RenderTarget) -> u32 {
rt.config.width * rt.config.height
}
#[allow(dead_code)]
pub fn render_target_byte_size(rt: &RenderTarget) -> usize {
let bpp = format_bytes_per_pixel(&rt.config.format) as usize;
rt.config.width as usize * rt.config.height as usize * bpp
}
#[allow(dead_code)]
pub fn invalidate_render_target(rt: &mut RenderTarget) {
rt.is_valid = false;
rt.texture_id = 0;
rt.framebuffer_id = 0;
}
#[allow(dead_code)]
pub fn resize_render_target(rt: &mut RenderTarget, w: u32, h: u32) {
rt.config.width = w;
rt.config.height = h;
rt.is_valid = true;
}
#[allow(dead_code)]
pub fn render_target_to_json(rt: &RenderTarget) -> String {
format!(
"{{\"width\":{},\"height\":{},\"format\":\"{}\",\"msaa\":{},\
\"mipmaps\":{},\"valid\":{}}}",
rt.config.width,
rt.config.height,
render_target_format_name(rt),
rt.config.msaa_samples,
rt.config.generate_mipmaps,
rt.is_valid
)
}
#[allow(dead_code)]
pub fn new_blit_config(
src_x: u32,
src_y: u32,
dst_x: u32,
dst_y: u32,
w: u32,
h: u32,
) -> BlitConfig {
BlitConfig {
src_x,
src_y,
dst_x,
dst_y,
width: w,
height: h,
}
}
#[allow(dead_code)]
pub fn blit_area(cfg: &BlitConfig) -> u32 {
cfg.width * cfg.height
}
#[allow(dead_code)]
pub fn format_bytes_per_pixel(fmt: &RenderTargetFormat) -> u32 {
match fmt {
RenderTargetFormat::Rgba8 => 4,
RenderTargetFormat::Rgba16F => 8,
RenderTargetFormat::R32F => 4,
RenderTargetFormat::Depth24 => 4,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_render_target_config() {
let cfg = default_render_target_config(1920, 1080);
assert_eq!(cfg.width, 1920);
assert_eq!(cfg.height, 1080);
assert_eq!(cfg.format, RenderTargetFormat::Rgba8);
assert_eq!(cfg.msaa_samples, 1);
assert!(!cfg.generate_mipmaps);
}
#[test]
fn test_new_render_target_valid() {
let cfg = default_render_target_config(512, 512);
let rt = new_render_target(cfg);
assert!(rt.is_valid);
assert_ne!(rt.texture_id, 0);
assert_ne!(rt.framebuffer_id, 0);
}
#[test]
fn test_render_target_dimensions() {
let rt = new_render_target(default_render_target_config(800, 600));
assert_eq!(render_target_width(&rt), 800);
assert_eq!(render_target_height(&rt), 600);
}
#[test]
fn test_render_target_format_names() {
let mut cfg = default_render_target_config(1, 1);
cfg.format = RenderTargetFormat::Rgba8;
assert_eq!(render_target_format_name(&new_render_target(cfg.clone())), "RGBA8");
cfg.format = RenderTargetFormat::Rgba16F;
assert_eq!(render_target_format_name(&new_render_target(cfg.clone())), "RGBA16F");
cfg.format = RenderTargetFormat::R32F;
assert_eq!(render_target_format_name(&new_render_target(cfg.clone())), "R32F");
cfg.format = RenderTargetFormat::Depth24;
assert_eq!(render_target_format_name(&new_render_target(cfg)), "DEPTH24");
}
#[test]
fn test_render_target_pixel_count() {
let rt = new_render_target(default_render_target_config(100, 50));
assert_eq!(render_target_pixel_count(&rt), 5000);
}
#[test]
fn test_render_target_byte_size_rgba8() {
let rt = new_render_target(default_render_target_config(100, 100));
assert_eq!(render_target_byte_size(&rt), 100 * 100 * 4);
}
#[test]
fn test_render_target_byte_size_rgba16f() {
let mut cfg = default_render_target_config(64, 64);
cfg.format = RenderTargetFormat::Rgba16F;
let rt = new_render_target(cfg);
assert_eq!(render_target_byte_size(&rt), 64 * 64 * 8);
}
#[test]
fn test_invalidate_render_target() {
let mut rt = new_render_target(default_render_target_config(256, 256));
invalidate_render_target(&mut rt);
assert!(!rt.is_valid);
assert_eq!(rt.texture_id, 0);
assert_eq!(rt.framebuffer_id, 0);
}
#[test]
fn test_resize_render_target() {
let mut rt = new_render_target(default_render_target_config(100, 100));
resize_render_target(&mut rt, 200, 150);
assert_eq!(render_target_width(&rt), 200);
assert_eq!(render_target_height(&rt), 150);
assert!(rt.is_valid);
}
#[test]
fn test_render_target_to_json() {
let rt = new_render_target(default_render_target_config(320, 240));
let json = render_target_to_json(&rt);
assert!(json.contains("\"width\":320"));
assert!(json.contains("\"height\":240"));
assert!(json.contains("\"format\":\"RGBA8\""));
assert!(json.contains("\"valid\":true"));
}
#[test]
fn test_blit_config_area() {
let blit = new_blit_config(0, 0, 10, 10, 64, 32);
assert_eq!(blit_area(&blit), 64 * 32);
assert_eq!(blit.src_x, 0);
assert_eq!(blit.dst_x, 10);
}
#[test]
fn test_format_bytes_per_pixel() {
assert_eq!(format_bytes_per_pixel(&RenderTargetFormat::Rgba8), 4);
assert_eq!(format_bytes_per_pixel(&RenderTargetFormat::Rgba16F), 8);
assert_eq!(format_bytes_per_pixel(&RenderTargetFormat::R32F), 4);
assert_eq!(format_bytes_per_pixel(&RenderTargetFormat::Depth24), 4);
}
#[test]
fn test_resize_then_invalidate() {
let mut rt = new_render_target(default_render_target_config(10, 10));
resize_render_target(&mut rt, 20, 20);
assert!(rt.is_valid);
invalidate_render_target(&mut rt);
assert!(!rt.is_valid);
assert_eq!(render_target_width(&rt), 20);
}
}