use gfx_core::{
format::{ChannelType, DepthFormat, Format, RenderFormat},
handle::{DepthStencilView, RawDepthStencilView, RawRenderTargetView, RenderTargetView},
memory::Typed,
texture,
};
use gfx_device_gl::Resources as R;
use glutin::{NotCurrent, PossiblyCurrent};
type GfxInitTuple<Color, Depth> = (
glutin::WindowedContext<PossiblyCurrent>,
gfx_device_gl::Device,
gfx_device_gl::Factory,
RenderTargetView<R, Color>,
DepthStencilView<R, Depth>,
);
pub trait ContextBuilderExt {
fn with_gfx_color<Color: RenderFormat>(self) -> Self;
fn with_gfx_color_raw(self, color_format: Format) -> Self;
fn with_gfx_depth<Depth: DepthFormat>(self) -> Self;
fn with_gfx_depth_raw(self, ds_format: Format) -> Self;
fn with_gfx_color_depth<Color: RenderFormat, Depth: DepthFormat>(self) -> Self;
}
impl ContextBuilderExt for glutin::ContextBuilder<'_, NotCurrent> {
fn with_gfx_color<Color: RenderFormat>(self) -> Self {
self.with_gfx_color_raw(Color::get_format())
}
fn with_gfx_color_raw(self, Format(surface, channel): Format) -> Self {
let color_total_bits = surface.get_total_bits();
let alpha_bits = surface.get_alpha_stencil_bits();
self.with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
.with_srgb(channel == ChannelType::Srgb)
}
fn with_gfx_depth<Depth: DepthFormat>(self) -> Self {
self.with_gfx_depth_raw(Depth::get_format())
}
fn with_gfx_depth_raw(self, Format(surface, _): Format) -> Self {
let depth_total_bits = surface.get_total_bits();
let stencil_bits = surface.get_alpha_stencil_bits();
self.with_depth_buffer(depth_total_bits - stencil_bits)
.with_stencil_buffer(stencil_bits)
}
fn with_gfx_color_depth<Color: RenderFormat, Depth: DepthFormat>(self) -> Self {
self.with_gfx_color::<Color>().with_gfx_depth::<Depth>()
}
}
pub trait WindowInitExt {
fn init_gfx<Color: RenderFormat, Depth: DepthFormat>(self) -> GfxInitTuple<Color, Depth>;
fn init_gfx_raw(
self,
color_format: Format,
ds_format: Format,
) -> (
glutin::WindowedContext<PossiblyCurrent>,
gfx_device_gl::Device,
gfx_device_gl::Factory,
RawRenderTargetView<R>,
RawDepthStencilView<R>,
);
}
impl WindowInitExt for glutin::WindowedContext<NotCurrent> {
fn init_gfx<Color: RenderFormat, Depth: DepthFormat>(self) -> GfxInitTuple<Color, Depth> {
let (window, device, factory, color_view, ds_view) =
self.init_gfx_raw(Color::get_format(), Depth::get_format());
(
window,
device,
factory,
Typed::new(color_view),
Typed::new(ds_view),
)
}
fn init_gfx_raw(
self,
color_format: Format,
ds_format: Format,
) -> (
glutin::WindowedContext<PossiblyCurrent>,
gfx_device_gl::Device,
gfx_device_gl::Factory,
RawRenderTargetView<R>,
RawDepthStencilView<R>,
) {
let window = unsafe { self.make_current().unwrap() };
let (device, factory) =
gfx_device_gl::create(|s| window.get_proc_address(s) as *const std::os::raw::c_void);
let dim = get_window_dimensions(&window);
let (color_view, ds_view) =
gfx_device_gl::create_main_targets_raw(dim, color_format.0, ds_format.0);
(window, device, factory, color_view, ds_view)
}
}
pub trait WindowUpdateExt {
fn update_gfx<Color: RenderFormat, Depth: DepthFormat>(
&self,
color_view: &mut RenderTargetView<R, Color>,
ds_view: &mut DepthStencilView<R, Depth>,
);
fn updated_views_raw(
&self,
old_dimensions: texture::Dimensions,
color_format: Format,
ds_format: Format,
) -> Option<(RawRenderTargetView<R>, RawDepthStencilView<R>)>;
}
impl WindowUpdateExt for glutin::WindowedContext<PossiblyCurrent> {
fn update_gfx<Color: RenderFormat, Depth: DepthFormat>(
&self,
color_view: &mut RenderTargetView<R, Color>,
ds_view: &mut DepthStencilView<R, Depth>,
) {
let dim = color_view.get_dimensions();
debug_assert_eq!(dim, ds_view.get_dimensions());
if let Some((cv, dv)) =
self.updated_views_raw(dim, Color::get_format(), Depth::get_format())
{
*color_view = Typed::new(cv);
*ds_view = Typed::new(dv);
}
}
fn updated_views_raw(
&self,
old_dimensions: texture::Dimensions,
color_format: Format,
ds_format: Format,
) -> Option<(RawRenderTargetView<R>, RawDepthStencilView<R>)> {
let dim = get_window_dimensions(self);
if dim != old_dimensions {
Some(gfx_device_gl::create_main_targets_raw(
dim,
color_format.0,
ds_format.0,
))
} else {
None
}
}
}
fn get_window_dimensions(ctx: &glutin::WindowedContext<PossiblyCurrent>) -> texture::Dimensions {
let window = ctx.window();
let (width, height) = {
let size = window.inner_size();
(size.width as _, size.height as _)
};
let aa = ctx.get_pixel_format().multisampling.unwrap_or(0) as texture::NumSamples;
(width, height, 1, aa.into())
}