use {
crate::{
camera::{IntoProjection, View},
canvas::CanvasEvent,
color::IntoLinear,
error::*,
framebuffer::FrameFilter,
handles::*,
mesh::Data as MeshData,
pipeline::ParametersBuilder,
render::{Render, RenderContext},
resources::Resources,
screen::Screen,
shader_data::{
InstanceModel, Source, SourceModel, Space, SpaceData, SpaceModel, TextureData,
},
topology::Topology,
transform::IntoMat,
vertex::Vertex,
},
winit::{event_loop::EventLoopProxy, window::Window},
};
type Proxy = EventLoopProxy<CanvasEvent>;
pub struct Context {
pub(crate) window: Window,
pub(crate) proxy: Proxy,
pub(crate) render: Render,
pub(crate) resources: Resources,
limits: Limits,
models: Vec<InstanceModel>,
sources: Vec<SourceModel>,
spaces: Vec<SpaceModel>,
space_data: Vec<SpaceData<'static>>,
}
impl Context {
pub(crate) fn new(window: Window, proxy: Proxy, render_context: RenderContext) -> Self {
const DEFAULT_CAPACITY: usize = 8;
let mut resources = Resources::default();
Self {
window,
proxy,
render: Render::new(render_context, &mut resources),
resources,
limits: Limits::default(),
models: Vec::with_capacity(DEFAULT_CAPACITY),
sources: Vec::with_capacity(DEFAULT_CAPACITY),
spaces: Vec::with_capacity(DEFAULT_CAPACITY),
space_data: Vec::with_capacity(DEFAULT_CAPACITY),
}
}
pub(crate) fn min_frame_delta_time(&self) -> Option<f32> {
self.limits.min_frame_delta_time
}
#[must_use]
pub fn window(&self) -> &Window {
&self.window
}
pub fn plan_to_close(&self) {
_ = self.proxy.send_event(CanvasEvent::Close);
}
#[must_use]
pub fn size(&self) -> (u32, u32) {
self.render.screen().virtual_size()
}
pub fn set_limits(&mut self, limits: Limits) {
self.limits = limits;
}
pub fn set_frame_parameters(&mut self, params: FrameParameters) {
self.render.set_screen(Some(Screen {
pixel_size: params.pixel_size,
filter: params.filter,
..self.render.screen()
}));
}
pub fn create_layer<V, T>(&mut self) -> LayerHandle<V, T>
where
V: Vertex,
T: Topology,
{
self.create_layer_with_parameters().build()
}
pub fn create_layer_with_parameters<V, T>(&mut self) -> ParametersBuilder<V, T> {
ParametersBuilder::new(&self.render, &mut self.resources)
}
pub fn delete_layer<V, T>(
&mut self,
handle: LayerHandle<V, T>,
) -> Result<(), ResourceNotFound> {
self.resources.delete_layer(handle)
}
pub fn create_texture(&mut self, data: TextureData) -> TextureHandle {
self.resources.create_texture(&self.render, data)
}
pub fn update_texture(
&mut self,
handle: TextureHandle,
data: TextureData,
) -> Result<(), Error> {
self.resources.update_texture(&self.render, handle, data)
}
pub fn delete_texture(&mut self, handle: TextureHandle) -> Result<(), ResourceNotFound> {
self.resources.delete_texture(handle)
}
pub fn create_instances<I>(&mut self, data: I) -> InstanceHandle
where
I: IntoIterator,
I::Item: IntoMat,
{
self.models.clear();
let models = data
.into_iter()
.map(|transform| InstanceModel::from(transform.into_mat()));
self.models.extend(models);
self.resources.create_instances(&self.render, &self.models)
}
pub fn update_instances<I>(&mut self, handle: InstanceHandle, data: I) -> Result<(), Error>
where
I: IntoIterator,
I::Item: IntoMat,
{
self.models.clear();
let models = data
.into_iter()
.map(|transform| InstanceModel::from(transform.into_mat()));
self.models.extend(models);
self.resources
.update_instances(&self.render, handle, &self.models)
}
pub fn delete_instances(&mut self, handle: InstanceHandle) -> Result<(), ResourceNotFound> {
self.resources.delete_instances(handle)
}
pub fn create_mesh<V, T>(&mut self, data: &MeshData<V, T>) -> MeshHandle<V, T>
where
V: Vertex,
T: Topology,
{
self.resources.create_mesh(&self.render, data)
}
pub fn delete_mesh<V, T>(&mut self, handle: MeshHandle<V, T>) -> Result<(), ResourceNotFound> {
self.resources.delete_mesh(handle)
}
pub fn create_view<P>(&mut self, view: View<P>) -> ViewHandle
where
P: IntoProjection,
{
self.resources
.create_view(&self.render, view.into_projection_view())
}
pub fn update_view<P>(
&mut self,
handle: ViewHandle,
view: View<P>,
) -> Result<(), ResourceNotFound>
where
P: IntoProjection,
{
self.resources
.update_view(handle, view.into_projection_view())
}
pub fn delete_view(&mut self, handle: ViewHandle) -> Result<(), ResourceNotFound> {
self.resources.delete_view(handle)
}
pub fn create_light<C, I, S>(
&mut self,
ambient: C,
srcs: I,
) -> Result<LightHandle, TooManySources>
where
C: IntoLinear<3>,
I: IntoIterator<Item = Source<S>>,
S: IntoLinear<3>,
{
self.sources.clear();
let models = srcs
.into_iter()
.map(|src| SourceModel::new(src.into_linear()));
self.sources.extend(models);
self.resources
.create_light(&self.render, ambient.into_linear(), &self.sources)
}
pub fn update_light<C, I, S>(
&mut self,
handle: LightHandle,
ambient: C,
srcs: I,
) -> Result<(), Error>
where
C: IntoLinear<3>,
I: IntoIterator<Item = Source<S>>,
S: IntoLinear<3>,
{
self.sources.clear();
let models = srcs
.into_iter()
.map(|src| SourceModel::new(src.into_linear()));
self.sources.extend(models);
self.resources
.update_light(&self.render, handle, ambient.into_linear(), &self.sources)
}
pub fn update_nth_light<S>(
&mut self,
handle: LightHandle,
n: usize,
src: Source<S>,
) -> Result<(), Error>
where
S: IntoLinear<3>,
{
self.resources.update_nth_light(
&self.render,
handle,
n,
SourceModel::new(src.into_linear()),
)
}
pub fn delete_light(&mut self, handle: LightHandle) -> Result<(), ResourceNotFound> {
self.resources.delete_light(handle)
}
pub fn create_space<'a, I, M, C>(&mut self, spaces: I) -> Result<SpaceHandle, TooManySpaces>
where
I: IntoIterator<Item = Space<'a, M, C>>,
M: IntoMat,
C: IntoLinear<3>,
{
use std::mem;
self.spaces.clear();
debug_assert!(self.space_data.is_empty(), "`space_data` is already empty");
let mut space_data = mem::take(&mut self.space_data);
for space in spaces {
space_data.push(space.data);
self.spaces
.push(SpaceModel::new(&space.into_mat_and_linear()));
}
let space = self
.resources
.create_space(&self.render, &self.spaces, &space_data);
space_data.clear();
self.space_data = space_data.into_iter().map(|_| unreachable!()).collect();
space
}
pub fn update_space<'a, I, M, C>(&mut self, handle: SpaceHandle, spaces: I) -> Result<(), Error>
where
I: IntoIterator<Item = Space<'a, M, C>>,
M: IntoMat,
C: IntoLinear<3>,
{
use std::mem;
self.spaces.clear();
debug_assert!(self.space_data.is_empty(), "`space_data` is already empty");
let mut space_data = mem::take(&mut self.space_data);
for space in spaces {
space_data.push(space.data);
self.spaces
.push(SpaceModel::new(&space.into_mat_and_linear()));
}
let updated = self
.resources
.update_space(&self.render, handle, &self.spaces, &space_data);
space_data.clear();
self.space_data = space_data.into_iter().map(|_| unreachable!()).collect();
updated
}
pub fn update_nth_space<M, C>(
&mut self,
handle: SpaceHandle,
n: usize,
space: Space<M, C>,
) -> Result<(), Error>
where
M: IntoMat,
C: IntoLinear<3>,
{
self.resources.update_nth_space(
&self.render,
handle,
n,
SpaceModel::new(&space.into_mat_and_linear()),
)
}
pub fn update_nth_space_color<C>(
&mut self,
handle: SpaceHandle,
n: usize,
color: C,
) -> Result<(), Error>
where
C: IntoLinear<3>,
{
self.resources
.update_nth_space_color(&self.render, handle, n, color.into_linear())
}
pub fn update_nth_space_data(
&mut self,
handle: SpaceHandle,
n: usize,
data: SpaceData,
) -> Result<(), Error> {
self.resources
.update_nth_space_data(&self.render, handle, n, data)
}
pub fn delete_space(&mut self, handle: SpaceHandle) -> Result<(), ResourceNotFound> {
self.resources.delete_space(handle)
}
#[must_use]
pub fn take_screenshot(&self) -> Screenshot {
self.render.take_screenshot()
}
}
#[derive(Clone, Copy)]
pub struct Limits {
pub min_frame_delta_time: Option<f32>,
}
impl Default for Limits {
fn default() -> Self {
const FPS: f32 = 60.;
Self {
min_frame_delta_time: Some(1. / FPS),
}
}
}
#[derive(Clone, Copy, Default)]
pub struct FrameParameters {
pub pixel_size: PixelSize,
pub filter: FrameFilter,
}
#[derive(Clone, Copy, Default)]
pub enum PixelSize {
XHalf,
#[default]
X1,
X2,
X3,
X4,
}
pub struct Screenshot {
pub width: u32,
pub height: u32,
pub data: Vec<u8>,
}