Compare commits
No commits in common. "4caf3485875faa1bdf3140cb73b85e0b270d86d6" and "2b7a562b308eda25f02c4bff45811341ddbdfdac" have entirely different histories.
4caf348587
...
2b7a562b30
63
Cargo.lock
generated
63
Cargo.lock
generated
@ -233,20 +233,6 @@ name = "bytemuck"
|
|||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
|
checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
|
||||||
dependencies = [
|
|
||||||
"bytemuck_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytemuck_derive"
|
|
||||||
version = "1.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.87",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
@ -595,18 +581,6 @@ version = "0.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flume"
|
|
||||||
version = "0.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
"nanorand",
|
|
||||||
"spin",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -758,10 +732,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -786,9 +758,6 @@ name = "glam"
|
|||||||
version = "0.29.2"
|
version = "0.29.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
|
checksum = "dc46dd3ec48fdd8e693a98d2b8bafae273a2d54c1de02a2a7e3d57d501f39677"
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
@ -839,7 +808,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"presser",
|
"presser",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"windows 0.58.0",
|
"windows 0.56.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1446,12 +1415,6 @@ dependencies = [
|
|||||||
name = "mp_elements"
|
name = "mp_elements"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
|
||||||
"flume",
|
|
||||||
"glam",
|
|
||||||
"mp_core",
|
|
||||||
"pollster",
|
|
||||||
"regex",
|
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1476,15 +1439,6 @@ dependencies = [
|
|||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nanorand"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi-derive-backend-ohos"
|
name = "napi-derive-backend-ohos"
|
||||||
version = "0.0.7"
|
version = "0.0.7"
|
||||||
@ -1757,12 +1711,6 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pollster"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@ -2196,15 +2144,6 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "spin"
|
|
||||||
version = "0.9.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
|
||||||
dependencies = [
|
|
||||||
"lock_api",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spirv"
|
name = "spirv"
|
||||||
version = "0.3.0+sdk-1.3.268.0"
|
version = "0.3.0+sdk-1.3.268.0"
|
||||||
|
|||||||
@ -4,10 +4,4 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = { version = "1.19.0", features = ["derive"] }
|
|
||||||
glam = { version = "0.29.2", features = ["bytemuck"] }
|
|
||||||
regex = "1.11.1"
|
|
||||||
wgpu = "23.0.0"
|
wgpu = "23.0.0"
|
||||||
mp_core = { path = "../mp_core", version = "*" }
|
|
||||||
flume = "0.11.1"
|
|
||||||
pollster = "0.4.0"
|
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
@group(1) @binding(0) var color_map_texture: texture_2d<f32>;
|
|
||||||
@group(1) @binding(1) var color_map_sampler: sampler;
|
|
||||||
@group(1) @binding(2) var<uniform> color_map_params: ColorMapParams;
|
|
||||||
|
|
||||||
struct ColorMapParams {
|
|
||||||
color_count: u32,
|
|
||||||
value_min: f32,
|
|
||||||
value_max: f32
|
|
||||||
invalid_value: f32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_idx(ratio: f32) -> f32 {
|
|
||||||
var sum = 0.0;
|
|
||||||
var i = 0.0;
|
|
||||||
var count = (color_map_params.color_count - 1) as f32;
|
|
||||||
while (ratio > sum) {
|
|
||||||
sum += textureSample(color_map_texture, color_map_sampler, vec2<f32>(i / count, 0.0)).r;
|
|
||||||
i += 1.0;
|
|
||||||
}
|
|
||||||
return i / count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn linear_colormap(value: f32) -> vec4f {
|
|
||||||
var v = clamp((value - color_map_params.value_min) / (color_map_params.value_max - color_map_params.value_min), 0.0, 1.0);
|
|
||||||
float idx = find_idx(v);
|
|
||||||
let c0: vec3f = textureSample(color_map_texture, color_map_sampler, vec2<f32>(idx, 0.0)).rgb;
|
|
||||||
return vec4f(c0, 1.0);
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
const PI:f32 = 3.14159265358979323846264338327950288;
|
|
||||||
const TWO_PI:f32 = 6.28318530717958647692528676655900576;
|
|
||||||
const HALF_PI:f32 = 1.57079632679489661923132169163975144;
|
|
||||||
const LOG2:f32 = 0.693147180559945309417232121458176568;
|
|
||||||
const LOG10:f32 = 2.30258509299404568401799145468436421;
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
#include "constants.wgsl";
|
|
||||||
#include "colormap.wgsl";
|
|
||||||
|
|
||||||
@group(2) @binding(0) var<uniform> params: UniformParams;
|
|
||||||
@group(2) @binding(1) var data_buffer: texture_3d<f32>;
|
|
||||||
|
|
||||||
struct UniformParams {
|
|
||||||
origin: vec3f
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VertexOutput {
|
|
||||||
@location(0) position: vec4f,
|
|
||||||
@location(1) r_range: vec2f,
|
|
||||||
@location(2) idx: vec3f
|
|
||||||
}
|
|
||||||
|
|
||||||
struct UniformParams {
|
|
||||||
// Model-View-Projection matrix
|
|
||||||
mvp: mat4x4f,
|
|
||||||
origin: vec3f
|
|
||||||
}
|
|
||||||
|
|
||||||
@vertex
|
|
||||||
fn vertex(
|
|
||||||
@location(0) position: vec3f,
|
|
||||||
@location(1) r_range: vec2f,
|
|
||||||
@location(2) idx: vec3f
|
|
||||||
) -> VertexOutput {
|
|
||||||
|
|
||||||
var out: VertexOutput;
|
|
||||||
|
|
||||||
// Transform position
|
|
||||||
out.position = params.mvp * vec4f(position, 1.0);
|
|
||||||
out.r_range = r_range;
|
|
||||||
out.idx = idx;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn polar_forward(cartesian: vec3f) -> vec3f {
|
|
||||||
let r = length(cartesian.xy - params.origin.xy);
|
|
||||||
let theta = atan2(cartesian.y, cartesian.x);
|
|
||||||
let z = cartesian.z;
|
|
||||||
return vec3f(r, theta, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@fragment
|
|
||||||
fn fragment(input: VertexOutput) -> location(0) vec4f {
|
|
||||||
// Sample data texture
|
|
||||||
let value = textureSample(data_texture, data_sampler, input.idx).r;
|
|
||||||
let ear = polar_forward(input.position);
|
|
||||||
var color = linear_colormap(value);
|
|
||||||
|
|
||||||
let r = ear.z;
|
|
||||||
// Valid range
|
|
||||||
let r_range = input.r_range;
|
|
||||||
|
|
||||||
let outside_lower_bound = step(r, r_range.x);
|
|
||||||
let outside_upper_bound = step(r_range.y, r);
|
|
||||||
let is_outside = outside_lower_bound + outside_upper_bound;
|
|
||||||
color.a *= 1.0 - is_outside;
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,35 +1,18 @@
|
|||||||
use std::collections::HashMap;
|
use wgpu::{core::instance, Backends, Instance, RequestAdapterOptions};
|
||||||
|
pub struct App {}
|
||||||
use crate::elements::{ElementAttach, Elements, ElementsRef};
|
|
||||||
use crate::elementvec::ElementVec;
|
|
||||||
use wgpu::{Backends, Instance};
|
|
||||||
|
|
||||||
const BACKENDS_DEFAULT: u32 = Backends::DX12.bits()
|
const BACKENDS_DEFAULT: u32 = Backends::DX12.bits()
|
||||||
| Backends::METAL.bits()
|
| Backends::METAL.bits()
|
||||||
| Backends::GL.bits()
|
| Backends::GL.bits()
|
||||||
| Backends::BROWSER_WEBGPU.bits();
|
| Backends::BROWSER_WEBGPU.bits();
|
||||||
|
|
||||||
pub struct App {
|
|
||||||
device: wgpu::Device,
|
|
||||||
queue: wgpu::Queue,
|
|
||||||
common_utils: CommonUtils,
|
|
||||||
_texture: wgpu::Texture,
|
|
||||||
texture_view: wgpu::TextureView,
|
|
||||||
pipelines: Option<ElementVec>,
|
|
||||||
|
|
||||||
buffer_pool: DataBufferPool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub async fn instant() -> Self {
|
pub async fn inistant() -> Self {
|
||||||
// 修复方法名称拼写错误
|
|
||||||
// Instance is a handle to the backend. It is used to create adapters.
|
|
||||||
let instance = Instance::new(wgpu::InstanceDescriptor {
|
let instance = Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends: Backends::from_bits(BACKENDS_DEFAULT).unwrap(),
|
backends: Backends::from_bits(BACKENDS_DEFAULT).unwrap(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Request an adapter, which is a handle to a physical device.
|
|
||||||
let adapter = instance
|
let adapter = instance
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
power_preference: wgpu::PowerPreference::default(),
|
power_preference: wgpu::PowerPreference::default(),
|
||||||
@ -39,279 +22,27 @@ impl App {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Request a device and a queue from the adapter. The device is the handle to the GPU, and the queue is used to submit commands to the GPU.
|
|
||||||
let (device, queue) = adapter
|
let (device, queue) = adapter
|
||||||
.request_device(&Default::default(), None)
|
.request_device(&Default::default(), None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Create a new instance of the common utils struct. This struct contains the bind group layout, bind group, and uniform buffer.
|
let texture_size = 256u32;
|
||||||
let common_utils = CommonUtils::new(&device);
|
let texture_desc = wgpu::TextureDescriptor {
|
||||||
|
|
||||||
// Create a new texture. This texture will be used as the output texture for the render pass.
|
|
||||||
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
|
||||||
label: Some("output texture"),
|
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
width: 800,
|
width: texture_size,
|
||||||
height: 600,
|
height: texture_size,
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
},
|
},
|
||||||
mip_level_count: 1,
|
mip_level_count: 1,
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
label: None,
|
||||||
view_formats: &[],
|
view_formats: &[],
|
||||||
});
|
};
|
||||||
|
|
||||||
// Create a texture view from the texture. This texture view will be used as the output texture for the render pass.
|
Self {}
|
||||||
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
// Buffer pool
|
|
||||||
let buffer_pool = DataBufferPool::new();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
device,
|
|
||||||
queue,
|
|
||||||
common_utils,
|
|
||||||
pipelines: None,
|
|
||||||
_texture: texture,
|
|
||||||
texture_view,
|
|
||||||
buffer_pool,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new context struct. This struct contains references to the device, queue, bind group layout, and bind group.
|
|
||||||
pub fn ctx(&self) -> Ctx {
|
|
||||||
Ctx::new(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the app. This method creates the pipelines and initializes the elements.
|
|
||||||
pub async fn init(&mut self) {
|
|
||||||
self.pipelines = Some(ElementVec::init(&Ctx::new(self)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a reference to the pipelines.
|
|
||||||
pub fn pipelines(&self) -> &ElementVec {
|
|
||||||
self.pipelines.as_ref().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn common_utils_mut(&mut self) -> &mut CommonUtils {
|
|
||||||
&mut self.common_utils
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw the elements in the draw list.
|
|
||||||
pub fn draw(&self, draw_list: DrawList) {
|
|
||||||
let mut encoder = self
|
|
||||||
.device
|
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
||||||
label: Some("draw_command_encoder"),
|
|
||||||
});
|
|
||||||
|
|
||||||
{
|
|
||||||
let render_pass_desc = wgpu::RenderPassDescriptor {
|
|
||||||
label: Some("Some Render Pass"),
|
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
||||||
view: &self.texture_view,
|
|
||||||
resolve_target: None,
|
|
||||||
ops: wgpu::Operations {
|
|
||||||
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
|
|
||||||
store: wgpu::StoreOp::Store,
|
|
||||||
},
|
|
||||||
})],
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
let mut render_pass = encoder.begin_render_pass(&render_pass_desc);
|
|
||||||
|
|
||||||
// Set the common utils bind group.
|
|
||||||
let common_utils = &self.common_utils.bind_group;
|
|
||||||
|
|
||||||
// Draw each element in the draw list.
|
|
||||||
for (attach, element) in draw_list.elements {
|
|
||||||
let pipeline = element.pipeline();
|
|
||||||
// Set the pipeline for the render pass.
|
|
||||||
render_pass.set_pipeline(pipeline);
|
|
||||||
|
|
||||||
// Set the common utils bind group for the render pass.
|
|
||||||
render_pass.set_bind_group(0, common_utils, &[]);
|
|
||||||
|
|
||||||
// Set the bind group for the render pass.
|
|
||||||
for (index, bind_group) in attach.bind_group.iter() {
|
|
||||||
render_pass.set_bind_group(*index, bind_group, &[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the bind group for the render pass.
|
|
||||||
attach.bind(&mut render_pass);
|
|
||||||
|
|
||||||
// Draw the element.
|
|
||||||
element.draw(attach, &mut render_pass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.queue.submit(Some(encoder.finish()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ctx<'a> {
|
|
||||||
pub device: &'a wgpu::Device,
|
|
||||||
pub queue: &'a wgpu::Queue,
|
|
||||||
pub common_tools_bind_group_layout: &'a wgpu::BindGroupLayout,
|
|
||||||
pub common_tools_bind_group: &'a wgpu::BindGroup,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Ctx<'a> {
|
|
||||||
pub fn bind_group_layout(&self) -> Vec<wgpu::BindGroupLayout> {
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(app: &'a App) -> Self {
|
|
||||||
Self {
|
|
||||||
device: &app.device,
|
|
||||||
queue: &app.queue,
|
|
||||||
common_tools_bind_group_layout: &app.common_utils.bind_group_layout,
|
|
||||||
common_tools_bind_group: &app.common_utils.bind_group,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DrawList<'b, 'a: 'b> {
|
|
||||||
pub elements: Vec<(&'b ElementAttach, ElementsRef<'a>)>, // 修复字段访问权限
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'b, 'a: 'b> DrawList<'b, 'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { elements: vec![] }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push<Ele: Into<ElementsRef<'a>>>(&mut self, element: Ele, attach: &'a ElementAttach) {
|
|
||||||
self.elements.push((attach, element.into()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct CommonUniform {
|
|
||||||
pub model_matrix: glam::Mat4,
|
|
||||||
pub view_matrix: glam::Mat4,
|
|
||||||
pub proj_matrix: glam::Mat4,
|
|
||||||
pub camera_position: glam::Vec3,
|
|
||||||
pub camera_front: glam::Vec3,
|
|
||||||
pub camera_up: glam::Vec3,
|
|
||||||
pub light_position: glam::Vec3,
|
|
||||||
pub light_color: glam::Vec3,
|
|
||||||
pub light_intensity: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CommonUtils {
|
|
||||||
pub bind_group_layout: wgpu::BindGroupLayout,
|
|
||||||
pub bind_group: wgpu::BindGroup,
|
|
||||||
pub uniform_buffer: wgpu::Buffer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommonUtils {
|
|
||||||
fn new(device: &wgpu::Device) -> Self {
|
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
label: Some("common_utils_bind_group_layout"),
|
|
||||||
entries: &[wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::all(),
|
|
||||||
ty: wgpu::BindingType::Buffer {
|
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: None,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
label: Some("common_utils_buffer"),
|
|
||||||
size: std::mem::size_of::<CommonUniform>() as u64,
|
|
||||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,
|
|
||||||
mapped_at_creation: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
label: Some("common_utils_bind_group"),
|
|
||||||
layout: &bind_group_layout,
|
|
||||||
entries: &[wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: buffer.as_entire_binding(),
|
|
||||||
}],
|
|
||||||
});
|
|
||||||
|
|
||||||
Self {
|
|
||||||
bind_group_layout,
|
|
||||||
bind_group,
|
|
||||||
uniform_buffer: buffer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DataBufferPool {
|
|
||||||
buffers: HashMap<BufferKey, wgpu::Buffer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DataBufferPool {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
buffers: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_or_create_buffer(&mut self) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub struct BufferKey {
|
|
||||||
pub size: u64,
|
|
||||||
pub from: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test {
|
|
||||||
use mp_core::{PluginManager, RadarGridData};
|
|
||||||
|
|
||||||
use crate::elements::{Element, PPI};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_app() {
|
|
||||||
let plugin_manager = PluginManager::new("/Users/tsuki/projects/mp/loaders").unwrap();
|
|
||||||
|
|
||||||
let data = plugin_manager.try_load_data(
|
|
||||||
"/Users/tsuki/Desktop/Z_RADR_I_X5775_20230726180000_O_DOR-XPD-CAP-FMT.BIN.zip",
|
|
||||||
);
|
|
||||||
|
|
||||||
pollster::block_on(async {
|
|
||||||
let mut app = App::instant().await;
|
|
||||||
app.init().await;
|
|
||||||
|
|
||||||
let pipelines = app.pipelines();
|
|
||||||
let ctx = app.ctx();
|
|
||||||
|
|
||||||
let ppi = pipelines.ppi();
|
|
||||||
|
|
||||||
if let Ok(data) = data {
|
|
||||||
let first_block = data.first().unwrap();
|
|
||||||
|
|
||||||
// Convert the first block into a PPI struct.
|
|
||||||
if let Ok(data) = first_block.try_into() {
|
|
||||||
let buffer_pool = &mut app.buffer_pool;
|
|
||||||
// Reused buffer is None, so a new attachment is created.
|
|
||||||
let attachment = ppi.new_attachment(&ctx, buffer_pool);
|
|
||||||
|
|
||||||
// Load the data into the attachment.
|
|
||||||
ppi.load_data(&ctx, data, &attachment);
|
|
||||||
|
|
||||||
// Create a new draw list and push the attachment into it.
|
|
||||||
let mut draw_list = DrawList::new();
|
|
||||||
draw_list.push(ppi, &attachment);
|
|
||||||
|
|
||||||
// Draw the elements in the draw list.
|
|
||||||
app.draw(draw_list);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("Failed to load data");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,111 +0,0 @@
|
|||||||
pub mod ppi;
|
|
||||||
use crate::app::{Ctx, DataBufferPool};
|
|
||||||
pub use ppi::PPI;
|
|
||||||
use std::any::Any;
|
|
||||||
use wgpu::util::DeviceExt;
|
|
||||||
|
|
||||||
macro_rules! elements {
|
|
||||||
($(($element_name:ident,$element: ty),)+) => {
|
|
||||||
pub enum Elements {
|
|
||||||
$($element_name($element),)+
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ElementsRef<'a> {
|
|
||||||
$($element_name(&'a $element),)+
|
|
||||||
}
|
|
||||||
|
|
||||||
$(
|
|
||||||
impl From<$element> for Elements {
|
|
||||||
fn from(element: $element) -> Self {
|
|
||||||
Elements::$element_name(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> From<&'a $element> for ElementsRef<'a> {
|
|
||||||
fn from(element: &'a $element) -> Self {
|
|
||||||
ElementsRef::$element_name(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
|
|
||||||
impl Elements {
|
|
||||||
pub fn pipeline(&self) -> &wgpu::RenderPipeline {
|
|
||||||
match self {
|
|
||||||
$(Elements::$element_name(element) => element.pipeline(),)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(&self, attach: &ElementAttach, render_pass: &mut wgpu::RenderPass) {
|
|
||||||
match self {
|
|
||||||
$(Elements::$element_name(element) => element.draw(attach, render_pass),)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ElementsRef<'a> {
|
|
||||||
pub fn pipeline(&'a self) -> &wgpu::RenderPipeline {
|
|
||||||
match self {
|
|
||||||
$(ElementsRef::$element_name(element) => element.pipeline(),)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(&'a self, attach: &ElementAttach, render_pass: &mut wgpu::RenderPass) {
|
|
||||||
match self {
|
|
||||||
$(ElementsRef::$element_name(element) => element.draw(attach, render_pass),)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Element {
|
|
||||||
type Vertex;
|
|
||||||
type Uniform;
|
|
||||||
type Data;
|
|
||||||
|
|
||||||
fn new(ctx: &Ctx) -> Self;
|
|
||||||
|
|
||||||
fn new_attachment<'a>(&self, ctx: &Ctx, buffer_pool: &'a mut DataBufferPool) -> ElementAttach;
|
|
||||||
|
|
||||||
// Bake the data into vertices and indices
|
|
||||||
fn bake(&self, data: &Self::Data) -> (Vec<Self::Vertex>, Option<Vec<u32>>);
|
|
||||||
|
|
||||||
fn supports(&self, _data: &Self::Data) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pipeline(&self) -> &wgpu::RenderPipeline;
|
|
||||||
|
|
||||||
fn draw(&self, attach: &ElementAttach, render_pass: &mut wgpu::RenderPass);
|
|
||||||
|
|
||||||
fn load_data(&self, ctx: &Ctx, data: &Self::Data, attach: &ElementAttach);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ElementAttach {
|
|
||||||
pub vertex_buffer: wgpu::Buffer,
|
|
||||||
pub index_buffer: Option<wgpu::Buffer>,
|
|
||||||
pub num_indices: u32,
|
|
||||||
pub uniform_buffer: Option<wgpu::Buffer>,
|
|
||||||
pub bind_group: Vec<(u32, wgpu::BindGroup)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementAttach {
|
|
||||||
pub fn update_data<T>(&self, ctx: &Ctx, data: (Vec<T>, Option<Vec<u32>>))
|
|
||||||
where
|
|
||||||
T: bytemuck::Zeroable + bytemuck::Pod,
|
|
||||||
{
|
|
||||||
let device = ctx.device;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bind(&self, render_pass: &mut wgpu::RenderPass) {
|
|
||||||
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
|
||||||
if let Some(index_buffer) = &self.index_buffer {
|
|
||||||
render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
elements! {
|
|
||||||
(PPI, PPI),
|
|
||||||
}
|
|
||||||
@ -1,408 +0,0 @@
|
|||||||
use std::{ops::Sub, result};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
app::{Ctx, DataBufferPool},
|
|
||||||
utils::merge_shader,
|
|
||||||
};
|
|
||||||
use bytemuck;
|
|
||||||
use glam::Vec3;
|
|
||||||
use mp_core::{data::CoordType, RadarGridData};
|
|
||||||
|
|
||||||
use super::{Element, ElementAttach};
|
|
||||||
|
|
||||||
const EMAXNUM: u64 = 50;
|
|
||||||
const AMAXNUM: u64 = 360;
|
|
||||||
const RMAXNUM: u64 = 50;
|
|
||||||
|
|
||||||
pub struct PPI {
|
|
||||||
bind_group_layout: wgpu::BindGroupLayout,
|
|
||||||
pipeline: wgpu::RenderPipeline,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
|
||||||
pub struct PPIUniform {
|
|
||||||
origin: Vec3,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
|
||||||
pub struct PPIVertex {
|
|
||||||
position: Vec3,
|
|
||||||
r_ranges: [f32; 2],
|
|
||||||
idx: [u32; 3],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PPIVertex {
|
|
||||||
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
|
||||||
wgpu::VertexBufferLayout {
|
|
||||||
array_stride: std::mem::size_of::<Self>() as wgpu::BufferAddress,
|
|
||||||
step_mode: wgpu::VertexStepMode::Vertex,
|
|
||||||
attributes: &[
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: 0,
|
|
||||||
shader_location: 0,
|
|
||||||
format: wgpu::VertexFormat::Float32x3,
|
|
||||||
},
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: std::mem::size_of::<Vec3>() as wgpu::BufferAddress,
|
|
||||||
shader_location: 1,
|
|
||||||
format: wgpu::VertexFormat::Float32x2,
|
|
||||||
},
|
|
||||||
wgpu::VertexAttribute {
|
|
||||||
offset: std::mem::size_of::<[f32; 2]>() as wgpu::BufferAddress,
|
|
||||||
shader_location: 2,
|
|
||||||
format: wgpu::VertexFormat::Uint32x3,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Element for PPI {
|
|
||||||
type Vertex = PPIVertex;
|
|
||||||
type Uniform = PPIUniform;
|
|
||||||
type Data = RadarGridData;
|
|
||||||
|
|
||||||
fn new(ctx: &Ctx) -> Self {
|
|
||||||
let device = ctx.device;
|
|
||||||
// Group Layout
|
|
||||||
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
|
||||||
label: Some("PPI Bind Group Layout"),
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 0,
|
|
||||||
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Buffer {
|
|
||||||
ty: wgpu::BufferBindingType::Uniform,
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: None,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
wgpu::BindGroupLayoutEntry {
|
|
||||||
binding: 1,
|
|
||||||
visibility: wgpu::ShaderStages::FRAGMENT,
|
|
||||||
ty: wgpu::BindingType::Buffer {
|
|
||||||
ty: wgpu::BufferBindingType::Storage { read_only: true },
|
|
||||||
has_dynamic_offset: false,
|
|
||||||
min_binding_size: None,
|
|
||||||
},
|
|
||||||
count: None,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Shader Code
|
|
||||||
let shader = Self::init_shader(device);
|
|
||||||
|
|
||||||
// Render Pipeline Layout
|
|
||||||
let render_pipeline_layout =
|
|
||||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
||||||
label: Some("PPI Render Pipeline Layout"),
|
|
||||||
bind_group_layouts: &[
|
|
||||||
// common_tools
|
|
||||||
&ctx.common_tools_bind_group_layout,
|
|
||||||
// ppi
|
|
||||||
&bind_group_layout,
|
|
||||||
],
|
|
||||||
push_constant_ranges: &[],
|
|
||||||
});
|
|
||||||
|
|
||||||
// Render Pipeline
|
|
||||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
||||||
label: Some("PPI Render Pipeline"),
|
|
||||||
layout: Some(&render_pipeline_layout),
|
|
||||||
vertex: wgpu::VertexState {
|
|
||||||
module: &shader,
|
|
||||||
compilation_options: Default::default(),
|
|
||||||
entry_point: Some("vertex"),
|
|
||||||
buffers: &[PPIVertex::desc()],
|
|
||||||
},
|
|
||||||
fragment: Some(wgpu::FragmentState {
|
|
||||||
module: &shader,
|
|
||||||
compilation_options: Default::default(),
|
|
||||||
entry_point: Some("fragment"),
|
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
|
||||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
|
||||||
blend: None,
|
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
|
||||||
})],
|
|
||||||
}),
|
|
||||||
primitive: wgpu::PrimitiveState {
|
|
||||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
|
||||||
strip_index_format: None,
|
|
||||||
front_face: wgpu::FrontFace::Ccw,
|
|
||||||
cull_mode: None,
|
|
||||||
polygon_mode: wgpu::PolygonMode::Fill,
|
|
||||||
unclipped_depth: false,
|
|
||||||
conservative: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
depth_stencil: None,
|
|
||||||
multisample: wgpu::MultisampleState {
|
|
||||||
count: 1,
|
|
||||||
mask: !0,
|
|
||||||
alpha_to_coverage_enabled: false,
|
|
||||||
},
|
|
||||||
multiview: None,
|
|
||||||
cache: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
PPI {
|
|
||||||
bind_group_layout: bind_group_layout,
|
|
||||||
pipeline: render_pipeline,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_attachment<'a>(&self, ctx: &Ctx, buffer_pool: &'a mut DataBufferPool) -> ElementAttach {
|
|
||||||
let device = ctx.device;
|
|
||||||
|
|
||||||
// Buffers
|
|
||||||
|
|
||||||
let data_buffer = buffer_pool.get_or_create_buffer();
|
|
||||||
// let data_buffer = if let Some(reused) = reused_buffer {
|
|
||||||
// reused[0]
|
|
||||||
// } else {
|
|
||||||
// &Self::create_data_buffer(device)
|
|
||||||
// };
|
|
||||||
|
|
||||||
let uniform_buffer = Self::create_uniform_buffer(device);
|
|
||||||
|
|
||||||
// Bind Group
|
|
||||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
|
||||||
layout: &self.bind_group_layout,
|
|
||||||
entries: &[
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 0,
|
|
||||||
resource: uniform_buffer.as_entire_binding(),
|
|
||||||
},
|
|
||||||
wgpu::BindGroupEntry {
|
|
||||||
binding: 1,
|
|
||||||
resource: data_buffer.as_entire_binding(),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
label: Some("PPI Bind Group"),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Vertex Buffer
|
|
||||||
let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
label: Some("PPI Vertex Buffer"),
|
|
||||||
mapped_at_creation: false,
|
|
||||||
size: std::mem::size_of::<PPIVertex>() as wgpu::BufferAddress * EMAXNUM * AMAXNUM,
|
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Index Buffer
|
|
||||||
let index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
label: Some("PPI Index Buffer"),
|
|
||||||
mapped_at_creation: false,
|
|
||||||
size: EMAXNUM
|
|
||||||
* AMAXNUM
|
|
||||||
* RMAXNUM
|
|
||||||
* 6
|
|
||||||
* std::mem::size_of::<u32>() as wgpu::BufferAddress,
|
|
||||||
usage: wgpu::BufferUsages::INDEX,
|
|
||||||
});
|
|
||||||
|
|
||||||
ElementAttach {
|
|
||||||
vertex_buffer,
|
|
||||||
index_buffer: Some(index_buffer),
|
|
||||||
num_indices: 0,
|
|
||||||
uniform_buffer: Some(uniform_buffer),
|
|
||||||
bind_group: vec![(1, bind_group)],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bake(&self, data: &Self::Data) -> (Vec<Self::Vertex>, Option<Vec<u32>>) {
|
|
||||||
let coord_typ = data.coord_type().unwrap();
|
|
||||||
|
|
||||||
if let CoordType::Polar {
|
|
||||||
range,
|
|
||||||
azimuth,
|
|
||||||
elevation,
|
|
||||||
} = coord_typ
|
|
||||||
{
|
|
||||||
let e = elevation.map(|v| *v.first().unwrap_or(&0.0)).unwrap_or(0.0);
|
|
||||||
let (vertices, indices) = Self::bake_vi(e, azimuth, &range);
|
|
||||||
|
|
||||||
(vertices, Some(indices))
|
|
||||||
} else {
|
|
||||||
panic!("PPI only supports polar coordinates");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pipeline(&self) -> &wgpu::RenderPipeline {
|
|
||||||
&self.pipeline
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(&self, attach: &ElementAttach, render_pass: &mut wgpu::RenderPass) {
|
|
||||||
render_pass.draw_indexed(0..attach.num_indices, 0, 0..1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_data(&self, ctx: &Ctx, data: &Self::Data, attach: &ElementAttach) {
|
|
||||||
let (vertex, index) = self.bake(data);
|
|
||||||
let queue = ctx.queue;
|
|
||||||
|
|
||||||
// Update Vertex Buffer
|
|
||||||
let vertex_buffer = &attach.vertex_buffer;
|
|
||||||
queue.write_buffer(vertex_buffer, 0, bytemuck::cast_slice(&vertex));
|
|
||||||
|
|
||||||
// Update Index Buffer
|
|
||||||
if let Some(indices) = index {
|
|
||||||
let index_buffer = attach.index_buffer.as_ref().unwrap();
|
|
||||||
queue.write_buffer(index_buffer, 0, bytemuck::cast_slice(&indices));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load Data
|
|
||||||
let data_array = data.get_data();
|
|
||||||
let data_array_f32 = data_array.cast_to::<f32>();
|
|
||||||
queue.write_buffer(
|
|
||||||
data_buffer,
|
|
||||||
0,
|
|
||||||
bytemuck::cast_slice(data_array_f32.as_slice().unwrap()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PPI {
|
|
||||||
fn init_shader(device: &wgpu::Device) -> wgpu::ShaderModule {
|
|
||||||
let shader_str = merge_shader("../../shaders/ppi.wgsl");
|
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
||||||
label: Some("PPI Shader Module"),
|
|
||||||
source: wgpu::ShaderSource::Wgsl(shader_str.into()),
|
|
||||||
});
|
|
||||||
shader
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_uniform_buffer(device: &wgpu::Device) -> wgpu::Buffer {
|
|
||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
label: Some("PPI Uniform Buffer"),
|
|
||||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::STORAGE,
|
|
||||||
size: 0,
|
|
||||||
mapped_at_creation: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_data_buffer(device: &wgpu::Device) -> wgpu::Buffer {
|
|
||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
|
||||||
label: Some("PPI Texture Buffer"),
|
|
||||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::STORAGE,
|
|
||||||
size: 0,
|
|
||||||
mapped_at_creation: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bake_vi(e: f64, a: &Vec<f64>, r: &Vec<f64>) -> (Vec<PPIVertex>, Vec<u32>) {
|
|
||||||
// Sort azimuth
|
|
||||||
let mut sorted_azimuth = a.clone();
|
|
||||||
sorted_azimuth.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Greater));
|
|
||||||
|
|
||||||
// Calculate step
|
|
||||||
let azi_step = max_step(&sorted_azimuth, f64::MIN) / 2.0;
|
|
||||||
let r_step = min_step(&r, f64::MAX) / (r[r.len() - 1]) / 2.0;
|
|
||||||
let r_step_f32 = r_step as f32;
|
|
||||||
|
|
||||||
// One cell has 4 vertices
|
|
||||||
let mut vertexs = Vec::with_capacity(a.len() * r.len() * 4);
|
|
||||||
for (a_idx, _a) in sorted_azimuth.into_iter().enumerate() {
|
|
||||||
for (r_idx, _r) in r.iter().enumerate() {
|
|
||||||
let r_ranges = [*_r as f32 - r_step_f32, *_r as f32 + r_step_f32];
|
|
||||||
let idx = [0, a_idx as u32, r_idx as u32];
|
|
||||||
// Left Top
|
|
||||||
let lt = polar_to_cartesian(*_r + r_step, _a - azi_step, e);
|
|
||||||
vertexs.push(PPIVertex {
|
|
||||||
position: Vec3::new(lt.0, lt.1, lt.2),
|
|
||||||
r_ranges,
|
|
||||||
idx,
|
|
||||||
});
|
|
||||||
// Left Bot
|
|
||||||
let lb = polar_to_cartesian(*_r - r_step, _a - azi_step, e);
|
|
||||||
vertexs.push(PPIVertex {
|
|
||||||
position: Vec3::new(lb.0, lb.1, lb.2),
|
|
||||||
r_ranges,
|
|
||||||
idx,
|
|
||||||
});
|
|
||||||
// Right Top
|
|
||||||
let rt = polar_to_cartesian(*_r + r_step, _a + azi_step, e);
|
|
||||||
vertexs.push(PPIVertex {
|
|
||||||
position: Vec3::new(rt.0, rt.1, rt.2),
|
|
||||||
r_ranges,
|
|
||||||
idx,
|
|
||||||
});
|
|
||||||
// Right Bot
|
|
||||||
let rb = polar_to_cartesian(*_r - r_step, _a + azi_step, e);
|
|
||||||
vertexs.push(PPIVertex {
|
|
||||||
position: Vec3::new(rb.0, rb.1, rb.2),
|
|
||||||
r_ranges,
|
|
||||||
idx,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// index buffer
|
|
||||||
let mut indice_buffer = Vec::with_capacity(a.len() * r.len() * 6);
|
|
||||||
for a_idx in 0..a.len() - 1 {
|
|
||||||
for r_idx in 0..r.len() - 1 {
|
|
||||||
let lt = (a_idx * r.len() + r_idx) as u32;
|
|
||||||
let lb = (a_idx * r.len() + r_idx + 1) as u32;
|
|
||||||
let rt = ((a_idx + 1) * r.len() + r_idx) as u32;
|
|
||||||
let rb = ((a_idx + 1) * r.len() + r_idx + 1) as u32;
|
|
||||||
|
|
||||||
indice_buffer.push(lt);
|
|
||||||
indice_buffer.push(lb);
|
|
||||||
indice_buffer.push(rt);
|
|
||||||
|
|
||||||
indice_buffer.push(lb);
|
|
||||||
indice_buffer.push(rb);
|
|
||||||
indice_buffer.push(rt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (vertexs, indice_buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn min_step<T: Sub<T, Output = T> + Copy>(data: &Vec<T>, gap: T) -> T
|
|
||||||
where
|
|
||||||
<T as std::ops::Sub>::Output: PartialOrd<T>,
|
|
||||||
{
|
|
||||||
// 计算相邻元素之间的间距
|
|
||||||
let mut min_gap = gap;
|
|
||||||
for window in data.windows(2) {
|
|
||||||
if let [a, b] = window {
|
|
||||||
let gap = *b - *a;
|
|
||||||
if gap < min_gap {
|
|
||||||
min_gap = gap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return min_gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_step<T: Copy + Sub<T, Output = T>>(data: &Vec<T>, gap: T) -> T
|
|
||||||
where
|
|
||||||
<T as std::ops::Sub>::Output: PartialOrd<T>,
|
|
||||||
{
|
|
||||||
// 计算相邻元素之间的间距
|
|
||||||
let mut max_gap = gap;
|
|
||||||
for window in data.windows(2) {
|
|
||||||
if let [a, b] = window {
|
|
||||||
let gap = *b - *a;
|
|
||||||
if gap > max_gap {
|
|
||||||
max_gap = gap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return max_gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn polar_to_cartesian(r: f64, azimuth: f64, elevation: f64) -> (f32, f32, f32) {
|
|
||||||
let x = r * azimuth.cos() * elevation.cos();
|
|
||||||
let y = r * azimuth.sin() * elevation.cos();
|
|
||||||
let z = r * elevation.sin();
|
|
||||||
(x as f32, y as f32, z as f32)
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
use crate::app::Ctx;
|
|
||||||
use crate::elements::*;
|
|
||||||
macro_rules! elementvec {
|
|
||||||
($({$element: ident, $element_ty: ty})+) => {
|
|
||||||
pub struct ElementVec {
|
|
||||||
$($element: $element_ty,)+
|
|
||||||
}
|
|
||||||
impl ElementVec {
|
|
||||||
pub fn init(ctx: &Ctx) -> Self {
|
|
||||||
// Compile the shaders, create the pipelines, etc.
|
|
||||||
Self {
|
|
||||||
$($element: <$element_ty>::new(ctx),)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(pub fn $element(&self) -> &$element_ty {
|
|
||||||
&self.$element
|
|
||||||
})+
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
() => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
elementvec!({
|
|
||||||
ppi, PPI
|
|
||||||
});
|
|
||||||
@ -1,5 +1 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
pub mod elements;
|
|
||||||
pub mod elementvec;
|
|
||||||
pub mod renderer;
|
|
||||||
mod utils;
|
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
use glam::*;
|
|
||||||
pub struct Camera {
|
|
||||||
pub position: Vec3,
|
|
||||||
pub center: Vec3,
|
|
||||||
pub up: Vec3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Camera {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
position: Vec3::new(0.0, 0.0, 0.0),
|
|
||||||
center: Vec3::new(0.0, 0.0, 0.0),
|
|
||||||
up: Vec3::new(0.0, 0.0, 0.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Camera {
|
|
||||||
pub fn new(position: Vec3, center: Vec3, up: Vec3) -> Self {
|
|
||||||
Self {
|
|
||||||
position,
|
|
||||||
center,
|
|
||||||
up,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn calc_matrix(&self) -> Mat4 {
|
|
||||||
Mat4::look_at_rh(self.position, self.center, self.up)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
pub mod camera;
|
|
||||||
pub mod projection;
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
use glam::*;
|
|
||||||
pub struct Projection {
|
|
||||||
aspect: f32,
|
|
||||||
fovy: f32,
|
|
||||||
znear: f32,
|
|
||||||
zfar: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Projection {
|
|
||||||
pub fn new(width: u32, height: u32, fovy: f32, z_near: f32, z_far: f32) -> Self {
|
|
||||||
Self {
|
|
||||||
aspect: width as f32 / height as f32,
|
|
||||||
fovy,
|
|
||||||
znear: z_near,
|
|
||||||
zfar: z_far,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn resize(&mut self, width: u32, height: u32) {
|
|
||||||
self.aspect = width as f32 / height as f32;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn calc_matrix(&self) -> Mat4 {
|
|
||||||
Mat4::perspective_rh(self.fovy, self.aspect, self.znear, self.zfar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use regex::Regex;
|
|
||||||
pub(crate) fn merge_shader<'a>(shader: &'a str) -> String {
|
|
||||||
const TOOLS: &'static str = r#"// This is a tool that merges the shader code with the shader code from the shader module.
|
|
||||||
|
|
||||||
struct UniformCommonTools {
|
|
||||||
model_matrix: mat4,
|
|
||||||
view_matrix: mat4,
|
|
||||||
proj_matrix: mat4,
|
|
||||||
camera_position: vec3,
|
|
||||||
camera_front: vec3,
|
|
||||||
camera_up: vec3,
|
|
||||||
light_position: vec3,
|
|
||||||
light_color: vec3,
|
|
||||||
light_intensity: float,
|
|
||||||
}
|
|
||||||
|
|
||||||
@group(0) @binding(0) var<uniform> common_tools: UniformCommonTools;
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let mut visited_files = std::collections::HashSet::new();
|
|
||||||
let path: PathBuf = PathBuf::from(shader);
|
|
||||||
|
|
||||||
let base = match path.canonicalize() {
|
|
||||||
Ok(path) => path.parent().unwrap().to_owned(),
|
|
||||||
Err(e) => {
|
|
||||||
panic!("Failed to canonicalize path: {}", e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut result = process_file(&path, &mut visited_files, &base);
|
|
||||||
|
|
||||||
// 将工具代码插入到 shader 代码的开头
|
|
||||||
result.insert_str(0, TOOLS);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_file<'a, P: AsRef<std::path::Path> + 'a, B: AsRef<std::path::Path>>(
|
|
||||||
file_path: P,
|
|
||||||
visited_files: &mut std::collections::HashSet<std::path::PathBuf>,
|
|
||||||
base_path: B,
|
|
||||||
) -> String {
|
|
||||||
let base_path = base_path.as_ref();
|
|
||||||
let file_path = file_path.as_ref();
|
|
||||||
|
|
||||||
// 如果该文件已经处理过,则避免死循环
|
|
||||||
if visited_files.contains(file_path) {
|
|
||||||
return String::new(); // 返回空字符串表示已经处理过
|
|
||||||
}
|
|
||||||
|
|
||||||
visited_files.insert(file_path.to_path_buf());
|
|
||||||
|
|
||||||
let content = std::fs::read_to_string(file_path).unwrap_or_else(|_| {
|
|
||||||
panic!("Failed to read file: {}", file_path.display());
|
|
||||||
});
|
|
||||||
|
|
||||||
let re = Regex::new(r#"#include\s+\"([^\"]+\.wgsl)\";"#).unwrap();
|
|
||||||
|
|
||||||
let result = re.replace_all(&content, |caps: ®ex::Captures| {
|
|
||||||
let included_file = &caps[1]; // 获取文件名
|
|
||||||
|
|
||||||
let included_path = resolve_included_file(included_file, base_path.as_ref());
|
|
||||||
|
|
||||||
let included_content = process_file(
|
|
||||||
&included_path,
|
|
||||||
visited_files,
|
|
||||||
base_path.parent().unwrap_or(base_path),
|
|
||||||
);
|
|
||||||
|
|
||||||
included_content
|
|
||||||
});
|
|
||||||
|
|
||||||
result.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_included_file(included_file: &str, base_path: &std::path::Path) -> std::path::PathBuf {
|
|
||||||
let included_path = std::path::Path::new(included_file);
|
|
||||||
|
|
||||||
if included_path.is_relative() {
|
|
||||||
base_path.join(included_path)
|
|
||||||
} else {
|
|
||||||
included_path.to_path_buf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test {
|
|
||||||
use super::merge_shader;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
let merged = merge_shader("/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl");
|
|
||||||
println!("{}", merged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user