Draft support for dynamic custom renderer injection
This commit is contained in:
parent
2b00e8b145
commit
188db4da48
12 changed files with 316 additions and 35 deletions
|
|
@ -1,4 +1,5 @@
|
|||
use crate::core::Color;
|
||||
use crate::custom;
|
||||
use crate::graphics::compositor::{Information, SurfaceError, Window};
|
||||
use crate::graphics::{Error, Viewport};
|
||||
use crate::{Renderer, Settings};
|
||||
|
|
@ -10,12 +11,14 @@ pub enum Compositor {
|
|||
TinySkia(iced_tiny_skia::window::Compositor),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::window::Compositor),
|
||||
Custom(Box<dyn custom::Compositor>),
|
||||
}
|
||||
|
||||
pub enum Surface {
|
||||
TinySkia(iced_tiny_skia::window::Surface),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::window::Surface<'static>),
|
||||
Custom(Box<dyn custom::Surface>),
|
||||
}
|
||||
|
||||
impl crate::graphics::Compositor for Compositor {
|
||||
|
|
@ -56,6 +59,9 @@ impl crate::graphics::Compositor for Compositor {
|
|||
Compositor::Wgpu(compositor) => {
|
||||
Renderer::Wgpu(compositor.create_renderer())
|
||||
}
|
||||
Compositor::Custom(compositor) => {
|
||||
Renderer::Custom(compositor.create_renderer())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +79,9 @@ impl crate::graphics::Compositor for Compositor {
|
|||
Self::Wgpu(compositor) => {
|
||||
Surface::Wgpu(compositor.create_surface(window, width, height))
|
||||
}
|
||||
Self::Custom(compositor) => Surface::Custom(
|
||||
compositor.create_surface(Box::new(window), width, height),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +99,9 @@ impl crate::graphics::Compositor for Compositor {
|
|||
(Self::Wgpu(compositor), Surface::Wgpu(surface)) => {
|
||||
compositor.configure_surface(surface, width, height);
|
||||
}
|
||||
(Self::Custom(compositor), Surface::Custom(surface)) => {
|
||||
compositor.configure_surface(surface, width, height);
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided surface is not compatible with the compositor."
|
||||
|
|
@ -102,6 +114,7 @@ impl crate::graphics::Compositor for Compositor {
|
|||
Self::TinySkia(compositor) => compositor.fetch_information(),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(compositor) => compositor.fetch_information(),
|
||||
Self::Custom(compositor) => compositor.fetch_information(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,6 +157,18 @@ impl crate::graphics::Compositor for Compositor {
|
|||
overlay,
|
||||
)
|
||||
}),
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
(
|
||||
Self::Custom(compositor),
|
||||
crate::Renderer::Custom(renderer),
|
||||
Surface::Custom(surface),
|
||||
) => renderer.present(
|
||||
surface.as_mut(),
|
||||
viewport,
|
||||
background_color,
|
||||
compositor.as_mut(),
|
||||
),
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => panic!(
|
||||
"The provided renderer or surface are not compatible \
|
||||
|
|
|
|||
164
renderer/src/custom.rs
Normal file
164
renderer/src/custom.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
use crate::core::image;
|
||||
use crate::core::renderer;
|
||||
use crate::core::svg;
|
||||
use crate::core::text::Text;
|
||||
use crate::core::{
|
||||
Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
|
||||
};
|
||||
use crate::graphics::compositor;
|
||||
use crate::graphics::text::{Editor, Paragraph};
|
||||
use crate::graphics::{Mesh, Viewport};
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
use crate::graphics::geometry::{self, Fill, Path, Stroke};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub trait Renderer {
|
||||
fn draw_mesh(&mut self, mesh: Mesh);
|
||||
|
||||
fn start_layer(&mut self);
|
||||
|
||||
fn end_layer(&mut self, bounds: Rectangle);
|
||||
|
||||
fn start_transformation(&mut self);
|
||||
|
||||
fn end_transformation(&mut self, transformation: Transformation);
|
||||
|
||||
fn fill_quad(&mut self, quad: renderer::Quad, background: Background);
|
||||
|
||||
fn clear(&mut self);
|
||||
|
||||
fn default_font(&self) -> Font;
|
||||
|
||||
fn default_size(&self) -> Pixels;
|
||||
|
||||
fn load_font(&mut self, bytes: Cow<'static, [u8]>);
|
||||
|
||||
fn fill_paragraph(
|
||||
&mut self,
|
||||
paragraph: &Paragraph,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
);
|
||||
|
||||
fn fill_editor(
|
||||
&mut self,
|
||||
editor: &Editor,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
);
|
||||
|
||||
fn fill_text(
|
||||
&mut self,
|
||||
text: Text<'_, Font>,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
);
|
||||
|
||||
fn measure_image(&self, handle: &image::Handle) -> Size<u32>;
|
||||
|
||||
fn draw_image(
|
||||
&mut self,
|
||||
handle: image::Handle,
|
||||
filter_method: image::FilterMethod,
|
||||
bounds: Rectangle,
|
||||
);
|
||||
|
||||
fn measure_svg(&self, handle: &svg::Handle) -> Size<u32>;
|
||||
|
||||
fn draw_svg(
|
||||
&mut self,
|
||||
handle: crate::core::svg::Handle,
|
||||
color: Option<crate::core::Color>,
|
||||
bounds: Rectangle,
|
||||
);
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
fn new_frame(&self, size: Size) -> Box<dyn Frame>;
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
fn draw_geometry(&mut self, geometry: Box<dyn Geometry>);
|
||||
|
||||
fn present(
|
||||
&mut self,
|
||||
surface: &mut dyn Surface,
|
||||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
compositor: &mut dyn Compositor,
|
||||
) -> Result<(), compositor::SurfaceError>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
pub trait Frame: std::any::Any {
|
||||
fn new(&self, size: Size) -> Box<dyn Frame>;
|
||||
|
||||
fn width(&self) -> f32;
|
||||
|
||||
fn height(&self) -> f32;
|
||||
|
||||
fn size(&self) -> Size;
|
||||
|
||||
fn center(&self) -> Point;
|
||||
|
||||
fn fill(&mut self, path: &Path, fill: Fill);
|
||||
|
||||
fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: Fill);
|
||||
|
||||
fn stroke<'a>(&mut self, path: &Path, stroke: Stroke<'a>);
|
||||
|
||||
fn fill_text(&mut self, text: geometry::Text);
|
||||
|
||||
fn translate(&mut self, translation: crate::core::Vector);
|
||||
|
||||
fn rotate(&mut self, angle: crate::core::Radians);
|
||||
|
||||
fn scale(&mut self, scale: f32);
|
||||
|
||||
fn scale_nonuniform(&mut self, scale: crate::core::Vector);
|
||||
|
||||
fn push_transform(&mut self);
|
||||
|
||||
fn pop_transform(&mut self);
|
||||
|
||||
fn clip(&mut self, frame: Box<dyn Frame>, origin: Point);
|
||||
|
||||
fn into_geometry(self: Box<Self>) -> Box<dyn Geometry>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
pub trait Geometry: std::any::Any + std::fmt::Debug {
|
||||
fn transform(
|
||||
self: Box<Self>,
|
||||
transformation: Transformation,
|
||||
) -> Box<dyn Geometry>;
|
||||
|
||||
fn cache(self: Box<Self>) -> std::sync::Arc<dyn Geometry>;
|
||||
|
||||
fn load(self: std::sync::Arc<Self>) -> Box<dyn Geometry>;
|
||||
}
|
||||
|
||||
pub trait Compositor: std::any::Any {
|
||||
fn create_renderer(&self) -> Box<dyn Renderer>;
|
||||
|
||||
fn create_surface(
|
||||
&mut self,
|
||||
window: Box<dyn compositor::Window>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Box<dyn Surface>;
|
||||
|
||||
fn configure_surface(
|
||||
&mut self,
|
||||
surface: &mut Box<dyn Surface>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
);
|
||||
|
||||
fn fetch_information(&self) -> compositor::Information;
|
||||
}
|
||||
|
||||
pub trait Surface: std::any::Any {}
|
||||
|
|
@ -3,6 +3,7 @@ mod cache;
|
|||
pub use cache::Cache;
|
||||
|
||||
use crate::core::{Point, Radians, Rectangle, Size, Transformation, Vector};
|
||||
use crate::custom;
|
||||
use crate::graphics::geometry::{Fill, Path, Stroke, Text};
|
||||
use crate::Renderer;
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ macro_rules! delegate {
|
|||
Self::TinySkia($name) => $body,
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu($name) => $body,
|
||||
Self::Custom($name) => $body,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -20,6 +22,7 @@ pub enum Geometry {
|
|||
TinySkia(iced_tiny_skia::Primitive),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::Primitive),
|
||||
Custom(Box<dyn custom::Geometry>),
|
||||
}
|
||||
|
||||
impl Geometry {
|
||||
|
|
@ -32,6 +35,9 @@ impl Geometry {
|
|||
Self::Wgpu(primitive) => {
|
||||
Self::Wgpu(primitive.transform(transformation))
|
||||
}
|
||||
Self::Custom(geometry) => {
|
||||
Self::Custom(geometry.transform(transformation))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +46,7 @@ pub enum Frame {
|
|||
TinySkia(iced_tiny_skia::geometry::Frame),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::geometry::Frame),
|
||||
Custom(Box<dyn custom::Frame>),
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
|
|
@ -52,6 +59,9 @@ impl Frame {
|
|||
Renderer::Wgpu(_) => {
|
||||
Frame::Wgpu(iced_wgpu::geometry::Frame::new(size))
|
||||
}
|
||||
Renderer::Custom(renderer) => {
|
||||
Frame::Custom(renderer.new_frame(size))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +92,7 @@ impl Frame {
|
|||
/// Draws the given [`Path`] on the [`Frame`] by filling it with the
|
||||
/// provided style.
|
||||
pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
|
||||
delegate!(self, frame, frame.fill(path, fill));
|
||||
delegate!(self, frame, frame.fill(path, fill.into()));
|
||||
}
|
||||
|
||||
/// Draws an axis-aligned rectangle given its top-left corner coordinate and
|
||||
|
|
@ -93,13 +103,17 @@ impl Frame {
|
|||
size: Size,
|
||||
fill: impl Into<Fill>,
|
||||
) {
|
||||
delegate!(self, frame, frame.fill_rectangle(top_left, size, fill));
|
||||
delegate!(
|
||||
self,
|
||||
frame,
|
||||
frame.fill_rectangle(top_left, size, fill.into())
|
||||
);
|
||||
}
|
||||
|
||||
/// Draws the stroke of the given [`Path`] on the [`Frame`] with the
|
||||
/// provided style.
|
||||
pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
|
||||
delegate!(self, frame, frame.stroke(path, stroke));
|
||||
delegate!(self, frame, frame.stroke(path, stroke.into()));
|
||||
}
|
||||
|
||||
/// Draws the characters of the given [`Text`] on the [`Frame`], filling
|
||||
|
|
@ -116,7 +130,7 @@ impl Frame {
|
|||
/// Support for vectorial text is planned, and should address all these
|
||||
/// limitations.
|
||||
pub fn fill_text(&mut self, text: impl Into<Text>) {
|
||||
delegate!(self, frame, frame.fill_text(text));
|
||||
delegate!(self, frame, frame.fill_text(text.into()));
|
||||
}
|
||||
|
||||
/// Stores the current transform of the [`Frame`] and executes the given
|
||||
|
|
@ -155,6 +169,7 @@ impl Frame {
|
|||
Self::Wgpu(_) => {
|
||||
Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size()))
|
||||
}
|
||||
Self::Custom(frame) => Self::Custom(frame.new(region.size())),
|
||||
};
|
||||
|
||||
let result = f(&mut frame);
|
||||
|
|
@ -169,6 +184,9 @@ impl Frame {
|
|||
(Self::Wgpu(target), Self::Wgpu(frame)) => {
|
||||
target.clip(frame, origin);
|
||||
}
|
||||
(Self::Custom(target), Self::Custom(frame)) => {
|
||||
target.clip(frame, origin);
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
|
@ -185,19 +203,19 @@ impl Frame {
|
|||
/// Applies a rotation in radians to the current transform of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn rotate(&mut self, angle: impl Into<Radians>) {
|
||||
delegate!(self, frame, frame.rotate(angle));
|
||||
delegate!(self, frame, frame.rotate(angle.into()));
|
||||
}
|
||||
|
||||
/// Applies a uniform scaling to the current transform of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn scale(&mut self, scale: impl Into<f32>) {
|
||||
delegate!(self, frame, frame.scale(scale));
|
||||
delegate!(self, frame, frame.scale(scale.into()));
|
||||
}
|
||||
|
||||
/// Applies a non-uniform scaling to the current transform of the [`Frame`].
|
||||
#[inline]
|
||||
pub fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
|
||||
delegate!(self, frame, frame.scale_nonuniform(scale));
|
||||
delegate!(self, frame, frame.scale_nonuniform(scale.into()));
|
||||
}
|
||||
|
||||
pub fn into_geometry(self) -> Geometry {
|
||||
|
|
@ -205,6 +223,7 @@ impl Frame {
|
|||
Self::TinySkia(frame) => Geometry::TinySkia(frame.into_primitive()),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu(frame) => Geometry::Wgpu(frame.into_primitive()),
|
||||
Self::Custom(frame) => Geometry::Custom(frame.into_geometry()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::core::Size;
|
||||
use crate::custom;
|
||||
use crate::geometry::{Frame, Geometry};
|
||||
use crate::Renderer;
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ enum Internal {
|
|||
TinySkia(Arc<iced_tiny_skia::Primitive>),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(Arc<iced_wgpu::Primitive>),
|
||||
Custom(Arc<dyn custom::Geometry>),
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
|
|
@ -82,6 +84,9 @@ impl Cache {
|
|||
content: primitive.clone(),
|
||||
});
|
||||
}
|
||||
Internal::Custom(geometry) => {
|
||||
return Geometry::Custom(geometry.clone().load())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -100,6 +105,9 @@ impl Cache {
|
|||
Geometry::Wgpu(primitive) => {
|
||||
Internal::Wgpu(Arc::new(primitive))
|
||||
}
|
||||
Geometry::Custom(geometry) => {
|
||||
Internal::Custom(geometry.cache())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -120,6 +128,7 @@ impl Cache {
|
|||
content: primitive,
|
||||
})
|
||||
}
|
||||
Internal::Custom(geometry) => Geometry::Custom(geometry.load()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
pub use iced_wgpu as wgpu;
|
||||
|
||||
pub mod compositor;
|
||||
pub mod custom;
|
||||
|
||||
#[cfg(feature = "geometry")]
|
||||
pub mod geometry;
|
||||
|
|
@ -38,6 +39,7 @@ pub enum Renderer {
|
|||
TinySkia(iced_tiny_skia::Renderer),
|
||||
#[cfg(feature = "wgpu")]
|
||||
Wgpu(iced_wgpu::Renderer),
|
||||
Custom(Box<dyn custom::Renderer>),
|
||||
}
|
||||
|
||||
macro_rules! delegate {
|
||||
|
|
@ -46,6 +48,7 @@ macro_rules! delegate {
|
|||
Self::TinySkia($name) => $body,
|
||||
#[cfg(feature = "wgpu")]
|
||||
Self::Wgpu($name) => $body,
|
||||
Self::Custom($name) => $body,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -62,6 +65,9 @@ impl Renderer {
|
|||
iced_wgpu::primitive::Custom::Mesh(mesh),
|
||||
));
|
||||
}
|
||||
Self::Custom(renderer) => {
|
||||
renderer.draw_mesh(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -96,6 +102,18 @@ impl core::Renderer for Renderer {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Self::Custom(renderer) => {
|
||||
renderer.start_layer();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
Self::Custom(renderer) => {
|
||||
renderer.end_layer(bounds);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +150,18 @@ impl core::Renderer for Renderer {
|
|||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Self::Custom(renderer) => {
|
||||
renderer.start_transformation();
|
||||
|
||||
f(self);
|
||||
|
||||
match self {
|
||||
Self::Custom(renderer) => {
|
||||
renderer.end_transformation(transformation);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +170,7 @@ impl core::Renderer for Renderer {
|
|||
quad: renderer::Quad,
|
||||
background: impl Into<Background>,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.fill_quad(quad, background));
|
||||
delegate!(self, renderer, renderer.fill_quad(quad, background.into()));
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
|
|
@ -216,36 +246,43 @@ impl text::Renderer for Renderer {
|
|||
impl crate::core::image::Renderer for Renderer {
|
||||
type Handle = crate::core::image::Handle;
|
||||
|
||||
fn dimensions(
|
||||
fn measure_image(
|
||||
&self,
|
||||
handle: &crate::core::image::Handle,
|
||||
) -> core::Size<u32> {
|
||||
delegate!(self, renderer, renderer.dimensions(handle))
|
||||
delegate!(self, renderer, renderer.measure_image(handle))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
fn draw_image(
|
||||
&mut self,
|
||||
handle: crate::core::image::Handle,
|
||||
filter_method: crate::core::image::FilterMethod,
|
||||
bounds: Rectangle,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.draw(handle, filter_method, bounds));
|
||||
delegate!(
|
||||
self,
|
||||
renderer,
|
||||
renderer.draw_image(handle, filter_method, bounds)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "svg")]
|
||||
impl crate::core::svg::Renderer for Renderer {
|
||||
fn dimensions(&self, handle: &crate::core::svg::Handle) -> core::Size<u32> {
|
||||
delegate!(self, renderer, renderer.dimensions(handle))
|
||||
fn measure_svg(
|
||||
&self,
|
||||
handle: &crate::core::svg::Handle,
|
||||
) -> core::Size<u32> {
|
||||
delegate!(self, renderer, renderer.measure_svg(handle))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
fn draw_svg(
|
||||
&mut self,
|
||||
handle: crate::core::svg::Handle,
|
||||
color: Option<crate::core::Color>,
|
||||
bounds: Rectangle,
|
||||
) {
|
||||
delegate!(self, renderer, renderer.draw(handle, color, bounds));
|
||||
delegate!(self, renderer, renderer.draw_svg(handle, color, bounds));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,6 +300,7 @@ impl crate::graphics::geometry::Renderer for Renderer {
|
|||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
crate::Geometry::Wgpu(_) => unreachable!(),
|
||||
crate::Geometry::Custom(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -274,6 +312,19 @@ impl crate::graphics::geometry::Renderer for Renderer {
|
|||
renderer.draw_primitive(primitive);
|
||||
}
|
||||
crate::Geometry::TinySkia(_) => unreachable!(),
|
||||
crate::Geometry::Custom(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Self::Custom(renderer) => {
|
||||
for layer in layers {
|
||||
match layer {
|
||||
crate::Geometry::Custom(geometry) => {
|
||||
renderer.draw_geometry(geometry);
|
||||
}
|
||||
crate::Geometry::TinySkia(_) => unreachable!(),
|
||||
#[cfg(feature = "wgpu")]
|
||||
crate::Geometry::Wgpu(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -297,6 +348,11 @@ impl iced_wgpu::primitive::pipeline::Renderer for Renderer {
|
|||
Self::Wgpu(renderer) => {
|
||||
renderer.draw_pipeline_primitive(bounds, primitive);
|
||||
}
|
||||
Self::Custom(_renderer) => {
|
||||
log::warn!(
|
||||
"Custom shader primitive is unavailable with custom renderer."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue