I want to make my own game engine and for that I want that the user later on can use these traits I created to define the game logic and rendering to the screen. Also it should be fairly easy to create the window.
The error comes up in the event loop where I try to call my functions I created earlier but somehow I cant use a function that needs &mut self
. I already tried using Rc
and RefCell
aswell as channels which both did not help me with my problem.
event_loop
.run(move |event, control_flow| {
let mut app = app.lock().unwrap();
match event {
Event::Resumed => {
log::debug!("Resumed");
}
Event::WindowEvent {
ref event,
window_id,
} if window_id == self.window.id() => match event {
WindowEvent::CloseRequested => control_flow.exit(),
WindowEvent::Resized(physical_size) => {
log::info!("physical_size: {physical_size:?}");
surface_configured = false;
// self.resize(*physical_size);
let mut app_ref = app.deref_mut();
app_ref.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
self.window.request_redraw();
app.system.update();
}
_ => {}
},
_ => {}
}
})
.unwrap();
And here is the the full compiler diagnostic:
error[E0596]: cannot borrow `**app_ref` as mutable, as it is behind a `&` reference
--> srccoreengine.rs:141:21
|
141 | app_ref.resize(*physical_size);
| ^^^^^^^ cannot borrow as mutable
How can I fix my code?
Here is the full code:
use std::borrow::BorrowMut;
use std::iter;
use std::ops::DerefMut;
use std::sync::{Arc, Mutex, MutexGuard};
use wgpu::{Device, Queue, Surface, SurfaceConfiguration};
use winit::{
dpi::PhysicalSize,
event::*,
event_loop::{self, EventLoop},
keyboard::{KeyCode, PhysicalKey},
window::{Window, WindowBuilder},
};
pub trait GameSystem {
fn render(&self);
fn update(&self);
fn handle_input(&mut self);
}
#[derive(Debug)]
pub struct Engine<'a, T: GameSystem> {
system: T,
surface: Surface<'a>,
device: Device,
queue: Queue,
config: SurfaceConfiguration,
size: PhysicalSize<u32>,
window: &'a Window,
}
impl<'a, T: GameSystem> Engine<'a, T> {
pub fn new(system: T, window: &'a Window) -> Self {
env_logger::init();
let mut surface_configured = false;
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::PRIMARY,
..Default::default()
});
let surface = instance
.create_surface(window)
.expect("ENGINE_ERROR: Failed to create WGPU Surface");
let (adapter, device, queue) = pollster::block_on(async {
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: Some(&surface),
force_fallback_adapter: false,
})
.await
.expect("ENGINE_ERROR: Failed to Request Adapter");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::default(),
},
None,
)
.await
.expect("ENGINE_ERROR: Failed to request Device");
(adapter, device, queue)
});
let surface_caps = surface.get_capabilities(&adapter);
let surface_format = surface_caps
.formats
.iter()
.copied()
.find(|f| f.is_srgb())
.expect("ENGINE_ERROR: Couln't find surface_format");
let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: surface_format,
width: size.width,
height: size.height,
present_mode: surface_caps.present_modes[0],
alpha_mode: surface_caps.alpha_modes[0],
desired_maximum_frame_latency: 2,
view_formats: vec![],
};
Engine {
system: system,
surface: surface,
device: device,
queue: queue,
config: config,
size: size,
window: window,
}
}
fn render(&mut self) {
let output = self
.surface
.get_current_texture()
.expect("ENGINE_ERROR: Failed getting current surface texture");
let view = output
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.1,
g: 0.2,
b: 0.3,
a: 1.0,
}),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
}
self.queue.submit(iter::once(encoder.finish()));
output.present();
}
fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 {
self.size = new_size;
self.config.width = new_size.width;
self.config.height = new_size.height;
self.surface.configure(&self.device, &self.config)
}
}
pub fn run(&self, event_loop: EventLoop<()>) {
// let mut surface_configured_thread = Arc::clone(&Arc::new(Mutex::new(false)));
let mut surface_configured = false;
let app = Arc::new(Mutex::new(self));
event_loop
.run(move |event, control_flow| {
let mut app = app.lock().unwrap();
match event {
Event::Resumed => {
log::debug!("Resumed");
}
Event::WindowEvent {
ref event,
window_id,
} if window_id == self.window.id() => match event {
WindowEvent::CloseRequested => control_flow.exit(),
WindowEvent::Resized(physical_size) => {
log::info!("physical_size: {physical_size:?}");
surface_configured = false;
// self.resize(*physical_size);
let mut app_ref = app.deref_mut();
app_ref.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
self.window.request_redraw();
app.system.update();
}
_ => {}
},
_ => {}
}
})
.unwrap();
// self.system.handle_input();
// self.system.update();
// self.system.render();
}
}
user26369614 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
The type of app
is Arc<Mutex<&Engine>>
meaning you’ll only get immutable access to the engine since you’re only protecting a shared reference. Your run
only has &self
. If you change it to &mut self
(and avoid using self
in your loop, use app
instead), then it will work.
However, in this case since event_loop.run
loops in-place, it doesn’t require a 'static
lifetime and therefore you don’t need to use Arc
or Mutex
in the first place. Just use self
everywhere:
pub fn run(&mut self, event_loop: EventLoop<()>) {
let mut surface_configured = false;
event_loop
.run(move |event, control_flow| match event {
Event::Resumed => {
log::debug!("Resumed");
}
Event::WindowEvent {
ref event,
window_id,
} if window_id == self.window.id() => match event {
WindowEvent::CloseRequested => control_flow.exit(),
WindowEvent::Resized(physical_size) => {
log::info!("physical_size: {physical_size:?}");
surface_configured = false;
self.resize(*physical_size);
}
WindowEvent::RedrawRequested => {
self.window.request_redraw();
self.system.update();
}
_ => {}
},
_ => {}
})
.unwrap();
}
3