aboutsummaryrefslogtreecommitdiff
path: root/stockton-render/src/draw
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:20 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:20 +0100
commitf6c2f402e245c620f8f03dcf3aa6265fca6e8dcf (patch)
tree96454af34e3a0cb15c17ccefea3d99ceb9a2ce3a /stockton-render/src/draw
parent9806e1d2552b944e809d4f545e5d8bdb6827c144 (diff)
feat(render): 3D projection
Diffstat (limited to 'stockton-render/src/draw')
-rw-r--r--stockton-render/src/draw/buffer.rs2
-rw-r--r--stockton-render/src/draw/camera.rs215
-rw-r--r--stockton-render/src/draw/context.rs68
-rw-r--r--stockton-render/src/draw/data/stockton.frag17
-rw-r--r--stockton-render/src/draw/data/stockton.vert22
-rw-r--r--stockton-render/src/draw/mod.rs1
6 files changed, 278 insertions, 47 deletions
diff --git a/stockton-render/src/draw/buffer.rs b/stockton-render/src/draw/buffer.rs
index 7bbd7e3..f59431e 100644
--- a/stockton-render/src/draw/buffer.rs
+++ b/stockton-render/src/draw/buffer.rs
@@ -86,7 +86,7 @@ impl<'a, T: Sized> StagedBuffer<'a, T> {
// Map it somewhere and get a slice to that memory
let staged_mapped_memory = unsafe {
- let ptr = device.map_memory(&staged_memory, Segment::ALL).unwrap();
+ let ptr = device.map_memory(&staged_memory, Segment::ALL).unwrap(); // TODO
std::slice::from_raw_parts_mut(ptr as *mut T, size.try_into().unwrap())
};
diff --git a/stockton-render/src/draw/camera.rs b/stockton-render/src/draw/camera.rs
new file mode 100644
index 0000000..2cba57e
--- /dev/null
+++ b/stockton-render/src/draw/camera.rs
@@ -0,0 +1,215 @@
+// Copyright (C) 2019 Oscar Shrimpton
+
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>.
+
+//! Things related to converting 3D world space to 2D screen space
+
+use std::iter::once;
+use hal::prelude::*;
+use hal::buffer::Usage;
+use na::{look_at_lh, perspective_lh_zo};
+
+use core::mem::ManuallyDrop;
+
+use crate::error;
+use crate::types::*;
+use super::buffer::{StagedBuffer, ModifiableBuffer};
+use stockton_types::{Vector3, Matrix4};
+
+/// Holds settings related to the projection of world space to screen space
+/// Also holds maths for generating important matrices
+pub struct Camera<'a> {
+ position: Vector3,
+ looking_at: Vector3,
+ up: Vector3,
+
+ /// Aspect ratio as a fraction
+ aspect_ratio: f32,
+
+ /// FOV in radians
+ fov: f32,
+
+ /// Near clipping plane (world units)
+ near: f32,
+
+ /// Far clipping plane (world units)
+ far: f32,
+
+ /// Layout of the descriptor set to pass to the shader
+ pub descriptor_set_layout: ManuallyDrop<DescriptorSetLayout>,
+
+ /// Buffer of memory used for passing data to shaders
+ // TODO: Does this need to be staged?
+ buffer: ManuallyDrop<StagedBuffer<'a, Matrix4>>,
+
+ // TODO: Share descriptor pool with textures?
+ descriptor_pool: ManuallyDrop<DescriptorPool>,
+ descriptor_set: DescriptorSet,
+
+ /// If true, buffer needs updated
+ is_dirty: bool
+}
+
+impl<'a> Camera<'a> {
+ /// Return a camera with default settings
+ // TODO
+ pub fn defaults(aspect_ratio: f32, device: &mut Device, adapter: &Adapter,
+ command_queue: &mut CommandQueue,
+ command_pool: &mut CommandPool) -> Result<Camera<'a>, error::CreationError> {
+
+ let descriptor_type = {
+ use hal::pso::{DescriptorType, BufferDescriptorType, BufferDescriptorFormat};
+
+ DescriptorType::Buffer {
+ ty: BufferDescriptorType::Uniform,
+ format: BufferDescriptorFormat::Structured {
+ dynamic_offset: false
+ }
+ }
+ };
+
+ // Create set layout
+ let descriptor_set_layout = unsafe {
+ use hal::pso::{DescriptorSetLayoutBinding, ShaderStageFlags};
+
+ device.create_descriptor_set_layout(
+ &[
+ DescriptorSetLayoutBinding {
+ binding: 0,
+ ty: descriptor_type,
+ count: 1,
+ stage_flags: ShaderStageFlags::VERTEX,
+ immutable_samplers: false
+ }
+ ],
+ &[],
+ )
+ }.map_err(|_| error::CreationError::OutOfMemoryError)?;
+
+ // Create pool and allocate set
+ let (descriptor_pool, descriptor_set) = unsafe {
+ use hal::pso::{DescriptorRangeDesc, DescriptorPoolCreateFlags};
+
+ let mut pool = device.create_descriptor_pool(
+ 1,
+ &[
+ DescriptorRangeDesc {
+ ty: descriptor_type,
+ count: 1
+ }
+ ],
+ DescriptorPoolCreateFlags::empty()
+ ).map_err(|_| error::CreationError::OutOfMemoryError)?;
+
+ let set = pool.allocate_set(&descriptor_set_layout).map_err(|_| error::CreationError::OutOfMemoryError)?;
+
+ (pool, set)
+ };
+
+ // Create buffer for descriptor
+ let mut buffer = StagedBuffer::new(device, adapter, Usage::UNIFORM, 1)?;
+
+ // Bind our buffer to our descriptor set
+ unsafe {
+ use hal::pso::{Descriptor, DescriptorSetWrite};
+ use hal::buffer::SubRange;
+
+ device.write_descriptor_sets(once(
+ DescriptorSetWrite {
+ set: &descriptor_set,
+ binding: 0,
+ array_offset: 0,
+ descriptors: once(
+ Descriptor::Buffer(buffer.commit(device, command_queue, command_pool), SubRange::WHOLE)
+ )
+ }
+ ));
+ }
+
+ Ok(Camera {
+ position: Vector3::new(-0.5, 1.5, -1.0),
+ looking_at: Vector3::new(0.5, 0.5, 0.5),
+ up: Vector3::new(0.0, 1.0, 0.0),
+
+ aspect_ratio,
+ fov: f32::to_radians(90.0),
+ near: 0.1,
+ far: 100.0,
+
+ descriptor_set_layout: ManuallyDrop::new(descriptor_set_layout),
+ buffer: ManuallyDrop::new(buffer),
+
+ descriptor_pool: ManuallyDrop::new(descriptor_pool),
+ descriptor_set: descriptor_set,
+
+ is_dirty: true
+ })
+ }
+
+ /// Returns a matrix that transforms from world space to screen space
+ pub fn vp_matrix(&self) -> Matrix4 {
+ // Converts world space to camera space
+ let view_matrix = look_at_lh(
+ &self.position,
+ &self.looking_at,
+ &self.up
+ );
+
+ // Converts camera space to screen space
+ let projection_matrix = {
+ let mut temp = perspective_lh_zo(
+ self.aspect_ratio,
+ self.fov,
+ self.near,
+ self.far
+ );
+
+ // Vulkan's co-ord system is different from openGLs
+ temp[(1, 1)] *= -1.0;
+
+ temp
+ };
+
+ // Chain them together into a single matrix
+ projection_matrix * view_matrix
+ }
+
+ pub fn commit<'b>(&'b mut self, device: &Device,
+ command_queue: &mut CommandQueue,
+ command_pool: &mut CommandPool) -> &'b DescriptorSet {
+ // Update buffer if needed
+ if self.is_dirty {
+ self.buffer[0] = self.vp_matrix();
+ self.buffer.commit(device, command_queue, command_pool);
+
+ self.is_dirty = false;
+ }
+
+ // Return the descriptor set for matrices
+ &self.descriptor_set
+ }
+
+ /// This should be called before dropping
+ pub fn deactivate(mut self, device: &mut Device) -> () {
+ unsafe {
+ use core::ptr::read;
+
+ ManuallyDrop::into_inner(read(&self.buffer)).deactivate(device);
+
+ self.descriptor_pool.reset();
+ device.destroy_descriptor_pool(ManuallyDrop::into_inner(read(&self.descriptor_pool)));
+ device.destroy_descriptor_set_layout(ManuallyDrop::into_inner(read(&self.descriptor_set_layout)));
+ }
+ }
+} \ No newline at end of file
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs
index c179f9d..061d22c 100644
--- a/stockton-render/src/draw/context.rs
+++ b/stockton-render/src/draw/context.rs
@@ -19,8 +19,8 @@
use std::{
mem::{ManuallyDrop, size_of},
- iter::once,
- ops::Deref
+ ops::Deref,
+ borrow::Borrow
};
use winit::window::Window;
use arrayvec::ArrayVec;
@@ -35,6 +35,7 @@ use stockton_types::{Vector2, Vector3};
use crate::types::*;
use crate::error;
+use super::camera::Camera;
use super::texture::TextureStore;
use super::buffer::{StagedBuffer, ModifiableBuffer};
@@ -63,9 +64,9 @@ const VERTEX_SOURCE: &str = include_str!("./data/stockton.vert");
/// Source for fragment shader. TODO
const FRAGMENT_SOURCE: &str = include_str!("./data/stockton.frag");
-/// Represents a point of a vertices, including RGB, UV and texture information.
+/// Represents a point of a triangle, including UV and texture information.
#[derive(Debug, Clone, Copy)]
-pub struct UVPoint (pub Vector2, pub Vector3, pub Vector2, pub i32);
+pub struct UVPoint (pub Vector3, pub Vector2, pub i32);
/// Contains all the hal related stuff.
/// In the end, this takes some 3D points and puts it on the screen.
@@ -109,6 +110,8 @@ pub struct RenderingContext<'a> {
// These are both staged
pub vert_buffer: ManuallyDrop<StagedBuffer<'a, UVPoint>>,
pub index_buffer: ManuallyDrop<StagedBuffer<'a, (u16, u16, u16)>>,
+
+ camera: ManuallyDrop<Camera<'a>>
}
impl<'a> RenderingContext<'a> {
@@ -129,7 +132,7 @@ impl<'a> RenderingContext<'a> {
let adapter = adapters.remove(0);
// Device & Queue group
- let (mut device, queue_group) = {
+ let (mut device, mut queue_group) = {
let family = adapter
.queue_families
.iter()
@@ -283,12 +286,12 @@ impl<'a> RenderingContext<'a> {
// Command Pool, Buffers, imageviews, framebuffers & Sync objects
let frames_in_flight = backbuffer.len();
- let (cmd_pool, cmd_buffers, get_image, render_complete, present_complete, imageviews, framebuffers) = {
+ let (mut cmd_pool, cmd_buffers, get_image, render_complete, present_complete, imageviews, framebuffers) = {
use hal::pool::CommandPoolCreateFlags;
use hal::command::Level;
let mut cmd_pool = ManuallyDrop::new(unsafe {
- device.create_command_pool(queue_group.family, CommandPoolCreateFlags::empty())
+ device.create_command_pool(queue_group.family, CommandPoolCreateFlags::RESET_INDIVIDUAL)
}.map_err(|_| error::CreationError::OutOfMemoryError)?);
let mut cmd_buffers = Vec::with_capacity(frames_in_flight);
@@ -332,8 +335,17 @@ impl<'a> RenderingContext<'a> {
// Texture store
let texture_store = TextureStore::new(&mut device, INITIAL_TEX_SIZE)?;
+ // Camera
+ // TODO: Settings
+ let ratio = extent.width as f32 / extent.height as f32;
+ let camera = Camera::defaults(ratio, &mut device, &adapter, &mut queue_group.queues[0], &mut cmd_pool)?;
+
+ let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new();
+ descriptor_set_layouts.push(camera.descriptor_set_layout.deref());
+ descriptor_set_layouts.push(texture_store.descriptor_set_layout.deref());
+
// Graphics pipeline
- let (pipeline_layout, pipeline) = Self::create_pipeline(&mut device, extent, &subpass, &texture_store.descriptor_set_layout)?;
+ let (pipeline_layout, pipeline) = Self::create_pipeline(&mut device, extent, &subpass, descriptor_set_layouts)?;
Ok(RenderingContext {
instance: ManuallyDrop::new(instance),
@@ -365,6 +377,8 @@ impl<'a> RenderingContext<'a> {
vert_buffer: ManuallyDrop::new(vert_buffer),
index_buffer: ManuallyDrop::new(index_buffer),
+
+ camera: ManuallyDrop::new(camera)
})
}
@@ -378,11 +392,11 @@ impl<'a> RenderingContext<'a> {
}
#[allow(clippy::type_complexity)]
- pub fn create_pipeline(device: &mut Device, extent: hal::image::Extent, subpass: &hal::pass::Subpass<back::Backend>, set_layout: &DescriptorSetLayout) -> Result<
+ pub fn create_pipeline<T>(device: &mut Device, extent: hal::image::Extent, subpass: &hal::pass::Subpass<back::Backend>, set_layouts: T) -> Result<
(
PipelineLayout,
GraphicsPipeline,
- ), error::CreationError> {
+ ), error::CreationError> where T: IntoIterator, T::Item: Borrow<DescriptorSetLayout> {
use hal::pso::*;
use hal::format::Format;
@@ -435,44 +449,37 @@ impl<'a> RenderingContext<'a> {
// Vertex buffers
let vertex_buffers: Vec<VertexBufferDesc> = vec![VertexBufferDesc {
binding: 0,
- stride: (size_of::<f32>() * 8) as u32,
+ stride: (size_of::<f32>() * 6) as u32,
rate: VertexInputRate::Vertex,
}];
- let attributes: Vec<AttributeDesc> = vec![AttributeDesc { // XY Attribute
+ let attributes: Vec<AttributeDesc> = vec![AttributeDesc { // XYZ Attribute
location: 0,
binding: 0,
element: Element {
- format: Format::Rg32Sfloat,
+ format: Format::Rgb32Sfloat,
offset: 0,
},
- }, AttributeDesc { // RGB Attribute
- location: 1,
- binding: 0,
- element: Element {
- format: Format::Rgb32Sfloat,
- offset: (size_of::<f32>() * 2) as ElemOffset,
- }
}, AttributeDesc { // UV Attribute
- location: 2,
+ location: 1,
binding: 0,
element: Element {
format: Format::Rg32Sfloat,
- offset: (size_of::<f32>() * 5) as ElemOffset,
+ offset: (size_of::<f32>() * 3) as ElemOffset,
}
}, AttributeDesc { // Tex Attribute
- location: 3,
+ location: 2,
binding: 0,
element: Element {
format: Format::R32Sint,
- offset: (size_of::<f32>() * 7) as ElemOffset
+ offset: (size_of::<f32>() * 5) as ElemOffset
}
}];
// Rasterizer
let rasterizer = Rasterizer {
polygon_mode: PolygonMode::Fill,
- cull_face: Face::NONE,
+ cull_face: Face::BACK,
front_face: FrontFace::Clockwise,
depth_clamping: false,
depth_bias: None,
@@ -489,7 +496,7 @@ impl<'a> RenderingContext<'a> {
// Pipeline layout
let layout = unsafe {
- device.create_pipeline_layout(once(set_layout), &[])
+ device.create_pipeline_layout(set_layouts, &[])
}.map_err(|_| error::CreationError::OutOfMemoryError)?;
// Colour blending
@@ -694,10 +701,16 @@ impl<'a> RenderingContext<'a> {
);
buffer.bind_graphics_pipeline(&self.pipeline);
+ let mut descriptor_sets: ArrayVec<[_; 2]> = ArrayVec::new();
+ descriptor_sets.push(self.camera.commit(&self.device,
+ &mut self.queue_group.queues[0],
+ &mut self.cmd_pool));
+ descriptor_sets.push(&self.texture_store.descriptor_set);
+
buffer.bind_graphics_descriptor_sets(
&self.pipeline_layout,
0,
- once(self.texture_store.descriptor_set.deref()),
+ descriptor_sets,
&[]
);
@@ -765,6 +778,7 @@ impl<'a> core::ops::Drop for RenderingContext<'a> {
ManuallyDrop::into_inner(read(&self.vert_buffer)).deactivate(&mut self.device);
ManuallyDrop::into_inner(read(&self.index_buffer)).deactivate(&mut self.device);
ManuallyDrop::into_inner(read(&self.texture_store)).deactivate(&mut self.device);
+ ManuallyDrop::into_inner(read(&self.camera)).deactivate(&mut self.device);
self.device.destroy_command_pool(
ManuallyDrop::into_inner(read(&self.cmd_pool)),
diff --git a/stockton-render/src/draw/data/stockton.frag b/stockton-render/src/draw/data/stockton.frag
index 09ff8a7..b558335 100644
--- a/stockton-render/src/draw/data/stockton.frag
+++ b/stockton-render/src/draw/data/stockton.frag
@@ -1,19 +1,16 @@
#version 450
-layout(set = 0, binding = 0) uniform texture2D tex[2];
-layout(set = 0, binding = 1) uniform sampler samp[2];
+// DescriptorSet 0 = Matrices
+// DescriptorSet 1 = Textures
+layout(set = 1, binding = 0) uniform texture2D tex[2];
+layout(set = 1, binding = 1) uniform sampler samp[2];
-layout (location = 1) in vec3 frag_color;
-layout (location = 2) in vec2 frag_uv;
-layout (location = 3) in flat int frag_tex;
+layout (location = 1) in vec2 frag_uv;
+layout (location = 2) in flat int frag_tex;
layout (location = 0) out vec4 color;
void main()
{
- if(frag_tex == -1) {
- color = vec4(frag_color, 1.0);
- } else {
- color = texture(sampler2D(tex[frag_tex], samp[frag_tex]), frag_uv);
- }
+ color = texture(sampler2D(tex[frag_tex], samp[frag_tex]), frag_uv);
} \ No newline at end of file
diff --git a/stockton-render/src/draw/data/stockton.vert b/stockton-render/src/draw/data/stockton.vert
index f40d0b8..d3f4438 100644
--- a/stockton-render/src/draw/data/stockton.vert
+++ b/stockton-render/src/draw/data/stockton.vert
@@ -1,21 +1,25 @@
#version 450
-layout (location = 0) in vec2 position;
-layout (location = 1) in vec3 colour;
-layout (location = 2) in vec2 uv;
-layout (location = 3) in int tex;
+// DescriptorSet 0 = Matrices
+layout (binding = 0) uniform UniformBufferObject {
+ mat4 vp;
+} matrices;
+
+// DescriptorSet 1 = Textures/Samplers
+
+layout (location = 0) in vec3 position;
+layout (location = 1) in vec2 uv;
+layout (location = 2) in int tex;
out gl_PerVertex {
vec4 gl_Position;
};
-layout (location = 1) out vec3 frag_colour;
-layout (location = 2) out vec2 frag_uv;
-layout (location = 3) out flat int frag_tex;
+layout (location = 1) out vec2 frag_uv;
+layout (location = 2) out flat int frag_tex;
void main()
{
- gl_Position = vec4(position, 0.0, 1.0);
- frag_colour = colour;
+ gl_Position = matrices.vp * vec4(position, 1.0);
frag_uv = uv;
frag_tex = tex;
} \ No newline at end of file
diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs
index a1a5780..00b5bb6 100644
--- a/stockton-render/src/draw/mod.rs
+++ b/stockton-render/src/draw/mod.rs
@@ -18,6 +18,7 @@
mod context;
mod buffer;
mod texture;
+mod camera;
pub use self::context::RenderingContext;
pub use self::context::UVPoint;