Implement window creation.
This commit is contained in:
parent
ebbfd4b336
commit
cde7b3560f
15
Cargo.toml
15
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"
|
||||
|
3
src/app/context/mod.rs
Normal file
3
src/app/context/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub struct Context {
|
||||
|
||||
}
|
1
src/app/mod.rs
Normal file
1
src/app/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod context;
|
@ -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();
|
||||
}
|
||||
|
@ -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::<Vec<u8>>(100);
|
||||
|
||||
if let Ok(hid) = HidApi::new() {
|
||||
|
||||
let mut devices = Vec::<Device>::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.");
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
623
src/hid/mod.rs
623
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<u32>,
|
||||
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<usize>,
|
||||
|
||||
bit_offset:usize,
|
||||
}
|
||||
|
||||
pub struct Report {
|
||||
pub id:u32,
|
||||
pub length:usize,
|
||||
pub fields:Vec<Field>,
|
||||
}
|
||||
|
||||
pub struct ReportDescriptor {
|
||||
pub interfaces:Vec<Interface>,
|
||||
pub inputs:Vec<usize>,
|
||||
pub outputs:Vec<usize>,
|
||||
pub features:Vec<usize>,
|
||||
pub reports:Vec<Report>,
|
||||
|
||||
has_id:bool,
|
||||
}
|
||||
impl ReportDescriptor {
|
||||
pub fn parse(bytes:&[u8]) -> Result<Self,()>
|
||||
{
|
||||
// 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::<GlobalState>::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<Vec<usize>,()>
|
||||
{
|
||||
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<u8>
|
||||
{
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn find_report(&self, id:u32) -> Option<usize>
|
||||
{
|
||||
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::*;
|
||||
|
89
src/lib.rs
89
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<Query>,
|
||||
supervisor:Sender<Query>,
|
||||
sender:Sender<Query>,
|
||||
receiver:Receiver<Query>,
|
||||
}
|
||||
impl Donten {
|
||||
pub fn init(_config:Config) -> Result<Self, Error>
|
||||
{
|
||||
// Initialize supervisor.
|
||||
let channel = system::Supervisor::start(None)?;
|
||||
let supervisor = system::Supervisor::start(None)?;
|
||||
let (sender, receiver) = crossbeam::channel::bounded::<Query>(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<system::WindowManager>
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,12 +34,6 @@ impl Internal {
|
||||
}
|
||||
|
||||
QueryData::Window(request) => match request {
|
||||
WindowQuery::Create {
|
||||
|
||||
} => {
|
||||
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,6 @@ pub enum QueryData {
|
||||
Network,
|
||||
Scene,
|
||||
Storage,
|
||||
Video,
|
||||
Video(VideoQuery),
|
||||
Window(WindowQuery),
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
mod world;
|
||||
pub struct SceneManager {
|
||||
channel:Sender<Query>,
|
||||
}
|
||||
|
118
src/system/scene/world/consts.rs
Normal file
118
src/system/scene/world/consts.rs
Normal file
@ -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.,
|
||||
},
|
||||
];
|
113
src/system/scene/world/mod.rs
Normal file
113
src/system/scene/world/mod.rs
Normal file
@ -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<Layer>,
|
||||
}
|
||||
|
||||
struct Cell {
|
||||
vertices:glam::IVec3,
|
||||
}
|
||||
|
||||
struct TerrainData {
|
||||
vertices:Vec<glam::Vec3>,
|
||||
cells:Vec<Cell>,
|
||||
extent:[glam::IVec3; 3],
|
||||
}
|
||||
|
||||
|
||||
struct World {
|
||||
regions:Vec<Region>,
|
||||
|
||||
radius:i64,
|
||||
density:i64,
|
||||
|
||||
terrain:Option<Arc<Terrain>>,
|
||||
ocean:Option<Arc<Ocean>>,
|
||||
atmosphere:Option<Arc<Atmosphere>>,
|
||||
}
|
||||
|
||||
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<System>,
|
||||
stars:Vec<Star>,
|
||||
}
|
||||
|
||||
struct Star {
|
||||
mass:f32,
|
||||
radius:f32,
|
||||
}
|
||||
|
||||
enum Body {
|
||||
Star(Star),
|
||||
Gas {
|
||||
|
||||
},
|
||||
Terrestrial {
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
struct Cosmos {
|
||||
worlds:Pool<World>,
|
||||
systems:Pool<StarSystem>,
|
||||
stars:Vec<Star>,
|
||||
}
|
@ -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
|
||||
|
||||
|
31
src/system/video/internal/mod.rs
Normal file
31
src/system/video/internal/mod.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use crate::system::*;
|
||||
use super::vulkan::*;
|
||||
|
||||
pub struct Internal {
|
||||
supervisor:Sender<Query>,
|
||||
}
|
||||
impl Internal {
|
||||
pub fn thread(supervisor:Sender<Query>, _tx:Sender<Query>, rx:Receiver<Query>)
|
||||
{
|
||||
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 {
|
||||
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Query>,
|
||||
}
|
||||
@ -9,8 +13,20 @@ impl VideoManager {
|
||||
}
|
||||
|
||||
impl Subsystem for VideoManager {
|
||||
fn start(_supervisor:Option<Sender<Query>>) -> Result<Sender<Query>, Error>
|
||||
fn start(supervisor:Option<Sender<Query>>) -> Result<Sender<Query>, Error>
|
||||
{
|
||||
if let Some(supervisor) = supervisor {
|
||||
let (tx, rx) = channel::bounded::<Query>(24);
|
||||
|
||||
let sys_tx = tx.clone();
|
||||
std::thread::spawn(move || {
|
||||
Internal::thread(supervisor, sys_tx, rx);
|
||||
});
|
||||
|
||||
Ok(tx)
|
||||
} else {
|
||||
Err(Error::new())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
4
src/system/video/query.rs
Normal file
4
src/system/video/query.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub enum VideoQuery {
|
||||
None,
|
||||
|
||||
}
|
@ -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<VkPhysicalDevice>,
|
||||
name:String,
|
||||
|
||||
queue_transfer:Vec<usize>,
|
||||
queue_graphics:Vec<usize>,
|
||||
queue_compute:Vec<usize>,
|
||||
|
||||
usable:bool,
|
||||
}
|
||||
|
||||
pub struct Vulkan {
|
||||
instance:Arc<VkInstance>,
|
||||
|
||||
devices:Vec<Device>,
|
||||
}
|
||||
impl Vulkan {
|
||||
pub fn init() -> Result<Self,()>
|
||||
{
|
||||
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<usize,()>
|
||||
{
|
||||
// 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();
|
||||
|
||||
}
|
||||
impl Renderer for Vulkan {
|
||||
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
@ -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<usize>,
|
||||
}
|
||||
|
37
src/system/window/internal/display.rs
Normal file
37
src/system/window/internal/display.rs
Normal file
@ -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<Display>,
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Query>,
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
pub fn new(channel:Sender<Query>) -> 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"); }
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +1,151 @@
|
||||
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,
|
||||
|
||||
mod handler; use handler::Handler;
|
||||
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 display; use display::DisplayManager;
|
||||
|
||||
static mut WINPROC_SENDER :RwLock<Option<crossbeam::channel::Sender<Query>>> = RwLock::new(None);
|
||||
|
||||
enum InternalQuery {
|
||||
None,
|
||||
Thread(u32),
|
||||
}
|
||||
|
||||
pub struct Internal {
|
||||
supervisor:Sender<Query>,
|
||||
display:DisplayManager,
|
||||
}
|
||||
impl Internal {
|
||||
pub fn thread(supervisor:Sender<Query>, tx:Sender<Query>, rx:Receiver<Query>)
|
||||
{
|
||||
let _sv = Internal {
|
||||
supervisor,
|
||||
display:DisplayManager::new(),
|
||||
};
|
||||
|
||||
// Initialize event loop.
|
||||
let channel = tx.clone();
|
||||
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();
|
||||
if let Ok(channel) = unsafe {WINPROC_SENDER.get_mut()} {
|
||||
*channel = Some(tx.clone());
|
||||
} else {
|
||||
println!("error: failed to set window system sender.");
|
||||
}
|
||||
});
|
||||
|
||||
// Handle messages.
|
||||
while let Ok(msg) = rx.recv() {
|
||||
let (system_sender, system_receiver) = crossbeam::channel::bounded::<InternalQuery>(16);
|
||||
let (thread_sender, thread_receiver) = crossbeam::channel::bounded::<Query>(16);
|
||||
std::thread::spawn(move || {
|
||||
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::<WNDCLASSEXW>() 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::<RAWINPUTDEVICE>() 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 {
|
||||
@ -46,9 +161,51 @@ impl Internal {
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => { }
|
||||
@ -59,3 +216,121 @@ impl Internal {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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; }
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::<RAWINPUTHEADER>() 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)
|
||||
}
|
||||
|
25
src/system/window/layout.rs
Normal file
25
src/system/window/layout.rs
Normal file
@ -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<Layout>,
|
||||
pub monitors:Vec<MonitorInfo>,
|
||||
}
|
@ -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<Sender<Query>>) -> Result<Sender<Query>, crate::Error>
|
||||
{
|
||||
if let Some(supervisor) = supervisor {
|
||||
@ -44,8 +42,6 @@ impl Subsystem for WindowManager {
|
||||
|
||||
impl From<Sender<Query>> for WindowManager {
|
||||
fn from(channel:Sender<Query>) -> Self {
|
||||
Self {
|
||||
channel
|
||||
}
|
||||
Self { channel }
|
||||
}
|
||||
}
|
||||
|
@ -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<usize>,
|
||||
},
|
||||
|
||||
// Set window properties
|
||||
Configure {
|
||||
id:usize,
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user