Compare commits
3 commits
main
...
transforms
Author | SHA1 | Date | |
---|---|---|---|
5afd5b0c1e | |||
0e8209f9b9 | |||
22a58044d5 |
7 changed files with 109 additions and 30 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3707,6 +3707,7 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||||
name = "zenyx"
|
name = "zenyx"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"build-print",
|
"build-print",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
|
@ -45,7 +45,7 @@ cgmath = "0.18.0"
|
||||||
image = "0.25.6"
|
image = "0.25.6"
|
||||||
smol = "2.0.2"
|
smol = "2.0.2"
|
||||||
|
|
||||||
winit = { version = "0.30.9" }
|
winit = "0.30.9"
|
||||||
terminator = "0.3.2"
|
terminator = "0.3.2"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
tobj = "4.0.3"
|
tobj = "4.0.3"
|
||||||
|
@ -55,10 +55,10 @@ vulkano = "0.35.1"
|
||||||
wgpu = { version = "25.0.0", features = ["spirv"] }
|
wgpu = { version = "25.0.0", features = ["spirv"] }
|
||||||
zlog.workspace = true
|
zlog.workspace = true
|
||||||
allocator-api2 = "0.2.21"
|
allocator-api2 = "0.2.21"
|
||||||
|
ahash = "0.8.11"
|
||||||
|
|
||||||
[target.aarch64-linux-android.dependencies]
|
[target.aarch64-linux-android.dependencies]
|
||||||
winit = { version = "0.30.9", features = ["android-native-activity"] }
|
winit = { version = "0.30.9", features = ["android-native-activity"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
build-print = "0.1.1"
|
build-print = "0.1.1"
|
||||||
bytemuck = "1.22.0"
|
bytemuck = "1.22.0"
|
||||||
|
|
11
build.rs
11
build.rs
|
@ -3,7 +3,7 @@ use naga::{
|
||||||
ShaderStage,
|
ShaderStage,
|
||||||
back::spv::{self, WriterFlags},
|
back::spv::{self, WriterFlags},
|
||||||
front::glsl::{self, Options as GlslOptions, ParseErrors},
|
front::glsl::{self, Options as GlslOptions, ParseErrors},
|
||||||
valid::{ValidationError, ValidationFlags, Validator},
|
valid::{Capabilities, ValidationError, ValidationFlags, Validator},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
env, fs,
|
env, fs,
|
||||||
|
@ -62,9 +62,12 @@ fn compile_shader(path: &Path, out_dir: &Path) -> Result<(), BuildError> {
|
||||||
let module = glsl::Frontend::default()
|
let module = glsl::Frontend::default()
|
||||||
.parse(&GlslOptions::from(stage), &src)
|
.parse(&GlslOptions::from(stage), &src)
|
||||||
.map_err(|e| (ext.clone(), e))?;
|
.map_err(|e| (ext.clone(), e))?;
|
||||||
let info = Validator::new(ValidationFlags::all(), Default::default())
|
let info = Validator::new(
|
||||||
.validate(&module)
|
ValidationFlags::all(),
|
||||||
.map_err(|e| (ext.clone(), e.into_inner()))?;
|
Capabilities::default().union(Capabilities::PUSH_CONSTANT),
|
||||||
|
)
|
||||||
|
.validate(&module)
|
||||||
|
.map_err(|e| (ext.clone(), e.into_inner()))?;
|
||||||
let mut writer = spv::Writer::new(&spv::Options {
|
let mut writer = spv::Writer::new(&spv::Options {
|
||||||
flags: WriterFlags::empty(),
|
flags: WriterFlags::empty(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec2 tex_coords;
|
layout(location = 0) in vec2 tex_coords;
|
||||||
|
layout(location = 1) in vec4 normal;
|
||||||
layout(set = 1, binding = 0) uniform texture2D t_diffuse;
|
layout(set = 1, binding = 0) uniform texture2D t_diffuse;
|
||||||
layout(set = 1, binding = 1) uniform sampler s_diffuse;
|
layout(set = 1, binding = 1) uniform sampler s_diffuse;
|
||||||
layout(location = 0) out vec4 out_color;
|
layout(location = 0) out vec4 out_color;
|
||||||
// layout(group = 0, binding = 0) out texture2D;
|
// layout(group = 0, binding = 0) out texture2D;
|
||||||
void main() {
|
void main() {
|
||||||
|
float ambient = 0.2;
|
||||||
|
vec3 light_dir = normalize(vec3(0.5, 1.0, 0.5));
|
||||||
|
float diffuse = clamp(dot(normalize(vec3(normal.x, normal.y, normal.z)), light_dir), 0.0, 1.0);
|
||||||
|
float brightness = ambient + (1.0 - ambient) * diffuse;
|
||||||
|
// out_color = vec4(normal.x, normal.y, normal.z, 1.0);
|
||||||
|
// out_color = vec3(1.0,.0.0)
|
||||||
out_color = texture(sampler2D(t_diffuse, s_diffuse), tex_coords);
|
out_color = texture(sampler2D(t_diffuse, s_diffuse), tex_coords);
|
||||||
|
out_color.r = clamp(out_color.r * 0.6 * brightness, 0.0, 1.0);
|
||||||
|
out_color.g = clamp(out_color.g * 0.6 * brightness, 0.0, 1.0);
|
||||||
|
out_color.b = clamp(out_color.b * 0.9 * brightness, 0.0, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,36 @@
|
||||||
|
|
||||||
layout(location = 0) in vec3 position;
|
layout(location = 0) in vec3 position;
|
||||||
layout(location = 1) in vec3 color;
|
layout(location = 1) in vec3 color;
|
||||||
|
layout(location = 2) in vec3 normal_in;
|
||||||
layout(location = 3) in vec2 tex_coords;
|
layout(location = 3) in vec2 tex_coords;
|
||||||
layout(location = 0) out vec2 tex_coord;
|
layout(location = 0) out vec2 tex_coord;
|
||||||
|
layout(location = 1) out vec4 normal;
|
||||||
|
layout(push_constant) uniform float TIME;
|
||||||
layout(set = 0, binding = 0) uniform UniformBufferObject {
|
layout(set = 0, binding = 0) uniform UniformBufferObject {
|
||||||
mat4x4 projection;
|
mat4x4 projection;
|
||||||
} view;
|
} view;
|
||||||
void main() {
|
mat4 rotation(float lerp) {
|
||||||
gl_Position = view.projection * vec4(position, 1.0);
|
return mat4(cos(lerp), -sin(lerp), 0., 0.,
|
||||||
tex_coord = tex_coords;
|
sin(lerp), cos(lerp), 0., 0.,
|
||||||
// gl_Position
|
0., 0., 1., 0.,
|
||||||
// out_color = color;
|
0., 0., 0., 1.);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float sum_val = sin(TIME / 5);
|
||||||
|
|
||||||
|
mat4 model = transpose(mat4(
|
||||||
|
1.0, 0.0, 0.0, sum_val,
|
||||||
|
0.0, 1.0, 0.0, sum_val,
|
||||||
|
0.0, 0.0, 1.0, sum_val,
|
||||||
|
0.0, 0.0, 0.0, 1.0) * mat4((sin(TIME) + 1.0) / 2, 0.0, 0.0, 0.0,
|
||||||
|
0.0, (sin(TIME) + 1.0) / 2, 0.0, 0.0,
|
||||||
|
0.0, 0.0, (sin(TIME) + 1.0) / 2, 0.0,
|
||||||
|
0.0, 0.0, 0.0, 1) * rotation(TIME * 2.5));
|
||||||
|
|
||||||
|
gl_Position = view.projection * model * vec4(position, 1.0);
|
||||||
|
tex_coord = tex_coords * abs(sin(TIME / 4));
|
||||||
|
// tex_coord.x = tex_coord.x * sin(TIME / 2);
|
||||||
|
// tex_coord.y = tex_coord.y * cos(TIME / 2);
|
||||||
|
normal = model * vec4(normal_in, 1.0);
|
||||||
}
|
}
|
||||||
|
|
72
src/main.rs
72
src/main.rs
|
@ -3,13 +3,14 @@ use std::collections::BTreeMap;
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use tracing::info;
|
use tracing::{error, info};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
Backends, FragmentState, IndexFormat, Instance, InstanceDescriptor, PipelineCompilationOptions,
|
Backends, Features, FragmentState, IndexFormat, Instance, InstanceDescriptor, Limits,
|
||||||
|
PipelineCompilationOptions, PushConstantRange, ShaderStages,
|
||||||
};
|
};
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::{ElementState, MouseButton};
|
use winit::event::{ElementState, MouseButton, WindowEvent};
|
||||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use winit::platform::android::activity::AndroidApp;
|
use winit::platform::android::activity::AndroidApp;
|
||||||
|
@ -48,6 +49,9 @@ struct WgpuRenderer<'surface> {
|
||||||
camera_bind_group: wgpu::BindGroup,
|
camera_bind_group: wgpu::BindGroup,
|
||||||
pumpkin: model::Model,
|
pumpkin: model::Model,
|
||||||
delta: f32,
|
delta: f32,
|
||||||
|
time_elapsed: f32,
|
||||||
|
start_time: Instant,
|
||||||
|
|
||||||
last_frame_time: Instant,
|
last_frame_time: Instant,
|
||||||
default_texture: wgpu::BindGroup,
|
default_texture: wgpu::BindGroup,
|
||||||
}
|
}
|
||||||
|
@ -85,6 +89,11 @@ impl WgpuRenderer<'_> {
|
||||||
});
|
});
|
||||||
rpass.set_pipeline(&self.render_pipeline);
|
rpass.set_pipeline(&self.render_pipeline);
|
||||||
rpass.set_bind_group(0, &self.camera_bind_group, &[]);
|
rpass.set_bind_group(0, &self.camera_bind_group, &[]);
|
||||||
|
rpass.set_push_constants(
|
||||||
|
ShaderStages::VERTEX,
|
||||||
|
0,
|
||||||
|
&bytemuck::cast_slice(&[self.time_elapsed]),
|
||||||
|
);
|
||||||
|
|
||||||
for mesh in &self.pumpkin.meshes {
|
for mesh in &self.pumpkin.meshes {
|
||||||
let bind_group = mesh
|
let bind_group = mesh
|
||||||
|
@ -99,9 +108,12 @@ impl WgpuRenderer<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.queue.submit(Some(encoder.finish()));
|
self.queue.submit(Some(encoder.finish()));
|
||||||
|
let elapsed_time = std::time::Instant::elapsed(&self.start_time);
|
||||||
|
self.time_elapsed = elapsed_time.as_secs_f32();
|
||||||
|
// info!("{}", self.time_elapsed);
|
||||||
let delta_time = std::time::Instant::now() - self.last_frame_time;
|
let delta_time = std::time::Instant::now() - self.last_frame_time;
|
||||||
self.delta = delta_time.as_secs_f32();
|
self.delta = delta_time.as_secs_f32();
|
||||||
info!("{}", self.delta);
|
// info!("{}", self.delta);
|
||||||
surface_texture.present();
|
surface_texture.present();
|
||||||
self.last_frame_time = std::time::Instant::now();
|
self.last_frame_time = std::time::Instant::now();
|
||||||
}
|
}
|
||||||
|
@ -153,17 +165,30 @@ impl WgpuState {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_renderer<'surface>(&self, window: Arc<Window>) -> WgpuRenderer<'surface> {
|
async fn create_renderer<'surface>(&self, window: Arc<Window>) -> WgpuRenderer<'surface> {
|
||||||
let surface = self.instance.create_surface(window.clone()).unwrap();
|
let surface = match self.instance.create_surface(window.clone()) {
|
||||||
|
Ok(surface) => surface,
|
||||||
|
Err(e) => {
|
||||||
|
panic!("{e}")
|
||||||
|
}
|
||||||
|
};
|
||||||
let adapter = self
|
let adapter = self
|
||||||
.instance
|
.instance
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
power_preference: wgpu::PowerPreference::default(),
|
power_preference: wgpu::PowerPreference::default(),
|
||||||
compatible_surface: Some(&surface),
|
compatible_surface: Some(&surface),
|
||||||
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let device_descriptor = wgpu::DeviceDescriptor::default();
|
let device_descriptor = wgpu::DeviceDescriptor {
|
||||||
|
required_features: Features::PUSH_CONSTANTS,
|
||||||
|
required_limits: Limits {
|
||||||
|
max_push_constant_size: 4,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
let (device, queue) = adapter.request_device(&device_descriptor).await.unwrap();
|
let (device, queue) = adapter.request_device(&device_descriptor).await.unwrap();
|
||||||
|
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
|
@ -212,7 +237,10 @@ impl WgpuState {
|
||||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("Pipeline Layout"),
|
label: Some("Pipeline Layout"),
|
||||||
bind_group_layouts: &[&camera_bind_group_layout, &texture_bind_group_layout],
|
bind_group_layouts: &[&camera_bind_group_layout, &texture_bind_group_layout],
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[PushConstantRange {
|
||||||
|
stages: ShaderStages::VERTEX,
|
||||||
|
range: 0..4,
|
||||||
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
let vert_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
let vert_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
@ -299,10 +327,10 @@ impl WgpuState {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
desired_maximum_frame_latency: 3,
|
desired_maximum_frame_latency: 3,
|
||||||
};
|
};
|
||||||
|
static PUMPKIN: &[u8] = include_bytes!("../Pumpkin.obj");
|
||||||
surface.configure(&device, &surface_config);
|
surface.configure(&device, &surface_config);
|
||||||
let pumpkin = model::Model::load_obj(
|
let pumpkin = model::Model::load_obj(
|
||||||
&mut BufReader::new(std::fs::File::open("Pumpkin.obj").unwrap()),
|
&mut BufReader::new(PUMPKIN),
|
||||||
&device,
|
&device,
|
||||||
&queue,
|
&queue,
|
||||||
&texture_bind_group_layout,
|
&texture_bind_group_layout,
|
||||||
|
@ -373,6 +401,7 @@ impl WgpuState {
|
||||||
let render_pipeline = device.create_render_pipeline(&pipeline_descriptor);
|
let render_pipeline = device.create_render_pipeline(&pipeline_descriptor);
|
||||||
|
|
||||||
WgpuRenderer {
|
WgpuRenderer {
|
||||||
|
time_elapsed: 0.0,
|
||||||
surface,
|
surface,
|
||||||
surface_config,
|
surface_config,
|
||||||
depth_texture,
|
depth_texture,
|
||||||
|
@ -386,6 +415,8 @@ impl WgpuState {
|
||||||
depth_texture_view,
|
depth_texture_view,
|
||||||
pumpkin,
|
pumpkin,
|
||||||
default_texture,
|
default_texture,
|
||||||
|
start_time: std::time::Instant::now(),
|
||||||
|
|
||||||
delta: 0f32,
|
delta: 0f32,
|
||||||
last_frame_time: Instant::now(),
|
last_frame_time: Instant::now(),
|
||||||
}
|
}
|
||||||
|
@ -427,15 +458,15 @@ impl ApplicationHandler for App<'_> {
|
||||||
event: winit::event::WindowEvent,
|
event: winit::event::WindowEvent,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
winit::event::WindowEvent::RedrawRequested => {
|
winit::event::WindowEvent::RedrawRequested => match self.windows.get_mut(&window_id) {
|
||||||
let window_ctx = self.windows.get_mut(&window_id).unwrap();
|
Some(window_ctx) => {
|
||||||
window_ctx.renderer.draw()
|
window_ctx.renderer.draw();
|
||||||
}
|
window_ctx.request_redraw();
|
||||||
|
}
|
||||||
|
None => self.resumed(event_loop),
|
||||||
|
},
|
||||||
winit::event::WindowEvent::CloseRequested => {
|
winit::event::WindowEvent::CloseRequested => {
|
||||||
let _ = self.windows.remove(&window_id);
|
let _ = self.windows.remove(&window_id);
|
||||||
if self.windows.is_empty() {
|
|
||||||
event_loop.exit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
winit::event::WindowEvent::MouseInput { state, button, .. } => {
|
winit::event::WindowEvent::MouseInput { state, button, .. } => {
|
||||||
if button == MouseButton::Left && state == ElementState::Pressed {
|
if button == MouseButton::Left && state == ElementState::Pressed {
|
||||||
|
@ -474,6 +505,11 @@ impl ApplicationHandler for App<'_> {
|
||||||
.configure(&window_ctx.renderer.device, &new_config)
|
.configure(&window_ctx.renderer.device, &new_config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
WindowEvent::Destroyed => {
|
||||||
|
if self.windows.is_empty() {
|
||||||
|
event_loop.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,12 +563,16 @@ pub fn run_app(event_loop: winit::event_loop::EventLoop<()>) -> Result<(), termi
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
extern "C" fn android_main(app: AndroidApp) {
|
extern "C" fn android_main(app: AndroidApp) {
|
||||||
|
use android_logger::Config;
|
||||||
|
use android_logger::FilterBuilder;
|
||||||
|
use tracing::level_filters::LevelFilter;
|
||||||
use winit::event_loop::EventLoopBuilder;
|
use winit::event_loop::EventLoopBuilder;
|
||||||
use winit::platform::android::EventLoopBuilderExtAndroid;
|
use winit::platform::android::EventLoopBuilderExtAndroid;
|
||||||
let event_loop = EventLoopBuilder::default()
|
let event_loop = EventLoopBuilder::default()
|
||||||
.with_android_app(app)
|
.with_android_app(app)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
android_logger::init_once(Config::default().with_tag("Zenyx"));
|
||||||
run_app(event_loop).unwrap()
|
run_app(event_loop).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
use std::io::{BufRead, BufReader};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io::{BufRead, BufReader},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::texture::Texture;
|
use crate::texture::Texture;
|
||||||
use cgmath::{Vector2, Vector3, Zero};
|
use cgmath::{Vector2, Vector3, Zero};
|
||||||
use tobj::Model as tModel;
|
use tobj::{MTLLoadResult, Model as tModel};
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
@ -38,7 +41,7 @@ impl Model {
|
||||||
single_index: true,
|
single_index: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|p| tobj::load_mtl_buf(&mut BufReader::new(std::fs::File::open(p).unwrap())),
|
|_| MTLLoadResult::Ok((vec![], ahash::AHashMap::new())),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue