113 lines
3.6 KiB
C++
113 lines
3.6 KiB
C++
// StardustBridge.hpp
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <functional>
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
// A lightweight bridge to the StardustXR compositor.
|
|
// Assumes a C API is available at runtime; this implementation provides a
|
|
// minimal in-process fallback so the app remains testable without the shared lib.
|
|
class StardustBridge {
|
|
public:
|
|
using NodeId = std::uint64_t;
|
|
|
|
// Connect to the StardustXR compositor via IPC.
|
|
// Returns true on success. Searches standard socket locations if socketPath is empty.
|
|
bool connect(const std::string& socketPath = {});
|
|
|
|
|
|
// Create a 3D node with an initial transform. Optionally parent it.
|
|
NodeId createNode(const std::string& name,
|
|
const glm::mat4& transform = glm::mat4(1.0f),
|
|
std::optional<NodeId> parent = std::nullopt);
|
|
|
|
// Update a node's transform. Returns false if the node doesn't exist.
|
|
bool updateNodeTransform(NodeId id, const glm::mat4& transform);
|
|
|
|
// Set visual properties for a node
|
|
bool setNodeModel(NodeId id, const std::string& modelUrl);
|
|
bool setNodeTexture(NodeId id, const std::string& textureUrl);
|
|
bool setNodeColor(NodeId id, const glm::vec3& color, float alpha = 1.0f);
|
|
bool setNodeDimensions(NodeId id, const glm::vec3& dimensions);
|
|
bool setNodeEntityType(NodeId id, uint8_t entityType);
|
|
|
|
// Remove a node. Returns false if the node doesn't exist.
|
|
bool removeNode(NodeId id);
|
|
|
|
// Poll compositor events and input. Non-blocking.
|
|
void poll();
|
|
|
|
// Lifecycle helpers for the main loop.
|
|
bool running() const { return m_running; }
|
|
void requestQuit() { m_running = false; }
|
|
|
|
// Input snapshot (polled each frame via poll()).
|
|
glm::vec2 joystick() const { return m_joystick; } // x,y in [-1, 1]
|
|
glm::mat4 headPose() const { return m_headPose; } // world-from-head
|
|
|
|
// Utility: compute default IPC socket path (first-best guess).
|
|
static std::string defaultSocketPath();
|
|
|
|
~StardustBridge();
|
|
// Explicit cleanup
|
|
void close();
|
|
|
|
private:
|
|
struct Node {
|
|
std::string name;
|
|
std::optional<NodeId> parent;
|
|
glm::mat4 transform{1.0f};
|
|
};
|
|
|
|
// Fallback in-process scene representation for testing without the runtime.
|
|
std::unordered_map<NodeId, Node> m_nodes;
|
|
NodeId m_nextId{1};
|
|
|
|
// Connection and state
|
|
bool m_connected{false};
|
|
bool m_running{true};
|
|
std::string m_socketPath;
|
|
int m_socketFd{-1};
|
|
|
|
// Input state
|
|
glm::vec2 m_joystick{0.0f, 0.0f};
|
|
glm::mat4 m_headPose{1.0f};
|
|
|
|
// Optional root for the Overte world subscene
|
|
std::optional<NodeId> m_overteRoot;
|
|
|
|
// Dynamic Rust bridge (dlopen) function pointers
|
|
void* m_bridgeHandle{nullptr};
|
|
using fn_start_t = int(*)(const char*);
|
|
using fn_poll_t = int(*)();
|
|
using fn_shutdown_t = void(*)();
|
|
using fn_create_node_t = std::uint64_t(*)(const char*, const float*);
|
|
using fn_update_node_t = int(*)(std::uint64_t, const float*);
|
|
using fn_remove_node_t = int(*)(std::uint64_t);
|
|
using fn_set_model_t = int(*)(std::uint64_t, const char*);
|
|
using fn_set_texture_t = int(*)(std::uint64_t, const char*);
|
|
using fn_set_color_t = int(*)(std::uint64_t, float, float, float, float);
|
|
using fn_set_dimensions_t = int(*)(std::uint64_t, float, float, float);
|
|
using fn_set_entity_type_t = int(*)(std::uint64_t, std::uint8_t);
|
|
|
|
fn_start_t m_fnStart{nullptr};
|
|
fn_poll_t m_fnPoll{nullptr};
|
|
fn_shutdown_t m_fnShutdown{nullptr};
|
|
fn_create_node_t m_fnCreateNode{nullptr};
|
|
fn_update_node_t m_fnUpdateNode{nullptr};
|
|
fn_remove_node_t m_fnRemoveNode{nullptr};
|
|
fn_set_model_t m_fnSetModel{nullptr};
|
|
fn_set_texture_t m_fnSetTexture{nullptr};
|
|
fn_set_color_t m_fnSetColor{nullptr};
|
|
fn_set_dimensions_t m_fnSetDimensions{nullptr};
|
|
fn_set_entity_type_t m_fnSetEntityType{nullptr};
|
|
|
|
bool loadBridge();
|
|
};
|
|
|