Add shadows and light effects
[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 "../libopengl/opengl.h"
46 #include "ovr.h"
47
48 #include <OVR_CAPI.h>
49 #include <OVR_CAPI_GL.h>
50 #include "helper.h"
51
52 #define GL3_PROTOTYPES 1
53 #include <GL/glew.h>
54
55 #if 0
56 #if defined(_WIN32)
57     #include <dxgi.h> // for GetDefaultAdapterLuid
58     #pragma comment(lib, "dxgi.lib")
59 #endif
60
61 static ovrGraphicsLuid GetDefaultAdapterLuid()
62 {
63         ovrGraphicsLuid luid = ovrGraphicsLuid();
64
65 #if defined(_WIN32)
66         IDXGIFactory* factory = nullptr;
67
68         if (SUCCEEDED(CreateDXGIFactory(IID_PPV_ARGS(&factory)))) {
69                 IDXGIAdapter* adapter = nullptr;
70
71                 if (SUCCEEDED(factory->EnumAdapters(0, &adapter))) {
72                         DXGI_ADAPTER_DESC desc;
73
74                         adapter->GetDesc(&desc);
75                         memcpy(&luid, &desc.AdapterLuid, sizeof(luid));
76                         adapter->Release();
77                 }
78
79                 factory->Release();
80         }
81 #endif
82
83         return luid;
84 }
85
86 static int Compare(const ovrGraphicsLuid lhs, const ovrGraphicsLuid rhs)
87 {
88     return memcmp(&lhs, &rhs, sizeof(ovrGraphicsLuid));
89 }
90 #endif
91
92 static int ovr_initialized = 0;
93 static ovrSession session = NULL;
94 static ovrGraphicsLuid luid;
95 static ovrHmdDesc hmdDesc;
96 static ovrSizei TextureSize[2];
97 static ovrTextureSwapChain textureSwapChain[2] = { NULL, NULL };
98 static GLuint fboId[2] = { 0, 0 };
99 static GLuint mirrorFBO = 0;
100 static int mirror_width;
101 static int mirror_height;
102 static ovrEyeRenderDesc eyeRenderDesc[2];
103 static ovrPosef hmdToEyeViewPose[2];
104 static ovrPosef headPose;
105 static ovrPosef handPose;
106 static ovrInputState inputState;
107 static ovrLayerEyeFov layer;
108 static int multisampling;
109 static long long frameIndex = 0;
110 static double observer_x = 0.0;
111 static double observer_x_reset = 0.0;
112 static double hand_x_reset = 0.0;
113 static double observer_y = 0.0;
114 static double observer_y_reset = 0.0;
115 static double hand_y_reset = 0.0;
116 static double observer_z = 0.0;
117 static double observer_z_reset = 0.0;
118 static double hand_z_reset = 0.0;
119
120 int init_ovr(int _multisampling)
121 {
122         ovrResult result;
123         int eye;
124
125         multisampling = _multisampling;
126
127         glewExperimental = GL_TRUE;
128         if (glewInit() != GLEW_OK) {
129                 print_error("Failed to init GLEW\n");
130                 goto error;
131         }
132
133         result = ovr_Initialize(NULL);
134         if (OVR_FAILURE(result)) {
135                 print_error("Failed to init OVR (is Oculus Rift service running?)\n");
136                 goto error;
137         }
138         ovr_initialized = 1;
139
140         result = ovr_Create(&session, &luid);
141         if (OVR_FAILURE(result)) {
142                 print_error("Failed to create OVR session (is the HMD connected?)\n");
143                 goto error;
144         }
145
146 #if 0
147         if (Compare(luid, GetDefaultAdapterLuid())) { // If luid that the Rift is on is not the default adapter LUID...
148                 print_error("OpenGL supports only the default graphics adapter.\n");
149                 goto error;
150         }
151 #endif
152
153         hmdDesc = ovr_GetHmdDesc(session);
154
155         memset(&layer, 0, sizeof(layer));
156         layer.Header.Type      = ovrLayerType_EyeFov;
157         layer.Header.Flags     = 0;
158
159         /* do we need this??? seems to work without */
160         if (multisampling > 1)
161                 glEnable(GL_MULTISAMPLE);
162
163         /* create render buffers */
164         for (eye = 0; eye < 2; eye++) {
165                 TextureSize[eye] = ovr_GetFovTextureSize(session, (eye == 0) ? ovrEye_Left : ovrEye_Right, hmdDesc.DefaultEyeFov[eye], 1.0);
166                 ovrTextureSwapChainDesc desc;
167                 int length, i;
168                 GLuint chainTexId;
169
170                 memset(&desc, 0, sizeof(desc));
171                 desc.Type = ovrTexture_2D;
172                 desc.ArraySize = 1;
173                 desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
174                 desc.Width = TextureSize[eye].w;
175                 desc.Height = TextureSize[eye].h;
176                 desc.MipLevels = 1;
177                 desc.SampleCount = (multisampling > 1) ? multisampling : 1;
178                 desc.StaticImage = ovrFalse;
179
180                 result = ovr_CreateTextureSwapChainGL(session, &desc, &textureSwapChain[eye]);
181                 if (OVR_FAILURE(result)) {
182                         print_error("ovr_CreateTextureSwapChainGL() failed! (error %d)\n", result);
183                         goto error;
184                 }
185
186                 ovr_GetTextureSwapChainLength(session, textureSwapChain[eye], &length);
187                 for (i = 0; i < length; i++) {
188                         ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], i, &chainTexId);
189                         glBindTexture((multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, chainTexId);
190                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
191                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
192                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
193                         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
194                 }
195
196                 glGenFramebuffers(1, &(fboId[eye]));
197
198                 eyeRenderDesc[eye] = ovr_GetRenderDesc(session, (eye == 0) ? ovrEye_Left : ovrEye_Right, hmdDesc.DefaultEyeFov[eye]);
199                 hmdToEyeViewPose[eye] = eyeRenderDesc[eye].HmdToEyePose;
200
201                 layer.ColorTexture[eye]  = textureSwapChain[eye];
202                 layer.Fov[eye]           = eyeRenderDesc[eye].Fov;
203                 layer.Viewport[eye].Pos.x = 0;
204                 layer.Viewport[eye].Pos.y = 0;
205                 layer.Viewport[eye].Size.w = TextureSize[eye].w;
206                 layer.Viewport[eye].Size.h = TextureSize[eye].h;
207         }
208
209         ovrMirrorTexture mirrorTexture = NULL;
210         ovrMirrorTextureDesc desc;
211         memset(&desc, 0, sizeof(desc));
212         desc.Width = mirror_width = TextureSize[0].w;
213         desc.Height = mirror_height = TextureSize[0].h;
214         desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
215         desc.MirrorOptions =
216 //              ovrMirrorOption_PostDistortion |
217                 ovrMirrorOption_LeftEyeOnly |
218                 ovrMirrorOption_IncludeGuardian |
219                 ovrMirrorOption_IncludeNotifications |
220                 ovrMirrorOption_IncludeSystemGui;
221
222         /* Create mirror texture and an FBO used to copy mirror texture to back buffer */
223         result = ovr_CreateMirrorTextureWithOptionsGL(session, &desc, &mirrorTexture);
224         if (!OVR_SUCCESS(result)) {
225                 print_error("ovr_CreateMirrorTextureWithOptionsGL() failed! (error %d)\n", result);
226                 goto error;
227         }
228
229         /* Configure the mirror read buffer */
230         GLuint texId;
231         ovr_GetMirrorTextureBufferGL(session, mirrorTexture, &texId);
232
233         glGenFramebuffers(1, &mirrorFBO);
234         glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
235         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
236         glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
237
238         return 0;
239
240 error:
241         exit_ovr();
242         return -EINVAL;
243 }
244
245 void get_poses_ovr(int *button_a, int *button_b, int *button_x, int *button_y, int *button_menu, int *button_left_trigger, int *button_right_trigger, int *button_left_thumb, int *button_right_thumb, double *hand_right_x, double *hand_right_y, double *hand_right_z, double *hand_right_yaw, double *hand_right_pitch, double *hand_right_roll, double *stick_left_x, double *stick_left_y, double *stick_right_x, double *stick_right_y, double *head_yaw, double *head_pitch, double *head_roll)
246 {       
247         ovrResult result;
248         float yaw, pitch, roll;
249         double x, y, z;
250         unsigned int hand_mask = (ovrStatus_OrientationTracked | ovrStatus_PositionTracked);
251         unsigned int hand_flags = (ovrStatus_OrientationTracked | ovrStatus_PositionTracked);
252
253         /* Get both eye poses simultaneously, with IPD offset already included. */
254         double displayMidpointSeconds = ovr_GetPredictedDisplayTime(session, frameIndex);
255         ovrTrackingState hmdState = ovr_GetTrackingState(session, displayMidpointSeconds, ovrTrue);
256         ovr_CalcEyePoses(hmdState.HeadPose.ThePose, hmdToEyeViewPose, layer.RenderPose);
257         /* Grab hand poses useful for rendering head/hand or controller representation */
258         headPose = hmdState.HeadPose.ThePose;
259         handPose = headPose;
260 //      if ((hmdState.HandStatusFlags[ovrHand_Left] & hand_mask) == hand_flags)
261 //              handPose = hmdState.HandPoses[ovrHand_Left].ThePose;
262         if ((hmdState.HandStatusFlags[ovrHand_Right] & hand_mask) == hand_flags)
263                 handPose = hmdState.HandPoses[ovrHand_Right].ThePose;
264         x = handPose.Position.x;
265         y = handPose.Position.y;
266         z = handPose.Position.z;
267         x += hand_x_reset;
268         y += hand_y_reset;
269         z += hand_z_reset;
270         *hand_right_x = x / 0.0254;
271         *hand_right_y = y / 0.0254;
272         *hand_right_z = z / 0.0254;
273         ovrOrientation2yawpitchroll(headPose.Orientation, &yaw, &pitch, &roll);
274         *head_yaw = yaw;
275         *head_pitch = pitch;
276         *head_roll = roll;
277         ovrOrientation2yawpitchroll(handPose.Orientation, &yaw, &pitch, &roll);
278         *hand_right_yaw = yaw;
279         *hand_right_pitch = pitch;
280         *hand_right_roll = roll;
281
282         result = ovr_GetInputState(session, ovrControllerType_Active, &inputState);
283         if (OVR_SUCCESS(result)) {
284                 if (inputState.Buttons & ovrButton_A)
285                         *button_a = 1;
286                 else
287                         *button_a = 0;
288                 if (inputState.Buttons & ovrButton_B)
289                         *button_b = 1;
290                 else
291                         *button_b = 0;
292                 if (inputState.Buttons & ovrButton_X)
293                         *button_x = 1;
294                 else
295                         *button_x = 0;
296                 if (inputState.Buttons & ovrButton_Y)
297                         *button_y = 1;
298                 else
299                         *button_y = 0;
300                 if (inputState.Buttons & ovrButton_Enter)
301                         *button_menu = 1;
302                 else
303                         *button_menu = 0;
304                 if (inputState.Buttons & ovrButton_LThumb)
305                         *button_left_thumb = 1;
306                 else
307                         *button_left_thumb = 0;
308                 if (inputState.Buttons & ovrButton_RThumb)
309                         *button_right_thumb = 1;
310                 else
311                         *button_right_thumb = 0;
312                 if (inputState.IndexTrigger[ovrHand_Left] >= 0.8)
313                         *button_left_trigger = 1;
314                 else
315                         *button_left_trigger = 0;
316                 if (inputState.IndexTrigger[ovrHand_Right] >= 0.8)
317                         *button_right_trigger = 1;
318                 else
319                         *button_right_trigger = 0;
320                 *stick_left_x = inputState.ThumbstickNoDeadzone[ovrHand_Left].x;
321                 *stick_left_y = inputState.ThumbstickNoDeadzone[ovrHand_Left].y;
322                 *stick_right_x = inputState.ThumbstickNoDeadzone[ovrHand_Right].x;
323                 *stick_right_y = inputState.ThumbstickNoDeadzone[ovrHand_Right].y;
324         }
325 }
326
327 void begin_render_ovr(void)
328 {
329         ovrResult result;
330
331         result = ovr_WaitToBeginFrame(session, frameIndex);
332         if (!OVR_SUCCESS(result))
333                 print_info("Failed to wait to begin frame (error %d)\n", result);
334         result = ovr_BeginFrame(session, frameIndex);
335         if (!OVR_SUCCESS(result))
336                 print_info("Failed to begin frame (error %d)\n", result);
337 }
338
339 static int initial_observer_reset = 1;
340
341 void begin_render_ovr_eye(int eye, double *camera_x, double *camera_y, double *camera_z, int *width, int *height)
342 {
343         int curIndex;
344         GLuint chainTexId;
345         float yaw, pitch, roll;
346         double x, y, z;
347
348         /* set render surface */
349         ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain[eye], &curIndex);
350         ovr_GetTextureSwapChainBufferGL(session, textureSwapChain[eye], curIndex, &chainTexId);
351         glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
352         current_framebuffer = fboId[eye];
353         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, (multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, chainTexId, 0);
354
355         glViewport(0, 0, TextureSize[eye].w, TextureSize[eye].h);
356         *width = TextureSize[eye].w;
357         *height = TextureSize[eye].h;
358         glMatrixMode(GL_PROJECTION);
359         glLoadIdentity();
360         glFrustum(
361                 -layer.Fov[eye].LeftTan,
362                 layer.Fov[eye].RightTan,
363                 layer.Fov[eye].UpTan,
364                 -layer.Fov[eye].DownTan,
365                 1.0, 5000000000.0);
366
367         ovrOrientation2yawpitchroll(layer.RenderPose[eye].Orientation, &yaw, &pitch, &roll);
368         x = layer.RenderPose[eye].Position.x;
369         y = layer.RenderPose[eye].Position.y;
370         z = layer.RenderPose[eye].Position.z;
371
372         /* reset to game's observer, if requrested by user */
373         observer_x = x;
374         observer_y = y;
375         observer_z = z;
376         if (initial_observer_reset) {
377                 initial_observer_reset = 0;
378                 reset_observer_ovr();
379         }
380         x += observer_x_reset;
381         y += observer_y_reset;
382         z += observer_z_reset;
383
384         glRotatef(-roll / M_PI * 180.0,0,0,1);
385         glRotatef(-pitch / M_PI * 180.0,1,0,0);
386         glRotatef(-yaw / M_PI * 180.0,0,1,0);
387
388         *camera_x = x / 0.0254;
389         *camera_y = y / 0.0254;
390         *camera_z = z / 0.0254;
391         glTranslated(-(*camera_x), -(*camera_y), -(*camera_z)); /* convert to inch */
392
393         glMatrixMode(GL_MODELVIEW);
394
395         /* DO NOT ENABLE, since our mercenary-textures are not SRGB */
396         //glEnable(GL_FRAMEBUFFER_SRGB);
397
398 }
399
400 void end_render_ovr_eye(int eye)
401 {
402         // unset render surface
403         glBindFramebuffer(GL_FRAMEBUFFER, fboId[eye]);
404         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, (multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, 0, 0);
405         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, (multisampling > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, 0, 0);
406         glBindFramebuffer(GL_FRAMEBUFFER, 0);
407         current_framebuffer = 0;
408
409         // Commit the changes to the texture swap chain
410         ovr_CommitTextureSwapChain(session, textureSwapChain[eye]);
411 }
412
413 void end_render_ovr(void)
414 {
415         ovrResult result;
416
417         const ovrLayerHeader *layers[] = { &layer.Header };
418         result = ovr_EndFrame(session, frameIndex, NULL, layers, 1);
419         if (!OVR_SUCCESS(result))
420                 print_info("Failed to submit frame (error %d)\n", result);
421         frameIndex++;
422 }
423
424 void render_mirror_ovr(int view_width, int view_height)
425 {
426         int view_x = 0, view_y = 0;
427         int new_height; //, new_width;
428
429         /* avoid division by zero, if one dimension is too small */
430         if (view_width < 1 || view_height < 1)
431                 return;
432
433         /* calculate a viewport that has apect of TextureSize */
434 //      if (view_height * mirror_width > view_width * mirror_height) {
435                 new_height = view_width * mirror_height / mirror_width;
436                 view_y = view_y + view_height / 2 - new_height / 2;
437                 view_height = new_height;
438 //      } else if (view_height * mirror_width < view_width * mirror_height) {
439 //              new_width = view_height * mirror_width / mirror_height;
440 //              view_x = view_x + view_width / 2 - new_width / 2;
441 //              view_width = new_width;
442 //      }
443
444         /* avoid views that are too small */
445         if (view_width < 1 || view_height < 1)
446                 return;
447
448         glBindFramebuffer(GL_FRAMEBUFFER, 0);
449
450         glClearColor(0.0, 0.0, 0.0, 1.0);
451         glClear(GL_COLOR_BUFFER_BIT);
452
453         /* Blit mirror texture to back buffer */
454         glBindFramebuffer(GL_READ_FRAMEBUFFER, mirrorFBO);
455         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
456         glBlitFramebuffer(0, mirror_height, mirror_width, 0,
457                 view_x, view_y, view_x + view_width, view_y + view_height,
458                 GL_COLOR_BUFFER_BIT, GL_LINEAR);
459         glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
460 }
461
462 void reset_observer_ovr(void)
463 {
464         observer_x_reset = -observer_x;
465         observer_y_reset = -observer_y;
466         observer_z_reset = -observer_z;
467         hand_x_reset = -observer_x;
468         hand_y_reset = -observer_y;
469         hand_z_reset = -observer_z;
470 }
471
472 int should_quit_ovr(void)
473 {
474         ovrSessionStatus sessionStatus;
475         ovrResult result;
476
477         result = ovr_GetSessionStatus(session, &sessionStatus);
478
479         if (OVR_SUCCESS(result))
480                 return sessionStatus.ShouldQuit;
481         return 0;
482 }
483
484 void exit_ovr(void)
485 {
486         int eye;
487
488         /* destroy render buffers */
489         for (eye = 0; eye < 2; eye++) {
490                 if (textureSwapChain[eye]) {
491                         ovr_DestroyTextureSwapChain(session, textureSwapChain[eye]);
492                         textureSwapChain[eye] = NULL;
493                 }
494                 if (fboId[eye]) {
495                         glDeleteFramebuffers(1, &fboId[eye]);
496                         fboId[eye] = 0;
497                 }
498         }
499         if (mirrorFBO) {
500                 glDeleteFramebuffers(1, &mirrorFBO);
501                 mirrorFBO = 0;
502         }
503
504         if (session) {
505                 ovr_Destroy(session);
506                 session = NULL;
507         }
508         if (ovr_initialized) {
509                 ovr_Shutdown();
510                 ovr_initialized = 0;
511         }
512 }
513