bool PureClientContext::m_connectCallbacksOnPath(std::string const &path) { /// Start by removing handler from interface tree and handler container /// for this path, if found. Ensures that if we early-out (fail to set /// up a handler) we don't have a leftover one still active. m_interfaces.eraseHandlerForPath(path); auto source = common::resolveTreeNode(m_pathTree, path); if (!source.is_initialized()) { OSVR_DEV_VERBOSE("Could not resolve source for " << path); return false; } auto handler = m_factory.invokeFactory( *source, m_interfaces.getInterfacesForPath(path), *this); if (handler) { OSVR_DEV_VERBOSE("Successfully produced handler for " << path); // Store the new handler in the interface tree auto oldHandler = m_interfaces.replaceHandlerForPath(path, handler); BOOST_ASSERT_MSG( !oldHandler, "We removed the old handler before so it should be null now"); return true; } OSVR_DEV_VERBOSE("Could not produce handler for " << path); return false; }
OSVR_ReturnCode osvrClientGetSkeletonBoneName(OSVR_Skeleton skel, OSVR_SkeletonBoneCount boneId, char *boneName, uint32_t len) { OSVR_VALIDATE_SKELETON_CONFIG; OSVR_VALIDATE_OUTPUT_PTR(boneName, "bone name"); try { auto name = skel->getBoneName(boneId); if (name.size() + 1 > len) { /// buffer too small return OSVR_RETURN_FAILURE; } // this line pops warning 4996 on VS compiler, disabled above name.copy(boneName, name.size()); boneName[name.size()] = '\0'; } catch (osvr::client::IdNotFound &) { OSVR_DEV_VERBOSE( "Error getting name for provided boneId : Id not found"); return OSVR_RETURN_FAILURE; } catch (std::exception &e) { OSVR_DEV_VERBOSE( "Error getting name for provided boneId : " << e.what()); return OSVR_RETURN_FAILURE; } return OSVR_RETURN_SUCCESS; }
OSVR_ReturnCode osvrAnalysisSyncInit(OSVR_IN_PTR OSVR_PluginRegContext ctx, OSVR_IN_STRZ const char *name, OSVR_IN_PTR OSVR_DeviceInitOptions options, OSVR_OUT_PTR OSVR_DeviceToken *device, OSVR_OUT_PTR OSVR_ClientContext *clientCtx) { if (!ctx) { OSVR_DEV_VERBOSE("osvrAnalysisSyncInit: can't use a null plugin " "registration context."); return OSVR_RETURN_FAILURE; } if (!name || !(name[0])) { OSVR_DEV_VERBOSE( "osvrAnalysisSyncInit: can't use a null or empty device name."); return OSVR_RETURN_FAILURE; } OSVR_VALIDATE_OUTPUT_PTR(device, "device token"); OSVR_VALIDATE_OUTPUT_PTR(clientCtx, "client context"); auto initialResult = osvrDeviceSyncInitWithOptions(ctx, name, options, device); if (initialResult == OSVR_RETURN_FAILURE) { OSVR_DEV_VERBOSE( "osvrAnalysisSyncInit: couldn't create initial device token."); return OSVR_RETURN_FAILURE; } /// Dig the VRPN connection out of the server. auto osvrConn = osvr::connection::Connection::retrieveConnection( osvr::pluginhost::PluginSpecificRegistrationContext::get(ctx) .getParent()); auto vrpnConn = extractVrpnConnection(*osvrConn); /// Create a client context here /// @todo Use an interface factory that handles relative paths. auto clientCtxSmart = osvr::common::wrapSharedContext( osvr::client::createAnalysisClientContext( "org.osvr.analysisplugin" /**< @todo */, "localhost" /**< @todo */, vrpn_ConnectionPtr(vrpnConn))); auto &dev = **device; /// pass ownership dev.acquireObject(clientCtxSmart); /// register client context update dev.setPreConnectionInteract([=] { clientCtxSmart->update(); }); /// finally return the client context too. *clientCtx = clientCtxSmart.get(); return OSVR_RETURN_SUCCESS; }
bool addAlias(PathNode &node, std::string const &source, AliasPriority priority) { ParsedAlias newSource(source); if (!newSource.isValid()) { /// @todo signify invalid route in some other way? OSVR_DEV_VERBOSE("Could not parse source: " << source); return false; } if (!isPathAbsolute(newSource.getLeaf())) { /// @todo signify not to pass relative paths here in some other way? OSVR_DEV_VERBOSE( "Source contains a relative path, not permitted: " << source); return false; } return addAliasImpl(node, newSource.getAlias(), priority); }
void ParsedAlias::m_parse(Json::Value &val) { if (val.isString()) { // Assume a string is just a string. m_value = val; return; } if (val.isObject()) { if (val.isMember(SOURCE_KEY)) { // Strip any initial "source" level m_parse(val[SOURCE_KEY]); return; } // Assume an object means a transform. m_simple = false; m_value = val; auto &leaf = m_leaf(); if (leaf.isString()) { return; } auto trackerEquiv = getPathFromOldRouteSource(leaf); if (!trackerEquiv.empty()) { leaf = trackerEquiv; return; } OSVR_DEV_VERBOSE( "Couldn't handle transform leaf: " << leaf.toStyledString()); } m_value = Json::nullValue; /// @todo finish by throwing? }
bool ServerImpl::loop() { bool shouldContinue; { /// @todo More elegant way of running queued things than grabbing a /// mutex each time through? boost::unique_lock<boost::mutex> lock(m_mainThreadMutex); m_conn->process(); if (m_treeDirty) { OSVR_DEV_VERBOSE("Path tree updated"); m_sendTree(); m_treeDirty.reset(); } m_systemDevice->update(); for (auto &f : m_mainloopMethods) { f(); } shouldContinue = m_run.shouldContinue(); } if (m_sleepTime > 0) { osvr::util::time::microsleep(m_sleepTime); } else { m_thread.yield(); } return shouldContinue; }
AnalysisClientContext::AnalysisClientContext( const char appId[], const char host[], vrpn_ConnectionPtr const &conn, common::ClientContextDeleter del) : ::OSVR_ClientContextObject(appId, del), m_mainConn(conn), m_ifaceMgr(m_pathTreeOwner, m_factory, *static_cast<common::ClientContext *>(this)) { /// Create all the remote handler factories. populateRemoteHandlerFactory(m_factory, m_vrpnConns); m_vrpnConns.addConnection(m_mainConn, "localhost"); m_vrpnConns.addConnection(m_mainConn, host); std::string sysDeviceName = std::string(common::SystemComponent::deviceName()) + "@" + host; m_mainConn = m_vrpnConns.getConnection( common::SystemComponent::deviceName(), host); /// Create the system client device. m_systemDevice = common::createClientDevice(sysDeviceName, m_mainConn); m_systemComponent = m_systemDevice->addComponent(common::SystemComponent::create()); using DedupJsonFunction = common::DeduplicatingFunctionWrapper<Json::Value const &>; m_systemComponent->registerReplaceTreeHandler( DedupJsonFunction([&](Json::Value nodes) { OSVR_DEV_VERBOSE("Got updated path tree, processing"); // Tree observers will handle destruction/creation of remote // handlers. m_pathTreeOwner.replaceTree(nodes); })); // No startup spin. }
RenderManagerConfigPtr RenderManagerConfigFactory::createShared(OSVR_ClientContext ctx) { try { auto const configString = ctx->getStringParameter("/renderManagerConfig"); RenderManagerConfigPtr cfg(new RenderManagerConfig(configString)); return cfg; } catch (std::exception const &e) { OSVR_DEV_VERBOSE( "Couldn't create a render manager config internally! Exception: " << e.what()); return RenderManagerConfigPtr{}; } catch (...) { OSVR_DEV_VERBOSE("Couldn't create a render manager config internally! " "Unknown exception!"); return RenderManagerConfigPtr{}; } }
OSVR_ReturnCode osvrClientGetSkeletonStringBoneNameLength( OSVR_Skeleton skel, OSVR_SkeletonBoneCount boneId, uint32_t *len) { OSVR_VALIDATE_SKELETON_CONFIG; OSVR_VALIDATE_OUTPUT_PTR(len, "name length"); try { auto boneName = skel->getBoneName(boneId); *len = static_cast<uint32_t>(boneName.empty() ? 0 : (boneName.size() + 1)); } catch (osvr::client::IdNotFound &) { OSVR_DEV_VERBOSE( "Error getting name for provided boneId : Id not found"); return OSVR_RETURN_FAILURE; } catch (std::exception &e) { OSVR_DEV_VERBOSE( "Error getting name for provided boneId : " << e.what()); return OSVR_RETURN_FAILURE; } return OSVR_RETURN_SUCCESS; }
OSVR_ReturnCode osvrClientGetSkeletonBoneId(OSVR_Skeleton skel, const char *boneName, OSVR_SkeletonBoneCount *boneId) { OSVR_VALIDATE_SKELETON_CONFIG; OSVR_VALIDATE_OUTPUT_PTR(boneId, "bone Id"); if (!skel->getBoneId(boneName, boneId)) { OSVR_DEV_VERBOSE("Error getting boneId for " << boneName); return OSVR_RETURN_FAILURE; } return OSVR_RETURN_SUCCESS; }
OSVR_ReturnCode osvrClientGetSkeletonJointState(OSVR_Skeleton skel, OSVR_SkeletonJointCount jointId, OSVR_SkeletonJointState *state) { OSVR_VALIDATE_SKELETON_CONFIG; OSVR_VALIDATE_OUTPUT_PTR(state, "joint state"); try { OSVR_Pose3 pose = skel->getJointState(jointId); state->jointId = jointId; state->pose = pose; } catch (osvr::client::NoPoseYet &) { OSVR_DEV_VERBOSE("Error getting pose for joint: no pose yet available"); return OSVR_RETURN_FAILURE; } catch (std::exception &e) { OSVR_DEV_VERBOSE("Error getting joint pose - exception: " << e.what()); return OSVR_RETURN_FAILURE; } return OSVR_RETURN_SUCCESS; }
OSVR_ReturnCode osvrClientGetSkeletonJointId(OSVR_Skeleton skel, const char *jointName, OSVR_SkeletonJointCount *jointId) { OSVR_VALIDATE_SKELETON_CONFIG; OSVR_VALIDATE_OUTPUT_PTR(jointId, "joint Id"); if (!skel->getJointId(jointName, jointId)) { OSVR_DEV_VERBOSE("Error getting jointId for " << jointName); return OSVR_RETURN_FAILURE; } return OSVR_RETURN_SUCCESS; }
void VrpnBasedConnection::m_initConnection(const char iface[], int port) { if (!m_network.isUp()) { OSVR_DEV_VERBOSE("Network error: " << m_network.getError()); throw std::runtime_error(m_network.getError()); } if (0 == port) { port = vrpn_DEFAULT_LISTEN_PORT_NO; } m_vrpnConnection = vrpn_ConnectionPtr::create_server_connection( port, nullptr, nullptr, iface); }
OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetSkeletonAvailableJointId( OSVR_Skeleton skel, OSVR_SkeletonJointCount jointIndex, OSVR_SkeletonJointCount *jointId) { OSVR_VALIDATE_SKELETON_CONFIG; OSVR_VALIDATE_OUTPUT_PTR(jointId, "joint Id"); if (!skel->getAvailableJointId(jointIndex, jointId)) { OSVR_DEV_VERBOSE("ERROR getting the jointId for jointIndex " << jointIndex); return OSVR_RETURN_FAILURE; } return OSVR_RETURN_SUCCESS; }
VRPNAnalogHandler(vrpn_ConnectionPtr const &conn, const char *src, boost::optional<int> sensor, common::InterfaceList &ifaces) : m_remote(new vrpn_Analog_Remote(src, conn.get())), m_interfaces(ifaces), m_all(!sensor.is_initialized()) { m_remote->register_change_handler(this, &VRPNAnalogHandler::handle); OSVR_DEV_VERBOSE("Constructed an AnalogHandler for " << src); if (sensor.is_initialized()) { m_sensors.setValue(*sensor); } }
OSVR_CLIENTKIT_EXPORT OSVR_ReturnCode osvrClientGetSkeletonAvailableBoneId( OSVR_Skeleton skel, OSVR_SkeletonBoneCount boneIndex, OSVR_SkeletonBoneCount *boneId) { OSVR_VALIDATE_SKELETON_CONFIG; OSVR_VALIDATE_OUTPUT_PTR(boneId, "bone Id"); if (!skel->getAvailableBoneId(boneIndex, boneId)) { OSVR_DEV_VERBOSE("ERROR getting the boneId for boneIndex " << boneIndex); return OSVR_RETURN_FAILURE; } return OSVR_RETURN_SUCCESS; }
void ServerImpl::m_handleDeviceDescriptors() { for (auto const &dev : m_conn->getDevices()) { auto const &descriptor = dev->getDeviceDescriptor(); if (descriptor.empty()) { OSVR_DEV_VERBOSE("Developer Warning: No device descriptor for " << dev->getName()); } else { m_treeDirty += common::processDeviceDescriptorForPathTree( m_tree, dev->getName(), descriptor); } } }
void JointClientContext::m_handleReplaceTree(Json::Value const &nodes) { OSVR_DEV_VERBOSE("Got updated path tree, processing"); // reset path tree m_pathTree.reset(); // wipe out handlers in the interface tree m_interfaces.clearHandlers(); // populate path tree from message common::jsonToPathTree(m_pathTree, nodes); // re-connect handlers. m_connectNeededCallbacks(); }
/// @brief Handle an alias element void operator()(elements::AliasElement const &elt) { // This is an alias. ParsedAlias parsed(elt.getSource()); if (!parsed.isValid()) { OSVR_DEV_VERBOSE("Couldn't parse alias: " << elt.getSource()); return; } /// @todo update the element with the normalized source? if (!parsed.isSimple()) { // Not simple: store the full string as a transform. m_source.nestTransform(parsed.getAliasValue()); } m_recurse(parsed.getLeaf()); }
void PureClientContext::m_update() { /// Mainloop connections m_vrpnConns.updateAll(); if (!m_gotConnection && m_mainConn->connected()) { OSVR_DEV_VERBOSE("Got connection to main OSVR server"); m_gotConnection = true; } /// Update system device m_systemDevice->update(); /// Update handlers. m_interfaces.updateHandlers(); }
bool addAliasFromSourceAndRelativeDest(PathNode &node, std::string const &source, std::string const &dest, AliasPriority priority) { auto &aliasNode = treePathRetrieve(node, dest); ParsedAlias newSource(source); if (!newSource.isValid()) { /// @todo signify invalid route in some other way? OSVR_DEV_VERBOSE("Could not parse source: " << source); return false; } auto absSource = getAbsolutePath(node, newSource.getLeaf()); newSource.setLeaf(absSource); return addAliasImpl(aliasNode, newSource.getAlias(), priority); }
NetworkDirectionRemoteHandler(vrpn_ConnectionPtr const &conn, std::string const &deviceName, boost::optional<OSVR_ChannelCount> sensor, common::InterfaceList &ifaces) : m_dev(common::createClientDevice(deviceName, conn)), m_internals(ifaces), m_all(!sensor.is_initialized()), m_sensor(sensor) { auto direction = common::DirectionComponent::create(); m_dev->addComponent(direction); direction->registerDirectionHandler( [&](common::DirectionData const &data, util::time::TimeValue const ×tamp) { m_handleDirection(data, timestamp); }); OSVR_DEV_VERBOSE("Constructed an Direction Handler for " << deviceName); }
shared_ptr<RemoteHandler> ButtonRemoteFactory:: operator()(common::OriginalSource const &source, common::InterfaceList &ifaces, common::ClientContext &) { shared_ptr<RemoteHandler> ret; if (source.hasTransform()) { OSVR_DEV_VERBOSE( "Ignoring transform found on route for Button data!"); } auto const &devElt = source.getDeviceElement(); /// @todo find out why make_shared causes a crash here ret.reset(new VRPNButtonHandler(m_conns.getConnection(devElt), devElt.getFullDeviceName().c_str(), source.getSensorNumber(), ifaces)); return ret; }
JointClientContext::JointClientContext(const char appId[], common::ClientContextDeleter del) : ::OSVR_ClientContextObject(appId, del), m_ifaceMgr(m_pathTreeOwner, m_factory, *static_cast<common::ClientContext *>(this)) { /// Create all the remote handler factories. populateRemoteHandlerFactory(m_factory, m_vrpnConns); /// creates the OSVR connection with its nested VRPN connection auto conn = connection::Connection::createLoopbackConnection(); /// Get the VRPN connection out and use it. m_mainConn = static_cast<vrpn_Connection *>(std::get<0>(conn)); m_vrpnConns.addConnection(m_mainConn, HOST); BOOST_ASSERT(!m_vrpnConns.empty()); /// Get the OSVR connection out and use it to make a server. m_server = server::Server::createNonListening(std::get<1>(conn)); std::string sysDeviceName = std::string(common::SystemComponent::deviceName()) + "@" + HOST; /// Create the system client device. m_systemDevice = common::createClientDevice(sysDeviceName, m_mainConn); m_systemComponent = m_systemDevice->addComponent(common::SystemComponent::create()); typedef common::DeduplicatingFunctionWrapper<Json::Value const &> DedupJsonFunction; using DedupJsonFunction = common::DeduplicatingFunctionWrapper<Json::Value const &>; m_systemComponent->registerReplaceTreeHandler( DedupJsonFunction([&](Json::Value nodes) { OSVR_DEV_VERBOSE("Got updated path tree, processing"); // Tree observers will handle destruction/creation of remote // handlers. m_pathTreeOwner.replaceTree(nodes); })); }
shared_ptr<RemoteHandler> ImagingRemoteFactory:: operator()(common::OriginalSource const &source, common::InterfaceList &ifaces, common::ClientContext &) { shared_ptr<RemoteHandler> ret; if (source.hasTransform()) { OSVR_DEV_VERBOSE( "Ignoring transform found on route for Imaging data!"); } /// @todo This is where we'd take a different path for IPC imaging data. auto const &devElt = source.getDeviceElement(); /// @todo find out why make_shared causes a crash here ret.reset(new NetworkImagingRemoteHandler( m_conns.getConnection(devElt), devElt.getFullDeviceName(), source.getSensorNumberAsChannelCount(), ifaces)); return ret; }
void PureClientContext::m_connectNeededCallbacks() { std::unordered_set<std::string> failedPaths; size_t successfulPaths{0}; for (auto const &iface : getInterfaces()) { /// @todo slightly overkill, but it works - tree traversal would be /// better. auto path = iface->getPath(); /// For every interface, if there's no handler at that path on the /// interface tree, try to set one up. if (!m_interfaces.getHandlerForPath(path)) { auto success = m_connectCallbacksOnPath(path); if (success) { successfulPaths++; } else { failedPaths.insert(path); } } } OSVR_DEV_VERBOSE("Connected " << successfulPaths << " of " << successfulPaths + failedPaths.size() << " unconnected paths successfully"); }
void PureClientContext::m_handleReplaceTree(Json::Value const &nodes) { m_gotTree = true; OSVR_DEV_VERBOSE("Got updated path tree, processing"); // reset path tree m_pathTree.reset(); // wipe out handlers in the interface tree m_interfaces.clearHandlers(); // populate path tree from message common::jsonToPathTree(m_pathTree, nodes); // replace the @localhost with the correct host name // in case we are a remote client, otherwise the connection // would fail LocalhostReplacer replacer(m_host); util::traverseWith(m_pathTree.getRoot(), [&replacer](osvr::common::PathNode &node) { common::applyPathNodeVisitor(replacer, node); }); // re-connect handlers. m_connectNeededCallbacks(); }
void DisplayDescriptor::m_processResolution(Json::Value const &resolution) { // if there is more than 1 input, display descriptor right now // specifies one resolution value for both inputs. that may be // changed in the future Resolution res; res.video_inputs = resolution.get("video_inputs", 1).asInt(); // Window bounds res.width = resolution["width"].asInt(); res.height = resolution["height"].asInt(); // Display mode - Default to horiz side by side unless we have // multiple video inputs, then default to full screen (? seems // logical but not strictly what the json schema specifies) res.display_mode = (res.video_inputs > 1 ? FULL_SCREEN : HORIZONTAL_SIDE_BY_SIDE); auto const &display_mode = resolution["display_mode"]; if (display_mode.isString()) { const std::string display_mode_str = display_mode.asString(); if ("horz_side_by_side" == display_mode_str) { res.display_mode = HORIZONTAL_SIDE_BY_SIDE; } else if ("vert_side_by_side" == display_mode_str) { res.display_mode = VERTICAL_SIDE_BY_SIDE; } else if ("full_screen" == display_mode_str) { res.display_mode = FULL_SCREEN; } else { OSVR_DEV_VERBOSE("DisplayDescriptor::parse(): WARNING: " "Unknown display mode string: " << display_mode_str << " (using default)"); } } m_resolutions.push_back(res); }
PureClientContext::PureClientContext(const char appId[], const char host[], common::ClientContextDeleter del) : ::OSVR_ClientContextObject(appId, del), m_host(host) { if (!m_network.isUp()) { throw std::runtime_error("Network error: " + m_network.getError()); } /// Create all the remote handler factories. populateRemoteHandlerFactory(m_factory, m_vrpnConns); std::string sysDeviceName = std::string(common::SystemComponent::deviceName()) + "@" + host; m_mainConn = m_vrpnConns.getConnection( common::SystemComponent::deviceName(), host); /// Create the system client device. m_systemDevice = common::createClientDevice(sysDeviceName, m_mainConn); m_systemComponent = m_systemDevice->addComponent(common::SystemComponent::create()); #define OSVR_USE_DEDUP #ifdef OSVR_USE_DEDUP typedef common::DeduplicatingFunctionWrapper<Json::Value const &> DedupJsonFunction; m_systemComponent->registerReplaceTreeHandler(DedupJsonFunction( [&](Json::Value const &nodes) { m_handleReplaceTree(nodes); })); #else // Just for testing purposes, figuring out why we end up looping too // much. m_systemComponent->registerReplaceTreeHandler( [&](Json::Value const &nodes, util::time::TimeValue const &) { m_handleReplaceTree(nodes); }); #endif typedef std::chrono::system_clock clock; auto begin = clock::now(); // Spin the update to get a connection auto connEnd = begin + STARTUP_CONNECT_TIMEOUT; while (clock::now() < connEnd && !m_gotConnection) { m_update(); std::this_thread::sleep_for(STARTUP_LOOP_SLEEP); } if (!m_gotConnection) { OSVR_DEV_VERBOSE( "Could not connect to OSVR server in the timeout period " "allotted of " << std::chrono::duration_cast<std::chrono::milliseconds>( STARTUP_CONNECT_TIMEOUT) .count() << "ms"); return; // Bail early if we don't even have a connection } // Spin the update to get a path tree auto treeEnd = begin + STARTUP_TREE_TIMEOUT; while (clock::now() < treeEnd && !m_gotTree) { m_update(); std::this_thread::sleep_for(STARTUP_LOOP_SLEEP); } auto timeToStartup = (clock::now() - begin); OSVR_DEV_VERBOSE( "Connection process took " << std::chrono::duration_cast<std::chrono::milliseconds>( timeToStartup) .count() << "ms: " << (m_gotConnection ? "have connection to server, " : "don't have connection to server, ") << (m_gotTree ? "have path tree" : "don't have path tree")); }
void DisplayDescriptor::parse(const std::string &display_description) { auto root = common::jsonParse(display_description); auto const &hmd = root["hmd"]; { auto const &fov = hmd["field_of_view"]; // Field of view m_monocularHorizontalFOV = util::Angle( fov["monocular_horizontal"].asDouble() * util::degrees); m_monocularVerticalFOV = util::Angle( fov["monocular_vertical"].asDouble() * util::degrees); m_overlapPercent = fov.get("overlap_percent", 100).asDouble() / 100.0; m_pitchTilt = util::Angle(fov.get("pitch_tilt", 0).asDouble() * util::degrees); } { auto const &devprops = hmd["device"]; // Device properties m_vendor = devprops["vendor"].asString(); m_model = devprops["model"].asString(); m_version = devprops["Version"].asString(); m_note = devprops["Note"].asString(); } { auto const &resolutions = hmd["resolutions"]; if (resolutions.isNull()) { OSVR_DEV_VERBOSE( "DisplayDescriptor::parse(): ERROR: Couldn't " "find resolutions array!"); throw DisplayDescriptorParseException( "Couldn't find resolutions array."); } for (auto const &resolution : resolutions) { m_processResolution(resolution); } if (m_resolutions.empty()) { // We couldn't find any appropriate resolution entries OSVR_DEV_VERBOSE( "DisplayDescriptor::parse(): ERROR: Couldn't " "find any appropriate resolutions."); return; } } { auto const &rendering = hmd["rendering"]; m_rightRoll = rendering.get("right_roll", 0).asDouble(); m_leftRoll = rendering.get("left_roll", 0).asDouble(); } { auto const &distortion = hmd["distortion"]; m_distort.k1_red = distortion.get("k1_red", 0).asDouble(); m_distort.k1_green = distortion.get("k1_green", 0).asDouble(); m_distort.k1_blue = distortion.get("k1_blue", 0).asDouble(); } { auto const &eyes = hmd["eyes"]; if (eyes.isNull()) { OSVR_DEV_VERBOSE("DisplayDescriptor::parse(): ERROR: " "Couldn't find eyes array!"); throw DisplayDescriptorParseException( "Couldn't find eyes array."); } for (auto const &eye : eyes) { EyeInfo e; e.m_CenterProjX = eye.get("center_proj_x", 0.5).asDouble(); e.m_CenterProjY = eye.get("center_proj_y", 0.5).asDouble(); if (eye.isMember("rotate_180")) { auto const& rot = eye["rotate_180"]; if (rot.isBool()) { e.m_rotate180 = rot.asBool(); } else { e.m_rotate180 = (rot.asInt() != 0); } } m_eyes.push_back(e); } } }