ui_gl: Revise code for concision.
[Ale.git] / ui / ui_gl.h
blobb8886adaa8a76058643ca711e9323decbdd714a6
1 // Copyright 2008 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@gmail.com>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine 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 The Anti-Lamenessing Engine 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 the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #ifndef __ui_gl_h__
22 #define __ui_gl_h__
24 #ifdef USE_FREEGLUT
25 #include <GL/freeglut.h>
26 #elif USE_GLUT
27 #include <GL/glut.h>
28 #endif
30 #include "../d2.h"
31 #include "ui.h"
32 #include "gpu.h"
35 * OpenGL user interface.
38 class ui_gl : public ui {
39 private:
40 int osd_mode;
41 int width, height;
42 int cursor_line;
43 int cursor_period;
45 #ifdef USE_PTHREAD
46 pthread_t update_thread;
47 #endif
49 void printf(const char *format, ...) {
50 update();
53 * Reject messages that aren't loud.
56 if (!strstr(format, "\n***"))
57 return;
59 va_list ap;
60 va_start(ap, format);
61 vfprintf(ui_stream, format, ap);
62 va_end(ap);
65 void update() {
66 glutPostRedisplay();
69 static void *thread_update_loop(void *vu) {
70 #if defined HAVE_GLUT_MAIN_LOOP_EVENT && defined HAVE_NANOSLEEP
71 for(;;) {
72 struct timespec t;
73 t.tv_sec = 0;
74 t.tv_nsec = 10000000;
75 nanosleep(&t, NULL);
77 gpu::lock();
78 glutMainLoopEvent();
79 gpu::unlock();
81 #endif
83 return NULL;
87 * GLUT callback logic.
90 static ui_gl *instance;
93 * Reshape callback.
95 static void glutReshape(int width, int height) {
97 * Correct projection and window parameters.
99 glViewport(0, 0, width, height);
101 glMatrixMode(GL_PROJECTION);
102 glLoadIdentity();
103 gluOrtho2D(0, width, height, 0);
104 glMatrixMode( GL_MODELVIEW );
106 instance->width = width;
107 instance->height = height;
110 static void bitmap_string(const char *s) {
111 while (*s)
112 glutBitmapCharacter(GLUT_BITMAP_8_BY_13, *s++);
115 static void outline_string(int i, int j, const char *s) {
116 for (int ii = -1; ii <= 1; ii++)
117 for (int jj = -1; jj <= 1; jj++) {
118 glColor3f(0, 0, 0);
119 glRasterPos2f(i + ii, j + jj);
120 bitmap_string(s);
123 glColor3f(1, 1, 1);
124 glRasterPos2f(i, j);
125 bitmap_string(s);
128 static void printf_glut(const char *format, ...) {
129 char line_buffer[1000];
130 line_buffer[999] = '\0';
131 int line_buffer_len = 999;
133 va_list ap;
134 va_start(ap, format);
135 vsnprintf(line_buffer, line_buffer_len, format, ap);
136 va_end(ap);
138 outline_string(10, instance->cursor_line, line_buffer);
139 instance->cursor_line += instance->cursor_period;
143 * Keyboard callback
145 static void glutKeyboard(unsigned char c, int x, int y) {
146 if (c == 'o') {
147 instance->osd_mode = (instance->osd_mode + 1) % 3;
148 glutPostRedisplay();
149 } else if (c == 'O') {
150 instance->osd_mode = (instance->osd_mode + 2) % 3;
151 glutPostRedisplay();
157 * Display callback
159 static void glutDisplay() {
161 * Clear buffer
163 glClearColor(0, 0, 0, 0);
164 glClear(GL_COLOR_BUFFER_BIT);
167 * Display text.
170 instance->cursor_line = 23;
171 instance->cursor_period = 18;
173 int baseline = instance->height - 15;
175 if (instance->osd_mode >= 1) {
176 const char *action = "";
177 int current_frame = instance->status.frame_num;
178 int total_frames = d2::image_rw::count();
180 switch(instance->status.code) {
181 case status_type::LOAD_FILE:
182 action = "Loading frame";
183 break;
184 case status_type::EXPOSURE_PASS_1:
185 case status_type::PREMATCH:
186 case status_type::ALIGN:
187 case status_type::GLOBAL_ALIGN:
188 case status_type::POSTMATCH:
189 case status_type::EXPOSURE_PASS_2:
190 case status_type::MULTI:
191 action = "Aligning";
192 break;
193 case status_type::RENDERA:
194 case status_type::RENDERD:
195 case status_type::RENDERO:
196 action = "Rendering";
197 break;
198 case status_type::WRITED:
199 case status_type::WRITEO:
200 case status_type::IP_WRITE:
201 action = "Writing";
202 break;
203 case status_type::IP_RENDER:
204 case status_type::IP_UPDATE:
205 action = "Irani-Peleg";
206 break;
207 case status_type::D3_CONTROL_POINT_SOLVE:
208 case status_type::D3_SUBDIVIDING_SPACE:
209 case status_type::D3_UPDATING_OCCUPANCY:
210 case status_type::D3_RENDER:
211 action = "3D operations";
212 break;
213 default:
214 break;
216 if (strcmp(action, "")) {
217 printf_glut("%s (%u/%u)", action, current_frame + 1, total_frames);
221 if (instance->osd_mode >= 2) {
222 switch(instance->status.code) {
223 case status_type::PREMATCH:
224 case status_type::ALIGN:
225 case status_type::GLOBAL_ALIGN:
226 case status_type::POSTMATCH:
227 case status_type::MULTI:
228 printf_glut(" match=%.6f%%", instance->status.match_value);
229 printf_glut(" perturb= %.3f", instance->status.perturb_size);
230 printf_glut(" lod= %.3f", pow(2, -instance->status.align_lod));
231 printf_glut("exp_mult= %.3f %.3f %.3f",
232 instance->status.exp_multiplier[0],
233 instance->status.exp_multiplier[1],
234 instance->status.exp_multiplier[2]);
235 break;
236 case status_type::WRITED:
237 case status_type::IP_WRITE:
238 printf_glut(d2::image_rw::output_name());
239 break;
241 case status_type::WRITEO:
242 break;
244 case status_type::IP_RENDER:
245 case status_type::IP_UPDATE:
246 printf_glut("Step %u/%u", instance->status.irani_peleg_step + 1, instance->status.irani_peleg_steps);
247 if (instance->status.irani_peleg_stage == 1) {
248 printf_glut("Simulate");
249 } else if (instance->status.irani_peleg_stage == 2) {
250 printf_glut("Backproject");
252 break;
253 case status_type::D3_CONTROL_POINT_SOLVE:
254 case status_type::D3_SUBDIVIDING_SPACE:
255 case status_type::D3_UPDATING_OCCUPANCY:
256 case status_type::D3_RENDER:
257 break;
258 default:
259 break;
263 if (instance->cursor_line < baseline - instance->cursor_period)
264 instance->cursor_line = baseline - instance->cursor_period;
266 printf_glut("No preview available");
267 printf_glut("'o' cycles text");
270 * Show result.
272 glutSwapBuffers();
275 public:
276 ui_gl() {
277 #ifndef USE_GLUT
278 const char *glut_error = "this build was not configured for GLUT";
279 throw glut_error;
280 #endif
281 #ifndef HAVE_GLUT_MAIN_LOOP_EVENT
282 const char *freeglut_error = "need extension glutMainLoopEvent()";
283 throw freeglut_error;
284 #endif
285 #ifndef USE_PTHREAD
286 const char *pthread_error = "need POSIX threads";
287 throw pthread_error;
288 #endif
289 #ifndef HAVE_NANOSLEEP
290 const char *nanosleep_error = "need nanosleep()";
291 throw nanosleep_error;
292 #endif
295 if (!gpu::is_ok()) {
296 const char *gpu_init_error = "GPU initialization error";
297 throw gpu_init_error;
300 instance = this;
302 osd_mode = 2;
305 * Initialization
308 gpu::lock();
309 glMatrixMode( GL_PROJECTION );
310 glLoadIdentity();
311 gluOrtho2D( -1., 1., -1., 1. );
312 glMatrixMode( GL_MODELVIEW );
313 gpu::unlock();
316 * XXX: We don't lock the GPU for these, which could cause a
317 * problem.
320 glutReshapeFunc(glutReshape);
321 glutDisplayFunc(glutDisplay);
322 glutKeyboardFunc(glutKeyboard);
323 glutReshapeWindow(640, 480);
326 * Start an update thread.
328 #ifdef USE_PTHREAD
329 pthread_attr_t pattr;
330 pthread_attr_init(&pattr);
331 pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
332 pthread_create(&update_thread, NULL, thread_update_loop, (void *) this);
333 #endif
336 ~ui_gl() {
337 #ifdef USE_PTHREAD
338 pthread_cancel(update_thread);
339 pthread_join(update_thread, NULL);
340 #endif
344 #endif