OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
DisplayConfig.cpp
Go to the documentation of this file.
1 
11 // Copyright 2015 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 // Internal Includes
28 #include <osvr/Util/Verbosity.h>
30 
31 // Library/third-party includes
32 #include <osvr/Util/EigenExtras.h>
33 
34 // Standard includes
35 #include <stdexcept>
36 
37 namespace osvr {
38 namespace client {
41  inline static Viewport
42  computeViewport(uint8_t eye,
43  display_schema_1::DisplayDescriptor &descriptor) {
44  Viewport viewport;
45  // Set up the viewport based on the display resolution and the
46  // display configuration.
47  switch (descriptor.getDisplayMode()) {
48  case display_schema_1::DisplayDescriptor::FULL_SCREEN:
49  viewport.bottom = viewport.left = 0;
50  viewport.width = descriptor.getDisplayWidth();
51  viewport.height = descriptor.getDisplayHeight();
52  break;
53  case display_schema_1::DisplayDescriptor::HORIZONTAL_SIDE_BY_SIDE:
54  viewport.bottom = 0;
55  viewport.height = descriptor.getDisplayHeight();
56  viewport.width = descriptor.getDisplayWidth() / 2;
57  // Eye 0 starts at the left, eye 1 starts in the middle.
58  viewport.left = eye * viewport.width;
59  break;
60  case display_schema_1::DisplayDescriptor::VERTICAL_SIDE_BY_SIDE:
61  viewport.left = 0;
62  viewport.width = descriptor.getDisplayWidth();
63  viewport.height = descriptor.getDisplayHeight() / 2;
64  // Eye 0 in the top half, eye 1 at the bottom.
65  if (eye == 0) {
66  viewport.bottom = viewport.height;
67  } else {
68  viewport.bottom = 0;
69  }
70  break;
71  default:
72  throw std::logic_error("Unrecognized enum value for display mode");
73  }
74 
75  return viewport;
76  }
77 
78  inline static util::Rectd
79  computeRect(display_schema_1::DisplayDescriptor &descriptor) {
80  return util::computeSymmetricFOVRect(descriptor.getHorizontalFOV(),
81  descriptor.getVerticalFOV());
82  }
83 
84  static const char HEAD_PATH[] = "/me/head";
86  DisplayConfigPtr cfg(new DisplayConfig);
87  try {
88  auto const descriptorString = ctx->getStringParameter("/display");
89 
90  auto desc = display_schema_1::DisplayDescriptor(descriptorString);
91  cfg->m_viewers.container().emplace_back(Viewer(ctx, HEAD_PATH));
92  auto &viewer = cfg->m_viewers.container().front();
93  auto eyesDesc = desc.getEyes();
94 
96  std::vector<uint8_t> eyeIndices;
97  Eigen::Vector3d offset;
98  if (eyesDesc.size() == 2) {
99  // stereo
100  offset = desc.getIPDMeters() / 2. * Eigen::Vector3d::UnitX();
101  eyeIndices = {0, 1};
102  } else {
103  // if (eyesDesc.size() == 1)
104  // mono
105  offset = Eigen::Vector3d::Zero();
106  eyeIndices = {0};
107  }
108 
110  boost::optional<OSVR_RadialDistortionParameters> distort;
111  auto k1 = desc.getDistortion();
112  if (k1.k1_red != 0 || k1.k1_green != 0 || k1.k1_blue != 0) {
114  params.k1.data[0] = k1.k1_red;
115  params.k1.data[1] = k1.k1_green;
116  params.k1.data[2] = k1.k1_blue;
117  distort = params;
118  }
119 
121  util::Angle axisOffset = 0. * util::radians;
122  {
123  auto overlapPct = desc.getOverlapPercent();
124 
125  if (overlapPct < 1.) {
126  const auto hfov = desc.getHorizontalFOV();
127  const auto angularOverlap = hfov * overlapPct;
128  axisOffset = (hfov - angularOverlap) / 2.;
129  }
130  }
131 
134  std::vector<OSVR_DisplayInputCount> displayInputIndices;
135  if (eyesDesc.size() == 2 &&
136  display_schema_1::DisplayDescriptor::FULL_SCREEN ==
137  desc.getDisplayMode()) {
138  // two eyes, full screen - that means two screens.
139 
140  displayInputIndices = {0, 1};
141 
142  cfg->m_displayInputs.push_back(DisplayInput(
143  desc.getDisplayWidth(), desc.getDisplayHeight()));
144  cfg->m_displayInputs.push_back(DisplayInput(
145  desc.getDisplayWidth(), desc.getDisplayHeight()));
146  } else {
147  // everything else, assume 1 screen.
148  // Note that it's OK that displayInputIndices.size() >=
149  // eyesDesc.size(), we'll just not end up using the second
150  // entry.
151  displayInputIndices = {0, 0};
152 
153  cfg->m_displayInputs.push_back(DisplayInput(
154  desc.getDisplayWidth(), desc.getDisplayHeight()));
155  }
156  BOOST_ASSERT_MSG(displayInputIndices.size() >= eyesDesc.size(),
157  "Must have at least as many indices as eyes");
158 
160  for (auto eye : eyeIndices) {
161  // This little computation turns 0 into -1 and 1 into 1, used as
162  // a coefficient to make the two eyes do opposite things.
163  // Doesn't affect mono, which has a zero offset vector.
164  double offsetFactor = (2. * eye) - 1.;
165 
166  // Set up per-eye distortion parameters, if needed
167  boost::optional<OSVR_RadialDistortionParameters> distortEye(
168  distort);
169  if (distortEye) {
170  distortEye->centerOfProjection.data[0] =
171  eyesDesc[eye].m_CenterProjX;
172  distortEye->centerOfProjection.data[1] =
173  eyesDesc[eye].m_CenterProjY;
174  }
175 
176  // precompute translation offset for this eye
177  auto xlateOffset = (offsetFactor * offset).eval();
178 
179  // precompute the optical axis rotation for this eye
180  // here, the left eye should get a positive offset since it's a
181  // positive rotation about y, hence the -1 factor.
182  auto eyeAxisOffset = axisOffset * -1. * offsetFactor;
183 
184  // Look up the display index for this eye.
185  auto displayInputIdx = displayInputIndices[eye];
186 
188  viewer.container().emplace_back(ViewerEye(
189  ctx, xlateOffset, HEAD_PATH, computeViewport(eye, desc),
190  computeRect(desc), eyesDesc[eye].m_rotate180,
191  desc.getPitchTilt().value(), distortEye, displayInputIdx,
192  eyeAxisOffset));
193  }
194 
195  OSVR_DEV_VERBOSE("Display: " << desc.getHumanReadableDescription());
196  return cfg;
197  } catch (std::exception const &e) {
198  OSVR_DEV_VERBOSE(
199  "Couldn't create a display config internally! Exception: "
200  << e.what());
201  return DisplayConfigPtr{};
202  } catch (...) {
203  OSVR_DEV_VERBOSE("Couldn't create a display config internally! "
204  "Unknown exception!");
205  return DisplayConfigPtr{};
206  }
207  }
208  DisplayConfig::DisplayConfig() {}
209 
210  bool DisplayConfig::isStartupComplete() const {
211  for (auto const &viewer : m_viewers) {
212  if (!viewer.hasPose()) {
213  return false;
214  }
215  for (auto const &eye : viewer) {
216  if (!eye.hasPose()) {
217  return false;
218  }
219  }
220  }
221  return true;
222  }
223 
224 } // namespace client
225 } // namespace osvr
AngleRadiansd Angle
Default angle type.
Definition: Angles.h:63
Parameters for a per-color-component radial distortion shader.
OSVR_Vec3 k1
Vector of K1 coefficients for the R, G, B channels.
std::string getStringParameter(std::string const &path) const
Gets a string parameter value.
double data[3]
Internal array data.
Definition: Vec3C.h:50
Rectd computeSymmetricFOVRect(AngleGeneric< System > hFov, AngleGeneric< System > vFov)
Compute a rectangle at unit distance for the given fov values.
static DisplayConfigPtr create(OSVR_ClientContext ctx)
Internal, configured header file for verbosity macros.