3 * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
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.
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.
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/>.
28 #define GL3_PROTOTYPES 1
32 #define MONITOR_DISTANCE 35.0
33 static uint8_t *image_rgb = NULL;
34 static uint8_t *osd_rgba[MAX_OSD] = { NULL, NULL };
35 static GLuint image_name;
36 static GLuint osd_name[MAX_OSD];
37 static int image_width, image_height;
38 static int osd_width[MAX_OSD], osd_height[MAX_OSD];
39 static int texture_size;
40 static int osd_size[MAX_OSD];
43 /* alloc and init an image texture with size that is greater than the power of two */
44 int init_opengl_image(int _image_width, int _image_height)
48 image_width = _image_width;
49 image_height = _image_height;
51 /* generate texture */
52 for (texture_size = 1; texture_size <= image_width || texture_size <= image_height; texture_size *= 2)
55 image_rgb = calloc(texture_size * texture_size, 3);
57 print_error("Failed to allocate texture\n");
61 glShadeModel(GL_FLAT);
62 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
63 glGenTextures(1, &image_name);
64 glBindTexture(GL_TEXTURE_2D, image_name);
65 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
66 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
67 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, image_rgb);
77 /* alloc and init an osd texture with size that is greater than the power of two */
78 int init_opengl_osd(int num, int _osd_width, int _osd_height)
82 if (num < 0 || num >= MAX_OSD) {
83 print_error("given OSD number out of range");
88 osd_width[num] = _osd_width;
89 osd_height[num] = _osd_height;
91 /* generate texture */
92 for (osd_size[num] = 1; osd_size[num] <= osd_width[num] || osd_size[num] <= osd_height[num]; osd_size[num] *= 2)
94 osd_rgba[num] = calloc(osd_size[num] * osd_size[num], 4);
96 print_error("Failed to allocate texture\n");
100 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
101 glGenTextures(1, &osd_name[num]);
102 glBindTexture(GL_TEXTURE_2D, osd_name[num]);
103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
105 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, osd_size[num], osd_size[num], 0, GL_RGBA, GL_UNSIGNED_BYTE, osd_rgba[num]);
114 void opengl_clear(int _flip_y)
119 glClearColor(0.0, 0.0, 0.0, 1.0);
120 glClear(GL_COLOR_BUFFER_BIT);
123 /* set viewport for improved rendering */
124 void opengl_viewport(int view_width, int view_height, int split, int benson_at_line, double fov, double benson_size)
126 int view_x = 0, view_y = 0;
127 int new_width, new_height;
129 /* center view, or put it in the top half of the window */
131 view_y = view_height / 2;
132 view_height = view_height / 2;
133 } else if (split == 2) {
134 view_height = view_height / 2;
137 /* avoid division by zero, if one dimension is too small */
138 if (view_width < 1 || view_height < 1)
141 /* calculate a viewport that has apect of image_width:image_height */
142 if (view_height * image_width > view_width * image_height) {
143 new_height = view_width * image_height / image_width;
144 view_y = view_y + view_height / 2 - new_height / 2;
145 view_height = new_height;
146 } else if (view_height * image_width < view_width * image_height) {
147 new_width = view_height * image_width / image_height;
148 view_x = view_x + view_width / 2 - new_width / 2;
149 view_width = new_width;
152 /* avoid views that are too small */
153 if (view_width < 1 || view_height < 1)
156 /* viewport and projection matrix */
157 glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
158 glMatrixMode(GL_PROJECTION);
161 /* calculate field-of-view */
162 double slope = tan(fov / 360 * M_PI);
163 /* make frustum to center the view in the game view above benson */
164 double left = -slope;
165 double right = slope;
166 double benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
167 double top = slope * ((double)image_height - benson_start_at_position) / (double)image_width;
168 double bottom = -slope * ((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
169 glFrustum(left, right, bottom, top, 1.0, 5000000000.0);
171 glMatrixMode(GL_MODELVIEW);
174 /* render image or only benson */
175 void opengl_blit_image(uint8_t *rgb, int filter, int benson_at_line, int render_benson_only, double fov, double monitor_distance, double benson_size, int benson_case)
177 double texture_left = 0;
178 double texture_right = ((double)image_width) / (double)texture_size;
179 double texture_top = ((double)benson_at_line) / (double)texture_size;
180 double texture_bottom = ((double)image_height) / (double)texture_size;
181 double image_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
182 double image_top = -((double)image_height - image_start_at_position) / (double)image_width;
183 double image_bottom = -((double)image_height * 2.0 - ((double)image_height - image_start_at_position)) / (double)image_width;
185 /* calculate field-of-view */
186 double slope = tan(fov / 360 * M_PI) * monitor_distance;
191 glEnable(GL_CULL_FACE);
196 glEnable(GL_TEXTURE_2D);
197 glBindTexture(GL_TEXTURE_2D, image_name);
198 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
201 if (render_benson_only) {
202 /* render benson only, and copy top line of benson to one line above, so the texture filter will not take false data above benson */
203 rgb += image_width * (benson_at_line - 1) * 3;
204 memcpy(rgb, rgb + image_width * 3, image_width * 3);
205 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, benson_at_line - 1, image_width, image_height - benson_at_line - 1, GL_RGB, GL_UNSIGNED_BYTE, rgb);
207 image_top = -image_top;
209 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
212 glTexCoord2f(texture_left, texture_bottom);
213 glVertex3f(-benson_size * slope, image_bottom * slope, -monitor_distance);
214 glTexCoord2f(texture_right, texture_bottom);
215 glVertex3f(benson_size * slope, image_bottom * slope, -monitor_distance);
216 glTexCoord2f(texture_right, texture_top);
217 glVertex3f(benson_size * slope, image_top * slope, -monitor_distance);
218 glTexCoord2f(texture_left, texture_top);
219 glVertex3f(-benson_size * slope, image_top * slope, -monitor_distance);
221 glDisable(GL_TEXTURE_2D);
222 /* render benson case */
224 double left, right, bottom, top, near, far;
225 left = -benson_size * slope;
226 right = benson_size * slope;
227 bottom = image_bottom * slope;
228 top = image_top * slope;
229 near = -monitor_distance;
230 far = near - benson_size * slope / 3.0;
233 glColor4f(0.3, 0.3, 0.3, 1.0);
234 glVertex3f(left, top, far);
235 glVertex3f(right, top, far);
236 glVertex3f(right, bottom, far);
237 glVertex3f(left, bottom, far);
239 glColor4f(0.2, 0.2, 0.2, 1.0);
240 glVertex3f(left, top, near);
241 glVertex3f(right, top, near);
242 glVertex3f(right, top, far);
243 glVertex3f(left, top, far);
245 glColor4f(0.05, 0.05, 0.05, 1.0);
246 glVertex3f(left, bottom, far);
247 glVertex3f(right, bottom, far);
248 glVertex3f(right, bottom, near);
249 glVertex3f(left, bottom, near);
251 glColor4f(0.1, 0.1, 0.1, 1.0);
252 glVertex3f(left, bottom, far);
253 glVertex3f(left, bottom, near);
254 glVertex3f(left, top, near);
255 glVertex3f(left, top, far);
257 glVertex3f(right, top, far);
258 glVertex3f(right, top, near);
259 glVertex3f(right, bottom, near);
260 glVertex3f(right, bottom, far);
265 glDisable(GL_CULL_FACE);
269 /* render osd texture */
270 void opengl_blit_osd(int num, uint8_t *rgba, int filter, int benson_at_line, double fov, double monitor_distance, double benson_size, double scale_x, double scale_y, double offset_x, double offset_y)
272 double texture_left = 0.0;
273 double texture_right = (double)osd_width[num] / (double)osd_size[num];
274 double texture_top = 0.0;
275 double texture_bottom = (double)osd_height[num] / (double)osd_size[num];
276 double benson_start_at_position;
277 double osd_left = 0.0;
278 double osd_right = 1.0;
279 double osd_top = 0.0;
280 double osd_bottom = 1.0;
281 double slope, range, center;
285 benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
286 osd_top = ((double)image_height - benson_start_at_position) / (double)image_width;
287 osd_bottom = -((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
288 /* calculate field-of-view */
289 slope = tan(fov / 360 * M_PI) * monitor_distance;
291 range = (osd_right - osd_left) / 2.0;
292 center = (osd_right + osd_left) / 2.0;
293 osd_left = (osd_left - center) * scale_x + center + range * offset_x;
294 osd_right = (osd_right - center) * scale_x + center + range * offset_x;
295 range = (osd_bottom - osd_top) / 2.0;
296 center = (osd_bottom + osd_top) / 2.0;
297 osd_top = (osd_top - center) * scale_y + center + range * offset_y;
298 osd_bottom = (osd_bottom - center) * scale_y + center + range * offset_y;
301 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
302 glEnable(GL_TEXTURE_2D);
303 glBindTexture(GL_TEXTURE_2D, osd_name[num]);
304 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
307 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, osd_width[num], osd_height[num], GL_RGBA, GL_UNSIGNED_BYTE, rgba);
310 /* perspective viewport */
311 glTexCoord2f(texture_left, texture_bottom);
312 glVertex3f(osd_left * slope, osd_bottom * slope, -monitor_distance);
313 glTexCoord2f(texture_right, texture_bottom);
314 glVertex3f(osd_right * slope, osd_bottom * slope, -monitor_distance);
315 glTexCoord2f(texture_right, texture_top);
316 glVertex3f(osd_right * slope, osd_top * slope, -monitor_distance);
317 glTexCoord2f(texture_left, texture_top);
318 glVertex3f(osd_left * slope, osd_top * slope, -monitor_distance);
320 /* orthogonal viewport */
321 glTexCoord2f(texture_left, texture_top);
322 glVertex3f(osd_left, osd_top, 0.0);
323 glTexCoord2f(texture_right, texture_top);
324 glVertex3f(osd_right, osd_top, 0.0);
325 glTexCoord2f(texture_right, texture_bottom);
326 glVertex3f(osd_right, osd_bottom, 0.0);
327 glTexCoord2f(texture_left, texture_bottom);
328 glVertex3f(osd_left, osd_bottom, 0.0);
331 glDisable(GL_TEXTURE_2D);
335 /* set color and opacity */
336 void opengl_render_color(double r, double g, double b, double a)
340 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
341 glColor4d(r, g, b, a);
349 void opengl_render_polygon(double *x, double *y, double *z, int count, int cull_face)
354 glEnable(GL_CULL_FACE);
355 glFrontFace((flip_y) ? GL_CCW : GL_CW);
359 for (i = 0; i < count; i++)
360 glVertex3d(x[i], y[i], -z[i]);
363 glDisable(GL_CULL_FACE);
366 /* render polygon, but make sure any size of it is visible */
367 void opengl_render_polygon_and_line(double *x, double *y, double *z, int count)
372 for (i = 0; i < count; i++)
373 glVertex3d(x[i], y[i], -z[i]);
375 glBegin(GL_LINE_LOOP);
376 for (i = 0; i < count; i++)
377 glVertex3d(x[i], y[i], -z[i]);
382 void opengl_render_line(double x1, double y1, double z1, double x2, double y2, double z2, double size)
386 glVertex3f(x1, y1, -z1);
387 glVertex3f(x2, y2, -z2);
394 void opengl_render_point(double x, double y, double z, double size)
398 glVertex3f(x, y, -z);
404 /* free image texture */
405 void exit_opengl(void)
413 for (i = 0; i < MAX_OSD; i++) {