rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@2
|
3 #include <assert.h>
|
nuclear@0
|
4 #include <SDL2/SDL.h>
|
nuclear@0
|
5 #include <GL/glew.h>
|
nuclear@0
|
6
|
nuclear@2
|
7 #ifdef WIN32
|
nuclear@2
|
8 #define OVR_OS_WIN32
|
nuclear@2
|
9 #endif
|
nuclear@2
|
10 #ifdef __APPLE__
|
nuclear@2
|
11 #define OVR_OS_MAC
|
nuclear@2
|
12 #endif
|
nuclear@2
|
13
|
nuclear@0
|
14 #include <OVR_CAPI.h>
|
nuclear@0
|
15 #include <OVR_CAPI_GL.h>
|
nuclear@0
|
16
|
nuclear@2
|
17 int init(void);
|
nuclear@2
|
18 void cleanup(void);
|
nuclear@2
|
19 void display(void);
|
nuclear@2
|
20 void draw_scene(void);
|
nuclear@2
|
21 void draw_box(float xsz, float ysz, float zsz, float norm_sign);
|
nuclear@0
|
22 void update_rtarg(int width, int height);
|
nuclear@0
|
23 int handle_event(SDL_Event *ev);
|
nuclear@0
|
24 int key_event(int key, int state);
|
nuclear@0
|
25 void reshape(int x, int y);
|
nuclear@0
|
26 unsigned int next_pow2(unsigned int x);
|
nuclear@0
|
27
|
nuclear@0
|
28 OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enable);
|
nuclear@0
|
29
|
nuclear@0
|
30 static SDL_Window *win;
|
nuclear@0
|
31 static SDL_GLContext ctx;
|
nuclear@2
|
32 static int win_width, win_height;
|
nuclear@0
|
33
|
nuclear@0
|
34 static unsigned int fbo, fb_tex, fb_depth;
|
nuclear@0
|
35 static int fb_width, fb_height;
|
nuclear@0
|
36 static int fb_tex_width, fb_tex_height;
|
nuclear@0
|
37
|
nuclear@0
|
38 static ovrHmd hmd;
|
nuclear@0
|
39 static ovrSizei eyeres[2];
|
nuclear@2
|
40 static ovrEyeRenderDesc eye_rdesc[2];
|
nuclear@2
|
41 static ovrGLTexture fb_ovr_tex[2];
|
nuclear@0
|
42
|
nuclear@0
|
43
|
nuclear@0
|
44 int main(void)
|
nuclear@0
|
45 {
|
nuclear@0
|
46 if(init() == -1) {
|
nuclear@0
|
47 return 1;
|
nuclear@0
|
48 }
|
nuclear@0
|
49
|
nuclear@0
|
50 for(;;) {
|
nuclear@0
|
51 SDL_Event ev;
|
nuclear@0
|
52
|
nuclear@0
|
53 while(SDL_PollEvent(&ev)) {
|
nuclear@0
|
54 if(handle_event(&ev) == -1) {
|
nuclear@0
|
55 goto done;
|
nuclear@0
|
56 }
|
nuclear@0
|
57 }
|
nuclear@0
|
58
|
nuclear@0
|
59 display();
|
nuclear@0
|
60 }
|
nuclear@0
|
61
|
nuclear@0
|
62 done:
|
nuclear@0
|
63 cleanup();
|
nuclear@0
|
64 return 0;
|
nuclear@0
|
65 }
|
nuclear@0
|
66
|
nuclear@0
|
67
|
nuclear@2
|
68 int init(void)
|
nuclear@0
|
69 {
|
nuclear@2
|
70 int i, x, y;
|
nuclear@0
|
71 unsigned int flags, dcaps;
|
nuclear@0
|
72 union ovrGLConfig glcfg;
|
nuclear@0
|
73
|
nuclear@0
|
74 // this must be called before any OpenGL init according to the docs
|
nuclear@0
|
75 ovr_Initialize();
|
nuclear@0
|
76
|
nuclear@0
|
77 SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
nuclear@0
|
78
|
nuclear@0
|
79 x = y = SDL_WINDOWPOS_UNDEFINED;
|
nuclear@2
|
80 flags = SDL_WINDOW_OPENGL;
|
nuclear@0
|
81 if(!(win = SDL_CreateWindow("simple oculus example", x, y, 1280, 800, flags))) {
|
nuclear@0
|
82 fprintf(stderr, "failed to create window\n");
|
nuclear@0
|
83 return -1;
|
nuclear@0
|
84 }
|
nuclear@0
|
85 if(!(ctx = SDL_GL_CreateContext(win))) {
|
nuclear@0
|
86 fprintf(stderr, "failed to create OpenGL context\n");
|
nuclear@0
|
87 return -1;
|
nuclear@0
|
88 }
|
nuclear@0
|
89
|
nuclear@0
|
90 glewInit();
|
nuclear@0
|
91
|
nuclear@0
|
92 if(!(hmd = ovrHmd_Create(0))) {
|
nuclear@0
|
93 fprintf(stderr, "failed to open Oculus HMD, falling back to virtual debug HMD\n");
|
nuclear@2
|
94 if(!(hmd = ovrHmd_CreateDebug(ovrHmd_DK2))) {
|
nuclear@0
|
95 fprintf(stderr, "failed to create virtual debug HMD\n");
|
nuclear@0
|
96 return -1;
|
nuclear@0
|
97 }
|
nuclear@0
|
98 }
|
nuclear@0
|
99 printf("initialized HMD: %s - %s\n", hmd->Manufacturer, hmd->ProductName);
|
nuclear@0
|
100
|
nuclear@2
|
101 SDL_SetWindowSize(win, hmd->Resolution.w, hmd->Resolution.h);
|
nuclear@0
|
102
|
nuclear@0
|
103 ovrHmd_ConfigureTracking(hmd, 0xffffffff, 0);
|
nuclear@0
|
104 eyeres[0] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Left, hmd->DefaultEyeFov[0], 1.0);
|
nuclear@0
|
105 eyeres[1] = ovrHmd_GetFovTextureSize(hmd, ovrEye_Right, hmd->DefaultEyeFov[1], 1.0);
|
nuclear@0
|
106
|
nuclear@2
|
107 SDL_GetWindowSize(win, &win_width, &win_height);
|
nuclear@2
|
108
|
nuclear@2
|
109 fb_width = eyeres[0].w + eyeres[1].w;
|
nuclear@0
|
110 fb_height = eyeres[0].h > eyeres[1].h ? eyeres[0].h : eyeres[1].h;
|
nuclear@0
|
111 update_rtarg(fb_width, fb_height);
|
nuclear@0
|
112
|
nuclear@2
|
113 for(i=0; i<2; i++) {
|
nuclear@2
|
114 fb_ovr_tex[i].OGL.Header.API = ovrRenderAPI_OpenGL;
|
nuclear@2
|
115 fb_ovr_tex[i].OGL.Header.TextureSize.w = fb_tex_width;
|
nuclear@2
|
116 fb_ovr_tex[i].OGL.Header.TextureSize.h = fb_tex_height;
|
nuclear@2
|
117 fb_ovr_tex[i].OGL.Header.RenderViewport.Pos.y = 0;
|
nuclear@2
|
118 fb_ovr_tex[i].OGL.Header.RenderViewport.Size.w = fb_width / 2.0;
|
nuclear@2
|
119 fb_ovr_tex[i].OGL.Header.RenderViewport.Size.h = fb_height;
|
nuclear@2
|
120 fb_ovr_tex[i].OGL.TexId = fb_tex;
|
nuclear@2
|
121 }
|
nuclear@2
|
122 fb_ovr_tex[0].OGL.Header.RenderViewport.Pos.x = 0;
|
nuclear@2
|
123 fb_ovr_tex[1].OGL.Header.RenderViewport.Pos.x = fb_width / 2.0;
|
nuclear@2
|
124
|
nuclear@0
|
125 memset(&glcfg, 0, sizeof glcfg);
|
nuclear@0
|
126 glcfg.OGL.Header.API = ovrRenderAPI_OpenGL;
|
nuclear@0
|
127 glcfg.OGL.Header.RTSize = hmd->Resolution;
|
nuclear@0
|
128 glcfg.OGL.Header.Multisample = 1;
|
nuclear@0
|
129
|
nuclear@0
|
130 if(hmd->HmdCaps & ovrHmdCap_ExtendDesktop) {
|
nuclear@0
|
131 printf("running in \"extended desktop\" mode\n");
|
nuclear@0
|
132 } else {
|
nuclear@2
|
133 #ifdef WIN32
|
nuclear@2
|
134 void *sys_win = GetActiveWindow();
|
nuclear@2
|
135 glcfg.OGL.Window = sys_win;
|
nuclear@2
|
136 glcfg.OGL.DC = wglGetCurrentDC();
|
nuclear@2
|
137 ovrHmd_AttachToWindow(hmd, sys_win, 0, 0);
|
nuclear@2
|
138 #endif
|
nuclear@0
|
139 printf("running in \"direct-hmd\" mode\n");
|
nuclear@0
|
140 }
|
nuclear@2
|
141 ovrHmd_SetEnabledCaps(hmd, ovrHmdCap_LowPersistence | ovrHmdCap_DynamicPrediction);
|
nuclear@0
|
142
|
nuclear@2
|
143 dcaps = ovrDistortionCap_Chromatic | ovrDistortionCap_Vignette | ovrDistortionCap_TimeWarp;
|
nuclear@0
|
144 if(!ovrHmd_ConfigureRendering(hmd, &glcfg.Config, dcaps, hmd->DefaultEyeFov, eye_rdesc)) {
|
nuclear@0
|
145 fprintf(stderr, "failed to configure distortion renderer\n");
|
nuclear@0
|
146 }
|
nuclear@0
|
147
|
nuclear@2
|
148 /* ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); */
|
nuclear@0
|
149
|
nuclear@0
|
150
|
nuclear@0
|
151 glEnable(GL_DEPTH_TEST);
|
nuclear@0
|
152 glEnable(GL_CULL_FACE);
|
nuclear@0
|
153 glEnable(GL_LIGHTING);
|
nuclear@0
|
154 glEnable(GL_LIGHT0);
|
nuclear@0
|
155
|
nuclear@2
|
156 glClearColor(0.5, 0.05, 0.05, 1);
|
nuclear@0
|
157
|
nuclear@0
|
158 return 0;
|
nuclear@0
|
159 }
|
nuclear@0
|
160
|
nuclear@2
|
161 void cleanup(void)
|
nuclear@0
|
162 {
|
nuclear@0
|
163 if(hmd) {
|
nuclear@0
|
164 ovrHmd_Destroy(hmd);
|
nuclear@0
|
165 }
|
nuclear@0
|
166 ovr_Shutdown();
|
nuclear@0
|
167
|
nuclear@0
|
168 SDL_Quit();
|
nuclear@0
|
169 }
|
nuclear@0
|
170
|
nuclear@2
|
171 void display(void)
|
nuclear@0
|
172 {
|
nuclear@2
|
173 int i;
|
nuclear@2
|
174 ovrMatrix4f proj;
|
nuclear@2
|
175 ovrPosef pose[2];
|
nuclear@2
|
176
|
nuclear@2
|
177 ovrHmd_BeginFrame(hmd, 0);
|
nuclear@2
|
178
|
nuclear@2
|
179 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
nuclear@0
|
180 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@0
|
181
|
nuclear@2
|
182 /* for each eye ... */
|
nuclear@2
|
183 for(i=0; i<2; i++) {
|
nuclear@2
|
184 int eye = hmd->EyeRenderOrder[i];
|
nuclear@2
|
185
|
nuclear@2
|
186 /* vport0(0, 0, width/2, height), vport1(width/2, 0, width/2, height) */
|
nuclear@2
|
187 glViewport(eye == 0 ? 0 : fb_width / 2, 0, fb_width / 2, fb_height);
|
nuclear@2
|
188
|
nuclear@2
|
189 proj = ovrMatrix4f_Projection(hmd->DefaultEyeFov[eye], 0.5, 500.0, 1);
|
nuclear@2
|
190 glMatrixMode(GL_PROJECTION);
|
nuclear@2
|
191 glLoadMatrixf(proj.M[0]);
|
nuclear@2
|
192
|
nuclear@2
|
193 pose[eye] = ovrHmd_GetEyePose(hmd, eye);
|
nuclear@2
|
194 glMatrixMode(GL_MODELVIEW);
|
nuclear@2
|
195 /* TODO: get HMD orientation data and use them */
|
nuclear@2
|
196 glTranslatef(0, -ovrHmd_GetFloat(hmd, OVR_KEY_EYE_HEIGHT, 1.65), 0);
|
nuclear@2
|
197
|
nuclear@2
|
198 draw_scene();
|
nuclear@2
|
199 }
|
nuclear@2
|
200
|
nuclear@2
|
201 glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
nuclear@2
|
202 glViewport(0, 0, win_width, win_height);
|
nuclear@2
|
203
|
nuclear@2
|
204 ovrHmd_EndFrame(hmd, pose, &fb_ovr_tex[0].Texture);
|
nuclear@2
|
205
|
nuclear@2
|
206 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
207 }
|
nuclear@2
|
208
|
nuclear@2
|
209 void draw_scene(void)
|
nuclear@2
|
210 {
|
nuclear@2
|
211 int i;
|
nuclear@2
|
212 float lpos[] = {0, 5, 0, 1};
|
nuclear@2
|
213 glLightfv(GL_LIGHT0, GL_POSITION, lpos);
|
nuclear@2
|
214
|
nuclear@2
|
215 glTranslatef(0, 5, 0);
|
nuclear@2
|
216 draw_box(20, 10, 20, -1.0);
|
nuclear@2
|
217
|
nuclear@2
|
218 for(i=0; i<4; i++) {
|
nuclear@2
|
219 glPushMatrix();
|
nuclear@2
|
220 if(i & 1) {
|
nuclear@2
|
221 glTranslatef(0, 0, i & 2 ? 7.5 : -7.5);
|
nuclear@2
|
222 } else {
|
nuclear@2
|
223 glTranslatef(i & 2 ? 7.5 : -7.5, 0, 0);
|
nuclear@2
|
224 }
|
nuclear@2
|
225 draw_box(3, 0, 3, 1.0);
|
nuclear@2
|
226 glPopMatrix();
|
nuclear@2
|
227 }
|
nuclear@2
|
228 }
|
nuclear@2
|
229
|
nuclear@2
|
230 void draw_box(float xsz, float ysz, float zsz, float norm_sign)
|
nuclear@2
|
231 {
|
nuclear@2
|
232 glMatrixMode(GL_MODELVIEW);
|
nuclear@2
|
233 glScalef(xsz * 0.5, ysz * 0.5, zsz * 0.5);
|
nuclear@2
|
234
|
nuclear@2
|
235 if(norm_sign < 0.0) {
|
nuclear@2
|
236 glFrontFace(GL_CW);
|
nuclear@2
|
237 }
|
nuclear@2
|
238
|
nuclear@2
|
239 glBegin(GL_QUADS);
|
nuclear@2
|
240 glNormal3f(0, 0, 1 * norm_sign);
|
nuclear@2
|
241 glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
|
nuclear@2
|
242 glTexCoord2f(1, 0); glVertex3f(1, -1, 1);
|
nuclear@2
|
243 glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
|
nuclear@2
|
244 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
|
nuclear@2
|
245 glNormal3f(1 * norm_sign, 0, 0);
|
nuclear@2
|
246 glTexCoord2f(0, 0); glVertex3f(1, -1, 1);
|
nuclear@2
|
247 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
|
nuclear@2
|
248 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
|
nuclear@2
|
249 glTexCoord2f(0, 1); glVertex3f(1, 1, 1);
|
nuclear@2
|
250 glNormal3f(0, 0, -1 * norm_sign);
|
nuclear@2
|
251 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
|
nuclear@2
|
252 glTexCoord2f(1, 0); glVertex3f(-1, -1, -1);
|
nuclear@2
|
253 glTexCoord2f(1, 1); glVertex3f(-1, 1, -1);
|
nuclear@2
|
254 glTexCoord2f(0, 1); glVertex3f(1, 1, -1);
|
nuclear@2
|
255 glNormal3f(-1 * norm_sign, 0, 0);
|
nuclear@2
|
256 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
|
nuclear@2
|
257 glTexCoord2f(1, 0); glVertex3f(-1, -1, 1);
|
nuclear@2
|
258 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
|
nuclear@2
|
259 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
|
nuclear@2
|
260 glNormal3f(0, 1 * norm_sign, 0);
|
nuclear@2
|
261 glTexCoord2f(0, 0); glVertex3f(-1, 1, 1);
|
nuclear@2
|
262 glTexCoord2f(1, 0); glVertex3f(1, 1, 1);
|
nuclear@2
|
263 glTexCoord2f(1, 1); glVertex3f(1, 1, -1);
|
nuclear@2
|
264 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
|
nuclear@2
|
265 glNormal3f(0, -1 * norm_sign, 0);
|
nuclear@2
|
266 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
|
nuclear@2
|
267 glTexCoord2f(1, 0); glVertex3f(1, -1, -1);
|
nuclear@2
|
268 glTexCoord2f(1, 1); glVertex3f(1, -1, 1);
|
nuclear@2
|
269 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
|
nuclear@2
|
270 glEnd();
|
nuclear@2
|
271
|
nuclear@2
|
272 glFrontFace(GL_CCW);
|
nuclear@0
|
273 }
|
nuclear@0
|
274
|
nuclear@0
|
275 void update_rtarg(int width, int height)
|
nuclear@0
|
276 {
|
nuclear@0
|
277 if(!fbo) {
|
nuclear@0
|
278 glGenFramebuffers(1, &fbo);
|
nuclear@0
|
279 glGenTextures(1, &fb_tex);
|
nuclear@0
|
280 glGenRenderbuffers(1, &fb_depth);
|
nuclear@0
|
281
|
nuclear@0
|
282 glBindTexture(GL_TEXTURE_2D, fb_tex);
|
nuclear@0
|
283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
nuclear@0
|
284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@0
|
285 }
|
nuclear@0
|
286
|
nuclear@0
|
287 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
nuclear@0
|
288
|
nuclear@0
|
289 fb_tex_width = next_pow2(width);
|
nuclear@0
|
290 fb_tex_height = next_pow2(height);
|
nuclear@0
|
291
|
nuclear@0
|
292 glBindTexture(GL_TEXTURE_2D, fb_tex);
|
nuclear@0
|
293 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, fb_tex_width, fb_tex_height, 0,
|
nuclear@0
|
294 GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
nuclear@0
|
295 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
|
nuclear@0
|
296
|
nuclear@0
|
297 glBindRenderbuffer(GL_RENDERBUFFER, fb_depth);
|
nuclear@0
|
298 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, fb_tex_width, fb_tex_height);
|
nuclear@0
|
299 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fb_depth);
|
nuclear@0
|
300
|
nuclear@0
|
301 if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
nuclear@0
|
302 fprintf(stderr, "incomplete framebuffer!\n");
|
nuclear@0
|
303 }
|
nuclear@0
|
304
|
nuclear@0
|
305 glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
nuclear@0
|
306 printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height);
|
nuclear@0
|
307 }
|
nuclear@0
|
308
|
nuclear@0
|
309 int handle_event(SDL_Event *ev)
|
nuclear@0
|
310 {
|
nuclear@0
|
311 switch(ev->type) {
|
nuclear@0
|
312 case SDL_KEYDOWN:
|
nuclear@0
|
313 case SDL_KEYUP:
|
nuclear@0
|
314 if(key_event(ev->key.keysym.sym, ev->key.state == SDL_PRESSED) == -1) {
|
nuclear@0
|
315 return -1;
|
nuclear@0
|
316 }
|
nuclear@0
|
317 break;
|
nuclear@0
|
318
|
nuclear@0
|
319 default:
|
nuclear@0
|
320 break;
|
nuclear@0
|
321 }
|
nuclear@0
|
322
|
nuclear@0
|
323 return 0;
|
nuclear@0
|
324 }
|
nuclear@0
|
325
|
nuclear@0
|
326 int key_event(int key, int state)
|
nuclear@0
|
327 {
|
nuclear@0
|
328 if(state) {
|
nuclear@0
|
329 switch(key) {
|
nuclear@0
|
330 case 27:
|
nuclear@0
|
331 return -1;
|
nuclear@0
|
332
|
nuclear@0
|
333 default:
|
nuclear@0
|
334 break;
|
nuclear@0
|
335 }
|
nuclear@0
|
336 }
|
nuclear@0
|
337 return 0;
|
nuclear@0
|
338 }
|
nuclear@2
|
339
|
nuclear@2
|
340 unsigned int next_pow2(unsigned int x)
|
nuclear@2
|
341 {
|
nuclear@2
|
342 x -= 1;
|
nuclear@2
|
343 x |= x >> 1;
|
nuclear@2
|
344 x |= x >> 2;
|
nuclear@2
|
345 x |= x >> 4;
|
nuclear@2
|
346 x |= x >> 8;
|
nuclear@2
|
347 x |= x >> 16;
|
nuclear@2
|
348 return x + 1;
|
nuclear@2
|
349 } |