3 * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * Based on example code:
21 * Content : Simple minimal VR demo
22 * Created : December 1, 2014
24 * Copyright : Copyright 2012 Oculus, Inc. All Rights reserved.
26 * Licensed under the Apache License, Version 2.0 (the "License");
27 * you may not use this file except in compliance with the License.
28 * You may obtain a copy of the License at
30 * http://www.apache.org/licenses/LICENSE-2.0
32 * Unless required by applicable law or agreed to in writing, software
33 * distributed under the License is distributed on an "AS IS" BASIS,
34 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
35 * See the License for the specific language governing permissions and
36 * limitations under the License.
44 #include "../libsdl/print.h"
48 #include <OVR_CAPI_GL.h>
51 #define GL3_PROTOTYPES 1
56 #include <dxgi.h> // for GetDefaultAdapterLuid
57 #pragma comment(lib, "dxgi.lib")
60 static ovrGraphicsLuid GetDefaultAdapterLuid()
62 ovrGraphicsLuid luid = ovrGraphicsLuid();
65 IDXGIFactory* factory = nullptr;
67 if (SUCCEEDED(CreateDXGIFactory(IID_PPV_ARGS(&factory)))) {
68 IDXGIAdapter* adapter = nullptr;
70 if (SUCCEEDED(factory->EnumAdapters(0, &adapter))) {
71 DXGI_ADAPTER_DESC desc;
73 adapter->GetDesc(&desc);
74 memcpy(&luid, &desc.AdapterLuid, sizeof(luid));
85 static int Compare(const ovrGraphicsLuid lhs, const ovrGraphicsLuid rhs)
87 return memcmp(&lhs, &rhs, sizeof(ovrGraphicsLuid));
91 static int ovr_initialized = 0;
92 static ovrSession session = NULL;
93 static ovrGraphicsLuid luid;
94 static ovrHmdDesc hmdDesc;
95 static ovrSizei TextureSize[2];
96 static ovrTextureSwapChain textureSwapChain[2] = { NULL, NULL };
97 static GLuint fboId[2] = { 0, 0 };
98 static ovrEyeRenderDesc eyeRenderDesc[2];
99 static ovrPosef hmdToEyeViewPose[2];
100 static ovrLayerEyeFov layer;
101 static long long frameIndex = 0;
102 static double observer_x = 0.0;
103 static double observer_x_normalize = 0.0;
104 static double observer_y = 0.0;
105 static double observer_y_normalize = 0.0;
106 static double observer_z = 0.0;
107 static double observer_z_normalize = 0.0;
111 int sample_count = 1; // FIXME: make MSAA
115 glewExperimental = GL_TRUE;
116 if (glewInit() != GLEW_OK) {
117 print_error("Failed to init GLEW\n");
121 result = ovr_Initialize(NULL);
122 if (OVR_FAILURE(result)) {
123 print_error("Failed to init OVR (is Oculus Rift service running?)\n");
128 result = ovr_Create(&session, &luid);
129 if (OVR_FAILURE(result)) {
130 print_error("Failed to create OVR session (is the HMD connected?)\n");
135 if (Compare(luid, GetDefaultAdapterLuid())) { // If luid that the Rift is on is not the default adapter LUID...
136 print_error("OpenGL supports only the default graphics adapter.\n");
141 hmdDesc = ovr_GetHmdDesc(session);
143 memset(&layer, 0, sizeof(layer));
144 layer.Header.Type = ovrLayerType_EyeFov;
145 layer.Header.Flags = 0;
147 /* create render buffers */
148 for (eye = 0; eye < 2; eye++) {
149 TextureSize[eye] = ovr_GetFovTextureSize(session, (eye == 0) ? ovrEye_Left : ovrEye_Right, hmdDesc.DefaultEyeFov[eye], 1.0);
150 #warning hacking resolution
151 //TextureSize[eye].w *= 2;
152 //TextureSize[eye].h *= 2;
153 ovrTextureSwapChainDesc desc;
157 memset(&desc, 0, sizeof(desc));
158 desc.Type = ovrTexture_2D;
160 desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
161 desc.Width = TextureSize[eye].w;
162 desc.Height = TextureSize[eye].h;
164 desc.SampleCount = sample_count;
165 desc.StaticImage = ovrFalse;
167 result = ovr_CreateTextureSwapChainGL(session, &desc, &textureSwapChain[eye]);
168 if (OVR_FAILURE(result)) {
169 print_error("ovr_CreateTextureSwapChainGL() failed!\n");
173 ovr_GetTextureSwapChainLength(session, textureSwapChain[eye], &length);
174 for (i = 0; i < length; i++) {
175 ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], i, &chainTexId);
176 glBindTexture(GL_TEXTURE_2D, chainTexId);
177 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
178 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
183 glGenFramebuffers(1, &(fboId[eye]));
185 eyeRenderDesc[eye] = ovr_GetRenderDesc(session, (eye == 0) ? ovrEye_Left : ovrEye_Right, hmdDesc.DefaultEyeFov[eye]);
186 hmdToEyeViewPose[eye] = eyeRenderDesc[eye].HmdToEyePose;
188 layer.ColorTexture[eye] = textureSwapChain[eye];
189 layer.Fov[eye] = eyeRenderDesc[eye].Fov;
190 layer.Viewport[eye].Pos.x = 0;
191 layer.Viewport[eye].Pos.y = 0;
192 layer.Viewport[eye].Size.w = TextureSize[eye].w;
193 layer.Viewport[eye].Size.h = TextureSize[eye].h;
204 void begin_render_ovr(void)
208 /* Get both eye poses simultaneously, with IPD offset already included. */
209 double displayMidpointSeconds = ovr_GetPredictedDisplayTime(session, 0);
210 ovrTrackingState hmdState = ovr_GetTrackingState(session, displayMidpointSeconds, ovrTrue);
211 ovr_CalcEyePoses(hmdState.HeadPose.ThePose, hmdToEyeViewPose, layer.RenderPose);
213 result = ovr_WaitToBeginFrame(session, frameIndex);
214 if (!OVR_SUCCESS(result))
215 print_info("Failed to wait to begin frame (error %d)\n", result);
216 result = ovr_BeginFrame(session, frameIndex);
217 if (!OVR_SUCCESS(result))
218 print_info("Failed to begin frame (error %d)\n", result);
221 void begin_render_ovr_eye(int eye)
225 float yaw, pitch, roll;
228 /* set render surface */
229 ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
230 ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
231 glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
232 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, chainTexId, 0);
234 glViewport(0, 0, TextureSize[eye].w, TextureSize[eye].h);
235 glMatrixMode(GL_PROJECTION);
238 -layer.Fov[eye].LeftTan,
239 layer.Fov[eye].RightTan,
240 layer.Fov[eye].UpTan,
241 -layer.Fov[eye].DownTan,
244 ovrOrientation2yawpitchroll(layer.RenderPose[eye].Orientation, &yaw, &pitch, &roll);
245 x = layer.RenderPose[eye].Position.x;
246 y = layer.RenderPose[eye].Position.y;
247 z = layer.RenderPose[eye].Position.z;
249 /* normalize height to game's observer, if requrested by user */
251 x += observer_x_normalize;
253 y += observer_y_normalize;
255 z += observer_z_normalize;
257 glRotatef(-roll / M_PI * 180.0,0,0,1);
258 glRotatef(-pitch / M_PI * 180.0,1,0,0);
259 glRotatef(-yaw / M_PI * 180.0,0,1,0);
261 glTranslated(-x / 0.0254, -y / 0.0254, -z / 0.0254); /* convert to inch */
263 glMatrixMode(GL_MODELVIEW);
265 /* DO NOT ENABLE, since our mercenary-textures are not SRGB */
266 //glEnable(GL_FRAMEBUFFER_SRGB);
270 void end_render_ovr_eye(int eye)
272 // unset render surface
273 glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
274 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
275 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
276 glBindFramebuffer(GL_FRAMEBUFFER, 0);
278 // Commit the changes to the texture swap chain
279 ovr_CommitTextureSwapChain(session, textureSwapChain[eye]);
282 void end_render_ovr(void)
286 const ovrLayerHeader *layers[] = { &layer.Header };
287 result = ovr_EndFrame(session, frameIndex, NULL, layers, 1);
288 if (!OVR_SUCCESS(result))
289 print_info("Failed to submit frame (error %d)\n", result);
293 void render_mirror_ovr(int view_width, int view_height)
295 int eye = 0; /* left eye */
300 glClearColor(1.0, 0.0, 0.0, 1.0);
301 glClear(GL_COLOR_BUFFER_BIT);
303 /* orthogonal viewport */
304 glViewport((GLsizei)0, (GLsizei)0, (GLsizei)view_width, (GLsizei)view_height);
305 glMatrixMode(GL_PROJECTION);
307 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
308 glMatrixMode(GL_MODELVIEW);
310 /* get texture from OVR */
311 ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
312 ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
314 /* render mirror from texture */
315 glEnable(GL_TEXTURE_2D);
316 glBindTexture(GL_TEXTURE_2D, chainTexId);
317 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
320 glVertex3f(-1.0, -1.0, 0.0);
322 glVertex3f(1.0, -1.0, 0.0);
324 glVertex3f(1.0, 1.0, 0.0);
326 glVertex3f(-1.0, 1.0, 0.0);
328 glDisable(GL_TEXTURE_2D);
331 void normalize_observer_ovr(void)
333 observer_x_normalize = -observer_x;
334 observer_y_normalize = -observer_y;
335 observer_z_normalize = -observer_z;
342 /* destroy render buffers */
343 for (eye = 0; eye < 2; eye++) {
344 if (textureSwapChain[eye]) {
345 ovr_DestroyTextureSwapChain(session, textureSwapChain[eye]);
346 textureSwapChain[eye] = NULL;
349 glDeleteFramebuffers(1, &fboId[eye]);
355 ovr_Destroy(session);
358 if (ovr_initialized) {