diff --git a/Cargo.toml b/Cargo.toml index 312f779..888cb47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,20 @@ winit = "0.30.5" rayon = "1.10.0" crossbeam = "0.8.4" -hidapi = "2.6.3" +vulkano = "0.34.1" +glam = "0.29.2" + +pool = { git = "https://git.tsukiyo.org/Utility/pool" } [target.'cfg(windows)'.dependencies] -windows = "0.58.0" +windows = { version = "0.58.0", features = [ + "Win32_Foundation", + "Win32_UI_WindowsAndMessaging", + "Win32_Graphics_Gdi", + "Win32_UI_Input", + "Win32_System_Threading", +] } +widestring = "1.1.0" [target.'cfg(linux)'.dependencies] +evdev = "0.12.2" diff --git a/src/app/context/mod.rs b/src/app/context/mod.rs new file mode 100644 index 0000000..d936ec8 --- /dev/null +++ b/src/app/context/mod.rs @@ -0,0 +1,3 @@ +pub struct Context { + +} diff --git a/src/app/mod.rs b/src/app/mod.rs new file mode 100644 index 0000000..9efb2ab --- /dev/null +++ b/src/app/mod.rs @@ -0,0 +1 @@ +pub mod context; diff --git a/src/bin/client.rs b/src/bin/client.rs index 8e25747..c341c4f 100644 --- a/src/bin/client.rs +++ b/src/bin/client.rs @@ -1,13 +1,29 @@ +use windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT; + fn main() { // Initialize Donten engine let cfg = donten::Config::new(); - let _engine = if let Ok(engine) = donten::Donten::init(cfg) { + let engine = if let Ok(engine) = donten::Donten::init(cfg) { engine } else { println!("fatal: failed to initialize engine."); return; }; + engine.start(donten::System::Window, true); + + let sys_win = engine.sys_window().unwrap(); + + sys_win.create(donten::WindowConfig { + x: CW_USEDEFAULT, y: CW_USEDEFAULT, + width: 640, height: 480, + visible: true, + resize: false, caption: true, sysmenu: false, + private: false, + title: "Hello".to_string(), + context: None, + }).ok(); + std::thread::park(); } diff --git a/src/bin/test-hid.rs b/src/bin/test-hid.rs deleted file mode 100644 index f8d52b5..0000000 --- a/src/bin/test-hid.rs +++ /dev/null @@ -1,137 +0,0 @@ -#![allow(dead_code)] - -use hidapi::HidApi; - -use donten::hid; - -#[derive(Clone)] -struct Device { - product:String, - manufacturer:String, - serial:String, -} - -fn main() -{ - let (tx, rx) = crossbeam::channel::bounded::>(100); - - if let Ok(hid) = HidApi::new() { - - let mut devices = Vec::::new(); - - for device_info in hid.device_list() { - - let product = if let Some(s) = device_info.product_string() { s } else { "" }.to_string(); - let manufacturer = if let Some(s) = device_info.manufacturer_string() { s } else { "" }.to_string(); - let serial = if let Some(s) = device_info.serial_number() { s } else { "" }.to_string(); - - let mut index = 0; - while index < devices.len() { - if devices[index].product == product - && devices[index].manufacturer == manufacturer - && devices[index].serial == serial - { - break; - } - index += 1; - } - - if index == devices.len() { - // Insert new device - - let device = Device { - product, - manufacturer, - serial, - }; - - /*println!("{} ({})", - device.product, - device.manufacturer, - );*/ - - devices.push(device); - } - - // Add usage to device. - let mut desc_bytes = [0u8; hidapi::MAX_REPORT_DESCRIPTOR_SIZE]; - - //println!("## {} ##", devices[index].product); - - if let Ok(hwd) = device_info.open_device(&hid) { - if let Ok(desc_size) = hwd.get_report_descriptor(&mut desc_bytes) { - - if let Ok(descriptor) = hid::ReportDescriptor::parse(&desc_bytes[0..desc_size]) { - - /*println!("[INPUT]"); - for id in &descriptor.inputs { - let interface = &descriptor.interfaces[*id]; - - let (usage_page, usage) = if let Some(page) = hid::consts::USAGES.get(interface.usage_page) { - (page.name.to_string(), if let Some(usage) = page.get(interface.usage) { - usage.name.to_string() - } else { format!("Unknown({})", interface.usage) }) - } else {( - format!("Unknown({})", interface.usage_page), - format!("Unknown({})", interface.usage) - )}; - - println!(" > {} / {} [{:02x}:{:02x}]", - usage_page, - usage, - interface.collection, - interface.index, - ); - }*/ - - // Listen for input reports from device. - let _ttx = tx.clone(); - let device = devices[index].clone(); - std::thread::spawn(move || { - let _device_index = index; - let mut descriptor = descriptor; - let hwd = hwd; - - let mut buffer_length = 0; - for report in &descriptor.reports { - buffer_length = buffer_length.max(1 + (report.length / 8)); - } - - hwd.set_blocking_mode(true).ok(); - - let mut buffer = vec![0u8; buffer_length]; - loop { - match hwd.read(&mut buffer) { - Ok(size) => { - println!("report {}", device.product); - - if let Ok(changes) = descriptor.read_report(&buffer[..size]) { - for change in changes { - println!(" - change {}", change); - } - } else { - println!("Failed report read."); - } - } - Err(e) => { - println!("error ({}): {}", device.product, e.to_string()); - break; - } - } - } - - println!("drop {}", device.product); - }); - } - } - } - } - - // Process input reports. - while let Ok(_msg) = rx.recv() { - - } - } else { - println!("failed to init hidapi."); - } -} diff --git a/src/hid/consts.rs b/src/hid/consts.rs index 2ae62a0..f43212b 100644 --- a/src/hid/consts.rs +++ b/src/hid/consts.rs @@ -1,5 +1,5 @@ pub struct UsageCollection { - pages:&'static [UsagePage], + pub pages:&'static [UsagePage], } impl UsageCollection { pub fn get(&self, id:u16) -> Option<&'static UsagePage> @@ -17,7 +17,7 @@ pub struct UsagePage { pub id:u16, pub name:&'static str, - usages:&'static [Usage], + pub usages:&'static [Usage], } impl UsagePage { pub fn get(&self, id:u16) -> Option<&'static Usage> diff --git a/src/hid/mod.rs b/src/hid/mod.rs index b12d23b..777c632 100644 --- a/src/hid/mod.rs +++ b/src/hid/mod.rs @@ -1,622 +1 @@ -pub mod consts; - -// Main Items -const MN_INPUT :u8 = 0b1000_00_00; -const MN_OUTPUT :u8 = 0b1001_00_00; -const MN_FEATURE :u8 = 0b1011_00_00; -const MN_COLLECTION_BEGIN :u8 = 0b1010_00_00; -const MN_COLLECTION_END :u8 = 0b1100_00_00; -const MN_EXTENDED :u8 = 0b1111_11_00; - -// Global Items -const GB_USAGE_PAGE :u8 = 0b0000_01_00; -const GB_LOGICAL_MIN :u8 = 0b0001_01_00; -const GB_LOGICAL_MAX :u8 = 0b0010_01_00; -const GB_PHYSICAL_MIN :u8 = 0b0011_01_00; -const GB_PHYSICAL_MAX :u8 = 0b0100_01_00; -const GB_UNIT_EXPONENT :u8 = 0b0101_01_00; -const GB_UNIT :u8 = 0b0110_01_00; -const GB_REPORT_SIZE :u8 = 0b0111_01_00; -const GB_REPORT_ID :u8 = 0b1000_01_00; -const GB_REPORT_COUNT :u8 = 0b1001_01_00; -const GB_PUSH :u8 = 0b1010_01_00; -const GB_POP :u8 = 0b1011_01_00; - -// Local Items -const LC_USAGE :u8 = 0b0000_10_00; -const LC_USAGE_MIN :u8 = 0b0001_10_00; -const LC_USAGE_MAX :u8 = 0b0010_10_00; -const LC_DESIGNATOR_INDEX :u8 = 0b0011_10_00; -const LC_DESIGNATOR_MIN :u8 = 0b0100_10_00; -const LC_DESIGNATOR_MAX :u8 = 0b0101_10_00; -const LC_STRING_INDEX :u8 = 0b0111_10_00; -const LC_STRING_MIN :u8 = 0b1000_10_00; -const LC_STRING_MAX :u8 = 0b1001_10_00; -const LC_DELIMITER :u8 = 0b1010_10_00; - -#[derive(Clone, Copy)] -struct GlobalState { - pub usage_page:u16, - pub logical_min:i32, - pub logical_max:i32, - pub physical_min:i32, - pub physical_max:i32, - pub unit_exponent:i32, - pub unit:u32, - pub report_id:u32, - pub report_size:u32, - pub report_count:u32, -} -impl GlobalState { - pub fn new() -> Self - { - Self { - usage_page:0, - logical_min:0, - logical_max:0, - physical_min:0, - physical_max:0, - unit_exponent:0, - unit:0, - report_id:0, - report_size:0, - report_count:0, - } - } -} - -struct LocalState { - pub usages:Vec, - pub usage_range:[u32;2], -} -impl LocalState { - pub fn new() -> Self - { - Self { - usages:Vec::new(), - usage_range:[0, 0], - } - } -} - -struct Collection { - pub usage:u32, - pub index:u32, -} - -pub struct Interface { - pub usage_page:u16, - pub usage:u16, - pub collection:u16, - pub index:u16, - - working_value:i32, - pub value:i32, -} - -pub struct Field { - container:u8, - - is_const:bool, - is_var:bool, - is_rel:bool, - is_wrap:bool, - is_linear:bool, - has_pref:bool, - has_null:bool, - is_volatile:bool, - is_buffered:bool, - - report_size:usize, - report_count:usize, - - logical_min:i32, - logical_max:i32, - physical_min:i32, - physical_max:i32, - unit_exponent:i32, - unit:u32, - - interfaces:Vec, - - bit_offset:usize, -} - -pub struct Report { - pub id:u32, - pub length:usize, - pub fields:Vec, -} - -pub struct ReportDescriptor { - pub interfaces:Vec, - pub inputs:Vec, - pub outputs:Vec, - pub features:Vec, - pub reports:Vec, - - has_id:bool, -} -impl ReportDescriptor { - pub fn parse(bytes:&[u8]) -> Result - { - // Output - let mut descriptor = Self { - interfaces:Vec::new(), - inputs:Vec::new(), - outputs:Vec::new(), - features:Vec::new(), - reports:Vec::new(), - - has_id:false, - }; - - // Global State - let mut global_state = Vec::::new(); - global_state.push(GlobalState::new()); - - // Local State - let mut local_state = LocalState::new(); - - // Tracking - let mut collection_stack = vec![Collection { usage:0, index:0 }]; - let mut collection_index = 0; - //let mut delimiter = false; - - let mut index = 0; - while index < bytes.len() { - let mut sz = bytes[index] & 0x03; - let mut tg = bytes[index] & 0xFC; - - // Get byte size from index - sz = [ 0, 1, 2, 4 ][sz as usize]; - - index += 1; - - if bytes.len() - index >= sz as usize { - let global_state_index = global_state.len() - 1; - let collection_stack_index = collection_stack.len() - 1; - - // Handle long tag - if sz == 2 && tg == MN_EXTENDED { - sz = bytes[index + 1]; - tg = bytes[index + 2]; - - if bytes.len() - index < sz as usize { - return Err(()); - } - } - - if sz <= 4 { - let udata = Self::unpack(&bytes, &index, sz as usize); - let idata = Self::unpack_signed(&bytes, &index, sz as usize); - - match tg { - MN_INPUT | MN_OUTPUT | MN_FEATURE => { - /* - ** 0: Data(0), Constant(1) - ** 1: Array(0), Variable(1) - ** 2: Absolute(0), Relative(1) - ** 3: NoWrap(0), Wrap(1) - ** 4: Linear(0), NonLinear(1) - ** 5: PreferredState(0), NoPreferred(1) - ** 6: NoNull(0), NullState(1) - ** 7: reserved - ** 8: BitField(0), BufferedBytes(1) - ** _: reserved - */ - - let mut field = Field { - container:tg, - - is_const:(udata & 0x01) != 0, - is_var:(udata & 0x02) != 0, - is_rel:(udata & 0x04) != 0, - is_wrap:(udata & 0x04) != 0, - is_linear:(udata & 0x04) != 0, - has_pref:(udata & 0x04) != 0, - has_null:(udata & 0x04) != 0, - is_volatile:(udata & 0x04) != 0, - is_buffered:(udata & 0x04) != 0, - - report_size:global_state[global_state_index].report_size as usize, - report_count:global_state[global_state_index].report_count as usize, - - logical_min:global_state[global_state_index].logical_min, - logical_max:global_state[global_state_index].logical_max, - physical_min:global_state[global_state_index].physical_min, - physical_max:global_state[global_state_index].physical_max, - unit_exponent:global_state[global_state_index].unit_exponent, - unit:global_state[global_state_index].unit, - - interfaces:Vec::new(), - - bit_offset:0, - }; - - // Add data interfaces to descriptor. - if !field.is_const { - let interface_count = if field.is_var { - global_state[global_state_index].report_count as usize - } else { - if local_state.usage_range != [0; 2] { - (local_state.usage_range[1] - local_state.usage_range[0]) as usize - } else { - local_state.usages.len() as usize - } - }; - - for i in 0..interface_count { - - let mut usage_index = 0; - let usage = if local_state.usage_range != [0; 2] { - if (i as u32) <= local_state.usage_range[1] - local_state.usage_range[0] { - local_state.usage_range[0] + i as u32 - } else { - usage_index += 1; - local_state.usage_range[1] - } - } else if i < local_state.usages.len() { - local_state.usages[i] - } else if local_state.usages.len() > 0 { - let index = local_state.usages.len() - 1; - usage_index += 1; - local_state.usages[index] - } else { - 0 - }; - - let usage_page = if usage <= 0xFFFF { - global_state[global_state_index].usage_page - } else { - (usage >> 16) as u16 - }; - - let usage = usage as u16; - let collection = collection_stack[collection_stack_index].index as u16; - - // Check if interface already exists - let mut existing_index = None; - for i in 0..descriptor.interfaces.len() { - if descriptor.interfaces[i].usage_page == usage_page - && descriptor.interfaces[i].usage == usage - && descriptor.interfaces[i].collection == collection - && descriptor.interfaces[i].index == usage_index - { - existing_index = Some(i); - break; - } - } - - if let Some(existing_index) = existing_index { - field.interfaces.push(existing_index); - } else { - let interface = Interface { - usage_page, - usage:usage, - collection, - index:usage_index, - - working_value:0, - value:0, - }; - - descriptor.interfaces.push(interface); - - let id = descriptor.interfaces.len() - 1; - field.interfaces.push(id); - - match tg { - MN_OUTPUT => { descriptor.outputs.push(id); } - MN_FEATURE => { descriptor.features.push(id); } - _ => { descriptor.inputs.push(id); } - } - } - } - } - - let report_index = if let Some(report_index) = descriptor.find_report(global_state[global_state_index].report_id) { - report_index - } else { - descriptor.reports.push(Report { - id:global_state[global_state_index].report_id, - length:0, - fields:Vec::new(), - }); - descriptor.reports.len() - 1 - }; - - // Add interfaces to report. - let report = &mut descriptor.reports[report_index]; - - let bit_offset = if let Some(field) = report.fields.last() { - field.bit_offset + field.report_size - } else { 0 }; - - field.bit_offset = bit_offset; - //field.bit_length = global_state[global_state_index].report_size as usize; - - report.length += field.report_size * field.report_count; - report.fields.push(field); - - local_state = LocalState::new(); - } - - MN_COLLECTION_BEGIN => { - /* - ** 00: Physical - ** 01: Application - ** 02: Logical - ** 03: Report - ** 04: NamedArray - ** 05: UsageSwitch - ** 06: UsageModifier - ** 07-7F: reserved - ** 80-FF: vendor-defined - */ - - collection_stack.push(Collection { - usage:udata, - index:collection_index, - }); - collection_index += 1; - local_state = LocalState::new(); - } - - MN_COLLECTION_END => { - collection_stack.pop(); - local_state = LocalState::new(); - } - - GB_USAGE_PAGE => { - global_state[global_state_index].usage_page = udata as u16; - } - - GB_LOGICAL_MIN => { - global_state[global_state_index].logical_min = idata; - } - - GB_LOGICAL_MAX => { - global_state[global_state_index].logical_max = idata; - } - - GB_PHYSICAL_MIN => { - global_state[global_state_index].physical_min = idata; - } - - GB_PHYSICAL_MAX => { - global_state[global_state_index].physical_max = idata; - } - - GB_UNIT_EXPONENT => { - global_state[global_state_index].unit_exponent = idata; - } - - GB_UNIT => { - global_state[global_state_index].unit = udata; - } - - GB_REPORT_SIZE => { - global_state[global_state_index].report_size = udata; - } - - GB_REPORT_ID => { - descriptor.has_id = true; - global_state[global_state_index].report_id = udata; - - // Create new report if id not found. - if descriptor.find_report(udata).is_none() { - descriptor.reports.push(Report { - id:udata, - length:0, - fields:Vec::new(), - }); - } - } - - GB_REPORT_COUNT => { - global_state[global_state_index].report_count = udata; - } - - GB_PUSH => { - global_state.push(global_state[global_state.len() - 1]); - } - - GB_POP => { - if global_state.len() > 1 { - global_state.pop(); - } - } - - LC_USAGE => { - local_state.usages.push(udata); - } - - LC_USAGE_MIN => { - local_state.usage_range[0] = udata; - } - - LC_USAGE_MAX => { - local_state.usage_range[1] = udata; - } - - LC_DESIGNATOR_INDEX => { - - } - - LC_DESIGNATOR_MIN => { - - } - - LC_DESIGNATOR_MAX => { - - } - - LC_STRING_INDEX => { - - } - - LC_STRING_MIN => { - - } - - LC_STRING_MAX => { - - } - - LC_DELIMITER => { - - } - - _ => { return Err(()); } - } - } - - index += sz as usize; - } - } - - Ok(descriptor) - } - - pub fn read_report(&mut self, bytes:&[u8]) -> Result,()> - { - let mut start = 0; - - if bytes.len() == 0 { return Err(()); } - - // Read report id - let report_id = if self.has_id { - start += 1; - bytes[0] - } else { - 0 - } as u32; - - if let Some(report_index) = self.find_report(report_id) { - let report = &self.reports[report_index]; - let mut changes = Vec::new(); - - for field in &report.fields { - - // Set interface working values to zero. - for inf in &field.interfaces { - self.interfaces[*inf].working_value = 0; - } - - // Get report values. - for ri in 0..field.report_count { - let bit_offset = field.bit_offset + (ri * field.report_size); - - let byte = bit_offset / 8; - let bit = bit_offset % 8; - let byte_count = ((bit_offset + field.report_size) / 8) - byte; - - let mut value = (bytes[start + byte] as i64) >> bit; - for i in 1..byte_count { - value |= (bytes[start + byte + i] as i64) << ((i * 8) - bit); - } - - if value >= field.logical_min as i64 && value <= field.logical_max as i64 { - if field.is_var { - let interface = &mut self.interfaces[field.interfaces[ri]]; - - // Normalize value - if field.physical_min != 0 || field.physical_max != 0 { - let domain = (field.logical_max - field.logical_min) as i64; - let range = (field.physical_max - field.physical_min) as i64; - let basis = 1 << 24; - - interface.working_value = field.physical_min + (((value - field.logical_min as i64) * (range * basis)) / domain) as i32; - } - } else { - let interface = &mut self.interfaces[field.interfaces[value as usize]]; - interface.working_value = 1 << 24; - } - } - } - - // Set interface working values to zero. - for inf in &field.interfaces { - if self.interfaces[*inf].working_value != self.interfaces[*inf].value { - self.interfaces[*inf].value = self.interfaces[*inf].working_value; - changes.push(*inf); - } - } - } - - Ok(changes) - } else { - Err(()) - } - } - - pub fn write_report(&self) -> Vec - { - Vec::new() - } - - fn find_report(&self, id:u32) -> Option - { - let mut ri = 0; - while ri < self.reports.len() { - if self.reports[ri].id == id { return Some(ri); } - ri += 1; - } - None - } - - fn unpack(data:&[u8], index:&usize, size:usize) -> u32 - { - let mut result = 0u32; - if data.len() - *index >= size { - match size { - 1 => { - result = data[*index] as u32; - } - - 2 => { - result = (data[*index] as u32) - | ((data[*index + 1] as u32) << 8); - } - - 4 => { - result = (data[*index] as u32) - | ((data[*index + 1] as u32) << 8) - | ((data[*index + 2] as u32) << 16) - | ((data[*index + 3] as u32) << 24); - } - - _ => { } - } - } - result - } - - fn unpack_signed(data:&[u8], index:&usize, size:usize) -> i32 - { - let mut result = 0i32; - if data.len() - *index >= size { - match size { - 1 => { - result = data[*index] as i32; - } - - 2 => { - result = (data[*index] as i32) - | ((data[*index + 1] as i32) << 8); - } - - 4 => { - result = (data[*index] as i32) - | ((data[*index + 1] as i32) << 8) - | ((data[*index + 2] as i32) << 16) - | ((data[*index + 3] as i32) << 24); - } - - _ => { } - } - } - result - } -} +mod consts; pub use consts::*; diff --git a/src/lib.rs b/src/lib.rs index 3a6b207..bc03c80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,30 +1,103 @@ #![allow(dead_code, unused_imports)] -use crossbeam::channel::Sender; +use crossbeam::channel::{Receiver, Sender}; mod util; mod error; pub use error::Error; mod config; pub use config::Config; -use system::{Subsystem, Query}; -mod system; -mod platform; - +mod system; use system::{ + Subsystem, + Query, QueryData, + SupervisorQuery, + WindowManager, +}; +pub use system::{ + System, + window::WindowConfig, +}; pub mod hid; +mod platform; +mod app; pub struct Donten { - channel:Sender, + supervisor:Sender, + sender:Sender, + receiver:Receiver, } impl Donten { pub fn init(_config:Config) -> Result { // Initialize supervisor. - let channel = system::Supervisor::start(None)?; + let supervisor = system::Supervisor::start(None)?; + let (sender, receiver) = crossbeam::channel::bounded::(16); // Parse config and push instructions to supervisor. // ... // Ok(Self { - channel, + supervisor, + sender, + receiver, }) } + + pub fn start(&self, system:System, block:bool) -> bool + { + let resp = if block { Some(self.sender.clone()) } else { None }; + if self.supervisor.send(Query::new(resp, QueryData::Supervisor( + SupervisorQuery::Start { system } + ))).is_ok() { + if block { + while let Ok(query) = self.receiver.recv() { + match query.data { + QueryData::Supervisor(query) => match query { + SupervisorQuery::Status { + system, + channel, + } => match system { + System::Window => { return channel.is_some() } + _ => { } + } + _ => { } + } + _ => { } + } + } + } + return true; + } + return false; + } + + pub fn sys_window(&self) -> Option + { + if self.supervisor.send(Query::new(Some(self.sender.clone()), QueryData::Supervisor( + SupervisorQuery::Status { system: System::Window, channel: None } + ))).is_ok() { + match self.receiver.recv() { + Ok(query) => match query.data { + QueryData::Supervisor(query) => match query { + SupervisorQuery::Status { + system, + channel + } => match system { + System::Window => { + if let Some(channel) = channel { + Some(WindowManager::from(channel)) + } else { + None + } + } + _ => None + } + _ => None + } + _ => None + } + Err(_) => None + } + } else { + None + } + } } diff --git a/src/system/input/internal/mod.rs b/src/system/input/internal/mod.rs index fcef662..8bc1b21 100644 --- a/src/system/input/internal/mod.rs +++ b/src/system/input/internal/mod.rs @@ -34,12 +34,6 @@ impl Internal { } QueryData::Window(request) => match request { - WindowQuery::Create { - - } => { - - } - _ => { } } diff --git a/src/system/query.rs b/src/system/query.rs index 23db4d5..56bc5f2 100644 --- a/src/system/query.rs +++ b/src/system/query.rs @@ -23,6 +23,6 @@ pub enum QueryData { Network, Scene, Storage, - Video, + Video(VideoQuery), Window(WindowQuery), } diff --git a/src/system/scene/mod.rs b/src/system/scene/mod.rs index aec57af..f458976 100644 --- a/src/system/scene/mod.rs +++ b/src/system/scene/mod.rs @@ -1,5 +1,6 @@ use super::*; +mod world; pub struct SceneManager { channel:Sender, } diff --git a/src/system/scene/world/consts.rs b/src/system/scene/world/consts.rs new file mode 100644 index 0000000..b518dac --- /dev/null +++ b/src/system/scene/world/consts.rs @@ -0,0 +1,118 @@ +pub struct Chemical { + name:&'static str, + formula:&'static str, + mass:f32, +} + +pub const CHEMICALS :&[Chemical] = &[ + Chemical { + name:"Hydrogen", + formula:"H2", + mass:2.02, + }, + Chemical { + name:"Helium", + formula:"He", + mass:4.0, + }, + Chemical { + name:"Tritium", + formula:"T2", + mass:6., + }, + Chemical { + name:"Methane", + formula:"CH4", + mass:16.04, + }, + Chemical { + name:"Ammonia", + formula:"NH3", + mass:17.03, + }, + Chemical { + name:"Water", + formula:"H2O", + mass:18.01528, + }, + Chemical { + name:"Carbon Monoxide", + formula:"CO", + mass:28.01, + }, + Chemical { + name:"Nitrogen", + formula:"N2", + mass:28.01, + }, + Chemical { + name:"Ethylene", + formula:"C2H4", + mass:28.05, + }, + Chemical { + name:"Ethane", + formula:"C2H6", + mass:30.07, + }, + Chemical { + name:"Oxygen", + formula:"O2", + mass:32.0, + }, + Chemical { + name:"Fluorine", + formula:"F2", + mass:38., + }, + Chemical { + name:"Argon", + formula:"Ar", + mass:39.95, + }, + Chemical { + name:"Carbon Dioxide", + formula:"CO2", + mass:44.01, + }, + Chemical { + name:"Propane", + formula:"C3H8", + mass:44.10, + }, + Chemical { + name:"Ozone", + formula:"O3", + mass:48., + }, + Chemical { + name:"Butane", + formula:"C4H10", + mass:58.12, + }, + Chemical { + name:"Sulfer Dioxide", + formula:"SO2", + mass:64.06, + }, + Chemical { + name:"Chlorine", + formula:"Cl2", + mass:70.91, + }, + Chemical { + name:"Krypton", + formula:"Kr", + mass:84., + }, + Chemical { + name:"Hexane", + formula:"C6H14", + mass:86.18, + }, + Chemical { + name:"Xenon", + formula:"Xe", + mass:131., + }, +]; diff --git a/src/system/scene/world/mod.rs b/src/system/scene/world/mod.rs new file mode 100644 index 0000000..43c8ad0 --- /dev/null +++ b/src/system/scene/world/mod.rs @@ -0,0 +1,113 @@ +use std::sync::Arc; + +use glam::*; +use pool::Pool; + +mod consts; + +/* +** Descriptor Data +*/ + +// - System +// - Star +// - World +// - Region +// - Features +// - Terrain +// - Ocean +// - Atmosphere +// - Tectonics? +// - Climate +// - Biomes +// - Ecosystems +// - + +/* +** Runtime Data +*/ + +// Relief +// Entities (Static, Dynamic) +// Waves +// Weather + +struct Layer { + +} + +struct Region { + id:usize, + neighbors:[usize;7], + layers:Vec, +} + +struct Cell { + vertices:glam::IVec3, +} + +struct TerrainData { + vertices:Vec, + cells:Vec, + extent:[glam::IVec3; 3], +} + + +struct World { + regions:Vec, + + radius:i64, + density:i64, + + terrain:Option>, + ocean:Option>, + atmosphere:Option>, +} + +struct Terrain { + relief:i64, +} + +struct Ocean { + depth:i64, + composition:Vec<(usize, f32)>, +} + +struct Atmosphere { + surface_pressure:i64, + composition:Vec<(usize, f32)>, +} + + +enum System { + Object { + children:usize, + }, + Pair, +} + +struct StarSystem { + systems:Vec, + stars:Vec, +} + +struct Star { + mass:f32, + radius:f32, +} + +enum Body { + Star(Star), + Gas { + + }, + Terrestrial { + + }, +} + +struct Cosmos { + worlds:Pool, + systems:Pool, + stars:Vec, +} diff --git a/src/system/supervisor/internal.rs b/src/system/supervisor/internal.rs index fde35c3..835731b 100644 --- a/src/system/supervisor/internal.rs +++ b/src/system/supervisor/internal.rs @@ -18,11 +18,11 @@ impl Internal { SupervisorQuery::Start { system, } => if sv.subsystems[system as usize].is_none() { - let sv_channel = sv.subsystems[System::Supervisor as usize].clone(); + let supervisor_responder = sv.subsystems[System::Supervisor as usize].clone(); if let Ok(channel) = match system { - System::Window => WindowManager::start(sv_channel), + System::Window => WindowManager::start(supervisor_responder), _ => { Err(Error::new()) } } { @@ -38,6 +38,17 @@ impl Internal { ))).ok(); } } + + if let Some(resp) = query.resp { + resp.send(Query::new(None, QueryData::Supervisor( + SupervisorQuery::Status { + system, + channel: Some(channel.clone()), + } + ))).ok(); + } + + sv.subsystems[system as usize] = Some(channel); } else { // Log subsystem startup error diff --git a/src/system/video/internal/mod.rs b/src/system/video/internal/mod.rs new file mode 100644 index 0000000..60f0a5b --- /dev/null +++ b/src/system/video/internal/mod.rs @@ -0,0 +1,31 @@ +use crate::system::*; +use super::vulkan::*; + +pub struct Internal { + supervisor:Sender, +} +impl Internal { + pub fn thread(supervisor:Sender, _tx:Sender, rx:Receiver) + { + let _sv = Internal { + supervisor, + }; + + // Initialize rendering system. + if let Ok(_renderer) = Vulkan::init() { + + // Handle messages. + while let Ok(msg) = rx.recv() { + match &msg.data { + QueryData::Video(query) => match query { + + + _ => { } + } + + _ => { } + } + } + } + } +} diff --git a/src/system/video/mod.rs b/src/system/video/mod.rs index 99f3aef..09fdf91 100644 --- a/src/system/video/mod.rs +++ b/src/system/video/mod.rs @@ -1,5 +1,9 @@ use super::*; +mod vulkan; use vulkan::Vulkan as Renderer; +mod internal; use internal::Internal; +mod query; pub use query::VideoQuery; + pub struct VideoManager { channel:Sender, } @@ -9,8 +13,20 @@ impl VideoManager { } impl Subsystem for VideoManager { - fn start(_supervisor:Option>) -> Result, Error> + fn start(supervisor:Option>) -> Result, Error> { - Err(Error::new()) + if let Some(supervisor) = supervisor { + let (tx, rx) = channel::bounded::(24); + + let sys_tx = tx.clone(); + std::thread::spawn(move || { + Internal::thread(supervisor, sys_tx, rx); + }); + + Ok(tx) + } else { + Err(Error::new()) + } } } + diff --git a/src/system/video/query.rs b/src/system/video/query.rs new file mode 100644 index 0000000..8785a85 --- /dev/null +++ b/src/system/video/query.rs @@ -0,0 +1,4 @@ +pub enum VideoQuery { + None, + +} diff --git a/src/system/video/vulkan/mod.rs b/src/system/video/vulkan/mod.rs index 2ee4834..658d036 100644 --- a/src/system/video/vulkan/mod.rs +++ b/src/system/video/vulkan/mod.rs @@ -1,11 +1,113 @@ -use super::Renderer; +use vulkano::{ + device::{ + Device as VkDevice, DeviceCreateInfo, + QueueFlags, QueueCreateInfo, + physical::PhysicalDevice as VkPhysicalDevice, + }, + instance::{Instance as VkInstance, InstanceCreateFlags, InstanceCreateInfo}, + memory::allocator::StandardMemoryAllocator, + Version, + VulkanLibrary, + VulkanObject, +}; +use std::sync::Arc; + +pub struct Device { + handle:Arc, + name:String, + + queue_transfer:Vec, + queue_graphics:Vec, + queue_compute:Vec, + + usable:bool, +} pub struct Vulkan { + instance:Arc, + devices:Vec, } impl Vulkan { - -} -impl Renderer for Vulkan { + pub fn init() -> Result + { + if let Ok(library) = VulkanLibrary::new() { + if let Ok(instance) = VkInstance::new( + library, + InstanceCreateInfo { + flags:InstanceCreateFlags::ENUMERATE_PORTABILITY, + ..Default::default() + } + ) { + return Ok(Self { + instance, + devices:Vec::new(), + }); + } + } + Err(()) + } + + pub fn enumerate_devices(&mut self) -> usize + { + self.devices.clear(); + if let Ok(devices) = self.instance.enumerate_physical_devices() { + for device in devices { + + let mut queue_transfer = Vec::new(); + let mut queue_graphics = Vec::new(); + let mut queue_compute = Vec::new(); + + let mut index = 0; + for family in device.queue_family_properties() { + if family.queue_flags.contains(QueueFlags::TRANSFER) { + queue_transfer.push(index); + } + if family.queue_flags.contains(QueueFlags::GRAPHICS) { + queue_graphics.push(index); + } + if family.queue_flags.contains(QueueFlags::COMPUTE) { + queue_compute.push(index); + } + + index += 1; + } + + let usable = queue_graphics.len() > 0; + + self.devices.push(Device { + name:device.properties().device_name.clone(), + handle:device, + + queue_transfer, + queue_graphics, + queue_compute, + + usable, + }) + } + } + self.devices.len() + } + + pub fn init_context(&mut self, device:usize, queue_family_index:u32) -> Result + { + // Acquire device and queues + if let Ok((device, mut queues)) = VkDevice::new( + self.devices[device].handle.clone(), + DeviceCreateInfo { + queue_create_infos:vec![QueueCreateInfo { + queue_family_index, + ..Default::default() + }], + ..Default::default() + } + ) { + let queue = queues.next().unwrap(); + + } + + Err(()) + } } diff --git a/src/system/window/config.rs b/src/system/window/config.rs index 7fd1fc8..6833528 100644 --- a/src/system/window/config.rs +++ b/src/system/window/config.rs @@ -1,3 +1,13 @@ pub struct WindowConfig { + pub x:i32, pub y:i32, + pub width:i32, pub height:i32, + pub visible:bool, + pub resize:bool, + pub caption:bool, + pub sysmenu:bool, + pub private:bool, + + pub title:String, + pub context:Option, } diff --git a/src/system/window/internal/display.rs b/src/system/window/internal/display.rs new file mode 100644 index 0000000..24050af --- /dev/null +++ b/src/system/window/internal/display.rs @@ -0,0 +1,37 @@ +use windows::Win32::Graphics::Gdi::{ + EnumDisplayDevicesW, + DISPLAY_DEVICEW, +}; + +use pool::Pool; + +pub struct Display { + x:i32, y:i32, + width:i32, height:i32, +} + +pub struct DisplayManager { + displays:Pool, +} +impl DisplayManager { + pub fn new() -> Self + { + let mut this = Self { + displays:Pool::new(), + }; + + this.enumerate(); + this + } + + pub fn enumerate(&mut self) + { + let mut index = 0; + let mut device = DISPLAY_DEVICEW::default(); + while unsafe {EnumDisplayDevicesW(None, index, &mut device, 1)}.into() { + + + index += 1; + } + } +} diff --git a/src/system/window/internal/handler.rs b/src/system/window/internal/handler.rs deleted file mode 100644 index 1919c86..0000000 --- a/src/system/window/internal/handler.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crossbeam::channel::Sender; -use winit::{ - event::{Event, WindowEvent}, - event_loop::{ActiveEventLoop, ControlFlow, EventLoop}, - window::{Window, WindowId}, - application::ApplicationHandler, -}; -use crate::system::Query; - -pub struct Handler { - pub channel:Sender, -} - -impl Handler { - pub fn new(channel:Sender) -> Self - { - Self { channel } - } -} - -impl ApplicationHandler for Handler { - fn resumed(&mut self, _event_loop: &winit::event_loop::ActiveEventLoop) - { - - } - - fn window_event( - &mut self, - _event_loop:&ActiveEventLoop, - _window_id:WindowId, - _event: WindowEvent, - ) { - - } - - fn device_event( - &mut self, - _event_loop: &ActiveEventLoop, - _device_id: winit::event::DeviceId, - event: winit::event::DeviceEvent, - ) { - use winit::event::DeviceEvent; - - match event { - DeviceEvent::Added => { println!(" - added"); } - DeviceEvent::Removed => { println!(" - removed"); } - _ => { } - } - } -} diff --git a/src/system/window/internal/mod.rs b/src/system/window/internal/mod.rs index a3d5b0c..b8734c9 100644 --- a/src/system/window/internal/mod.rs +++ b/src/system/window/internal/mod.rs @@ -1,61 +1,336 @@ use crate::system::*; -use winit::{ - event::{Event, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, - window::Window, - application::ApplicationHandler, +use windows::{ + core::PCWSTR, + Win32::{ + Foundation::{ + GetLastError, + HINSTANCE, + HWND, + LPARAM, + LRESULT, + WPARAM, + }, + Graphics::Gdi::HBRUSH, + + UI::{ + Input::{ + GetRawInputData, + RegisterRawInputDevices, + HRAWINPUT, + RAWINPUT, + RAWINPUTDEVICE, + RAWINPUTHEADER, + RID_INPUT, + RIDEV_DEVNOTIFY, + RIM_TYPEHID, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE, + }, + WindowsAndMessaging::{ + PostMessageW, + CreateWindowExW, + DefWindowProcW, + DispatchMessageW, + GetMessageW, + PostThreadMessageW, + RegisterClassExW, + SetWindowTextW, + ShowWindow, + TranslateMessage, + SetWindowDisplayAffinity, + HCURSOR, + HICON, + MSG, + WINDOW_EX_STYLE, + WNDCLASSEXW, + WDA_MONITOR, + CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, + SW_SHOW, + WM_MOVE, WM_SIZE, + WM_INPUT, WM_DEVICECHANGE, WM_DISPLAYCHANGE, + WM_NULL, + WS_OVERLAPPED, WS_POPUPWINDOW, + WS_BORDER, WS_SIZEBOX, WS_CAPTION, + WS_SYSMENU, WS_MINIMIZEBOX, WS_MAXIMIZEBOX, + WS_VISIBLE, + WS_EX_APPWINDOW, WS_EX_NOREDIRECTIONBITMAP, + }, + }, + System::Threading::GetCurrentThreadId, + } }; +use std::sync::RwLock; -mod handler; use handler::Handler; +mod display; use display::DisplayManager; + +static mut WINPROC_SENDER :RwLock>> = RwLock::new(None); + +enum InternalQuery { + None, + Thread(u32), +} pub struct Internal { supervisor:Sender, + display:DisplayManager, } impl Internal { pub fn thread(supervisor:Sender, tx:Sender, rx:Receiver) { let _sv = Internal { supervisor, + display:DisplayManager::new(), }; - // Initialize event loop. - let channel = tx.clone(); + if let Ok(channel) = unsafe {WINPROC_SENDER.get_mut()} { + *channel = Some(tx.clone()); + } else { + println!("error: failed to set window system sender."); + } + + let (system_sender, system_receiver) = crossbeam::channel::bounded::(16); + let (thread_sender, thread_receiver) = crossbeam::channel::bounded::(16); std::thread::spawn(move || { - if let Ok(event_loop) = EventLoop::new() { - let mut handler = Handler::new(channel); - event_loop.set_control_flow(ControlFlow::Wait); - event_loop.run_app(&mut handler).ok(); + let system_sender = system_sender; + + // Initialize window settings. + let class_name = widestring::U16CString::from_str("donten-window-class").unwrap(); + let class_name = PCWSTR(class_name.as_ptr()); + + let wnd_class = WNDCLASSEXW { + cbSize:std::mem::size_of::() as u32, + style:CS_HREDRAW | CS_VREDRAW, + lpfnWndProc:Some(window_proc), + cbClsExtra:0, + cbWndExtra:0, + hInstance:HINSTANCE::default(), + hIcon:HICON::default(), + hCursor:HCURSOR::default(), + hbrBackground:HBRUSH::default(), + lpszMenuName:PCWSTR::null(), + lpszClassName:class_name, + hIconSm:HICON::default(), + }; + unsafe {RegisterClassExW(&wnd_class)}; + + // Register input devices. + let mut rawinput_devices = Vec::new(); + for page in crate::hid::USAGES.pages { + for usage in page.usages { + use crate::hid::UsageType; + match usage.usage_type { + UsageType::Application => { + rawinput_devices.push(RAWINPUTDEVICE { + usUsagePage:page.id, + usUsage:usage.id, + dwFlags:RIDEV_DEVNOTIFY, + hwndTarget:HWND::default(), + }); + } + _ => { } + } + } + } + if unsafe {RegisterRawInputDevices(&rawinput_devices, std::mem::size_of::() as u32)}.is_err() { + println!("Failed to register input devices: {}", unsafe {GetLastError()}.to_hresult().message()); + } + + // Send thread id to system. + system_sender.send(InternalQuery::Thread(unsafe {GetCurrentThreadId()})).ok(); + + // Process window events. + let mut msg = MSG::default(); + unsafe { + while GetMessageW(&mut msg, None, 0, 0).into() { + TranslateMessage(&msg).ok().ok(); + DispatchMessageW(&msg); + + if msg.message == WM_NULL { + if let Ok(msg) = thread_receiver.recv() { + match msg.data { + QueryData::Supervisor(request) => match request { + SupervisorQuery::Stop { + system: _, + } => { + + // Perform shutdown operations and terminate thread. + return; + } + + _ => { } + } + + QueryData::Window(request) => match request { + WindowQuery::Create { + config, + } => { + + let dwexstyle = WS_EX_APPWINDOW; + let mut dwstyle = if config.caption { WS_OVERLAPPED } else { WS_POPUPWINDOW }; + + if config.sysmenu { + dwstyle |= WS_SYSMENU | WS_MINIMIZEBOX; + } + + if config.resize { + dwstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; + } + + if config.visible { + dwstyle |= WS_VISIBLE; + } + + match CreateWindowExW( + dwexstyle, + class_name, + PCWSTR(widestring::U16CString::from_str(config.title).unwrap().as_ptr()), + dwstyle, + config.x, + config.y, + config.width, + config.height, + None, + None, + HINSTANCE::default(), + None, + ) { + Ok(hwnd) => { + if config.private { + SetWindowDisplayAffinity(hwnd, WDA_MONITOR).ok(); + } + + // Return window information to manager. + + } + + Err(e) => { + println!("error: {}", e.to_string()); + } + } + } + + _ => { } + } + + _ => { } + } + } + } + } } }); - // Handle messages. - while let Ok(msg) = rx.recv() { - match msg.data { - QueryData::Supervisor(request) => match request { - SupervisorQuery::Stop { - system: _, - } => { + // Wait for handler thread id to be set. + let mut thread_id = 0u32; + if let Ok(resp) = system_receiver.recv() { + if let InternalQuery::Thread(id) = resp { thread_id = id; } - // Perform shutdown operations and terminate thread. - return; + // Handle messages. + while let Ok(msg) = rx.recv() { + match &msg.data { + QueryData::Window(query) => match query { + + // Forward thread-required queries. + WindowQuery::Create { .. } => { + if thread_sender.send(msg).is_ok() { + // Dispatch window message to allow receiving of query. + unsafe {PostThreadMessageW(thread_id, WM_NULL, WPARAM(0), LPARAM(0))}.ok(); + } else { + // System is presumed dead. + break; + } + } + + _ => { } } _ => { } } + } + } + } +} - QueryData::Window(request) => match request { - WindowQuery::Create { +unsafe extern "system" fn window_proc( + hwnd:HWND, + msg:u32, + wparam:WPARAM, + lparam:LPARAM, +) -> LRESULT { + if let Ok(sender) = WINPROC_SENDER.read() { + if let Some(_sender) = sender.as_ref() { + match msg { + WM_MOVE => { + + } - } => { - + WM_SIZE => { + + } + + WM_INPUT => { + //println!("INPUT"); + + let mut _rawinput_header = RAWINPUTHEADER::default(); + let header_size = std::mem::size_of::() as u32; + + let mut size = 0; + let result = unsafe {GetRawInputData( + HRAWINPUT(lparam.0 as _), + RID_INPUT, + None, + &mut size, + header_size, + )}; + + if result == 0 && size > 0 { + let mut buffer = vec![0u8; size as usize]; + + if unsafe {GetRawInputData( + HRAWINPUT(lparam.0 as _), + RID_INPUT, + Some(buffer.as_mut_ptr() as *mut _), + &mut size, + header_size, + )} > 0 { + let raw_input :&RAWINPUT = &*(buffer.as_ptr() as *const RAWINPUT); + + const TYPE_MOUSE :u32 = RIM_TYPEMOUSE.0; + const TYPE_KEYBOARD :u32 = RIM_TYPEKEYBOARD.0; + const TYPE_HID :u32 = RIM_TYPEHID.0; + match raw_input.header.dwType { + TYPE_MOUSE => { + let _data = unsafe {raw_input.data.mouse}; + //sender.send(0).ok(); + } + + TYPE_KEYBOARD => { + let _data = unsafe {raw_input.data.keyboard}; + } + + TYPE_HID => { + let _data = unsafe {raw_input.data.hid}; + } + + _ => { } + } + + } } - _ => { } + return LRESULT(0); + } + + WM_DEVICECHANGE => { + println!("DEVICECHANGE"); + } + + WM_DISPLAYCHANGE => { + println!("DISPLAYCHANGE"); } _ => { } } } } + DefWindowProcW(hwnd, msg, wparam, lparam) } diff --git a/src/system/window/layout.rs b/src/system/window/layout.rs new file mode 100644 index 0000000..44b52f0 --- /dev/null +++ b/src/system/window/layout.rs @@ -0,0 +1,25 @@ +//use windows::Win32::Graphics::Gdi::EnumDisplayMonitors; + +pub struct MonitorInfo { + pub x:i32, + pub y:i32, + pub width:u32, + pub height:u32, +} + +pub struct WindowLayout { + pub x:i32, + pub y:i32, + pub width:u32, + pub height:u32, + +} + +pub struct Layout { + +} + +pub struct LayoutSystem { + pub layouts:Vec, + pub monitors:Vec, +} diff --git a/src/system/window/mod.rs b/src/system/window/mod.rs index 5146227..af69d7f 100644 --- a/src/system/window/mod.rs +++ b/src/system/window/mod.rs @@ -2,6 +2,7 @@ use super::*; mod query; pub use query::WindowQuery; mod config; pub use config::WindowConfig; +mod layout; pub use layout::*; mod internal; use internal::Internal; pub struct WindowManager { @@ -10,21 +11,18 @@ pub struct WindowManager { impl WindowManager { - pub fn create(&mut self) -> Result<(),()> + pub fn create(&self, config:WindowConfig) -> Result<(),()> { self.channel.send(Query::new( Some(self.channel.clone()), QueryData::Window(WindowQuery::Create { - + config, } - ))).ok(); - - Err(()) + ))).map_err(|_|()) } } impl Subsystem for WindowManager { - fn start(supervisor:Option>) -> Result, crate::Error> { if let Some(supervisor) = supervisor { @@ -43,9 +41,7 @@ impl Subsystem for WindowManager { } impl From> for WindowManager { - fn from(channel :Sender) -> Self { - Self { - channel - } + fn from(channel:Sender) -> Self { + Self { channel } } } diff --git a/src/system/window/query.rs b/src/system/window/query.rs index 25da49a..988c379 100644 --- a/src/system/window/query.rs +++ b/src/system/window/query.rs @@ -1,7 +1,46 @@ +use super::WindowConfig; + pub enum WindowQuery { None, + // Create a new window Create { - + config:WindowConfig, }, + + // Close a window + Destroy { + id:usize, + }, + + // Change window size + Resize { + width:u32, + height:u32, + }, + + // Move window to coordinates + Move { + x:i32, + y:i32, + }, + + // Set window show/hidden + Visibility { + id:usize, + visible:bool, + }, + + // Get list of windows + GetList { }, + List { + ids:Vec, + }, + + // Set window properties + Configure { + id:usize, + }, + + }