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