1 // Copyright 2004 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
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
44 class ui_tty
: public ui
{
54 pthread_t update_thread
;
65 fputc('\r', ui_stream
);
66 fputs(buffer
, ui_stream
);
67 status_index
= buffer_index
;
71 while (status_index
< terminal_width
) {
73 fprintf(ui_stream
, " ");
78 fputc('\r', ui_stream
);
79 for (int i
= 0; i
< terminal_width
; i
++) {
80 fprintf(ui_stream
, " ");
85 int status_printf(int count
, ...) {
91 char *local_buffer
= (char *) calloc(terminal_width
- status_index
, sizeof(char));
98 for (int i
= 0; i
< count
; i
++) {
104 for (int arg
= 0; arg
< i
+ 1; arg
++)
105 format
= va_arg(ap
, char *);
106 for (int arg
= i
+ 1; arg
< count
; arg
++)
111 n
= vsnprintf(local_buffer
, terminal_width
- status_index
, format
, ap
);
114 if (n
< 0 || n
> terminal_width
- status_index
- 1)
117 fputs(local_buffer
, ui_stream
);
128 * If we reach this point, then there was no valid string produced.
142 void pad_align_status() {
143 for (int i
= 0; i
< status
.steps
- status
.steps_completed
; i
++) {
144 status_printf(1, " ");
147 void pad_match_status() {
148 status_printf(1, " ");
151 int write_match_status() {
152 return status_printf(1, format_string_working(), status
.match_value
);
155 void write_status() {
157 if (status
.code
== status
.UNDEFINED
158 || status
.code
== status
.FRAME_DONE
159 || status
.code
== status
.SET_DONE
160 || status
.code
== status
.IP_STEP_DONE
) {
165 if (status
.code
== status
.GLOBAL_ALIGN
166 || status
.code
== status
.ALIGN
167 || status
.code
== status
.POSTMATCH
168 || status
.code
== status
.EXPOSURE_PASS_2
) {
170 if (write_match_status()) {
172 fprintf(ui_stream
, "\n");
173 write_match_status();
177 status_printf(1, " | ");
179 switch (status
.code
) {
180 case status_type::LOAD_FILE
:
181 status_printf(4, "Loading Image (%s)",
182 "Loading Image", "Loading", "load",
183 status
.cache
? "caching" : "cache is full");
185 case status_type::EXPOSURE_PASS_1
:
186 status_printf(3, "Registering exposure (first pass)", "Registering exposure", "regexp1");
188 case status_type::LODCLUSTER_CREATE
:
189 status_printf(3, "Creating LOD cluster, scale %g", "Creating LOD clusters", "lodcluster",
190 pow(2, -status
.align_lod
));
192 case status_type::PREMATCH
:
193 status_printf(3, "Calculating pre-alignment match", "Calculating match", "prematch");
195 case status_type::MULTI
:
196 status_printf(3, "Assigning multi-alignment pixels", "Multi-alignment", "multi");
198 case status_type::GLOBAL_ALIGN
:
199 case status_type::ALIGN
:
200 status_printf(5, "%s [perturb=%6.3g] [lod=%6.3g] [exp_mult=%6.3g %6.3g %6.3g]",
201 "%s [perturb=%6.3g] [lod=%6.3g]",
202 "%s [perturb=%6.3g]",
205 (status
.code
== status_type::GLOBAL_ALIGN
)
209 pow(2, -status
.align_lod
),
210 status
.exp_multiplier
[0],
211 status
.exp_multiplier
[1],
212 status
.exp_multiplier
[2]);
214 case status_type::POSTMATCH
:
215 status_printf(3, "Calculating post-alignment match", "Calculating match", "postmatch");
217 case status_type::EXPOSURE_PASS_2
:
218 status_printf(3, "Registering exposure (second pass)", "Registering exposure", "regexp2");
220 case status_type::RENDERA
:
221 status_printf(3, "Rendering alignment reference image", "Rendering", "render-a");
223 case status_type::RENDERD
:
224 status_printf(3, "Rendering default chain", "Rendering", "render-d");
226 case status_type::RENDERO
:
227 status_printf(3, "Rendering chain %d", "Rendering", "render-o%d", status
.onum
);
229 case status_type::WRITED
:
230 status_printf(4, "Writing default chain to '%s'",
231 "Writing '%s'", "Writing", "write-d", d2::image_rw::output_name());
233 case status_type::WRITEO
:
234 status_printf(3, "Writing image for chain %d", "Writing", "write-o%d", status
.onum
);
236 case status_type::IP_RENDER
:
237 status_printf(3, "Frame '%s'%s",
238 "Frame '%s'", "Processing",
239 d2::image_rw::name(status
.frame_num
), status
.irani_peleg_stage
240 ? ((status
.irani_peleg_stage
== 1) ? " [simulate ]" : " [backproject]")
243 case status_type::IP_UPDATE
:
244 status_printf(3, "Updating approximation", "Updating", "update");
246 case status_type::IP_WRITE
:
247 status_printf(3, "Writing '%s'", "Writing", "write", d2::image_rw::output_name());
249 case status_type::D3_CONTROL_POINT_SOLVE
:
250 status_printf(1, "Aligning control points, %g%% done, error=%g",
251 log(status
.cp_cur_perturb
/ status
.cp_max_perturb
)
252 / log(status
.cp_min_perturb
/ status
.cp_max_perturb
),
253 status
.cp_cur_error
);
255 case status_type::D3_SUBDIVIDING_SPACE
:
256 status_printf(2, "Subdividing space, frame pair (%u, %u), y=%u, x=%u, spaces=%u",
257 "Subdividing space", status
.frame_num
,
258 status
.secondary_frame_num
, status
.y_coordinate
, status
.x_coordinate
,
259 status
.total_spaces
);
261 case status_type::D3_UPDATING_OCCUPANCY
:
262 status_printf(2, "Updating occupancy, step %u/%u, frame %u, space %u/%u",
263 "Updating occupancy", status
.steps_completed
,
264 status
.steps
, status
.frame_num
,
265 status
.space_num
, status
.total_spaces
);
267 case status_type::D3_RENDER
:
268 if (status
.filtering
== 0 && status
.focusing
== 0) {
269 status_printf(1, "space %u/%u",
270 status
.space_num
, status
.total_spaces
);
271 } else if (status
.filtering
== 1 && status
.focusing
== 0) {
272 status_printf(1, "frame %u, y=%u, x=%u",
273 status
.frame_num
, status
.y_coordinate
, status
.x_coordinate
);
274 } else if (status
.filtering
== 0 && status
.focusing
== 1) {
275 status_printf(1, "y=%u, x=%u, view=%u", status
.y_coordinate
, status
.x_coordinate
,
277 } else if (status
.filtering
== 1 && status
.focusing
== 1) {
278 status_printf(1, "view=%u, y=%u, x=%u, frame=%u",
279 status
.view_num
, status
.y_coordinate
, status
.x_coordinate
,
297 void printf(const char *format
, ...) {
299 pthread_mutex_lock(&lock
);
304 if (buffer_index
>= 0 && buffer_index
< terminal_width
/* && format[strlen(format) - 1] != '\n' */) {
305 va_start(ap
, format
);
306 n
= vsnprintf(buffer
+ buffer_index
, terminal_width
- buffer_index
, format
, ap
);
310 if (n
>= 0 && n
< terminal_width
- buffer_index
) {
312 * The message fits in the buffer, so update the index
313 * and write buffer and status information.
318 if (format
[strlen(format
) - 1] == '\n') {
326 * The message does not fit in the buffer, so write any
327 * existing buffer and append the new text to the stream.
329 if (buffer_index
>= 0) {
330 assert(buffer_index
< terminal_width
);
331 buffer
[buffer_index
] = '\0';
335 va_start(ap
, format
);
336 vfprintf(ui_stream
, format
, ap
);
341 * This is not the only case that produces a newline,
342 * but ignoring other cases should be safe.
344 if (format
[strlen(format
) - 1] == '\n') {
349 pthread_mutex_unlock(&lock
);
354 static time_t last_update
= 0;
355 time_t now
= time(NULL
);
358 * Handle DONE status.
361 if (status
.code
== status_type::FRAME_DONE
) {
364 pthread_mutex_lock(&lock
);
366 fputc('\n', ui_stream
);
370 pthread_mutex_unlock(&lock
);
372 } else if (status
.code
== status_type::SET_DONE
) {
374 pthread_mutex_lock(&lock
);
376 fputc('\n', ui_stream
);
380 pthread_mutex_unlock(&lock
);
385 * Handle optional output.
389 pthread_mutex_lock(&lock
);
391 if (now
== last_update
) {
399 pthread_mutex_unlock(&lock
);
407 static void *update_loop(void *vu
) {
408 ui_tty
*u
= (ui_tty
*) vu
;
411 #ifdef HAVE_NANOSLEEP
414 t
.tv_nsec
= 100000000;
420 pthread_mutex_lock(&u
->lock
);
423 pthread_mutex_unlock(&u
->lock
);
432 * Constructor may throw an exception to signal that using ui_wo would
433 * be more appropriate.
436 int exception_value
= 1;
438 if (!isatty(fileno(ui_stream
)))
439 throw exception_value
;
442 * Don't use the last column, as this may cause
443 * wrapping in some environments (BSD, Hurd).
446 terminal_width
= get_terminal_width(ui_stream
) - 1;
448 if (terminal_width
< 0)
449 throw exception_value
;
451 buffer
= (char *) calloc(terminal_width
+ 1, sizeof(char));
456 throw exception_value
;
464 * Start an updating thread if possible.
467 pthread_mutex_init(&lock
, NULL
);
468 pthread_attr_t pattr
;
469 pthread_attr_init(&pattr
);
470 pthread_attr_setdetachstate(&pattr
, PTHREAD_CREATE_JOINABLE
);
471 pthread_create(&update_thread
, NULL
, update_loop
, (void *) this);
477 pthread_cancel(update_thread
);
478 pthread_join(update_thread
, NULL
);