use super::{SdlGpuRenderer, sdl_pixel_rect};
use crate::render::path::Path;
use crate::render::texture::Texture;
use crate::types::{Color, Fixed, Point, Rect};
use sdl2_sys::{SDL_Color, SDL_FPoint, SDL_Vertex};
impl<S: AsRef<[u8]> + AsMut<[u8]>> SdlGpuRenderer<'_, S> {
pub(super) fn fill_quad_inner(
&mut self,
q: &[Point; 4],
radius: Fixed,
color: &Color,
opa: u8,
clip: &Rect,
) {
let phys_clip = self.viewport.rect_to_physical(*clip);
let phys_q = [
self.viewport.point_to_physical(q[0]),
self.viewport.point_to_physical(q[1]),
self.viewport.point_to_physical(q[2]),
self.viewport.point_to_physical(q[3]),
];
let phys_radius = radius * self.viewport.scale();
let path = Path::rounded_quad(&phys_q, phys_radius);
self.tessellator.fill(
&path,
None,
color,
opa,
crate::render::raster::FillRule::NonZero,
);
self.submit_geometry(&phys_clip, opa != 255 || color.a != 255);
}
pub(super) fn stroke_quad_inner(
&mut self,
q: &[Point; 4],
width: Fixed,
radius: Fixed,
color: &Color,
opa: u8,
clip: &Rect,
) {
let phys_clip = self.viewport.rect_to_physical(*clip);
let phys_q = [
self.viewport.point_to_physical(q[0]),
self.viewport.point_to_physical(q[1]),
self.viewport.point_to_physical(q[2]),
self.viewport.point_to_physical(q[3]),
];
let phys_radius = radius * self.viewport.scale();
let phys_width = (width * self.viewport.scale()).max(Fixed::ONE);
let path = Path::rounded_quad(&phys_q, phys_radius);
self.tessellator.stroke(
&path,
None,
crate::render::raster::StrokeSpec {
width: phys_width,
cap: crate::render::raster::LineCap::Butt,
join: crate::render::raster::LineJoin::Miter,
miter_limit: Fixed::from_int(4),
dash: &[],
dash_scale: Fixed::ONE,
},
color,
opa,
);
self.submit_geometry(&phys_clip, opa != 255 || color.a != 255);
}
pub(super) fn blit_quad_inner(&mut self, src: &Texture, q: &[Point; 4], clip: &Rect, opa: u8) {
if opa == 0 {
return;
}
let sdl_fmt = Self::texture_format(src.format);
let phys_clip = self.viewport.rect_to_physical(*clip);
let phys_q = [
self.viewport.point_to_physical(q[0]),
self.viewport.point_to_physical(q[1]),
self.viewport.point_to_physical(q[2]),
self.viewport.point_to_physical(q[3]),
];
let Some(sdl_clip) = sdl_pixel_rect(&phys_clip, &phys_clip) else {
return;
};
let src_width = src.width as u32;
let src_height = src.height as u32;
let tint = SDL_Color {
r: 255,
g: 255,
b: 255,
a: opa,
};
let verts: [SDL_Vertex; 4] = [
SDL_Vertex {
position: SDL_FPoint {
x: phys_q[0].x.to_f32(),
y: phys_q[0].y.to_f32(),
},
color: tint,
tex_coord: SDL_FPoint { x: 0.0, y: 0.0 },
},
SDL_Vertex {
position: SDL_FPoint {
x: phys_q[1].x.to_f32(),
y: phys_q[1].y.to_f32(),
},
color: tint,
tex_coord: SDL_FPoint { x: 1.0, y: 0.0 },
},
SDL_Vertex {
position: SDL_FPoint {
x: phys_q[2].x.to_f32(),
y: phys_q[2].y.to_f32(),
},
color: tint,
tex_coord: SDL_FPoint { x: 1.0, y: 1.0 },
},
SDL_Vertex {
position: SDL_FPoint {
x: phys_q[3].x.to_f32(),
y: phys_q[3].y.to_f32(),
},
color: tint,
tex_coord: SDL_FPoint { x: 0.0, y: 1.0 },
},
];
let indices: [i32; 6] = [0, 1, 2, 0, 2, 3];
let canvas = &mut *self.canvas;
let mut uploaded = false;
self.label_cache.with_creator(|creator| {
let mut tex = match creator.create_texture_streaming(sdl_fmt, src_width, src_height) {
Ok(t) => t,
Err(_) => return,
};
if !Self::upload_texture(&mut tex, src) {
return;
}
tex.set_blend_mode(sdl2::render::BlendMode::Blend);
canvas.set_clip_rect(sdl_clip);
uploaded = unsafe {
sdl2_sys::SDL_RenderGeometry(
canvas.raw(),
tex.raw(),
verts.as_ptr(),
verts.len() as _,
indices.as_ptr(),
indices.len() as _,
) == 0
};
canvas.set_clip_rect(None);
});
if !uploaded {
self.draw_failed = true;
}
}
}