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 void 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.
136 void pad_align_status() {
137 for (int i
= 0; i
< status
.steps
- status
.steps_completed
; i
++) {
138 status_printf(1, " ");
141 void pad_match_status() {
142 status_printf(1, " ");
145 void write_match_status() {
146 status_printf(1, format_string_working(), status
.match_value
);
149 void write_status() {
151 if (status
.code
== status
.UNDEFINED
152 || status
.code
== status
.FRAME_DONE
153 || status
.code
== status
.SET_DONE
154 || status
.code
== status
.IP_STEP_DONE
) {
159 if (status
.code
== status
.GLOBAL_ALIGN
160 || status
.code
== status
.ALIGN
161 || status
.code
== status
.POSTMATCH
162 || status
.code
== status
.EXPOSURE_PASS_2
) {
164 write_match_status();
167 status_printf(1, " | ");
169 switch (status
.code
) {
170 case status_type::LOAD_FILE
:
171 status_printf(4, "Loading Image (%s)",
172 "Loading Image", "Loading", "load",
173 status
.cache
? "caching" : "cache is full");
175 case status_type::EXPOSURE_PASS_1
:
176 status_printf(3, "Registering exposure (first pass)", "Registering exposure", "regexp1");
178 case status_type::LODCLUSTER_CREATE
:
179 status_printf(3, "Creating LOD cluster, scale %g", "Creating LOD clusters", "lodcluster",
180 pow(2, -status
.align_lod
));
182 case status_type::PREMATCH
:
183 status_printf(3, "Calculating pre-alignment match", "Calculating match", "prematch");
185 case status_type::GLOBAL_ALIGN
:
186 case status_type::ALIGN
:
187 status_printf(6, "%s [mc=%6.3g] [perturb=%6.3g] [lod=%6.3g] [exp_mult=%6.3g %6.3g %6.3g]",
188 "%s [mc=%6.3g] [perturb=%6.3g] [lod=%6.3g]",
189 "%s [mc=%6.3g] [perturb=%6.3g]",
193 (status
.code
== status_type::GLOBAL_ALIGN
)
198 pow(2, -status
.align_lod
),
199 status
.exp_multiplier
[0],
200 status
.exp_multiplier
[1],
201 status
.exp_multiplier
[2]);
203 case status_type::POSTMATCH
:
204 status_printf(3, "Calculating post-alignment match", "Calculating match", "postmatch");
206 case status_type::EXPOSURE_PASS_2
:
207 status_printf(3, "Registering exposure (second pass)", "Registering exposure", "regexp2");
209 case status_type::RENDERA
:
210 status_printf(3, "Rendering alignment reference image", "Rendering", "render-a");
212 case status_type::RENDERD
:
213 status_printf(3, "Rendering default chain", "Rendering", "render-d");
215 case status_type::RENDERO
:
216 status_printf(3, "Rendering chain %d", "Rendering", "render-o%d", status
.onum
);
218 case status_type::WRITED
:
219 status_printf(4, "Writing default chain to '%s'",
220 "Writing '%s'", "Writing", "write-d", d2::image_rw::output_name());
222 case status_type::WRITEO
:
223 status_printf(3, "Writing image for chain %d", "Writing", "write-o%d", status
.onum
);
225 case status_type::IP_RENDER
:
226 status_printf(3, "Frame '%s'%s",
227 "Frame '%s'", "Processing",
228 d2::image_rw::name(status
.frame_num
), status
.irani_peleg_stage
229 ? ((status
.irani_peleg_stage
== 1) ? " [simulate ]" : " [backproject]")
232 case status_type::IP_UPDATE
:
233 status_printf(3, "Updating approximation", "Updating", "update");
235 case status_type::IP_WRITE
:
236 status_printf(3, "Writing '%s'", "Writing", "write", d2::image_rw::output_name());
238 case status_type::D3_CONTROL_POINT_SOLVE
:
239 status_printf(1, "Aligning control points, %g%% done, error=%g",
240 log(status
.cp_cur_perturb
/ status
.cp_max_perturb
)
241 / log(status
.cp_min_perturb
/ status
.cp_max_perturb
),
242 status
.cp_cur_error
);
244 case status_type::D3_SUBDIVIDING_SPACE
:
245 status_printf(2, "Subdividing space, frame pair (%u, %u), y=%u, x=%u, spaces=%u",
246 "Subdividing space", status
.frame_num
,
247 status
.secondary_frame_num
, status
.y_coordinate
, status
.x_coordinate
,
248 status
.total_spaces
);
250 case status_type::D3_UPDATING_OCCUPANCY
:
251 status_printf(2, "Updating occupancy, step %u/%u, frame %u, space %u/%u",
252 "Updating occupancy", status
.steps_completed
,
253 status
.steps
, status
.frame_num
,
254 status
.space_num
, status
.total_spaces
);
256 case status_type::D3_RENDER
:
257 if (status
.filtering
== 0 && status
.focusing
== 0) {
258 status_printf(1, "space %u/%u",
259 status
.space_num
, status
.total_spaces
);
260 } else if (status
.filtering
== 1 && status
.focusing
== 0) {
261 status_printf(1, "frame %u, y=%u, x=%u",
262 status
.frame_num
, status
.y_coordinate
, status
.x_coordinate
);
263 } else if (status
.filtering
== 0 && status
.focusing
== 1) {
264 status_printf(1, "y=%u, x=%u, view=%u", status
.y_coordinate
, status
.x_coordinate
,
266 } else if (status
.filtering
== 1 && status
.focusing
== 1) {
267 status_printf(1, "view=%u, y=%u, x=%u, frame=%u",
268 status
.view_num
, status
.y_coordinate
, status
.x_coordinate
,
286 void printf(const char *format
, ...) {
288 pthread_mutex_lock(&lock
);
293 if (buffer_index
>= 0 && buffer_index
< terminal_width
/* && format[strlen(format) - 1] != '\n' */) {
294 va_start(ap
, format
);
295 n
= vsnprintf(buffer
+ buffer_index
, terminal_width
- buffer_index
, format
, ap
);
299 if (n
>= 0 && n
< terminal_width
- buffer_index
) {
301 * The message fits in the buffer, so update the index
302 * and write buffer and status information.
307 if (format
[strlen(format
) - 1] == '\n') {
315 * The message does not fit in the buffer, so write any
316 * existing buffer and append the new text to the stream.
318 if (buffer_index
>= 0) {
319 assert(buffer_index
< terminal_width
);
320 buffer
[buffer_index
] = '\0';
324 va_start(ap
, format
);
325 vfprintf(ui_stream
, format
, ap
);
330 * This is not the only case that produces a newline,
331 * but ignoring other cases should be safe.
333 if (format
[strlen(format
) - 1] == '\n') {
338 pthread_mutex_unlock(&lock
);
343 static time_t last_update
= 0;
344 time_t now
= time(NULL
);
347 * Handle DONE status.
350 if (status
.code
== status_type::FRAME_DONE
) {
353 pthread_mutex_lock(&lock
);
355 fputc('\n', ui_stream
);
359 pthread_mutex_unlock(&lock
);
361 } else if (status
.code
== status_type::SET_DONE
) {
363 pthread_mutex_lock(&lock
);
365 fputc('\n', ui_stream
);
369 pthread_mutex_unlock(&lock
);
374 * Handle optional output.
378 pthread_mutex_lock(&lock
);
380 if (now
== last_update
) {
388 pthread_mutex_unlock(&lock
);
396 static void *update_loop(void *vu
) {
397 ui_tty
*u
= (ui_tty
*) vu
;
400 #ifdef HAVE_NANOSLEEP
403 t
.tv_nsec
= 100000000;
409 pthread_mutex_lock(&u
->lock
);
412 pthread_mutex_unlock(&u
->lock
);
421 * Constructor may throw an exception to signal that using ui_wo would
422 * be more appropriate.
425 int exception_value
= 1;
427 if (!isatty(fileno(ui_stream
)))
428 throw exception_value
;
431 * Don't use the last column, as this may cause
432 * wrapping in some environments (BSD, Hurd).
435 terminal_width
= get_terminal_width(ui_stream
) - 1;
437 if (terminal_width
< 0)
438 throw exception_value
;
440 buffer
= (char *) calloc(terminal_width
+ 1, sizeof(char));
445 throw exception_value
;
453 * Start an updating thread if possible.
456 pthread_mutex_init(&lock
, NULL
);
457 pthread_attr_t pattr
;
458 pthread_attr_init(&pattr
);
459 pthread_attr_setdetachstate(&pattr
, PTHREAD_CREATE_JOINABLE
);
460 pthread_create(&update_thread
, NULL
, update_loop
, (void *) this);
466 pthread_cancel(update_thread
);
467 pthread_join(update_thread
, NULL
);