1
/**************************************************************************
2
* Copyright (c) 2014 Bastiaan Veelo <Bastiaan a_t Veelo d_o_t net> *
3
* Copyright (c) 2014 Jürgen Riegel <FreeCAD@juergen-riegel.net> *
5
* All rights reserved. Contact me if the below is too restrictive for you.*
7
* Redistribution and use in source and binary forms, with or without *
8
* modification, are permitted provided that the following conditions are *
11
* Redistributions of source code must retain the above copyright notice, *
12
* this list of conditions and the following disclaimer. *
14
* Redistributions in binary form must reproduce the above copyright *
15
* notice, this list of conditions and the following disclaimer in the *
16
* documentation and/or other materials provided with the distribution. *
18
* Neither the name of the copyright holder nor the names of its *
19
* contributors may be used to endorse or promote products derived from *
20
* this software without specific prior written permission. *
22
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
23
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
24
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR *
25
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT *
26
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
27
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
28
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
29
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
30
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
31
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE *
32
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
33
\**************************************************************************/
35
#include "PreCompiled.h"
36
#include "CoinRiftWidget.h"
38
#include <Base/Console.h>
49
CoinRiftWidget::CoinRiftWidget() : QGLWidget()
51
for (int eye = 0; eye < 2; eye++) {
52
reinterpret_cast<ovrGLTextureData*>(&eyeTexture[eye])->TexId = 0;
54
frameBufferID[eye] = 0;
55
depthBufferID[eye] = 0;
59
// OVR will do the swapping.
60
setAutoBufferSwap(false);
62
hmd = ovrHmd_Create(0);
64
qDebug() << "Could not find Rift device.";
68
if (!ovrHmd_ConfigureTracking (hmd, ovrTrackingCap_Orientation |
69
ovrTrackingCap_MagYawCorrection |
70
ovrTrackingCap_Position,
71
ovrTrackingCap_Orientation |
72
ovrTrackingCap_MagYawCorrection |
73
ovrTrackingCap_Position
74
)) { // Capabilities we require.
75
qDebug() << "Could not start Rift motion sensor.";
79
resize(hmd->Resolution.w, hmd->Resolution.h);
81
// Configure stereo settings.
82
ovrSizei recommenedTex0Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left,
83
hmd->DefaultEyeFov[0], 1.0f);
84
ovrSizei recommenedTex1Size = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right,
85
hmd->DefaultEyeFov[1], 1.0f);
87
#ifdef USE_SO_OFFSCREEN_RENDERER
88
renderer = new SoOffscreenRenderer(SbViewportRegion(std::max(recommenedTex0Size.w, recommenedTex0Size.w),
89
std::max(recommenedTex1Size.h, recommenedTex1Size.h)));
90
renderer->setComponents(SoOffscreenRenderer::RGB_TRANSPARENCY);
91
BackgroundColor = SbColor(.0f, .0f, .8f);
92
renderer->setBackgroundColor(BackgroundColor);
95
m_sceneManager = new SoSceneManager();
96
m_sceneManager->setViewportRegion(SbViewportRegion(std::max(recommenedTex0Size.w, recommenedTex0Size.w),
97
std::max(recommenedTex1Size.h, recommenedTex1Size.h)));
98
m_sceneManager->setBackgroundColor(SbColor(.0f, .0f, .8f));
100
basePosition = SbVec3f(0.0f, 0.0f, -2.0f);
103
SoDirectionalLight *light = new SoDirectionalLight();
104
light->direction.setValue(1,-1,-1);
106
SoDirectionalLight *light2 = new SoDirectionalLight();
107
light2->direction.setValue(-1,-1,-1);
108
light2->intensity.setValue(0.6);
109
light2->color.setValue(0.8,0.8,1);
112
scene = new SoSeparator(0); // Placeholder.
113
for (int eye = 0; eye < 2; eye++) {
114
rootScene[eye] = new SoSeparator();
115
rootScene[eye]->ref();
116
camera[eye] = new SoFrustumCamera();
117
camera[eye]->position.setValue(basePosition);
118
camera[eye]->focalDistance.setValue(5.0f);
119
camera[eye]->viewportMapping.setValue(SoCamera::LEAVE_ALONE);
120
rootScene[eye]->addChild(camera[eye]);
121
rootScene[eye]->addChild(light);
122
rootScene[eye]->addChild(light2);
123
rootScene[eye]->addChild(scene);
126
// Populate ovrEyeDesc[2].
127
eyeRenderDesc[0].Eye = ovrEye_Left;
128
eyeRenderDesc[1].Eye = ovrEye_Right;
129
eyeRenderDesc[0].Fov = hmd->DefaultEyeFov[0];
130
eyeRenderDesc[1].Fov = hmd->DefaultEyeFov[1];
131
#ifdef USE_SO_OFFSCREEN_RENDERER
132
eyeTexture[0].Header.TextureSize.w = renderer->getViewportRegion().getViewportSizePixels().getValue()[0];
133
eyeTexture[0].Header.TextureSize.h = renderer->getViewportRegion().getViewportSizePixels().getValue()[1];
134
eyeTexture[1].Header.TextureSize = eyeTexture[0].Header.TextureSize;
136
#ifdef USE_FRAMEBUFFER
137
eyeTexture[0].Header.TextureSize = recommenedTex0Size;
138
eyeTexture[1].Header.TextureSize = recommenedTex1Size;
140
eyeTexture[0].Header.RenderViewport.Pos.x = 0;
141
eyeTexture[0].Header.RenderViewport.Pos.y = 0;
142
eyeTexture[0].Header.RenderViewport.Size = eyeTexture[0].Header.TextureSize;
143
eyeTexture[1].Header.RenderViewport.Pos = eyeTexture[0].Header.RenderViewport.Pos;
144
eyeTexture[1].Header.RenderViewport.Size = eyeTexture[1].Header.TextureSize;
146
const int backBufferMultisample = 0; // TODO This is a guess?
148
cfg.OGL.Header.API = ovrRenderAPI_OpenGL;
149
cfg.OGL.Header.RTSize = hmd->Resolution;
150
cfg.OGL.Header.Multisample = backBufferMultisample;
151
cfg.OGL.Window = reinterpret_cast<HWND>(winId());
153
//cfg.OGL.WglContext = wglGetCurrentContext(); // http://stackoverflow.com/questions/17532033/qglwidget-get-gl-contextes-for-windows
154
cfg.OGL.DC = wglGetCurrentDC();
155
qDebug() << "Window:" << cfg.OGL.Window;
156
//qDebug() << "Context:" << cfg.OGL.WglContext;
157
qDebug() << "DC:" << cfg.OGL.DC;
159
int DistortionCaps = 0;
160
DistortionCaps |= ovrDistortionCap_Chromatic;
161
// DistortionCaps |= ovrDistortionCap_TimeWarp; // Produces black screen...
162
DistortionCaps |= ovrDistortionCap_Vignette;
163
DistortionCaps |= ovrDistortionCap_HqDistortion;
165
bool VSyncEnabled(false); // TODO This is a guess.
166
if (!ovrHmd_ConfigureRendering( hmd,
168
/*(VSyncEnabled ? 0 : ovrHmdCap_NoVSync),*/
170
hmd->DefaultEyeFov,//eyes,
172
qDebug() << "Could not configure OVR rendering.";
175
static const float nearPlane = 0.01;
177
for (int eye = 0; eye < 2; eye++) {
178
camera[eye]->aspectRatio.setValue((eyeRenderDesc[eye].Fov.LeftTan + eyeRenderDesc[eye].Fov.RightTan) /
179
(eyeRenderDesc[eye].Fov.UpTan + eyeRenderDesc[eye].Fov.DownTan));
180
camera[eye]->nearDistance.setValue(nearPlane);
181
camera[eye]->farDistance.setValue(10000.0f);
182
camera[eye]->left.setValue(-eyeRenderDesc[eye].Fov.LeftTan * nearPlane);
183
camera[eye]->right.setValue(eyeRenderDesc[eye].Fov.RightTan * nearPlane);
184
camera[eye]->top.setValue(eyeRenderDesc[eye].Fov.UpTan * nearPlane);
185
camera[eye]->bottom.setValue(-eyeRenderDesc[eye].Fov.DownTan * nearPlane);
190
CoinRiftWidget::~CoinRiftWidget()
192
#ifdef USE_SO_OFFSCREEN_RENDERER
195
for (int eye = 0; eye < 2; eye++) {
196
rootScene[eye]->unref();
197
ovrGLTextureData *texData = reinterpret_cast<ovrGLTextureData*>(&eyeTexture[eye]);
198
if (texData->TexId) {
199
glDeleteTextures(1, &texData->TexId);
202
#ifdef USE_FRAMEBUFFER
203
if (frameBufferID[eye] != 0) {
204
// OVR::CAPI::GL::glDeleteFramebuffersExt(1, &frameBufferID[eye]); // TODO
205
frameBufferID[eye] = 0;
207
if (depthBufferID[eye] != 0) {
208
// OVR::CAPI::GL::glDeleteRenderbuffersExt(1, &depthBufferID[eye]); // TODO
209
depthBufferID[eye] = 0;
214
//ovrHmd_StopSensor(hmd);
219
void CoinRiftWidget::setBackgroundColor(const SbColor &Col)
221
BackgroundColor = Col;
222
renderer->setBackgroundColor(BackgroundColor);
226
void CoinRiftWidget::setSceneGraph(SoNode *sceneGraph)
228
rootScene[0]->replaceChild(scene, sceneGraph);
229
rootScene[1]->replaceChild(scene, sceneGraph);
234
void CoinRiftWidget::resizeGL(int width, int height) {
235
int side = qMin(width, height);
236
glViewport((width - side) / 2, (height - side) / 2, side, side);
238
glMatrixMode(GL_PROJECTION);
240
glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1000.0);
241
glMatrixMode(GL_MODELVIEW);
244
void CoinRiftWidget::initializeGL()
247
// Infer hardware capabilities.
248
#ifdef USE_FRAMEBUFFER
249
OVR::CAPI::GL::InitGLExtensions();
250
if (OVR::CAPI::GL::glBindFramebuffer == NULL) {
251
qDebug() << "No GL extensions found.";
255
// Store old framebuffer.
257
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldfb);
260
// Create rendering target textures.
261
glEnable(GL_TEXTURE_2D);
262
for (int eye = 0; eye < 2; eye++) {
263
#ifdef USE_FRAMEBUFFER
264
OVR::CAPI::GL::glGenFramebuffers(1, &frameBufferID[eye]);
265
OVR::CAPI::GL::glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBufferID[eye]);
266
// Create the render buffer.
267
// TODO: need to check for OpenGl 3 or higher and load the functions JR 2014
268
/*OVR::CAPI::GL::*/glGenRenderbuffers(1, &depthBufferID[eye]);
269
/*OVR::CAPI::GL::*/glBindRenderbuffer(GL_RENDERBUFFER_EXT, depthBufferID[eye]);
270
/*OVR::CAPI::GL::*/glRenderbufferStorage(GL_RENDERBUFFER_EXT,
271
GL_DEPTH_COMPONENT16,
272
eyeTexture[eye].Header.TextureSize.w,
273
eyeTexture[eye].Header.TextureSize.h);
274
// Attach renderbuffer to framebuffer.
275
OVR::CAPI::GL::glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
276
GL_DEPTH_ATTACHMENT_EXT,
280
ovrGLTextureData *texData = reinterpret_cast<ovrGLTextureData*>(&eyeTexture[eye]);
281
texData->Header.API = ovrRenderAPI_OpenGL;
282
texData->Header.TextureSize = eyeTexture[eye].Header.TextureSize;
283
texData->Header.RenderViewport = eyeTexture[eye].Header.RenderViewport;
284
glGenTextures(1, &texData->TexId);
285
glBindTexture(GL_TEXTURE_2D, texData->TexId);
286
Q_ASSERT(!glGetError());
287
// Allocate storage for the texture.
288
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, eyeTexture[eye].Header.TextureSize.w, eyeTexture[eye].Header.TextureSize.h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
289
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
290
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
291
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
292
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
293
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
294
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
295
Q_ASSERT(!glGetError());
296
#ifdef USE_FRAMEBUFFER
297
// Attach texture to framebuffer color object.
298
OVR::CAPI::GL::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
299
GL_COLOR_ATTACHMENT0_EXT,
300
GL_TEXTURE_2D, texData->TexId, 0);
301
if (OVR::CAPI::GL::glCheckFramebufferStatus(GL_FRAMEBUFFER) !=
302
GL_FRAMEBUFFER_COMPLETE)
303
qDebug() << "ERROR: FrameBuffer is not operational!";
306
glBindTexture(GL_TEXTURE_2D, 0);
307
glDisable(GL_TEXTURE_2D);
309
#ifdef USE_FRAMEBUFFER
310
// Continue rendering to the original frame buffer (likely 0, the onscreen buffer).
311
OVR::CAPI::GL::glBindFramebuffer(GL_FRAMEBUFFER_EXT, oldfb);
317
void CoinRiftWidget::paintGL()
319
const int ms(1000 / 75 /*fps*/);
320
QTimer::singleShot(ms, this, &CoinRiftWidget::updateGL);
322
// handling the safety warning
323
handlingSafetyWarning();
329
glEnable(GL_TEXTURE_2D);
331
ovrFrameTiming hmdFrameTiming = ovrHmd_BeginFrame(hmd, 0);
332
for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) {
333
ovrEyeType eye = hmd->EyeRenderOrder[eyeIndex];
334
eyePose[eye] = ovrHmd_GetEyePose(hmd, eye);
337
SbRotation riftOrientation( eyePose[eye].Orientation.x,
338
eyePose[eye].Orientation.y,
339
eyePose[eye].Orientation.z,
340
eyePose[eye].Orientation.w);
342
camera[eye]->orientation.setValue(riftOrientation);
344
SbVec3f riftPosition = SbVec3f(eyePose[eye].Position.x,
345
eyePose[eye].Position.y,
346
eyePose[eye].Position.z);
349
//SbVec3f originalPosition(camera[eye]->position.getValue());
350
SbVec3f viewAdjust(eyeRenderDesc[eye].ViewAdjust.x,
351
eyeRenderDesc[eye].ViewAdjust.y,
352
eyeRenderDesc[eye].ViewAdjust.z);
354
riftOrientation.multVec(viewAdjust,viewAdjust);
356
camera[eye]->position.setValue(basePosition - viewAdjust + riftPosition);
358
//Base::Console().Log("Eye(%d) Pos: %f, %f, %f ViewAdjust: %f, %f, %f \n",eye, eyePose[eye].Position.x,
359
// eyePose[eye].Position.y,
360
// eyePose[eye].Position.z,
361
// eyeRenderDesc[eye].ViewAdjust.x,
362
// eyeRenderDesc[eye].ViewAdjust.y,
363
// eyeRenderDesc[eye].ViewAdjust.z);
365
#ifdef USE_SO_OFFSCREEN_RENDERER
366
ovrGLTextureData *texData = reinterpret_cast<ovrGLTextureData*>(&eyeTexture[eye]);
367
glBindTexture(GL_TEXTURE_2D, texData->TexId);
368
renderer->render(rootScene[eye]);
369
Q_ASSERT(!glGetError());
370
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
371
eyeTexture[eye].Header.TextureSize.w,
372
eyeTexture[eye].Header.TextureSize.h,
373
0, GL_RGBA /*GL_BGRA*/, GL_UNSIGNED_BYTE, renderer->getBuffer());
374
Q_ASSERT(!glGetError());
375
glBindTexture(GL_TEXTURE_2D, 0);
377
#ifdef USE_FRAMEBUFFER
378
// Clear state pollution from OVR SDK.
379
glBindTexture(GL_TEXTURE_2D, 0); // You need this, at least if (hmdDesc.DistortionCaps & ovrDistortion_Chromatic).
380
OVR::CAPI::GL::glUseProgram(0); // You need this even more.
383
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &oldfb);
384
// Set up framebuffer for rendering.
385
OVR::CAPI::GL::glBindFramebuffer(GL_FRAMEBUFFER_EXT, frameBufferID[eye]);
387
m_sceneManager->setSceneGraph(rootScene[eye]);
388
// m_sceneManager->setCamera(camera[eye]); // SoSceneManager does this implicitly.
389
m_sceneManager->render();
391
// Continue rendering to the original frame buffer (likely 0, the onscreen buffer).
392
OVR::CAPI::GL::glBindFramebuffer(GL_FRAMEBUFFER_EXT, oldfb);
393
Q_ASSERT(!glGetError());
396
//camera[eye]->position.setValue(originalPosition);
400
// Submit the texture for distortion.
401
ovrHmd_EndFrame(hmd, eyePose, eyeTexture);
404
glDisable(GL_CULL_FACE);
405
glDisable(GL_DEPTH_TEST);
406
//ovrHmd_EndFrame(hmd);
407
glEnable(GL_CULL_FACE);
408
glEnable(GL_DEPTH_TEST);
414
void CoinRiftWidget::handlingSafetyWarning(void)
416
// Health and Safety Warning display state.
417
ovrHSWDisplayState hswDisplayState;
418
ovrHmd_GetHSWDisplayState(hmd, &hswDisplayState);
419
if (hswDisplayState.Displayed)
421
// Dismiss the warning if the user pressed the appropriate key or if the user
422
// is tapping the side of the HMD.
423
// If the user has requested to dismiss the warning via keyboard or controller input...
424
//if (Util_GetAndResetHSWDismissedState())
425
ovrHmd_DismissHSWDisplay(hmd);
428
// // Detect a moderate tap on the side of the HMD.
429
// ovrTrackingState ts = ovrHmd_GetTrackingState(hmd, ovr_GetTimeInSeconds());
430
// if (ts.StatusFlags & ovrStatus_OrientationTracked)
432
// const OVR::Vector3f v(ts.RawSensorData.Accelerometer.x,
433
// ts.RawSensorData.Accelerometer.y,
434
// ts.RawSensorData.Accelerometer.z);
435
// // Arbitrary value and representing moderate tap on the side of the DK2 Rift.
436
// if (v.LengthSq() > 250.f)
437
// ovrHmd_DismissHSWDisplay(hmd);
445
#ifdef BUILD_RIFT_TEST_MAIN
447
int main(int argc, char *argv[])
451
QApplication app(argc, argv);
452
qAddPostRoutine(cleanup);
454
// Moved here because of https://developer.oculusvr.com/forums/viewtopic.php?f=17&t=7915&p=108503#p108503
456
if (!ovr_Initialize()) {
457
qDebug() << "Could not initialize Oculus SDK.";
461
CoinRiftWidget window;
465
static const char * inlineSceneGraph[] = {
466
"#Inventor V2.1 ascii\n",
469
" Rotation { rotation 1 0 0 0.3 }\n",
471
" BaseColor { rgb 1 0 0 }\n",
472
" Scale { scaleFactor .7 .7 .7 }\n",
475
" DrawStyle { style LINES }\n",
476
" ShapeHints { vertexOrdering COUNTERCLOCKWISE }\n",
479
" -2 -2 1.1, -2 -1 1.1, -2 1 1.1, -2 2 1.1,\n",
480
" -1 -2 1.1, -1 -1 1.1, -1 1 1.1, -1 2 1.1\n",
481
" 1 -2 1.1, 1 -1 1.1, 1 1 1.1, 1 2 1.1\n",
482
" 2 -2 1.1, 2 -1 1.1, 2 1 1.1, 2 2 1.1\n",
486
" Complexity { value 0.7 }\n",
488
" numUControlPoints 4\n",
489
" numVControlPoints 4\n",
490
" uKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n",
491
" vKnotVector [ 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 ]\n",
498
in.setStringArray(inlineSceneGraph);
500
window.setSceneGraph(SoDB::readAll(&in));
505
#endif //BUILD_RIFT_TEST_MAIN