-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmain.cpp
More file actions
1558 lines (1300 loc) · 56.4 KB
/
Copy pathmain.cpp
File metadata and controls
1558 lines (1300 loc) · 56.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Original FreeGLUT framework by Song Ho Ahn (song.ahn@gmail.com)
// Reverse engineering, conversion, and updating:
// Finn Sinclair (fns2@illinois.edu)
// Joseph Ravichandran (jpr3@illinois.edu)
// in order to get function prototypes from glext.h, define GL_GLEXT_PROTOTYPES before including glext.h
#define GL_GLEXT_PROTOTYPES
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#include <GL/freeglut.h>
#endif
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include "glext.h"
#include "glInfo.h" // glInfo struct
#include "Timer.h"
#include "utils/algebra.h"
#include "utils/hmd.h"
#include "image.h"
using std::stringstream;
using std::string;
using std::cout;
using std::endl;
using std::ends;
#define OPENGL_VERSION_MAJOR 4
#define OPENGL_VERSION_MINOR 3
#define GLSL_VERSION "430 core"
#define GLSL_EXTENSIONS "#extension GL_EXT_shader_io_blocks : enable\n"
// GLUT CALLBACK functions ////////////////////////////////////////////////////
void displayCB();
void reshapeCB(int w, int h);
void timerCB(int millisec);
void idleCB();
void mouseCB(int button, int stat, int x, int y);
void mouseMotionCB(int x, int y);
void init_images(const char* fname);
// CALLBACK function when exit() called ///////////////////////////////////////
void exitCB();
// function declearations /////////////////////////////////////////////////////
void initGL();
int initGLUT(int argc, char **argv);
bool initSharedMem(const char* fname);
void clearSharedMem();
void drawString(const char *str, int x, int y, float color[4], void *font);
void drawString3D(const char *str, float pos[3], float color[4], void *font);
// FBO utils
bool checkFramebufferStatus(GLuint fbo);
void printFramebufferInfo(GLuint fbo);
std::string convertInternalFormatToString(GLenum format);
std::string getTextureParameters(GLuint id);
std::string getRenderbufferParameters(GLuint id);
// constants
const int SCREEN_WIDTH = 2560;
const int SCREEN_HEIGHT = 1440;
const float CAMERA_DISTANCE = 6.0f;
const int TEXT_WIDTH = 8;
const int TEXT_HEIGHT = 13;
const int TEXTURE_WIDTH = 2560; // NOTE: texture size cannot be larger than
const int TEXTURE_HEIGHT = 1440; // the rendering window size in non-FBO mode
const int NUM_EYES = 2;
const int NUM_COLOR_CHANNELS = 3;
// global variables
GLuint fboId; // ID of FBO
GLuint textureId; // ID of texture
GLuint rboColorId, rboDepthId; // IDs of Renderbuffer objects
void *font = GLUT_BITMAP_8_BY_13;
int screenWidth;
int screenHeight;
bool mouseLeftDown;
bool mouseRightDown;
float mouseX, mouseY;
float cameraAngleX;
float cameraAngleY;
float cameraDistance;
bool fboSupported;
bool fboUsed;
int fboSampleCount;
int drawMode;
Timer timer, tApp, tWarp;
float playTime; // to compute rotation angle
float renderToTextureTime; // elapsed time for render-to-texture
float timewarpTime; // elapsed time for timewarp
// Global HMD and body information
hmd_info_t hmd_info;
body_info_t body_info;
// Distortion shaders and shader program handles
GLuint tw_vertex_shader;
GLuint tw_frag_shader;
GLuint tw_shader_program;
// Eye sampler array
GLuint eye_sampler_0;
GLuint eye_sampler_1;
// Eye index uniform
GLuint tw_eye_index_unif;
// VAOs
GLuint tw_vao;
GLuint basic_vao;
// Position and UV attribute locations
GLuint distortion_pos_attr;
GLuint distortion_uv0_attr;
GLuint distortion_uv1_attr;
GLuint distortion_uv2_attr;
// Distortion mesh information
GLuint num_distortion_vertices;
GLuint num_distortion_indices;
// Distortion mesh CPU buffers and GPU VBO handles
mesh_coord3d_t* distortion_positions;
GLuint distortion_positions_vbo;
GLuint* distortion_indices;
GLuint distortion_indices_vbo;
uv_coord_t* distortion_uv0;
GLuint distortion_uv0_vbo;
uv_coord_t* distortion_uv1;
GLuint distortion_uv1_vbo;
uv_coord_t* distortion_uv2;
GLuint distortion_uv2_vbo;
// Handles to the start and end timewarp
// transform matrices (3x4 uniforms)
GLuint tw_start_transform_unif;
GLuint tw_end_transform_unif;
// Basic perspective projection matrix
ksMatrix4x4f basicProjection;
// Basic shaders and basic shader program
GLuint basic_vertex_shader;
GLuint basic_frag_shader;
GLuint basic_shader_program;
// Position and UV attribute locations
GLuint basic_pos_attr;
GLuint basic_uv_attr;
// Position and UV vbo's
GLuint basic_pos_vbo;
GLuint basic_uv_vbo;
GLuint basic_indices_vbo;
// Texture Image objects
Image* prerendered_image;
GLuint prerendered_image_tex;
const char* const timeWarpSpatialVertexProgramGLSL =
"#version " GLSL_VERSION "\n"
"uniform highp mat3x4 TimeWarpStartTransform;\n"
"uniform highp mat3x4 TimeWarpEndTransform;\n"
"in highp vec3 vertexPosition;\n"
"in highp vec2 vertexUv1;\n"
"out mediump vec2 fragmentUv1;\n"
"out gl_PerVertex { vec4 gl_Position; };\n"
"out mediump vec2 viz;\n"
"void main( void )\n"
"{\n"
" gl_Position = vec4( vertexPosition, 1.0 );\n"
"\n"
" float displayFraction = vertexPosition.x * 0.5 + 0.5;\n" // landscape left-to-right
"\n"
" vec3 startUv1 = vec4( vertexUv1, -1.0, 1.0 ) * TimeWarpStartTransform;\n"
" vec3 endUv1 = vec4( vertexUv1, -1.0, 1.0 ) * TimeWarpEndTransform;\n"
" vec3 curUv1 = mix( startUv1, endUv1, displayFraction );\n"
" fragmentUv1 = curUv1.xy * ( 1.0 / max( curUv1.z, 0.00001 ) );\n"
" viz = vertexUv1.xy;\n"
"}\n";
const char* const timeWarpSpatialFragmentProgramGLSL =
"#version " GLSL_VERSION "\n"
"uniform highp sampler2D Texture;\n"
"in mediump vec2 fragmentUv1;\n"
"in mediump vec2 viz;\n"
"out lowp vec4 outColor;\n"
"void main()\n"
"{\n"
//" outColor = texture( Texture, fragmentUv1 );\n"
" outColor = vec4(fract(fragmentUv1.x * 4.), fract(fragmentUv1.y * 4.), 1.0, 1.0);\n"
"}\n";
const char* const timeWarpChromaticVertexProgramGLSL =
"#version " GLSL_VERSION "\n"
"uniform highp mat3x4 TimeWarpStartTransform;\n"
"uniform highp mat3x4 TimeWarpEndTransform;\n"
"in highp vec3 vertexPosition;\n"
"in highp vec2 vertexUv0;\n"
"in highp vec2 vertexUv1;\n"
"in highp vec2 vertexUv2;\n"
"out mediump vec2 fragmentUv0;\n"
"out mediump vec2 fragmentUv1;\n"
"out mediump vec2 fragmentUv2;\n"
"out gl_PerVertex { vec4 gl_Position; };\n"
"void main( void )\n"
"{\n"
" gl_Position = vec4( vertexPosition, 1.0 );\n"
"\n"
" float displayFraction = vertexPosition.x * 0.5 + 0.5;\n" // landscape left-to-right
"\n"
" vec3 startUv0 = vec4( vertexUv0, -1, 1 ) * TimeWarpStartTransform;\n"
" vec3 startUv1 = vec4( vertexUv1, -1, 1 ) * TimeWarpStartTransform;\n"
" vec3 startUv2 = vec4( vertexUv2, -1, 1 ) * TimeWarpStartTransform;\n"
"\n"
" vec3 endUv0 = vec4( vertexUv0, -1, 1 ) * TimeWarpEndTransform;\n"
" vec3 endUv1 = vec4( vertexUv1, -1, 1 ) * TimeWarpEndTransform;\n"
" vec3 endUv2 = vec4( vertexUv2, -1, 1 ) * TimeWarpEndTransform;\n"
"\n"
" vec3 curUv0 = mix( startUv0, endUv0, displayFraction );\n"
" vec3 curUv1 = mix( startUv1, endUv1, displayFraction );\n"
" vec3 curUv2 = mix( startUv2, endUv2, displayFraction );\n"
"\n"
" fragmentUv0 = curUv0.xy * ( 1.0 / max( curUv0.z, 0.00001 ) );\n"
" fragmentUv1 = curUv1.xy * ( 1.0 / max( curUv1.z, 0.00001 ) );\n"
" fragmentUv2 = curUv2.xy * ( 1.0 / max( curUv2.z, 0.00001 ) );\n"
"}\n";
const char* const timeWarpChromaticFragmentProgramGLSL =
"#version " GLSL_VERSION "\n"
"uniform int ArrayLayer;\n"
"uniform highp sampler2DArray Texture;\n"
"in mediump vec2 fragmentUv0;\n"
"in mediump vec2 fragmentUv1;\n"
"in mediump vec2 fragmentUv2;\n"
"out lowp vec4 outColor;\n"
"void main()\n"
"{\n"
" outColor.r = texture( Texture, vec3( fragmentUv0, ArrayLayer ) ).r;\n"
" outColor.g = texture( Texture, vec3( fragmentUv1, ArrayLayer ) ).g;\n"
" outColor.b = texture( Texture, vec3( fragmentUv2, ArrayLayer ) ).b;\n"
" outColor.a = 1.0;\n"
"}\n";
const char* const timeWarpChromaticFragmentDebugProgramGLSL =
"#version " GLSL_VERSION "\n"
"uniform int ArrayLayer;\n"
"uniform highp sampler2DArray Texture;\n"
"in mediump vec2 fragmentUv0;\n"
"in mediump vec2 fragmentUv1;\n"
"in mediump vec2 fragmentUv2;\n"
"out lowp vec4 outColor;\n"
"void main()\n"
"{\n"
" float chess0 = floor(fragmentUv0.x * 5.0) + floor(fragmentUv0.y * 5.0);"
" chess0 = fract(chess0 * 0.5);"
" float chess1 = floor(fragmentUv1.x * 5.0) + floor(fragmentUv1.y * 5.0);"
" chess1 = fract(chess1 * 0.5);"
" float chess2 = floor(fragmentUv2.x * 5.0) + floor(fragmentUv2.y * 5.0);"
" chess2 = fract(chess2 * 0.5);"
" outColor.r = chess0;\n"
" outColor.g = chess1;\n"
" outColor.b = chess2;\n"
" if(fragmentUv0.x > 1.0 || fragmentUv0.x < 0.0 || fragmentUv0.y > 1.0 || fragmentUv0.y < 0.0)\n"
" outColor = vec4(vec3(0.0), 1.0);\n"
"}\n";
const char* const basicVertexShader =
"#version " GLSL_VERSION "\n"
"in vec3 vertexPosition;\n"
"in vec2 vertexUV;\n"
"out vec2 vUV;\n"
"out gl_PerVertex { vec4 gl_Position; };\n"
"void main()\n"
"{\n"
" gl_Position = vec4( vertexPosition, 1.0 );\n"
" vUV = vertexUV;\n"
"}\n";
const char* const basicFragmentShader =
"#version " GLSL_VERSION "\n"
"uniform highp sampler2D Texture;\n"
"in vec2 vUV;\n"
"out lowp vec4 outcolor;\n"
"void main()\n"
"{\n"
" outcolor = vec4(vUV.x, vUV.y, 1.0, 1.0);\n"
//" outcolor = vec4(0.0,0.0,0.0, 1.0);\n"
" outcolor = texture(Texture, vUV);\n"
"}\n";
GLfloat cube_vertices[24] = { // Coordinates for the vertices of a cube.
1,1,1, 1,1,-1, 1,-1,-1, 1,-1,1,
-1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1 };
GLfloat cube_colors[24] = { // An RGB color value for each vertex
1,1,1, 1,0,0, 1,1,0, 0,1,0,
0,0,1, 1,0,1, 0,0,0, 0,1,1 };
GLuint cube_indices[24] = { // Vertex number for the six faces.
0,1,2,3, 0,3,7,4, 0,4,5,1,
6,2,1,5, 6,5,4,7, 6,7,3,2 };
GLfloat plane_vertices[8] = { // Coordinates for the vertices of a plane.
-1, 1, 1, 1,
-1, -1, 1, -1 };
GLfloat plane_uvs[8] = { // UVs for plane
0, 1, 1, 1,
0, 0, 1, 0 };
GLuint plane_indices[6] = { // Plane indices
0,2,3, 1,0,3 };
void GetHmdViewMatrixForTime( ksMatrix4x4f * viewMatrix, float time )
{
// FIXME: use double?
const float offset = time * 2.0f;
const float degrees = 10.0f;
const float degreesX = sinf( offset ) * degrees;
const float degreesY = cosf( offset ) * degrees;
ksMatrix4x4f_CreateRotation( viewMatrix, degreesX, degreesY, 0.0f );
}
void BuildDistortionMeshes( mesh_coord2d_t * distort_coords[NUM_EYES][NUM_COLOR_CHANNELS], hmd_info_t * hmdInfo )
{
const float horizontalShiftMeters = ( hmdInfo->lensSeparationInMeters / 2 ) - ( hmdInfo->visibleMetersWide / 4 );
const float horizontalShiftView = horizontalShiftMeters / ( hmdInfo->visibleMetersWide / 2 );
for ( int eye = 0; eye < NUM_EYES; eye++ )
{
for ( int y = 0; y <= hmdInfo->eyeTilesHigh; y++ )
{
const float yf = 1.0f - (float)y / (float)hmdInfo->eyeTilesHigh;
for ( int x = 0; x <= hmdInfo->eyeTilesWide; x++ )
{
const float xf = (float)x / (float)hmdInfo->eyeTilesWide;
const float in[2] = { ( eye ? -horizontalShiftView : horizontalShiftView ) + xf, yf };
const float ndcToPixels[2] = { hmdInfo->visiblePixelsWide * 0.25f, hmdInfo->visiblePixelsHigh * 0.5f };
const float pixelsToMeters[2] = { hmdInfo->visibleMetersWide / hmdInfo->visiblePixelsWide, hmdInfo->visibleMetersHigh / hmdInfo->visiblePixelsHigh };
float theta[2];
for ( int i = 0; i < 2; i++ )
{
const float unit = in[i];
const float ndc = 2.0f * unit - 1.0f;
const float pixels = ndc * ndcToPixels[i];
const float meters = pixels * pixelsToMeters[i];
const float tanAngle = meters / hmdInfo->metersPerTanAngleAtCenter;
theta[i] = tanAngle;
}
const float rsq = theta[0] * theta[0] + theta[1] * theta[1];
const float scale = EvaluateCatmullRomSpline( rsq, hmdInfo->K, hmdInfo->numKnots );
const float chromaScale[NUM_COLOR_CHANNELS] =
{
scale * ( 1.0f + hmdInfo->chromaticAberration[0] + rsq * hmdInfo->chromaticAberration[1] ),
scale,
scale * ( 1.0f + hmdInfo->chromaticAberration[2] + rsq * hmdInfo->chromaticAberration[3] )
};
const int vertNum = y * ( hmdInfo->eyeTilesWide + 1 ) + x;
for ( int channel = 0; channel < NUM_COLOR_CHANNELS; channel++ )
{
distort_coords[eye][channel][vertNum].x = chromaScale[channel] * theta[0];
distort_coords[eye][channel][vertNum].y = chromaScale[channel] * theta[1];
}
}
}
}
}
void BuildTimewarp(hmd_info_t* hmdInfo){
// Calculate the number of vertices+indices in the distortion mesh.
num_distortion_vertices = ( hmdInfo->eyeTilesHigh + 1 ) * ( hmdInfo->eyeTilesWide + 1 );
num_distortion_indices = hmdInfo->eyeTilesHigh * hmdInfo->eyeTilesWide * 6;
// Allocate memory for the elements/indices array.
distortion_indices = (GLuint*) malloc(num_distortion_indices * sizeof(GLuint));
// This is just a simple grid/plane index array, nothing fancy.
// Same for both eye distortions, too!
for ( int y = 0; y < hmdInfo->eyeTilesHigh; y++ )
{
for ( int x = 0; x < hmdInfo->eyeTilesWide; x++ )
{
const int offset = ( y * hmdInfo->eyeTilesWide + x ) * 6;
distortion_indices[offset + 0] = (GLuint)( ( y + 0 ) * ( hmdInfo->eyeTilesWide + 1 ) + ( x + 0 ) );
distortion_indices[offset + 1] = (GLuint)( ( y + 1 ) * ( hmdInfo->eyeTilesWide + 1 ) + ( x + 0 ) );
distortion_indices[offset + 2] = (GLuint)( ( y + 0 ) * ( hmdInfo->eyeTilesWide + 1 ) + ( x + 1 ) );
distortion_indices[offset + 3] = (GLuint)( ( y + 0 ) * ( hmdInfo->eyeTilesWide + 1 ) + ( x + 1 ) );
distortion_indices[offset + 4] = (GLuint)( ( y + 1 ) * ( hmdInfo->eyeTilesWide + 1 ) + ( x + 0 ) );
distortion_indices[offset + 5] = (GLuint)( ( y + 1 ) * ( hmdInfo->eyeTilesWide + 1 ) + ( x + 1 ) );
}
}
// Allocate memory for the distortion coordinates.
// These are NOT the actual distortion mesh's vertices,
// they are calculated distortion grid coefficients
// that will be used to set the actual distortion mesh's UV space.
mesh_coord2d_t* tw_mesh_base_ptr = (mesh_coord2d_t *) malloc( NUM_EYES * NUM_COLOR_CHANNELS * num_distortion_vertices * sizeof( mesh_coord2d_t ) );
// Set the distortion coordinates as a series of arrays
// that will be written into by the BuildDistortionMeshes() function.
mesh_coord2d_t * distort_coords[NUM_EYES][NUM_COLOR_CHANNELS] =
{
{ tw_mesh_base_ptr + 0 * num_distortion_vertices, tw_mesh_base_ptr + 1 * num_distortion_vertices, tw_mesh_base_ptr + 2 * num_distortion_vertices },
{ tw_mesh_base_ptr + 3 * num_distortion_vertices, tw_mesh_base_ptr + 4 * num_distortion_vertices, tw_mesh_base_ptr + 5 * num_distortion_vertices }
};
BuildDistortionMeshes( distort_coords, hmdInfo );
// Allocate memory for position and UV CPU buffers.
for(int eye = 0; eye < NUM_EYES; eye++){
distortion_positions = (mesh_coord3d_t *) malloc(NUM_EYES * num_distortion_vertices * sizeof(mesh_coord3d_t));
distortion_uv0 = (uv_coord_t *) malloc(NUM_EYES * num_distortion_vertices * sizeof(uv_coord_t));
distortion_uv1 = (uv_coord_t *) malloc(NUM_EYES * num_distortion_vertices * sizeof(uv_coord_t));
distortion_uv2 = (uv_coord_t *) malloc(NUM_EYES * num_distortion_vertices * sizeof(uv_coord_t));
}
for ( int eye = 0; eye < NUM_EYES; eye++ )
{
for ( int y = 0; y <= hmdInfo->eyeTilesHigh; y++ )
{
for ( int x = 0; x <= hmdInfo->eyeTilesWide; x++ )
{
const int index = y * ( hmdInfo->eyeTilesWide + 1 ) + x;
// Set the physical distortion mesh coordinates. These are rectangular/gridlike, not distorted.
// The distortion is handled by the UVs, not the actual mesh coordinates!
distortion_positions[eye * num_distortion_vertices + index].x = ( -1.0f + eye + ( (float)x / hmdInfo->eyeTilesWide ) );
distortion_positions[eye * num_distortion_vertices + index].y = ( -1.0f + 2.0f * ( ( hmdInfo->eyeTilesHigh - (float)y ) / hmdInfo->eyeTilesHigh ) *
( (float)( hmdInfo->eyeTilesHigh * hmdInfo->tilePixelsHigh ) / hmdInfo->displayPixelsHigh ) );
distortion_positions[eye * num_distortion_vertices + index].z = 0.0f;
// Use the previously-calculated distort_coords to set the UVs on the distortion mesh
distortion_uv0[eye * num_distortion_vertices + index].u = distort_coords[eye][0][index].x;
distortion_uv0[eye * num_distortion_vertices + index].v = distort_coords[eye][0][index].y;
distortion_uv1[eye * num_distortion_vertices + index].u = distort_coords[eye][1][index].x;
distortion_uv1[eye * num_distortion_vertices + index].v = distort_coords[eye][1][index].y;
distortion_uv2[eye * num_distortion_vertices + index].u = distort_coords[eye][2][index].x;
distortion_uv2[eye * num_distortion_vertices + index].v = distort_coords[eye][2][index].y;
}
}
}
// Construct a basic perspective projection
ksMatrix4x4f_CreateProjectionFov( &basicProjection, 40.0f, 40.0f, 40.0f, 40.0f, 0.1f, 0.0f );
// This was just temporary.
free(tw_mesh_base_ptr);
return;
}
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
GLenum err;
if (argc < 2) {
fprintf(stderr, "Usage: %s [image]\n", argv[0]);
exit(1);
}
// init global vars
initSharedMem(argv[1]);
// register exit callback
atexit(exitCB);
// init GLUT and GL
initGLUT(argc, argv);
initGL();
err = glGetError();
if(err){
printf("main, error after initGL: %x\n", err);
}
// Creating a texture object for the FBO to be mapped into.
// This texture will be used to perform the timewarp and lens distortion process.
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D_ARRAY, textureId);
// Set the texture parameters for the texture that the FBO will be
// mapped into.
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
//glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
//glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
// Unbind the texture, we'll re-bind it later when we perform the distortion
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
// Create the FBO, and save the handle.
glGenFramebuffers(1, &fboId);
// Bind the FBO as the active framebuffer.
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
err = glGetError();
if(err){
printf("main, error after creating and binding fbo: %x\n", err);
}
// create a renderbuffer object to store depth info
// NOTE: A depth renderable image should be attached the FBO for depth test.
// If we don't attach a depth renderable image to the FBO, then
// the rendering output will be corrupted because of missing depth test.
// If you also need stencil test for your rendering, then you must
// attach additional image to the stencil attachement point, too.
glGenRenderbuffers(1, &rboDepthId);
glBindRenderbuffer(GL_RENDERBUFFER, rboDepthId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
//glRenderbufferStorageMultisample(GL_RENDERBUFFER, fboSampleCount, GL_DEPTH_COMPONENT, TEXTURE_WIDTH, TEXTURE_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, textureId);
// Attach the texture we created earlier to the FBO.
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureId, 0, 0);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
err = glGetError();
if(err){
printf("main, error2: %x\n", err);
}
// attach a renderbuffer to depth attachment point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepthId);
err = glGetError();
if(err){
printf("main, error3: %x\n", err);
}
// check FBO status
//printFramebufferInfo(fboId);
//bool status = checkFramebufferStatus(fboId);
//if(!status)
//fboUsed = false;
err = glGetError();
if(err){
printf("main, error after fbo things: %x\n", err);
}
// Unbind the framebuffer, so the distortion can render
// to the main framebuffer (aka, the screen)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// start timer
timer.start();
// the last GLUT call (LOOP)
// window will be shown and display callback is triggered by events
// NOTE: this call never return main().
glutMainLoop(); /* Start GLUT event-processing loop */
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// initialize GLUT for windowing
///////////////////////////////////////////////////////////////////////////////
int initGLUT(int argc, char **argv)
{
// GLUT stuff for windowing
// initialization openGL window.
// It must be called before any other GLUT routine.
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL); // display mode
glutInitWindowSize(screenWidth, screenHeight); // window size
glutInitWindowPosition(100, 100); // window location
glutInitContextVersion(4, 3);
glutInitContextProfile( GLUT_CORE_PROFILE );
// finally, create a window with openGL context
// Window will not displayed until glutMainLoop() is called
// It returns a unique ID.
int handle = glutCreateWindow(argv[0]); // param is the title of window
// register GLUT callback functions
glutDisplayFunc(displayCB);
//glutTimerFunc(33, timerCB, 33); // redraw only every given millisec
glutIdleFunc(idleCB); // redraw whenever system is idle
glutReshapeFunc(reshapeCB);
glutMouseFunc(mouseCB);
glutMotionFunc(mouseMotionCB);
return handle;
}
// Return: handle to shader program
GLuint init_and_link_shader (const char* vertex_shader, const char* fragment_shader) {
GLint result, vertex_shader_handle, fragment_shader_handle, shader_program;
vertex_shader_handle = glCreateShader(GL_VERTEX_SHADER);
GLint vshader_len = strlen(vertex_shader);
glShaderSource(vertex_shader_handle, 1, &vertex_shader, &vshader_len);
glCompileShader(vertex_shader_handle);
glGetShaderiv(vertex_shader_handle, GL_COMPILE_STATUS, &result);
if ( result == GL_FALSE )
{
GLchar msg[4096];
GLsizei length;
glGetShaderInfoLog( vertex_shader_handle, sizeof( msg ), &length, msg );
printf( "1 Error: %s\n", msg);
}
//////////////////////////////////////////////////////////
// Create and compile timewarp distortion fragment shader
GLint fragResult = GL_FALSE;
fragment_shader_handle = glCreateShader(GL_FRAGMENT_SHADER);
GLint fshader_len = strlen(fragment_shader);
glShaderSource(fragment_shader_handle, 1, &fragment_shader, &fshader_len);
glCompileShader(fragment_shader_handle);
if(glGetError()){
printf("Fragment shader compilation failed\n");
}
glGetShaderiv(fragment_shader_handle, GL_COMPILE_STATUS, &fragResult);
if ( fragResult == GL_FALSE )
{
GLchar msg[4096];
GLsizei length;
glGetShaderInfoLog( fragment_shader_handle, sizeof( msg ), &length, msg );
printf( "2 Error: %s\n", msg);
}
// Create program and link shaders
shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader_handle);
glAttachShader(shader_program, fragment_shader_handle);
if(glGetError()){
printf("AttachShader or createProgram failed\n");
}
///////////////////
// Link and verify
glLinkProgram(shader_program);
if(glGetError()){
printf("Linking failed\n");
}
glGetProgramiv(shader_program, GL_LINK_STATUS, &result);
GLenum err = glGetError();
if(err){
printf("initGL, error getting link status, %x", err);
}
if ( result == GL_FALSE )
{
GLchar msg[4096];
GLsizei length;
glGetShaderInfoLog( fragment_shader_handle, sizeof( msg ), &length, msg );
printf( "3 Error: %s\n", msg);
}
if(glGetError()){
printf("initGL, error at end of initGL");
}
// After successful link, detach shaders from shader program
glDetachShader(shader_program, vertex_shader_handle);
glDetachShader(shader_program, fragment_shader_handle);
return shader_program;
}
/* initGL()
*
* Initializes, links, and compiles relevant shaders
* Initializes various VBOs for use in the timewarp distortion shader
*
*/
void initGL()
{
// GL features
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
//glClearColor(0, 0, 0, 0); // background color
//glClearStencil(0); // clear stencil buffer
//glClearDepth(1.0f); // 0 is near, 1 is far
//glEnable(GL_SCISSOR_TEST);
glDepthFunc(GL_LEQUAL);
// Create and bind global VAO object.
// This may not be necessary, and I can't
// really find very many good resources
// online as to why and how this is needed.
glGenVertexArrays(1, &tw_vao);
glBindVertexArray(tw_vao);
///////////////////////////////////////////////////////
// Create and compile timewarp distortion vertex shader
tw_shader_program = init_and_link_shader(timeWarpChromaticVertexProgramGLSL, timeWarpChromaticFragmentProgramGLSL);
//////////////////////
// VBO Initialization
// Acquire attribute and uniform locations from the compiled and linked shader program
distortion_pos_attr = glGetAttribLocation(tw_shader_program, "vertexPosition");
distortion_uv0_attr = glGetAttribLocation(tw_shader_program, "vertexUv0");
distortion_uv1_attr = glGetAttribLocation(tw_shader_program, "vertexUv1");
distortion_uv2_attr = glGetAttribLocation(tw_shader_program, "vertexUv2");
tw_start_transform_unif = glGetUniformLocation(tw_shader_program, "TimeWarpStartTransform");
tw_end_transform_unif = glGetUniformLocation(tw_shader_program, "TimeWarpEndTransform");
tw_eye_index_unif = glGetUniformLocation(tw_shader_program, "ArrayLayer");
eye_sampler_0 = glGetUniformLocation(tw_shader_program, "Texture[0]");
eye_sampler_1 = glGetUniformLocation(tw_shader_program, "Texture[1]");
// Config distortion mesh position vbo
glGenBuffers(1, &distortion_positions_vbo);
glBindBuffer(GL_ARRAY_BUFFER, distortion_positions_vbo);
glBufferData(GL_ARRAY_BUFFER, NUM_EYES * (num_distortion_vertices * 3) * sizeof(GLfloat), distortion_positions, GL_STATIC_DRAW);
glVertexAttribPointer(distortion_pos_attr, 3, GL_FLOAT, GL_FALSE, 0, 0);
//glEnableVertexAttribArray(distortion_pos_attr);
// Config distortion uv0 vbo
glGenBuffers(1, &distortion_uv0_vbo);
glBindBuffer(GL_ARRAY_BUFFER, distortion_uv0_vbo);
glBufferData(GL_ARRAY_BUFFER, NUM_EYES * (num_distortion_vertices * 2) * sizeof(GLfloat), distortion_uv0, GL_STATIC_DRAW);
glVertexAttribPointer(distortion_uv0_attr, 2, GL_FLOAT, GL_FALSE, 0, 0);
//glEnableVertexAttribArray(distortion_uv0_attr);
// Config distortion uv1 vbo
glGenBuffers(1, &distortion_uv1_vbo);
glBindBuffer(GL_ARRAY_BUFFER, distortion_uv1_vbo);
glBufferData(GL_ARRAY_BUFFER, NUM_EYES * (num_distortion_vertices * 2) * sizeof(GLfloat), distortion_uv1, GL_STATIC_DRAW);
glVertexAttribPointer(distortion_uv1_attr, 2, GL_FLOAT, GL_FALSE, 0, 0);
//glEnableVertexAttribArray(distortion_uv1_attr);
// Config distortion uv2 vbo
glGenBuffers(1, &distortion_uv2_vbo);
glBindBuffer(GL_ARRAY_BUFFER, distortion_uv2_vbo);
glBufferData(GL_ARRAY_BUFFER, NUM_EYES * (num_distortion_vertices * 2) * sizeof(GLfloat), distortion_uv2, GL_STATIC_DRAW);
glVertexAttribPointer(distortion_uv2_attr, 2, GL_FLOAT, GL_FALSE, 0, 0);
//glEnableVertexAttribArray(distortion_uv2_attr);
// Config distortion mesh indices vbo
glGenBuffers(1, &distortion_indices_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, distortion_indices_vbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_distortion_indices * sizeof(GLuint), distortion_indices, GL_STATIC_DRAW);
glGenVertexArrays(1, &basic_vao);
glBindVertexArray(basic_vao);
// Create the basic shader program
basic_shader_program = init_and_link_shader (basicVertexShader, basicFragmentShader);
// Acquire attribute and uniform locations from the compiled and linked shader program
basic_pos_attr = glGetAttribLocation(basic_shader_program, "vertexPosition");
basic_uv_attr = glGetAttribLocation(basic_shader_program, "vertexUV");
GLenum err;
// Config basic mesh position vbo
glGenBuffers(1, &basic_pos_vbo);
glBindBuffer(GL_ARRAY_BUFFER, basic_pos_vbo);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), plane_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(basic_pos_attr, 2, GL_FLOAT, GL_FALSE, 0, 0);
err = glGetError();
if(err){
printf("Error after configuring basic position vbo: %x\n", err);
}
// Config basic mesh uv vbo
glGenBuffers(1, &basic_uv_vbo);
glBindBuffer(GL_ARRAY_BUFFER, basic_uv_vbo);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), plane_uvs, GL_STATIC_DRAW);
glVertexAttribPointer(basic_uv_attr, 2, GL_FLOAT, GL_FALSE, 0, 0);
err = glGetError();
if(err){
printf("Error after configuring basic uv vbo: %x\n", err);
}
// Config basic mesh indices vbo
glGenBuffers(1, &basic_indices_vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, basic_indices_vbo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLfloat), plane_indices, GL_STATIC_DRAW);
err = glGetError();
if(err){
printf("Error after configuring basic uv vbo: %x\n", err);
}
// Generate texture for prerendered_image Image
glGenTextures(1, &prerendered_image_tex);
glBindTexture(GL_TEXTURE_2D, prerendered_image_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
//glBindBuffer(GL_TEXTURE_2D, prerendered_image_tex);
glTexImage2D(GL_TEXTURE_2D, 0,
prerendered_image->hasAlpha ? GL_RGBA : GL_RGB,
prerendered_image->width,
prerendered_image->height,
0,
prerendered_image->hasAlpha ? GL_RGBA : GL_RGB,
GL_UNSIGNED_BYTE,
prerendered_image->texture);
return;
}
///////////////////////////////////////////////////////////////////////////////
// initialize global variables
///////////////////////////////////////////////////////////////////////////////
bool initSharedMem(const char* fname)
{
init_images(fname);
screenWidth = SCREEN_WIDTH;
screenHeight = SCREEN_HEIGHT;
mouseLeftDown = mouseRightDown = false;
mouseX = mouseY = 0;
fboId = rboColorId = rboDepthId = textureId = 0;
fboSupported = fboUsed = false;
playTime = renderToTextureTime = timewarpTime = 0;
// Generate reference HMD and physical body dimensions
GetDefaultHmdInfo(SCREEN_WIDTH, SCREEN_HEIGHT, &hmd_info);
GetDefaultBodyInfo(&body_info);
// Construct timewarp meshes and other data
BuildTimewarp(&hmd_info);
return true;
}
///////////////////////////////////////////////////////////////////////////////
// clean up global variables
///////////////////////////////////////////////////////////////////////////////
void clearSharedMem()
{
glDeleteTextures(1, &textureId);
textureId = 0;
glDeleteBuffers(1, &distortion_positions_vbo);
glDeleteBuffers(1, &distortion_indices_vbo);
glDeleteBuffers(1, &distortion_uv0_vbo);
// clean up FBO, RBO
if(fboSupported)
{
glDeleteFramebuffers(1, &fboId);
fboId = 0;
glDeleteRenderbuffers(1, &rboDepthId);
rboDepthId = 0;
}
}
///////////////////////////////////////////////////////////////////////////////
// check FBO completeness
///////////////////////////////////////////////////////////////////////////////
bool checkFramebufferStatus(GLuint fbo)
{
// check FBO status
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // bind
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
switch(status)
{
case GL_FRAMEBUFFER_COMPLETE:
std::cout << "Framebuffer complete." << std::endl;
return true;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
std::cout << "[ERROR] Framebuffer incomplete: Attachment is NOT complete." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
std::cout << "[ERROR] Framebuffer incomplete: No image is attached to FBO." << std::endl;
return false;
/*
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
std::cout << "[ERROR] Framebuffer incomplete: Attached images have different dimensions." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
std::cout << "[ERROR] Framebuffer incomplete: Color attached images have different internal formats." << std::endl;
return false;
*/
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
std::cout << "[ERROR] Framebuffer incomplete: Draw buffer." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
std::cout << "[ERROR] Framebuffer incomplete: Read buffer." << std::endl;
return false;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
std::cout << "[ERROR] Framebuffer incomplete: Multisample." << std::endl;
return false;
case GL_FRAMEBUFFER_UNSUPPORTED:
std::cout << "[ERROR] Framebuffer incomplete: Unsupported by FBO implementation." << std::endl;
return false;
default:
std::cout << "[ERROR] Framebuffer incomplete: Unknown error." << std::endl;
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind
}
///////////////////////////////////////////////////////////////////////////////
// print out the FBO infos
///////////////////////////////////////////////////////////////////////////////
void printFramebufferInfo(GLuint fbo)
{
// bind fbo
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
std::cout << "\n===== FBO STATUS =====\n";
// print max # of colorbuffers supported by FBO
int colorBufferCount = 0;
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &colorBufferCount);
std::cout << "Max Number of Color Buffer Attachment Points: " << colorBufferCount << std::endl;
// get max # of multi samples
int multiSampleCount = 0;
glGetIntegerv(GL_MAX_SAMPLES, &multiSampleCount);
std::cout << "Max Number of Samples for MSAA: " << multiSampleCount << std::endl;
int objectType;
int objectId;
// print info of the colorbuffer attachable image
for(int i = 0; i < colorBufferCount; ++i)
{
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0+i,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
&objectType);
if(objectType != GL_NONE)
{
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0+i,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
&objectId);
std::string formatName;
std::cout << "Color Attachment " << i << ": ";
if(objectType == GL_TEXTURE)
{
std::cout << "GL_TEXTURE, " << getTextureParameters(objectId) << std::endl;
}