Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod ds;
pub mod object;
pub mod material;
pub mod wgpu_handler;
pub mod wgpu_handler;
pub mod ui;
33 changes: 25 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::collections::HashMap;
use std::sync::{Arc, RwLock};

use clap::Parser;
use image::ImageReader;
use render_engine::ui::{self, UIElement};
use winit::application::ApplicationHandler;
use winit::event::{ElementState, KeyEvent, WindowEvent, DeviceEvent, DeviceId};
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
Expand Down Expand Up @@ -54,8 +56,9 @@ impl Arguments {

struct App {
// window
window: Option<Arc<Window>>,
gpu: wgpu_handler::GpuHandler,
window: Option<Arc<Window>>,
gpu: wgpu_handler::GpuHandler,
ui: Vec<UIElement>,

// scene
player: RwLock<object::Player>,
Expand All @@ -77,9 +80,18 @@ struct App {

impl App {
pub fn new(config: Arguments, player: object::Player, objects: Vec<Box<dyn object::Renderable>>) -> Self {
Self {
window: None,
gpu: wgpu_handler::GpuHandler::default(),
let this: Self = Self {
window: None,
gpu: wgpu_handler::GpuHandler::default(),
ui: vec![
ui::UIElement::new(
ui::Image::new(
ImageReader::open("./textures/crosshair.png").expect("No image").decode().expect("Bad decode").to_rgba8().into_raw(),
16, 16
).unwrap(),
ui::VerticalAnchor::Middle, ui::HorizontalAnchor::Center
)
],

player: RwLock::new(player),
objects: objects,
Expand All @@ -94,7 +106,9 @@ impl App {
fps_stat: 0,
deltatime_stat: 0,
statistics_timer: std::time::Instant::now(),
}
};

this
}

pub fn handle_movement(&mut self) {
Expand Down Expand Up @@ -149,8 +163,10 @@ impl App {
.filter_map(|o| o.as_any().downcast_ref::<object::Quad>())
.map(|s| s.to_gpu())
.collect();

let gpu_ui: Vec<ui::ui_element::GPUUIElement> = self.ui.iter().map(|s| s.to_gpu()).collect();

return self.gpu.draw_frame(&gpu_spheres, &gpu_quads, &mut uniform);
return self.gpu.draw_frame(&gpu_spheres, &gpu_quads, &gpu_ui, &mut uniform);
}
}

Expand All @@ -174,7 +190,8 @@ impl ApplicationHandler for App {
self.gpu.init(
window.clone(),
self.config.width as u32,
self.config.height as u32,
self.config.height as u32,
&mut self.ui,
vec!["textures/dirt.png", "textures/grass_side.png", "textures/grass_top.png"])
);

Expand Down
6 changes: 4 additions & 2 deletions src/object/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ pub struct GpuUniform {
pub sphere_count: u32,
pub pixel_delta_h: [f32; 3],
pub quad_count: u32,
pub _pad_end: [u32; 48], // pad to 256 bytes
pub texture_count: u32,
pub _pad_end: [u32; 47], // pad to 256 bytes
}

impl Camera {
Expand Down Expand Up @@ -125,7 +126,8 @@ impl Camera {
height: self.window_dimensions.1 as u32,
sphere_count: 0,
quad_count: 0,
_pad_end: [0u32; 48],
texture_count: 0,
_pad_end: [0u32; 47],
}
}

Expand Down
61 changes: 54 additions & 7 deletions src/shaders/main.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,81 @@ fn main(
return;
}


let pixel_center = uniforms.pixel00_loc
+ f32(x) * uniforms.pixel_delta_w
+ f32(y) * uniforms.pixel_delta_h;

let ray_dir = pixel_center - uniforms.pos;

let idx = y * uniforms.width + x;

if uniforms.sphere_count == 0u && uniforms.quad_count == 0u {
output[idx] = 0x00FF0000u;
return;
}

output[idx] = ray_color(uniforms.pos, ray_dir);
}

// not sure what these do but docs say i need them
// fragment shader is the second pass
@fragment
fn fs_main(@builtin(position) pos: vec4<f32>) -> @location(0) vec4<f32> {
let idx = u32(pos.y) * uniforms.width + u32(pos.x);

for (var i = 0u; i < uniforms.texture_count; i++) {
var ui_element = ui_info[i];

var top_left_y = ui_element.v_anchor * ((uniforms.height-ui_element.height)/2);
var top_left_x = ui_element.h_anchor * ((uniforms.width-ui_element.width)/2);

// shorthand for this kinda thing
// switch ui_element.v_anchor {
// case 0:
// break;
// case 1:
// top_left_y = uniforms.height/2 - ui_element.height/2;
// break;
// case 2:
// top_left_y = uniforms.height - ui_element.height;
// }

if(
u32(pos.x) >= top_left_x &&
u32(pos.x) < top_left_x+ui_element.width &&
u32(pos.y) >= top_left_y &&
u32(pos.y) < top_left_y+ui_element.height
) {
// we are inbound of the image, so draw the corresponding pixel

let rel_x = u32(pos.x) - top_left_x;
let rel_y = u32(pos.y) - top_left_y;

var c = ui_textures[ui_element.pointer + rel_x + rel_y*ui_element.width];
let r = f32((c ) & 0xFFu) / 255.0; // u8s are written as little endian, so i read it backwards
let g = f32((c >> 8u ) & 0xFFu) / 255.0;
let b = f32((c >> 16u) & 0xFFu) / 255.0;
let a = f32((c >> 24u) & 0xFFu) / 255.0;

c = output[idx];
let bg = vec4(
f32((c >> 16u) & 0xFFu) / 255.0,
f32((c >> 8u) & 0xFFu) / 255.0,
f32( c & 0xFFu) / 255.0,
1.0
);

return vec4(
r * a + bg.r * (1.0 - a),
g * a + bg.g * (1.0 - a),
b * a + bg.b * (1.0 - a),
1.0
);
}
}

let c = output[idx];
let r = f32((c >> 16u) & 0xFFu) / 255.0;
let g = f32((c >> 8u) & 0xFFu) / 255.0;
let b = f32( c & 0xFFu) / 255.0;
return vec4(r, g, b, 1.0);
}

// not sure what this does but docs say i need it
@vertex
fn vs_main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {
var positions = array<vec2<f32>, 3>(
Expand Down
11 changes: 11 additions & 0 deletions src/shaders/types.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ struct Uniform {
sphere_count: u32,
pixel_delta_h: vec3<f32>,
quad_count: u32,
texture_count: u32,
}

struct Sphere {
Expand Down Expand Up @@ -43,11 +44,21 @@ struct Material {
texture_id: i32,
}

struct UIElement {
v_anchor: u32,
h_anchor: u32,
width: u32,
height: u32,
pointer: u32
}

@group(0) @binding(0) var<uniform> uniforms: Uniform;
@group(0) @binding(1) var<storage, read_write> output: array<u32>;
@group(0) @binding(2) var<storage, read> spheres: array<Sphere>;
@group(0) @binding(3) var<storage, read> quads: array<Quad>;
@group(0) @binding(4) var textures: texture_2d<f32>;
@group(0) @binding(5) var<storage, read> ui_info: array<UIElement>;
@group(0) @binding(6) var<storage, read> ui_textures: array<u32>;

fn ray_at(ray_pos: vec3<f32>, ray_dir: vec3<f32>, t: f32) -> vec3<f32> {
return ray_pos + t * ray_dir;
Expand Down
46 changes: 46 additions & 0 deletions src/ui/anchor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
pub struct Anchor {
pub v_anchor: VerticalAnchor,
pub h_anchor: HorizontalAnchor
}

impl Anchor {
pub fn new(v: VerticalAnchor, h: HorizontalAnchor) -> Self {
Self {
v_anchor: v,
h_anchor: h,
}
}
}
#[derive(Copy, Clone)]
pub enum VerticalAnchor {
Top,
Middle,
Bottom
}

impl From<VerticalAnchor> for u32 {
fn from(a: VerticalAnchor) -> u32 {
return match a {
VerticalAnchor::Top => 0,
VerticalAnchor::Middle => 1,
VerticalAnchor::Bottom => 2,
}
}
}

#[derive(Copy, Clone)]
pub enum HorizontalAnchor {
Left,
Center,
Right
}

impl From<HorizontalAnchor> for u32 {
fn from(a: HorizontalAnchor) -> u32 {
return match a {
HorizontalAnchor::Left => 0,
HorizontalAnchor::Center => 1,
HorizontalAnchor::Right => 2,
}
}
}
62 changes: 62 additions & 0 deletions src/ui/image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
pub struct Image {
bytes: Vec<u8>,
width: usize,
height: usize,
}

#[derive(Debug)]
pub enum ImageError {
UncaughtException,
TooManyBytes,
NotEnoughBytes
}

impl Image {
pub fn new(bytes: Vec<u8>, width: usize, height: usize) -> Result<Self, ImageError> {
return match width*height*4 {
d if d > bytes.len() => Err(ImageError::NotEnoughBytes),
d if d < bytes.len() => Err(ImageError::TooManyBytes),
d if d == bytes.len() => {
Ok(Self {
bytes: bytes,
width: width,
height: height,
})
}
_ => Err(ImageError::UncaughtException),
}
}

pub fn at(&self, x: usize, y: usize) -> Option<&[u8]> {
let i = x*4 + y*self.width*4;
if i+4 > self.bytes.len() {
return None
}

Some(&self.bytes[i..i+4])
}

pub fn row(&self, y: usize) -> Option<&[u8]> {
if y >= self.height {
return None
}

Some(&self.bytes[y*self.width*4..(y+1)*self.width*4])
}

pub fn size(&self) -> usize {
self.width * self.height * 4
}

pub fn width(&self) -> usize {
self.width
}

pub fn height(&self) -> usize {
self.height
}

pub fn bytes(&self) -> &[u8] {
&self.bytes
}
}
9 changes: 9 additions & 0 deletions src/ui/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pub mod anchor;
pub mod image;
pub mod ui_element;

pub use anchor::Anchor;
pub use anchor::VerticalAnchor;
pub use anchor::HorizontalAnchor;
pub use image::Image;
pub use ui_element::UIElement;
Loading
Loading