mirror of
https://github.com/ScrelliCopter/NeHe-SDL_GPU.git
synced 2025-06-19 21:49:17 +10:00
rust: Implement lesson08
This commit is contained in:
@@ -36,3 +36,7 @@ path = "src/rust/lesson6.rs"
|
|||||||
[[bin]]
|
[[bin]]
|
||||||
name = "lesson7"
|
name = "lesson7"
|
||||||
path = "src/rust/lesson7.rs"
|
path = "src/rust/lesson7.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "lesson8"
|
||||||
|
path = "src/rust/lesson8.rs"
|
||||||
|
|||||||
1
build.rs
1
build.rs
@@ -42,6 +42,7 @@ pub fn main()
|
|||||||
&[
|
&[
|
||||||
"NeHe.bmp",
|
"NeHe.bmp",
|
||||||
"Crate.bmp",
|
"Crate.bmp",
|
||||||
|
"Glass.bmp",
|
||||||
]);
|
]);
|
||||||
copy_resources(&src_dir.join("shaders"), &dst_dir.join("Shaders"),
|
copy_resources(&src_dir.join("shaders"), &dst_dir.join("Shaders"),
|
||||||
&[
|
&[
|
||||||
|
|||||||
@@ -239,9 +239,10 @@ impl AppImplementation for Lesson7
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create texture samplers
|
// Create texture samplers
|
||||||
let create_sampler = |filter: SDL_GPUFilter, enable_mip: bool| -> Result<&mut SDL_GPUSampler, NeHeError>
|
let create_sampler = |filter: SDL_GPUFilter, enable_mip: bool|
|
||||||
|
-> Result<&mut SDL_GPUSampler, NeHeError>
|
||||||
{
|
{
|
||||||
let mut sampler_info: SDL_GPUSamplerCreateInfo = unsafe { std::mem::zeroed() };
|
let mut sampler_info = SDL_GPUSamplerCreateInfo::default();
|
||||||
sampler_info.min_filter = filter;
|
sampler_info.min_filter = filter;
|
||||||
sampler_info.mag_filter = filter;
|
sampler_info.mag_filter = filter;
|
||||||
sampler_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
sampler_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
||||||
|
|||||||
407
src/rust/lesson8.rs
Normal file
407
src/rust/lesson8.rs
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: (C) 2025 a dinosaur
|
||||||
|
* SPDX-License-Identifier: Zlib
|
||||||
|
*/
|
||||||
|
|
||||||
|
use nehe::application::config::AppImplementation;
|
||||||
|
use nehe::application::run;
|
||||||
|
use nehe::context::NeHeContext;
|
||||||
|
use nehe::error::NeHeError;
|
||||||
|
use nehe::matrix::Mtx;
|
||||||
|
use sdl3_sys::gpu::*;
|
||||||
|
use sdl3_sys::keyboard::SDL_GetKeyboardState;
|
||||||
|
use sdl3_sys::keycode::{SDL_Keycode, SDLK_B, SDLK_F, SDLK_L};
|
||||||
|
use sdl3_sys::pixels::SDL_FColor;
|
||||||
|
use sdl3_sys::scancode::{SDL_SCANCODE_DOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UP};
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::mem::offset_of;
|
||||||
|
use std::process::ExitCode;
|
||||||
|
use std::ptr::{addr_of, null_mut};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
x: f32, y: f32, z: f32,
|
||||||
|
nx: f32, ny: f32, nz: f32,
|
||||||
|
u: f32, v: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const VERTICES: &'static [Vertex] =
|
||||||
|
&[
|
||||||
|
// Front Face
|
||||||
|
Vertex { x: -1.0, y: -1.0, z: 1.0, nx: 0.0, ny: 0.0, nz: 1.0, u: 0.0, v: 0.0 },
|
||||||
|
Vertex { x: 1.0, y: -1.0, z: 1.0, nx: 0.0, ny: 0.0, nz: 1.0, u: 1.0, v: 0.0 },
|
||||||
|
Vertex { x: 1.0, y: 1.0, z: 1.0, nx: 0.0, ny: 0.0, nz: 1.0, u: 1.0, v: 1.0 },
|
||||||
|
Vertex { x: -1.0, y: 1.0, z: 1.0, nx: 0.0, ny: 0.0, nz: 1.0, u: 0.0, v: 1.0 },
|
||||||
|
// Back Face
|
||||||
|
Vertex { x: -1.0, y: -1.0, z: -1.0, nx: 0.0, ny: 0.0, nz: -1.0, u: 1.0, v: 0.0 },
|
||||||
|
Vertex { x: -1.0, y: 1.0, z: -1.0, nx: 0.0, ny: 0.0, nz: -1.0, u: 1.0, v: 1.0 },
|
||||||
|
Vertex { x: 1.0, y: 1.0, z: -1.0, nx: 0.0, ny: 0.0, nz: -1.0, u: 0.0, v: 1.0 },
|
||||||
|
Vertex { x: 1.0, y: -1.0, z: -1.0, nx: 0.0, ny: 0.0, nz: -1.0, u: 0.0, v: 0.0 },
|
||||||
|
// Top Face
|
||||||
|
Vertex { x: -1.0, y: 1.0, z: -1.0, nx: 0.0, ny: 1.0, nz: 0.0, u: 0.0, v: 1.0 },
|
||||||
|
Vertex { x: -1.0, y: 1.0, z: 1.0, nx: 0.0, ny: 1.0, nz: 0.0, u: 0.0, v: 0.0 },
|
||||||
|
Vertex { x: 1.0, y: 1.0, z: 1.0, nx: 0.0, ny: 1.0, nz: 0.0, u: 1.0, v: 0.0 },
|
||||||
|
Vertex { x: 1.0, y: 1.0, z: -1.0, nx: 0.0, ny: 1.0, nz: 0.0, u: 1.0, v: 1.0 },
|
||||||
|
// Bottom Face
|
||||||
|
Vertex { x: -1.0, y: -1.0, z: -1.0, nx: 0.0, ny: -1.0, nz: 0.0, u: 1.0, v: 1.0 },
|
||||||
|
Vertex { x: 1.0, y: -1.0, z: -1.0, nx: 0.0, ny: -1.0, nz: 0.0, u: 0.0, v: 1.0 },
|
||||||
|
Vertex { x: 1.0, y: -1.0, z: 1.0, nx: 0.0, ny: -1.0, nz: 0.0, u: 0.0, v: 0.0 },
|
||||||
|
Vertex { x: -1.0, y: -1.0, z: 1.0, nx: 0.0, ny: -1.0, nz: 0.0, u: 1.0, v: 0.0 },
|
||||||
|
// Right face
|
||||||
|
Vertex { x: 1.0, y: -1.0, z: -1.0, nx: 1.0, ny: 0.0, nz: 0.0, u: 1.0, v: 0.0 },
|
||||||
|
Vertex { x: 1.0, y: 1.0, z: -1.0, nx: 1.0, ny: 0.0, nz: 0.0, u: 1.0, v: 1.0 },
|
||||||
|
Vertex { x: 1.0, y: 1.0, z: 1.0, nx: 1.0, ny: 0.0, nz: 0.0, u: 0.0, v: 1.0 },
|
||||||
|
Vertex { x: 1.0, y: -1.0, z: 1.0, nx: 1.0, ny: 0.0, nz: 0.0, u: 0.0, v: 0.0 },
|
||||||
|
// Left Face
|
||||||
|
Vertex { x: -1.0, y: -1.0, z: -1.0, nx: -1.0, ny: 0.0, nz: 0.0, u: 0.0, v: 0.0 },
|
||||||
|
Vertex { x: -1.0, y: -1.0, z: 1.0, nx: -1.0, ny: 0.0, nz: 0.0, u: 1.0, v: 0.0 },
|
||||||
|
Vertex { x: -1.0, y: 1.0, z: 1.0, nx: -1.0, ny: 0.0, nz: 0.0, u: 1.0, v: 1.0 },
|
||||||
|
Vertex { x: -1.0, y: 1.0, z: -1.0, nx: -1.0, ny: 0.0, nz: 0.0, u: 0.0, v: 1.0 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const INDICES: &'static [u16] =
|
||||||
|
&[
|
||||||
|
0, 1, 2, 2, 3, 0, // Front
|
||||||
|
4, 5, 6, 6, 7, 4, // Back
|
||||||
|
8, 9, 10, 10, 11, 8, // Top
|
||||||
|
12, 13, 14, 14, 15, 12, // Bottom
|
||||||
|
16, 17, 18, 18, 19, 16, // Right
|
||||||
|
20, 21, 22, 22, 23, 20 // Left
|
||||||
|
];
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Light
|
||||||
|
{
|
||||||
|
ambient: (f32, f32, f32, f32),
|
||||||
|
diffuse: (f32, f32, f32, f32),
|
||||||
|
position: (f32, f32, f32, f32),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Lesson8
|
||||||
|
{
|
||||||
|
pso_unlit: *mut SDL_GPUGraphicsPipeline,
|
||||||
|
pso_light: *mut SDL_GPUGraphicsPipeline,
|
||||||
|
pso_blend_unlit: *mut SDL_GPUGraphicsPipeline,
|
||||||
|
pso_blend_light: *mut SDL_GPUGraphicsPipeline,
|
||||||
|
vtx_buffer: *mut SDL_GPUBuffer,
|
||||||
|
idx_buffer: *mut SDL_GPUBuffer,
|
||||||
|
samplers: [*mut SDL_GPUSampler; 3],
|
||||||
|
texture: *mut SDL_GPUTexture,
|
||||||
|
projection: Mtx,
|
||||||
|
|
||||||
|
lighting: bool,
|
||||||
|
blending: bool,
|
||||||
|
light: Light,
|
||||||
|
filter: usize,
|
||||||
|
|
||||||
|
rot: (f32, f32),
|
||||||
|
speed: (f32, f32),
|
||||||
|
z: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Lesson8
|
||||||
|
{
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self
|
||||||
|
{
|
||||||
|
pso_unlit: null_mut(),
|
||||||
|
pso_light: null_mut(),
|
||||||
|
pso_blend_unlit: null_mut(),
|
||||||
|
pso_blend_light: null_mut(),
|
||||||
|
vtx_buffer: null_mut(),
|
||||||
|
idx_buffer: null_mut(),
|
||||||
|
samplers: [null_mut(); 3],
|
||||||
|
texture: null_mut(),
|
||||||
|
projection: Mtx::IDENTITY,
|
||||||
|
|
||||||
|
lighting: false,
|
||||||
|
blending: false,
|
||||||
|
light: Light
|
||||||
|
{
|
||||||
|
ambient: (0.5, 0.5, 0.5, 1.0),
|
||||||
|
diffuse: (1.0, 1.0, 1.0, 1.0),
|
||||||
|
position: (0.0, 0.0, 2.0, 1.0),
|
||||||
|
},
|
||||||
|
filter: 0,
|
||||||
|
|
||||||
|
rot: (0.0, 0.0),
|
||||||
|
speed: (0.0, 0.0),
|
||||||
|
z: -5.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppImplementation for Lesson8
|
||||||
|
{
|
||||||
|
const TITLE: &'static str = "Tom Stanis & NeHe's Blending Tutorial";
|
||||||
|
const WIDTH: i32 = 640;
|
||||||
|
const HEIGHT: i32 = 480;
|
||||||
|
const CREATE_DEPTH_BUFFER: SDL_GPUTextureFormat = SDL_GPU_TEXTUREFORMAT_D16_UNORM;
|
||||||
|
|
||||||
|
fn init(&mut self, ctx: &NeHeContext) -> Result<(), NeHeError>
|
||||||
|
{
|
||||||
|
let (vertex_shader_unlit, fragment_shader_unlit) = ctx.load_shaders("lesson6", 1, 0, 1)?;
|
||||||
|
let (vertex_shader_light, fragment_shader_light) = ctx.load_shaders("lesson7", 2, 0, 1)?;
|
||||||
|
|
||||||
|
const VERTEX_DESCRIPTIONS: &'static [SDL_GPUVertexBufferDescription] =
|
||||||
|
&[
|
||||||
|
SDL_GPUVertexBufferDescription
|
||||||
|
{
|
||||||
|
slot: 0,
|
||||||
|
pitch: size_of::<Vertex>() as u32,
|
||||||
|
input_rate: SDL_GPU_VERTEXINPUTRATE_VERTEX,
|
||||||
|
instance_step_rate: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const VERTEX_ATTRIBS: &'static [SDL_GPUVertexAttribute] =
|
||||||
|
&[
|
||||||
|
SDL_GPUVertexAttribute
|
||||||
|
{
|
||||||
|
location: 0,
|
||||||
|
buffer_slot: 0,
|
||||||
|
format: SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3,
|
||||||
|
offset: offset_of!(Vertex, x) as u32,
|
||||||
|
},
|
||||||
|
SDL_GPUVertexAttribute
|
||||||
|
{
|
||||||
|
location: 2,
|
||||||
|
buffer_slot: 0,
|
||||||
|
format: SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3,
|
||||||
|
offset: offset_of!(Vertex, nx) as u32,
|
||||||
|
},
|
||||||
|
SDL_GPUVertexAttribute
|
||||||
|
{
|
||||||
|
location: 1,
|
||||||
|
buffer_slot: 0,
|
||||||
|
format: SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
|
||||||
|
offset: offset_of!(Vertex, u) as u32,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut info = SDL_GPUGraphicsPipelineCreateInfo::default();
|
||||||
|
info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
||||||
|
info.vertex_input_state = SDL_GPUVertexInputState
|
||||||
|
{
|
||||||
|
vertex_buffer_descriptions: VERTEX_DESCRIPTIONS.as_ptr(),
|
||||||
|
num_vertex_buffers: VERTEX_DESCRIPTIONS.len() as u32,
|
||||||
|
vertex_attributes: VERTEX_ATTRIBS.as_ptr(),
|
||||||
|
num_vertex_attributes: VERTEX_ATTRIBS.len() as u32,
|
||||||
|
};
|
||||||
|
info.rasterizer_state.fill_mode = SDL_GPU_FILLMODE_FILL;
|
||||||
|
info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE;
|
||||||
|
info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
|
||||||
|
|
||||||
|
// Common pipeline depth & colour target options
|
||||||
|
|
||||||
|
let mut color_target = [ SDL_GPUColorTargetDescription::default() ];
|
||||||
|
color_target[0].format = unsafe { SDL_GetGPUSwapchainTextureFormat(ctx.device, ctx.window) };
|
||||||
|
info.target_info.color_target_descriptions = color_target.as_ptr();
|
||||||
|
info.target_info.num_color_targets = 1;
|
||||||
|
info.target_info.depth_stencil_format = Self::CREATE_DEPTH_BUFFER;
|
||||||
|
info.target_info.has_depth_stencil_target = true;
|
||||||
|
info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL;
|
||||||
|
|
||||||
|
// Setup depth/stencil & colour pipeline state for no blending
|
||||||
|
info.depth_stencil_state.enable_depth_test = true;
|
||||||
|
info.depth_stencil_state.enable_depth_write = true;
|
||||||
|
color_target[0].blend_state = unsafe { std::mem::zeroed() };
|
||||||
|
|
||||||
|
// Create unlit pipeline
|
||||||
|
info.vertex_shader = vertex_shader_unlit;
|
||||||
|
info.fragment_shader = fragment_shader_unlit;
|
||||||
|
self.pso_unlit = unsafe { SDL_CreateGPUGraphicsPipeline(ctx.device, &info).as_mut() }
|
||||||
|
.ok_or(NeHeError::sdl("SDL_CreateGPUGraphicsPipeline"))?;
|
||||||
|
|
||||||
|
// Create lit pipeline
|
||||||
|
info.vertex_shader = vertex_shader_light;
|
||||||
|
info.fragment_shader = fragment_shader_light;
|
||||||
|
self.pso_light = unsafe { SDL_CreateGPUGraphicsPipeline(ctx.device, &info).as_mut() }
|
||||||
|
.ok_or(NeHeError::sdl("SDL_CreateGPUGraphicsPipeline"))?;
|
||||||
|
|
||||||
|
// Setup depth/stencil & colour pipeline state for blending
|
||||||
|
info.depth_stencil_state.enable_depth_test = false;
|
||||||
|
info.depth_stencil_state.enable_depth_write = false;
|
||||||
|
color_target[0].blend_state.enable_blend = true;
|
||||||
|
color_target[0].blend_state.color_blend_op = SDL_GPU_BLENDOP_ADD;
|
||||||
|
color_target[0].blend_state.alpha_blend_op = SDL_GPU_BLENDOP_ADD;
|
||||||
|
color_target[0].blend_state.src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA;
|
||||||
|
color_target[0].blend_state.dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
|
||||||
|
color_target[0].blend_state.src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA;
|
||||||
|
color_target[0].blend_state.dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE;
|
||||||
|
|
||||||
|
// Create unlit blended pipeline
|
||||||
|
info.vertex_shader = vertex_shader_unlit;
|
||||||
|
info.fragment_shader = fragment_shader_unlit;
|
||||||
|
self.pso_blend_unlit = unsafe { SDL_CreateGPUGraphicsPipeline(ctx.device, &info).as_mut() }
|
||||||
|
.ok_or(NeHeError::sdl("SDL_CreateGPUGraphicsPipeline"))?;
|
||||||
|
|
||||||
|
// Create lit blended pipeline
|
||||||
|
info.vertex_shader = vertex_shader_light;
|
||||||
|
info.fragment_shader = fragment_shader_light;
|
||||||
|
self.pso_blend_light = unsafe { SDL_CreateGPUGraphicsPipeline(ctx.device, &info).as_mut() }
|
||||||
|
.ok_or(NeHeError::sdl("SDL_CreateGPUGraphicsPipeline"))?;
|
||||||
|
|
||||||
|
// Free shaders
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
SDL_ReleaseGPUShader(ctx.device, fragment_shader_light);
|
||||||
|
SDL_ReleaseGPUShader(ctx.device, vertex_shader_light);
|
||||||
|
SDL_ReleaseGPUShader(ctx.device, fragment_shader_unlit);
|
||||||
|
SDL_ReleaseGPUShader(ctx.device, vertex_shader_unlit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create texture samplers
|
||||||
|
let create_sampler = |filter: SDL_GPUFilter, enable_mip: bool|
|
||||||
|
-> Result<&mut SDL_GPUSampler, NeHeError>
|
||||||
|
{
|
||||||
|
let mut sampler_info = SDL_GPUSamplerCreateInfo::default();
|
||||||
|
sampler_info.min_filter = filter;
|
||||||
|
sampler_info.mag_filter = filter;
|
||||||
|
sampler_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
||||||
|
sampler_info.max_lod = if enable_mip { f32::MAX } else { 0.0 };
|
||||||
|
unsafe { SDL_CreateGPUSampler(ctx.device, &sampler_info).as_mut() }
|
||||||
|
.ok_or(NeHeError::sdl("SDL_CreateGPUSampler"))
|
||||||
|
};
|
||||||
|
self.samplers[0] = create_sampler(SDL_GPU_FILTER_NEAREST, false)?;
|
||||||
|
self.samplers[1] = create_sampler(SDL_GPU_FILTER_LINEAR, false)?;
|
||||||
|
self.samplers[2] = create_sampler(SDL_GPU_FILTER_LINEAR, true)?;
|
||||||
|
|
||||||
|
ctx.copy_pass(|pass|
|
||||||
|
{
|
||||||
|
self.texture = pass.load_texture("Data/Glass.bmp", true, true)?;
|
||||||
|
self.vtx_buffer = pass.create_buffer(SDL_GPU_BUFFERUSAGE_VERTEX, VERTICES)?;
|
||||||
|
self.idx_buffer = pass.create_buffer(SDL_GPU_BUFFERUSAGE_INDEX, INDICES)?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quit(&mut self, ctx: &NeHeContext)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
SDL_ReleaseGPUBuffer(ctx.device, self.idx_buffer);
|
||||||
|
SDL_ReleaseGPUBuffer(ctx.device, self.vtx_buffer);
|
||||||
|
SDL_ReleaseGPUTexture(ctx.device, self.texture);
|
||||||
|
self.samplers.iter().rev().for_each(|sampler| SDL_ReleaseGPUSampler(ctx.device, *sampler));
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(ctx.device, self.pso_blend_light);
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(ctx.device, self.pso_blend_unlit);
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(ctx.device, self.pso_light);
|
||||||
|
SDL_ReleaseGPUGraphicsPipeline(ctx.device, self.pso_unlit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(&mut self, _ctx: &NeHeContext, width: i32, height: i32)
|
||||||
|
{
|
||||||
|
let aspect = width as f32 / max(height, 1) as f32;
|
||||||
|
self.projection = Mtx::perspective(45.0, aspect, 0.1, 100.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, ctx: &NeHeContext, cmd: *mut SDL_GPUCommandBuffer, swapchain: *mut SDL_GPUTexture)
|
||||||
|
{
|
||||||
|
let mut color_info = SDL_GPUColorTargetInfo::default();
|
||||||
|
color_info.texture = swapchain;
|
||||||
|
color_info.clear_color = SDL_FColor { r: 0.0, g: 0.0, b: 0.0, a: 0.5 };
|
||||||
|
color_info.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
color_info.store_op = SDL_GPU_STOREOP_STORE;
|
||||||
|
|
||||||
|
let mut depth_info = SDL_GPUDepthStencilTargetInfo::default();
|
||||||
|
depth_info.texture = ctx.depth_texture;
|
||||||
|
depth_info.clear_depth = 1.0;
|
||||||
|
depth_info.load_op = SDL_GPU_LOADOP_CLEAR;
|
||||||
|
depth_info.store_op = SDL_GPU_STOREOP_DONT_CARE;
|
||||||
|
depth_info.stencil_load_op = SDL_GPU_LOADOP_DONT_CARE;
|
||||||
|
depth_info.stencil_store_op = SDL_GPU_STOREOP_DONT_CARE;
|
||||||
|
depth_info.cycle = true;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
// Begin pass & bind pipeline state
|
||||||
|
let pass = SDL_BeginGPURenderPass(cmd, &color_info, 1, &depth_info);
|
||||||
|
SDL_BindGPUGraphicsPipeline(pass, match (self.blending, self.lighting)
|
||||||
|
{
|
||||||
|
(false, false) => self.pso_unlit,
|
||||||
|
(false, true) => self.pso_light,
|
||||||
|
(true, false) => self.pso_blend_unlit,
|
||||||
|
(true, true) => self.pso_blend_light,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bind texture
|
||||||
|
let texture_binding = SDL_GPUTextureSamplerBinding
|
||||||
|
{
|
||||||
|
texture: self.texture,
|
||||||
|
sampler: self.samplers[self.filter],
|
||||||
|
};
|
||||||
|
SDL_BindGPUFragmentSamplers(pass, 0, &texture_binding, 1);
|
||||||
|
|
||||||
|
// Bind vertex & index buffers
|
||||||
|
let vtx_binding = SDL_GPUBufferBinding { buffer: self.vtx_buffer, offset: 0 };
|
||||||
|
let idx_binding = SDL_GPUBufferBinding { buffer: self.idx_buffer, offset: 0 };
|
||||||
|
SDL_BindGPUVertexBuffers(pass, 0, &vtx_binding, 1);
|
||||||
|
SDL_BindGPUIndexBuffer(pass, &idx_binding, SDL_GPU_INDEXELEMENTSIZE_16BIT);
|
||||||
|
|
||||||
|
// Setup the cube's model matrix
|
||||||
|
let mut model = Mtx::translation(0.0, 0.0, self.z);
|
||||||
|
model.rotate(self.rot.0, 1.0, 0.0, 0.0);
|
||||||
|
model.rotate(self.rot.1, 0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
// Push shader uniforms
|
||||||
|
if self.lighting
|
||||||
|
{
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Uniforms { model: Mtx, projection: Mtx }
|
||||||
|
let u = Uniforms { model, projection: self.projection };
|
||||||
|
SDL_PushGPUVertexUniformData(cmd, 0, addr_of!(u) as *const c_void, size_of::<Uniforms>() as u32);
|
||||||
|
SDL_PushGPUVertexUniformData(cmd, 1, addr_of!(self.light) as *const c_void, size_of::<Light>() as u32);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct Uniforms { model_view_proj: Mtx, color: [f32; 4] }
|
||||||
|
let color = [1.0, 1.0, 1.0, 0.5]; // 50% translucency
|
||||||
|
let u = Uniforms { model_view_proj: self.projection * model, color };
|
||||||
|
SDL_PushGPUVertexUniformData(cmd, 0, addr_of!(u) as *const c_void, size_of::<Uniforms>() as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the textured cube
|
||||||
|
SDL_DrawGPUIndexedPrimitives(pass, INDICES.len() as u32, 1, 0, 0, 0);
|
||||||
|
|
||||||
|
SDL_EndGPURenderPass(pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
let keys = unsafe
|
||||||
|
{
|
||||||
|
let mut numkeys: std::ffi::c_int = 0;
|
||||||
|
let keys = SDL_GetKeyboardState(&mut numkeys);
|
||||||
|
std::slice::from_raw_parts(keys, numkeys as usize)
|
||||||
|
};
|
||||||
|
if keys[SDL_SCANCODE_PAGEUP.0 as usize] { self.z -= 0.02 }
|
||||||
|
if keys[SDL_SCANCODE_PAGEDOWN.0 as usize] { self.z += 0.02; }
|
||||||
|
if keys[SDL_SCANCODE_UP.0 as usize] { self.speed.0 -= 0.01; }
|
||||||
|
if keys[SDL_SCANCODE_DOWN.0 as usize] { self.speed.0 += 0.01; }
|
||||||
|
if keys[SDL_SCANCODE_RIGHT.0 as usize] { self.speed.1 += 0.1; }
|
||||||
|
if keys[SDL_SCANCODE_LEFT.0 as usize] { self.speed.1 -= 0.1; }
|
||||||
|
|
||||||
|
self.rot.0 += self.speed.0;
|
||||||
|
self.rot.1 += self.speed.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key(&mut self, _ctx: &NeHeContext, key: SDL_Keycode, down: bool, _repeat: bool)
|
||||||
|
{
|
||||||
|
match key
|
||||||
|
{
|
||||||
|
SDLK_L if down => self.lighting = !self.lighting,
|
||||||
|
SDLK_B if down => self.blending = !self.blending,
|
||||||
|
SDLK_F if down => self.filter = (self.filter + 1) % self.samplers.len(),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() -> Result<ExitCode, Box<dyn std::error::Error>>
|
||||||
|
{
|
||||||
|
run::<Lesson8>()?;
|
||||||
|
Ok(ExitCode::SUCCESS)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user