Resolve merge conflict in bridge/src/lib.rs by preserving feature branch logic
This commit is contained in:
2
bridge/Cargo.lock
generated
2
bridge/Cargo.lock
generated
@@ -2823,7 +2823,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "stardust-xr-molecules"
|
name = "stardust-xr-molecules"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
source = "git+https://github.com/StardustXR/molecules.git?branch=dev#53cfb2eecb066faf60a1b0da0b70f84231bae2be"
|
source = "git+https://github.com/StardustXR/molecules.git?branch=dev#26e004af199ccccb2ff4d8662f82f4d65311d8d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ashpd",
|
"ashpd",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ impl Reify for BridgeState {
|
|||||||
} else {
|
} else {
|
||||||
format!("primitive from {}", model_path.display())
|
format!("primitive from {}", model_path.display())
|
||||||
};
|
};
|
||||||
|
<<<<<<< HEAD
|
||||||
eprintln!("[bridge/reify] Loading {} for node {} {}", entity_type_name, id, model_source);
|
eprintln!("[bridge/reify] Loading {} for node {} {}", entity_type_name, id, model_source);
|
||||||
match node.entity_type {
|
match node.entity_type {
|
||||||
4 => {
|
4 => {
|
||||||
@@ -204,6 +205,26 @@ impl Reify for BridgeState {
|
|||||||
node.color[0], node.color[1], node.color[2], node.color[3]
|
node.color[0], node.color[1], node.color[2], node.color[3]
|
||||||
));
|
));
|
||||||
Some(text.build())
|
Some(text.build())
|
||||||
|
=======
|
||||||
|
|
||||||
|
eprintln!("[bridge/reify] Loading {} for node {} {}",
|
||||||
|
entity_type_name, id, model_source);
|
||||||
|
|
||||||
|
match Model::direct(&model_path) {
|
||||||
|
Ok(model) => {
|
||||||
|
// TODO: Color tinting is not currently supported due to missing public API in asteroids.
|
||||||
|
// When Model/MaterialParameter API is available, apply color here.
|
||||||
|
if node.color != [1.0, 1.0, 1.0, 1.0] {
|
||||||
|
eprintln!("[bridge/reify] Node {} requested color tint RGBA({:.2}, {:.2}, {:.2}, {:.2}) -- NOT SUPPORTED YET",
|
||||||
|
id, node.color[0], node.color[1], node.color[2], node.color[3]);
|
||||||
|
}
|
||||||
|
// TODO: Apply texture from texture_url (future)
|
||||||
|
if !node.texture_url.is_empty() {
|
||||||
|
eprintln!("[bridge/reify] Node {} has texture URL: {} - NOT YET APPLIED",
|
||||||
|
id, node.texture_url);
|
||||||
|
}
|
||||||
|
Some(model.build())
|
||||||
|
>>>>>>> origin/main
|
||||||
}
|
}
|
||||||
5 => {
|
5 => {
|
||||||
eprintln!("[bridge/reify] Image entity type detected for node {}. Using PanelUI as placeholder.", id);
|
eprintln!("[bridge/reify] Image entity type detected for node {}. Using PanelUI as placeholder.", id);
|
||||||
@@ -263,108 +284,67 @@ impl Reify for BridgeState {
|
|||||||
// Recursively build children
|
// Recursively build children
|
||||||
let children: Vec<_> = nodes.iter()
|
let children: Vec<_> = nodes.iter()
|
||||||
.filter_map(|(child_id, child_node)| {
|
.filter_map(|(child_id, child_node)| {
|
||||||
if child_node.parent == Some(id) {
|
eprintln!("[bridge/reify] Loading {} for node {} {}", entity_type_name, id, model_source);
|
||||||
build_node(*child_id, nodes, downloader)
|
match node.entity_type {
|
||||||
} else {
|
4 => {
|
||||||
None
|
let text = ast::elements::Text::new(&node.name)
|
||||||
|
.character_height(node.dimensions[1].max(0.01))
|
||||||
|
.color(ast::elements::RgbaLinear::new(
|
||||||
|
node.color[0], node.color[1], node.color[2], node.color[3]
|
||||||
|
));
|
||||||
|
Some(text.build())
|
||||||
|
}
|
||||||
|
5 => {
|
||||||
|
eprintln!("[bridge/reify] Image entity type detected for node {}. Using PanelUI as placeholder.", id);
|
||||||
|
let panel = ast::elements::PanelUI::default();
|
||||||
|
Some(panel.build())
|
||||||
|
}
|
||||||
|
6 => {
|
||||||
|
eprintln!("[bridge/reify] Light entity type detected for node {}.", id);
|
||||||
|
let color = ast::elements::RgbaLinear::new(
|
||||||
|
node.color[0], node.color[1], node.color[2], node.color[3]
|
||||||
|
);
|
||||||
|
let intensity = node.dimensions.get(1).copied().unwrap_or(1.0).max(0.01);
|
||||||
|
let light = ast::elements::Light::new()
|
||||||
|
.color(color)
|
||||||
|
.intensity(intensity);
|
||||||
|
Some(light.build())
|
||||||
|
}
|
||||||
|
7 => {
|
||||||
|
eprintln!("[bridge/reify] Zone entity type detected for node {}.", id);
|
||||||
|
let color = ast::elements::RgbaLinear::new(
|
||||||
|
node.color[0], node.color[1], node.color[2], node.color[3]
|
||||||
|
);
|
||||||
|
let size = glam::Vec3::from(node.dimensions);
|
||||||
|
let zone = ast::elements::Zone::new()
|
||||||
|
.color(color)
|
||||||
|
.size([size.x, size.y, size.z]);
|
||||||
|
Some(zone.build())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
match Model::direct(&model_path) {
|
||||||
|
Ok(mut model) => {
|
||||||
|
if node.color != [1.0, 1.0, 1.0, 1.0] {
|
||||||
|
let color = ast::elements::RgbaLinear::new(
|
||||||
|
node.color[0], node.color[1], node.color[2], node.color[3]
|
||||||
|
);
|
||||||
|
model = model.color_tint(color);
|
||||||
|
eprintln!("[bridge/reify] Node {}: applied color tint RGBA({:.2}, {:.2}, {:.2}, {:.2})",
|
||||||
|
id, node.color[0], node.color[1], node.color[2], node.color[3]);
|
||||||
|
}
|
||||||
|
if !node.texture_url.is_empty() {
|
||||||
|
eprintln!("[bridge/reify] Node {} has texture URL: {} - NOT YET APPLIED (API limitation)",
|
||||||
|
id, node.texture_url);
|
||||||
|
}
|
||||||
|
Some(model.build())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("[bridge/reify] Failed to load model for node {}: {}", id, e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let mut spatial = Spatial::default()
|
|
||||||
.transform(transform)
|
|
||||||
.build()
|
|
||||||
.maybe_child(model_child);
|
|
||||||
for (_cid, child_spatial) in children {
|
|
||||||
spatial = spatial.child(child_spatial);
|
|
||||||
}
|
|
||||||
Some((id, spatial))
|
|
||||||
}
|
|
||||||
// Only attach root nodes (no parent) to PlaySpace
|
|
||||||
let root_nodes: Vec<_> = self.nodes.iter()
|
|
||||||
.filter_map(|(id, node)| if node.parent.is_none() { build_node(*id, &self.nodes, downloader) } else { None })
|
|
||||||
.collect();
|
|
||||||
PlaySpace.build().stable_children(root_nodes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static STARTED: AtomicBool = AtomicBool::new(false);
|
|
||||||
static STOP_REQUESTED: AtomicBool = AtomicBool::new(false);
|
|
||||||
lazy_static::lazy_static! {
|
|
||||||
static ref CTRL: Mutex<Ctrl> = Mutex::new(Ctrl::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
||||||
struct Node {
|
|
||||||
id: u64,
|
|
||||||
name: String,
|
|
||||||
parent: Option<u64>,
|
|
||||||
#[serde(skip)]
|
|
||||||
transform: Mat4,
|
|
||||||
entity_type: u8, // 0=Unknown, 1=Box, 2=Sphere, 3=Model, etc.
|
|
||||||
model_url: String,
|
|
||||||
texture_url: String,
|
|
||||||
#[serde(skip)]
|
|
||||||
color: [f32; 4], // RGBA
|
|
||||||
#[serde(skip)]
|
|
||||||
dimensions: [f32; 3], // xyz dimensions in meters
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Ctrl {
|
|
||||||
rt: Option<Runtime>,
|
|
||||||
handle: Option<JoinHandle<()>>, // client running thread
|
|
||||||
tx: Option<tokio::sync::mpsc::UnboundedSender<Command>>,
|
|
||||||
next_id: u64,
|
|
||||||
nodes: HashMap<u64, Node>,
|
|
||||||
shared_state: Option<Arc<Mutex<BridgeState>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Ctrl {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
rt: None,
|
|
||||||
handle: None,
|
|
||||||
tx: None,
|
|
||||||
next_id: 1,
|
|
||||||
nodes: HashMap::new(),
|
|
||||||
shared_state: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn sdxr_start(app_id: *const std::os::raw::c_char) -> i32 {
|
|
||||||
if STARTED.swap(true, Ordering::SeqCst) { return 0; }
|
|
||||||
let _name = unsafe { CStr::from_ptr(app_id) }.to_string_lossy().to_string();
|
|
||||||
|
|
||||||
// Reset connection status flags
|
|
||||||
CONNECTION_SUCCESS.store(false, Ordering::SeqCst);
|
|
||||||
CONNECTION_FAILED.store(false, Ordering::SeqCst);
|
|
||||||
|
|
||||||
let mut ctrl = CTRL.lock().unwrap();
|
|
||||||
ctrl.next_id = 1;
|
|
||||||
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<Command>();
|
|
||||||
ctrl.tx = Some(tx.clone());
|
|
||||||
|
|
||||||
// Shared state that both the command handler and the client state will access
|
|
||||||
let shared_state = Arc::new(Mutex::new(BridgeState::default()));
|
|
||||||
let shared_for_commands = Arc::clone(&shared_state);
|
|
||||||
let shared_for_event_loop = Arc::clone(&shared_state);
|
|
||||||
|
|
||||||
// Build a multi-threaded Tokio runtime for the client
|
|
||||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
|
||||||
.enable_all()
|
|
||||||
.build()
|
|
||||||
.expect("tokio runtime");
|
|
||||||
let handle = std::thread::spawn(move || {
|
|
||||||
let res = rt.block_on(async move {
|
|
||||||
// Spawn command processor task that updates shared state
|
|
||||||
let cmd_task = tokio::spawn(async move {
|
|
||||||
while let Some(cmd) = rx.recv().await {
|
|
||||||
match cmd {
|
|
||||||
Command::Create { c_id, name, parent, transform } => {
|
|
||||||
if let Ok(mut state) = shared_for_commands.lock() {
|
|
||||||
let node = Node {
|
|
||||||
id: c_id,
|
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
parent,
|
parent,
|
||||||
transform,
|
transform,
|
||||||
|
|||||||
Reference in New Issue
Block a user