use graphics::Model;
use rin_graphics::{
self as graphics, PrimitiveType, CoordinateOrigin, path::LineCap,
};
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
use rin_graphics::ttf::{BoxCoordinatesX, BoxCoordinatesY, BoxFlags};
use color::ToRgba;
#[cfg(not(any(feature="gles", feature="webgl")))]
use glin::query::*;
use glin::{Context,Program,SimpleVao,texture,
fbo,buffer,cubemap,
program,vao,simple_vao, VaoDraw};
#[cfg(not(any(feature="gles", feature="webgl")))]
use glin::Fence;
use super::{Material, traits::ToSimpleVao,
vao_mesh, BasicMaterial,
vao_path, VaoPathContour, VaoPathFill,
ShaderMaterial, BitmapFont, object, basic_material,SimpleFbo, Object,
VaoMesh};
#[cfg(not(target_os="unknown"))]
use super::autoload;
use util::LogErr;
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
use super::{ttf, Ttf};
use densevec::DenseVec;
use crate::gl::{self, types::*};
use crate::default_attribute_bindings;
use std::f32;
use rin_math::{Pnt2, Vec2, vec2, Rect};
use rin_window as window;
use std::cell::{RefCell, UnsafeCell};
use std::rc::Rc;
use std::ops::Deref;
use std::path::Path;
use rin_util as util;
use glin::{self, Result, VertexFormat, RenderSurface, Sampler};
use glin::CreationContext as GlinCreationContext;
use hashbrown::{HashMap, hash_map::Entry};
use std::any::{TypeId, Any};
use std::mem;
use std::borrow::Cow;
use glin::uniforms;
#[cfg(not(feature="webgl"))]
use glin::DebugGroup;
#[cfg(not(feature="webgl"))]
use glin::GlWindow;
#[cfg(any(feature="webgl"))]
use glin::WebGlWindow as GlWindow;
thread_local!(static NEXT_ID: RefCell<usize> = RefCell::new(0));
struct RendererData{
vaos_cache: UnsafeCell<HashMap<(TypeId, u64), Box<dyn Any>>>,
#[cfg(not(any(feature="gles", feature="webgl")))]
material_thick_lines: ShaderMaterial,
bitmap_font: BitmapFont,
resolution_factor: f32,
id: usize,
camera_uniforms_cache: UnsafeCell<DenseVec<graphics::mvp::CameraUniformsCache>>,
model_uniforms_cache: UnsafeCell<DenseVec<graphics::mvp::ModelUniformsCache>>,
mvp_uniforms_cache: UnsafeCell<DenseVec<graphics::mvp::UniformsLocationCache>>,
last_mvp_set: UnsafeCell<DenseVec<(usize, usize)>>,
}
#[must_use = "Calling with on a renderer doesn't change that renderer, it returns a new one with the properties applied. Instead of calling `gl.with(...)` do `let gl = gl.with(...)`"]
pub struct Renderer<'c, R: RenderSurface + 'c = glin::Screen>{
data: Rc<RendererData>,
mvp: Cow<'c, graphics::Mvp>,
model_matrices_as_attributes: bool,
context: Cow<'c, Context<'c, R>>,
}
pub struct RendererWithMaterial<'r, R: RenderSurface + 'r = glin::Screen>{
renderer: Renderer<'r,R>,
program: &'r glin::Program,
}
impl<'r, R: RenderSurface> RendererWithMaterial<'r, R>{
#[inline]
pub fn draw_vao<V>(&self, vao: V)
where V: VaoDraw
{
self.renderer.draw_vao(vao, self.program, &[])
}
#[inline]
pub fn with_model<MO: Into<graphics::Model>>(&self, model: MO) -> RendererWithMaterial<R>{
RendererWithMaterial{
renderer: self.renderer.with_model(model),
program: self.program,
}
}
pub fn draw_vao_with_model<V,MO>(&self, vao: V, model: MO)
where V: VaoDraw,
MO: Into<graphics::Model>
{
self.renderer.draw_vao_with_model(vao, model, self.program, &[])
}
}
impl<'c> Renderer<'c>{
pub fn new<'w, W: window::WindowExt + GlWindow>(window: &'w mut W) -> Result<Renderer<'static>>{
Renderer::with_default_properties(window, &[])
}
pub fn with_default_properties<'w, W: window::WindowExt + GlWindow>(window: &'w mut W, default_properties: &[glin::Property]) -> Result<Renderer<'static>>{
let resolution_factor = window.resolution_factor();
let default_mvp = graphics::Mvp::ortho_top_left(window.viewport());
let context = Cow::Owned(glin::Context::from_properties(window, default_properties)?);
#[cfg(not(any(feature="gles", feature="webgl")))]
let program_thick_lines = Renderer::allocate_program_thicklines(&context).log_err("")?;
Ok(Renderer{
data: Rc::new(RendererData{
vaos_cache: UnsafeCell::new(HashMap::new()),
bitmap_font: BitmapFont::new(&context),
resolution_factor: resolution_factor,
id: NEXT_ID.with(|id| { let ret = *id.borrow(); *id.borrow_mut()+=1; ret }),
camera_uniforms_cache: UnsafeCell::new(DenseVec::new()),
model_uniforms_cache: UnsafeCell::new(DenseVec::new()),
mvp_uniforms_cache: UnsafeCell::new(DenseVec::new()),
last_mvp_set: UnsafeCell::new(DenseVec::new()),
#[cfg(not(any(feature="gles", feature="webgl")))]
material_thick_lines: ShaderMaterial::new(program_thick_lines),
}),
context,
mvp: Cow::Owned(default_mvp),
model_matrices_as_attributes: false,
})
}
#[cfg(not(any(feature="gles", feature="webgl")))]
fn allocate_program_thicklines(gl: &Context) -> Result<Program>{
gl.new_program().from_settings(glin::program::Settings{
version: crate::default_glsl_version(),
extensions: vec![],
precision: glin::program::ShaderPrecision::High,
defines: vec![],
shaders: vec![
(gl::VERTEX_SHADER, shaders::VERTEX_SHADER_DEFAULT),
(gl::GEOMETRY_SHADER, shaders::GEOM_SHADER_THICK_LINES),
(gl::FRAGMENT_SHADER, shaders::FRAGMENT_SHADER_THICK_LINES),
],
bindings: crate::default_attribute_bindings().clone(),
base_path: "",
includes: glin::hash_map!{
"mvp_uniforms.glsl" => include_str!("shaders/mvp_uniforms.glsl")
},
})
}
pub unsafe fn reset_default_state(&mut self, state: glin::State<'static>){
self.context.to_mut().reset_default_state(state)
}
}
impl<'c, R: RenderSurface + 'c> Renderer<'c, R>{
pub fn resolution_factor(&self) -> f32{
self.data.resolution_factor
}
pub fn clear_color<C:ToRgba>(&self, color: &C){
self.context.clear_color(&color.to_rgba::<f32>());
}
pub fn clear_depth(&self, depth: f64){
self.context.clear_depth(depth)
}
pub fn clear_stencil(&self, stencil: i32){
self.context.clear_stencil(stencil)
}
pub fn clear_all<C>(&self, color: Option<C>, depth: Option<f64>, stencil: Option<i32>)
where C:ToRgba
{
self.context.clear(color.map(|c| c.to_rgba::<f32>()), depth, stencil)
}
pub fn mvp(&self) -> &graphics::Mvp{
&self.mvp
}
pub fn with_camera_viewport<C: graphics::CameraExt + ?Sized>(&self, camera: &C, viewport: &Rect<i32>) -> Renderer<R>{
self.with_mvp(graphics::Mvp::with_camera_viewport(camera, *viewport))
}
pub fn with_mvp<M: Into<graphics::Mvp>>(&self, mvp: M) -> Renderer<R>{
let mvp = mvp.into();
let viewport = glin::Rect{
left: mvp.viewport().pos.x as u32,
bottom: mvp.viewport().pos.y as u32,
width: mvp.viewport().width as u32,
height: mvp.viewport().height as u32,
};
Renderer{
data: self.data.clone(),
context: Cow::Owned(self.context.with(&[glin::Property::Viewport(viewport)])),
mvp: Cow::Owned(mvp),
model_matrices_as_attributes: self.model_matrices_as_attributes,
}
}
pub fn with_model<M: Into<graphics::Model>>(&self, model: M) -> Renderer<R>{
let model = model.into();
let mvp = self.mvp.for_model(model);
Renderer{
data: self.data.clone(),
mvp: Cow::Owned(mvp),
context: Cow::Borrowed(self.context.as_ref()),
model_matrices_as_attributes: false,
}
}
pub fn with_properties<'a,P>(&self, properties: P) -> Renderer<R>
where P: IntoIterator<Item = &'a glin::Property>
{
Renderer{
data: self.data.clone(),
context: Cow::Owned(self.context.with(properties)),
mvp: Cow::Borrowed(self.mvp.as_ref()),
model_matrices_as_attributes: self.model_matrices_as_attributes,
}
}
pub fn with_model_matrices_as_attributes(&self) -> Renderer<R>{
Renderer{
data: self.data.clone(),
context: Cow::Borrowed(self.context.as_ref()),
mvp: Cow::Borrowed(self.mvp.as_ref()),
model_matrices_as_attributes: true,
}
}
pub fn with_material<'m, M: Material>(&'m mut self, material: &'m M) -> RendererWithMaterial<'m,R>{
let renderer = self.with_properties(material.properties());
let uniforms = material.uniforms(&renderer);
let program = material.program(&renderer);
let _ = program.set_uniforms(uniforms);
RendererWithMaterial{
renderer,
program,
}
}
pub fn id(&self) -> usize{
self.data.id
}
pub fn context(&self) -> &glin::Context<'c, R>{
&self.context
}
pub fn context_mut(&mut self) -> &mut glin::Context<'c, R>{
self.context.to_mut()
}
pub fn new_texture(&self) -> texture::Builder{
self.context.new_texture()
}
pub fn new_cubemap(&self) -> cubemap::Builder{
self.context.new_cubemap()
}
pub fn new_buffer(&self) -> buffer::Builder{
self.context.new_buffer()
}
pub fn new_shared_buffer(&self) -> buffer::SharedBuilder{
self.context.new_shared_buffer()
}
pub fn new_vao(&self) -> vao::Builder{
self.context.new_vao()
}
pub fn new_simple_vao(&self) -> simple_vao::Builder{
self.context.new_simple_vao()
}
pub fn new_program(&self) -> program::Builder{
self.context.new_program()
}
pub fn new_sampler(&self) -> Sampler{
self.context.new_sampler()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
pub fn new_timestamp_query(&self) -> TimeStamp{
self.context.new_timestamp_query()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
pub fn new_duration_query(&self) -> Duration{
self.context.new_duration_query()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
pub fn new_fence(&self) -> Fence{
self.context.new_fence()
}
#[cfg(not(feature="webgl"))]
pub fn new_debug_group(&self, id: u32, message: &str) -> DebugGroup {
self.context.new_debug_group(id, message)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
pub fn new_ttf<'a>(&'a self, path: &'a str, pt_height: f32) -> ttf::Builder<'a>{
ttf::Builder::new(self.creation_proxy(), path, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
pub fn new_ttf_from_bytes<'a>(&'a self, bytes: &'a [u8], pt_height: f32) -> ttf::Builder<'a>{
ttf::Builder::from_bytes(self.creation_proxy(), bytes, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
pub fn new_ttf_material<'a>(&self, ttf: &'a graphics::Ttf) -> ttf::MaterialBuilder<'a>{
ttf::MaterialBuilder::new(self.creation_proxy(), ttf)
}
pub fn new_vao_mesh(&self) -> vao_mesh::Builder{
vao_mesh::Builder(self.creation_proxy())
}
pub fn new_vao_path(&self) -> vao_path::Builder{
vao_path::Builder(self.creation_proxy())
}
#[cfg(not(target_os="unknown"))]
pub fn new_auto_program<P: AsRef<Path> + Clone + 'static>(&self, settings: autoload::ProgramSettings<P>) -> util::AutoLoader<glin::Program>{
autoload::new_program(self.creation_proxy(), settings)
}
pub fn new_object(&self) -> object::Builder{
object::Builder{gl: self.creation_proxy()}
}
pub fn to_simple_vao<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M) -> Result<SimpleVao<T>>{
mesh.to_simple_vao(self, default_attribute_bindings(), gl::STATIC_DRAW)
}
pub fn to_simple_vao_bindings<T, U, M: ToSimpleVao<T,U>, B: glin::Bindings>(&self, mesh: &M, bindings: &B) -> Result<SimpleVao<T>>{
mesh.to_simple_vao(self, bindings, gl::STATIC_DRAW)
}
pub fn to_simple_vao_usage<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M, usage: GLenum, program: &glin::Program) -> Result<SimpleVao<T>>{
mesh.to_simple_vao(self, default_attribute_bindings(), usage)
}
pub fn to_simple_vao_usage_bindings<T, U, M: ToSimpleVao<T,U>, B: glin::Bindings>(&self, mesh: &M, usage: GLenum, bindings: &B) -> Result<SimpleVao<T>>{
mesh.to_simple_vao(self, bindings, usage)
}
pub fn creation_proxy(&self) -> CreationProxy{
CreationProxy{ context: self.context.creation_proxy().clone() }
}
pub fn model_matrices_as_attributes(&self) -> bool{
self.model_matrices_as_attributes
}
pub fn clear<C:ToRgba>(&self, color: &C){
self.clear_color(color);
self.clear_depth(1.);
}
pub fn draw_mesh<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M)
where T: VertexFormat + Clone + 'static
{
let material = BasicMaterial::default();
self.draw_vao(
self.get_vao(mesh, material.program(self)).deref(),
material.program(self),
material.uniforms(self)
);
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
pub fn draw_string<C: ToRgba>(&self, font: &Ttf, string: &str, pos: &Pnt2, color: &C){
let material = font.material(color);
let text = font.mesh(string,pos,self.origin());
let vao_text = self.get_vao(&text, material.program(self));
self.draw_vao_with_material(vao_text, &material);
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
pub fn draw_string_box<C: ToRgba>(
&self,
font: &Ttf,
string: &str,
pos: &Pnt2,
w: BoxCoordinatesX,
h: BoxCoordinatesY,
flags: BoxFlags,
color: &C) -> Pnt2
{
let material = font.material(color);
let box_mesh = font.box_mesh(string, pos, w, h, self.origin(), flags);
let vao_text = self.get_vao(&box_mesh.mesh, material.program(self));
self.draw_vao_with_material(vao_text, &material);
box_mesh.next_position
}
pub fn draw_bitmap_string<C: ToRgba>(&self, string: &str, pos: &Pnt2, color: &C){
let material = self.data.bitmap_font.material(color);
let text = self.data.bitmap_font.mesh(string, pos, self.origin());
let vao_text = self.get_vao(&text, material.program(self));
self.draw_vao_with_material(vao_text, &material);
}
pub fn draw_line<C: ToRgba>(&self, from: &Pnt2, to: &Pnt2, color:&C ){
self.draw_mesh(&graphics::line_color(from, to, color));
}
pub fn draw_rectangle_fill<C: ToRgba>(&self, pos: &Pnt2, w: f32, h:f32, color:&C ){
self.draw_mesh(&graphics::rectangle_color(pos,w,h,color));
}
pub fn draw_rectangle_lines<C: ToRgba>(&self, pos: &Pnt2, w: f32, h:f32, color:&C ){
let mut mesh = graphics::rectangle_color(pos,w,h,color);
mesh.set_primitive_type(PrimitiveType::LineLoop);
self.draw_mesh(&mesh);
}
pub fn draw_circle_fill<C: ToRgba>(&self, pos: &Pnt2, radius: f32, resolution: u32, color:&C ){
self.draw_mesh(&graphics::circle_color(pos,radius,resolution,color));
}
pub fn draw_circle_lines<C: ToRgba>(&self, pos: &Pnt2, radius: f32, resolution: u32, color:&C ){
self.draw_mesh(&graphics::circle_color(pos,radius,resolution,color));
}
pub fn draw_ellipse_fill<C: ToRgba>(&self, pos: &Pnt2, w: f32, h: f32, resolution: u32, color:&C ){
self.draw_mesh(&graphics::ellipse_color(pos,w,h,resolution,color));
}
pub fn draw_ellipse_lines<C: ToRgba>(&self, pos: &Pnt2, w: f32, h: f32, resolution: u32, color:&C ){
self.draw_mesh(&graphics::ellipse_color(pos,w,h,resolution,color));
}
pub fn origin(&self) -> CoordinateOrigin{
self.mvp.origin()
}
fn get_vao<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M, program: &glin::Program) -> &glin::SimpleVao<T>
where T: VertexFormat + Clone + 'static
{
let cache = unsafe{ &mut *self.data.vaos_cache.get() };
match cache.entry((::std::any::TypeId::of::<T>(), program.attribute_bindings_hash())){
Entry::Occupied(mut entry) => {
let entry = entry.get_mut();
let vao: &mut glin::SimpleVao<T> = entry.downcast_mut().unwrap();
vao.load(mesh.as_simple_vao_data(), gl::STREAM_DRAW);
unsafe{ mem::transmute(vao) }
}
Entry::Vacant(entry) => {
let vao = entry.insert(Box::new(self.to_simple_vao_bindings(mesh, program).unwrap()))
.downcast_ref()
.unwrap();
vao
}
}
}
fn get_vao_for<T>(&self, program: &glin::Program,) -> &mut glin::SimpleVao<T>
where T: VertexFormat + Clone + 'static
{
let cache = unsafe{ &mut *self.data.vaos_cache.get() };
match cache.entry((::std::any::TypeId::of::<T>(), program.attribute_bindings_hash())){
Entry::Occupied(mut entry) => {
let entry = entry.get_mut();
let vao: &mut glin::SimpleVao<T> = entry.downcast_mut().unwrap();
unsafe{ mem::transmute(vao) }
}
Entry::Vacant(entry) => {
let vao = self.new_simple_vao()
.empty_from_bindings::<T>(program, gl::TRIANGLES)
.unwrap();
entry.insert(Box::new(vao)).downcast_mut().unwrap()
}
}
}
#[inline]
fn last_mvp_set(&self) -> &DenseVec<(usize, usize)>{
unsafe{ &*self.data.last_mvp_set.get() }
}
#[inline]
fn last_mvp_set_mut(&self) -> &mut DenseVec<(usize, usize)>{
unsafe{ &mut *self.data.last_mvp_set.get() }
}
fn model_uniforms_cache(&self) -> &mut DenseVec<graphics::mvp::ModelUniformsCache>{
unsafe{ &mut *self.data.model_uniforms_cache.get() }
}
fn camera_uniforms_cache(&self) -> &mut DenseVec<graphics::mvp::CameraUniformsCache>{
unsafe{ &mut *self.data.camera_uniforms_cache.get() }
}
fn mvp_uniforms_cache(&self) -> &mut DenseVec<graphics::mvp::UniformsLocationCache>{
unsafe{ &mut *self.data.mvp_uniforms_cache.get() }
}
fn draw_vao_with_mvp_properties<'a, V, U, P>(&self,
vao_range: V,
mvp: &graphics::Mvp,
program: &Program,
uniforms: U,
properties: Option<P>)
where V: VaoDraw,
U: IntoIterator<Item = &'a glin::program::Uniform>,
P: IntoIterator<Item = &'a glin::Property>
{
let needs_camera_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(camera, _model)| *camera != mvp.camera_matrices_id())
.unwrap_or(true);
if needs_camera_uniforms {
self.camera_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::CameraMatrices::uniforms_cache(&program))
.set_uniforms(&mvp.camera_matrices(), program);
}
if !self.model_matrices_as_attributes{
let needs_model_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(_camera, model)| *model != mvp.model_matrices_id())
.unwrap_or(true);
if needs_model_uniforms {
mvp.normal();
self.model_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::ModelMatrices::uniforms_cache(&program))
.set_uniforms(&mvp.model_matrices(), program);
}
if needs_camera_uniforms || needs_model_uniforms {
self.mvp_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::Mvp::uniforms_cache(&program))
.set_uniforms(&mvp, program);
self.last_mvp_set_mut()
.insert(program.unique_id(), (mvp.camera_matrices_id(), mvp.model_matrices_id()));
}
}else if needs_camera_uniforms{
self.last_mvp_set_mut()
.insert(program.unique_id(), (mvp.camera_matrices_id(), -1isize as usize));
}
if let Some(properties) = properties {
let _ = self.context.draw_with_properties(vao_range, program, uniforms, properties);
}else{
let _ = self.context.draw(vao_range, program, uniforms);
}
}
}
impl<'c> Renderer<'c> {
pub fn with_fbo<F: glin::UntypedOffscreenBuffer + Clone>(&self, fbo: F) -> Renderer<F> {
Renderer{
data: self.data.clone(),
context: Cow::Owned(self.context.with_fbo(fbo)),
mvp: Cow::Borrowed(self.mvp.as_ref()),
model_matrices_as_attributes: self.model_matrices_as_attributes,
}
}
pub fn new_fbo(&self) -> fbo::Builder{
self.context.new_fbo()
}
pub fn new_fbo_color_attachment(&self) -> fbo::ColorAttachmentBuilder{
self.context.new_fbo_color_attachment()
}
pub fn new_fbo_depth_attachment(&self) -> fbo::DepthAttachmentBuilder{
self.context.new_fbo_depth_attachment()
}
pub fn new_render_buffer(&self) -> fbo::RenderBufferBuilder{
self.context.new_render_buffer()
}
pub fn new_simple_fbo(&self, w: u32, h: u32, format: glin::fbo::ColorFormat) -> Result<SimpleFbo>{
SimpleFbo::new(self, w, h, 0, format)
}
pub fn new_simple_fbo_multisampled(&self, w: u32, h: u32, samples: u32, format: glin::fbo::ColorFormat) -> Result<SimpleFbo>{
SimpleFbo::new(self, w, h, samples, format)
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn dispatch_compute<U,I>(&self, program: &Program, x: u32, y: u32, z: u32, uniforms: I) -> Result<()>
where U: std::borrow::Borrow<program::Uniform>,
I: IntoIterator<Item=U>,
{
self.context.dispatch_compute(program, x, y, z, uniforms)
}
}
#[derive(Clone)]
pub struct CreationProxy{
context: Rc<glin::CreationProxy>,
}
pub trait CreationContext: GlinCreationContext{
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf<'a>(&'a self, path: &'a str, pt_height: f32) -> ttf::Builder<'a>;
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_from_bytes<'a>(&'a self, bytes: &'a [u8], pt_height: f32) -> ttf::Builder<'a>;
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_material<'a>(&self, ttf: &'a graphics::Ttf) -> ttf::MaterialBuilder<'a>;
fn new_vao_mesh(&self) -> vao_mesh::Builder;
fn new_vao_path(&self) -> vao_path::Builder;
#[cfg(not(target_os="unknown"))]
fn new_auto_program<P: AsRef<Path> + Clone + 'static>(&self, settings: autoload::ProgramSettings<P>) -> util::AutoLoader<glin::Program>;
fn new_object(&self) -> object::Builder;
fn to_simple_vao<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M) -> Result<SimpleVao<T>>;
}
impl GlinCreationContext for CreationProxy{
fn capabilities(&self) -> &glin::Capabilities{
self.context.capabilities()
}
fn new_texture(&self) -> texture::Builder{
self.context.new_texture()
}
fn new_cubemap(&self) -> cubemap::Builder{
self.context.new_cubemap()
}
fn new_buffer(&self) -> buffer::Builder{
self.context.new_buffer()
}
fn new_shared_buffer(&self) -> buffer::SharedBuilder{
self.context.new_shared_buffer()
}
fn new_vao(&self) -> vao::Builder{
self.context.new_vao()
}
fn new_simple_vao(&self) -> simple_vao::Builder{
self.context.new_simple_vao()
}
fn new_program(&self) -> program::Builder{
self.context.new_program()
}
fn new_sampler(&self) -> Sampler{
self.context.new_sampler()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
fn new_timestamp_query(&self) -> TimeStamp{
self.context.new_timestamp_query()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
fn new_duration_query(&self) -> Duration{
self.context.new_duration_query()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
fn new_fence(&self) -> Fence{
self.context.new_fence()
}
fn creation_proxy(&self) -> &Rc<glin::CreationProxy>{
&self.context
}
}
impl glin::SurfaceCreationContext for CreationProxy {
fn new_fbo(&self) -> fbo::Builder{
self.context.new_fbo()
}
fn new_fbo_color_attachment(&self) -> fbo::ColorAttachmentBuilder{
self.context.new_fbo_color_attachment()
}
fn new_fbo_depth_attachment(&self) -> fbo::DepthAttachmentBuilder{
self.context.new_fbo_depth_attachment()
}
fn new_render_buffer(&self) -> fbo::RenderBufferBuilder{
self.context.new_render_buffer()
}
}
impl CreationContext for CreationProxy{
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf<'a>(&'a self, path: &'a str, pt_height: f32) -> ttf::Builder<'a>{
ttf::Builder::new(self.clone(), path, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_from_bytes<'a>(&'a self, bytes: &'a [u8], pt_height: f32) -> ttf::Builder<'a>{
ttf::Builder::from_bytes(self.clone(), bytes, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_material<'a>(&self, ttf: &'a graphics::Ttf) -> ttf::MaterialBuilder<'a>{
ttf::MaterialBuilder::new(self.clone(), ttf)
}
fn new_vao_mesh(&self) -> vao_mesh::Builder{
vao_mesh::Builder(self.clone())
}
fn new_vao_path(&self) -> vao_path::Builder{
vao_path::Builder(self.clone())
}
#[cfg(not(target_os="unknown"))]
fn new_auto_program<P: AsRef<Path> + Clone + 'static>(&self, settings: autoload::ProgramSettings<P>) -> util::AutoLoader<glin::Program>{
autoload::new_program(self.clone(), settings)
}
fn new_object(&self) -> object::Builder{
object::Builder{gl: self.clone()}
}
fn to_simple_vao<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M) -> Result<SimpleVao<T>>{
mesh.to_simple_vao(self, default_attribute_bindings(), gl::STATIC_DRAW)
}
}
impl<'c, C: CreationContext> CreationContext for &'c C{
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf<'a>(&'a self, path: &'a str, pt_height: f32) -> ttf::Builder<'a>{
(*self).new_ttf(path, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_from_bytes<'a>(&'a self, bytes: &'a [u8], pt_height: f32) -> ttf::Builder<'a>{
(*self).new_ttf_from_bytes(bytes, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_material<'a>(&self, ttf: &'a graphics::Ttf) -> ttf::MaterialBuilder<'a>{
(*self).new_ttf_material(ttf)
}
fn new_vao_mesh(&self) -> vao_mesh::Builder{
(*self).new_vao_mesh()
}
fn new_vao_path(&self) -> vao_path::Builder{
(*self).new_vao_path()
}
#[cfg(not(target_os="unknown"))]
fn new_auto_program<P: AsRef<Path> + Clone + 'static>(&self, settings: autoload::ProgramSettings<P>) -> util::AutoLoader<glin::Program>{
(*self).new_auto_program(settings)
}
fn new_object(&self) -> object::Builder{
(*self).new_object()
}
fn to_simple_vao<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M) -> Result<SimpleVao<T>>{
(*self).to_simple_vao(mesh)
}
}
impl<'c, R: RenderSurface> CreationContext for Renderer<'c, R>{
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf<'a>(&'a self, path: &'a str, pt_height: f32) -> ttf::Builder<'a>{
ttf::Builder::new(self.creation_proxy(), path, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_from_bytes<'a>(&'a self, bytes: &'a [u8], pt_height: f32) -> ttf::Builder<'a>{
(*self).new_ttf_from_bytes(bytes, pt_height)
}
#[cfg(any(feature="ttf", feature="ttf_rusttype"))]
fn new_ttf_material<'a>(&self, ttf: &'a graphics::Ttf) -> ttf::MaterialBuilder<'a>{
(*self).new_ttf_material(ttf)
}
fn new_vao_mesh(&self) -> vao_mesh::Builder{
vao_mesh::Builder(self.creation_proxy())
}
fn new_vao_path(&self) -> vao_path::Builder{
vao_path::Builder(self.creation_proxy())
}
#[cfg(not(target_os="unknown"))]
fn new_auto_program<P: AsRef<Path> + Clone + 'static>(&self, settings: autoload::ProgramSettings<P>) -> util::AutoLoader<glin::Program>{
autoload::new_program(self.creation_proxy(), settings)
}
fn new_object(&self) -> object::Builder{
object::Builder{gl: self.creation_proxy()}
}
fn to_simple_vao<T, U, M: ToSimpleVao<T,U>>(&self, mesh: &M) -> Result<SimpleVao<T>>{
mesh.to_simple_vao(self, default_attribute_bindings(), gl::STATIC_DRAW)
}
}
impl<'c, R: RenderSurface> glin::CreationContext for Renderer<'c, R>{
fn capabilities(&self) -> &glin::Capabilities{
self.context.capabilities()
}
fn new_texture(&self) -> texture::Builder{
self.context.new_texture()
}
fn new_cubemap(&self) -> cubemap::Builder{
self.context.new_cubemap()
}
fn new_buffer(&self) -> buffer::Builder{
self.context.new_buffer()
}
fn new_shared_buffer(&self) -> buffer::SharedBuilder{
self.context.new_shared_buffer()
}
fn new_vao(&self) -> vao::Builder{
self.context.new_vao()
}
fn new_simple_vao(&self) -> simple_vao::Builder{
self.context.new_simple_vao()
}
fn new_program(&self) -> program::Builder{
self.context.new_program()
}
fn new_sampler(&self) -> Sampler{
self.context.new_sampler()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
fn new_timestamp_query(&self) -> TimeStamp{
self.context.new_timestamp_query()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
fn new_duration_query(&self) -> Duration{
self.context.new_duration_query()
}
#[cfg(not(any(feature="gles", feature="webgl")))]
fn new_fence(&self) -> Fence{
self.context.new_fence()
}
fn creation_proxy(&self) -> &Rc<glin::CreationProxy>{
self.context.creation_proxy()
}
}
impl<'c> glin::SurfaceCreationContext for Renderer<'c>{
fn new_fbo(&self) -> fbo::Builder{
self.context.new_fbo()
}
fn new_fbo_color_attachment(&self) -> fbo::ColorAttachmentBuilder{
self.context.new_fbo_color_attachment()
}
fn new_fbo_depth_attachment(&self) -> fbo::DepthAttachmentBuilder{
self.context.new_fbo_depth_attachment()
}
fn new_render_buffer(&self) -> fbo::RenderBufferBuilder{
self.context.new_render_buffer()
}
}
pub trait Renderer2d: Renderer3d{
fn draw_mesh_with_material<T, U, M: Material, G: ToSimpleVao<T,U>>(&self, mesh: &G, material: &M)
where T: VertexFormat + Clone + 'static;
fn draw_meshes_with_material<T, U, M: Material, G: ToSimpleVao<T,U>, I: IntoIterator<Item=G>>(&self, mesh: I, material: &M)
where T: VertexFormat + Clone + 'static;
fn draw_meshes_with_trafos_and_material<V, U, M: Material, G: ToSimpleVao<V,U>, T: Into<Model>, I: IntoIterator<Item=(G, T)>>(&self, mesh: I, material: &M)
where V: VertexFormat + Clone + 'static;
fn draw_mesh_with_trafos_and_material<V, U, M: Material, G: ToSimpleVao<V,U>, T: Into<Model>, I: IntoIterator<Item=T>>(&self, mesh: &G, trafos: I, material: &M)
where V: VertexFormat + Clone + 'static;
fn draw_pos<M: Material, R: Render2d<Material=M>>(&self, obj: R, pos: &Pnt2);
fn draw_size<M: Material, R: Render2d<Material=M>>(&self, obj: R, pos: &Pnt2, size: &Vec2);
fn draw_rect<M: Material, R: Render2d<Material=M>>(&self, obj: R, rect: &Rect<f32>);
fn draw_pos_with_material<M: Material, M2: Material, R: Render2d<Material=M>>(&self, obj: R, pos: &Pnt2, mat: &M2);
fn draw_size_with_material<M: Material, M2: Material, R: Render2d<Material=M>>(&self, obj: R, pos: &Pnt2, size: &Vec2, mat: &M2);
fn draw_rect_with_material<M: Material, M2: Material, R: Render2d<Material=M>>(&self, obj: R, rect: &Rect<f32>, mat: &M2);
}
impl<'c, R: RenderSurface + 'c> Renderer2d for Renderer<'c, R>{
fn draw_mesh_with_material<T, U, M: Material, G: ToSimpleVao<T,U>>(&self, mesh: &G, material: &M)
where T: VertexFormat + Clone + 'static
{
self.draw_vao_with_material(self.get_vao(mesh, material.program(self)).full_range(), &material);
}
fn draw_meshes_with_material<T, U, M: Material, G: ToSimpleVao<T,U>, I: IntoIterator<Item=G>>(&self, meshes: I, material: &M)
where T: VertexFormat + Clone + 'static
{
let program = material.program(self);
let uniforms = material.uniforms(self);
let properties = material.properties();
let vao = self.get_vao_for::<T>(program);
let _ = program.set_uniforms(uniforms);
let mvp = &self.mvp;
let needs_camera_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(camera, _model)| *camera != mvp.camera_matrices_id())
.unwrap_or(true);
if needs_camera_uniforms {
self.camera_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::CameraMatrices::uniforms_cache(&program))
.set_uniforms(&mvp.camera_matrices(), program);
}
if !self.model_matrices_as_attributes{
let needs_model_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(_camera, model)| *model != mvp.model_matrices_id())
.unwrap_or(true);
if needs_model_uniforms {
mvp.normal();
self.model_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::ModelMatrices::uniforms_cache(&program))
.set_uniforms(&mvp.model_matrices(), program);
}
if needs_camera_uniforms || needs_model_uniforms {
self.mvp_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::Mvp::uniforms_cache(&program))
.set_uniforms(&mvp, program);
self.last_mvp_set_mut()
.insert(program.unique_id(), (mvp.camera_matrices_id(), mvp.model_matrices_id()));
}
}else if needs_camera_uniforms{
self.last_mvp_set_mut()
.insert(program.unique_id(), (mvp.camera_matrices_id(), -1isize as usize));
}
let gl = self.context.with(properties);
for mesh in meshes.into_iter() {
vao.load(mesh.as_simple_vao_data(), gl::STREAM_DRAW);
let _ = gl.draw(vao.full_range(), program, &[]);
}
}
fn draw_meshes_with_trafos_and_material<V, U, M: Material, G: ToSimpleVao<V,U>, T: Into<Model>, I: IntoIterator<Item=(G, T)>>(&self, meshes: I, material: &M)
where V: VertexFormat + Clone + 'static
{
let program = material.program(self);
let uniforms = material.uniforms(self);
let properties = material.properties();
let vao = self.get_vao_for::<V>(program);
let _ = program.set_uniforms(uniforms);
let mvp = &self.mvp;
let needs_camera_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(camera, _model)| *camera != mvp.camera_matrices_id())
.unwrap_or(true);
if needs_camera_uniforms {
self.camera_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::CameraMatrices::uniforms_cache(&program))
.set_uniforms(&mvp.camera_matrices(), program);
}
let model_uniforms_cache = self.model_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::ModelMatrices::uniforms_cache(&program));
let gl = self.with_properties(properties);
for (mesh, trafo) in meshes.into_iter() {
vao.load(mesh.as_simple_vao_data(), gl::STREAM_DRAW);
let mvp = gl.mvp.for_model(trafo.into());
mvp.normal();
model_uniforms_cache.set_uniforms(&mvp.model_matrices(), program);
let _ = gl.context.draw(vao.full_range(), program, &[]);
}
}
fn draw_mesh_with_trafos_and_material<V, U, M, G, T, I>(&self, mesh: &G, trafos: I, material: &M)
where
V: VertexFormat + Clone + 'static,
M: Material,
G: ToSimpleVao<V,U>,
T: Into<Model>,
I: IntoIterator<Item=T>
{
let program = material.program(self);
let uniforms = material.uniforms(self);
let properties = material.properties();
let vao = self.get_vao(mesh, program);
let _ = program.set_uniforms(uniforms);
let needs_camera_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(camera, _model)| *camera != self.mvp.camera_matrices_id())
.unwrap_or(true);
if needs_camera_uniforms {
self.camera_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::CameraMatrices::uniforms_cache(&program))
.set_uniforms(&self.mvp.camera_matrices(), program);
}
let model_uniforms_cache = self.model_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::ModelMatrices::uniforms_cache(&program));
let gl = self.with_properties(properties);
for trafo in trafos.into_iter() {
let mvp = gl.mvp.for_model(trafo.into());
mvp.normal();
model_uniforms_cache.set_uniforms(&mvp.model_matrices(), program);
let _ = gl.context.draw(vao.full_range(), program, &[]);
}
}
fn draw_pos<M: Material, O: Render2d<Material=M>>(&self, obj: O, pos: &Pnt2){
obj.render(self, pos);
}
fn draw_size<M: Material, O: Render2d<Material=M>>(&self, obj: O, pos: &Pnt2, size: &Vec2){
obj.render_size(self, pos, size);
}
fn draw_rect<M: Material, O: Render2d<Material=M>>(&self, obj: O, rect: &Rect<f32>){
obj.render_size(self, &rect.pos, &vec2(rect.width,rect.height));
}
fn draw_pos_with_material<M: Material, M2: Material, O: Render2d<Material=M>>(&self, obj: O, pos: &Pnt2, mat: &M2){
obj.render_with_material(self, pos, mat);
}
fn draw_size_with_material<M: Material, M2: Material, O: Render2d<Material=M>>(&self, obj: O, pos: &Pnt2, size: &Vec2, mat: &M2){
obj.render_size_with_material(self, pos, size, mat);
}
fn draw_rect_with_material<M: Material, M2: Material, O: Render2d<Material=M>>(&self, obj: O, rect: &Rect<f32>, mat: &M2){
obj.render_size_with_material(self, &rect.pos, &vec2(rect.width,rect.height), mat);
}
}
pub trait Renderer3d{
fn draw<R: Render3d>(&self, obj: &R);
fn draw_with_material<V,M>(&self, obj: &Object<V>, material: &M)
where for<'a> &'a V: VaoDraw,
M: Material;
fn draw_vao_with_material<V, M>(&self, vao: V, material: &M)
where V: VaoDraw,
M: Material;
fn draw_vao_with_model_material<V, M, MO>(&self, vao: V, model: MO, material: &M)
where V: VaoDraw,
M: Material,
MO: Into<graphics::Model>;
fn draw_vao<'a, V, U>(&self, vao_range: V, program: &Program, uniforms: U)
where V: VaoDraw,
U: IntoIterator<Item = &'a glin::program::Uniform>;
fn draw_vao_with_model<'a, V, M, U>(&self, vao_range: V, model: M, program: &Program, uniforms: U)
where V: VaoDraw,
U: IntoIterator<Item = &'a glin::program::Uniform>,
M: Into<graphics::Model>;
fn draw_instanced_vao_with_material<V, M>(&self, obj: V, num_instances: usize, material: &M)
where V: VaoDraw,
M: Material;
fn draw_instanced_vao<'a, V, U>(&self, vao_range: V, num_instances: usize, program: &Program, uniforms: U)
where V: VaoDraw,
U: IntoIterator<Item = &'a glin::program::Uniform>;
}
impl<'c, R: RenderSurface + 'c> Renderer3d for Renderer<'c, R>{
fn draw<O: Render3d>(&self, obj: &O){
obj.render(self);
}
fn draw_with_material<V,M>(&self, obj: &Object<V>, material: &M)
where for<'a> &'a V: VaoDraw,
M: Material
{
self.draw_vao_with_model_material(obj.geometry(), obj, material)
}
fn draw_vao_with_material<V, M>(&self, vao: V, material: &M)
where V: VaoDraw,
M: Material
{
let program = material.program(self);
let uniforms = material.uniforms(self);
let properties = material.properties();
self.draw_vao_with_mvp_properties(vao, &self.mvp, program, uniforms, Some(properties));
}
fn draw_vao_with_model_material<V, M, MO>(&self, vao: V, model: MO, material: &M)
where V: VaoDraw,
M: Material,
MO: Into<graphics::Model>
{
let program = material.program(self);
let uniforms = material.uniforms(self);
let properties = material.properties();
let mvp = self.mvp.for_model(model);
self.draw_vao_with_mvp_properties(vao, &mvp, program, uniforms, Some(properties));
}
fn draw_instanced_vao_with_material<V, M>(&self, vao: V, num_instances: usize, material: &M)
where V: VaoDraw,
M: Material
{
let program = material.program(self);
let uniforms = material.uniforms(self);
let properties = material.properties();
let gl = self.with_properties(properties);
gl.draw_instanced_vao(vao, num_instances, program, uniforms);
}
fn draw_vao_with_model<'a, V, M, U>(&self, vao_range: V, model: M, program: &Program, uniforms: U)
where V: VaoDraw,
U: IntoIterator<Item = &'a glin::program::Uniform>,
M: Into<graphics::Model>
{
let mvp = self.mvp.for_model(model);
self.draw_vao_with_mvp_properties::<_,_,&[_]>(vao_range, &mvp, program, uniforms, None);
}
fn draw_vao<'a, V, U>(&self, vao_range: V, program: &Program, uniforms: U)
where V: VaoDraw,
U: IntoIterator<Item = &'a glin::program::Uniform>
{
self.draw_vao_with_mvp_properties::<_,_,&[_]>(vao_range, &self.mvp, program, uniforms, None);
}
fn draw_instanced_vao<'a, V, U>(&self, vao_range: V, num_instances: usize, program: &Program, uniforms: U)
where V: VaoDraw,
U: IntoIterator<Item = &'a glin::program::Uniform>
{
let needs_camera_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(camera, _model)| *camera != self.mvp.camera_matrices_id())
.unwrap_or(true);
if needs_camera_uniforms {
self.camera_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::CameraMatrices::uniforms_cache(&program))
.set_uniforms(&self.mvp.camera_matrices(), program);
}
if !self.model_matrices_as_attributes{
let needs_model_uniforms = self.last_mvp_set()
.get(program.unique_id() as usize)
.map(|(_camera, model)| *model != self.mvp.model_matrices_id())
.unwrap_or(true);
if needs_model_uniforms {
self.model_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::ModelMatrices::uniforms_cache(&program))
.set_uniforms(&self.mvp.model_matrices(), program);
}
if needs_camera_uniforms || needs_model_uniforms {
self.mvp_uniforms_cache()
.entry(program.unique_id())
.or_insert_with(|| graphics::Mvp::uniforms_cache(&program))
.set_uniforms(&self.mvp, program);
self.last_mvp_set_mut()
.insert(program.unique_id(), (self.mvp.camera_matrices_id(), self.mvp.model_matrices_id()));
}
}else if needs_camera_uniforms{
self.last_mvp_set_mut()
.insert(program.unique_id(), (self.mvp.camera_matrices_id(), -1isize as usize));
}
let _ = self.context.draw_instanced(vao_range, num_instances, program, uniforms);
}
}
pub trait Render3d{
fn render<R: RenderSurface>(&self, renderer: &Renderer<R>) where Self: Sized;
}
impl<T:Clone + VertexFormat + 'static> Render3d for VaoMesh<T>{
fn render<R: RenderSurface>(&self, gl: &Renderer<R>){
let material = BasicMaterial::default();
gl.draw_vao_with_material(self.vao().deref(), &material);
}
}
impl<'a> Render3d for VaoPathFill<'a>{
fn render<R: RenderSurface>(&self, gl: &Renderer<R>){
let material = BasicMaterial::default();
gl.clear_stencil(0);
gl.with_properties(&[
glin::Property::ColorMask([false, false, false, false]),
glin::Property::StencilTest(true),
glin::Property::StencilFunc(gl::ALWAYS, 0x0, 0x1),
glin::Property::StencilOp(gl::KEEP,gl::INVERT,gl::INVERT),
])
.draw_vao(self.vao_mesh().deref(), material.program(gl), material.uniforms(gl));
let bb_vao = gl.get_vao(
&bounding_box_mesh(self.vao_mesh().mesh(), &self.color()),
material.program(gl)
);
gl.with_properties(&[
glin::Property::ColorMask([true, true, true, true]),
glin::Property::StencilTest(true),
glin::Property::StencilFunc(gl::EQUAL, 0x1, 0x1),
glin::Property::StencilOp(gl::KEEP,gl::KEEP,gl::KEEP),
]).draw_vao(bb_vao.full_range(), material.program(gl), material.uniforms(gl));
}
}
#[cfg(not(any(feature="gles", feature="webgl")))]
impl<'a> Render3d for VaoPathContour<'a>{
fn render<R: RenderSurface>(&self, gl: &Renderer<R>){
if self.line_width() == 1. {
let material = &basic_material::Builder::new()
.build();
gl.draw_vao(self.vao_mesh().deref(), material.program(gl), material.uniforms(gl));
}else{
let material = &gl.data.material_thick_lines;
let uniforms = material.uniforms(gl);
let viewport = *gl.context.state().viewport();
let width = match self.line_cap(){
LineCap::Square =>
self.line_width().abs(),
LineCap::Triangular =>
-self.line_width().abs(),
};
let other_uniforms = uniforms!{
viewportSize: vec2(viewport.width() as f32, viewport.height() as f32),
lineWidth: width,
};
let uniforms = uniforms.iter().chain(&other_uniforms);
gl.draw_vao(self.vao_mesh(), material.program(gl), uniforms);
}
}
}
#[cfg(any(feature="gles", feature="webgl"))]
impl<'a> Render3d for VaoPathContour<'a>{
fn render<R: RenderSurface>(&self, gl: &Renderer<R>){
let material = &basic_material::Builder::new()
.create();
gl.with_properties(&[glin::Property::LineWidth(self.line_width())])
.draw_vao(self.vao_mesh(), material.program(gl), material.uniforms(gl));
}
}
pub trait Render2d{
type Material: Material;
fn default_material(&self) -> Self::Material;
fn render<R: RenderSurface>(&self, renderer: &Renderer<R>, pos: &Pnt2){
self.render_with_material(renderer, pos, &self.default_material());
}
fn render_size<R: RenderSurface>(&self, renderer: &Renderer<R>, pos: &Pnt2, size: &Vec2){
self.render_size_with_material(renderer, pos, size, &self.default_material());
}
fn render_with_material<R: RenderSurface, M: Material>(&self, renderer: &Renderer<R>, pos: &Pnt2, material: &M);
fn render_size_with_material<R: RenderSurface, M: Material>(&self, renderer: &Renderer<R>, pos: &Pnt2, size: &Vec2, material: &M);
}
fn bounding_box_mesh<C: ToRgba>(mesh: &graphics::Mesh<Vec2>, color: &C) -> graphics::Mesh<graphics::Vertex2DColor>{
let mut min = Pnt2::new(f32::MAX,f32::MAX);
let mut max = Pnt2::new(f32::MIN,f32::MIN);
for v in mesh.iter(){
if min.x > v.x { min.x = v.x; }
if min.y > v.y { min.y = v.y; }
if max.x < v.x { max.x = v.x; }
if max.y < v.y { max.y = v.y; }
}
let size = max - min;
graphics::rectangle_color(&min, size.x, size.y, color)
}
#[cfg(not(any(feature="gles", feature="webgl")))]
mod shaders{
pub static VERTEX_SHADER_DEFAULT: &'static str = include_str!("shaders/basic_material.vs.glsl");
pub static GEOM_SHADER_THICK_LINES: &'static str = include_str!("shaders/geom_thick_lines.glsl");
pub static FRAGMENT_SHADER_THICK_LINES: &'static str = include_str!("shaders/frag_thick_lines.glsl");
}
#[cfg(any(feature="gles", feature="webgl"))]
mod shaders{
pub static VERTEX_SHADER_DEFAULT: &'static str = include_str!("shaders/basic_material.vs.glsl");
pub static FRAGMENT_SHADER_THICK_LINES: &'static str = include_str!("shaders/basic_material.fs.glsl");
}