Implement window creation.

This commit is contained in:
yukirij 2024-11-30 17:48:53 -08:00
parent ebbfd4b336
commit cde7b3560f
25 changed files with 942 additions and 874 deletions

View File

@ -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
View File

@ -0,0 +1,3 @@
pub struct Context {
}

1
src/app/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod context;

View File

@ -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();
}

View File

@ -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.");
}
}

View File

@ -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>

View File

@ -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::*;

View File

@ -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
}
}
}

View File

@ -34,12 +34,6 @@ impl Internal {
}
QueryData::Window(request) => match request {
WindowQuery::Create {
} => {
}
_ => { }
}

View File

@ -23,6 +23,6 @@ pub enum QueryData {
Network,
Scene,
Storage,
Video,
Video(VideoQuery),
Window(WindowQuery),
}

View File

@ -1,5 +1,6 @@
use super::*;
mod world;
pub struct SceneManager {
channel:Sender<Query>,
}

View 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.,
},
];

View 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>,
}

View File

@ -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

View 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 {
_ => { }
}
_ => { }
}
}
}
}
}

View File

@ -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())
}
}
}

View File

@ -0,0 +1,4 @@
pub enum VideoQuery {
None,
}

View File

@ -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,
}
impl Renderer for Vulkan {
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();
}
Err(())
}
}

View File

@ -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>,
}

View 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;
}
}
}

View File

@ -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"); }
_ => { }
}
}
}

View File

@ -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());
}
}
}
_ => { }
@ -58,4 +215,122 @@ 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)
}

View 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>,
}

View File

@ -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 {
@ -43,9 +41,7 @@ impl Subsystem for WindowManager {
}
impl From<Sender<Query>> for WindowManager {
fn from(channel :Sender<Query>) -> Self {
Self {
channel
}
fn from(channel:Sender<Query>) -> Self {
Self { channel }
}
}

View File

@ -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,
},
}