use crate::Settings;
use crate::camera::{Camera, CameraController, CameraUniform};
use crate::data::TransformSettings;
use crate::data::internal::DataUniform;
use crate::data::internal::DataUniformBuilder;
use crate::picker::{self, Picked};
use crate::point_cloud::{DisplayPointCloud, PointCloud, PointCloudMut, UninitedPointCloud};
use crate::post_process;
use crate::sbv::SBV;
use crate::screenshot;
use crate::segment::{DisplaySegment, Segment, SegmentMut, UninitedSegment};
use crate::shape::{
AttachedRenderer, DisplayShape, GraphicalAttachedGeometry, GraphicalContext, Render, Renderer,
Shape, ShapeDescriptor, ShapeGeometry, ShapeMut, UninitedShape,
};
use crate::surface::{DisplaySurface, Surface, SurfaceMut, UninitedSurface};
use crate::texture::TextureBufferPool;
use crate::types::SurfaceIndices;
use crate::types::*;
use egui;
#[cfg(not(target_arch = "wasm32"))]
use egui_winit::clipboard::Clipboard;
use indexmap::IndexMap;
use pollster::FutureExt;
use rand::rngs::SmallRng;
#[cfg(feature = "saves")]
use serde::{Deserialize, Serialize};
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
use web_sys::Clipboard;
#[cfg(feature = "profiling")]
use wgpu_profiler::GpuProfiler;
use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
use winit::{event_loop::EventLoop, window::Window};
mod render_loop;
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(module = "/src/save.js")]
extern "C" {
fn save_state(filename: &str, data: &[u8]);
}
pub trait ContextHolder {
type Context<'a>;
type ExtendedContext<'a>;
type DataUniform;
type TransformUniform; type Renderer<Desc: ShapeDescriptor + ?Sized>;
type AttachedRenderer<Desc: ShapeDescriptor + ?Sized>;
fn get_settings<'a>(ctxt: &'a Self::Context<'_>) -> &'a Settings;
fn reborrow_context<'a: 'b, 'b>(ctxt: &'b mut Self::Context<'a>) -> Self::Context<'b>;
fn notify_refresh_screen(ctxt: &mut Self::Context<'_>, refresh: bool);
fn update_transform<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
transform: &TransformSettings,
ctxt: &Self::Context<'_>,
);
fn update_settings<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
settings: &Desc::Settings,
ctxt: &Self::Context<'_>,
);
fn build_renderer<Desc: ShapeDescriptor + ?Sized>(
geometry: &Desc::Geometry,
transform: &TransformSettings,
settings: &Desc::Settings,
data: Option<&Desc::Data>,
ctxt: &Self::Context<'_>,
) -> Self::Renderer<Desc>;
fn rebuild_fixed_buffer<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
geometry: &Desc::Geometry,
ctxt: &Self::Context<'_>,
);
fn rebuild_data_buffer<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
geometry: &Desc::Geometry,
data: Option<&Desc::Data>,
settings: &Desc::Settings,
ctxt: &Self::Context<'_>,
);
fn rebuild_pipeline<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
data: Option<&Desc::Data>,
settings: &Desc::Settings,
ctxt: &Self::Context<'_>,
);
fn get_renderer_data_uniform<Desc: ShapeDescriptor + ?Sized>(
this: &Self::Renderer<Desc>,
) -> &Self::DataUniform;
fn get_renderer_transform_uniform<Desc: ShapeDescriptor + ?Sized>(
this: &Self::Renderer<Desc>,
) -> &Self::TransformUniform;
fn build_attached_renderer<Desc: ShapeDescriptor + ?Sized>(
geometry: &Desc::Geometry,
settings: &Desc::Settings,
transform: &Self::TransformUniform,
ctxt: &Self::Context<'_>,
) -> Self::AttachedRenderer<Desc>;
}
pub trait ContainersHolder: ContextHolder + Sized {
fn get_containers_mut(
&mut self,
) -> (
&mut IndexMap<String, Surface<Self>>,
&mut IndexMap<String, PointCloud<Self>>,
&mut IndexMap<String, Segment<Self>>,
Self::Context<'_>,
Self::ExtendedContext<'_>,
);
fn get_containers(
&self,
) -> (
&IndexMap<String, Surface<Self>>,
&IndexMap<String, PointCloud<Self>>,
&IndexMap<String, Segment<Self>>,
);
}
pub trait ContainerContextGiver<Shape>: ContainersHolder {
fn get_container_mut(
&mut self,
) -> (
&mut IndexMap<String, Shape>,
Self::Context<'_>,
Self::ExtendedContext<'_>,
);
fn get_container(&self) -> &IndexMap<String, Shape>;
}
impl<State: ContainersHolder> ContainerContextGiver<Surface<State>> for State {
fn get_container_mut(
&mut self,
) -> (
&mut IndexMap<String, Surface<State>>,
Self::Context<'_>,
Self::ExtendedContext<'_>,
) {
let (surf, _pc, _seg, ctxt, ectxt) = self.get_containers_mut();
(surf, ctxt, ectxt)
}
fn get_container(&self) -> &IndexMap<String, Surface<State>> {
self.get_containers().0
}
}
impl<State: ContainersHolder> ContainerContextGiver<PointCloud<State>> for State {
fn get_container_mut(
&mut self,
) -> (
&mut IndexMap<String, PointCloud<State>>,
Self::Context<'_>,
Self::ExtendedContext<'_>,
) {
let (_surf, pc, _seg, ctxt, ectxt) = self.get_containers_mut();
(pc, ctxt, ectxt)
}
fn get_container(&self) -> &IndexMap<String, PointCloud<State>> {
self.get_containers().1
}
}
impl<State: ContainersHolder> ContainerContextGiver<Segment<State>> for State {
fn get_container_mut(
&mut self,
) -> (
&mut IndexMap<String, Segment<State>>,
Self::Context<'_>,
Self::ExtendedContext<'_>,
) {
let (_surf, _pc, seg, ctxt, ectxt) = self.get_containers_mut();
(seg, ctxt, ectxt)
}
fn get_container(&self) -> &IndexMap<String, Segment<State>> {
self.get_containers().2
}
}
pub trait GeometryHolder<Shape>: ContainerContextGiver<Shape> + Sized {
type Args;
fn register(&mut self, name: String, args: Self::Args) -> ShapeMut<'_, Shape, Self>;
fn get_shape_mut(&mut self, name: &str) -> Option<ShapeMut<'_, Shape, Self>>;
fn get_shape(&self, name: &str) -> Option<&'_ Shape>;
fn remove_shape(&mut self, name: &str);
}
impl<Desc> GeometryHolder<UninitedShape<Desc>> for InnerBareState
where
Desc: ShapeDescriptor,
Desc::Attached<InnerGraphicalState>: GraphicalAttachedGeometry,
InnerBareState: ContainerContextGiver<UninitedShape<Desc>>,
{
type Args = <<Desc as ShapeDescriptor>::Geometry as ShapeGeometry>::Args;
fn register(
&mut self,
name: String,
args: Self::Args,
) -> ShapeMut<'_, UninitedShape<Desc>, Self> {
let (container, mut context, _) = self.get_container_mut();
if container.contains_key(&name) {
let shape = container.get_mut(&name).unwrap();
shape.replace_or_create(args, &mut context);
ShapeMut {
inner: shape,
context,
}
} else {
let shape = Shape::new(name.clone(), args, None, &mut context);
container.insert(name.clone(), shape);
ShapeMut {
inner: container.get_mut(&name).unwrap(),
context,
}
}
}
fn get_shape_mut(&mut self, name: &str) -> Option<ShapeMut<'_, UninitedShape<Desc>, Self>> {
let (container, context, _) = self.get_container_mut();
container.get_mut(name).map(|shape| ShapeMut {
inner: shape,
context,
})
}
fn get_shape(&self, name: &str) -> Option<&'_ UninitedShape<Desc>> {
self.get_container().get(name)
}
fn remove_shape(&mut self, name: &str) {
self.get_container_mut().0.shift_remove(name);
}
}
impl<Desc> GeometryHolder<DisplayShape<Desc>> for InnerGraphicalState
where
Desc: ShapeDescriptor,
Renderer<Desc>: Render,
InnerGraphicalState: ContainerContextGiver<DisplayShape<Desc>>,
{
type Args = <<Desc as ShapeDescriptor>::Geometry as ShapeGeometry>::Args;
fn register(
&mut self,
name: String,
args: Self::Args,
) -> ShapeMut<'_, DisplayShape<Desc>, InnerGraphicalState> {
let (container, mut context, (should_resize, counters_dirty, picked)) =
self.get_container_mut();
*context.refresh_screen = true;
if container.contains_key(&name) {
let shape = container.get_mut(&name).unwrap();
if !shape.replace_or_create(args, &mut context) {
*should_resize = true;
*counters_dirty = true;
if let Some((picked_name, _picked)) = picked
&& *picked_name == name
{
*picked = None;
}
}
ShapeMut {
inner: shape,
context: context,
}
} else {
let shape = Shape::new(name.clone(), args, None, &mut context);
container.insert(name.clone(), shape);
*should_resize = true;
*counters_dirty = true;
if let Some((picked_name, _picked)) = picked {
if *picked_name == name {
*picked = None;
}
}
ShapeMut {
inner: container.get_mut(&name).unwrap(),
context,
}
}
}
fn get_shape_mut(
&mut self,
name: &str,
) -> Option<ShapeMut<'_, DisplayShape<Desc>, InnerGraphicalState>> {
let (container, context, _) = self.get_container_mut();
container.get_mut(name).map(|shape| ShapeMut {
inner: shape,
context,
})
}
fn get_shape(&self, name: &str) -> Option<&DisplayShape<Desc>> {
self.get_container().get(name)
}
fn remove_shape(&mut self, name: &str) {
let (container, context, (_should_resize, counters_dirty, picked)) =
self.get_container_mut();
if let Some(shape) = container.shift_remove(name) {
if let Some((picked_name, _picked)) = picked {
if *picked_name == name {
*picked = None;
}
}
*context.refresh_screen |= shape.show;
*counters_dirty = true;
}
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
struct JitterUniform {
x: f32,
y: f32,
_padding: [u32; 2],
}
pub struct InnerGraphicalState {
surfaces: IndexMap<String, DisplaySurface>,
clouds: IndexMap<String, DisplayPointCloud>,
segments: IndexMap<String, DisplaySegment>,
pub(crate) settings: Settings,
window: Option<Arc<Window>>,
proxy: Option<EventLoopProxy<UserEvent>>,
surface: Option<wgpu::Surface<'static>>,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
size: winit::dpi::PhysicalSize<u32>,
texture_buffer_pool: TextureBufferPool,
screenshoter: screenshot::Screenshoter,
ctrl_pressed: bool,
camera: Camera,
camera_controller: CameraController,
camera_uniform: CameraUniform,
camera_buffer: wgpu::Buffer,
jitter_buffer: wgpu::Buffer,
camera_bind_group_layout: wgpu::BindGroupLayout,
camera_bind_group: wgpu::BindGroup,
pub(crate) dirty: bool,
egui_dirty: bool,
should_resize: bool,
pub(crate) picker: picker::Picker,
copy: post_process::TextureCopy,
pbr_renderer: post_process::PBR,
ground: post_process::Ground,
ssao: post_process::SSAO,
taa_counter: u8,
sbv: SBV,
rng: SmallRng,
#[cfg(feature = "profiling")]
profiler: GpuProfiler,
}
impl ContextHolder for InnerGraphicalState {
type Context<'a> = GraphicalContext<'a>;
type ExtendedContext<'a> = (&'a mut bool, &'a mut bool, &'a mut Option<(String, Picked)>);
type DataUniform = Option<DataUniform>;
type TransformUniform = DataUniform;
type Renderer<Desc: ShapeDescriptor + ?Sized> = Renderer<Desc>;
type AttachedRenderer<Desc: ShapeDescriptor + ?Sized> = AttachedRenderer<Desc>;
fn get_settings<'a>(ctxt: &'a Self::Context<'_>) -> &'a Settings {
ctxt.settings
}
fn reborrow_context<'a: 'b, 'b>(ctxt: &'b mut Self::Context<'a>) -> Self::Context<'b> {
GraphicalContext {
settings: ctxt.settings,
device: ctxt.device,
queue: ctxt.queue,
camera_bind_group_layout: ctxt.camera_bind_group_layout,
counter_bind_group_layout: ctxt.counter_bind_group_layout,
refresh_screen: ctxt.refresh_screen,
}
}
fn notify_refresh_screen(ctxt: &mut Self::Context<'_>, refresh: bool) {
*ctxt.refresh_screen |= refresh;
}
fn update_transform<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
transform: &TransformSettings,
ctxt: &Self::Context<'_>,
) {
transform
.to_raw()
.refresh_buffer(ctxt.queue, &this.transform_uniform);
}
fn update_settings<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
settings: &Desc::Settings,
ctxt: &Self::Context<'_>,
) {
settings.refresh_buffer(ctxt.queue, &this.settings_uniform);
}
fn build_renderer<Desc: ShapeDescriptor + ?Sized>(
geometry: &Desc::Geometry,
transform: &TransformSettings,
settings: &Desc::Settings,
data: Option<&Desc::Data>,
ctxt: &Self::Context<'_>,
) -> Self::Renderer<Desc> {
Self::Renderer::<Desc>::new(
ctxt.device,
geometry,
transform,
settings,
data,
ctxt.camera_bind_group_layout,
ctxt.counter_bind_group_layout,
)
}
fn rebuild_fixed_buffer<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
geometry: &Desc::Geometry,
ctxt: &Self::Context<'_>,
) {
this.rebuild_fixed_buffer(ctxt.device, geometry);
}
fn rebuild_data_buffer<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
geometry: &Desc::Geometry,
data: Option<&Desc::Data>,
settings: &Desc::Settings,
ctxt: &Self::Context<'_>,
) {
this.rebuild_data_buffer(
ctxt.device,
geometry,
data,
settings,
ctxt.camera_bind_group_layout,
);
}
fn rebuild_pipeline<Desc: ShapeDescriptor + ?Sized>(
this: &mut Self::Renderer<Desc>,
data: Option<&Desc::Data>,
settings: &Desc::Settings,
ctxt: &Self::Context<'_>,
) {
this.rebuild_pipeline(ctxt.device, data, settings, ctxt.camera_bind_group_layout);
}
fn get_renderer_data_uniform<Desc: ShapeDescriptor + ?Sized>(
this: &Self::Renderer<Desc>,
) -> &Self::DataUniform {
&this.data_uniform
}
fn get_renderer_transform_uniform<Desc: ShapeDescriptor + ?Sized>(
this: &Self::Renderer<Desc>,
) -> &Self::TransformUniform {
&this.transform_uniform
}
fn build_attached_renderer<Desc: ShapeDescriptor + ?Sized>(
geometry: &Desc::Geometry,
settings: &Desc::Settings,
transform: &Self::TransformUniform,
ctxt: &Self::Context<'_>,
) -> Self::AttachedRenderer<Desc> {
AttachedRenderer::new(
ctxt.device,
geometry,
settings,
transform,
ctxt.camera_bind_group_layout,
ctxt.counter_bind_group_layout,
)
}
}
impl ContainersHolder for InnerGraphicalState {
fn get_containers(
&self,
) -> (
&IndexMap<String, Surface<Self>>,
&IndexMap<String, PointCloud<Self>>,
&IndexMap<String, Segment<Self>>,
) {
(&self.surfaces, &self.clouds, &self.segments)
}
fn get_containers_mut(
&mut self,
) -> (
&mut IndexMap<String, Surface<Self>>,
&mut IndexMap<String, PointCloud<Self>>,
&mut IndexMap<String, Segment<Self>>,
Self::Context<'_>,
Self::ExtendedContext<'_>,
) {
(
&mut self.surfaces,
&mut self.clouds,
&mut self.segments,
Self::Context {
settings: &self.settings,
device: &self.device,
queue: &self.queue,
camera_bind_group_layout: &self.camera_bind_group_layout,
counter_bind_group_layout: &self.picker.bind_group_layout,
refresh_screen: &mut self.dirty,
},
(
&mut self.should_resize,
&mut self.picker.counters_dirty,
&mut self.picker.picked_item,
),
)
}
}
impl StateTrait for InnerGraphicalState {
#[cfg(feature = "saves")]
fn load_from_state_slice(&mut self, data: &[u8]) -> Result<(), ()> {
let bared = serde_cbor::from_slice(data).map_err(|_| ())?;
self.receive_save(bared);
Ok(())
}
#[cfg(feature = "saves")]
fn save_state_vec(&self) -> Result<Vec<u8>, ()> {
let surfaces = self
.surfaces
.iter()
.map(|(name, field)| (name.clone(), field.downgrade()))
.collect();
let clouds = self
.clouds
.iter()
.map(|(name, field)| (name.clone(), field.downgrade()))
.collect();
let segments = self
.segments
.iter()
.map(|(name, field)| (name.clone(), field.downgrade()))
.collect();
let bared = InnerBareStateSerde {
settings: self.settings.clone(),
camera: self.camera.clone(),
surfaces,
clouds,
segments,
ground_level: self.ground.level,
};
serde_cbor::to_vec(&bared).map_err(|_| ())
}
fn get_camera(&self) -> &Camera {
&self.camera
}
fn get_camera_mut(&mut self) -> &mut Camera {
self.dirty = true;
&mut self.camera
}
fn get_settings(&self) -> &Settings {
&self.settings
}
fn get_settings_mut(&mut self) -> &mut Settings {
self.dirty = true;
&mut self.settings
}
}
pub struct InnerBareState {
pub(crate) surfaces: IndexMap<String, UninitedSurface>,
pub(crate) clouds: IndexMap<String, UninitedPointCloud>,
pub(crate) segments: IndexMap<String, UninitedSegment>,
pub settings: Settings,
pub camera: Camera,
}
#[cfg(feature = "saves")]
#[derive(Serialize, Deserialize)]
pub(crate) struct InnerBareStateSerde {
pub(crate) surfaces: IndexMap<String, UninitedSurface>,
pub(crate) clouds: IndexMap<String, UninitedPointCloud>,
pub(crate) segments: IndexMap<String, UninitedSegment>,
pub(crate) settings: Settings,
pub(crate) camera: Camera,
pub(crate) ground_level: f32,
}
impl ContextHolder for InnerBareState {
type Context<'a> = &'a mut Settings;
type ExtendedContext<'a> = ();
type DataUniform = ();
type TransformUniform = ();
type Renderer<Desc: ShapeDescriptor + ?Sized> = ();
type AttachedRenderer<Desc: ShapeDescriptor + ?Sized> = ();
fn get_settings<'a>(ctxt: &'a Self::Context<'_>) -> &'a Settings {
ctxt
}
fn reborrow_context<'a: 'b, 'b>(ctxt: &'b mut Self::Context<'a>) -> Self::Context<'b> {
ctxt
}
fn notify_refresh_screen(_ctxt: &mut Self::Context<'_>, _refresh: bool) {}
fn update_transform<Desc: ShapeDescriptor + ?Sized>(
_this: &mut Self::Renderer<Desc>,
_transform: &TransformSettings,
_ctxt: &Self::Context<'_>,
) {
}
fn update_settings<Desc: ShapeDescriptor + ?Sized>(
_this: &mut Self::Renderer<Desc>,
_settings: &Desc::Settings,
_ctxt: &Self::Context<'_>,
) {
}
fn build_renderer<Desc: ShapeDescriptor + ?Sized>(
_geometry: &Desc::Geometry,
_transform: &TransformSettings,
_settings: &Desc::Settings,
_data: Option<&Desc::Data>,
_ctxt: &Self::Context<'_>,
) -> Self::Renderer<Desc> {
()
}
fn rebuild_data_buffer<Desc: ShapeDescriptor + ?Sized>(
_this: &mut Self::Renderer<Desc>,
_geometry: &Desc::Geometry,
_data: Option<&Desc::Data>,
_settings: &Desc::Settings,
_ctxt: &Self::Context<'_>,
) {
}
fn rebuild_fixed_buffer<Desc: ShapeDescriptor + ?Sized>(
_this: &mut Self::Renderer<Desc>,
_geometry: &Desc::Geometry,
_ctxt: &Self::Context<'_>,
) {
}
fn rebuild_pipeline<Desc: ShapeDescriptor + ?Sized>(
_this: &mut Self::Renderer<Desc>,
_data: Option<&Desc::Data>,
_settings: &Desc::Settings,
_ctxt: &Self::Context<'_>,
) {
}
fn get_renderer_data_uniform<Desc: ShapeDescriptor + ?Sized>(
_this: &Self::Renderer<Desc>,
) -> &Self::DataUniform {
&()
}
fn get_renderer_transform_uniform<Desc: ShapeDescriptor + ?Sized>(
_this: &Self::Renderer<Desc>,
) -> &Self::TransformUniform {
&()
}
fn build_attached_renderer<Desc: ShapeDescriptor + ?Sized>(
_geometry: &Desc::Geometry,
_settings: &Desc::Settings,
_transform: &Self::TransformUniform,
_ctxt: &Self::Context<'_>,
) -> Self::AttachedRenderer<Desc> {
()
}
}
impl ContainersHolder for InnerBareState {
fn get_containers(
&self,
) -> (
&IndexMap<String, Surface<Self>>,
&IndexMap<String, PointCloud<Self>>,
&IndexMap<String, Segment<Self>>,
) {
(&self.surfaces, &self.clouds, &self.segments)
}
fn get_containers_mut(
&mut self,
) -> (
&mut IndexMap<String, Surface<Self>>,
&mut IndexMap<String, PointCloud<Self>>,
&mut IndexMap<String, Segment<Self>>,
Self::Context<'_>,
Self::ExtendedContext<'_>,
) {
(
&mut self.surfaces,
&mut self.clouds,
&mut self.segments,
&mut self.settings,
(),
)
}
}
impl StateTrait for InnerBareState {
#[cfg(feature = "saves")]
fn load_from_state_slice(&mut self, data: &[u8]) -> Result<(), ()> {
let bared: InnerBareStateSerde = serde_cbor::from_slice(data).map_err(|_| ())?;
self.surfaces = bared.surfaces;
self.clouds = bared.clouds;
self.segments = bared.segments;
self.settings = bared.settings;
self.camera = bared.camera;
Ok(())
}
#[cfg(feature = "saves")]
fn save_state_vec(&self) -> Result<Vec<u8>, ()> {
let surfaces = self.surfaces.clone();
let clouds = self.clouds.clone();
let segments = self.segments.clone();
let bared = InnerBareStateSerde {
settings: self.settings.clone(),
camera: self.camera.clone(),
surfaces,
clouds,
segments,
ground_level: 0.,
};
serde_cbor::to_vec(&bared).map_err(|_| ())
}
fn get_camera(&self) -> &Camera {
&self.camera
}
fn get_camera_mut(&mut self) -> &mut Camera {
&mut self.camera
}
fn get_settings(&self) -> &Settings {
&self.settings
}
fn get_settings_mut(&mut self) -> &mut Settings {
&mut self.settings
}
}
pub trait StateTrait:
GeometryHolder<Surface<Self>, Args = (SurfaceIndices, Vec<[f32; 3]>)>
+ GeometryHolder<PointCloud<Self>, Args = Vec<[f32; 3]>>
+ GeometryHolder<Segment<Self>, Args = (Vec<[f32; 3]>, Vec<[u32; 2]>)>
{
#[cfg(feature = "saves")]
fn load_from_state_slice(&mut self, data: &[u8]) -> Result<(), ()>;
#[cfg(feature = "saves")]
fn save_state_vec(&self) -> Result<Vec<u8>, ()>;
fn get_camera(&self) -> &Camera;
fn get_camera_mut(&mut self) -> &mut Camera;
fn get_settings(&self) -> &Settings;
fn get_settings_mut(&mut self) -> &mut Settings;
}
pub struct State<T>(pub(crate) T);
impl<T: StateTrait> State<T> {
pub(crate) fn new_inner(inner: T) -> Self {
Self(inner)
}
pub fn register_surface<V: Vertices, I: Into<SurfaceIndices>>(
&'_ mut self,
name: impl Into<String>,
vertices: V,
indices: I,
) -> SurfaceMut<'_, T> {
self.0
.register(name.into(), (indices.into(), vertices.into()))
}
pub fn get_surface_mut(&'_ mut self, name: &str) -> Option<SurfaceMut<'_, T>> {
self.0.get_shape_mut(name)
}
pub fn get_surface(&self, name: &str) -> Option<&Surface<T>> {
self.0.get_shape(name)
}
pub fn remove_surface(&mut self, name: &str) {
<T as GeometryHolder<Surface<T>>>::remove_shape(&mut self.0, name);
}
pub fn register_point_cloud<V: Vertices>(
&'_ mut self,
name: impl Into<String>,
positions: V,
) -> PointCloudMut<'_, T> {
self.0.register(name.into(), positions.into())
}
pub fn get_point_cloud_mut(&'_ mut self, name: &str) -> Option<PointCloudMut<'_, T>> {
self.0.get_shape_mut(name)
}
pub fn get_point_cloud(&self, name: &str) -> Option<&PointCloud<T>> {
self.0.get_shape(name)
}
pub fn remove_point_cloud(&mut self, name: &str) {
<T as GeometryHolder<PointCloud<T>>>::remove_shape(&mut self.0, name);
}
pub fn register_segment<V: Vertices>(
&'_ mut self,
name: impl Into<String>,
positions: V,
connections: Vec<[u32; 2]>,
) -> SegmentMut<'_, T> {
self.0
.register(name.into(), (positions.into(), connections))
}
pub fn get_segment_mut(&'_ mut self, name: &str) -> Option<SegmentMut<'_, T>> {
self.0.get_shape_mut(name)
}
pub fn get_segment(&self, name: &str) -> Option<&Segment<T>> {
self.0.get_shape(name)
}
pub fn remove_segment(&mut self, name: &str) {
<T as GeometryHolder<Segment<T>>>::remove_shape(&mut self.0, name);
}
#[cfg(all(feature = "saves", not(target_arch = "wasm32")))]
pub fn load_from_state_file(&mut self, path: impl AsRef<std::path::Path>) -> Result<(), ()> {
let data = std::fs::read(path.as_ref()).map_err(|_| ())?;
self.0.load_from_state_slice(&data)
}
#[cfg(feature = "saves")]
pub fn load_from_state_slice(&mut self, data: &[u8]) -> Result<(), ()> {
self.0.load_from_state_slice(data)
}
#[cfg(all(feature = "saves", not(target_arch = "wasm32")))]
pub fn save_state_file(&self, path: impl AsRef<std::path::Path>) -> Result<(), ()> {
let data = self.0.save_state_vec()?;
std::fs::write(path.as_ref(), &data).map_err(|_| ())
}
#[cfg(all(feature = "saves", target_arch = "wasm32"))]
pub fn save_state(&self) -> Result<(), ()> {
let data = self.0.save_state_vec()?;
save_state("deuxfleurs.cbor", &data);
Ok(())
}
#[cfg(feature = "saves")]
pub fn save_state_vec(&self) -> Result<Vec<u8>, ()> {
self.0.save_state_vec()
}
pub fn get_settings_mut(&mut self) -> &mut Settings {
self.0.get_settings_mut()
}
pub fn get_settings(&self) -> &Settings {
self.0.get_settings()
}
pub fn set_camera(&mut self, eye: [f32; 3], target: [f32; 3], up: [f32; 3]) {
self.0
.get_camera_mut()
.set_from_eye_target_up(eye, target, up);
}
pub fn get_camera(&self) -> ([f32; 3], [f32; 3], [f32; 3]) {
self.0.get_camera().as_eye_target_up()
}
}
pub type InitialState = State<InnerBareState>;
impl InitialState {
pub fn run<S: Into<String>>(self, width: u32, height: u32, id: Option<S>) {
self.run_with_callback(width, height, id, |_, _| ());
}
#[cfg(not(target_arch = "wasm32"))]
pub fn run_headless(self) -> RunningState {
let inner = InnerGraphicalState::new(
self.0.surfaces,
self.0.clouds,
self.0.segments,
self.0.settings,
self.0.camera,
None,
None,
None,
)
.block_on();
RunningState::new_inner(inner)
}
pub fn run_with_callback<S: Into<String>, U: FnMut(&mut egui::Ui, &mut RunningState)>(
self,
width: u32,
height: u32,
id: Option<S>,
callback: U,
) {
StateWrapper::run(self, width, height, id.map(Into::into), callback);
}
}
pub type RunningState = State<InnerGraphicalState>;
struct StateWrapper<T: FnMut(&mut egui::Ui, &mut RunningState)> {
init_state: Option<InitialState>,
state: Option<RunningState>,
ui: Option<crate::ui::UI>,
clipboard: Option<Clipboard>,
callback: T,
id: String,
width: u32,
height: u32,
proxy: EventLoopProxy<UserEvent>,
}
pub(crate) enum UserEvent {
#[cfg(feature = "surface_button")]
LoadMesh(Vec<[f32; 3]>, crate::types::SurfaceIndices, String),
#[cfg(feature = "saves")]
LoadState(InnerBareStateSerde),
Paste(String),
Pick,
}
impl Deref for RunningState {
type Target = InnerGraphicalState;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for RunningState {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl RunningState {
async fn new(
surfaces: IndexMap<String, UninitedSurface>,
clouds: IndexMap<String, UninitedPointCloud>,
segments: IndexMap<String, UninitedSegment>,
camera: Camera,
settings: Settings,
event_loop: &ActiveEventLoop,
window: Window,
proxy: EventLoopProxy<UserEvent>,
) -> Self {
let inner = InnerGraphicalState::new(
surfaces,
clouds,
segments,
settings,
camera,
Some(event_loop),
Some(window),
Some(proxy),
)
.await;
Self::new_inner(inner)
}
pub fn resize_scene(&mut self) {
self.0.resize_scene();
}
pub fn screenshot(&mut self) {
self.0.screenshot();
}
pub fn screenshot_to_buffer(&mut self) -> Result<Vec<u8>, ()> {
self.0.screenshot_to_buffer()
}
pub fn get_picked(&self) -> &Option<(String, Picked)> {
self.0.get_picked()
}
pub fn refresh(&mut self) {
self.0.refresh();
}
}
impl<T: FnMut(&mut egui::Ui, &mut RunningState)> StateWrapper<T> {
fn run(init_state: InitialState, width: u32, height: u32, id: Option<String>, callback: T) {
let id = id.unwrap_or("deuxfleurs".into());
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
}
#[cfg(feature = "logger")]
cfg_select! {
target_arch = "wasm32" => {
console_log::init_with_level(log::Level::Warn).expect("Couldn't initialize logger");
}
_ => {
env_logger::init();
}
}
let event_loop = EventLoop::<UserEvent>::with_user_event().build().unwrap();
let proxy = event_loop.create_proxy();
let mut app = Self {
init_state: Some(init_state),
state: None,
clipboard: None,
callback,
ui: None,
id,
width,
height,
proxy,
};
event_loop.run_app(&mut app).unwrap();
}
}