sync
This commit is contained in:
parent
fd8b343683
commit
4c0fa9e6ee
29 changed files with 2812 additions and 1172 deletions
960
Cargo.lock
generated
960
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
31
Cargo.toml
31
Cargo.toml
|
@ -2,6 +2,7 @@
|
|||
name = "minemod"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
default-run = "minemod"
|
||||
|
||||
[package.metadata.vita]
|
||||
title_id = "PKDC10002"
|
||||
|
@ -52,29 +53,46 @@ tracing = { version = "0.1.41", features = [
|
|||
] }
|
||||
tracing-subscriber = "0.3.19"
|
||||
log = "0.4.25"
|
||||
pretty_env_logger = "0.5.0"
|
||||
|
||||
anyhow = "1.0.95"
|
||||
thiserror = "2.0.11"
|
||||
|
||||
cgmath = "0.18.0"
|
||||
png = "0.17.16"
|
||||
glam = "0.29.2"
|
||||
#image_full = { package = "image", version = "0.25.5" }
|
||||
#image = { version = "0.25.5", default-features = false }
|
||||
#image_dds = "0.7.1"
|
||||
tbc = "0.3.0"
|
||||
png = "0.17.16" # temporary
|
||||
tobj = { version = "4.0.2", features = ["log"] }
|
||||
rand = "0.9.0"
|
||||
|
||||
[target.'cfg(any(target_os = "windows",target_os = "linux",target_os = "macos"))'.dependencies]
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
glfw = "0.59.0"
|
||||
#glfw = {version = "0.59.0", default-features = false, features = ["raw-window-handle-v0-6"]} # we literally just need the window management parts # nevermind this crashes immediately
|
||||
## OPENGL
|
||||
glutin = "0.32.2"
|
||||
glutin-winit = "0.5.0"
|
||||
#glutin-winit = "0.5.0" # no winit >:(
|
||||
raw-window-handle = "0.6.2"
|
||||
winit = { version = "0.30.0", features = ["rwh_06"] }
|
||||
drm = "0.14.1"
|
||||
# winit is hereby banished from this realm because it pissed me off >:(
|
||||
# its designed around mobile and desktop, but its mobile side sticks around even when its only being used for desktop and theres no way to cut it out
|
||||
# on top of its piss poor documentation around the breaking changes in update 0.3
|
||||
#winit = { version = "0.30.0", features = ["rwh_06"] }
|
||||
#drm = "0.14.1" # unix only
|
||||
## END OPENGL
|
||||
|
||||
## VULKAN
|
||||
vulkanalia = { version = "0.26.0", features = [
|
||||
"libloading",
|
||||
"provisional",
|
||||
"window",
|
||||
] }
|
||||
# kept for now so the vulkan demo works (also the tutorial is using it so once the tutorial is done and i fully understand how vulkan works i will be tossing winit fully and reworking the vulkan structure to better suit the engine)
|
||||
old_winit = { package = "winit", version = "0.29" } # dont update, many many breaking changes with no guides
|
||||
ctrlc = "3.4.5"
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
## END VULKAN
|
||||
|
||||
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||
wgpu = "24.0.0"
|
||||
|
@ -83,7 +101,6 @@ wgpu = "24.0.0"
|
|||
vitasdk-sys = { version = "0.3.3", features = ["all-stubs"] }
|
||||
concat-idents = "1.1.5"
|
||||
libc = "0.2.153"
|
||||
rand = "0.8.5"
|
||||
tokio = { version = "1.36.0", features = [
|
||||
"fs",
|
||||
"macros",
|
||||
|
@ -98,6 +115,8 @@ tokio = { version = "1.36.0", features = [
|
|||
] }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
gfx-backend-dx12 = "0.9.1"
|
||||
gfx-backend-dx11 = "0.9.0"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
|
||||
|
|
9
src/bin/bcntool.rs
Normal file
9
src/bin/bcntool.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use log::*;
|
||||
|
||||
// This tool will be used to convert any common image format to BCn of a specified level or BC1 by default.
|
||||
fn main() {
|
||||
pretty_env_logger::formatted_timed_builder().filter_level(LevelFilter::Info).init();
|
||||
info!("We support BC1, BC3, and BC4 via the tbc crate.");
|
||||
info!("Unfortunately this tool is not currently implemented.");
|
||||
unimplemented!();
|
||||
}
|
|
@ -1,16 +1,104 @@
|
|||
pub(crate) trait GraphicsCommander {}
|
||||
use std::collections::HashMap;
|
||||
|
||||
use glam::Vec3;
|
||||
|
||||
use crate::graphics_engines::Renderable;
|
||||
|
||||
pub struct Cataclysm {
|
||||
game_objects:Vec<GameObject>,
|
||||
pub chunks:HashMap<(u32, u32, u32), CataclysmChunk>,
|
||||
}
|
||||
|
||||
pub struct GameObject {
|
||||
pos:(f64, f64, f64),
|
||||
pub struct CataclysmChunk {
|
||||
pub simple_blocks:HashMap<(u8, u8, u8), SimpleBlock>,
|
||||
pub fancy_blocks: HashMap<Vec3, FancyBlock>,
|
||||
pub smart_blocks: HashMap<Vec3, SmartBlock>,
|
||||
pub entities: Vec<Entity>,
|
||||
}
|
||||
|
||||
pub enum ModelKind {
|
||||
Cube,
|
||||
Complex(),
|
||||
impl Cataclysm {
|
||||
pub const CHUNK_SIZE:u8 = 32;
|
||||
pub const ENTITY_RUN_LIMIT:u8 = 5;
|
||||
pub const WORLD_SIZE:(u8, u8) = (2, 2);
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
chunks: HashMap::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ResourceReference {}
|
||||
impl CataclysmChunk {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
simple_blocks: HashMap::new(),
|
||||
fancy_blocks: HashMap::new(),
|
||||
smart_blocks: HashMap::new(),
|
||||
entities: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimpleBlock {
|
||||
|
||||
}
|
||||
|
||||
impl Renderable for SimpleBlock {
|
||||
#[rustfmt::skip]
|
||||
fn vertext_data<'a>() -> (&'a [f32], &'a [u32]) {
|
||||
(&[
|
||||
-1.0, -1.0, 0.5, //0
|
||||
1.0, -1.0, 0.5, //1
|
||||
-1.0, 1.0, 0.5, //2
|
||||
1.0, 1.0, 0.5, //3
|
||||
-1.0, -1.0, -0.5, //4
|
||||
1.0, -1.0, -0.5, //5
|
||||
-1.0, 1.0, -0.5, //6
|
||||
1.0, 1.0, -0.5 //7
|
||||
],
|
||||
&[
|
||||
//Top
|
||||
2, 6, 7,
|
||||
2, 3, 7,
|
||||
|
||||
//Bottom
|
||||
0, 4, 5,
|
||||
0, 1, 5,
|
||||
|
||||
//Left
|
||||
0, 2, 6,
|
||||
0, 4, 6,
|
||||
|
||||
//Right
|
||||
1, 3, 7,
|
||||
1, 5, 7,
|
||||
|
||||
//Front
|
||||
0, 2, 3,
|
||||
0, 1, 3,
|
||||
|
||||
//Back
|
||||
4, 6, 7,
|
||||
4, 5, 7
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FancyBlock {
|
||||
pub pos:Vec3,
|
||||
}
|
||||
|
||||
pub struct SmartBlock {
|
||||
pub pos:Vec3,
|
||||
}
|
||||
|
||||
pub struct Entity {
|
||||
pub pos:Vec3,
|
||||
}
|
||||
|
||||
//pub enum ModelKind {
|
||||
// Cube,
|
||||
// Complex(),
|
||||
//}
|
||||
|
||||
//pub struct ResourceReference {}
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use glfw::PWindow;
|
||||
|
||||
use crate::cataclysm::Cataclysm;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
pub mod vulkan;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
pub mod vulkan_gc;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
pub mod opengl;
|
||||
|
||||
|
@ -11,3 +20,45 @@ pub mod opengl;
|
|||
#[cfg(target_os = "windows")] pub mod directx;
|
||||
|
||||
#[cfg(target_os = "vita")] pub mod gxm;
|
||||
|
||||
pub trait Renderable {
|
||||
fn vertext_data<'a>() -> (&'a [f32], &'a [u32]);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct VertexData {
|
||||
verts: Box<[f32]>,
|
||||
indices:Box<[u32]>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub trait GraphicsCommander {
|
||||
fn suspend_rendering(&mut self);
|
||||
fn resume_rendering(&mut self);
|
||||
|
||||
// will need a reference to game engine objects
|
||||
// replace with generic draw call? draw call will draw instructions to image, image may be framebuffer or not, allows gpu accelerated dynamic texture stuff
|
||||
fn render(&mut self, window:&mut PWindow, cataclysm:&mut Cataclysm) -> Result<()>;
|
||||
|
||||
/// This function will clear all existing vbos and replace them with its own.
|
||||
fn register_vbos(&mut self, data:&[VertexData]);
|
||||
// make generic for assets?
|
||||
fn register_texture(&mut self);
|
||||
fn destroy_texture(&mut self);
|
||||
|
||||
// cleans up all data from memory, used when exiting or switching graphics backends
|
||||
//fn cleanup(&mut self);
|
||||
fn exit(&mut self);
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum GMode {
|
||||
Vulkan,
|
||||
OpenGL,
|
||||
#[cfg(target_os = "macos")]
|
||||
Metal,
|
||||
#[cfg(target_os = "windows")]
|
||||
DirectX,
|
||||
}
|
||||
|
|
|
@ -1,36 +1,18 @@
|
|||
use std::error::Error;
|
||||
use std::ffi::CStr;
|
||||
use std::ffi::CString;
|
||||
use std::num::NonZeroU32;
|
||||
use std::ops::Deref;
|
||||
use crate::cataclysm::Cataclysm;
|
||||
|
||||
use gl::types::GLfloat;
|
||||
use raw_window_handle::HasWindowHandle;
|
||||
use winit::application::ApplicationHandler;
|
||||
use winit::event::KeyEvent;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::ActiveEventLoop;
|
||||
use winit::keyboard::Key;
|
||||
use winit::keyboard::NamedKey;
|
||||
use winit::window::Window;
|
||||
use winit::window::WindowAttributes;
|
||||
use super::GraphicsCommander;
|
||||
|
||||
use glutin::config::Config;
|
||||
use glutin::config::ConfigTemplateBuilder;
|
||||
use glutin::config::GetGlConfig;
|
||||
use glutin::context::ContextApi;
|
||||
use glutin::context::ContextAttributesBuilder;
|
||||
use glutin::context::NotCurrentContext;
|
||||
use glutin::context::PossiblyCurrentContext;
|
||||
use glutin::context::Version;
|
||||
use glutin::display::GetGlDisplay;
|
||||
use glutin::prelude::*;
|
||||
use glutin::surface::Surface;
|
||||
use glutin::surface::SwapInterval;
|
||||
use glutin::surface::WindowSurface;
|
||||
use anyhow::Result;
|
||||
|
||||
use glutin_winit::DisplayBuilder;
|
||||
use glutin_winit::GlWindow;
|
||||
use glam::vec2;
|
||||
use glam::vec3;
|
||||
|
||||
use glam::Vec2;
|
||||
use glam::Vec3;
|
||||
use glfw::Context;
|
||||
use glfw::PWindow;
|
||||
|
||||
use log::*;
|
||||
|
||||
pub mod gl {
|
||||
#![allow(clippy::all)]
|
||||
|
@ -39,276 +21,136 @@ pub mod gl {
|
|||
pub use Gles2 as Gl;
|
||||
}
|
||||
|
||||
pub fn main(event_loop:winit::event_loop::EventLoop<()>) -> Result<(), Box<dyn Error>> {
|
||||
// The template will match only the configurations supporting rendering
|
||||
// to windows.
|
||||
//
|
||||
// XXX We force transparency only on macOS, given that EGL on X11 doesn't
|
||||
// have it, but we still want to show window. The macOS situation is like
|
||||
// that, because we can query only one config at a time on it, but all
|
||||
// normal platforms will return multiple configs, so we can find the config
|
||||
// with transparency ourselves inside the `reduce`.
|
||||
let template = ConfigTemplateBuilder::new().with_alpha_size(8).with_transparency(cfg!(target_os = "macos"));
|
||||
impl GraphicsCommander for Renderer {
|
||||
fn suspend_rendering(&mut self) {
|
||||
}
|
||||
|
||||
let display_builder = DisplayBuilder::new().with_window_attributes(Some(window_attributes()));
|
||||
fn resume_rendering(&mut self) {
|
||||
}
|
||||
|
||||
let mut app = App::new(template, display_builder);
|
||||
event_loop.run_app(&mut app)?;
|
||||
fn render(&mut self, window:&mut glfw::PWindow, cataclysm:&mut Cataclysm) -> anyhow::Result<()> {
|
||||
let (red, green, blue, alpha) = (0.0125, 0.0094, 0.0071, 1.0);
|
||||
trace!("Clearing screen with color {red}|{green}|{blue}|{alpha}.");
|
||||
unsafe {
|
||||
self.gl.UseProgram(self.program);
|
||||
|
||||
app.exit_state
|
||||
}
|
||||
trace!("Bind.");
|
||||
self.gl.BindVertexArray(self.vao);
|
||||
self.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo);
|
||||
|
||||
impl ApplicationHandler for App {
|
||||
fn resumed(&mut self, event_loop:&ActiveEventLoop) {
|
||||
let (window, gl_config) = match &self.gl_display {
|
||||
// We just created the event loop, so initialize the display, pick the config, and
|
||||
// create the context.
|
||||
GlDisplayCreationState::Builder(display_builder) => {
|
||||
let (window, gl_config) = match display_builder.clone().build(event_loop, self.template.clone(), gl_config_picker) {
|
||||
Ok((window, gl_config)) => (window.unwrap(), gl_config),
|
||||
Err(err) => {
|
||||
self.exit_state = Err(err);
|
||||
event_loop.exit();
|
||||
return;
|
||||
},
|
||||
};
|
||||
|
||||
println!("Picked a config with {} samples", gl_config.num_samples());
|
||||
|
||||
// Mark the display as initialized to not recreate it on resume, since the
|
||||
// display is valid until we explicitly destroy it.
|
||||
self.gl_display = GlDisplayCreationState::Init;
|
||||
|
||||
// Create gl context.
|
||||
self.gl_context = Some(create_gl_context(&window, &gl_config).treat_as_possibly_current());
|
||||
|
||||
(window, gl_config)
|
||||
},
|
||||
GlDisplayCreationState::Init => {
|
||||
println!("Recreating window in `resumed`");
|
||||
// Pick the config which we already use for the context.
|
||||
let gl_config = self.gl_context.as_ref().unwrap().config();
|
||||
match glutin_winit::finalize_window(event_loop, window_attributes(), &gl_config) {
|
||||
Ok(window) => (window, gl_config),
|
||||
Err(err) => {
|
||||
self.exit_state = Err(err.into());
|
||||
event_loop.exit();
|
||||
return;
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let attrs = window.build_surface_attributes(Default::default()).expect("Failed to build surface attributes");
|
||||
let gl_surface = unsafe { gl_config.display().create_window_surface(&gl_config, &attrs).unwrap() };
|
||||
|
||||
// The context needs to be current for the Renderer to set up shaders and
|
||||
// buffers. It also performs function loading, which needs a current context on
|
||||
// WGL.
|
||||
let gl_context = self.gl_context.as_ref().unwrap();
|
||||
gl_context.make_current(&gl_surface).unwrap();
|
||||
|
||||
self.renderer.get_or_insert_with(|| Renderer::new(&gl_config.display()));
|
||||
|
||||
// Try setting vsync.
|
||||
if let Err(res) = gl_surface.set_swap_interval(gl_context, SwapInterval::Wait(NonZeroU32::new(1).unwrap())) {
|
||||
eprintln!("Error setting vsync: {res:?}");
|
||||
trace!("ClearColor.");
|
||||
self.gl.ClearColor(red, green, blue, alpha);
|
||||
trace!("Clear.");
|
||||
self.gl.Clear(gl::COLOR_BUFFER_BIT);
|
||||
trace!("DrawArrays.");
|
||||
self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
|
||||
}
|
||||
trace!("Done clearing screen.");
|
||||
|
||||
assert!(self.state.replace(AppState { gl_surface, window }).is_none());
|
||||
window.swap_buffers();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn suspended(&mut self, _event_loop:&ActiveEventLoop) {
|
||||
// This event is only raised on Android, where the backing NativeWindow for a GL
|
||||
// Surface can appear and disappear at any moment.
|
||||
println!("Android window removed");
|
||||
fn register_texture(&mut self) { todo!() }
|
||||
|
||||
// Destroy the GL Surface and un-current the GL Context before ndk-glue releases
|
||||
// the window back to the system.
|
||||
self.state = None;
|
||||
fn destroy_texture(&mut self) { todo!() }
|
||||
|
||||
// Make context not current.
|
||||
self.gl_context = Some(self.gl_context.take().unwrap().make_not_current().unwrap().treat_as_possibly_current());
|
||||
}
|
||||
//fn cleanup(&mut self) { todo!() }
|
||||
|
||||
fn window_event(&mut self, event_loop:&ActiveEventLoop, _window_id:winit::window::WindowId, event:WindowEvent) {
|
||||
match event {
|
||||
WindowEvent::Resized(size) if size.width != 0 && size.height != 0 => {
|
||||
// Some platforms like EGL require resizing GL surface to update the size
|
||||
// Notable platforms here are Wayland and macOS, other don't require it
|
||||
// and the function is no-op, but it's wise to resize it for portability
|
||||
// reasons.
|
||||
if let Some(AppState { gl_surface, window: _ }) = self.state.as_ref() {
|
||||
let gl_context = self.gl_context.as_ref().unwrap();
|
||||
gl_surface.resize(gl_context, NonZeroU32::new(size.width).unwrap(), NonZeroU32::new(size.height).unwrap());
|
||||
|
||||
let renderer = self.renderer.as_ref().unwrap();
|
||||
renderer.resize(size.width as i32, size.height as i32);
|
||||
}
|
||||
},
|
||||
WindowEvent::CloseRequested |
|
||||
WindowEvent::KeyboardInput {
|
||||
event: KeyEvent {
|
||||
logical_key: Key::Named(NamedKey::Escape),
|
||||
..
|
||||
},
|
||||
..
|
||||
} => event_loop.exit(),
|
||||
_ => (),
|
||||
fn exit(&mut self) {
|
||||
trace!("Destroying OpenGL instance.");
|
||||
unsafe {
|
||||
self.gl.DeleteProgram(self.program);
|
||||
for vbo in self.vbos.iter().take(self.vbos.len()) {
|
||||
self.gl.DeleteBuffers(1, vbo);
|
||||
}
|
||||
self.gl.DeleteVertexArrays(1, &self.vao);
|
||||
}
|
||||
}
|
||||
|
||||
fn exiting(&mut self, _event_loop:&ActiveEventLoop) {
|
||||
// NOTE: The handling below is only needed due to nvidia on Wayland to not crash
|
||||
// on exit due to nvidia driver touching the Wayland display from on
|
||||
// `exit` hook.
|
||||
let _gl_display = self.gl_context.take().unwrap().display();
|
||||
|
||||
// Clear the window.
|
||||
self.state = None;
|
||||
#[cfg(egl_backend)]
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
if let glutin::display::Display::Egl(display) = _gl_display {
|
||||
fn register_vbos(&mut self, data:&[super::VertexData]) {
|
||||
for data in data {
|
||||
trace!("Creating OpenGL VAO.");
|
||||
unsafe {
|
||||
display.terminate();
|
||||
let mut vao = std::mem::zeroed();
|
||||
self.gl.GenVertexArrays(1, &mut vao);
|
||||
self.gl.BindVertexArray(vao);
|
||||
}
|
||||
trace!("Creating OpenGL VBO.");
|
||||
unsafe {
|
||||
let mut vbo = std::mem::zeroed();
|
||||
self.gl.GenBuffers(1, &mut vbo);
|
||||
self.gl.BindBuffer(gl::ARRAY_BUFFER, vbo);
|
||||
self.gl.BufferData(
|
||||
gl::ARRAY_BUFFER,
|
||||
(VERTEX_DATA.len() * std::mem::size_of::<Vertex>()) as gl::types::GLsizeiptr,
|
||||
VERTEX_DATA.as_ptr() as *const _,
|
||||
gl::STATIC_DRAW,
|
||||
);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
trace!("Applying shader attributes.");
|
||||
let pos_attrib = self.gl.GetAttribLocation( self.program, b"position\0".as_ptr() as *const _);
|
||||
let color_attrib = self.gl.GetAttribLocation(self.program, b"color\0".as_ptr() as *const _);
|
||||
self.gl.VertexAttribPointer(
|
||||
pos_attrib as gl::types::GLuint,
|
||||
2,
|
||||
gl::FLOAT,
|
||||
0,
|
||||
std::mem::size_of::<Vertex>() as gl::types::GLsizei,
|
||||
std::ptr::null(),
|
||||
);
|
||||
self.gl.VertexAttribPointer(
|
||||
color_attrib as gl::types::GLuint,
|
||||
3,
|
||||
gl::FLOAT,
|
||||
0,
|
||||
5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
|
||||
(2 * std::mem::size_of::<f32>()) as *const () as *const _,
|
||||
);
|
||||
self.gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint);
|
||||
self.gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn about_to_wait(&mut self, _event_loop:&ActiveEventLoop) {
|
||||
if let Some(AppState { gl_surface, window }) = self.state.as_ref() {
|
||||
let gl_context = self.gl_context.as_ref().unwrap();
|
||||
let renderer = self.renderer.as_ref().unwrap();
|
||||
renderer.draw();
|
||||
window.request_redraw();
|
||||
|
||||
gl_surface.swap_buffers(gl_context).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_gl_context(window:&Window, gl_config:&Config) -> NotCurrentContext {
|
||||
let raw_window_handle = window.window_handle().ok().map(|wh| wh.as_raw());
|
||||
|
||||
// The context creation part.
|
||||
let context_attributes = ContextAttributesBuilder::new().build(raw_window_handle);
|
||||
|
||||
// Since glutin by default tries to create OpenGL core context, which may not be
|
||||
// present we should try gles.
|
||||
let fallback_context_attributes = ContextAttributesBuilder::new()
|
||||
.with_context_api(ContextApi::Gles(None))
|
||||
.build(raw_window_handle);
|
||||
|
||||
// There are also some old devices that support neither modern OpenGL nor GLES.
|
||||
// To support these we can try and create a 2.1 context.
|
||||
let legacy_context_attributes = ContextAttributesBuilder::new()
|
||||
.with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1))))
|
||||
.build(raw_window_handle);
|
||||
|
||||
// Reuse the uncurrented context from a suspended() call if it exists, otherwise
|
||||
// this is the first time resumed() is called, where the context still
|
||||
// has to be created.
|
||||
let gl_display = gl_config.display();
|
||||
|
||||
unsafe {
|
||||
gl_display.create_context(gl_config, &context_attributes).unwrap_or_else(|_| {
|
||||
gl_display.create_context(gl_config, &fallback_context_attributes).unwrap_or_else(|_| {
|
||||
gl_display
|
||||
.create_context(gl_config, &legacy_context_attributes)
|
||||
.expect("failed to create context")
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn window_attributes() -> WindowAttributes {
|
||||
Window::default_attributes()
|
||||
.with_transparent(true)
|
||||
.with_title("Glutin triangle gradient example (press Escape to exit)")
|
||||
}
|
||||
|
||||
enum GlDisplayCreationState {
|
||||
/// The display was not build yet.
|
||||
Builder(DisplayBuilder),
|
||||
/// The display was already created for the application.
|
||||
Init,
|
||||
}
|
||||
|
||||
struct App {
|
||||
template: ConfigTemplateBuilder,
|
||||
renderer: Option<Renderer>,
|
||||
// NOTE: `AppState` carries the `Window`, thus it should be dropped after everything else.
|
||||
state: Option<AppState>,
|
||||
gl_context:Option<PossiblyCurrentContext>,
|
||||
gl_display:GlDisplayCreationState,
|
||||
exit_state:Result<(), Box<dyn Error>>,
|
||||
}
|
||||
|
||||
impl App {
|
||||
fn new(template:ConfigTemplateBuilder, display_builder:DisplayBuilder) -> Self {
|
||||
Self {
|
||||
template,
|
||||
gl_display:GlDisplayCreationState::Builder(display_builder),
|
||||
exit_state:Ok(()),
|
||||
gl_context:None,
|
||||
state:None,
|
||||
renderer:None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AppState {
|
||||
gl_surface:Surface<WindowSurface>,
|
||||
// NOTE: Window should be dropped after all resources created using its
|
||||
// raw-window-handle.
|
||||
window: Window,
|
||||
}
|
||||
|
||||
// Find the config with the maximum number of samples, so our triangle will be
|
||||
// smooth.
|
||||
pub fn gl_config_picker(configs:Box<dyn Iterator<Item=Config>+'_>) -> Config {
|
||||
configs
|
||||
.reduce(|accum, config| {
|
||||
let transparency_check = config.supports_transparency().unwrap_or(false) & !accum.supports_transparency().unwrap_or(false);
|
||||
|
||||
if transparency_check || config.num_samples() > accum.num_samples() {
|
||||
config
|
||||
} else {
|
||||
accum
|
||||
}
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
use std::ffi::CStr;
|
||||
use std::ops::Deref;
|
||||
|
||||
pub struct Renderer {
|
||||
program:gl::types::GLuint,
|
||||
vao: gl::types::GLuint,
|
||||
vbo: gl::types::GLuint,
|
||||
vbos: Vec<gl::types::GLuint>,
|
||||
//vbo: gl::types::GLuint,
|
||||
gl: gl::Gl,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn new<D:GlDisplay>(gl_display:&D) -> Self {
|
||||
pub fn create(window:&mut PWindow) -> Result<Self> {
|
||||
trace!("Creating OpenGL renderer instance.");
|
||||
|
||||
unsafe {
|
||||
let gl = gl::Gl::load_with(|symbol| {
|
||||
let symbol = CString::new(symbol).unwrap();
|
||||
gl_display.get_proc_address(symbol.as_c_str()).cast()
|
||||
});
|
||||
let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));
|
||||
|
||||
if let Some(renderer) = get_gl_string(&gl, gl::RENDERER) {
|
||||
println!("Running on {}", renderer.to_string_lossy());
|
||||
info!("Running on {}", renderer.to_string_lossy());
|
||||
}
|
||||
if let Some(version) = get_gl_string(&gl, gl::VERSION) {
|
||||
println!("OpenGL Version {}", version.to_string_lossy());
|
||||
info!("OpenGL Version {}", version.to_string_lossy());
|
||||
}
|
||||
|
||||
if let Some(shaders_version) = get_gl_string(&gl, gl::SHADING_LANGUAGE_VERSION) {
|
||||
println!("Shaders version on {}", shaders_version.to_string_lossy());
|
||||
info!("Shaders version on {}", shaders_version.to_string_lossy());
|
||||
}
|
||||
|
||||
trace!("Loading shaders.");
|
||||
let vertex_shader = create_shader(&gl, gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE);
|
||||
let fragment_shader = create_shader(&gl, gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);
|
||||
|
||||
trace!("Creating OpenGL shader program.");
|
||||
let program = gl.CreateProgram();
|
||||
|
||||
gl.AttachShader(program, vertex_shader);
|
||||
|
@ -318,60 +160,12 @@ impl Renderer {
|
|||
|
||||
gl.UseProgram(program);
|
||||
|
||||
trace!("Deleting shader objects.");
|
||||
gl.DeleteShader(vertex_shader);
|
||||
gl.DeleteShader(fragment_shader);
|
||||
|
||||
let mut vao = std::mem::zeroed();
|
||||
gl.GenVertexArrays(1, &mut vao);
|
||||
gl.BindVertexArray(vao);
|
||||
|
||||
let mut vbo = std::mem::zeroed();
|
||||
gl.GenBuffers(1, &mut vbo);
|
||||
gl.BindBuffer(gl::ARRAY_BUFFER, vbo);
|
||||
gl.BufferData(
|
||||
gl::ARRAY_BUFFER,
|
||||
(VERTEX_DATA.len() * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr,
|
||||
VERTEX_DATA.as_ptr() as *const _,
|
||||
gl::STATIC_DRAW,
|
||||
);
|
||||
|
||||
let pos_attrib = gl.GetAttribLocation(program, b"position\0".as_ptr() as *const _);
|
||||
let color_attrib = gl.GetAttribLocation(program, b"color\0".as_ptr() as *const _);
|
||||
gl.VertexAttribPointer(
|
||||
pos_attrib as gl::types::GLuint,
|
||||
2,
|
||||
gl::FLOAT,
|
||||
0,
|
||||
5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
|
||||
std::ptr::null(),
|
||||
);
|
||||
gl.VertexAttribPointer(
|
||||
color_attrib as gl::types::GLuint,
|
||||
3,
|
||||
gl::FLOAT,
|
||||
0,
|
||||
5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
|
||||
(2 * std::mem::size_of::<f32>()) as *const () as *const _,
|
||||
);
|
||||
gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint);
|
||||
gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint);
|
||||
|
||||
Self { program, vao, vbo, gl }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self) { self.draw_with_clear_color(0.1, 0.1, 0.1, 0.9) }
|
||||
|
||||
pub fn draw_with_clear_color(&self, red:GLfloat, green:GLfloat, blue:GLfloat, alpha:GLfloat) {
|
||||
unsafe {
|
||||
self.gl.UseProgram(self.program);
|
||||
|
||||
self.gl.BindVertexArray(self.vao);
|
||||
self.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo);
|
||||
|
||||
self.gl.ClearColor(red, green, blue, alpha);
|
||||
self.gl.Clear(gl::COLOR_BUFFER_BIT);
|
||||
self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
|
||||
trace!("OpenGL renderer instance created.");
|
||||
Ok(Self { program, vao, vbos:vec![], gl })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,16 +182,6 @@ impl Deref for Renderer {
|
|||
fn deref(&self) -> &Self::Target { &self.gl }
|
||||
}
|
||||
|
||||
impl Drop for Renderer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.gl.DeleteProgram(self.program);
|
||||
self.gl.DeleteBuffers(1, &self.vbo);
|
||||
self.gl.DeleteVertexArrays(1, &self.vao);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn create_shader(gl:&gl::Gl, shader:gl::types::GLenum, source:&[u8]) -> gl::types::GLuint {
|
||||
let shader = gl.CreateShader(shader);
|
||||
gl.ShaderSource(shader, 1, [source.as_ptr().cast()].as_ptr(), std::ptr::null());
|
||||
|
@ -412,12 +196,72 @@ fn get_gl_string(gl:&gl::Gl, variant:gl::types::GLenum) -> Option<&'static CStr>
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Vertex {
|
||||
pos: Vec2,
|
||||
color:Vec3,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
static VERTEX_DATA: [f32; 15] = [
|
||||
-0.5, -0.5, 1.0, 0.0, 0.0,
|
||||
0.0, 0.5, 0.0, 1.0, 0.0,
|
||||
0.5, -0.5, 0.0, 0.0, 1.0,
|
||||
static VERTEX_DATA: [Vertex; 3] = [
|
||||
//-0.5, -0.5, 1.0, 0.0, 0.0,
|
||||
// 0.0, 0.5, 0.0, 1.0, 0.0,
|
||||
// 0.5, -0.5, 0.0, 0.0, 1.0,
|
||||
Vertex::new(vec2(-0.5, -0.5), vec3(0.3, 0.0, 1.0)),
|
||||
Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)),
|
||||
Vertex::new(vec2(0.5, -0.5), vec3(0.3, 0.0, 1.0)),
|
||||
//Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)),
|
||||
];
|
||||
impl Vertex {
|
||||
const fn new(pos:Vec2, color:Vec3) -> Self { Self { pos, color } }
|
||||
|
||||
//fn binding_description() -> vk::VertexInputBindingDescription {
|
||||
// vk::VertexInputBindingDescription::builder()
|
||||
// .binding(0)
|
||||
// .stride(size_of::<Vertex>() as u32)
|
||||
// .input_rate(vk::VertexInputRate::VERTEX)
|
||||
// .build()
|
||||
//}
|
||||
|
||||
//fn attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] {
|
||||
// let pos = vk::VertexInputAttributeDescription::builder()
|
||||
// .binding(0)
|
||||
// .location(0)
|
||||
// .format(vk::Format::R32G32_SFLOAT)
|
||||
// .offset(0)
|
||||
// .build();
|
||||
|
||||
// let color = vk::VertexInputAttributeDescription::builder()
|
||||
// .binding(0)
|
||||
// .location(1)
|
||||
// .format(vk::Format::R32G32B32_SFLOAT)
|
||||
// .offset(size_of::<Vec2f>() as u32)
|
||||
// .build();
|
||||
|
||||
// [pos, color]
|
||||
//}
|
||||
}
|
||||
|
||||
const VERTEX_SHADER_SOURCE2:&[u8] = b"
|
||||
#version 450
|
||||
|
||||
layout(binding = 0) uniform UniformBufferObject {
|
||||
mat4 model;
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
} ubo;
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
|
||||
void main() {
|
||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);
|
||||
fragColor = inColor;
|
||||
}
|
||||
\0";
|
||||
|
||||
const VERTEX_SHADER_SOURCE:&[u8] = b"
|
||||
#version 100
|
||||
|
@ -429,8 +273,20 @@ attribute vec3 color;
|
|||
varying vec3 v_color;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
v_color = color;
|
||||
gl_Position = vec4(position, 0.0, 1.0);
|
||||
v_color = color;
|
||||
}
|
||||
\0";
|
||||
|
||||
const FRAGMENT_SHADER_SOURCE2:&[u8] = b"
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
}
|
||||
\0";
|
||||
|
||||
|
|
|
@ -29,7 +29,12 @@ use vulkanalia::vk::ExtDebugUtilsExtension;
|
|||
use vulkanalia::vk::KhrSurfaceExtension;
|
||||
use vulkanalia::vk::KhrSwapchainExtension;
|
||||
|
||||
use old_winit::dpi::LogicalSize;
|
||||
use old_winit::event::Event;
|
||||
use old_winit::event::WindowEvent;
|
||||
use old_winit::event_loop::EventLoop;
|
||||
use old_winit::window::Window;
|
||||
use old_winit::window::WindowBuilder;
|
||||
|
||||
type Vec2f = cgmath::Vector2<f32>;
|
||||
type Vec3f = cgmath::Vector3<f32>;
|
||||
|
@ -84,6 +89,73 @@ macro_rules! const_shaders {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn start() -> Result<()> {
|
||||
info!("Initializing event loop and winit window instance.");
|
||||
|
||||
// Window
|
||||
|
||||
let event_loop = EventLoop::new()?;
|
||||
let window = WindowBuilder::new()
|
||||
.with_title("WHAT")
|
||||
.with_inner_size(LogicalSize::new(1024, 768))
|
||||
.build(&event_loop)?;
|
||||
|
||||
info!("Creating app and starting event loop.");
|
||||
|
||||
// App
|
||||
|
||||
let mut app = unsafe { App::create(&window)? };
|
||||
let mut minimized = false;
|
||||
|
||||
//let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx)));
|
||||
|
||||
event_loop.run(move |event, elwt| {
|
||||
//let mut shutdown_rx_guard = shutdown_rx.lock().unwrap();
|
||||
|
||||
//if let Some(receiver) = shutdown_rx_guard.as_mut() {
|
||||
// if receiver.try_recv().is_ok() {
|
||||
// info!("Closing event loop and destroying Vulkan instance.");
|
||||
// elwt.exit();
|
||||
// unsafe {
|
||||
// app.device.device_wait_idle().unwrap();
|
||||
// app.destroy();
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
|
||||
match event {
|
||||
// Request a redraw when all events were processed.
|
||||
Event::AboutToWait => window.request_redraw(),
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
// Render a frame if our Vulkan app is not being destroyed.
|
||||
WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => {
|
||||
unsafe { app.render(&window) }.unwrap();
|
||||
},
|
||||
WindowEvent::Resized(size) =>
|
||||
if size.width == 0 || size.height == 0 {
|
||||
minimized = true;
|
||||
} else {
|
||||
minimized = false;
|
||||
app.resized = true;
|
||||
},
|
||||
// Destroy our Vulkan app.
|
||||
WindowEvent::CloseRequested => {
|
||||
info!("Closing event loop and destroying Vulkan instance.");
|
||||
elwt.exit();
|
||||
unsafe {
|
||||
app.device.device_wait_idle().unwrap();
|
||||
app.destroy();
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Our Vulkan app.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct App {
|
||||
|
@ -1398,7 +1470,7 @@ unsafe fn copy_buffer_to_image(device:&Device, data:&AppData, buffer:vk::Buffer,
|
|||
|
||||
unsafe fn create_texture_image_view(device:&Device, data:&mut AppData) -> Result<()> {
|
||||
data.texture_image_view = create_image_view(device, data.texture_image, vk::Format::R8G8B8A8_SRGB)?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
1449
src/graphics_engines/vulkan_gc.rs
Normal file
1449
src/graphics_engines/vulkan_gc.rs
Normal file
File diff suppressed because it is too large
Load diff
116
src/linux.rs
116
src/linux.rs
|
@ -1,116 +0,0 @@
|
|||
use std::process::exit;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use log::*;
|
||||
|
||||
use vulkanalia::prelude::v1_0::*;
|
||||
|
||||
use old_winit::dpi::LogicalSize;
|
||||
use old_winit::event::Event;
|
||||
use old_winit::event::WindowEvent;
|
||||
use old_winit::event_loop::EventLoop;
|
||||
use old_winit::window::WindowBuilder;
|
||||
|
||||
use crate::graphics_engines;
|
||||
use crate::graphics_engines::vulkan::App;
|
||||
|
||||
const WINDOW_TITLE:&'static str = "MineMod";
|
||||
|
||||
const GRAPHICS_MODE:GMode = GMode::OpenGL;
|
||||
|
||||
enum GMode {
|
||||
Vulkan,
|
||||
OpenGL,
|
||||
}
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
super::init_logging();
|
||||
|
||||
info!("Registering CTRLC hook.");
|
||||
|
||||
let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
shutdown_tx.send(()).expect("Failed to send shutdown signal");
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
match GRAPHICS_MODE {
|
||||
GMode::Vulkan => {
|
||||
info!("Initializing event loop and winit window instance.");
|
||||
|
||||
// Window
|
||||
|
||||
let event_loop = EventLoop::new()?;
|
||||
let window = WindowBuilder::new()
|
||||
.with_title(WINDOW_TITLE)
|
||||
.with_inner_size(LogicalSize::new(1024, 768))
|
||||
.build(&event_loop)?;
|
||||
|
||||
info!("Creating app and starting event loop.");
|
||||
|
||||
// App
|
||||
|
||||
let mut app = unsafe { App::create(&window)? };
|
||||
let mut minimized = false;
|
||||
|
||||
let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx)));
|
||||
|
||||
event_loop.run(move |event, elwt| {
|
||||
let mut shutdown_rx_guard = shutdown_rx.lock().unwrap();
|
||||
|
||||
if let Some(receiver) = shutdown_rx_guard.as_mut() {
|
||||
if receiver.try_recv().is_ok() {
|
||||
info!("Closing event loop and destroying Vulkan instance.");
|
||||
elwt.exit();
|
||||
unsafe {
|
||||
app.device.device_wait_idle().unwrap();
|
||||
app.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
match event {
|
||||
// Request a redraw when all events were processed.
|
||||
Event::AboutToWait => window.request_redraw(),
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
// Render a frame if our Vulkan app is not being destroyed.
|
||||
WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => {
|
||||
unsafe { app.render(&window) }.unwrap();
|
||||
},
|
||||
WindowEvent::Resized(size) =>
|
||||
if size.width == 0 || size.height == 0 {
|
||||
minimized = true;
|
||||
} else {
|
||||
minimized = false;
|
||||
app.resized = true;
|
||||
},
|
||||
// Destroy our Vulkan app.
|
||||
WindowEvent::CloseRequested => {
|
||||
info!("Closing event loop and destroying Vulkan instance.");
|
||||
elwt.exit();
|
||||
unsafe {
|
||||
app.device.device_wait_idle().unwrap();
|
||||
app.destroy();
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
})?;
|
||||
},
|
||||
GMode::OpenGL => {
|
||||
if let Err(error) = graphics_engines::opengl::main(winit::event_loop::EventLoop::new()?) {
|
||||
error!("gl error {error}");
|
||||
exit(-1);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
info!("Exiting program.");
|
||||
|
||||
Ok(())
|
||||
}
|
96
src/mac.rs
96
src/mac.rs
|
@ -1,96 +0,0 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use log::*;
|
||||
|
||||
use vulkanalia::prelude::v1_0::*;
|
||||
|
||||
use winit::dpi::LogicalSize;
|
||||
use winit::event::Event;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::window::WindowBuilder;
|
||||
|
||||
use crate::graphics_engines::vulkan::App;
|
||||
|
||||
const WINDOW_TITLE:&'static str = "MineMod";
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
super::init_logging();
|
||||
|
||||
info!("Registering CTRLC hook.");
|
||||
|
||||
let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
shutdown_tx.send(()).expect("Failed to send shutdown signal");
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
info!("Initializing event loop and winit window instance.");
|
||||
|
||||
// Window
|
||||
|
||||
let event_loop = EventLoop::new()?;
|
||||
let window = WindowBuilder::new()
|
||||
.with_title(WINDOW_TITLE)
|
||||
.with_inner_size(LogicalSize::new(1024, 768))
|
||||
.build(&event_loop)?;
|
||||
|
||||
info!("Creating app and starting event loop.");
|
||||
|
||||
// App
|
||||
|
||||
let mut app = unsafe { App::create(&window)? };
|
||||
let mut minimized = false;
|
||||
|
||||
let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx)));
|
||||
|
||||
event_loop.run(move |event, elwt| {
|
||||
let mut shutdown_rx_guard = shutdown_rx.lock().unwrap();
|
||||
|
||||
if let Some(receiver) = shutdown_rx_guard.as_mut() {
|
||||
if receiver.try_recv().is_ok() {
|
||||
info!("Closing event loop and destroying Vulkan instance.");
|
||||
elwt.exit();
|
||||
unsafe {
|
||||
app.device.device_wait_idle().unwrap();
|
||||
app.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
match event {
|
||||
// Request a redraw when all events were processed.
|
||||
Event::AboutToWait => window.request_redraw(),
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
// Render a frame if our Vulkan app is not being destroyed.
|
||||
WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => {
|
||||
unsafe { app.render(&window) }.unwrap();
|
||||
},
|
||||
WindowEvent::Resized(size) =>
|
||||
if size.width == 0 || size.height == 0 {
|
||||
minimized = true;
|
||||
} else {
|
||||
minimized = false;
|
||||
app.resized = true;
|
||||
},
|
||||
// Destroy our Vulkan app.
|
||||
WindowEvent::CloseRequested => {
|
||||
info!("Closing event loop and destroying Vulkan instance.");
|
||||
elwt.exit();
|
||||
unsafe {
|
||||
app.device.device_wait_idle().unwrap();
|
||||
app.destroy();
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
})?;
|
||||
|
||||
info!("Exiting program.");
|
||||
|
||||
Ok(())
|
||||
}
|
82
src/main.rs
82
src/main.rs
|
@ -1,4 +1,4 @@
|
|||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
//#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
#![deny(clippy::unwrap_used)]
|
||||
#![allow(
|
||||
// dead_code,
|
||||
|
@ -8,8 +8,33 @@
|
|||
unsafe_op_in_unsafe_fn
|
||||
)]
|
||||
|
||||
mod audio_engines;
|
||||
mod cataclysm;
|
||||
mod graphics_engines;
|
||||
mod input_systems;
|
||||
mod targets;
|
||||
|
||||
/// i hope you will forgive me for these crimes, but as far as i can tell this is the best way
|
||||
/// to handle all these platforms with wildly different requirements and capabilities
|
||||
pub use targets::*;
|
||||
|
||||
// Logging is currently common across all platforms so it may live here
|
||||
fn init_logging() {
|
||||
tracing_subscriber::fmt()
|
||||
.compact()
|
||||
.with_timer(tracing_subscriber::fmt::time::uptime())
|
||||
.with_ansi(true)
|
||||
.with_level(true)
|
||||
.with_thread_names(true)
|
||||
.with_max_level(if cfg!(debug_assertions) {
|
||||
tracing::level_filters::LevelFilter::DEBUG
|
||||
} else {
|
||||
tracing::level_filters::LevelFilter::INFO
|
||||
})
|
||||
.init();
|
||||
|
||||
// pretty_env_logger::init_timed();
|
||||
}
|
||||
|
||||
// NOTE use crate:: for things in engine that depend on the target platform
|
||||
// this allows an incredibly easy way to handle gui and others per platform
|
||||
|
@ -38,58 +63,3 @@ mod graphics_engines;
|
|||
// test BCn vs raw formats
|
||||
|
||||
// research why texture atlases exist, it seems like an easy way to reduce the allocation calls since they are limited, and it seems to provide better usage of memory overall
|
||||
|
||||
// Planned system targets
|
||||
#[cfg(target_os = "linux")] mod linux;
|
||||
#[cfg(target_os = "linux")] pub use linux::*;
|
||||
#[cfg(target_os = "windows")] mod windows;
|
||||
#[cfg(target_os = "windows")] pub use windows::*;
|
||||
#[cfg(target_os = "macos")] mod mac;
|
||||
#[cfg(target_os = "macos")] pub use mac::*;
|
||||
#[cfg(target_family = "wasm")] mod wasm;
|
||||
#[cfg(target_family = "wasm")] pub use wasm::*;
|
||||
#[cfg(target_os = "vita")] mod vita;
|
||||
#[cfg(target_os = "vita")] pub use vita::*;
|
||||
|
||||
// Potential system targets
|
||||
|
||||
// bindgen, cc, https://github.com/rust-console
|
||||
|
||||
// switch // c lib: libnx, crate: rust-switch, toolchain: devkitPro
|
||||
// #[cfg(target_os = "horizon")]
|
||||
// mod switch;
|
||||
// #[cfg(target_os = "horizon")]
|
||||
// pub use switch::*;
|
||||
// ps3 // sdk: PSL1GHT, target: powerpc64-unknown-linux-gnu
|
||||
// #[cfg(target_os = "psl1ght")]
|
||||
// mod ps3;
|
||||
// #[cfg(target_os = "psl1ght")]
|
||||
// pub use ps3::*;
|
||||
// x360 // c lib: libxenon, make custom spec for xenon target
|
||||
// #[cfg(target_os = "xenon")]
|
||||
// mod x369;
|
||||
// #[cfg(target_os = "xenon")]
|
||||
// pub use x360::*;
|
||||
// wii // toolchain: devkitPPC, target: powerpc-unknown-eabi, c lib: libogc
|
||||
// #[cfg(target_os = "wii")]
|
||||
// mod wii;
|
||||
// #[cfg(target_os = "wii")]
|
||||
// pub use wii::*;
|
||||
|
||||
fn init_logging() {
|
||||
tracing_subscriber::fmt()
|
||||
.compact()
|
||||
.with_timer(tracing_subscriber::fmt::time::uptime())
|
||||
.with_ansi(true)
|
||||
.with_level(true)
|
||||
// .with_thread_ids(true)
|
||||
.with_thread_names(true)
|
||||
.with_max_level(if cfg!(debug_assertions) {
|
||||
tracing::level_filters::LevelFilter::DEBUG
|
||||
} else {
|
||||
tracing::level_filters::LevelFilter::INFO
|
||||
})
|
||||
.init();
|
||||
|
||||
// pretty_env_logger::init_timed();
|
||||
}
|
||||
|
|
13
src/targets/desktop/linux.rs
Normal file
13
src/targets/desktop/linux.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
//use anyhow::Result;
|
||||
|
||||
//use log::*;
|
||||
//use winit::event_loop::EventLoop;
|
||||
|
||||
//pub fn main() -> Result<()> {
|
||||
// crate::init_logging();
|
||||
|
||||
|
||||
|
||||
|
||||
// Ok(())
|
||||
//}
|
0
src/targets/desktop/mac/metal_bindgen/metal.rs
Normal file
0
src/targets/desktop/mac/metal_bindgen/metal.rs
Normal file
96
src/targets/desktop/mac/mod.rs
Normal file
96
src/targets/desktop/mac/mod.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
//use anyhow::Result;
|
||||
|
||||
//use log::*;
|
||||
|
||||
//use vulkanalia::prelude::v1_0::*;
|
||||
|
||||
//use winit::dpi::LogicalSize;
|
||||
//use winit::event::Event;
|
||||
//use winit::event::WindowEvent;
|
||||
//use winit::event_loop::EventLoop;
|
||||
//use winit::window::WindowBuilder;
|
||||
|
||||
//use crate::graphics_engines::vulkan::App;
|
||||
|
||||
//const WINDOW_TITLE:&'static str = "MineMod";
|
||||
|
||||
//pub fn main() -> Result<()> {
|
||||
// super::init_logging();
|
||||
|
||||
// info!("Registering CTRLC hook.");
|
||||
|
||||
// let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel();
|
||||
|
||||
// ctrlc::set_handler(move || {
|
||||
// shutdown_tx.send(()).expect("Failed to send shutdown signal");
|
||||
// })
|
||||
// .expect("Error setting Ctrl-C handler");
|
||||
|
||||
// info!("Initializing event loop and winit window instance.");
|
||||
|
||||
// // Window
|
||||
|
||||
// let event_loop = EventLoop::new()?;
|
||||
// let window = WindowBuilder::new()
|
||||
// .with_title(WINDOW_TITLE)
|
||||
// .with_inner_size(LogicalSize::new(1024, 768))
|
||||
// .build(&event_loop)?;
|
||||
|
||||
// info!("Creating app and starting event loop.");
|
||||
|
||||
// // App
|
||||
|
||||
// let mut app = unsafe { App::create(&window)? };
|
||||
// let mut minimized = false;
|
||||
|
||||
// let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx)));
|
||||
|
||||
// event_loop.run(move |event, elwt| {
|
||||
// let mut shutdown_rx_guard = shutdown_rx.lock().unwrap();
|
||||
|
||||
// if let Some(receiver) = shutdown_rx_guard.as_mut() {
|
||||
// if receiver.try_recv().is_ok() {
|
||||
// info!("Closing event loop and destroying Vulkan instance.");
|
||||
// elwt.exit();
|
||||
// unsafe {
|
||||
// app.device.device_wait_idle().unwrap();
|
||||
// app.destroy();
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// match event {
|
||||
// // Request a redraw when all events were processed.
|
||||
// Event::AboutToWait => window.request_redraw(),
|
||||
// Event::WindowEvent { event, .. } => match event {
|
||||
// // Render a frame if our Vulkan app is not being destroyed.
|
||||
// WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => {
|
||||
// unsafe { app.render(&window) }.unwrap();
|
||||
// },
|
||||
// WindowEvent::Resized(size) =>
|
||||
// if size.width == 0 || size.height == 0 {
|
||||
// minimized = true;
|
||||
// } else {
|
||||
// minimized = false;
|
||||
// app.resized = true;
|
||||
// },
|
||||
// // Destroy our Vulkan app.
|
||||
// WindowEvent::CloseRequested => {
|
||||
// info!("Closing event loop and destroying Vulkan instance.");
|
||||
// elwt.exit();
|
||||
// unsafe {
|
||||
// app.device.device_wait_idle().unwrap();
|
||||
// app.destroy();
|
||||
// }
|
||||
// },
|
||||
// _ => {},
|
||||
// },
|
||||
// _ => {},
|
||||
// }
|
||||
// })?;
|
||||
|
||||
// info!("Exiting program.");
|
||||
|
||||
// Ok(())
|
||||
//}
|
166
src/targets/desktop/mod.rs
Normal file
166
src/targets/desktop/mod.rs
Normal file
|
@ -0,0 +1,166 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use glfw::Action;
|
||||
use glfw::Context;
|
||||
use glfw::Key;
|
||||
|
||||
use log::*;
|
||||
|
||||
use crate::cataclysm::Cataclysm;
|
||||
use crate::cataclysm::CataclysmChunk;
|
||||
use crate::cataclysm::SimpleBlock;
|
||||
use crate::graphics_engines::GMode;
|
||||
use crate::graphics_engines::GraphicsCommander;
|
||||
|
||||
//#[cfg(target_os = "linux")] mod linux;
|
||||
//#[cfg(target_os = "linux")] pub use linux::*;
|
||||
//#[cfg(target_os = "windows")] mod windows;
|
||||
//#[cfg(target_os = "windows")] pub use windows::*;
|
||||
//#[cfg(target_os = "macos")] mod mac;
|
||||
//#[cfg(target_os = "macos")] pub use mac::*;
|
||||
|
||||
pub const WINDOW_TITLE:&'static str = "MineMod";
|
||||
pub const WINDOW_DECORATION_LEFT:bool = false;
|
||||
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
crate::init_logging();
|
||||
|
||||
info!("Registering ^C hook.");
|
||||
|
||||
let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
shutdown_tx.send(()).expect("Failed to send shutdown signal");
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
let mut glfw = glfw::init(|err, string| match err {
|
||||
// we dont give a shit because we supply our own render system
|
||||
glfw::Error::NoWindowContext /*| glfw::Error::NoError*/ => warn!("GLFW Error: {err} {string}"),
|
||||
_ => panic!("GLFW Error! {err}, {string}"),
|
||||
})?;
|
||||
|
||||
let graphics_mode = GMode::OpenGL;
|
||||
|
||||
// if we do not want to use opengl, disable it
|
||||
if graphics_mode != GMode::OpenGL {
|
||||
glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::NoApi));
|
||||
}
|
||||
|
||||
if let GMode::OpenGL = graphics_mode {}
|
||||
|
||||
let (mut window, events) = if let Some(glfw) = glfw.create_window(1024, 768, &WINDOW_TITLE, glfw::WindowMode::Windowed) {
|
||||
glfw
|
||||
} else {
|
||||
return Err("Could not create glfw window!".into());
|
||||
};
|
||||
|
||||
window.set_key_polling(true);
|
||||
window.make_current();
|
||||
|
||||
let mut cmd = /*Some(*/make_graphics_commander(graphics_mode, &mut window)?/*)*/;
|
||||
|
||||
let mut game_world = Cataclysm::new();
|
||||
|
||||
game_world.chunks.insert((0, 0, 0), CataclysmChunk::new());
|
||||
|
||||
for x in 0..Cataclysm::CHUNK_SIZE {
|
||||
for y in 0..Cataclysm::CHUNK_SIZE {
|
||||
for z in 0..Cataclysm::CHUNK_SIZE {
|
||||
game_world.chunks.get_mut(&(0, 0, 0)).unwrap().simple_blocks.insert((x, y, z), SimpleBlock {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//'mainloop: while !window.should_close() {
|
||||
loop {
|
||||
if shutdown_rx.try_recv().is_ok() {
|
||||
info!("^C triggered.");
|
||||
window.set_should_close(true);
|
||||
}
|
||||
|
||||
// Swap front and back buffers
|
||||
//window.swap_buffers(); // cannot be used
|
||||
|
||||
// dont flood the logs
|
||||
//std::thread::sleep(Duration::from_secs(1));
|
||||
|
||||
trace!("Polling GLFW events.");
|
||||
// Poll for and process events
|
||||
glfw.poll_events();
|
||||
|
||||
for (e, event) in glfw::flush_messages(&events) {
|
||||
info!("GLFW Event: {:?}", event);
|
||||
match event {
|
||||
//glfw::WindowEvent::FramebufferSize(x, y) => {},
|
||||
//glfw::WindowEvent::Close => window.set_should_close(true),
|
||||
// minimize? doesnt appear to be
|
||||
glfw::WindowEvent::Iconify(e) =>
|
||||
//if let Some(cmd) = graphics_commander.as_mut() {
|
||||
if e {
|
||||
cmd.suspend_rendering();
|
||||
} else {
|
||||
cmd.resume_rendering();
|
||||
},
|
||||
//},
|
||||
glfw::WindowEvent::Key(key, _, Action::Press, _) => match key {
|
||||
Key::Escape | Key::Q => window.set_should_close(true),
|
||||
//Key::E => {
|
||||
//if let Some(cmd) = graphics_commander.as_mut() {
|
||||
// cmd.exit();
|
||||
//}
|
||||
//let _gc = graphics_commander.take();
|
||||
//match graphics_mode {
|
||||
// GMode::Vulkan => graphics_mode = GMode::OpenGL,
|
||||
// GMode::OpenGL => graphics_mode = GMode::Vulkan,
|
||||
// #[cfg(target_os = "macos")]
|
||||
// GMode::Metal => todo!(),
|
||||
// #[cfg(target_os = "windows")]
|
||||
// GMode::DirectX => todo!(),
|
||||
//}
|
||||
//graphics_commander = Some(make_graphics_commander(graphics_mode, &mut window)?);
|
||||
//},
|
||||
_ => (),
|
||||
},
|
||||
event => {
|
||||
dbg!(event);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if window.should_close() {
|
||||
info!("Breaking loop.");
|
||||
break;
|
||||
}
|
||||
|
||||
//if let Some(cmd) = graphics_commander.as_mut() {
|
||||
trace!("Rendering.");
|
||||
//cmd.render_simple_blocks(game_world.chunks.get_mut(&(0, 0, 0)).unwrap().simple_blocks);
|
||||
cmd.render(&mut window, &mut game_world)?;
|
||||
//}
|
||||
}
|
||||
|
||||
//if let Some(cmd) = graphics_commander.as_mut() {
|
||||
info!("Closing GC instance.");
|
||||
cmd.exit();
|
||||
//}
|
||||
|
||||
info!("Exiting.");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_graphics_commander(graphics_mode:GMode, window:&mut glfw::PWindow) -> Result<Box<dyn GraphicsCommander>> {
|
||||
Ok(match graphics_mode {
|
||||
GMode::Vulkan => Box::new(unsafe { crate::graphics_engines::vulkan_gc::App::create(&window)? }),
|
||||
GMode::OpenGL => Box::new(crate::graphics_engines::opengl::Renderer::create(window)?),
|
||||
#[cfg(target_os = "macos")]
|
||||
GMode::Metal => todo!(),
|
||||
#[cfg(target_os = "windows")]
|
||||
GMode::DirectX => todo!(),
|
||||
})
|
||||
}
|
||||
|
||||
//fn make_glfw() -> Result<glfw::Glfw, Box<dyn std::error::Error>> {
|
||||
|
||||
// Ok(glfw)
|
||||
//}
|
96
src/targets/desktop/windows.rs
Normal file
96
src/targets/desktop/windows.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
//use anyhow::Result;
|
||||
|
||||
//use log::*;
|
||||
|
||||
//use vulkanalia::prelude::v1_0::*;
|
||||
|
||||
//use winit::dpi::LogicalSize;
|
||||
//use winit::event::Event;
|
||||
//use winit::event::WindowEvent;
|
||||
//use winit::event_loop::EventLoop;
|
||||
//use winit::window::WindowBuilder;
|
||||
|
||||
//use crate::graphics_engines::vulkan::App;
|
||||
|
||||
//const WINDOW_TITLE:&'static str = "MineMod";
|
||||
|
||||
//pub fn main() -> Result<()> {
|
||||
// super::init_logging();
|
||||
|
||||
// info!("Registering CTRLC hook.");
|
||||
|
||||
// let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel::<()>();
|
||||
|
||||
// ctrlc::set_handler(move || {
|
||||
// shutdown_tx.send(()).expect("Failed to send shutdown signal");
|
||||
// })
|
||||
// .expect("Error setting Ctrl-C handler");
|
||||
|
||||
// info!("Initializing event loop and winit window instance.");
|
||||
|
||||
// // Window
|
||||
|
||||
// let event_loop = EventLoop::new()?;
|
||||
// let window = WindowBuilder::new()
|
||||
// .with_title(WINDOW_TITLE)
|
||||
// .with_inner_size(LogicalSize::new(1024, 768))
|
||||
// .build(&event_loop)?;
|
||||
|
||||
// info!("Creating app and starting event loop.");
|
||||
|
||||
// // App
|
||||
|
||||
// let mut app = unsafe { App::create(&window)? };
|
||||
// let mut minimized = false;
|
||||
|
||||
// let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx)));
|
||||
|
||||
// event_loop.run(move |event, elwt| {
|
||||
// let mut shutdown_rx_guard = shutdown_rx.lock().unwrap();
|
||||
|
||||
// if let Some(receiver) = shutdown_rx_guard.as_mut() {
|
||||
// if receiver.try_recv().is_ok() {
|
||||
// info!("Closing event loop and destroying Vulkan instance.");
|
||||
// elwt.exit();
|
||||
// unsafe {
|
||||
// app.device.device_wait_idle().unwrap();
|
||||
// app.destroy();
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// match event {
|
||||
// // Request a redraw when all events were processed.
|
||||
// Event::AboutToWait => window.request_redraw(),
|
||||
// Event::WindowEvent { event, .. } => match event {
|
||||
// // Render a frame if our Vulkan app is not being destroyed.
|
||||
// WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => {
|
||||
// unsafe { app.render(&window) }.unwrap();
|
||||
// },
|
||||
// WindowEvent::Resized(size) =>
|
||||
// if size.width == 0 || size.height == 0 {
|
||||
// minimized = true;
|
||||
// } else {
|
||||
// minimized = false;
|
||||
// app.resized = true;
|
||||
// },
|
||||
// // Destroy our Vulkan app.
|
||||
// WindowEvent::CloseRequested => {
|
||||
// info!("Closing event loop and destroying Vulkan instance.");
|
||||
// elwt.exit();
|
||||
// unsafe {
|
||||
// app.device.device_wait_idle().unwrap();
|
||||
// app.destroy();
|
||||
// }
|
||||
// },
|
||||
// _ => {},
|
||||
// },
|
||||
// _ => {},
|
||||
// }
|
||||
// })?;
|
||||
|
||||
// info!("Exiting program.");
|
||||
|
||||
// Ok(())
|
||||
//}
|
37
src/targets/mod.rs
Normal file
37
src/targets/mod.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Planned system targets
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
mod desktop;
|
||||
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
||||
pub use desktop::*;
|
||||
|
||||
// wasm may count for desktop? it does not need windowing however
|
||||
//#[cfg(target_family = "wasm")] mod wasm;
|
||||
//#[cfg(target_family = "wasm")] pub use wasm::*;
|
||||
//#[cfg(target_os = "vita")] mod vita;
|
||||
//#[cfg(target_os = "vita")] pub use vita::*;
|
||||
|
||||
// Potential system targets
|
||||
|
||||
// bindgen, cc, https://github.com/rust-console
|
||||
|
||||
// switch // c lib: libnx, crate: rust-switch, toolchain: devkitPro
|
||||
// #[cfg(target_os = "horizon")]
|
||||
// mod switch;
|
||||
// #[cfg(target_os = "horizon")]
|
||||
// pub use switch::*;
|
||||
// ps3 // sdk: PSL1GHT, target: powerpc64-unknown-linux-gnu
|
||||
// #[cfg(target_os = "psl1ght")]
|
||||
// mod ps3;
|
||||
// #[cfg(target_os = "psl1ght")]
|
||||
// pub use ps3::*;
|
||||
// x360 // c lib: libxenon, make custom spec for xenon target
|
||||
// #[cfg(target_os = "xenon")]
|
||||
// mod x369;
|
||||
// #[cfg(target_os = "xenon")]
|
||||
// pub use x360::*;
|
||||
// wii // toolchain: devkitPPC, target: powerpc-unknown-eabi, c lib: libogc
|
||||
// #[cfg(target_os = "wii")]
|
||||
// mod wii;
|
||||
// #[cfg(target_os = "wii")]
|
||||
// pub use wii::*;
|
|
@ -1,96 +0,0 @@
|
|||
use anyhow::Result;
|
||||
|
||||
use log::*;
|
||||
|
||||
use vulkanalia::prelude::v1_0::*;
|
||||
|
||||
use winit::dpi::LogicalSize;
|
||||
use winit::event::Event;
|
||||
use winit::event::WindowEvent;
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::window::WindowBuilder;
|
||||
|
||||
use crate::graphics_engines::vulkan::App;
|
||||
|
||||
const WINDOW_TITLE:&'static str = "MineMod";
|
||||
|
||||
pub fn main() -> Result<()> {
|
||||
super::init_logging();
|
||||
|
||||
info!("Registering CTRLC hook.");
|
||||
|
||||
let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel::<()>();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
shutdown_tx.send(()).expect("Failed to send shutdown signal");
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
info!("Initializing event loop and winit window instance.");
|
||||
|
||||
// Window
|
||||
|
||||
let event_loop = EventLoop::new()?;
|
||||
let window = WindowBuilder::new()
|
||||
.with_title(WINDOW_TITLE)
|
||||
.with_inner_size(LogicalSize::new(1024, 768))
|
||||
.build(&event_loop)?;
|
||||
|
||||
info!("Creating app and starting event loop.");
|
||||
|
||||
// App
|
||||
|
||||
let mut app = unsafe { App::create(&window)? };
|
||||
let mut minimized = false;
|
||||
|
||||
let shutdown_rx = std::sync::Arc::new(std::sync::Mutex::new(Some(shutdown_rx)));
|
||||
|
||||
event_loop.run(move |event, elwt| {
|
||||
let mut shutdown_rx_guard = shutdown_rx.lock().unwrap();
|
||||
|
||||
if let Some(receiver) = shutdown_rx_guard.as_mut() {
|
||||
if receiver.try_recv().is_ok() {
|
||||
info!("Closing event loop and destroying Vulkan instance.");
|
||||
elwt.exit();
|
||||
unsafe {
|
||||
app.device.device_wait_idle().unwrap();
|
||||
app.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
match event {
|
||||
// Request a redraw when all events were processed.
|
||||
Event::AboutToWait => window.request_redraw(),
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
// Render a frame if our Vulkan app is not being destroyed.
|
||||
WindowEvent::RedrawRequested if !elwt.exiting() && !minimized => {
|
||||
unsafe { app.render(&window) }.unwrap();
|
||||
},
|
||||
WindowEvent::Resized(size) =>
|
||||
if size.width == 0 || size.height == 0 {
|
||||
minimized = true;
|
||||
} else {
|
||||
minimized = false;
|
||||
app.resized = true;
|
||||
},
|
||||
// Destroy our Vulkan app.
|
||||
WindowEvent::CloseRequested => {
|
||||
info!("Closing event loop and destroying Vulkan instance.");
|
||||
elwt.exit();
|
||||
unsafe {
|
||||
app.device.device_wait_idle().unwrap();
|
||||
app.destroy();
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
})?;
|
||||
|
||||
info!("Exiting program.");
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Add table
Reference in a new issue