use crate::color::{Rgba8, Rgba64F, ToRgba};
use crate::core::Window;
use crate::gfx::buffer_cache::BufferCache;
use crate::gfx::{
BindingValue, BlendMode, ColorMode, DrawCall, FilterMode, Font, IndexBuffer, RenderData,
RenderLayer, RenderPass, Sampler, Shader, SubTexture, Surface, Texture, Topology, UniformValue,
Vertex, VertexBuffer,
};
use crate::math::{
Affine2F, Angle, CircleF, LineF, Mat2F, Mat3F, Mat4F, Numeric, PolygonF, QuadF, RadiansF,
RectF, RectU, TriangleF, Vec2, Vec2F, Vec2U, Vec3F, Vec4F, vec2,
};
use std::collections::HashMap;
use std::fmt::{Debug, Formatter};
use std::mem::{replace, swap};
use wgpu::{
Color, CommandEncoderDescriptor, Device, IndexFormat, LoadOp, Operations, Queue,
RenderPassColorAttachment, RenderPassDescriptor, StoreOp, TextureViewDescriptor,
};
pub struct Draw {
cache: DrawCache,
data: RenderData,
pass: RenderPass,
layer: usize,
matrix: Affine2F,
matrix_stack: Vec<Affine2F>,
clip_rect: Option<RectU>,
}
impl Debug for Draw {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Draw").finish_non_exhaustive()
}
}
impl Draw {
pub(crate) fn new(
device: Device,
queue: Queue,
default_shader: Shader,
default_texture: Texture,
) -> Self {
Self {
cache: DrawCache {
device,
queue,
default_shader,
default_texture,
samplers: HashMap::new(),
buffer_cache: BufferCache::default(),
render_layer_vecs: Vec::new(),
draw_call_vecs: Vec::new(),
vertices_vecs: Vec::new(),
indices_vecs: Vec::new(),
window_size: Vec2U::ZERO,
},
data: RenderData::new(),
pass: RenderPass::new(None, None, Vec::new()),
layer: 0,
matrix: Affine2F::IDENTITY,
matrix_stack: Vec::new(),
clip_rect: None,
}
}
pub(crate) fn begin_frame(&mut self, window_size: Vec2U) {
self.cache.window_size = window_size;
self.cache.buffer_cache.reset();
for mut pass in self.data.passes.drain(..) {
for mut layer in pass.layers.drain(..) {
layer.calls.clear();
self.cache.draw_call_vecs.push(layer.calls);
layer.vertices.clear();
self.cache.vertices_vecs.push(layer.vertices);
layer.indices.clear();
self.cache.indices_vecs.push(layer.indices);
}
self.cache.render_layer_vecs.push(pass.layers);
}
self.data.clear();
self.pass = RenderPass::new(
None,
Some(Rgba8::BLACK),
self.cache.render_layer_vecs.pop().unwrap_or_default(),
);
self.pass.ensure_layer(0, &mut self.cache);
self.layer = 0;
self.matrix = Affine2F::IDENTITY;
self.matrix_stack.clear();
self.clip_rect = None;
}
pub(crate) fn end_frame(
&mut self,
frame: u64,
surface: &wgpu::Surface<'static>,
window: &Window,
) {
let mut pass = replace(&mut self.pass, RenderPass::new(None, None, Vec::new()));
if pass.finish(&mut self.cache) {
self.data.passes.push(pass);
}
let window_surface = surface
.get_current_texture()
.expect("failed to acquire surface texture");
let mut encoder = self
.cache
.device
.create_command_encoder(&CommandEncoderDescriptor { label: None });
if self.data.passes.is_empty() {
_ = encoder.begin_render_pass(&RenderPassDescriptor {
label: None,
color_attachments: &[Some(RenderPassColorAttachment {
view: &window_surface
.texture
.create_view(&TextureViewDescriptor::default()),
depth_slice: None,
resolve_target: None,
ops: Operations {
load: LoadOp::Clear(Color::BLACK),
store: StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
}
for pass in &self.data.passes {
let surface_tex = if let Some(surface) = pass.surface.as_ref() {
surface.texture().0.texture.clone()
} else {
window_surface.texture.clone()
};
let surface_format = surface_tex.format();
let load = if let Some(clear_color) = pass.clear_color {
let Rgba64F { r, g, b, a } = clear_color.to_rgba();
LoadOp::Clear(Color { r, g, b, a })
} else {
LoadOp::Load
};
let mut wgpu_pass = encoder.begin_render_pass(&RenderPassDescriptor {
label: None,
color_attachments: &[Some(RenderPassColorAttachment {
view: &surface_tex.create_view(&TextureViewDescriptor::default()),
depth_slice: None,
resolve_target: None,
ops: Operations {
load,
store: StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
for layer in pass.layers.iter() {
for call in layer.calls.iter() {
wgpu_pass.set_pipeline(&call.shader.request_pipeline(
&self.cache.device,
call.topology,
surface_format,
call.blend_mode,
));
if let Some(RectU { x, y, w, h }) = call.clip_rect {
wgpu_pass.set_scissor_rect(x, y, w, h);
} else {
let size = surface_tex.size();
wgpu_pass.set_scissor_rect(0, 0, size.width, size.height);
};
wgpu_pass.set_bind_group(
0,
&call.shader.request_bind_group(
&self.cache.device,
&self.cache.queue,
&call.bindings,
&mut self.cache.samplers,
frame,
),
&[],
);
wgpu_pass.set_vertex_buffer(
0,
call.vertices
.buffer()
.slice(..call.vertices.size_in_bytes().to_u64()),
);
wgpu_pass.set_index_buffer(
call.indices
.buffer()
.slice(..call.indices.size_in_bytes().to_u64()),
IndexFormat::Uint32,
);
wgpu_pass.draw_indexed(0..call.indices.count().to_u32(), 0, 0..1);
}
}
}
self.cache.queue.submit([encoder.finish()]);
window.0.pre_present_notify();
window_surface.present();
window.0.request_redraw();
}
#[inline]
pub fn set_surface(
&mut self,
surface: impl Into<Option<Surface>>,
clear_color: impl Into<Option<Rgba8>>,
) {
let surface = surface.into();
let clear_color = clear_color.into();
let mut prev = replace(
&mut self.pass,
RenderPass::new(
surface,
clear_color,
self.cache.render_layer_vecs.pop().unwrap_or_default(),
),
);
self.pass.ensure_layer(self.layer, &mut self.cache);
if prev.finish(&mut self.cache) {
self.data.passes.push(prev);
}
}
#[inline]
pub fn set_layer(&mut self, layer: usize) {
if self.layer == layer {
return;
}
self.layer = layer;
self.pass.ensure_layer(layer, &mut self.cache);
}
#[inline]
pub fn set_shader(&mut self, shader: impl Into<Option<Shader>>) {
let shader = shader
.into()
.unwrap_or_else(|| self.cache.default_shader.clone());
self.pass
.layer(self.layer)
.set_shader(&shader, &mut self.cache);
}
#[inline]
pub fn set_param_i32(&mut self, name: &str, value: i32) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Int(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_u32(&mut self, name: &str, value: u32) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Uint(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_f32(&mut self, name: &str, value: f32) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Float(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_vec2(&mut self, name: &str, value: Vec2F) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Vec2(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_vec3(&mut self, name: &str, value: Vec3F) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Vec3(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_vec4(&mut self, name: &str, value: Vec4F) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Vec4(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_mat2(&mut self, name: &str, value: Mat2F) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Mat2(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_mat3(&mut self, name: &str, value: Mat3F) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Mat3(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_mat4(&mut self, name: &str, value: Mat4F) {
self.pass.layer(self.layer).set_param(
name,
BindingValue::Uniform(UniformValue::Mat4(value)),
&mut self.cache,
);
}
#[inline]
pub fn set_param_texture(&mut self, name: &str, value: Texture) {
self.pass
.layer(self.layer)
.set_param(name, BindingValue::Texture(value), &mut self.cache);
}
#[inline]
pub fn set_param_sampler(&mut self, name: &str, value: Sampler) {
self.pass
.layer(self.layer)
.set_param(name, BindingValue::Sampler(value), &mut self.cache);
}
#[inline]
pub fn set_view_matrix(&mut self, value: &Mat4F) {
self.pass
.layer(self.layer)
.set_view_matrix(value, &mut self.cache);
}
#[inline]
pub fn main_texture(&mut self) -> &Texture {
&self.pass.layer(self.layer).main_texture
}
#[inline]
pub fn main_sampler(&mut self) -> Sampler {
self.pass.layer(self.layer).main_sampler
}
#[inline]
pub fn set_main_sampler(&mut self, value: Sampler) {
self.pass
.layer(self.layer)
.set_main_sampler(value, &mut self.cache);
}
#[inline]
pub fn blend_mode(&mut self) -> BlendMode {
self.pass.layer(self.layer).blend_mode
}
#[inline]
pub fn set_blend_mode(&mut self, value: BlendMode) {
self.pass
.layer(self.layer)
.set_blend_mode(value, &mut self.cache);
}
#[inline]
pub fn clip_rect(&self) -> Option<&RectU> {
self.clip_rect.as_ref()
}
#[inline]
pub fn set_clip_rect(&mut self, value: impl Into<Option<RectU>>) {
self.clip_rect = value.into();
self.pass
.layer(self.layer)
.set_scissor_rect(self.clip_rect, &mut self.cache);
}
#[inline]
pub fn transform(&self) -> &Affine2F {
&self.matrix
}
#[inline]
pub fn push_transform(&mut self, matrix: Affine2F) {
self.matrix_stack.push(self.matrix);
self.matrix = self.matrix * matrix;
}
#[inline]
pub fn set_transform(&mut self, matrix: Affine2F) {
self.matrix = matrix;
}
#[inline]
pub fn push_new_transform(&mut self, matrix: Affine2F) {
self.matrix_stack.push(self.matrix);
self.matrix = matrix;
}
#[inline]
pub fn push_translation(&mut self, amount: impl Into<Vec2F>) {
self.push_transform(Affine2F::translation(amount));
}
#[inline]
pub fn push_rotation(&mut self, amount: impl Angle<f32>) {
self.push_transform(Affine2F::rotation(amount));
}
#[inline]
pub fn push_scale(&mut self, scale: impl Into<Vec2F>) {
self.push_transform(Affine2F::scale(scale));
}
#[inline]
pub fn push_trs(
&mut self,
translation: impl Into<Vec2F>,
rotation: impl Angle<f32>,
scale: impl Into<Vec2F>,
) {
self.push_transform(Affine2F::trs(translation.into(), rotation, scale.into()));
}
#[inline]
pub fn push_scale_of(&mut self, scale: f32) {
self.push_transform(Affine2F::scale_of(scale));
}
#[inline]
pub fn pop_transform(&mut self) -> Result<(), DrawError> {
self.matrix = self
.matrix_stack
.pop()
.ok_or_else(|| DrawError::NoTransformToPop)?;
Ok(())
}
#[inline]
pub fn pop_transforms(&mut self, count: usize) -> Result<(), DrawError> {
for _ in 0..count {
self.pop_transform()?;
}
Ok(())
}
#[inline]
fn point_mode(&mut self) -> (&mut Vec<Vertex>, &mut Vec<u32>, &Affine2F) {
let layer = self.pass.layer(self.layer);
layer.set_topology(Topology::Points, &mut self.cache);
(&mut layer.vertices, &mut layer.indices, &self.matrix)
}
#[inline]
fn line_mode(&mut self) -> (&mut Vec<Vertex>, &mut Vec<u32>, &Affine2F) {
let layer = self.pass.layer(self.layer);
layer.set_topology(Topology::Lines, &mut self.cache);
(&mut layer.vertices, &mut layer.indices, &self.matrix)
}
#[inline]
fn tri_mode(&mut self) -> (&mut Vec<Vertex>, &mut Vec<u32>, &Affine2F) {
let layer = self.pass.layer(self.layer);
layer.set_topology(Topology::Triangles, &mut self.cache);
(&mut layer.vertices, &mut layer.indices, &self.matrix)
}
#[inline]
fn tex_mode(&mut self, texture: &Texture) -> (&mut Vec<Vertex>, &mut Vec<u32>, &Affine2F) {
let layer = self.pass.layer(self.layer);
layer.set_tex_mode(texture, &mut self.cache);
(&mut layer.vertices, &mut layer.indices, &self.matrix)
}
#[inline]
pub fn textured_quad_flipped(
&mut self,
texture: impl AsRef<Texture>,
quad: impl Into<QuadF>,
color: Rgba8,
mode: ColorMode,
flip: impl Into<Vec2<bool>>,
) {
let (verts, inds, mat) = self.tex_mode(texture.as_ref());
let [a, b, c, d] = quad.into().0.map(|p| mat.transform_pos2(p));
let [mut aa, mut bb, mut cc, mut dd] = RectF::sized(Vec2F::ONE).corners();
let flip = flip.into();
if flip.x {
swap(&mut aa.x, &mut bb.x);
swap(&mut cc.x, &mut dd.x);
}
if flip.y {
swap(&mut aa.y, &mut dd.y);
swap(&mut bb.y, &mut cc.y);
}
let i = verts.len() as u32;
verts.extend_from_slice(&[
Vertex::new(a, aa, color, mode),
Vertex::new(b, bb, color, mode),
Vertex::new(c, cc, color, mode),
Vertex::new(d, dd, color, mode),
]);
inds.extend_from_slice(&[i, i + 1, i + 2, i, i + 2, i + 3]);
}
#[inline]
pub fn textured_quad_ext(
&mut self,
texture: impl AsRef<Texture>,
quad: impl Into<QuadF>,
color: Rgba8,
mode: ColorMode,
) {
let (verts, inds, mat) = self.tex_mode(texture.as_ref());
let [a, b, c, d] = quad.into().0.map(|p| mat.transform_pos2(p));
let i = verts.len() as u32;
verts.extend_from_slice(&[
Vertex::new(a, vec2(0.0, 0.0), color, mode),
Vertex::new(b, vec2(1.0, 0.0), color, mode),
Vertex::new(c, vec2(1.0, 1.0), color, mode),
Vertex::new(d, vec2(0.0, 1.0), color, mode),
]);
inds.extend_from_slice(&[i, i + 1, i + 2, i, i + 2, i + 3]);
}
#[inline]
pub fn textured_quad(&mut self, texture: impl AsRef<Texture>, quad: impl Into<QuadF>) {
self.textured_quad_ext(texture, quad, Rgba8::WHITE, ColorMode::MULT);
}
#[inline]
pub fn texture_at_flipped(
&mut self,
texture: impl AsRef<Texture>,
pos: impl Into<Vec2F>,
color: Rgba8,
mode: ColorMode,
flip: impl Into<Vec2<bool>>,
) {
let rect = RectF::pos_size(pos.into(), texture.as_ref().size().to_f32());
self.textured_quad_flipped(texture, rect, color, mode, flip);
}
#[inline]
pub fn texture_at_ext(
&mut self,
texture: impl AsRef<Texture>,
pos: impl Into<Vec2F>,
color: Rgba8,
mode: ColorMode,
) {
let rect = RectF::pos_size(pos.into(), texture.as_ref().size().to_f32());
self.textured_quad_ext(texture, rect, color, mode);
}
#[inline]
pub fn texture_at(&mut self, texture: impl AsRef<Texture>, pos: impl Into<Vec2F>) {
self.texture_at_ext(texture, pos, Rgba8::WHITE, ColorMode::MULT);
}
#[inline]
pub fn point(&mut self, pos: Vec2F, color: Rgba8) {
let (verts, inds, mat) = self.point_mode();
let i = verts.len() as u32;
verts.push(Vertex::veto(mat.transform_pos2(pos), color));
inds.push(i);
}
#[inline]
pub fn points(&mut self, points: impl Iterator<Item = Vec2F>, color: Rgba8) {
let (verts, inds, mat) = self.point_mode();
let mut i = verts.len() as u32;
for p in points {
verts.push(Vertex::veto(mat.transform_pos2(p), color));
inds.push(i);
i += 1;
}
}
#[inline]
pub fn line(&mut self, line: impl Into<LineF>, color: Rgba8) {
let (verts, inds, mat) = self.line_mode();
let i = verts.len() as u32;
verts.extend_from_slice(
&line
.into()
.points()
.map(|p| Vertex::veto(mat.transform_pos2(p), color)),
);
inds.extend_from_slice(&[i, i + 1]);
}
#[inline]
pub fn lines(&mut self, points: impl IntoIterator<Item = Vec2F>, color: Rgba8, loops: bool) {
let (verts, inds, mat) = self.line_mode();
let start = verts.len() as u32;
verts.extend(
points
.into_iter()
.map(|p| Vertex::veto(mat.transform_pos2(p), color)),
);
let end = verts.len() as u32;
if end - start > 1 {
for i in start..(end - 1) {
inds.extend_from_slice(&[i, i + 1]);
}
if loops {
inds.extend_from_slice(&[end - 1, start]);
}
}
}
#[inline]
pub fn triangle(&mut self, tri: impl Into<TriangleF>, color: Rgba8) {
let (verts, inds, mat) = self.tri_mode();
let i = verts.len() as u32;
verts.extend_from_slice(
&tri.into()
.0
.map(|p| Vertex::veto(mat.transform_pos2(p), color)),
);
inds.extend_from_slice(&[i, i + 1, i + 2]);
}
#[inline]
pub fn triangle_outline(&mut self, tri: impl Into<TriangleF>, color: Rgba8) {
self.lines(tri.into().0, color, true);
}
#[inline]
pub fn quad(&mut self, quad: impl Into<QuadF>, color: Rgba8) {
let (verts, inds, mat) = self.tri_mode();
let i = verts.len() as u32;
verts.extend_from_slice(
&quad
.into()
.0
.map(|p| Vertex::veto(mat.transform_pos2(p), color)),
);
inds.extend_from_slice(&[i, i + 1, i + 2, i, i + 2, i + 3]);
}
#[inline]
pub fn quad_outline(&mut self, quad: impl Into<QuadF>, color: Rgba8) {
self.lines(quad.into().0, color, true);
}
#[inline]
pub fn rect(&mut self, rect: impl Into<RectF>, color: Rgba8) {
self.quad(rect.into(), color);
}
#[inline]
pub fn rect_outline(&mut self, rect: impl Into<RectF>, color: Rgba8) {
self.quad_outline(rect.into(), color);
}
#[inline]
pub fn polygon(&mut self, poly: &PolygonF, color: Rgba8) {
let (verts, inds, mat) = self.tri_mode();
let start = verts.len() as u32;
verts.extend(
poly.points()
.iter()
.map(|p| Vertex::veto(mat.transform_pos2(*p), color)),
);
let end = verts.len() as u32;
for i in start..(end - 2) {
inds.extend_from_slice(&[start, i + 1, i + 2]);
}
}
#[inline]
pub fn polygon_outline(&mut self, poly: &PolygonF, color: Rgba8) {
self.lines(poly.points().iter().copied(), color, true);
}
#[inline]
fn fan(&mut self, points: impl IntoIterator<Item = Vec2F>, color: Rgba8, loops: bool) {
let (verts, inds, mat) = self.tri_mode();
let start = verts.len() as u32;
verts.extend(
points
.into_iter()
.map(|p| Vertex::veto(mat.transform_pos2(p), color)),
);
let end = verts.len() as u32;
if end > start + 2 {
for i in (start + 1)..(end - 1) {
inds.push(start);
inds.push(i);
inds.push(i + 1);
}
if loops {
inds.push(start);
inds.push(end - 1);
inds.push(start + 1);
}
}
}
#[inline]
pub fn circle(&mut self, circ: impl Into<CircleF>, color: Rgba8, seg_count: Option<u32>) {
let circ = circ.into();
let seg_count = seg_count
.map(u32::to_f32)
.unwrap_or_else(|| circ.suggest_seg_count_f(|p| self.matrix.transform_pos2(p)));
self.fan(
Some(circ.center)
.into_iter()
.chain(circ.iter_hull_points_n(seg_count, RadiansF::ZERO)),
color,
true,
);
}
#[inline]
pub fn circle_outline(
&mut self,
circ: impl Into<CircleF>,
color: Rgba8,
seg_count: Option<u32>,
) {
let circ = circ.into();
let seg_count = match seg_count.map(u32::to_f32) {
Some(n) => (n / 2.0).floor() * 2.0,
None => circ.suggest_seg_count_f(|p| self.matrix.transform_pos2(p)),
};
self.lines(
circ.iter_hull_points_n(seg_count, RadiansF::ZERO),
color,
true,
);
}
#[inline]
pub fn subtextured_quad_flipped(
&mut self,
sub: impl AsRef<SubTexture>,
dst: impl Into<QuadF>,
color: Rgba8,
mode: ColorMode,
flip: impl Into<Vec2<bool>>,
) {
let sub = sub.as_ref();
let (verts, inds, mat) = self.tex_mode(&sub.texture);
let [a, b, c, d] = dst.into().0.map(|p| mat.transform_pos2(p));
let [mut aa, mut bb, mut cc, mut dd] = sub.coords;
let flip = flip.into();
if flip.x {
swap(&mut aa.x, &mut bb.x);
swap(&mut cc.x, &mut dd.x);
}
if flip.y {
swap(&mut aa.y, &mut dd.y);
swap(&mut bb.y, &mut cc.y);
}
let i = verts.len() as u32;
verts.extend_from_slice(&[
Vertex::new(a, aa, color, mode),
Vertex::new(b, bb, color, mode),
Vertex::new(c, cc, color, mode),
Vertex::new(d, dd, color, mode),
]);
inds.extend_from_slice(&[i, i + 1, i + 2, i, i + 2, i + 3]);
}
#[inline]
pub fn subtextured_quad_ext(
&mut self,
sub: impl AsRef<SubTexture>,
dst: impl Into<QuadF>,
color: Rgba8,
mode: ColorMode,
) {
let sub = sub.as_ref();
let (verts, inds, mat) = self.tex_mode(&sub.texture);
let points = dst.into().0;
let i = verts.len() as u32;
verts.extend_from_slice(&std::array::from_fn::<_, 4, _>(|i| {
let pos = mat.transform_pos2(points[i] + sub.offset);
Vertex::new(pos, sub.coords[i], color, mode)
}));
inds.extend_from_slice(&[i, i + 1, i + 2, i, i + 2, i + 3]);
}
#[inline]
pub fn subtextured_quad(&mut self, sub: impl AsRef<SubTexture>, dst: impl Into<QuadF>) {
self.subtextured_quad_ext(sub, dst, Rgba8::WHITE, ColorMode::MULT);
}
#[inline]
pub fn subtexture_at_flipped(
&mut self,
sub: impl AsRef<SubTexture>,
pos: impl Into<Vec2F>,
color: Rgba8,
mode: ColorMode,
flip: impl Into<Vec2<bool>>,
) {
let dst = RectF::pos_size(pos.into(), sub.as_ref().rect.size());
self.subtextured_quad_flipped(sub, dst, color, mode, flip);
}
#[inline]
pub fn subtexture_at_ext(
&mut self,
sub: impl AsRef<SubTexture>,
pos: impl Into<Vec2F>,
color: Rgba8,
mode: ColorMode,
) {
let dst = RectF::pos_size(pos.into(), sub.as_ref().rect.size());
self.subtextured_quad_ext(sub, dst, color, mode);
}
#[inline]
pub fn subtexture_at(&mut self, sub: impl AsRef<SubTexture>, pos: impl Into<Vec2F>) {
self.subtexture_at_ext(sub, pos, Rgba8::WHITE, ColorMode::MULT);
}
#[inline]
pub fn text(
&mut self,
text: &str,
pos: Vec2F,
font: &Font,
color: Rgba8,
size: impl Into<Option<f32>>,
) {
let size = size.into().unwrap_or(font.size());
let prev_sampler = self.main_sampler();
let mag_filter = match font.pixelated() {
true => FilterMode::Nearest,
false => FilterMode::Linear,
};
if prev_sampler.mag_filter != mag_filter {
self.set_main_sampler(Sampler {
mag_filter,
..prev_sampler
});
}
self.push_translation(pos);
self.push_scale_of(size / font.size());
let mut cursor = Vec2F::ZERO;
for chr in text.chars() {
if let Some(g) = font.glyph(chr) {
if let Some(sub) = g.sub.as_ref() {
self.subtexture_at_ext(sub, cursor, color, ColorMode::MULT);
}
cursor.x += g.adv;
}
}
self.pop_transforms(2).unwrap();
if prev_sampler.mag_filter != mag_filter {
self.set_main_sampler(prev_sampler);
}
}
#[inline]
pub fn custom(
&mut self,
texture: Option<Texture>,
topology: Topology,
vertices: impl IntoIterator<Item = Vertex>,
indices: impl IntoIterator<Item = u32>,
) {
let (verts, inds, mat) = match topology {
Topology::Triangles => match texture {
Some(tex) => self.tex_mode(&tex),
None => self.tri_mode(),
},
Topology::Lines => self.line_mode(),
Topology::Points => self.point_mode(),
};
let len = verts.len() as u32;
for mut v in vertices {
v.pos = mat.transform_pos2(v.pos);
verts.push(v);
}
inds.extend(indices.into_iter().map(|i| len + i));
}
#[inline]
pub fn buffers(
&mut self,
texture: Option<Texture>,
topology: Topology,
vertices: &VertexBuffer,
indices: &IndexBuffer,
) {
let layer = self.pass.layer(self.layer);
let texture = texture.unwrap_or_else(|| self.cache.default_texture.clone());
layer.submit_buffers(
texture,
topology,
vertices.clone(),
indices.clone(),
&mut self.cache,
);
}
}
pub(crate) struct DrawCache {
pub device: Device,
pub queue: Queue,
pub default_shader: Shader,
pub default_texture: Texture,
pub samplers: HashMap<Sampler, wgpu::Sampler>,
pub buffer_cache: BufferCache,
pub render_layer_vecs: Vec<Vec<RenderLayer>>,
pub draw_call_vecs: Vec<Vec<DrawCall>>,
pub vertices_vecs: Vec<Vec<Vertex>>,
pub indices_vecs: Vec<Vec<u32>>,
pub window_size: Vec2U,
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum DrawError {
#[error("no transform to pop")]
NoTransformToPop,
}