OVR: Add Support for Oculus Rift SDK
[mercenary-reloaded.git] / src / libovr / ovr.c
1 /* OVR handling
2  *
3  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
4  * All Rights Reserved
5  *
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.
10  *
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.
15  *
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/>.
18  *
19  * Based on example code:
20  * Filename    :   main.cpp
21  * Content     :   Simple minimal VR demo
22  * Created     :   December 1, 2014
23  * Author      :   Tom Heath
24  * Copyright   :   Copyright 2012 Oculus, Inc. All Rights reserved.
25  *
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
29  *
30  * http://www.apache.org/licenses/LICENSE-2.0
31  *
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.
37  */
38
39 #include <stdio.h>
40 #include <stdint.h>
41 #include <string.h>
42 #include <math.h>
43 #include <errno.h>
44 #include "../libsdl/print.h"
45 #include "ovr.h"
46
47 #include <OVR_CAPI.h>
48 #include <OVR_CAPI_GL.h>
49 #include "helper.h"
50
51 #define GL3_PROTOTYPES 1
52 #include <GL/glew.h>
53
54 #if 0
55 #if defined(_WIN32)
56     #include <dxgi.h> // for GetDefaultAdapterLuid
57     #pragma comment(lib, "dxgi.lib")
58 #endif
59
60 static ovrGraphicsLuid GetDefaultAdapterLuid()
61 {
62         ovrGraphicsLuid luid = ovrGraphicsLuid();
63
64 #if defined(_WIN32)
65         IDXGIFactory* factory = nullptr;
66
67         if (SUCCEEDED(CreateDXGIFactory(IID_PPV_ARGS(&factory)))) {
68                 IDXGIAdapter* adapter = nullptr;
69
70                 if (SUCCEEDED(factory->EnumAdapters(0, &adapter))) {
71                         DXGI_ADAPTER_DESC desc;
72
73                         adapter->GetDesc(&desc);
74                         memcpy(&luid, &desc.AdapterLuid, sizeof(luid));
75                         adapter->Release();
76                 }
77
78                 factory->Release();
79         }
80 #endif
81
82         return luid;
83 }
84
85 static int Compare(const ovrGraphicsLuid lhs, const ovrGraphicsLuid rhs)
86 {
87     return memcmp(&lhs, &rhs, sizeof(ovrGraphicsLuid));
88 }
89 #endif
90
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
103 int init_ovr(void)
104 {
105         int sample_count = 1; // FIXME: make MSAA
106         ovrResult result;
107         int eye;
108
109         glewExperimental = GL_TRUE;
110         if (glewInit() != GLEW_OK) {
111                 print_error("Failed to init GLEW\n");
112                 goto error;
113         }
114
115         result = ovr_Initialize(NULL);
116         if (OVR_FAILURE(result)) {
117                 print_error("Failed to init OVR (is Oculus Rift service running?)\n");
118                 goto error;
119         }
120         ovr_initialized = 1;
121
122         result = ovr_Create(&session, &luid);
123         if (OVR_FAILURE(result)) {
124                 print_error("Failed to create OVR session (is the HMD connected?)\n");
125                 goto error;
126         }
127
128 #if 0
129         if (Compare(luid, GetDefaultAdapterLuid())) { // If luid that the Rift is on is not the default adapter LUID...
130                 print_error("OpenGL supports only the default graphics adapter.\n");
131                 goto error;
132         }
133 #endif
134
135         hmdDesc = ovr_GetHmdDesc(session);
136
137         memset(&layer, 0, sizeof(layer));
138         layer.Header.Type      = ovrLayerType_EyeFov;
139         layer.Header.Flags     = 0;
140
141         /* create render buffers */
142         for (eye = 0; eye < 2; eye++) {
143                 TextureSize[eye] = ovr_GetFovTextureSize(session, (eye == 0) ? ovrEye_Left : ovrEye_Right, hmdDesc.DefaultEyeFov[eye], 1.0);
144 #warning hacking resolution
145 //TextureSize[eye].w *= 2;
146 //TextureSize[eye].h *= 2;
147                 ovrTextureSwapChainDesc desc;
148                 int length, i;
149                 GLuint chainTexId;
150
151                 memset(&desc, 0, sizeof(desc));
152                 desc.Type = ovrTexture_2D;
153                 desc.ArraySize = 1;
154                 desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
155                 desc.Width = TextureSize[eye].w;
156                 desc.Height = TextureSize[eye].h;
157                 desc.MipLevels = 1;
158                 desc.SampleCount = sample_count;
159                 desc.StaticImage = ovrFalse;
160
161                 result = ovr_CreateTextureSwapChainGL(session, &desc, &textureSwapChain[eye]);
162                 if (OVR_FAILURE(result)) {
163                         print_error("ovr_CreateTextureSwapChainGL() failed!\n");
164                         goto error;
165                 }
166
167                 ovr_GetTextureSwapChainLength(session, textureSwapChain[eye], &length);
168                 for (i = 0; i < length; i++) {
169                         ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], i, &chainTexId);
170                         glBindTexture(GL_TEXTURE_2D, chainTexId);
171                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
172                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
173                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
174                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
175                 }
176
177                 glGenFramebuffers(1, &(fboId[eye]));
178
179                 eyeRenderDesc[eye] = ovr_GetRenderDesc(session, (eye == 0) ? ovrEye_Left : ovrEye_Right, hmdDesc.DefaultEyeFov[eye]);
180                 hmdToEyeViewPose[eye] = eyeRenderDesc[eye].HmdToEyePose;
181
182                 layer.ColorTexture[eye]  = textureSwapChain[eye];
183                 layer.Fov[eye]           = eyeRenderDesc[eye].Fov;
184                 layer.Viewport[eye].Pos.x = 0;
185                 layer.Viewport[eye].Pos.y = 0;
186                 layer.Viewport[eye].Size.w = TextureSize[eye].w;
187                 layer.Viewport[eye].Size.h = TextureSize[eye].h;
188         }
189
190
191         return 0;
192
193 error:
194         exit_ovr();
195         return -EINVAL;
196 }
197
198 void begin_render_ovr(void)
199 {       
200         ovrResult result;
201
202         /* Get both eye poses simultaneously, with IPD offset already included. */
203         double displayMidpointSeconds = ovr_GetPredictedDisplayTime(session, 0);
204         ovrTrackingState hmdState = ovr_GetTrackingState(session, displayMidpointSeconds, ovrTrue);
205         ovr_CalcEyePoses(hmdState.HeadPose.ThePose, hmdToEyeViewPose, layer.RenderPose);
206
207         result = ovr_WaitToBeginFrame(session, frameIndex);
208         if (!OVR_SUCCESS(result))
209                 print_info("Failed to wait to begin frame (error %d)\n", result);
210         result = ovr_BeginFrame(session, frameIndex);
211         if (!OVR_SUCCESS(result))
212                 print_info("Failed to begin frame (error %d)\n", result);
213 }
214
215 void begin_render_ovr_eye(int eye)
216 {
217         int curIndex;
218         GLuint chainTexId;
219         float yaw, pitch, roll;
220         double x, y, z;
221
222         /* set render surface */
223         ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
224         ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
225         glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
226         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, chainTexId, 0);
227
228         glViewport(0, 0, TextureSize[eye].w, TextureSize[eye].h);
229         glMatrixMode(GL_PROJECTION);
230         glLoadIdentity();
231         glFrustum(
232                 -layer.Fov[eye].LeftTan,
233                 layer.Fov[eye].RightTan,
234                 layer.Fov[eye].UpTan,
235                 -layer.Fov[eye].DownTan,
236                 1.0, 5000000000.0);
237
238         ovrOrientation2yawpitchroll(layer.RenderPose[eye].Orientation, &yaw, &pitch, &roll);
239         x = layer.RenderPose[eye].Position.x;
240         y = layer.RenderPose[eye].Position.y;
241         z = layer.RenderPose[eye].Position.z;
242
243         glRotatef(-roll / M_PI * 180.0,0,0,1);
244         glRotatef(-pitch / M_PI * 180.0,1,0,0);
245         glRotatef(-yaw / M_PI * 180.0,0,1,0);
246
247         glTranslated(-x / 0.0254, -y / 0.0254, -z / 0.0254); /* convert to inch */
248
249         glMatrixMode(GL_MODELVIEW);
250
251         /* DO NOT ENABLE, since our mercenary-textures are not SRGB */
252         //glEnable(GL_FRAMEBUFFER_SRGB);
253
254 }
255
256 void end_render_ovr_eye(int eye)
257 {
258         // unset render surface
259         glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
260         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
261         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
262         glBindFramebuffer(GL_FRAMEBUFFER, 0);
263
264         // Commit the changes to the texture swap chain
265         ovr_CommitTextureSwapChain(session, textureSwapChain[eye]);
266 }
267
268 void end_render_ovr(void)
269 {
270         ovrResult result;
271
272         const ovrLayerHeader *layers[] = { &layer.Header };
273         result = ovr_EndFrame(session, frameIndex, NULL, layers, 1);
274         if (!OVR_SUCCESS(result))
275                 print_info("Failed to submit frame (error %d)\n", result);
276         frameIndex++;
277 }
278
279 void render_mirror_ovr(int view_width, int view_height)
280 {
281         int eye = 0; /* left eye */
282         int curIndex;
283         GLuint chainTexId;
284
285         /* clear screen */
286         glClearColor(1.0, 0.0, 0.0, 1.0);
287         glClear(GL_COLOR_BUFFER_BIT);
288
289         /* orthogonal viewport */
290         glViewport((GLsizei)0, (GLsizei)0, (GLsizei)view_width, (GLsizei)view_height);
291         glMatrixMode(GL_PROJECTION);
292         glLoadIdentity();
293         glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
294         glMatrixMode(GL_MODELVIEW);
295
296         /* get texture from OVR */
297         ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
298         ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
299
300         /* render mirror from texture */
301         glEnable(GL_TEXTURE_2D);
302         glBindTexture(GL_TEXTURE_2D, chainTexId);
303         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);  /* no modulation with color */
304         glBegin(GL_QUADS);
305         glTexCoord2f(0, 1);
306         glVertex3f(-1.0, -1.0, 0.0);
307         glTexCoord2f(1, 1);
308         glVertex3f(1.0, -1.0, 0.0);
309         glTexCoord2f(1, 0);
310         glVertex3f(1.0, 1.0, 0.0);
311         glTexCoord2f(0, 0);
312         glVertex3f(-1.0, 1.0, 0.0);
313         glEnd();
314         glDisable(GL_TEXTURE_2D);
315 }
316
317 void exit_ovr(void)
318 {
319         int eye;
320
321         /* destroy render buffers */
322         for (eye = 0; eye < 2; eye++) {
323                 if (textureSwapChain[eye]) {
324                         ovr_DestroyTextureSwapChain(session, textureSwapChain[eye]);
325                         textureSwapChain[eye] = NULL;
326                 }
327                 if (fboId[eye]) {
328                         glDeleteFramebuffers(1, &fboId[eye]);
329                         fboId[eye] = 0;
330                 }
331         }
332
333         if (session) {
334                 ovr_Destroy(session);
335                 session = NULL;
336         }
337         if (ovr_initialized) {
338                 ovr_Shutdown();
339                 ovr_initialized = 0;
340         }
341 }
342