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/>.
29 static uint8_t *legacy_rgb = NULL;
30 static uint8_t *benson_rgb = NULL;
31 static GLuint legacy_name;
32 static GLuint benson_name;
33 static int screen_width, screen_height;
34 static int image_width, image_height;
35 static int texture_size;
37 /* alloc and init an image texture with size that is greater than the power of two */
38 int init_opengl(int _image_width, int _image_height)
42 image_width = _image_width;
43 image_height = _image_height;
45 /* generate texture */
46 for (texture_size = 1; texture_size <= image_width || texture_size <= image_height; texture_size *= 2)
49 legacy_rgb = calloc(texture_size * texture_size, 3);
51 print_error("Failed to allocate texture\n");
55 glShadeModel(GL_FLAT);
56 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
57 glGenTextures(1, &legacy_name);
58 glBindTexture(GL_TEXTURE_2D, legacy_name);
59 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
60 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
61 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, legacy_rgb);
63 benson_rgb = calloc(texture_size * texture_size, 3);
65 print_error("Failed to allocate texture\n");
70 glShadeModel(GL_FLAT);
71 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
72 glGenTextures(1, &benson_name);
73 glBindTexture(GL_TEXTURE_2D, benson_name);
74 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
75 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
76 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, benson_rgb);
85 /* set clip planes so that the image portion of the image texture is centered and pixels are rectengular */
86 void resize_opengl(int _screen_width, int _screen_height)
88 screen_width = _screen_width;
89 screen_height = _screen_height;
92 void opengl_copy_last(void)
94 // FIXME: is it ok to copy full window height??? or just the current viewport
95 glReadBuffer(GL_FRONT);
96 glCopyPixels(0, 0, screen_width, screen_height, GL_COLOR);
97 glReadBuffer(GL_BACK);
100 void opengl_clear(void)
102 glClearColor(0.0, 0.0, 0.0, 1.0);
103 glClear(GL_COLOR_BUFFER_BIT);
106 /* set viewport for legacy image */
107 void opengl_viewport_legacy(int split)
110 int view_width, view_height;
111 int new_width, new_height;
116 view_width = screen_width;
117 view_height = screen_height;
120 view_y = screen_height / 2;
121 view_width = screen_width;
122 view_height = screen_height / 2;
125 /* avoid division by zero, if one dimension is too small */
126 if (view_width < 1 || view_height < 1)
129 /* calculate a viewport that has apect of image_width:image_height */
130 if (view_height * image_width > view_width * image_height) {
131 new_height = view_width * image_height / image_width;
132 view_y = view_y + view_height / 2 - new_height / 2;
133 view_height = new_height;
134 } else if (view_height * image_width < view_width * image_height) {
135 new_width = view_height * image_width / image_height;
136 view_x = view_x + view_width / 2 - new_width / 2;
137 view_width = new_width;
140 /* avoid views that are too small */
141 if (view_width < 1 || view_height < 1)
144 /* viewport and projection matrix */
145 glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
146 glMatrixMode(GL_PROJECTION);
148 glOrtho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);
149 glMatrixMode(GL_MODELVIEW);
152 /* render legacy image texture */
153 void opengl_blit_legacy(uint8_t *rgb, int filter)
155 double width = (double)image_width / (double)texture_size;
156 double height = (double)image_height / (double)texture_size;
158 glEnable(GL_TEXTURE_2D);
159 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); /* no modulation with color */
160 glBindTexture(GL_TEXTURE_2D, legacy_name);
161 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
162 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
163 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
165 glTexCoord2f(0.0, 0.0);
166 glVertex3f(0.0, 0.0, 0.0);
167 glTexCoord2f(width, 0.0);
168 glVertex3f(1.0, 0.0, 0.0);
169 glTexCoord2f(width, height);
170 glVertex3f(1.0, 1.0, 0.0);
171 glTexCoord2f(0.0, height);
172 glVertex3f(0.0, 1.0, 0.0);
174 glDisable(GL_TEXTURE_2D);
177 /* set viewport for improved rendering */
178 void opengl_viewport_improved(int split, int benson_at_line, double fov, double benson_size)
181 int view_width, view_height;
182 int new_width, new_height;
184 /* center view, or put it in the top half of the window */
188 view_width = screen_width;
189 view_height = screen_height;
193 view_width = screen_width;
194 view_height = screen_height / 2;
197 /* avoid division by zero, if one dimension is too small */
198 if (view_width < 1 || view_height < 1)
201 /* calculate a viewport that has apect of image_width:image_height */
202 if (view_height * image_width > view_width * image_height) {
203 new_height = view_width * image_height / image_width;
204 view_y = view_y + view_height / 2 - new_height / 2;
205 view_height = new_height;
206 } else if (view_height * image_width < view_width * image_height) {
207 new_width = view_height * image_width / image_height;
208 view_x = view_x + view_width / 2 - new_width / 2;
209 view_width = new_width;
212 /* avoid views that are too small */
213 if (view_width < 1 || view_height < 1)
216 /* viewport and projection matrix */
217 glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
218 glMatrixMode(GL_PROJECTION);
221 /* calculate field-of-view */
222 double slope = tan(fov / 360 * M_PI);
223 /* make frustum to center the view in the game view above benson */
224 double left = -slope;
225 double right = slope;
226 double benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
227 double top = slope * ((double)image_height - benson_start_at_position) / (double)image_width;
228 double bottom = -slope * ((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
229 glFrustum(left, right, bottom, top, 1.0, 5000000000.0);
230 glMatrixMode(GL_MODELVIEW);
233 /* render only benson */
234 void opengl_blit_benson(uint8_t *rgb, int filter, int benson_at_line, double fov, double benson_size, int pixel_size)
236 double border = (benson_size != 1.0) ? (double)pixel_size : 0.0;
237 double texture_left = border / (double)texture_size;
238 double texture_right = ((double)image_width - border) / (double)texture_size;
239 double texture_top = ((double)benson_at_line + border) / (double)texture_size;
240 double texture_bottom = ((double)image_height -border) / (double)texture_size;
241 double benson_start_at_position = ((double)image_height - (double)benson_at_line) * benson_size;
242 double benson_top = -((double)image_height - benson_start_at_position) / (double)image_width;
243 double benson_bottom = -((double)image_height * 2.0 - ((double)image_height - benson_start_at_position)) / (double)image_width;
245 /* calculate field-of-view */
246 double slope = tan(fov / 360 * M_PI);
249 rgb += image_width * benson_at_line * 3;
250 glEnable(GL_TEXTURE_2D);
251 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); /* no modulation with color */
252 glBindTexture(GL_TEXTURE_2D, benson_name);
253 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
254 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
255 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, benson_at_line, image_width, image_height - benson_at_line, GL_RGB, GL_UNSIGNED_BYTE, rgb);
257 glTexCoord2f(texture_left, texture_bottom);
258 glVertex3f(-100.0 * benson_size, 100.0 * benson_bottom, -100.0 / slope);
259 glTexCoord2f(texture_right, texture_bottom);
260 glVertex3f(100.0 * benson_size, 100.0 * benson_bottom, -100.0 / slope);
261 glTexCoord2f(texture_right, texture_top);
262 glVertex3f(100.0 * benson_size, 100.0 * benson_top, -100.0 / slope);
263 glTexCoord2f(texture_left, texture_top);
264 glVertex3f(-100.0 * benson_size, 100.0 * benson_top, -100.0 / slope);
266 glDisable(GL_TEXTURE_2D);
269 static double transparency;
271 /* start rendering scene */
272 void opengl_transparency_set(double _transparency)
277 transparency = _transparency;
279 /* for debugging use transparent rendering */
282 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
286 void opengl_render_color(double r, double g, double b)
289 glColor4d(r, g, b, 1.0 - transparency);
295 void opengl_render_polygon(double *x, double *y, double *z, int count, int cull_face)
300 glEnable(GL_CULL_FACE);
305 for (i = 0; i < count; i++)
306 glVertex3d(x[i], y[i], -z[i]);
309 glDisable(GL_CULL_FACE);
312 /* render polygon, but make sure any size of it is visible */
313 void opengl_render_polygon_and_line(double *x, double *y, double *z, int count)
318 for (i = 0; i < count; i++)
319 glVertex3d(x[i], y[i], -z[i]);
321 glBegin(GL_LINE_LOOP);
322 for (i = 0; i < count; i++)
323 glVertex3d(x[i], y[i], -z[i]);
328 void opengl_render_line(double x1, double y1, double z1, double x2, double y2, double z2, double size)
332 glVertex3f(x1, y1, -z1);
333 glVertex3f(x2, y2, -z2);
340 void opengl_render_point(double x, double y, double z, double size)
344 glVertex3f(x, y, -z);
350 /* free image texture */
351 void exit_opengl(void)