mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-22 14:58:44 -06:00
Compare commits
6 commits
906f4882a2
...
90784e21dd
Author | SHA1 | Date | |
---|---|---|---|
griffi-gh | 90784e21dd | ||
griffi-gh | 260f4b4232 | ||
griffi-gh | 35ff06a439 | ||
griffi-gh | 7ac045f013 | ||
griffi-gh | 0b69377865 | ||
griffi-gh | 324270ed7d |
42
kubi/shaders/world.wgsl
Normal file
42
kubi/shaders/world.wgsl
Normal file
|
@ -0,0 +1,42 @@
|
|||
// struct Uniforms {
|
||||
// transform: mat4x4<f32>;
|
||||
// };
|
||||
|
||||
// @group(1) @binding(0)
|
||||
// var<uniform> uniforms: Uniforms;
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
@location(2) uv: vec2<f32>,
|
||||
@location(3) @interpolate(flat) tex_index: u32,
|
||||
}
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
@location(0) uv: vec2<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
@location(2) color: vec4<f32>,
|
||||
@location(3) @interpolate(flat) tex_index: u32,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
in: VertexInput,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.uv = in.uv;
|
||||
out.clip_position = vec4<f32>(in.position, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
@group(0) @binding(0)
|
||||
var t_diffuse: texture_2d_array<f32>;
|
||||
|
||||
@group(0) @binding(1)
|
||||
var s_diffuse: sampler;
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
return textureSample(t_diffuse, s_diffuse, in.uv, in.tex_index);
|
||||
}
|
|
@ -5,9 +5,7 @@ use kubi_shared::block::BlockTexture;
|
|||
use crate::{filesystem::AssetManager, hui_integration::UiState, rendering::Renderer};
|
||||
|
||||
mod texture;
|
||||
mod shaders;
|
||||
|
||||
//use texture::load_texture2darray_prefab;
|
||||
use texture::load_texture2darray_prefab;
|
||||
|
||||
pub trait AssetPaths {
|
||||
fn file_name(self) -> &'static str;
|
||||
|
@ -39,19 +37,7 @@ impl AssetPaths for BlockTexture {
|
|||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct BlockTexturesPrefab(pub wgpu::Texture);
|
||||
|
||||
// #[derive(Unique)]
|
||||
// #[repr(transparent)]
|
||||
// pub struct ChunkShaderPrefab(pub Program);
|
||||
|
||||
// #[derive(Unique)]
|
||||
// #[repr(transparent)]
|
||||
// pub struct ColoredShaderPrefab(pub Program);
|
||||
|
||||
// #[derive(Unique)]
|
||||
// #[repr(transparent)]
|
||||
// pub struct Colored2ShaderPrefab(pub Program);
|
||||
pub struct BlockDiffuseTexture(pub wgpu::Texture);
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
|
@ -63,15 +49,14 @@ pub fn load_prefabs(
|
|||
mut ui: NonSendSync<UniqueViewMut<UiState>>,
|
||||
assman: UniqueView<AssetManager>
|
||||
) {
|
||||
// log::info!("Loading textures...");
|
||||
// storages.add_unique_non_send_sync(BlockTexturesPrefab(
|
||||
// load_texture2darray_prefab::<BlockTexture, _>(
|
||||
// &assman,
|
||||
// "blocks".into(),
|
||||
// &renderer.display,
|
||||
// MipmapsOption::AutoGeneratedMipmaps
|
||||
// )
|
||||
// ));
|
||||
log::info!("Loading textures...");
|
||||
storages.add_unique_non_send_sync(BlockDiffuseTexture(
|
||||
load_texture2darray_prefab::<BlockTexture>(
|
||||
&renderer,
|
||||
&assman,
|
||||
"blocks".into(),
|
||||
)
|
||||
));
|
||||
|
||||
log::info!("Loading the UI stuff...");
|
||||
{
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
macro_rules! include_shader_prefab {
|
||||
($name: literal, $vert: literal, $frag: literal, $facade: expr) => {
|
||||
{
|
||||
use ::glium::{Program, program::ProgramCreationInput};
|
||||
log::info!("compiling shader {}", $name);
|
||||
Program::new(&*$facade, ProgramCreationInput::SourceCode {
|
||||
vertex_shader: include_str!($vert),
|
||||
fragment_shader: include_str!($frag),
|
||||
geometry_shader: None,
|
||||
tessellation_control_shader: None,
|
||||
tessellation_evaluation_shader: None,
|
||||
transform_feedback_varyings: None,
|
||||
outputs_srgb: false,
|
||||
uses_point_size: false,
|
||||
}).expect("Failed to compile gpu program")
|
||||
}
|
||||
};
|
||||
}
|
||||
pub(crate) use include_shader_prefab;
|
|
@ -1,45 +1,75 @@
|
|||
// use strum::IntoEnumIterator;
|
||||
// use rayon::prelude::*;
|
||||
// use std::{path::PathBuf, io::BufReader};
|
||||
// use crate::filesystem::AssetManager;
|
||||
// use super::AssetPaths;
|
||||
use glam::UVec2;
|
||||
use strum::IntoEnumIterator;
|
||||
use rayon::prelude::*;
|
||||
use wgpu::util::{DeviceExt, TextureDataOrder};
|
||||
use std::{io::BufReader, path::PathBuf};
|
||||
use crate::{filesystem::AssetManager, rendering::Renderer};
|
||||
use super::AssetPaths;
|
||||
|
||||
// pub fn load_texture2darray_prefab<
|
||||
// T: AssetPaths + IntoEnumIterator,
|
||||
// E: Facade
|
||||
// >(
|
||||
// assman: &AssetManager,
|
||||
// directory: PathBuf,
|
||||
// facade: &E,
|
||||
// mipmaps: MipmapsOption,
|
||||
// ) -> SrgbTexture2dArray {
|
||||
// log::info!("started loading {}", directory.as_os_str().to_str().unwrap());
|
||||
// //Load raw images
|
||||
// let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect();
|
||||
// let raw_images: Vec<RawImage2d<u8>> = tex_files.par_iter().map(|&file_name| {
|
||||
// log::info!("loading texture {}", file_name);
|
||||
// //Get path to the image and open the file
|
||||
// let reader = {
|
||||
// let path = directory.join(file_name);
|
||||
// BufReader::new(assman.open_asset(&path).expect("Failed to open texture file"))
|
||||
// };
|
||||
// //Parse image data
|
||||
// let (image_data, dimensions) = {
|
||||
// let image = image::load(
|
||||
// reader,
|
||||
// image::ImageFormat::Png
|
||||
// ).unwrap().to_rgba8();
|
||||
// let dimensions = image.dimensions();
|
||||
// (image.into_raw(), dimensions)
|
||||
// };
|
||||
// //Create a glium RawImage
|
||||
// RawImage2d::from_raw_rgba_reversed(
|
||||
// &image_data,
|
||||
// dimensions
|
||||
// )
|
||||
// }).collect();
|
||||
// log::info!("done loading texture files, uploading to the gpu");
|
||||
// //Upload images to the GPU
|
||||
// SrgbTexture2dArray::with_mipmaps(facade, raw_images, mipmaps)
|
||||
// .expect("Failed to upload texture array to GPU")
|
||||
// }
|
||||
pub fn load_texture2darray_prefab<T: AssetPaths + IntoEnumIterator>(
|
||||
renderer: &Renderer,
|
||||
assman: &AssetManager,
|
||||
directory: PathBuf,
|
||||
) -> wgpu::Texture {
|
||||
log::info!("started loading {}", directory.as_os_str().to_str().unwrap());
|
||||
|
||||
//Load raw images
|
||||
let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect();
|
||||
let raw_images: Vec<(Vec<u8>, UVec2)> = tex_files.par_iter().map(|&file_name| {
|
||||
log::info!("loading texture {}", file_name);
|
||||
|
||||
//Get path to the image and open the file
|
||||
let reader = {
|
||||
let path = directory.join(file_name);
|
||||
BufReader::new(assman.open_asset(&path).expect("Failed to open texture file"))
|
||||
};
|
||||
|
||||
//Parse image data
|
||||
let (image_data, dimensions) = {
|
||||
let image = image::load(
|
||||
reader,
|
||||
image::ImageFormat::Png
|
||||
).unwrap().to_rgba8();
|
||||
let dimensions = image.dimensions();
|
||||
(image.into_raw(), dimensions)
|
||||
};
|
||||
(image_data, UVec2::from(dimensions))
|
||||
}).collect();
|
||||
|
||||
assert!(!raw_images.is_empty(), "no images loaded");
|
||||
//TODO: check same size
|
||||
|
||||
log::info!("done loading texture files, uploading to the gpu");
|
||||
|
||||
let size = raw_images[0].1;
|
||||
let layers = raw_images.len() as u32;
|
||||
|
||||
//Concat data into a single vec
|
||||
let mut data = Vec::with_capacity((size.x * size.y * layers * 4) as usize);
|
||||
for (layer_data, _) in raw_images {
|
||||
data.extend_from_slice(&layer_data);
|
||||
}
|
||||
|
||||
//Upload images to the GPU
|
||||
let desc = &wgpu::TextureDescriptor {
|
||||
label: Some("block_diffuse_texture"),
|
||||
size: wgpu::Extent3d {
|
||||
width: size.x,
|
||||
height: size.y,
|
||||
depth_or_array_layers: layers,
|
||||
},
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
view_formats: &[],
|
||||
};
|
||||
|
||||
renderer.device().create_texture_with_data(
|
||||
renderer.queue(),
|
||||
desc,
|
||||
TextureDataOrder::MipMajor,
|
||||
&data
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
use pollster::FutureExt;
|
||||
use raw_window_handle::HasRawWindowHandle;
|
||||
use shipyard::{AllStoragesView, AllStoragesViewMut, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View};
|
||||
use wgpu::SurfaceTargetUnsafe;
|
||||
use winit::{
|
||||
event_loop::ActiveEventLoop,
|
||||
window::{WindowAttributes, Fullscreen, Window},
|
||||
dpi::PhysicalSize
|
||||
};
|
||||
use shipyard::{AllStoragesView, AllStoragesViewMut, IntoIter, Unique, UniqueView, UniqueViewMut, View};
|
||||
use winit::dpi::PhysicalSize;
|
||||
use glam::{Vec3, UVec2};
|
||||
use crate::{events::WindowResizedEvent, settings::{FullscreenMode, GameSettings}, state::is_ingame};
|
||||
use crate::{events::WindowResizedEvent, state::is_ingame};
|
||||
|
||||
mod renderer;
|
||||
pub use renderer::Renderer;
|
||||
|
||||
pub mod primitives;
|
||||
pub mod world;
|
||||
|
@ -22,174 +18,20 @@ pub struct BufferPair {
|
|||
}
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct BackgroundColor(pub Vec3);
|
||||
|
||||
#[derive(Unique, Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
#[deprecated = "use Renderer.size instead"]
|
||||
#[allow(deprecated)]
|
||||
pub struct WindowSize(pub UVec2);
|
||||
|
||||
#[derive(Unique)]
|
||||
pub struct Renderer {
|
||||
instance: wgpu::Instance,
|
||||
surface: wgpu::Surface<'static>,
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
surface_config: wgpu::SurfaceConfiguration,
|
||||
size: PhysicalSize<u32>,
|
||||
// pub depth_texture: wgpu::Texture,
|
||||
|
||||
//must be last due to drop order
|
||||
window: Window,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn init(event_loop: &ActiveEventLoop, settings: &GameSettings) -> Self {
|
||||
log::info!("initializing display");
|
||||
|
||||
let window_attributes = Window::default_attributes()
|
||||
.with_title("kubi")
|
||||
.with_maximized(true)
|
||||
.with_min_inner_size(PhysicalSize::new(640, 480))
|
||||
.with_fullscreen({
|
||||
//this has no effect on android, so skip this pointless stuff
|
||||
#[cfg(target_os = "android")] {
|
||||
None
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
if let Some(fs_settings) = &settings.fullscreen {
|
||||
let monitor = event_loop.primary_monitor().or_else(|| {
|
||||
event_loop.available_monitors().next()
|
||||
});
|
||||
|
||||
if let Some(monitor) = monitor {
|
||||
log::info!("monitor: {}", monitor.name().unwrap_or_else(|| "generic".into()));
|
||||
match fs_settings.mode {
|
||||
FullscreenMode::Borderless => {
|
||||
log::info!("starting in borderless fullscreen mode");
|
||||
Some(Fullscreen::Borderless(Some(monitor)))
|
||||
},
|
||||
FullscreenMode::Exclusive => {
|
||||
log::warn!("exclusive fullscreen mode is experimental");
|
||||
log::info!("starting in exclusive fullscreen mode");
|
||||
//TODO: grabbing the first video mode is probably not the best idea...
|
||||
monitor.video_modes().next()
|
||||
.map(|vmode| {
|
||||
log::info!("video mode: {}", vmode.to_string());
|
||||
Some(Fullscreen::Exclusive(vmode))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
log::warn!("no valid video modes found, falling back to windowed mode instead");
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("no monitors found, falling back to windowed mode");
|
||||
None
|
||||
}
|
||||
} else {
|
||||
log::info!("starting in windowed mode");
|
||||
None
|
||||
}
|
||||
});
|
||||
let window = event_loop.create_window(window_attributes).unwrap();
|
||||
|
||||
let size = window.inner_size();
|
||||
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::VULKAN | wgpu::Backends::GL,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// Create a surface with `create_surface_unsafe` to get a surface with 'static lifetime
|
||||
// It should never outlive the window it's created from
|
||||
let surface = unsafe {
|
||||
instance.create_surface_unsafe(SurfaceTargetUnsafe::from_window(&window).unwrap()).unwrap()
|
||||
};
|
||||
|
||||
let adapter = instance.request_adapter(
|
||||
&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||
compatible_surface: Some(&surface),
|
||||
force_fallback_adapter: false,
|
||||
},
|
||||
).block_on().unwrap();
|
||||
|
||||
let (device, queue) = adapter.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::downlevel_defaults(),
|
||||
},
|
||||
None,
|
||||
).block_on().unwrap();
|
||||
|
||||
let surface_config = surface.get_default_config(&adapter, size.width, size.height).unwrap();
|
||||
surface.configure(&device, &surface_config);
|
||||
|
||||
Self { window, instance, surface, device, queue, surface_config, size }
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, size: PhysicalSize<u32>) {
|
||||
if size.width == 0 || size.height == 0 {
|
||||
log::warn!("Ignoring resize event with zero width or height");
|
||||
return
|
||||
}
|
||||
if self.size == size {
|
||||
log::warn!("Ignoring resize event with same size");
|
||||
return
|
||||
}
|
||||
log::debug!("resizing surface to {:?}", size);
|
||||
self.size = size;
|
||||
self.surface_config.width = size.width;
|
||||
self.surface_config.height = size.height;
|
||||
self.surface.configure(&self.device, &self.surface_config);
|
||||
}
|
||||
|
||||
pub fn reconfigure(&self) {
|
||||
self.surface.configure(&self.device, &self.surface_config);
|
||||
}
|
||||
|
||||
//getters:
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub fn window(&self) -> &Window {
|
||||
&self.window
|
||||
}
|
||||
|
||||
pub fn surface(&self) -> &wgpu::Surface<'static> {
|
||||
&self.surface
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &wgpu::Device {
|
||||
&self.device
|
||||
}
|
||||
|
||||
pub fn queue(&self) -> &wgpu::Queue {
|
||||
&self.queue
|
||||
}
|
||||
|
||||
pub fn surface_config(&self) -> &wgpu::SurfaceConfiguration {
|
||||
&self.surface_config
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_master(storages: AllStoragesViewMut) {
|
||||
let renderer = storages.borrow::<UniqueView<Renderer>>().unwrap();
|
||||
|
||||
let mut encoder = renderer.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
let mut encoder = renderer.device().create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("main_encoder"),
|
||||
});
|
||||
let surface_texture = renderer.surface().get_current_texture().unwrap();
|
||||
let surface_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
//Main in-game render pass
|
||||
if storages.run(is_ingame) {
|
||||
let bg_color = storages.borrow::<UniqueView<BackgroundColor>>().unwrap();
|
||||
let bg = storages.borrow::<UniqueView<BackgroundColor>>().unwrap().0;
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("main0_pass"),
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
|
@ -197,9 +39,9 @@ pub fn render_master(storages: AllStoragesViewMut) {
|
|||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||
r: bg_color.0.x as f64,
|
||||
g: bg_color.0.y as f64,
|
||||
b: bg_color.0.z as f64,
|
||||
r: bg.x as f64,
|
||||
g: bg.y as f64,
|
||||
b: bg.z as f64,
|
||||
a: 1.0,
|
||||
}),
|
||||
store: wgpu::StoreOp::Store,
|
||||
|
@ -212,27 +54,13 @@ pub fn render_master(storages: AllStoragesViewMut) {
|
|||
let data = (&mut render_pass, &*renderer);
|
||||
|
||||
storages.run_with_data(world::draw_world, data);
|
||||
|
||||
// render_pass.set_pipeline(&renderer.pipeline);
|
||||
// render_pass.set_bind_group(0, &renderer.bind_group, &[]);
|
||||
// render_pass.set_vertex_buffer(0, renderer.vertex_buffer.slice(..));
|
||||
// render_pass.set_index_buffer(renderer.index_buffer.slice(..));
|
||||
// render_pass.draw_indexed(0..renderer.num_indices, 0, 0..1);
|
||||
}
|
||||
|
||||
renderer.queue().submit(std::iter::once(encoder.finish()));
|
||||
surface_texture.present();
|
||||
}
|
||||
|
||||
// pub fn clear_background(
|
||||
// mut target: NonSendSync<UniqueViewMut<RenderTarget>>,
|
||||
// color: UniqueView<BackgroundColor>,
|
||||
// ) {
|
||||
// target.0.clear_color_srgb_and_depth((color.0.x, color.0.y, color.0.z, 1.), 1.);
|
||||
// }
|
||||
|
||||
//Resize the renderer
|
||||
|
||||
/// Resize the renderer when the window is resized
|
||||
pub fn resize_renderer(
|
||||
mut renderer: UniqueViewMut<Renderer>,
|
||||
resize: View<WindowResizedEvent>,
|
||||
|
@ -242,11 +70,15 @@ pub fn resize_renderer(
|
|||
}
|
||||
}
|
||||
|
||||
//not sure if this belongs here
|
||||
//Deprecated WindowSize thingy
|
||||
|
||||
pub fn init_window_size(
|
||||
storages: AllStoragesView,
|
||||
) {
|
||||
#[derive(Unique, Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
#[deprecated = "use Renderer.size instead"]
|
||||
#[allow(deprecated)]
|
||||
pub struct WindowSize(pub UVec2);
|
||||
|
||||
pub fn init_window_size(storages: AllStoragesView) {
|
||||
let size = storages.borrow::<View<WindowResizedEvent>>().unwrap().iter().next().unwrap().0;
|
||||
storages.add_unique(WindowSize(size))
|
||||
}
|
||||
|
@ -260,8 +92,8 @@ pub fn update_window_size(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn if_resized (
|
||||
resize: View<WindowResizedEvent>,
|
||||
) -> bool {
|
||||
resize.len() > 0
|
||||
}
|
||||
// pub fn if_resized (
|
||||
// resize: View<WindowResizedEvent>,
|
||||
// ) -> bool {
|
||||
// resize.len() > 0
|
||||
// }
|
||||
|
|
157
kubi/src/rendering/renderer.rs
Normal file
157
kubi/src/rendering/renderer.rs
Normal file
|
@ -0,0 +1,157 @@
|
|||
use pollster::FutureExt;
|
||||
use shipyard::Unique;
|
||||
use winit::{
|
||||
event_loop::ActiveEventLoop,
|
||||
window::{Fullscreen, Window},
|
||||
dpi::PhysicalSize
|
||||
};
|
||||
use crate::settings::{GameSettings, FullscreenMode};
|
||||
|
||||
#[derive(Unique)]
|
||||
pub struct Renderer {
|
||||
instance: wgpu::Instance,
|
||||
surface: wgpu::Surface<'static>,
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
surface_config: wgpu::SurfaceConfiguration,
|
||||
size: PhysicalSize<u32>,
|
||||
// pub depth_texture: wgpu::Texture,
|
||||
|
||||
//must be last due to drop order
|
||||
window: Window,
|
||||
}
|
||||
|
||||
impl Renderer {
|
||||
pub fn init(event_loop: &ActiveEventLoop, settings: &GameSettings) -> Self {
|
||||
log::info!("initializing display");
|
||||
|
||||
let window_attributes = Window::default_attributes()
|
||||
.with_title("kubi")
|
||||
.with_maximized(true)
|
||||
.with_min_inner_size(PhysicalSize::new(640, 480))
|
||||
.with_fullscreen({
|
||||
//this has no effect on android, so skip this pointless stuff
|
||||
#[cfg(target_os = "android")] {
|
||||
None
|
||||
}
|
||||
#[cfg(not(target_os = "android"))]
|
||||
if let Some(fs_settings) = &settings.fullscreen {
|
||||
let monitor = event_loop.primary_monitor().or_else(|| {
|
||||
event_loop.available_monitors().next()
|
||||
});
|
||||
|
||||
if let Some(monitor) = monitor {
|
||||
log::info!("monitor: {}", monitor.name().unwrap_or_else(|| "generic".into()));
|
||||
match fs_settings.mode {
|
||||
FullscreenMode::Borderless => {
|
||||
log::info!("starting in borderless fullscreen mode");
|
||||
Some(Fullscreen::Borderless(Some(monitor)))
|
||||
},
|
||||
FullscreenMode::Exclusive => {
|
||||
log::warn!("exclusive fullscreen mode is experimental");
|
||||
log::info!("starting in exclusive fullscreen mode");
|
||||
//TODO: grabbing the first video mode is probably not the best idea...
|
||||
monitor.video_modes().next()
|
||||
.map(|vmode| {
|
||||
log::info!("video mode: {}", vmode.to_string());
|
||||
Some(Fullscreen::Exclusive(vmode))
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
log::warn!("no valid video modes found, falling back to windowed mode instead");
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("no monitors found, falling back to windowed mode");
|
||||
None
|
||||
}
|
||||
} else {
|
||||
log::info!("starting in windowed mode");
|
||||
None
|
||||
}
|
||||
});
|
||||
let window = event_loop.create_window(window_attributes).unwrap();
|
||||
|
||||
let size = window.inner_size();
|
||||
|
||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::BROWSER_WEBGPU | wgpu::Backends::VULKAN | wgpu::Backends::GL,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// Create a surface with `create_surface_unsafe` to get a surface with 'static lifetime
|
||||
// It should never outlive the window it's created from
|
||||
let surface = unsafe {
|
||||
let target = wgpu::SurfaceTargetUnsafe::from_window(&window).unwrap();
|
||||
instance.create_surface_unsafe(target).unwrap()
|
||||
};
|
||||
|
||||
let adapter = instance.request_adapter(
|
||||
&wgpu::RequestAdapterOptions {
|
||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
||||
compatible_surface: Some(&surface),
|
||||
force_fallback_adapter: false,
|
||||
},
|
||||
).block_on().unwrap();
|
||||
|
||||
let (device, queue) = adapter.request_device(
|
||||
&wgpu::DeviceDescriptor {
|
||||
label: None,
|
||||
required_features: wgpu::Features::empty(),
|
||||
required_limits: wgpu::Limits::downlevel_defaults(),
|
||||
},
|
||||
None,
|
||||
).block_on().unwrap();
|
||||
|
||||
let surface_config = surface.get_default_config(&adapter, size.width, size.height).unwrap();
|
||||
surface.configure(&device, &surface_config);
|
||||
|
||||
Self { window, instance, surface, device, queue, surface_config, size }
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, size: PhysicalSize<u32>) {
|
||||
if size.width == 0 || size.height == 0 {
|
||||
log::warn!("Ignoring resize event with zero width or height");
|
||||
return
|
||||
}
|
||||
if self.size == size {
|
||||
log::warn!("Ignoring resize event with same size");
|
||||
return
|
||||
}
|
||||
log::debug!("resizing surface to {:?}", size);
|
||||
self.size = size;
|
||||
self.surface_config.width = size.width;
|
||||
self.surface_config.height = size.height;
|
||||
self.surface.configure(&self.device, &self.surface_config);
|
||||
}
|
||||
|
||||
pub fn reconfigure(&self) {
|
||||
self.surface.configure(&self.device, &self.surface_config);
|
||||
}
|
||||
|
||||
//getters:
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub fn window(&self) -> &Window {
|
||||
&self.window
|
||||
}
|
||||
|
||||
pub fn surface(&self) -> &wgpu::Surface<'static> {
|
||||
&self.surface
|
||||
}
|
||||
|
||||
pub fn device(&self) -> &wgpu::Device {
|
||||
&self.device
|
||||
}
|
||||
|
||||
pub fn queue(&self) -> &wgpu::Queue {
|
||||
&self.queue
|
||||
}
|
||||
|
||||
pub fn surface_config(&self) -> &wgpu::SurfaceConfiguration {
|
||||
&self.surface_config
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use bytemuck::{Pod, Zeroable};
|
||||
use glam::IVec3;
|
||||
use shipyard::{AllStoragesView, NonSendSync, Unique, UniqueView, UniqueViewMut, View};
|
||||
use kubi_shared::transform::Transform;
|
||||
use glam::{IVec3, Vec3};
|
||||
use shipyard::{AllStoragesView, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View};
|
||||
use kubi_shared::{chunk::CHUNK_SIZE, transform::Transform};
|
||||
use crate::{camera::Camera, settings::GameSettings, world::{ChunkMeshStorage, ChunkStorage}};
|
||||
use super::Renderer;
|
||||
|
||||
|
@ -43,7 +43,37 @@ pub fn draw_world(
|
|||
settings: UniqueView<GameSettings>,
|
||||
mut trans_queue: UniqueViewMut<TransChunkQueue>,
|
||||
) {
|
||||
let camera = camera.iter().next().expect("No cameras in the scene");
|
||||
let camera_matrix = camera.view_matrix * camera.perspective_matrix;
|
||||
|
||||
for (&position, chunk) in &chunks.chunks {
|
||||
if let Some(key) = chunk.mesh_index {
|
||||
let mesh = meshes.get(key).expect("Mesh index pointing to nothing");
|
||||
let world_position = position.as_vec3() * CHUNK_SIZE as f32;
|
||||
|
||||
//Skip if mesh is empty
|
||||
if mesh.main.index.size() == 0 && mesh.trans.index.size() == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
//Frustum culling
|
||||
let minp = world_position;
|
||||
let maxp = world_position + Vec3::splat(CHUNK_SIZE as f32);
|
||||
if !camera.frustum.is_box_visible(minp, maxp) {
|
||||
continue
|
||||
}
|
||||
|
||||
//Draw chunk mesh
|
||||
if mesh.main.index.size() > 0 {
|
||||
//TODO
|
||||
}
|
||||
|
||||
//TODO trans chunks
|
||||
// if mesh.trans_index_buffer.len() > 0 {
|
||||
// trans_queue.0.push(position);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue