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/>.
30 static uint8_t *legacy_rgb = NULL;
31 static uint8_t *benson_rgb = NULL;
32 static uint8_t *osd_rgba[MAX_OSD] = { NULL, NULL };
33 static GLuint legacy_name;
34 static GLuint benson_name;
35 static GLuint osd_name[MAX_OSD];
36 static int screen_width, screen_height;
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];
42 /* alloc and init an image texture with size that is greater than the power of two */
43 int init_opengl(int _image_width, int _image_height)
47 image_width = _image_width;
48 image_height = _image_height;
50 /* generate texture */
51 for (texture_size = 1; texture_size <= image_width || texture_size <= image_height; texture_size *= 2)
54 legacy_rgb = calloc(texture_size * texture_size, 3);
56 print_error("Failed to allocate texture\n");
60 glShadeModel(GL_FLAT);
61 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
62 glGenTextures(1, &legacy_name);
63 glBindTexture(GL_TEXTURE_2D, legacy_name);
64 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
65 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
66 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, legacy_rgb);
68 benson_rgb = calloc(texture_size * texture_size, 3);
70 print_error("Failed to allocate texture\n");
75 glShadeModel(GL_FLAT);
76 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
77 glGenTextures(1, &benson_name);
78 glBindTexture(GL_TEXTURE_2D, benson_name);
79 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
80 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
81 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, benson_rgb);
90 /* alloc and init an osd texture with size that is greater than the power of two */
91 int init_osd(int num, int _osd_width, int _osd_height)
95 if (num < 0 || num >= MAX_OSD) {
96 print_error("given OSD number out of range");
101 osd_width[num] = _osd_width;
102 osd_height[num] = _osd_height;
104 /* generate texture */
105 for (osd_size[num] = 1; osd_size[num] <= osd_width[num] || osd_size[num] <= osd_height[num]; osd_size[num] *= 2)
107 osd_rgba[num] = calloc(osd_size[num] * osd_size[num], 4);
108 if (!osd_rgba[num]) {
109 print_error("Failed to allocate texture\n");
113 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
114 glGenTextures(1, &osd_name[num]);
115 glBindTexture(GL_TEXTURE_2D, osd_name[num]);
116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
118 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, osd_size[num], osd_size[num], 0, GL_RGBA, GL_UNSIGNED_BYTE, osd_rgba[num]);
126 /* set clip planes so that the image portion of the image texture is centered and pixels are rectengular */
127 void resize_opengl(int _screen_width, int _screen_height)
129 screen_width = _screen_width;
130 screen_height = _screen_height;
133 void opengl_copy_last(void)
135 // FIXME: is it ok to copy full window height??? or just the current viewport
136 glReadBuffer(GL_FRONT);
137 glCopyPixels(0, 0, screen_width, screen_height, GL_COLOR);
138 glReadBuffer(GL_BACK);
141 void opengl_clear(void)
143 glClearColor(0.0, 0.0, 0.0, 1.0);
144 glClear(GL_COLOR_BUFFER_BIT);
147 /* set viewport for legacy image */
148 void opengl_viewport_legacy(int split)
151 int view_width, view_height;
152 int new_width, new_height;
157 view_width = screen_width;
158 view_height = screen_height;
161 view_y = screen_height / 2;
162 view_width = screen_width;
163 view_height = screen_height / 2;
166 /* avoid division by zero, if one dimension is too small */
167 if (view_width < 1 || view_height < 1)
170 /* calculate a viewport that has apect of image_width:image_height */
171 if (view_height * image_width > view_width * image_height) {
172 new_height = view_width * image_height / image_width;
173 view_y = view_y + view_height / 2 - new_height / 2;
174 view_height = new_height;
175 } else if (view_height * image_width < view_width * image_height) {
176 new_width = view_height * image_width / image_height;
177 view_x = view_x + view_width / 2 - new_width / 2;
178 view_width = new_width;
181 /* avoid views that are too small */
182 if (view_width < 1 || view_height < 1)
185 /* viewport and projection matrix */
186 glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
187 glMatrixMode(GL_PROJECTION);
189 glOrtho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);
190 glMatrixMode(GL_MODELVIEW);
193 /* render legacy image texture */
194 void opengl_blit_legacy(uint8_t *rgb, int filter)
196 double width = (double)image_width / (double)texture_size;
197 double height = (double)image_height / (double)texture_size;
199 glEnable(GL_TEXTURE_2D);
200 glBindTexture(GL_TEXTURE_2D, legacy_name);
201 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
204 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
206 glTexCoord2f(0.0, 0.0);
207 glVertex3f(0.0, 0.0, 0.0);
208 glTexCoord2f(width, 0.0);
209 glVertex3f(1.0, 0.0, 0.0);
210 glTexCoord2f(width, height);
211 glVertex3f(1.0, 1.0, 0.0);
212 glTexCoord2f(0.0, height);
213 glVertex3f(0.0, 1.0, 0.0);
215 glDisable(GL_TEXTURE_2D);
218 /* set viewport for improved rendering */
219 void opengl_viewport_improved(int split, int benson_at_line, double fov, double benson_size)
222 int view_width, view_height;
223 int new_width, new_height;
225 /* center view, or put it in the top half of the window */
229 view_width = screen_width;
230 view_height = screen_height;
234 view_width = screen_width;
235 view_height = screen_height / 2;
238 /* avoid division by zero, if one dimension is too small */
239 if (view_width < 1 || view_height < 1)
242 /* calculate a viewport that has apect of image_width:image_height */
243 if (view_height * image_width > view_width * image_height) {
244 new_height = view_width * image_height / image_width;
245 view_y = view_y + view_height / 2 - new_height / 2;
246 view_height = new_height;
247 } else if (view_height * image_width < view_width * image_height) {
248 new_width = view_height * image_width / image_height;
249 view_x = view_x + view_width / 2 - new_width / 2;
250 view_width = new_width;
253 /* avoid views that are too small */
254 if (view_width < 1 || view_height < 1)
257 /* viewport and projection matrix */
258 glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
259 glMatrixMode(GL_PROJECTION);
262 /* calculate field-of-view */
263 double slope = tan(fov / 360 * M_PI);
264 /* make frustum to center the view in the game view above benson */
265 double left = -slope;
266 double right = slope;
267 double benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
268 double top = slope * ((double)image_height - benson_start_at_position) / (double)image_width;
269 double bottom = -slope * ((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
270 glFrustum(left, right, bottom, top, 1.0, 5000000000.0);
271 glMatrixMode(GL_MODELVIEW);
274 /* render only benson */
275 void opengl_blit_benson(uint8_t *rgb, int filter, int benson_at_line, double fov, double benson_size, int pixel_size)
277 double border = (benson_size != 1.0) ? (double)pixel_size : 0.0;
278 double texture_left = border / (double)texture_size;
279 double texture_right = ((double)image_width - border) / (double)texture_size;
280 double texture_top = ((double)benson_at_line + border) / (double)texture_size;
281 double texture_bottom = ((double)image_height -border) / (double)texture_size;
282 double benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
283 double benson_top = -((double)image_height - benson_start_at_position) / (double)image_width;
284 double benson_bottom = -((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
286 /* calculate field-of-view */
287 double slope = tan(fov / 360 * M_PI);
290 rgb += image_width * benson_at_line * 3;
291 glEnable(GL_TEXTURE_2D);
292 glBindTexture(GL_TEXTURE_2D, benson_name);
293 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
295 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
296 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, benson_at_line, image_width, image_height - benson_at_line, GL_RGB, GL_UNSIGNED_BYTE, rgb);
298 glTexCoord2f(texture_left, texture_bottom);
299 glVertex3f(-100.0 * benson_size, 100.0 * benson_bottom, -100.0 / slope);
300 glTexCoord2f(texture_right, texture_bottom);
301 glVertex3f(100.0 * benson_size, 100.0 * benson_bottom, -100.0 / slope);
302 glTexCoord2f(texture_right, texture_top);
303 glVertex3f(100.0 * benson_size, 100.0 * benson_top, -100.0 / slope);
304 glTexCoord2f(texture_left, texture_top);
305 glVertex3f(-100.0 * benson_size, 100.0 * benson_top, -100.0 / slope);
307 glDisable(GL_TEXTURE_2D);
310 /* render osd texture */
311 void opengl_blit_osd(int num, uint8_t *rgba, int filter, int benson_at_line, double fov, double benson_size, double scale_x, double scale_y, double offset_x, double offset_y)
313 double texture_left = 0.0;
314 double texture_right = (double)osd_width[num] / (double)osd_size[num];
315 double texture_top = 0.0;
316 double texture_bottom = (double)osd_height[num] / (double)osd_size[num];
317 double benson_start_at_position;
318 double osd_left = 0.0;
319 double osd_right = 1.0;
320 double osd_top = 0.0;
321 double osd_bottom = 1.0;
322 double slope, range, center;
326 benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
327 osd_top = ((double)image_height - benson_start_at_position) / (double)image_width;
328 osd_bottom = -((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
329 /* calculate field-of-view */
330 slope = tan(fov / 360 * M_PI);
332 range = (osd_right - osd_left) / 2.0;
333 center = (osd_right + osd_left) / 2.0;
334 osd_left = (osd_left - center) * scale_x + center + range * offset_x;
335 osd_right = (osd_right - center) * scale_x + center + range * offset_x;
336 range = (osd_bottom - osd_top) / 2.0;
337 center = (osd_bottom + osd_top) / 2.0;
338 osd_top = (osd_top - center) * scale_y + center + range * offset_y;
339 osd_bottom = (osd_bottom - center) * scale_y + center + range * offset_y;
342 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
343 glEnable(GL_TEXTURE_2D);
344 glBindTexture(GL_TEXTURE_2D, osd_name[num]);
345 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /* no modulation with color */
346 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
347 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
348 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, osd_width[num], osd_height[num], GL_RGBA, GL_UNSIGNED_BYTE, rgba);
351 /* perspective viewport */
352 glTexCoord2f(texture_left, texture_bottom);
353 glVertex3f(100.0 * osd_left, 100.0 * osd_bottom, -100.0 / slope);
354 glTexCoord2f(texture_right, texture_bottom);
355 glVertex3f(100.0 * osd_right, 100.0 * osd_bottom, -100.0 / slope);
356 glTexCoord2f(texture_right, texture_top);
357 glVertex3f(100.0 * osd_right, 100.0 * osd_top, -100.0 / slope);
358 glTexCoord2f(texture_left, texture_top);
359 glVertex3f(100.0 * osd_left, 100.0 * osd_top, -100.0 / slope);
361 /* orthogonal viewport */
362 glTexCoord2f(texture_left, texture_top);
363 glVertex3f(osd_left, osd_top, 0.0);
364 glTexCoord2f(texture_right, texture_top);
365 glVertex3f(osd_right, osd_top, 0.0);
366 glTexCoord2f(texture_right, texture_bottom);
367 glVertex3f(osd_right, osd_bottom, 0.0);
368 glTexCoord2f(texture_left, texture_bottom);
369 glVertex3f(osd_left, osd_bottom, 0.0);
372 glDisable(GL_TEXTURE_2D);
376 /* set color and opacity */
377 void opengl_render_color(double r, double g, double b, double a)
381 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
382 glColor4d(r, g, b, a);
390 void opengl_render_polygon(double *x, double *y, double *z, int count, int cull_face)
395 glEnable(GL_CULL_FACE);
400 for (i = 0; i < count; i++)
401 glVertex3d(x[i], y[i], -z[i]);
404 glDisable(GL_CULL_FACE);
407 /* render polygon, but make sure any size of it is visible */
408 void opengl_render_polygon_and_line(double *x, double *y, double *z, int count)
413 for (i = 0; i < count; i++)
414 glVertex3d(x[i], y[i], -z[i]);
416 glBegin(GL_LINE_LOOP);
417 for (i = 0; i < count; i++)
418 glVertex3d(x[i], y[i], -z[i]);
423 void opengl_render_line(double x1, double y1, double z1, double x2, double y2, double z2, double size)
427 glVertex3f(x1, y1, -z1);
428 glVertex3f(x2, y2, -z2);
435 void opengl_render_point(double x, double y, double z, double size)
439 glVertex3f(x, y, -z);
445 /* free image texture */
446 void exit_opengl(void)
458 for (i = 0; i < MAX_OSD; i++) {