This commit is contained in:
Tsuki 2024-11-19 02:24:47 +08:00
parent 36e355335f
commit 1641585177
35 changed files with 1218 additions and 388 deletions

22
Cargo.lock generated
View File

@ -182,6 +182,17 @@ dependencies = [
"libloading 0.8.5", "libloading 0.8.5",
] ]
[[package]]
name = "async-trait"
version = "0.1.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.87",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.4.0"
@ -653,6 +664,13 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "element_bridge" name = "element_bridge"
version = "0.1.0" version = "0.1.0"
dependencies = [
"flume",
"makepad-widgets",
"mp_elements",
"tokio",
"wgpu",
]
[[package]] [[package]]
name = "encase" name = "encase"
@ -1693,6 +1711,9 @@ dependencies = [
name = "mp" name = "mp"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait",
"element_bridge",
"futures",
"glam", "glam",
"log", "log",
"makepad-widgets", "makepad-widgets",
@ -1735,6 +1756,7 @@ dependencies = [
"flume", "flume",
"glam", "glam",
"image", "image",
"log",
"mp_core", "mp_core",
"pollster", "pollster",
"quick_cache", "quick_cache",

24
backup.txt Normal file
View File

@ -0,0 +1,24 @@
let data = DATAPOOL
.get_or_load(
"/Users/tsuki/Desktop/Z_RADR_I_X5775_20230726180000_O_DOR-XPD-CAP-FMT.BIN.zip",
)
.unwrap();
let first_block = data.get(0).unwrap();
let first_block: &Data = &(*first_block);
if let Ok(d) = first_block.try_into() {
let attachment = {
// Ctx
let mut pipelines = GIAPP.pipelines();
let ppi = pipelines.ppi();
GIAPP.load_data(
ppi,
d,
&PPIConfig {
colormap: vec![[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]],
color_range: [0.0, 1.0],
},
)
};
}

View File

@ -4,3 +4,8 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
mp_elements = { path = "../mp_elements", version = "*" }
makepad-widgets = { git = "https://github.com/makepad/makepad", branch = "rik", version = "0.6.0" }
flume = "0.11.1"
wgpu = "23.0.0"
tokio = { version = "1.41.1", features = ["sync"] }

View File

@ -1,14 +1,70 @@
pub fn add(left: u64, right: u64) -> u64 { use makepad_widgets::{makepad_shader_compiler::builtin, Cx, Texture};
left + right use mp_elements::{
app::{Ctx, DrawList, RenderWindow},
App,
};
use std::sync::{Arc, Mutex};
pub use mp_elements::app::Window;
#[derive(Clone)]
pub struct TextureBridge {
dirty: bool,
_buffer: Arc<tokio::sync::Mutex<Vec<u8>>>,
window: Arc<RenderWindow>,
_texture: Texture,
} }
#[cfg(test)] impl TextureBridge {
mod tests { pub fn new(texture: Texture, app: &App, window: Window) -> Self {
use super::*; let window = app.create_window(window);
Self {
dirty: true,
_buffer: Arc::new(tokio::sync::Mutex::new(vec![0u8; 256 * 256 * 4])),
window: Arc::new(window),
_texture: texture,
}
}
#[test] pub fn texture(&self) -> &Texture {
fn it_works() { &self._texture
let result = add(2, 2); }
assert_eq!(result, 4);
pub fn window(&self) -> &RenderWindow {
&self.window
}
pub fn render_window(&self) -> Arc<RenderWindow> {
self.window.clone()
}
pub async fn draw(&mut self, app: &App, draw_list: DrawList) {
app.draw(&self.window, draw_list).await;
}
pub async fn load_data(buffer: Arc<Mutex<Vec<u8>>>, ctx: &Ctx, render_window: &RenderWindow) {
let output = &render_window.output().output_buffer;
let (sender, receiver) = flume::bounded(1);
let slice = output.slice(..);
slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap());
let device = &ctx.device;
device.poll(wgpu::Maintain::wait()).panic_on_timeout();
receiver.recv_async().await.unwrap().unwrap();
{
let view = slice.get_mapped_range();
let mut buffer = buffer.lock().unwrap();
buffer.copy_from_slice(&view[..]);
}
output.unmap();
}
pub fn update_texture(&self, cx: &mut Cx, buffer: Vec<u8>) {
self._texture.put_back_vec_u8(cx, buffer, None);
}
pub fn buffer(&self) -> Arc<tokio::sync::Mutex<Vec<u8>>> {
self._buffer.clone()
} }
} }

View File

@ -15,3 +15,7 @@ tracing = "0.1.40"
tracing-subscriber = "0.3.18" tracing-subscriber = "0.3.18"
mp_elements = { path = "../mp_elements", version = "*" } mp_elements = { path = "../mp_elements", version = "*" }
tokio = { version = "1.41.1", features = ["full"] } tokio = { version = "1.41.1", features = ["full"] }
element_bridge = { path = "../element_bridge", version = "*" }
futures = "0.3.31"
async-trait = "0.1.83"

View File

@ -1,8 +1,17 @@
use crate::widgets::area::TAreaWidgetRefExt;
use crate::windows_manager::WindowsManager;
use crate::{render_task::RenderTasks, PLUGIN_MANAGER, RUNTIME};
use crate::{DATAPOOL, GIAPP};
use ::log::info;
use makepad_widgets::makepad_micro_serde::*; use makepad_widgets::makepad_micro_serde::*;
use makepad_widgets::*; use makepad_widgets::*;
use mp_elements::elements::Element; use mp_core::Data;
use mp_elements::elements::ppi::PPIConfig;
use mp_elements::elements::PPI;
use std::sync::Arc;
use window_menu::WindowMenuWidgetRefExt;
use crate::{DATAPOOL, GIAPP, PLUGIN_MANAGER}; use tokio::sync::Mutex;
live_design! { live_design! {
import makepad_widgets::base::*; import makepad_widgets::base::*;
@ -48,6 +57,29 @@ live_design! {
<MainView>{} <MainView>{}
} }
window_menu = {
main = Main {items: [app, file, window, help]}
app = Sub {name: "MP", items: [about, line, settings, line, quit]}
about = Item {name: "About Makepad Studio", enabled: false}
settings = Item {name: "Settings", enabled: false}
quit = Item {name: "Quit Makepad Studio", key: KeyQ}
file = Sub {name: "File", items: [open_file, open_window]}
open_file = Item {name: "Open File", enabled: true, shift: true, key: KeyO}
open_window = Item {name: "Open Folder", enabled: false, shift: true, key: KeyN}
window = Sub {name: "Window", items: [minimize, zoom, line, all_to_front]}
minimize = Item {name: "Minimize", enabled: false}
zoom = Item {name: "Zoom", enabled: false}
all_to_front = Item {name: "Bring All to Front", enabled: false}
help = Sub {name: "Help", items: [about]}
line = Line,
}
} }
} }
} }
@ -58,6 +90,10 @@ live_design! {
pub struct App { pub struct App {
#[live] #[live]
ui: WidgetRef, ui: WidgetRef,
#[rust]
render_tasks: Arc<Mutex<RenderTasks>>,
#[rust]
windows_manager: WindowsManager,
} }
impl LiveRegister for App { impl LiveRegister for App {
@ -65,6 +101,7 @@ impl LiveRegister for App {
crate::makepad_widgets::live_design(_cx); crate::makepad_widgets::live_design(_cx);
crate::app_ui::live_design(_cx); crate::app_ui::live_design(_cx);
crate::widgets::area::live_design(_cx); crate::widgets::area::live_design(_cx);
crate::widgets::renderer::live_design(_cx);
} }
} }
@ -74,31 +111,61 @@ struct AppStateRon {
} }
impl MatchEvent for App { impl MatchEvent for App {
fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) { // Start UP
use native_dialog::FileDialog; fn handle_startup(&mut self, _cx: &mut Cx) {}
let ui = self.ui.clone();
if ui.button(id!(open_modal)).clicked(&actions) {
let supported_extensions = PLUGIN_MANAGER.supported_extensions();
// let file = FileDialog::new() fn handle_actions(&mut self, cx: &mut Cx, actions: &Actions) {}
// .add_filter("Supported files", &supported_extensions)
// .show_open_single_file()
// .unwrap();
// if let Some(file) = file {
// if let Ok(d) = DATAPOOL.get_or_load(file) {}
// }
ui.modal(id!(modal)).open(cx);
// ui.popup_notification(id!(test_noti)).open(cx);
}
}
} }
impl AppMain for App { impl AppMain for App {
fn handle_event(&mut self, cx: &mut Cx, event: &Event) { fn handle_event(&mut self, cx: &mut Cx, event: &Event) {
self.match_event(cx, event); self.match_event(cx, event);
self.ui.handle_event(cx, event, &mut Scope::empty()); self.ui.handle_event(cx, event, &mut Scope::empty());
spawn_background(self, event);
handle_menu(event);
}
}
fn spawn_background(app: &mut App, event: &Event) {
match event {
Event::Draw(_) => {
// Render Task
info!("Starting background task......");
let tasks = app.render_tasks.clone();
RUNTIME.spawn(async move {
let tasks = tasks.lock().await;
tasks.render().await;
});
let tasks = app.render_tasks.clone();
let all_buffers = app.windows_manager.buffer();
RUNTIME.spawn(async move {
let mut tasks = tasks.lock().await;
tasks.listen(all_buffers).await;
});
}
_ => {}
}
}
fn handle_menu(event: &Event) {
match event {
Event::MacosMenuCommand(command) => {
if command == &LiveId::from_str("open_file") {
use native_dialog::FileDialog;
info!("Open File Dialog");
let supported_extensions = PLUGIN_MANAGER.supported_extensions();
let file = FileDialog::new()
.add_filter("Supported files", &supported_extensions)
.show_open_single_file()
.unwrap();
if let Some(file) = file {
info!("File: {:?}", file);
}
}
}
_ => {}
} }
} }

View File

@ -3,6 +3,7 @@ live_design! {
import makepad_widgets::base::*; import makepad_widgets::base::*;
import makepad_widgets::theme_desktop_dark::*; import makepad_widgets::theme_desktop_dark::*;
import crate::widgets::area::Area; import crate::widgets::area::Area;
import crate::widgets::renderer::IRenderer;
import makepad_draw::shader::std::*; import makepad_draw::shader::std::*;
@ -59,28 +60,28 @@ live_design! {
y: 0.5 y: 0.5
}, },
quad = <Area> { quad = <Area> {
draw: { // draw: {
// this example shader is ported from kishimisu's tutorial // // this example shader is ported from kishimisu's tutorial
fn pixel(self) -> vec4 { // fn pixel(self) -> vec4 {
// let uv = self.pos - 0.5; // // let uv = self.pos - 0.5;
// let uv0 = uv; // // let uv0 = uv;
// let finalColor = vec3(0.0); // // let finalColor = vec3(0.0);
// let i = 0; // // let i = 0;
// for _i in 0..4 { // you cannot refer to _i inside the for loop; use i instead // // for _i in 0..4 { // you cannot refer to _i inside the for loop; use i instead
// uv = fract(uv * -1.5) - 0.5; // // uv = fract(uv * -1.5) - 0.5;
// let d = length(uv) * exp(-length(uv0)); // // let d = length(uv) * exp(-length(uv0));
// let col = Pal::iq2(length(uv0) + float(i) * .4 + self.time * .4); // // let col = Pal::iq2(length(uv0) + float(i) * .4 + self.time * .4);
// d = sin(d*8. + self.time) / 8.; // // d = sin(d*8. + self.time) / 8.;
// d = abs(d); // // d = abs(d);
// d = pow(0.01 / d, 1.2); // // d = pow(0.01 / d, 1.2);
// finalColor += col * d; // // finalColor += col * d;
// i = i+1; // // i = i+1;
// } // // }
// return vec4(finalColor ,1); // // return vec4(finalColor ,1);
} // }
} // }
} }

44
mp/src/handle_events.rs Normal file
View File

@ -0,0 +1,44 @@
use log::*;
use std::sync::{Arc, Mutex};
use crate::{app::App, render_task::RenderTasks, windows_manager::WindowsManager, GIAPP, RUNTIME};
pub async fn register_task(tasks: Arc<Mutex<RenderTasks>>, windows_manager: &mut WindowsManager) {
let render_window = {
let bridge = windows_manager.get_bridge(0).unwrap();
let b = bridge.lock().unwrap();
b.render_window().clone()
};
if let Ok(data) = DATAPOOL.get_or_load_async(file).await {
// First Block
let first_block = data.get(0).unwrap();
let first_block: &Data = &*first_block;
let pipelines = GIAPP.pipelines();
let ppi = pipelines.ppi();
let first_block = first_block.try_into().unwrap();
let attachment = {
let ppi: &PPI = &*ppi;
let attachment = GIAPP.load_data(
ppi,
first_block,
&PPIConfig {
colormap: vec![[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]],
color_range: [0.0, 1.0],
},
);
attachment
};
let mut tasks = tasks.lock().await;
let mut draw_list = mp_elements::app::DrawList::new();
let attachment = Arc::new(attachment);
draw_list.push(ppi.clone(), attachment);
tasks.register_task(0, render_window, draw_list);
info!("task registered, all {}", tasks.tasks.len());
info!("Data loaded");
}
}

View File

@ -1,12 +1,12 @@
use mp_elements; use mp_elements;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
pub mod app; pub mod app;
pub mod windows_manager;
pub use makepad_widgets; pub use makepad_widgets;
pub use makepad_widgets::makepad_draw; pub use makepad_widgets::makepad_draw;
pub use makepad_widgets::makepad_platform; pub use makepad_widgets::makepad_platform;
pub mod app_ui; pub mod app_ui;
pub mod render; pub mod render_task;
pub mod shaders;
pub mod widgets; pub mod widgets;
use mp_core::{config::Setting, datapool::DataPool, plugin_system::PluginManager}; use mp_core::{config::Setting, datapool::DataPool, plugin_system::PluginManager};

View File

@ -1 +0,0 @@
pub struct Camera {}

View File

@ -1,46 +0,0 @@
use makepad_widgets::{Cx, Texture, TextureFormat};
use mp_core::data::RadarGridData;
pub enum Data {
GridData(GridData),
}
pub struct GridData {
texture: Texture,
clear_buffer: bool,
shape: Option<Vec<u32>>,
}
impl GridData {
pub fn new(cx: &mut Cx) -> Self {
let mut texture = Texture::new_with_format(cx, TextureFormat::Unknown);
texture.texture_id();
GridData {
texture,
clear_buffer: true,
shape: None,
}
}
pub fn update(&mut self, cx: &mut Cx, data: &RadarGridData) {
let data = data.data.cast_to::<f32>();
self.clear_buffer = false;
// self.shape = Some(data.dim().into());
// self.texture.put_back_vec_f32(cx, data.into(), None);
}
pub fn clear(&mut self) {
self.clear_buffer = true;
}
pub fn texture(&self) -> &Texture {
&self.texture
}
}
impl From<GridData> for Data {
fn from(data: GridData) -> Self {
Data::GridData(data)
}
}

View File

@ -1,2 +0,0 @@
pub mod camera;
pub mod data;

123
mp/src/render_task.rs Normal file
View File

@ -0,0 +1,123 @@
use crate::{
widgets::renderer,
windows_manager::{AllBuffers, WindowsManager},
GIAPP, RUNTIME,
};
use element_bridge::TextureBridge;
use futures::future::BoxFuture;
use log::info;
use makepad_widgets::{Cx, Texture};
use mp_elements::{
app::{DrawList, RenderWindow},
App,
};
use std::sync::{Arc, Mutex};
#[derive(Default)]
pub struct RenderTasks {
pub(crate) tasks: Vec<(tokio::sync::mpsc::Receiver<Vec<u8>>, RenderTask)>,
}
impl RenderTasks {
pub fn new() -> Self {
Self { tasks: Vec::new() }
}
fn push_task(&mut self, task: (tokio::sync::mpsc::Receiver<Vec<u8>>, RenderTask)) {
self.tasks.push(task);
}
pub fn register_task(
&mut self,
bridge_id: usize,
bridge: Arc<RenderWindow>,
draw_list: DrawList,
) {
let (task, receiver) = RenderTask::new(bridge_id, bridge, draw_list);
self.push_task((receiver, task));
}
pub fn clear(&mut self) {
self.tasks.clear();
}
pub async fn render(&self) {
// Draw all tasks
let futures: Vec<_> = self
.tasks
.iter()
.map(|(_, task)| async {
info!("Drawing task");
task.draw().await;
})
.collect();
info!("all tasks: {:?}", futures.len());
futures::future::join_all(futures).await;
}
pub async fn listen(&mut self, manager: AllBuffers) {
let mut futures = Vec::new();
for (receiver, _) in self.tasks.iter_mut() {
let manager = manager.lock().unwrap();
let buffer = manager.get(&0).unwrap().clone();
let future = async move {
while let Some(data) = receiver.recv().await {
let mut buffer = buffer.lock().await;
info!("Received data");
buffer.copy_from_slice(&data);
}
};
futures.push(Box::pin(future));
}
futures::future::join_all(futures).await;
}
}
pub struct RenderTask {
// bridge: element_bridge::TextureBridge,
bridge_id: usize,
sender: tokio::sync::mpsc::Sender<Vec<u8>>,
buffer: Arc<Mutex<Vec<u8>>>,
render_window: Arc<RenderWindow>,
draw_list: DrawList,
}
impl RenderTask {
pub fn new(
bridge_id: usize,
bridge_render_window: Arc<RenderWindow>,
draw_list: DrawList,
) -> (Self, tokio::sync::mpsc::Receiver<Vec<u8>>) {
let (sender, receiver) = tokio::sync::mpsc::channel(1);
(
Self {
bridge_id,
sender,
buffer: Arc::new(Mutex::new(vec![0u8; 256 * 256 * 4])),
render_window: bridge_render_window,
draw_list,
},
receiver,
)
}
pub async fn draw(&self) {
GIAPP
.draw(&self.render_window, self.draw_list.clone())
.await;
let ctx = GIAPP.ctx();
TextureBridge::load_data(self.buffer.clone(), ctx, &self.render_window).await;
let bf = {
let buffer = self.buffer.clone();
let buffer = buffer.lock().unwrap();
buffer.clone()
};
self.sender.send(bf).await.unwrap();
}
}

View File

@ -1,63 +0,0 @@
use crate::render::data::GridData;
use makepad_widgets::*;
live_design! {
ColorMap = {{ColorMap}} {
// Cameras
uniform view: mat4
uniform projection: mat4
uniform model: mat4
uniform conf: vec4
varing value: float
varing range: vec4
// Data
texture data: texture3d
// ColorMAPPER
textrue color_map: texture1d
fn get_value_at(self, pos: vec3) -> float {
return sampler3d_rt(self.data, pos).r;
}
fn vertex(self) -> vec4 {
let v = sampler2d_rt(self.data, )
}
fn pixel(self) -> vec4 {
return vec4(1., 0., 0., 1.);
}
}
}
#[repr(C)]
#[derive(Live, LiveRegister)]
pub struct ColorMap {
#[deref]
draw_vars: DrawVars,
#[live]
geometry: GeometryQuad2D,
#[calc]
pub position: Vec3,
#[calc]
pub value: f32,
}
impl LiveHook for ColorMap {
fn before_apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) {
self.draw_vars
.before_apply_init_shader(cx, apply, index, nodes, &self.geometry);
}
fn after_apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) {
self.draw_vars
.after_apply_update_self(cx, apply, index, nodes, &self.geometry);
}
}
impl ColorMap {}

View File

@ -1,69 +0,0 @@
use crate::render::camera::Camera;
use crate::render::data::GridData;
use makepad_widgets::*;
live_design! {
PPI = {{PPI}} {
// Cameras
uniform view: mat4
uniform projection: mat4
uniform model: mat4
uniform conf: vec4
varing value: float
varing range: vec4
// Data
texture data: texture2d
// ColorMAPPER
textrue color_map: texture2d
fn get_value_at(self, pos: vec3) -> float {
return sampler3d(self.data, pos).r;
}
fn vertex(self) -> vec4 {
let v = sampler2d_rt(self.data, )
}
fn pixel(self) -> vec4 {
return vec4(1., 0., 0., 1.);
}
}
}
#[repr(C)]
#[derive(Live, LiveRegister)]
pub struct PPI {
#[deref]
pub draw_vars: DrawVars,
#[live]
geometry: GeometryQuad2D,
#[calc]
pub position: Vec3,
#[calc]
pub value: f32,
}
impl LiveHook for PPI {
fn before_apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) {
self.draw_vars
.before_apply_init_shader(cx, apply, index, nodes, &self.geometry);
}
fn after_apply(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) {
self.draw_vars
.after_apply_update_self(cx, apply, index, nodes, &self.geometry);
}
}
impl PPI {
pub fn update_draw_call_vars(&mut self, camera: &Camera, data: &GridData) {
self.draw_vars.texture_slots[0] = Some(data.texture().clone());
}
}

View File

@ -1,6 +1,16 @@
use std::cell::RefCell;
use std::sync::Arc;
use std::sync::Mutex;
use crate::windows_manager::WindowId;
use crate::windows_manager::WindowsManager;
use crate::GIAPP;
use element_bridge::{TextureBridge, Window};
use makepad_widgets::makepad_derive_widget::*; use makepad_widgets::makepad_derive_widget::*;
use makepad_widgets::makepad_draw::*; use makepad_widgets::makepad_draw::*;
use makepad_widgets::widget::*; use makepad_widgets::widget::*;
use mp_elements::renderer::camera::Camera;
use mp_elements::renderer::projection::Projection;
live_design! { live_design! {
Area = {{TArea}} {} Area = {{TArea}} {}
@ -17,32 +27,81 @@ pub struct TArea {
layout: Layout, layout: Layout,
#[live] #[live]
time: f32, time: f32,
// #[rust]
// next_frame: NextFrame, #[rust]
bridge: Option<Arc<Mutex<TextureBridge>>>,
} }
impl LiveHook for TArea { #[derive(Debug, Clone)]
fn after_new_from_doc(&mut self, cx: &mut Cx) { pub enum Status<T> {
// starts the animation cycle on startup Share(std::rc::Rc<RefCell<T>>),
// self.next_frame = cx.new_next_frame(); Own(T),
}
#[derive(Clone)]
pub struct TAreaState {
pub time: f32,
pub camera: Status<Camera>,
pub bridge: Option<TextureBridge>,
pub projection: Projection,
}
impl Default for TAreaState {
fn default() -> Self {
Self {
time: 0.0,
camera: Status::Own(Camera::default()),
bridge: None,
projection: Projection::default(),
}
} }
} }
impl TAreaState {
pub fn set_camera<F: FnOnce(&mut Camera)>(&mut self, f: F) {
match self.camera {
Status::Share(ref camera) => {
f(&mut camera.borrow_mut());
}
Status::Own(ref mut camera) => {
f(camera);
}
}
}
pub fn resize(&mut self, width: f32, height: f32) {
self.projection.resize(width as u32, height as u32);
}
pub fn set_bridge(&mut self, bridge: TextureBridge) {
self.bridge = Some(bridge);
}
pub fn new_bridge(&mut self, cx: &mut Cx, window: Window) {
let texture = Texture::new_with_format(
cx,
TextureFormat::VecRGBAf32 {
width: window.width as usize,
height: window.height as usize,
data: None,
updated: TextureUpdated::Full,
},
);
let bridge = TextureBridge::new(texture, &GIAPP, window);
self.bridge = Some(bridge);
}
}
impl LiveHook for TArea {}
#[derive(Clone, DefaultNone)] #[derive(Clone, DefaultNone)]
pub enum MyWidgetAction { pub enum MyWidgetAction {
None, None,
} }
impl Widget for TArea { impl Widget for TArea {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) { fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {}
// if let Some(ne) = self.next_frame.is_event(event) {
// // update time to use for animation
// self.time = (ne.time * 0.001).fract() as f32;
// // force updates, so that we can animate in the absence of user-generated events
// self.redraw(cx);
// self.next_frame = cx.new_next_frame();
// }
}
fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep { fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
self.draw.begin(cx, walk, self.layout); self.draw.begin(cx, walk, self.layout);
@ -50,3 +109,49 @@ impl Widget for TArea {
DrawStep::done() DrawStep::done()
} }
} }
impl TArea {
fn set_bridge(&mut self, bridge: Arc<Mutex<TextureBridge>>) {
self.bridge = Some(bridge);
self.draw
.draw_vars
.set_texture(0, self.bridge.as_ref().unwrap().lock().unwrap().texture());
}
fn init_bridge(&mut self, cx: &mut Cx, manager: &mut WindowsManager) {
let window_id = WindowId::new("Primary");
// let height = self.walk.height.
// let width = self.walk.width.fixed_or_zero();
let height = 256;
let width = 256;
let window = Window {
height: height as u32,
width: width as u32,
};
let texture = Texture::new_with_format(
cx,
TextureFormat::VecRGBAf32 {
width: window.width as usize,
height: window.height as usize,
data: None,
updated: TextureUpdated::Full,
},
);
let bridge = TextureBridge::new(texture, &GIAPP, window);
let (_, bridge) = manager.add_window(window_id, bridge);
self.set_bridge(bridge);
}
}
impl TAreaRef {
pub fn init_bridge(&self, cx: &mut Cx, manager: &mut WindowsManager) {
if let Some(mut bridge) = self.borrow_mut() {
bridge.init_bridge(cx, manager);
}
}
}

View File

@ -1 +1,2 @@
pub mod area; pub mod area;
pub mod renderer;

110
mp/src/widgets/renderer.rs Normal file
View File

@ -0,0 +1,110 @@
use std::cell::RefCell;
use crate::GIAPP;
use element_bridge::{TextureBridge, Window};
use makepad_widgets::makepad_derive_widget::*;
use makepad_widgets::makepad_draw::*;
use makepad_widgets::widget::*;
use mp_elements::renderer::camera::Camera;
use mp_elements::renderer::projection::Projection;
live_design! {
IRenderer = {{Renderer}} {
import crate::widgets::area::Area;
<Area> {
draw: {
fn pixel(self) -> vec4 {
return mix(#7,#4,self.pos.y);
}
}
}
}
}
#[derive(Live, Widget)]
pub struct Renderer {
#[redraw]
#[live]
draw: DrawQuad,
#[walk]
walk: Walk,
#[layout]
layout: Layout,
#[rust]
state: RenderState,
}
#[derive(Debug, Clone)]
pub enum Status<T> {
Share(std::rc::Rc<RefCell<T>>),
Own(T),
}
#[derive(Clone)]
pub struct RenderState {
pub time: f32,
pub camera: Status<Camera>,
pub bridge: Option<TextureBridge>,
pub projection: Projection,
}
impl Default for RenderState {
fn default() -> Self {
Self {
time: 0.0,
camera: Status::Own(Camera::default()),
bridge: None,
projection: Projection::default(),
}
}
}
impl RenderState {
pub fn set_camera<F: FnOnce(&mut Camera)>(&mut self, f: F) {
match self.camera {
Status::Share(ref camera) => {
f(&mut camera.borrow_mut());
}
Status::Own(ref mut camera) => {
f(camera);
}
}
}
pub fn resize(&mut self, width: f32, height: f32) {
self.projection.resize(width as u32, height as u32);
}
pub fn set_bridge(&mut self, bridge: TextureBridge) {
self.bridge = Some(bridge);
}
pub fn new_bridge(&mut self, cx: &mut Cx, window: Window) {
let texture = Texture::new_with_format(
cx,
TextureFormat::VecRGBAf32 {
width: window.width as usize,
height: window.height as usize,
data: None,
updated: TextureUpdated::Full,
},
);
let bridge = TextureBridge::new(texture, &GIAPP, window);
self.bridge = Some(bridge);
}
}
impl LiveHook for Renderer {}
impl Widget for Renderer {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, _scope: &mut Scope) {}
fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawStep {
self.draw.begin(cx, walk, self.layout);
self.draw.end(cx);
DrawStep::done()
}
}

73
mp/src/windows_manager.rs Normal file
View File

@ -0,0 +1,73 @@
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use element_bridge::TextureBridge;
pub type AllBuffers = Arc<Mutex<HashMap<usize, Arc<tokio::sync::Mutex<Vec<u8>>>>>>;
#[derive(Eq, Hash, PartialEq)]
pub struct WindowId {
id: u64,
name: String,
}
#[derive(Default)]
pub struct WindowsManager {
inner: HashMap<WindowId, Arc<Mutex<TextureBridge>>>,
all_bridges: Vec<(usize, Arc<Mutex<TextureBridge>>)>,
all_revelant_buffers: Arc<Mutex<HashMap<usize, Arc<tokio::sync::Mutex<Vec<u8>>>>>>,
}
impl WindowsManager {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
all_bridges: Vec::new(),
all_revelant_buffers: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn add_window(
&mut self,
id: WindowId,
bridge: TextureBridge,
) -> (usize, Arc<Mutex<TextureBridge>>) {
let bridge = Arc::new(Mutex::new(bridge));
self.inner.insert(id, bridge.clone());
let new_id = self.all_bridges.len();
self.all_bridges.push((new_id, bridge.clone()));
let buffer = {
let bridge = bridge.lock().unwrap();
bridge.buffer()
};
// self.all_revelant_buffers.push((new_id, buffer));
self.all_revelant_buffers
.lock()
.unwrap()
.insert(new_id, buffer);
(new_id, bridge)
}
pub fn get_bridge(&self, id: usize) -> Option<Arc<Mutex<TextureBridge>>> {
self.all_bridges.get(id).map(|(_, bridge)| bridge.clone())
}
pub fn buffer(&self) -> AllBuffers {
self.all_revelant_buffers.clone()
}
}
impl WindowId {
pub fn new<S: Into<String>>(name: S) -> Self {
Self {
id: 0,
name: name.into(),
}
}
}

View File

@ -6,15 +6,17 @@ edition = "2021"
[dependencies] [dependencies]
bytemuck = { version = "1.19.0", features = ["derive"] } bytemuck = { version = "1.19.0", features = ["derive"] }
glam = { version = "0.29.2", features = ["bytemuck"] } 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 = "*" } mp_core = { path = "../mp_core", version = "*" }
flume = "0.11.1"
pollster = "0.4.0"
quick_cache = "0.6.9" quick_cache = "0.6.9"
encase = { version = "0.10.0", features = ["glam"] } encase = { version = "0.10.0", features = ["glam"] }
image = "0.25.5" image = "0.25.5"
rust-embed = "8.5.0" rust-embed = "8.5.0"
flume = "0.11.1"
log = "0.4.22"
[build-dependencies] [build-dependencies]
regex = "1.11.1" regex = "1.11.1"
[dev-dependencies]
pollster = "0.4.0"

View File

@ -22,6 +22,11 @@ fn main() {
println!("cargo:rerun-if-changed={}", path.display()); println!("cargo:rerun-if-changed={}", path.display());
} }
let path_name = path.file_stem().unwrap().to_str().unwrap();
if path_name.contains("merged") {
continue;
}
let merged_shader = merge_shader(&path.display().to_string(), &shader_path_base); let merged_shader = merge_shader(&path.display().to_string(), &shader_path_base);
let out_path = Path::new(&crate_path) let out_path = Path::new(&crate_path)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -1,20 +1,20 @@
@group(1) @binding(0) var color_map_texture: texture_2d<f32>; @group(1) @binding(0) var color_map_texture: texture_1d<f32>;
@group(1) @binding(1) var color_map_sampler: sampler; @group(1) @binding(1) var color_map_sampler: sampler;
@group(1) @binding(2) var<uniform> color_map_params: ColorMapParams; @group(1) @binding(2) var<uniform> color_map_params: ColorMapParams;
struct ColorMapParams { struct ColorMapParams {
color_count: u32, color_count: u32,
value_min: f32, value_min: f32,
value_max: f32 value_max: f32,
invalid_value: f32 invalid_value: f32
} }
fn find_idx(ratio: f32) -> f32 { fn find_idx(ratio: f32) -> f32 {
var sum = 0.0; var sum = 0.0;
var i = 0.0; var i = 0.0;
var count = (color_map_params.color_count - 1) as f32; let count = f32(color_map_params.color_count - 1);
while (ratio > sum) { while (ratio > sum) {
sum += textureSample(color_map_texture, color_map_sampler, vec2<f32>(i / count, 0.0)).r; sum += textureSample(color_map_texture, color_map_sampler, i / count).r;
i += 1.0; i += 1.0;
} }
return i / count; return i / count;
@ -22,8 +22,8 @@ fn find_idx(ratio: f32) -> f32 {
fn linear_colormap(value: f32) -> vec4f { 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); let 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 idx = find_idx(v);
let c0: vec3f = textureSample(color_map_texture, color_map_sampler, vec2<f32>(idx, 0.0)).rgb; let c0 = textureSample(color_map_texture, color_map_sampler, idx).rgb;
return vec4f(c0, 1.0); return vec4f(c0, 1.0);
} }

View File

@ -1,4 +1,5 @@
#include "constants.wgsl"; #include "constants.wgsl";
#include "colormap.wgsl";
// Common Uniforms // Common Uniforms
// common_tools // common_tools
// model_matrix: mat4, // model_matrix: mat4,
@ -12,9 +13,9 @@
// light_intensity: float, // light_intensity: float,
// Uniforms // Uniforms
@group(1) @binding(0) var<uniform> params: UniformParams; @group(2) @binding(0) var<uniform> params: UniformParams;
// Data Buffer // Data Buffer
@group(1) @binding(1) var<storage> data: array<f32>; @group(2) @binding(1) var<storage> data: array<f32>;
struct UniformParams { struct UniformParams {
origin: vec4f origin: vec4f
@ -36,8 +37,7 @@ fn vertex(
var out: VertexOutput; var out: VertexOutput;
// Transform position // Transform position
out.position = common_tools.proj_matrix * common_tools.view_matrix * common_tools.model_matrix * vec4f(position, 1.0); out.position = vec4(position.xyz, 1.0);
// out.position = vec4(position.xyz, 1.0);
out.r_range = r_range; out.r_range = r_range;
let idx = u32(position.w); let idx = u32(position.w);
out.idx = idx; out.idx = idx;
@ -57,8 +57,8 @@ fn fragment(input: VertexOutput) -> @location(0) vec4f {
// Sample data texture // Sample data texture
let value = data[input.idx]; let value = data[input.idx];
let ear = polar_forward(input.position.xyz); let ear = polar_forward(input.position.xyz);
// var color = linear_colormap(value);
// let color = linear_colormap(value);
var color = clamp(value / 75.0, 0.0, 1.0); var color = clamp(value / 75.0, 0.0, 1.0);
// let r = ear.x; // let r = ear.x;

View File

@ -26,6 +26,35 @@ const HALF_PI:f32 = 1.57079632679489661923132169163975144;
const LOG2:f32 = 0.693147180559945309417232121458176568; const LOG2:f32 = 0.693147180559945309417232121458176568;
const LOG10:f32 = 2.30258509299404568401799145468436421; const LOG10:f32 = 2.30258509299404568401799145468436421;
@group(1) @binding(0) var color_map_texture: texture_1d<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;
let count = f32(color_map_params.color_count - 1);
while (ratio > sum) {
sum += textureSample(color_map_texture, color_map_sampler, i / count).r;
i += 1.0;
}
return i / count;
}
fn linear_colormap(value: f32) -> vec4f {
let v = clamp((value - color_map_params.value_min) / (color_map_params.value_max - color_map_params.value_min), 0.0, 1.0);
let idx = find_idx(v);
let c0 = textureSample(color_map_texture, color_map_sampler, idx).rgb;
return vec4f(c0, 1.0);
}
// Common Uniforms // Common Uniforms
// common_tools // common_tools
// model_matrix: mat4, // model_matrix: mat4,
@ -39,9 +68,9 @@ const LOG10:f32 = 2.30258509299404568401799145468436421;
// light_intensity: float, // light_intensity: float,
// Uniforms // Uniforms
@group(1) @binding(0) var<uniform> params: UniformParams; @group(2) @binding(0) var<uniform> params: UniformParams;
// Data Buffer // Data Buffer
@group(1) @binding(1) var<storage> data: array<f32>; @group(2) @binding(1) var<storage> data: array<f32>;
struct UniformParams { struct UniformParams {
origin: vec4f origin: vec4f
@ -63,8 +92,7 @@ fn vertex(
var out: VertexOutput; var out: VertexOutput;
// Transform position // Transform position
out.position = common_tools.proj_matrix * common_tools.view_matrix * common_tools.model_matrix * vec4f(position, 1.0); out.position = vec4(position.xyz, 1.0);
// out.position = vec4(position.xyz, 1.0);
out.r_range = r_range; out.r_range = r_range;
let idx = u32(position.w); let idx = u32(position.w);
out.idx = idx; out.idx = idx;
@ -84,8 +112,8 @@ fn fragment(input: VertexOutput) -> @location(0) vec4f {
// Sample data texture // Sample data texture
let value = data[input.idx]; let value = data[input.idx];
let ear = polar_forward(input.position.xyz); let ear = polar_forward(input.position.xyz);
// var color = linear_colormap(value);
// let color = linear_colormap(value);
var color = clamp(value / 75.0, 0.0, 1.0); var color = clamp(value / 75.0, 0.0, 1.0);
// let r = ear.x; // let r = ear.x;

View File

@ -1,12 +1,12 @@
use std::cell::RefCell;
use std::sync::{Arc, Mutex, MutexGuard};
use crate::elements::{Element, ElementAttach, Elements, ElementsRef};
use crate::elementvec::ElementVec;
use encase;
use quick_cache::sync::Cache; use quick_cache::sync::Cache;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
use crate::elements::{Element, ElementAttach, ElementsRef};
use crate::elementvec::ElementVec;
use wgpu::{Backends, Instance}; use wgpu::{Backends, Instance};
use encase;
type DB = std::sync::Arc<wgpu::Buffer>; type DB = std::sync::Arc<wgpu::Buffer>;
const BACKENDS_DEFAULT: u32 = Backends::DX12.bits() const BACKENDS_DEFAULT: u32 = Backends::DX12.bits()
@ -15,13 +15,8 @@ const BACKENDS_DEFAULT: u32 = Backends::DX12.bits()
| Backends::BROWSER_WEBGPU.bits(); | Backends::BROWSER_WEBGPU.bits();
pub struct App { pub struct App {
_texture: wgpu::Texture, pub(crate) pipelines: Option<ElementVec>,
_texture_size: wgpu::Extent3d, ctx: Ctx,
texture_view: wgpu::TextureView,
output: Output,
pub pipelines: Option<ElementVec>,
pub ctx: Ctx,
buffer_pool: DataBufferPool, buffer_pool: DataBufferPool,
} }
@ -59,44 +54,22 @@ impl App {
// Create a new instance of the common utils struct. This struct contains the bind group layout, bind group, and uniform buffer. // Create a new instance of the common utils struct. This struct contains the bind group layout, bind group, and uniform buffer.
let common_utils = CommonUtils::new(&device); let common_utils = CommonUtils::new(&device);
// Create a new texture. This texture will be used as the output texture for the render pass.
let texture_size = wgpu::Extent3d {
width: 256,
height: 256,
depth_or_array_layers: 1,
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("output texture"),
size: texture_size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
});
// Create a texture view from the texture. This texture view will be used as the output texture for the render pass.
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
// Buffer pool // Buffer pool
let buffer_pool = DataBufferPool::new(); let buffer_pool = DataBufferPool::new();
let ctx = Ctx::new(device, queue, common_utils); let ctx = Ctx::new(device, queue, common_utils);
let output = Output::new(&ctx.device);
Self { Self {
pipelines: None, pipelines: None,
_texture: texture,
_texture_size: texture_size,
texture_view,
buffer_pool, buffer_pool,
output,
ctx, ctx,
} }
} }
pub fn buffer_pool(&mut self) -> &mut DataBufferPool {
&mut self.buffer_pool
}
// Create a new context struct. This struct contains references to the device, queue, bind group layout, and bind group. // Create a new context struct. This struct contains references to the device, queue, bind group layout, and bind group.
pub fn ctx(&self) -> &Ctx { pub fn ctx(&self) -> &Ctx {
&self.ctx &self.ctx
@ -117,7 +90,7 @@ impl App {
} }
// Draw the elements in the draw list. // Draw the elements in the draw list.
pub async fn draw(&self, draw_list: DrawList<'_, '_>) { pub async fn draw(&self, window: &RenderWindow, draw_list: DrawList) {
let mut encoder = self let mut encoder = self
.ctx .ctx
.device .device
@ -129,7 +102,7 @@ impl App {
let render_pass_desc = wgpu::RenderPassDescriptor { let render_pass_desc = wgpu::RenderPassDescriptor {
label: Some("Some Render Pass"), label: Some("Some Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment { color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &self.texture_view, view: &window.texture_view,
resolve_target: None, resolve_target: None,
ops: wgpu::Operations { ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
@ -161,24 +134,105 @@ impl App {
attach.bind(&mut render_pass); attach.bind(&mut render_pass);
// Draw the element. // Draw the element.
element.draw(attach, &mut render_pass); element.draw(&attach, &mut render_pass);
} }
} }
// output // Output
self.output window.finish(&mut encoder);
.output(&mut encoder, &self._texture, self._texture_size, &self.ctx);
self.ctx.queue.submit(Some(encoder.finish())); self.ctx.queue.submit(Some(encoder.finish()));
self.output.get_data(&self.ctx).await;
} }
pub fn load_data<'a, T>(&mut self, element: &T, data: &T::Data) -> ElementAttach pub fn drop_all_buffers(&mut self) {
self.buffer_pool.buffers.clear();
}
pub fn load_data<'a, T>(&self, element: &T, data: &T::Data, config: &T::Config) -> ElementAttach
where where
T: Element, T: Element,
{ {
let buffer_pool = &mut self.buffer_pool; let buffer_pool = &self.buffer_pool;
let ctx = &self.ctx; let ctx = &self.ctx;
element.load_data(&ctx, data, buffer_pool) element.load_data(&ctx, data, buffer_pool, config)
}
pub fn create_window(&self, window: Window) -> RenderWindow {
RenderWindow::new(window, &self.ctx.device)
}
}
pub struct Window {
pub width: u32,
pub height: u32,
}
pub struct RenderWindow {
_texture: wgpu::Texture,
_texture_size: wgpu::Extent3d,
texture_view: wgpu::TextureView,
output: Output,
window: Window,
}
impl RenderWindow {
pub fn new(window: Window, device: &wgpu::Device) -> Self {
// Create a new texture. This texture will be used as the output texture for the render pass.
let texture_size = wgpu::Extent3d {
width: window.width,
height: window.height,
depth_or_array_layers: 1,
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("output texture"),
size: texture_size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
});
// Create a texture view from the texture. This texture view will be used as the output texture for the render pass.
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let output = Output::new(device);
Self {
_texture: texture,
_texture_size: texture_size,
texture_view,
output,
window,
}
}
pub fn output(&self) -> &Output {
&self.output
}
pub fn finish(&self, encoder: &mut wgpu::CommandEncoder) {
encoder.copy_texture_to_buffer(
wgpu::ImageCopyTexture {
texture: &self._texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
wgpu::ImageCopyBuffer {
buffer: &self.output.output_buffer,
layout: wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(256 * 4),
rows_per_image: Some(256),
},
},
wgpu::Extent3d {
width: self.window.width,
height: self.window.height,
depth_or_array_layers: 1,
},
);
} }
} }
@ -202,16 +256,21 @@ impl Ctx {
} }
} }
pub struct DrawList<'b, 'a: 'b> { #[derive(Clone)]
pub elements: Vec<(&'b ElementAttach, ElementsRef<'a>)>, // 修复字段访问权限 pub struct DrawList {
pub elements: Vec<(std::sync::Arc<ElementAttach>, Elements)>, // 修复字段访问权限
} }
impl<'b, 'a: 'b> DrawList<'b, 'a> { impl DrawList {
pub fn new() -> Self { pub fn new() -> Self {
Self { elements: vec![] } Self { elements: vec![] }
} }
pub fn push<Ele: Into<ElementsRef<'a>>>(&mut self, element: Ele, attach: &'a ElementAttach) { pub fn push<Ele: Into<Elements>>(
&mut self,
element: Ele,
attach: std::sync::Arc<ElementAttach>,
) {
self.elements.push((attach, element.into())); self.elements.push((attach, element.into()));
} }
} }
@ -298,7 +357,7 @@ impl DataBufferPool {
} }
} }
pub fn get_or_create_buffer<F>(&mut self, key: BufferKey, f: F) -> DB pub fn get_or_create_buffer<F>(&self, key: BufferKey, f: F) -> DB
where where
F: FnOnce() -> wgpu::Buffer, F: FnOnce() -> wgpu::Buffer,
{ {
@ -325,7 +384,7 @@ impl BufferKey {
} }
pub struct Output { pub struct Output {
output_buffer: wgpu::Buffer, pub output_buffer: wgpu::Buffer,
} }
impl Output { impl Output {
@ -346,34 +405,6 @@ impl Output {
Self { output_buffer } Self { output_buffer }
} }
pub fn output(
&self,
encoder: &mut wgpu::CommandEncoder,
texture: &wgpu::Texture,
texture_size: wgpu::Extent3d,
ctx: &Ctx,
) {
let u32_size = std::mem::size_of::<u32>() as u32;
encoder.copy_texture_to_buffer(
wgpu::ImageCopyTexture {
aspect: wgpu::TextureAspect::All,
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
},
wgpu::ImageCopyBuffer {
buffer: &self.output_buffer,
layout: wgpu::ImageDataLayout {
offset: 0,
bytes_per_row: Some(u32_size * 256),
rows_per_image: Some(256),
},
},
texture_size,
);
}
pub async fn get_data(&self, ctx: &Ctx) { pub async fn get_data(&self, ctx: &Ctx) {
let device = &ctx.device; let device = &ctx.device;
// 需要对映射变量设置范围,以便我们能够解除缓冲区的映射 // 需要对映射变量设置范围,以便我们能够解除缓冲区的映射
@ -404,29 +435,27 @@ impl Output {
mod test { mod test {
use mp_core::{PluginManager, RadarGridData}; use mp_core::{PluginManager, RadarGridData};
use wgpu::core::pipeline;
use crate::elements::{Element, PPI}; use crate::elements::{ppi::PPIConfig, Element, PPI};
use super::*; use super::*;
#[test] #[test]
fn test_app() { fn test_app() {
let plugin_manager = PluginManager::new( let plugin_manager = PluginManager::new(
// r#"/Users/tsuki/projects/mp/loaders"# r#"/Users/tsuki/projects/mp/loaders"#, // r#"C:\Users\qwin7\projects\radarmp\loaders"#,
r#"C:\Users\qwin7\projects\radarmp\loaders"#,
) )
.unwrap(); .unwrap();
let data = plugin_manager.try_load_data( let data = plugin_manager.try_load_data(
// "/Users/tsuki/Desktop/Z_RADR_I_X5775_20230726180000_O_DOR-XPD-CAP-FMT.BIN.zip", "/Users/tsuki/Desktop/Z_RADR_I_X5775_20230726180000_O_DOR-XPD-CAP-FMT.BIN.zip",
r#"C:\Users\qwin7\Downloads\ZJSXAA_20230113070200_R.dat.gz"#, // r#"C:\Users\qwin7\Downloads\ZJSXAA_20230113070200_R.dat.gz"#,
); );
pollster::block_on(async { pollster::block_on(async {
let mut app = App::instant().await; let mut app = App::instant().await;
app.init().await; app.init().await;
let pipelines = app.pipelines.as_ref().unwrap();
let ppi = pipelines.ppi();
let ctx = &app.ctx; let ctx = &app.ctx;
let buffer_pool = &mut app.buffer_pool; let buffer_pool = &mut app.buffer_pool;
@ -434,17 +463,33 @@ mod test {
let first_block = data.first().unwrap(); let first_block = data.first().unwrap();
// Convert the first block into a PPI struct. // Convert the first block into a PPI struct.
if let Ok(data) = first_block.try_into() { // if let Ok(data) = first_block.try_into() {
let attachment = ppi.load_data(&ctx, data, buffer_pool); // // let attachment = {
// // let pipelines = app.pipelines.as_mut().unwrap();
// // let ppi = pipelines.ppi();
// Create a new draw list and push the attachment into it. // // // let attachment = ppi.load_data(
// // // &ctx,
// // // data,
// // // buffer_pool,
// // // &PPIConfig {
// // // colormap: vec![[1.0, 1.0, 1.0, 1.0], [1.0, 1.0, 1.0, 1.0]],
// // // color_range: [0.0, 1.0],
// // // },
// // // );
// // attachment
// // };
let mut draw_list = DrawList::new(); // let pipeline = app.pipelines();
draw_list.push(ppi, &attachment); // let ppi = pipeline.ppi();
// Draw the elements in the draw list. // // Create a new draw list and push the attachment into it.
app.draw(draw_list).await; // let mut draw_list = DrawList::new();
} // // draw_list.push(ppi, &attachment);
// // Draw the elements in the draw list.
// // app.draw(draw_list).await;
// }
} else { } else {
panic!("Failed to load data"); panic!("Failed to load data");
} }

View File

@ -1,22 +1,33 @@
use std::sync::Arc;
pub mod ppi; pub mod ppi;
use crate::app::{BufferKey, Ctx, DataBufferPool}; use crate::{
app::{BufferKey, Ctx, DataBufferPool},
App,
};
use mp_core::config;
pub use ppi::PPI; pub use ppi::PPI;
use std::any::Any; use std::any::Any;
use wgpu::util::DeviceExt; use wgpu::util::DeviceExt;
macro_rules! elements { macro_rules! elements {
($(($element_name:ident,$element: ty),)+) => { ($(($element_name:ident,$element: ty),)+) => {
#[derive(Clone)]
pub enum Elements { pub enum Elements {
$($element_name($element),)+ $($element_name(Arc<$element>),)+
} }
#[derive(Clone, Copy)]
pub enum ElementsRef<'a> { pub enum ElementsRef<'a> {
$($element_name(&'a $element),)+ $($element_name(&'a $element),)+
} }
pub enum ElementsMut<'a> {
$($element_name(&'a mut $element),)+
}
$( $(
impl From<$element> for Elements { impl From<Arc<$element>> for Elements {
fn from(element: $element) -> Self { fn from(element: Arc<$element>) -> Self {
Elements::$element_name(element) Elements::$element_name(element)
} }
} }
@ -26,6 +37,21 @@ macro_rules! elements {
ElementsRef::$element_name(element) ElementsRef::$element_name(element)
} }
} }
impl<'a> From<&'a mut $element> for ElementsMut<'a> {
fn from(element: &'a mut $element) -> Self {
ElementsMut::$element_name(element)
}
}
impl<'a> From<&'a mut $element> for ElementsRef<'a> {
fn from(element: &'a mut $element) -> Self {
ElementsRef::$element_name(element)
}
}
)+ )+
impl Elements { impl Elements {
@ -57,6 +83,20 @@ macro_rules! elements {
} }
impl<'a> ElementsMut<'a> {
pub fn pipeline(&'a self) -> &wgpu::RenderPipeline {
match self {
$(ElementsMut::$element_name(element) => element.pipeline(),)+
}
}
pub fn draw(&'a self, attach: &ElementAttach, render_pass: &mut wgpu::RenderPass) {
match self {
$(ElementsMut::$element_name(element) => element.draw(attach, render_pass),)+
}
}
}
}; };
} }
@ -65,6 +105,8 @@ pub trait Element {
type Uniform; type Uniform;
type Data; type Data;
type Config;
fn new(ctx: &Ctx) -> Self; fn new(ctx: &Ctx) -> Self;
// fn new_attachment<'a>(&self, ctx: &Ctx) -> ElementAttach; // fn new_attachment<'a>(&self, ctx: &Ctx) -> ElementAttach;
@ -84,7 +126,8 @@ pub trait Element {
&self, &self,
ctx: &Ctx, ctx: &Ctx,
data: &Self::Data, data: &Self::Data,
buffer_pool: &mut DataBufferPool, buffer_pool: &DataBufferPool,
config: &Self::Config,
) -> ElementAttach; ) -> ElementAttach;
} }

View File

@ -1,6 +1,6 @@
use crate::Shaders; use crate::tools::colormap::{ColorMap, ColormapParams};
use rust_embed::RustEmbed; use log::*;
use std::{ops::Sub, result, vec}; use std::{ops::Sub, vec};
use crate::{ use crate::{
app::{BufferKey, Ctx, DataBufferPool}, app::{BufferKey, Ctx, DataBufferPool},
@ -20,6 +20,12 @@ const RMAXNUM: u64 = 50;
pub struct PPI { pub struct PPI {
bind_group_layout: wgpu::BindGroupLayout, bind_group_layout: wgpu::BindGroupLayout,
pipeline: wgpu::RenderPipeline, pipeline: wgpu::RenderPipeline,
colormap: Option<ColorMap>,
}
pub struct PPIConfig {
pub colormap: Vec<[f32; 4]>,
pub color_range: [f32; 2],
} }
#[repr(C)] #[repr(C)]
@ -67,8 +73,14 @@ impl Element for PPI {
type Uniform = PPIUniform; type Uniform = PPIUniform;
type Data = RadarGridData; type Data = RadarGridData;
type Config = PPIConfig;
fn new(ctx: &Ctx) -> Self { fn new(ctx: &Ctx) -> Self {
let device = &ctx.device; let device = &ctx.device;
// Tools
let colormap_layout = ColorMap::layout(device);
// Group Layout // Group Layout
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("PPI Bind Group Layout"), label: Some("PPI Bind Group Layout"),
@ -106,6 +118,8 @@ impl Element for PPI {
bind_group_layouts: &[ bind_group_layouts: &[
// common_tools // common_tools
&ctx.common_tools.bind_group_layout, &ctx.common_tools.bind_group_layout,
// colormap
&colormap_layout,
// ppi // ppi
&bind_group_layout, &bind_group_layout,
], ],
@ -155,6 +169,7 @@ impl Element for PPI {
PPI { PPI {
bind_group_layout: bind_group_layout, bind_group_layout: bind_group_layout,
pipeline: render_pipeline, pipeline: render_pipeline,
colormap: None,
} }
} }
@ -188,12 +203,13 @@ impl Element for PPI {
&self, &self,
ctx: &Ctx, ctx: &Ctx,
data: &Self::Data, data: &Self::Data,
buffer_pool: &mut DataBufferPool, buffer_pool: &DataBufferPool,
config: &Self::Config,
) -> ElementAttach { ) -> ElementAttach {
info!("Loading PPI data");
let (vertex, index) = self.bake(data); let (vertex, index) = self.bake(data);
println!("index: {:?}", &(index.as_ref()).unwrap()[0..24]);
println!("vertex: {:?}", &vertex[0..4]);
let device = &ctx.device; let device = &ctx.device;
let queue = &ctx.queue;
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("PPI Uniform Buffer"), label: Some("PPI Uniform Buffer"),
@ -247,12 +263,22 @@ impl Element for PPI {
label: Some("PPI Bind Group"), label: Some("PPI Bind Group"),
}); });
// ColorMap Bind Group
let color_map = ColorMap::new(
device,
queue,
ColormapParams::new(config.colormap.clone(), config.color_range),
);
let color_map_group = color_map.bind_group(device);
// self.colormap = Some(color_map);
ElementAttach { ElementAttach {
vertex_buffer: vertex_buffer, vertex_buffer: vertex_buffer,
index_buffer: Some(index_buffer), index_buffer: Some(index_buffer),
num_indices, num_indices,
uniform_buffer: Some(uniform_buffer), uniform_buffer: Some(uniform_buffer),
bind_group: vec![(1, bind_group)], // bind group 0 is always common tools
bind_group: vec![(1, color_map_group), (2, bind_group)],
data_buffer_key: Some(key), data_buffer_key: Some(key),
} }
} }
@ -262,7 +288,7 @@ impl PPI {
fn init_shader(device: &wgpu::Device) -> wgpu::ShaderModule { fn init_shader(device: &wgpu::Device) -> wgpu::ShaderModule {
// let shader_str = merge_shader(r#"/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl"#); // let shader_str = merge_shader(r#"/Users/tsuki/projects/mp/mp_elements/shaders/ppi.wgsl"#);
let shader_str = get_shader("ppi_merged.wgsl").as_ref(); let shader_str = get_shader("elements/ppi_merged.wgsl");
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("PPI Shader Module"), label: Some("PPI Shader Module"),

View File

@ -1,27 +1,29 @@
use crate::app::Ctx; use crate::app::Ctx;
use crate::elements::*; use crate::elements::*;
use std::sync::Arc;
macro_rules! elementvec { macro_rules! elementvec {
($({$element: ident, $element_ty: ty})+) => { ($({$element: ident, $element_ty: ty, $element_mut: ident})+) => {
pub struct ElementVec { pub struct ElementVec {
$($element: $element_ty,)+ $($element: Arc<$element_ty> ,)+
} }
impl ElementVec { impl ElementVec {
pub fn init(ctx: &Ctx) -> Self { pub fn init(ctx: &Ctx) -> Self {
// Compile the shaders, create the pipelines, etc. // Compile the shaders, create the pipelines, etc.
Self { Self {
$($element: <$element_ty>::new(ctx),)+ $($element: Arc::new((<$element_ty>::new(ctx))) ,)+
} }
} }
$(pub fn $element(&self) -> &$element_ty { $(pub fn $element(&self) -> &Arc< $element_ty> {
&self.$element &self.$element
})+ })+
} }
}; };
() => {}; () => {};
} }
elementvec!({ elementvec!({
ppi, PPI ppi, PPI, ppi_mut
}); });

View File

@ -2,6 +2,7 @@ pub mod app;
pub mod elements; pub mod elements;
pub mod elementvec; pub mod elementvec;
pub mod renderer; pub mod renderer;
pub mod tools;
mod utils; mod utils;
pub use app::App; pub use app::App;

View File

@ -1,4 +1,5 @@
use glam::*; use glam::*;
#[derive(Debug, Clone)]
pub struct Camera { pub struct Camera {
pub position: Vec3, pub position: Vec3,
pub center: Vec3, pub center: Vec3,

View File

@ -1,4 +1,5 @@
use glam::*; use glam::*;
#[derive(Clone, Debug)]
pub struct Projection { pub struct Projection {
aspect: f32, aspect: f32,
fovy: f32, fovy: f32,
@ -24,3 +25,14 @@ impl Projection {
Mat4::perspective_rh(self.fovy, self.aspect, self.znear, self.zfar) Mat4::perspective_rh(self.fovy, self.aspect, self.znear, self.zfar)
} }
} }
impl Default for Projection {
fn default() -> Self {
Self {
aspect: 1.0,
fovy: 45.0,
znear: 0.1,
zfar: 100.0,
}
}
}

View File

@ -0,0 +1,212 @@
use wgpu::util::DeviceExt;
pub struct ColorMap {
uniform: ColorMapUniform,
uniform_buffer: wgpu::Buffer,
unifrom_bind_group_layout: wgpu::BindGroupLayout,
texture: wgpu::Texture,
texture_view: wgpu::TextureView,
sampler: wgpu::Sampler,
}
pub struct ColormapParams {
pub colors: Vec<[f32; 4]>,
pub color_range: [f32; 2],
}
impl ColormapParams {
pub fn from_u8(colors: Vec<[u8; 4]>, color_range: [f32; 2]) -> Self {
let colors = colors
.iter()
.map(|c| {
let c = [c[0] as f32, c[1] as f32, c[2] as f32, c[3] as f32];
let c = [c[0] / 255.0, c[1] / 255.0, c[2] / 255.0, c[3] / 255.0];
c
})
.collect::<Vec<_>>();
ColormapParams {
colors,
color_range,
}
}
pub fn new(colors: Vec<[f32; 4]>, color_range: [f32; 2]) -> Self {
ColormapParams {
colors,
color_range,
}
}
fn as_texture_data(&self) -> Vec<u8> {
self.colors
.iter()
.flat_map(|color| bytemuck::bytes_of(color))
.copied()
.collect()
}
}
#[derive(Debug, Clone, Copy, encase::ShaderType)]
#[repr(C)]
pub struct ColorMapUniform {
color_count: u32,
value_min: f32,
value_max: f32,
invalid_value: f32,
}
impl ColorMapUniform {
fn as_slice(&self) -> encase::internal::Result<Vec<u8>> {
let mut buffer = encase::UniformBuffer::new(Vec::new());
buffer.write(self)?;
Ok(buffer.into_inner())
}
}
impl ColorMap {
pub fn new(device: &wgpu::Device, queue: &wgpu::Queue, params: ColormapParams) -> Self {
let uniform = ColorMapUniform {
color_count: params.colors.len() as u32,
value_min: params.color_range[0],
value_max: params.color_range[1],
invalid_value: 0.0,
};
let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("ColorMap Uniform Buffer"),
contents: uniform.as_slice().unwrap().as_slice(),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let texture = Self::create_color_texture(device, queue, &params);
let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = Self::create_sampler(device);
let bind_group_layout = Self::layout(device);
ColorMap {
uniform,
uniform_buffer: buffer,
unifrom_bind_group_layout: bind_group_layout,
sampler,
texture,
texture_view,
// uniform_bind_group: bind_group,
}
}
pub fn layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("ColorMap Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::all(),
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D1,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::all(),
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
})
}
pub fn bind_group(&self, device: &wgpu::Device) -> wgpu::BindGroup {
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("ColorMap Bind Group"),
layout: &self.unifrom_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&self.texture_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&self.sampler),
},
wgpu::BindGroupEntry {
binding: 2,
resource: self.uniform_buffer.as_entire_binding(),
},
],
});
bind_group
}
pub fn bind_group_layout(&self) -> &wgpu::BindGroupLayout {
&self.unifrom_bind_group_layout
}
pub fn set_uniform<F>(&mut self, f: F)
where
F: FnOnce(&mut ColorMapUniform),
{
f(&mut self.uniform);
}
pub fn update(&mut self, queue: &wgpu::Queue) {
queue.write_buffer(
&self.uniform_buffer,
0,
self.uniform.as_slice().unwrap().as_slice(),
);
}
fn create_color_texture(
device: &wgpu::Device,
queue: &wgpu::Queue,
params: &ColormapParams,
) -> wgpu::Texture {
device.create_texture_with_data(
queue,
&wgpu::TextureDescriptor {
label: Some("ColorMap Texture"),
size: wgpu::Extent3d {
width: params.colors.len() as u32,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D1,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
},
wgpu::util::TextureDataOrder::LayerMajor,
&params.as_texture_data(),
)
}
fn create_sampler(device: &wgpu::Device) -> wgpu::Sampler {
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("ColorMap Sampler"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
sampler
}
}

View File

@ -1,2 +1 @@
pub mod colormap; pub mod colormap;
pub mod ppi;

View File

@ -2,8 +2,8 @@ use crate::Shaders;
use std::borrow::Cow; use std::borrow::Cow;
use std::str; use std::str;
pub fn get_shader(name: &str) -> Cow<'static, str> { pub fn get_shader(name: &str) -> String {
let file = Shaders::get(name).unwrap(); let file = Shaders::get(name).unwrap();
let string = String::from_utf8_lossy(&file.data); let string = String::from_utf8(file.data.to_vec()).unwrap();
string string
} }