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};
|
use crate::{filesystem::AssetManager, hui_integration::UiState, rendering::Renderer};
|
||||||
|
|
||||||
mod texture;
|
mod texture;
|
||||||
mod shaders;
|
use texture::load_texture2darray_prefab;
|
||||||
|
|
||||||
//use texture::load_texture2darray_prefab;
|
|
||||||
|
|
||||||
pub trait AssetPaths {
|
pub trait AssetPaths {
|
||||||
fn file_name(self) -> &'static str;
|
fn file_name(self) -> &'static str;
|
||||||
|
@ -39,19 +37,7 @@ impl AssetPaths for BlockTexture {
|
||||||
|
|
||||||
#[derive(Unique)]
|
#[derive(Unique)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct BlockTexturesPrefab(pub wgpu::Texture);
|
pub struct BlockDiffuseTexture(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);
|
|
||||||
|
|
||||||
#[derive(Unique)]
|
#[derive(Unique)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
@ -63,15 +49,14 @@ pub fn load_prefabs(
|
||||||
mut ui: NonSendSync<UniqueViewMut<UiState>>,
|
mut ui: NonSendSync<UniqueViewMut<UiState>>,
|
||||||
assman: UniqueView<AssetManager>
|
assman: UniqueView<AssetManager>
|
||||||
) {
|
) {
|
||||||
// log::info!("Loading textures...");
|
log::info!("Loading textures...");
|
||||||
// storages.add_unique_non_send_sync(BlockTexturesPrefab(
|
storages.add_unique_non_send_sync(BlockDiffuseTexture(
|
||||||
// load_texture2darray_prefab::<BlockTexture, _>(
|
load_texture2darray_prefab::<BlockTexture>(
|
||||||
// &assman,
|
&renderer,
|
||||||
// "blocks".into(),
|
&assman,
|
||||||
// &renderer.display,
|
"blocks".into(),
|
||||||
// MipmapsOption::AutoGeneratedMipmaps
|
)
|
||||||
// )
|
));
|
||||||
// ));
|
|
||||||
|
|
||||||
log::info!("Loading the UI stuff...");
|
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 glam::UVec2;
|
||||||
// use rayon::prelude::*;
|
use strum::IntoEnumIterator;
|
||||||
// use std::{path::PathBuf, io::BufReader};
|
use rayon::prelude::*;
|
||||||
// use crate::filesystem::AssetManager;
|
use wgpu::util::{DeviceExt, TextureDataOrder};
|
||||||
// use super::AssetPaths;
|
use std::{io::BufReader, path::PathBuf};
|
||||||
|
use crate::{filesystem::AssetManager, rendering::Renderer};
|
||||||
|
use super::AssetPaths;
|
||||||
|
|
||||||
// pub fn load_texture2darray_prefab<
|
pub fn load_texture2darray_prefab<T: AssetPaths + IntoEnumIterator>(
|
||||||
// T: AssetPaths + IntoEnumIterator,
|
renderer: &Renderer,
|
||||||
// E: Facade
|
assman: &AssetManager,
|
||||||
// >(
|
directory: PathBuf,
|
||||||
// assman: &AssetManager,
|
) -> wgpu::Texture {
|
||||||
// directory: PathBuf,
|
log::info!("started loading {}", directory.as_os_str().to_str().unwrap());
|
||||||
// facade: &E,
|
|
||||||
// mipmaps: MipmapsOption,
|
//Load raw images
|
||||||
// ) -> SrgbTexture2dArray {
|
let tex_files: Vec<&'static str> = T::iter().map(|x| x.file_name()).collect();
|
||||||
// log::info!("started loading {}", directory.as_os_str().to_str().unwrap());
|
let raw_images: Vec<(Vec<u8>, UVec2)> = tex_files.par_iter().map(|&file_name| {
|
||||||
// //Load raw images
|
log::info!("loading texture {}", file_name);
|
||||||
// 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| {
|
//Get path to the image and open the file
|
||||||
// log::info!("loading texture {}", file_name);
|
let reader = {
|
||||||
// //Get path to the image and open the file
|
let path = directory.join(file_name);
|
||||||
// let reader = {
|
BufReader::new(assman.open_asset(&path).expect("Failed to open texture file"))
|
||||||
// let path = directory.join(file_name);
|
};
|
||||||
// BufReader::new(assman.open_asset(&path).expect("Failed to open texture file"))
|
|
||||||
// };
|
//Parse image data
|
||||||
// //Parse image data
|
let (image_data, dimensions) = {
|
||||||
// let (image_data, dimensions) = {
|
let image = image::load(
|
||||||
// let image = image::load(
|
reader,
|
||||||
// reader,
|
image::ImageFormat::Png
|
||||||
// image::ImageFormat::Png
|
).unwrap().to_rgba8();
|
||||||
// ).unwrap().to_rgba8();
|
let dimensions = image.dimensions();
|
||||||
// let dimensions = image.dimensions();
|
(image.into_raw(), dimensions)
|
||||||
// (image.into_raw(), dimensions)
|
};
|
||||||
// };
|
(image_data, UVec2::from(dimensions))
|
||||||
// //Create a glium RawImage
|
}).collect();
|
||||||
// RawImage2d::from_raw_rgba_reversed(
|
|
||||||
// &image_data,
|
assert!(!raw_images.is_empty(), "no images loaded");
|
||||||
// dimensions
|
//TODO: check same size
|
||||||
// )
|
|
||||||
// }).collect();
|
log::info!("done loading texture files, uploading to the gpu");
|
||||||
// log::info!("done loading texture files, uploading to the gpu");
|
|
||||||
// //Upload images to the GPU
|
let size = raw_images[0].1;
|
||||||
// SrgbTexture2dArray::with_mipmaps(facade, raw_images, mipmaps)
|
let layers = raw_images.len() as u32;
|
||||||
// .expect("Failed to upload texture array to GPU")
|
|
||||||
// }
|
//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 shipyard::{AllStoragesView, AllStoragesViewMut, IntoIter, Unique, UniqueView, UniqueViewMut, View};
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use winit::dpi::PhysicalSize;
|
||||||
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 glam::{Vec3, UVec2};
|
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 primitives;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
@ -22,174 +18,20 @@ pub struct BufferPair {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Unique)]
|
#[derive(Unique)]
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct BackgroundColor(pub Vec3);
|
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) {
|
pub fn render_master(storages: AllStoragesViewMut) {
|
||||||
let renderer = storages.borrow::<UniqueView<Renderer>>().unwrap();
|
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"),
|
label: Some("main_encoder"),
|
||||||
});
|
});
|
||||||
let surface_texture = renderer.surface().get_current_texture().unwrap();
|
let surface_texture = renderer.surface().get_current_texture().unwrap();
|
||||||
let surface_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let surface_view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
|
||||||
|
//Main in-game render pass
|
||||||
if storages.run(is_ingame) {
|
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 {
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: Some("main0_pass"),
|
label: Some("main0_pass"),
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
@ -197,9 +39,9 @@ pub fn render_master(storages: AllStoragesViewMut) {
|
||||||
resolve_target: None,
|
resolve_target: None,
|
||||||
ops: wgpu::Operations {
|
ops: wgpu::Operations {
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||||
r: bg_color.0.x as f64,
|
r: bg.x as f64,
|
||||||
g: bg_color.0.y as f64,
|
g: bg.y as f64,
|
||||||
b: bg_color.0.z as f64,
|
b: bg.z as f64,
|
||||||
a: 1.0,
|
a: 1.0,
|
||||||
}),
|
}),
|
||||||
store: wgpu::StoreOp::Store,
|
store: wgpu::StoreOp::Store,
|
||||||
|
@ -212,27 +54,13 @@ pub fn render_master(storages: AllStoragesViewMut) {
|
||||||
let data = (&mut render_pass, &*renderer);
|
let data = (&mut render_pass, &*renderer);
|
||||||
|
|
||||||
storages.run_with_data(world::draw_world, data);
|
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()));
|
renderer.queue().submit(std::iter::once(encoder.finish()));
|
||||||
surface_texture.present();
|
surface_texture.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn clear_background(
|
/// Resize the renderer when the window is resized
|
||||||
// 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
|
|
||||||
|
|
||||||
pub fn resize_renderer(
|
pub fn resize_renderer(
|
||||||
mut renderer: UniqueViewMut<Renderer>,
|
mut renderer: UniqueViewMut<Renderer>,
|
||||||
resize: View<WindowResizedEvent>,
|
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(
|
#[derive(Unique, Clone, Copy)]
|
||||||
storages: AllStoragesView,
|
#[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;
|
let size = storages.borrow::<View<WindowResizedEvent>>().unwrap().iter().next().unwrap().0;
|
||||||
storages.add_unique(WindowSize(size))
|
storages.add_unique(WindowSize(size))
|
||||||
}
|
}
|
||||||
|
@ -260,8 +92,8 @@ pub fn update_window_size(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn if_resized (
|
// pub fn if_resized (
|
||||||
resize: View<WindowResizedEvent>,
|
// resize: View<WindowResizedEvent>,
|
||||||
) -> bool {
|
// ) -> bool {
|
||||||
resize.len() > 0
|
// 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 bytemuck::{Pod, Zeroable};
|
||||||
use glam::IVec3;
|
use glam::{IVec3, Vec3};
|
||||||
use shipyard::{AllStoragesView, NonSendSync, Unique, UniqueView, UniqueViewMut, View};
|
use shipyard::{AllStoragesView, IntoIter, NonSendSync, Unique, UniqueView, UniqueViewMut, View};
|
||||||
use kubi_shared::transform::Transform;
|
use kubi_shared::{chunk::CHUNK_SIZE, transform::Transform};
|
||||||
use crate::{camera::Camera, settings::GameSettings, world::{ChunkMeshStorage, ChunkStorage}};
|
use crate::{camera::Camera, settings::GameSettings, world::{ChunkMeshStorage, ChunkStorage}};
|
||||||
use super::Renderer;
|
use super::Renderer;
|
||||||
|
|
||||||
|
@ -43,7 +43,37 @@ pub fn draw_world(
|
||||||
settings: UniqueView<GameSettings>,
|
settings: UniqueView<GameSettings>,
|
||||||
mut trans_queue: UniqueViewMut<TransChunkQueue>,
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO trans chunks
|
||||||
|
// if mesh.trans_index_buffer.len() > 0 {
|
||||||
|
// trans_queue.0.push(position);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue