1 /*
2  * Copyright (C) 2013 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14 
15 #include "config.h"
16 #include "glext.h"
17 #include "video.h"
18 #include "glsl.h"
19 #include "fbo.h"
20 
21 /*---------------------------------------------------------------------------*/
22 
23 static glsl distortion = { 0, 0, 0 };
24 
25 static fbo    L_fbo = { 0, 0, 0 };
26 static fbo    R_fbo = { 0, 0, 0 };
27 
28 static GLuint L_vbo = 0;
29 static GLuint R_vbo = 0;
30 
31 struct point
32 {
33     GLfloat x;
34     GLfloat y;
35     GLfloat u;
36     GLfloat v;
37 };
38 
39 static const struct point L_rect[4] = {
40     { -1, -1,  0,  0 }, {  0, -1,  1,  0 },
41     { -1,  1,  0,  1 }, {  0,  1,  1,  1 }
42 };
43 static const struct point R_rect[4] = {
44     {  0, -1,  0,  0 }, {  1, -1,  1,  0 },
45     {  0,  1,  0,  1 }, {  1,  1,  1,  1 }
46 };
47 
48 /*---------------------------------------------------------------------------*/
49 
50 static const char *hmd_vert[] = {
51     "void main()\n",
52     "{\n",
53         "gl_TexCoord[0] = gl_MultiTexCoord0;\n",
54         "gl_Position    = gl_Vertex;\n",
55     "}\n",
56 };
57 
58 #if 0
59 
60 /* This fragment shader does not perform chromatic aberration correction. */
61 
62 static const char *hmd_frag[] = {
63     "#version 120\n",
64 
65     "uniform sampler2D warpTexture;\n",
66     "uniform vec2      LensCenter;\n",
67     "uniform vec4      DistortionK;\n",
68     "uniform vec2      ScaleIn;\n",
69     "uniform vec2      ScaleOut;\n",
70 
71     "void main()\n",
72     "{\n",
73         "vec2  v  = (gl_TexCoord[0].xy - LensCenter) * ScaleIn;\n",
74         "float rr = v.x * v.x + v.y * v.y;\n",
75 
76         "vec2 w = v * (DistortionK.x + ",
77                       "DistortionK.y * rr + ",
78                       "DistortionK.z * rr * rr + ",
79                       "DistortionK.w * rr * rr * rr);\n",
80 
81         "vec2 t = LensCenter + ScaleOut * w;\n",
82         "vec2 b = step(vec2(0.0), t) * step(t, vec2(1.0));\n",
83 
84         "gl_FragColor = b.x * b.y * texture2D(warpTexture, t);\n",
85     "}\n",
86 };
87 
88 #else
89 
90 static const char *hmd_frag[] = {
91     "#version 120\n",
92 
93     "uniform sampler2D warpTexture;\n",
94     "uniform vec2      LensCenter;\n",
95     "uniform vec4      DistortionK;\n",
96     "uniform vec4      ChromAbParam;\n",
97     "uniform vec2      ScaleIn;\n",
98     "uniform vec2      ScaleOut;\n",
99 
100     "vec2 GetOut(vec2 v)\n",
101     "{\n",
102         "return LensCenter + ScaleOut * v;\n",
103     "}\n",
104 
105     "void main()\n",
106     "{\n",
107         "vec2  v  = (gl_TexCoord[0].xy - LensCenter) * ScaleIn;\n",
108         "float rr = v.x * v.x + v.y * v.y;\n",
109 
110         "vec2 w = v * (DistortionK.x + ",
111                       "DistortionK.y * rr + ",
112                       "DistortionK.z * rr * rr + ",
113                       "DistortionK.w * rr * rr * rr);\n",
114 
115         "vec2 tb = GetOut(w * (ChromAbParam.z + ChromAbParam.w * rr));\n",
116         "vec2 tr = GetOut(w * (ChromAbParam.x + ChromAbParam.y * rr));\n",
117         "vec2 tg = GetOut(w);\n",
118 
119         "vec2 b = step(vec2(0.0), tb) * step(tb, vec2(1.0));\n",
120 
121         "gl_FragColor = b.x * b.y * vec4(texture2D(warpTexture, tr).r,",
122                                         "texture2D(warpTexture, tg).g,",
123                                         "texture2D(warpTexture, tb).b, 1.0);\n",
124     "}\n",
125 };
126 
127 #endif
128 
hmd_common_stat()129 int hmd_common_stat()
130 {
131     return (distortion.program && L_vbo && L_fbo.framebuffer
132                                && R_vbo && R_fbo.framebuffer);
133 }
134 
hmd_common_init(int w,int h)135 void hmd_common_init(int w, int h)
136 {
137     /* Create the off-screen frame buffers. */
138 
139     fbo_create(&L_fbo, 5 * w / 4 / 2, 5 * h / 4);
140     fbo_create(&R_fbo, 5 * w / 4 / 2, 5 * h / 4);
141 
142     /* Create and initialize the distortion shader. */
143 
144     glsl_create(&distortion, sizeof (hmd_vert) / sizeof (char *), hmd_vert,
145                              sizeof (hmd_frag) / sizeof (char *), hmd_frag);
146 
147     /* Initialize VBOs for the on-screen rectangles. */
148 
149     glGenBuffers_(1, &L_vbo);
150     glBindBuffer_(GL_ARRAY_BUFFER, L_vbo);
151     glBufferData_(GL_ARRAY_BUFFER, sizeof (L_rect), L_rect, GL_STATIC_DRAW);
152     glGenBuffers_(1, &R_vbo);
153     glBindBuffer_(GL_ARRAY_BUFFER, R_vbo);
154     glBufferData_(GL_ARRAY_BUFFER, sizeof (R_rect), R_rect, GL_STATIC_DRAW);
155     glBindBuffer_(GL_ARRAY_BUFFER, 0);
156 }
157 
hmd_common_left()158 void hmd_common_left()
159 {
160     glBindFramebuffer_(GL_FRAMEBUFFER, L_fbo.framebuffer);
161     glViewport(0, 0, L_fbo.width, L_fbo.height);
162 }
163 
hmd_common_right()164 void hmd_common_right()
165 {
166     glBindFramebuffer_(GL_FRAMEBUFFER, R_fbo.framebuffer);
167     glViewport(0, 0, R_fbo.width, R_fbo.height);
168 }
169 
hmd_common_draw(GLuint texture,GLuint buffer)170 void hmd_common_draw(GLuint texture, GLuint buffer)
171 {
172     if (buffer)
173     {
174         glBindTexture(GL_TEXTURE_2D, texture);
175         glBindBuffer_(GL_ARRAY_BUFFER, buffer);
176 
177         glVertexPointer  (2, GL_FLOAT, sizeof (struct point), (GLvoid *) 0);
178         glTexCoordPointer(2, GL_FLOAT, sizeof (struct point), (GLvoid *) 8);
179 
180         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
181         glBindBuffer_(GL_ARRAY_BUFFER, 0);
182     }
183 }
184 
hmd_common_swap(float center,float scale,const float * barrel_correction,const float * chroma_correction)185 void hmd_common_swap(float center,
186                      float scale,
187                      const float *barrel_correction,
188                      const float *chroma_correction)
189 {
190     int w = video.device_w;
191     int h = video.device_h;
192 
193     float a = (float) w / (float) h / 2;
194 
195     /* Prepare to draw a screen-filling pair of rectangles. */
196 
197     glBindFramebuffer_(GL_FRAMEBUFFER, 0);
198     glViewport(0, 0, w, h);
199 
200     glDisable(GL_BLEND);
201     glEnableClientState(GL_VERTEX_ARRAY);
202     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
203 
204     glUseProgram_(distortion.program);
205     {
206         /* Set distortion parameters for both eyes. */
207 
208         glsl_uniform2f(&distortion, "ScaleOut", 0.5f / scale, 0.5f * a / scale);
209         glsl_uniform2f(&distortion, "ScaleIn",  2.0f,         2.0f / a);
210         glsl_uniform4f(&distortion, "DistortionK",  barrel_correction[0],
211                                                     barrel_correction[1],
212                                                     barrel_correction[2],
213                                                     barrel_correction[3]);
214         glsl_uniform4f(&distortion, "ChromAbParam", chroma_correction[0],
215                                                     chroma_correction[1],
216                                                     chroma_correction[2],
217                                                     chroma_correction[3]);
218         /* Draw the left eye. */
219 
220         glsl_uniform2f(&distortion, "LensCenter", 0.5f + 0.5f * center, 0.5f);
221         hmd_common_draw(L_fbo.color_texture, L_vbo);
222 
223         /* Draw the right eye.*/
224 
225         glsl_uniform2f(&distortion, "LensCenter", 0.5f - 0.5f * center, 0.5f);
226         hmd_common_draw(R_fbo.color_texture, R_vbo);
227     }
228     glUseProgram_(0);
229 
230     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
231     glDisableClientState(GL_VERTEX_ARRAY);
232     glEnable(GL_BLEND);
233 }
234 
hmd_common_free()235 void hmd_common_free()
236 {
237     fbo_delete(&L_fbo);
238     fbo_delete(&R_fbo);
239 
240     glsl_delete(&distortion);
241 
242     if (L_vbo) glDeleteBuffers_(1, &L_vbo);
243     if (R_vbo) glDeleteBuffers_(1, &R_vbo);
244 }
245 
246 /*---------------------------------------------------------------------------*/
247