bugs: Advantages for incremental library separation by analogy with incremental
[Ale.git] / ui / input.h
blob5c2c571aa204886e02795a486b641b4f5a23eb33
1 // Copyright 2002, 2003, 2004, 2005, 2006 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
21 #ifndef __input_h__
22 #define __input_h__
25 * ANSI C and POSIX include files.
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <assert.h>
32 #include <time.h>
33 // #include <math.h>
34 #include <stack>
35 #include <map>
37 #include "../ale_math.h"
40 * Interface files
43 #include "ui.h"
44 #include "accel.h"
45 #include "unsupported.h"
46 #include "implication.h"
49 * Configuration
52 #if HAVE_CONFIG_H
53 # include <config.h>
54 #endif
57 * Types
60 #include "../ale_pos.h"
61 #include "../ale_real.h"
64 * 2D include files
67 #include "../d2.h"
70 * 3D include files
73 #include "../d3.h"
76 * Thread include files
79 #include "../thread.h"
82 * Device configuration files
85 #include "../device/xvp610_320x240.h"
86 #include "../device/xvp610_640x480.h"
87 #include "../device/ov7620_raw_linear.h"
88 #include "../device/canon_300d_raw_linear.h"
89 #include "../device/canon_300d_raw_linear_85mm_1_8.h"
90 #include "../device/canon_300d_raw_linear_50mm_1_8.h"
91 #include "../device/canon_300d_raw_linear_50mm_1_4.h"
92 #include "../device/canon_300d_raw_linear_50mm_1_4_1_4.h"
93 #include "../device/nikon_d50.h"
96 * Help files
99 #include "help.h"
101 class input {
104 * Flag for global options.
107 static int global_options;
110 * Helper functions.
114 * Argument counter.
116 * Counts instances of a given option.
118 static unsigned int arg_count(int argc, const char *argv[], const char *arg) {
119 unsigned int count = 0;
120 for (int i = 0; i < argc; i++) {
121 if (!strcmp(argv[i], arg))
122 count++;
123 else if (!strcmp(argv[i], "--"))
124 return count;
126 return count;
130 * Argument prefix counter.
132 * Counts instances of a given option prefix.
134 static unsigned int arg_prefix_count(int argc, const char *argv[], const char *pfix) {
135 unsigned int count = 0;
136 for (int i = 0; i < argc; i++) {
137 if (!strncmp(argv[i], pfix, strlen(pfix)))
138 count++;
139 else if (!strcmp(argv[i], "--"))
140 return count;
142 return count;
146 * Reallocation function
148 static void *local_realloc(void *ptr, size_t size) {
149 void *new_ptr = realloc(ptr, size);
151 if (new_ptr == NULL)
152 ui::get()->memory_error_location("main()");
154 return new_ptr;
158 * Not enough arguments function.
160 static void not_enough(const char *opt_name) {
161 ui::get()->cli_not_enough(opt_name);
165 * Bad argument function
167 static void bad_arg(const char *opt_name) {
168 ui::get()->cli_bad_arg(opt_name);
172 * String comparison class.
175 class compare_strings {
176 public:
177 int operator()(const char *A, const char *B) const {
178 return strcmp(A, B) < 0;
183 * Environment structures.
185 * XXX: It's arguable that these should be public members of the
186 * 'input' class in order to allow passing environment values to other
187 * classes, but, since we're currently using them only to prepare state
188 * for an internal 'input' function, they can stay private for now. A
189 * more nuanced approach will likely be required later.
192 class environment {
193 static std::stack<environment *> environment_stack;
194 static std::set<environment *> environment_set;
196 std::map<const char *, const char *, compare_strings> environment_map;
199 * Internal set operations do not protect any data.
202 void internal_set(const char *name, const char *value) {
203 environment_map[name] = value;
206 void internal_unset(const char *name) {
207 environment_map.erase(name);
210 const char *internal_convert_pointer(const void *pointer) {
211 int chars = sizeof(void *) * 2 + 3;
212 char *c = (char *) malloc(sizeof(char) * chars);
214 assert(c);
216 if (!c)
217 ui::get()->memory_error_location("environment::set_ptr");
219 int count = snprintf(c, chars, "%p", pointer);
221 assert (count >= 0 && count < chars);
223 return c;
226 void internal_set_ptr(const char *name, const void *pointer) {
227 internal_set(name, internal_convert_pointer(pointer));
231 * Check for restricted names.
234 int name_ok(const char *name) {
235 if (!strcmp(name, "---chain") || !strcmp(name, "---this"))
236 return 0;
238 return 1;
241 void name_check(const char *name) {
242 if (!name_ok(name)) {
243 fprintf(stderr, "Bad set operation.");
244 assert(0);
245 exit(1);
249 public:
252 * Get the environment map.
255 std::map<const char *, const char *, compare_strings> &get_map() {
256 return environment_map;
260 * Public set operations restrict valid names.
263 void set(const char *name, const char *value) {
264 name_check(name);
265 internal_set(name, value);
268 void unset(const char *name) {
269 name_check(name);
270 internal_unset(name);
273 void set_ptr(const char *name, const void *pointer) {
274 name_check(name);
275 internal_set_ptr(name, pointer);
278 const char *get(const char *name) {
279 if (environment_map.count(name) == 0)
280 return NULL;
282 return environment_map[name];
286 * Make an environment substructure. Note that since deep
287 * structures are currently referenced rather than copied when
288 * the stack is pushed, there is no current need for any
289 * chaining mechanism.
291 void make_substructure(const char *name) {
292 environment *s = new environment;
293 set_ptr(name, s);
294 environment_set.insert(s);
297 static int is_env(const char *name) {
298 void *ptr_value;
299 sscanf(name, "%p", &ptr_value);
302 * Check for bad pointers.
305 if (!environment_set.count((environment *) ptr_value)) {
306 return 0;
309 return 1;
312 const char *get_option_name(const char *name) {
313 if (strncmp(name, "0 ", strlen("0 ")))
314 return NULL;
316 name += strlen("0 ");
318 if (!isdigit(name[0]))
319 return NULL;
321 while (isdigit(name[0]))
322 name++;
324 if (!isspace(name[0]))
325 return NULL;
327 while (isspace(name[0]))
328 name++;
330 if (!isalnum(name[0]))
331 return NULL;
333 return name;
336 int is_option(const char *name) {
337 return (get_option_name(name) != NULL);
340 int is_arg(const char *name, unsigned int arg) {
341 assert (is_option(name));
343 int length = strlen(name) + 3 * sizeof(unsigned int);
345 char *desired_string = (char *) malloc(sizeof(char) * length);
347 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
349 int result = environment_map.count(desired_string);
351 free(desired_string);
353 return result > 0;
356 void remove_arg(const char *name, unsigned int arg) {
357 assert (is_option(name));
358 assert (is_arg(name, arg));
360 int length = strlen(name) + 3 * sizeof(unsigned int);
362 char *desired_string = (char *) malloc(sizeof(char) * length);
364 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
366 environment_map.erase(desired_string);
368 free(desired_string);
371 const char *get_string_arg(const char *name, unsigned int arg) {
372 assert (is_option(name));
374 int length = strlen(name) + 3 * sizeof(unsigned int);
376 char *desired_string = (char *) malloc(sizeof(char) * length);
378 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
380 const char *result = environment_map[desired_string];
382 assert (result);
384 free(desired_string);
386 return result;
389 long int get_long_arg(const char *name, unsigned int arg) {
390 assert (is_option(name));
392 const char *string = get_string_arg(name, arg);
393 char *endptr;
395 long int result = strtol(string, &endptr, 0);
397 if (endptr[0] != '\0') {
398 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
399 exit(1);
402 return result;
405 int get_int_arg(const char *name, unsigned int arg) {
406 return (int) get_long_arg(name, arg);
409 unsigned int get_unsigned_arg(const char *name, unsigned int arg) {
410 long int result = get_long_arg(name, arg);
412 if (result < 0) {
413 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
414 exit(1);
417 return (unsigned int) result;
420 double get_double_arg(const char *name, unsigned int arg) {
421 assert (is_option(name));
423 const char *string = get_string_arg(name, arg);
424 char *endptr;
426 double result = strtod(string, &endptr);
428 if (endptr[0] != '\0') {
429 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
430 exit(1);
433 return result;
436 static environment *get_env(const char *name) {
438 assert(name);
440 void *ptr_value;
441 sscanf(name, "%p", &ptr_value);
444 * Check for bad pointers.
447 if (!environment_set.count((environment *) ptr_value)) {
448 assert(0);
449 fprintf(stderr, "Bad environment pointer.\n");
450 exit(1);
453 return (environment *) ptr_value;
457 * Prepend to a list.
459 void prepend(const char *list, const char *element) {
460 environment *d = get_env(get(list));
461 make_substructure(list);
462 get_env(get(list))->set("a", element);
463 get_env(get(list))->set_ptr("d", d);
466 void prepend_ptr(const char *list, void *ptr) {
467 prepend(list, internal_convert_pointer(ptr));
471 * Clone the environment.
473 environment *clone() {
474 environment *e = new environment();
476 for (std::map<const char *, const char *, compare_strings>::iterator i = environment_map.begin();
477 i != environment_map.end(); i++) {
479 if (!name_ok(i->first))
480 continue;
482 if (is_env(i->second)) {
483 e->set_ptr(i->first, get_env(i->second)->clone());
484 } else {
485 e->set(i->first, i->second);
489 return e;
492 static environment *top() {
493 if (environment_stack.empty()) {
494 environment_stack.push(new environment);
495 environment_set.insert(environment_stack.top());
497 return environment_stack.top();
500 static void push() {
501 environment *e = new environment;
503 e->environment_map = environment_stack.top()->environment_map;
505 e->internal_set_ptr("---chain", environment_stack.top());
506 e->internal_set_ptr("---this", e);
507 e->make_substructure("---dup");
509 environment_stack.push(e);
510 environment_set.insert(e);
513 static void dup_second() {
514 environment_stack.top()->prepend_ptr("---dup",
515 environment::get_env(environment_stack.top()->get("---chain")));
518 static void push_and_dup_output() {
519 push();
520 dup_second();
523 static void pop() {
524 assert(!environment_stack.empty());
527 * Execution environments should never be referenced by
528 * structures further up the call chain, so they can
529 * safely be deleted. (XXX: In particular, while
530 * lexical scoping may require copying of execution
531 * environments from lower on the call chain, there is
532 * no obvious reason that a reference should be used in
533 * this case; a shallow copy should be used instead.)
536 environment_set.erase(environment_stack.top());
537 delete environment_stack.top();
539 environment_stack.pop();
543 * Set with duplication.
546 void set_with_dup(const char *name, const char *value) {
547 set(name, value);
549 if (!get("---dup"))
550 return;
552 environment *dup_item = get_env(get("---dup"));
554 assert (dup_item);
556 while (dup_item->get("a")) {
557 get_env(dup_item->get("a"))->set_with_dup(name, value);
558 assert(dup_item->get("d"));
559 dup_item = get_env(dup_item->get("d"));
560 assert(dup_item);
566 * Read tokens from a stream.
568 class token_reader {
569 public:
571 * Get the next token
573 virtual const char *get() = 0;
576 * Peek at the next token.
579 virtual const char *peek() = 0;
582 * Divert the stream until the next occurrence of TOKEN.
584 virtual token_reader *divert(const char *open_token, const char *close_token) = 0;
586 virtual int expects_exactly_one_option(void) {
587 return 0;
590 virtual ~token_reader() {
594 class argument_parsing_token_reader : public token_reader {
595 const char *index;
596 const char *separators;
597 public:
598 argument_parsing_token_reader(const char *s) {
599 index = s;
600 separators = "=";
603 int expects_exactly_one_option(void) {
604 return 1;
607 virtual const char *get() {
608 int length = strcspn(index, separators);
610 if (length == 0)
611 return NULL;
613 const char *result = strndup(index, length);
614 index += length;
616 if (strspn(index, separators) >= 1)
617 index++;
619 separators = ",";
621 return result;
624 virtual const char *peek() {
625 int length = strcspn(index, separators);
627 if (length == 0)
628 return NULL;
630 const char *result = strndup(index, length);
632 return result;
635 virtual token_reader *divert(const char *open_token, const char *close_token) {
636 assert(0);
637 return NULL;
641 class cstring_token_reader : public token_reader {
642 const char *separators;
643 const char *string;
644 int ephemeral;
646 cstring_token_reader(const char *s, int ephemeral) {
647 assert(ephemeral == 1);
649 separators = "\n \t";
650 string = s;
651 this->ephemeral = 1;
654 public:
655 cstring_token_reader(const char *s) {
656 separators = "\n \t";
657 string = s;
658 ephemeral = 0;
661 const char *get() {
663 string += strspn(string, separators);
665 size_t length_to_next = strcspn(string, separators);
667 if (length_to_next == 0)
668 return NULL;
670 const char *result = strndup(string, length_to_next);
672 string += length_to_next;
674 return result;
677 const char *peek() {
678 string += strspn(string, separators);
680 size_t length_to_next = strcspn(string, separators);
682 if (length_to_next == 0)
683 return NULL;
685 return strndup(string, length_to_next);
688 cstring_token_reader *divert(const char *open_token, const char *close_token) {
690 * This function might be broken.
693 assert(0);
695 int search = 0;
696 int next = strcspn(string, separators);
697 int depth = 0;
699 while (*(string + search) != '\0' &&
700 (depth || strcmp(close_token, (string + search)))) {
701 if (!strcmp(close_token, (string + search)))
702 depth--;
703 if (!strcmp(open_token, (string + search)))
704 depth++;
705 search = next;
706 next = strcspn((string + next), separators);
709 if (*(string + search) == '\0') {
710 fprintf(stderr, "Parse error: End of scope not found.");
711 exit(1);
714 cstring_token_reader *result = new cstring_token_reader(strndup(string, search), 1);
716 string += search;
719 * Eat the closing token.
722 get();
724 return result;
727 ~cstring_token_reader() {
728 if (ephemeral)
729 free((void *) string);
733 class cli_token_reader : public token_reader {
735 int arg_index;
736 int argc;
737 const char **argv;
739 public:
740 cli_token_reader(int c, const char *v[]) {
741 argc = c;
742 argv = v;
743 arg_index = 0;
746 const char *get() {
748 if (arg_index < argc)
749 return argv[arg_index++];
750 else
751 return NULL;
755 const char *peek() {
757 if (arg_index < argc)
758 return argv[arg_index];
759 else
760 return NULL;
764 cli_token_reader *divert(const char *open_token, const char *close_token) {
765 int search = 0;
766 int depth = 0;
768 while (arg_index + search < argc
769 && (depth || strcmp(argv[arg_index + search], close_token))) {
770 if (!strcmp(close_token, argv[arg_index + search]))
771 depth--;
772 if (!strcmp(open_token, argv[arg_index + search]))
773 depth++;
774 search++;
777 if (arg_index + search == argc) {
778 fprintf(stderr, "Parse error: end of scope not found.\n");
779 exit(1);
782 cli_token_reader *result = new cli_token_reader(search, argv + arg_index);
784 arg_index += search;
787 * Eat the closing token.
790 get();
792 return result;
797 struct simple_option {
798 const char *name;
799 const char *map_name;
800 const char *map_value;
801 int arg_count;
802 int multi;
805 static const char *supported_nonglobal_option_table[];
806 static const char *focus_prefixes[];
807 static simple_option simple_option_table[];
809 static int option_name_match(const char *unadorned, const char *token, int require_ornamentation = 1) {
810 int strip_max = 2;
812 if (!strcmp(unadorned, token) && !require_ornamentation)
813 return 1;
815 while (token[0] == '-' && strip_max) {
816 token++;
817 strip_max--;
818 if (!strcmp(unadorned, token))
819 return 1;
822 return 0;
825 static int is_scope_operator(const char *string) {
826 if (!strcmp("{", string)
827 || !strcmp("}", string)
828 || !strcmp("[", string)
829 || !strcmp("]", string)
830 || !strcmp("<", string)
831 || !strcmp(">", string))
832 return 1;
834 return 0;
837 static const char *option_name_gen(const char *unadorned, const char *map_name, int arg_num, int multi) {
838 static unsigned int multi_counter = 0;
840 if (map_name) {
841 unadorned = map_name;
844 int length = (strlen(unadorned) + sizeof(unsigned int) * 3 + sizeof(int) * 3 + 2) + 1;
846 char *result = (char *) malloc(sizeof(char) * length);
848 assert (result);
850 if (!multi) {
851 snprintf(result, length, "%u 0 %s", arg_num, unadorned);
852 } else {
855 * XXX: This assumes that generating calls for
856 * options other than 0 exist in the same
857 * multiplicity group as the most recently
858 * generated 0-option multiplicity.
861 if (arg_num == 0)
862 multi_counter++;
864 snprintf(result, length, "%u %u %s", arg_num, multi_counter, unadorned);
867 return result;
870 static environment *genv;
872 static const char *get_next(token_reader *tr, const char *option_name) {
873 const char *argument = tr->get();
875 if (argument == NULL) {
876 fprintf(stderr, "\n\nError: not enough arguments for `%s'.\n\n", option_name);
877 exit(1);
880 return argument;
883 static int table_contains(const char **haystack, const char *needle, int prefix_length = 0) {
885 if (needle == NULL)
886 return 0;
888 while (*haystack != NULL) {
889 if (prefix_length == 0 && !strcmp(*haystack, needle))
890 return 1;
891 if (prefix_length > 0 && !strncmp(*haystack, needle, prefix_length))
892 return 1;
893 haystack++;
896 return 0;
899 static int option_is_identical(environment *a, environment *b, const char *option_name) {
900 if (!a->is_option(option_name) || !b->is_option(option_name))
901 return 0;
903 int option_number = 0;
905 while (a->is_arg(option_name, option_number) || b->is_arg(option_name, option_number)) {
906 if (!a->is_arg(option_name, option_number)
907 || !b->is_arg(option_name, option_number))
908 return 0;
910 const char *a_str = a->get_string_arg(option_name, option_number);
911 const char *b_str = b->get_string_arg(option_name, option_number);
913 if (strcmp(a_str, b_str))
914 return 0;
916 option_number++;
919 return 1;
922 static void remove_option(environment *a, const char *option_name) {
923 assert(a->is_option(option_name));
925 int option_number = 0;
927 while (a->is_arg(option_name, option_number)) {
928 a->remove_arg(option_name, option_number);
929 option_number++;
933 static void remove_nonglobals(environment *a) {
934 assert(a);
936 std::stack<const char *> removal_stack;
938 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
939 i != a->get_map().end(); i++) {
941 if (!a->is_option(i->first))
942 continue;
944 if (!table_contains(supported_nonglobal_option_table, a->get_option_name(i->first)))
945 continue;
947 removal_stack.push(i->first);
950 while (!removal_stack.empty()) {
951 remove_option(a, removal_stack.top());
952 removal_stack.pop();
956 static void option_intersect(environment *a, environment *b) {
957 assert(a);
958 assert(b);
960 std::stack<const char *> removal_stack;
962 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
963 i != a->get_map().end(); i++) {
965 if (!a->is_option(i->first))
966 continue;
968 if (option_is_identical(a, b, i->first))
969 continue;
971 removal_stack.push(i->first);
974 while (!removal_stack.empty()) {
975 remove_option(a, removal_stack.top());
976 removal_stack.pop();
980 static void option_difference(environment *a, environment *b) {
981 assert(a);
982 assert(b);
984 std::stack<const char *> removal_stack;
986 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
987 i != a->get_map().end(); i++) {
989 if (!a->is_option(i->first))
990 continue;
992 if (!option_is_identical(a, b, i->first))
993 continue;
995 removal_stack.push(i->first);
998 while (!removal_stack.empty()) {
999 remove_option(a, removal_stack.top());
1000 removal_stack.pop();
1004 static void evaluate_stream(token_reader *tr,
1005 std::vector<std::pair<const char *, environment *> > *files) {
1006 const char *token;
1007 int end_of_options = 0;
1009 while ((token = tr->get())) {
1012 * Check for nesting
1015 if (!strcmp(token, "{") && !end_of_options) {
1016 environment::push_and_dup_output();
1017 token_reader *tr_nest = tr->divert("{", "}");
1018 evaluate_stream(tr_nest, files);
1019 delete tr_nest;
1020 environment::pop();
1021 } else if (!strcmp(token, "[") && !end_of_options) {
1022 global_options = 0;
1023 environment::push();
1024 token_reader *tr_nest = tr->divert("[", "]");
1025 evaluate_stream(tr_nest, files);
1026 delete tr_nest;
1027 environment::pop();
1028 } else if (!strcmp(token, "<") && !end_of_options) {
1029 environment *dup_list = environment::get_env(environment::top()->get("---dup"));
1030 assert (dup_list != NULL);
1031 dup_list = dup_list->clone();
1033 environment::dup_second();
1034 token_reader *tr_nest = tr->divert("<", ">");
1035 evaluate_stream(tr_nest, files);
1036 delete tr_nest;
1038 environment::top()->set_ptr("---dup", dup_list);
1042 * Check for non-whitespace argument separators
1045 else if (!end_of_options && token && token[0] == '-' && strchr(token, '=')) {
1046 environment::push_and_dup_output();
1047 token_reader *tr_nest = new argument_parsing_token_reader(token);
1048 evaluate_stream(tr_nest, files);
1049 delete tr_nest;
1050 environment::pop();
1054 * Trap the end-of-option indicator.
1057 else if (!strcmp(token, "--")) {
1058 global_options = 0;
1059 end_of_options = 1;
1063 * Check for options and filenames
1066 else {
1068 * Handle filenames.
1071 if (strncmp("-", token, strlen("-")) || end_of_options) {
1073 assert(files);
1075 global_options = 0;
1076 files->push_back(std::pair<const char *, environment *>(strdup(token),
1077 environment::top()->clone()));
1079 if (tr->expects_exactly_one_option() && tr->get()) {
1080 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1081 exit(1);
1084 continue;
1088 * Handle focus option.
1091 if (option_name_match("focus", token)) {
1093 environment *target;
1094 target = environment::top();
1096 target->set_with_dup(option_name_gen("focus", NULL, 0, 0), "1");
1098 const char *option = get_next(tr, "focus");
1100 target->set_with_dup(option_name_gen("focus", NULL, 1, 0), option);
1102 if (!strcmp(option, "d")) {
1103 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1104 get_next(tr, "focus"));
1105 } else if (!strcmp(option, "p")) {
1106 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1107 get_next(tr, "focus"));
1108 target->set_with_dup(option_name_gen("focus", NULL, 3, 0),
1109 get_next(tr, "focus"));
1110 } else
1111 bad_arg("focus");
1113 int arg = 0;
1115 while (table_contains(focus_prefixes, tr->peek(), 3)) {
1116 target->set_with_dup(option_name_gen("focus", NULL, 4 + arg, 0),
1117 get_next(tr, "focus"));
1118 arg++;
1121 continue;
1125 * Handle simple options.
1128 int found_option = 0;
1129 for (int i = 0; simple_option_table[i].name; i++) {
1130 if (!option_name_match(simple_option_table[i].name, token))
1131 continue;
1134 * Handle the match case.
1137 found_option = 1;
1140 * Determine which environment should be modified
1143 environment *target;
1144 target = environment::top();
1147 * Store information required for
1148 * handling the local case later.
1151 const char *map_value = "1";
1153 if (simple_option_table[i].map_value) {
1154 map_value = simple_option_table[i].map_value;
1155 } else if (simple_option_table[i].map_name) {
1156 map_value = simple_option_table[i].name;
1159 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1160 simple_option_table[i].map_name,
1162 simple_option_table[i].multi),
1163 map_value);
1165 for (int j = 0; j < simple_option_table[i].arg_count; j++) {
1166 const char *option = tr->get();
1168 if (option == NULL) {
1169 fprintf(stderr, "\n\nError: not enough options for `%s'.\n\n", token);
1170 exit(1);
1174 * Reject scope operators as options,
1175 * at least for now.
1178 if (is_scope_operator(option)) {
1179 fprintf(stderr, "\n\nError: illegal argument to `%s'.\n\n", token);
1180 exit(1);
1183 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1184 simple_option_table[i].map_name,
1185 j + 1,
1186 simple_option_table[i].multi),
1187 option);
1192 * Trap illegal options.
1195 if (!found_option)
1196 ui::get()->illegal_option(token);
1199 if (tr->expects_exactly_one_option() && tr->get()) {
1200 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1201 exit(1);
1206 public:
1209 * Libale Sequence structure and functions.
1212 static ale_image seq_file(ale_sequence s, int n) {
1213 return d2::image_rw::open_simple(n);
1216 static ale_trans seq_trans(ale_sequence s, int n) {
1217 return align::of(n);
1220 static ale_exclusion_list seq_ex(ale_sequence s, int n) {
1221 return ((input *) ale_sequence_data(s))->ex;
1224 static void seq_status(int n, ale_sequence s) {
1227 static void seq_step(ale_sequence s, int j) {
1228 input *input_data = (input *) ale_sequence_data(s);
1231 * Iterate through non-global options
1234 environment *env = files[j].second;
1236 for (std::map<const char *, const char *>::iterator i = env->get_map().begin();
1237 i != env->get_map().end(); i++) {
1239 if (!env->is_option(i->first))
1240 continue;
1242 const char *option_name = env->get_option_name(i->first);
1244 if (!strcmp(option_name, "mc")) {
1245 d2::align::mc(env->get_double_arg(i->first, 1));
1246 } else if (!strcmp(option_name, "md")) {
1247 d2::trans_multi::set_md(env->get_double_arg(i->first, 1));
1248 } else if (!strcmp(option_name, "ma-cert")) {
1249 d2::align::set_ma_cert(env->get_double_arg(i->first, 1));
1250 } else if (!strcmp(option_name, "mi")) {
1251 d2::trans_multi::set_mi(env->get_double_arg(i->first, 1));
1252 } else if (!strcmp(option_name, "gs-mo")) {
1253 const char *option = env->get_string_arg(i->first, 1);
1254 double gs_mo;
1255 int characters;
1256 sscanf(option, "%lf%n", &gs_mo, &characters);
1257 if (*(option + characters) == '%')
1258 d2::align::gs_mo(gs_mo, 1);
1259 else
1260 d2::align::gs_mo(gs_mo, 0);
1261 } else if (!strcmp(option_name, "ev")) {
1262 double ev = env->get_double_arg(i->first, 1);
1263 double gain_value = pow(2, -ev);
1265 if (j == 0)
1266 d2::exposure::set_gain_reference(gain_value);
1267 else
1268 input_exposure[j]->set_gain_multiplier(
1269 (double) d2::exposure::get_gain_reference()
1270 / gain_value);
1272 } else if (!strcmp(option_name, "black")) {
1273 double black = env->get_double_arg(i->first, 1);
1274 input_exposure[j]->set_black_level(black);
1275 } else if (!strcmp(option_name, "perturb-upper")) {
1276 const char *option = env->get_string_arg(i->first, 1);
1277 double perturb_upper;
1278 int characters;
1279 sscanf(option, "%lf%n", &perturb_upper, &characters);
1280 if (*(option + characters) == '%')
1281 d2::align::set_perturb_upper(perturb_upper, 1);
1282 else
1283 d2::align::set_perturb_upper(perturb_upper, 0);
1284 } else if (!strcmp(option_name, "threads")) {
1285 thread::set_count((unsigned int) env->get_int_arg(i->first, 1));
1286 } else if (!strcmp(option_name, "per-cpu")) {
1287 thread::set_per_cpu((unsigned int) env->get_int_arg(i->first, 1));
1288 } else {
1290 * This error should be encountered earlier.
1293 assert(0);
1295 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
1296 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
1297 option_name);
1298 exit(1);
1302 if (j == 0) {
1305 * Write comment information about original frame and
1306 * target image to the transformation save file, if we
1307 * have one.
1310 tsave_orig(tsave, files[0].first);
1311 tsave_target(tsave, files[files.size() - 1].first);
1313 ui::get()->original_frame_start(files[0].first);
1315 } else {
1318 * Write comment information about the supplemental
1319 * frame to the transformation save file, if we have
1320 * one.
1323 tsave_info (tsave, name);
1325 ui::get()->supplemental_frame_start(d2::image_rw::name(j));
1329 for (int i = 0; i < input_data->oc_count; i++) {
1331 ui::get()->set_orender_current(opt);
1333 if (input_data->extend || j == 0)
1334 ale_render_extend_sync(input_data->ochain[i], s, j);
1336 ale_render_merge_sync(input_data->ochain[i], s, j);
1338 if (inc) {
1339 ui::get()->writing_output(opt);
1340 d2::image_rw::write_image(ochain_names[opt], ochain[opt]->get_image(0));
1343 d2::vise_core::frame_queue_add(j);
1346 if (j == 0)
1347 ui::get()->original_frame_done();
1348 else
1349 ui::get()->supplemental_frame_done();
1354 * Input handler.
1356 * Does one of two things:
1358 * (1) Output version information if called with '--version'
1360 * (2) Read options and file arguments, and if the arguments are correct,
1361 * write output. If an error is detected, print the usage statement.
1365 static void handle(int argc, const char *argv[], const char *package, const char *short_version, const char *version) {
1368 * Initialize help object
1371 help hi(package, argv[0], short_version);
1374 * Output version information if --version appears
1375 * on the command line.
1378 if (arg_count(argc, argv, "--version")) {
1380 * Output the version
1383 fprintf(stdout, "%s", version);
1386 * Output relevant environment variables
1389 fprintf(stdout, "Environment:\n");
1391 const char *env_names[] = {
1392 "ALE_BIN",
1393 "DCRAW",
1394 "EXIF_UTILITY",
1395 "ALE_COUNT_THREADS",
1396 "PAGER",
1397 NULL
1400 for (int i = 0; env_names[i]; i++) {
1401 char *value = getenv(env_names[i]);
1403 fprintf(stdout, " %s=%s\n",
1404 env_names[i], value ? value : "");
1407 return;
1411 * Handle help options
1414 if (arg_prefix_count(argc, argv, "--h"))
1415 for (int i = 1; i < argc; i++) {
1416 int all = !strcmp(argv[i], "--hA");
1417 int is_help_option = !strncmp(argv[i], "--h", strlen("--h"));
1418 int found_help = 0;
1420 if (!strcmp(argv[i], "--hu") || all)
1421 hi.usage(), found_help = 1;
1422 if (!strcmp(argv[i], "--hq") || all)
1423 hi.defaults(), found_help = 1;
1424 if (!strcmp(argv[i], "--hf") || all)
1425 hi.file(), found_help = 1;
1426 if (!strcmp(argv[i], "--he") || all)
1427 hi.exclusion(), found_help = 1;
1428 if (!strcmp(argv[i], "--ha") || all)
1429 hi.alignment(), found_help = 1;
1430 if (!strcmp(argv[i], "--hr") || all)
1431 hi.rendering(), found_help = 1;
1432 if (!strcmp(argv[i], "--hx") || all)
1433 hi.exposure(), found_help = 1;
1434 if (!strcmp(argv[i], "--ht") || all)
1435 hi.tdf(), found_help = 1;
1436 if (!strcmp(argv[i], "--hl") || all)
1437 hi.filtering(), found_help = 1;
1438 if (!strcmp(argv[i], "--hd") || all)
1439 hi.device(), found_help = 1;
1440 if (!strcmp(argv[i], "--hi") || all)
1441 hi.interface(), found_help = 1;
1442 if (!strcmp(argv[i], "--hv") || all)
1443 hi.visp(), found_help = 1;
1444 if (!strcmp(argv[i], "--hc") || all)
1445 hi.cp(), found_help = 1;
1446 if (!strcmp(argv[i], "--h3") || all)
1447 hi.d3(), found_help = 1;
1448 if (!strcmp(argv[i], "--hs") || all)
1449 hi.scope(), found_help = 1;
1450 if (!strcmp(argv[i], "--hp") || all)
1451 hi.process(), found_help = 1;
1452 if (!strcmp(argv[i], "--hz") || all)
1453 hi.undocumented(), found_help = 1;
1455 if (is_help_option && !found_help)
1456 hi.usage();
1459 * Check for the end-of-options marker, a non-option argument,
1460 * or the end of arguments. In all of these cases, we exit.
1463 if (!strcmp(argv[i], "--")
1464 || strncmp(argv[i], "--", strlen("--"))
1465 || i == argc - 1)
1466 return;
1470 * Undocumented projective transformation utility
1473 if (arg_count(argc, argv, "--ptcalc") > 0) {
1474 fprintf(stderr, "\n\n*** Warning: this feature is not documented ***\n\n");
1475 printf("Enter: w h tlx tly blx bly brx bry trx try x y\n\n");
1477 double w, h, tlx, tly, blx, bly, brx, bry, trx, tr_y, x, y;
1479 printf("> ");
1481 if (scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
1482 &w, &h, &tlx, &tly, &blx, &bly, &brx, &bry, &trx, &tr_y, &x, &y) != 12) {
1484 fprintf(stderr, "Error reading input.\n");
1485 exit(1);
1488 d2::image *i = d2::new_image_ale_real((int)h, (int)w, 3);
1489 d2::transformation t = d2::transformation::gpt_identity(i, 1);
1490 d2::point q[4] = {
1491 d2::point(tly, tlx),
1492 d2::point(bly, blx),
1493 d2::point(bry, brx),
1494 d2::point(tr_y, trx)
1496 t.gpt_set(q);
1498 d2::point a(y, x), b;
1500 b = t.transform_scaled(a);
1502 printf("TRANSFORM t(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1504 b = t.scaled_inverse_transform(a);
1506 printf("INVERSE t^-1(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1508 exit(0);
1512 * Thread initialization.
1515 thread::init();
1518 * Flags and variables
1521 double scale_factor = 1;
1522 double vise_scale_factor = 1;
1523 #if 0
1524 double usm_multiplier = 0.0;
1525 #endif
1526 int extend = 0;
1527 struct d2::tload_t *tload = NULL;
1528 struct d2::tsave_t *tsave = NULL;
1529 struct d3::tload_t *d3_tload = NULL;
1530 struct d3::tsave_t *d3_tsave = NULL;
1531 int ip_iterations = 0;
1532 int ip_use_median = 0;
1533 double ipwl = 0;
1534 enum { psf_linear, psf_nonlinear, psf_N };
1535 const char *psf[psf_N] = {NULL, NULL};
1536 const char *device = NULL;
1537 int psf_match = 0;
1538 double psf_match_args[6];
1539 int inc = 0;
1540 int exposure_register = 1;
1541 const char *wm_filename = NULL;
1542 int wm_offsetx = 0, wm_offsety = 0;
1543 double cx_parameter = 1;
1544 double *d3px_parameters = NULL;
1545 int d3px_count = 0;
1546 d2::exclusion *ex_parameters = NULL;
1547 int ex_count = 0;
1548 int ex_show = 0;
1549 d2::render *achain;
1550 const char *achain_type = "triangle:2";
1551 const char *afilter_type = "internal";
1552 d2::render **ochain = NULL;
1553 const char **ochain_names = NULL;
1554 const char **ochain_types = NULL;
1555 const char *d3chain_type = NULL;
1556 int oc_count = 0;
1557 const char **visp = NULL;
1558 int vise_count = 0;
1559 const char **d3_output = NULL;
1560 const char **d3_depth = NULL;
1561 unsigned int d3_count = 0;
1562 double user_view_angle = 0;
1563 int user_bayer = IMAGE_BAYER_DEFAULT;
1564 d2::pixel exp_mult = d2::pixel(1, 1, 1);
1565 std::map<const char *, d3::pt> d3_output_pt;
1566 std::map<const char *, d3::pt> d3_depth_pt;
1567 double cache = 256; /* MB */
1570 * dchain is ochain[0].
1573 ochain = (d2::render **) local_realloc(ochain,
1574 (oc_count + 1) * sizeof(d2::render *));
1575 ochain_names = (const char **) local_realloc((void *)ochain_names,
1576 (oc_count + 1) * sizeof(const char *));
1577 ochain_types = (const char **) local_realloc((void *)ochain_types,
1578 (oc_count + 1) * sizeof(const char *));
1580 ochain_types[0] = "sinc*lanc:8";
1582 oc_count = 1;
1585 * Handle default settings
1588 if (arg_prefix_count(argc, argv, "--q") > 0)
1589 ui::get()->error("Default settings --q* are no longer recognized.");
1591 #define FIXED16 4
1592 #if ALE_COLORS == FIXED16
1593 const char *defaults =
1594 "--dchain auto:triangle:2,fine:box:1,triangle:2 "
1595 "--achain triangle:2 "
1596 "--ips 0 "
1597 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ";
1598 #else
1599 const char *defaults =
1600 "--dchain auto:triangle:2,fine:box:1,triangle:2 "
1601 "--achain triangle:2 "
1602 "--ips 1 "
1603 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ";
1604 #endif
1605 #undef FIXED16
1607 token_reader *default_reader = new cstring_token_reader(defaults);
1609 evaluate_stream(default_reader, NULL);
1612 * Set basic program information in the environment.
1615 environment::top()->set_with_dup("---package", package);
1616 environment::top()->set_with_dup("---short-version", short_version);
1617 environment::top()->set_with_dup("---version", version);
1618 environment::top()->set_with_dup("---invocation", argv[0]);
1621 * Initialize the top-level token-reader and generate
1622 * an environment variable for it.
1625 token_reader *tr = new cli_token_reader(argc - 1, argv + 1);
1626 environment::top()->set_ptr("---token-reader", tr);
1629 * Evaluate the command-line arguments to generate environment
1630 * structures.
1633 std::vector<std::pair<const char *, environment *> > files;
1635 evaluate_stream(tr, &files);
1638 * If there are fewer than two files, then output usage information.
1641 if (files.size() < 2) {
1642 hi.usage();
1643 exit(1);
1647 * Extract the global environment and check non-globals
1648 * against a list of supported non-global options.
1651 genv = files[0].second->clone();
1653 remove_nonglobals(genv);
1655 for (unsigned int i = 0; i < files.size(); i++) {
1656 option_intersect(genv, files[i].second);
1659 for (unsigned int i = 0; i < files.size(); i++) {
1660 option_difference(files[i].second, genv);
1662 for (std::map<const char *, const char *>::iterator j = files[i].second->get_map().begin();
1663 j != files[i].second->get_map().end(); j++) {
1665 environment *env = files[i].second;
1667 if (!env->is_option(j->first))
1668 continue;
1670 const char *option_name = env->get_option_name(j->first);
1672 if (!table_contains(supported_nonglobal_option_table, option_name)) {
1673 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
1674 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
1675 option_name);
1676 exit(1);
1682 * Iterate through the global environment,
1683 * looking for options.
1686 for (std::map<const char *, const char *>::iterator i = genv->get_map().begin();
1687 i != genv->get_map().end(); i++) {
1689 environment *env = genv;
1691 if (!env->is_option(i->first))
1692 continue;
1694 const char *option_name = env->get_option_name(i->first);
1696 if (!strcmp(option_name, "default")) {
1698 * Do nothing. Defaults have already been set.
1700 } else if (!strcmp(option_name, "bpc")) {
1701 if (!strcmp(env->get_string_arg(i->first, 0), "8bpc"))
1702 d2::image_rw::depth8();
1703 else if (!strcmp(env->get_string_arg(i->first, 0), "16bpc"))
1704 d2::image_rw::depth16();
1705 else
1706 assert(0);
1707 } else if (!strcmp(option_name, "format")) {
1708 if (!strcmp(env->get_string_arg(i->first, 0), "plain"))
1709 d2::image_rw::ppm_plain();
1710 else if (!strcmp(env->get_string_arg(i->first, 0), "raw"))
1711 d2::image_rw::ppm_raw();
1712 else if (!strcmp(env->get_string_arg(i->first, 0), "auto"))
1713 d2::image_rw::ppm_auto();
1714 else
1715 assert(0);
1716 } else if (!strcmp(option_name, "align")) {
1717 if (!strcmp(env->get_string_arg(i->first, 0), "align-all"))
1718 d2::align::all();
1719 else if (!strcmp(env->get_string_arg(i->first, 0), "align-green"))
1720 d2::align::green();
1721 else if (!strcmp(env->get_string_arg(i->first, 0), "align-sum"))
1722 d2::align::sum();
1723 else
1724 assert(0);
1725 } else if (!strcmp(option_name, "transformation")) {
1726 if (!strcmp(env->get_string_arg(i->first, 0), "translation"))
1727 d2::align::class_translation();
1728 else if (!strcmp(env->get_string_arg(i->first, 0), "euclidean"))
1729 d2::align::class_euclidean();
1730 else if (!strcmp(env->get_string_arg(i->first, 0), "projective"))
1731 d2::align::class_projective();
1732 else
1733 assert(0);
1734 } else if (!strcmp(option_name, "transformation-default")) {
1735 if (!strcmp(env->get_string_arg(i->first, 0), "identity"))
1736 d2::align::initial_default_identity();
1737 else if (!strcmp(env->get_string_arg(i->first, 0), "follow"))
1738 d2::align::initial_default_follow();
1739 else
1740 assert(0);
1741 } else if (!strcmp(option_name, "perturb")) {
1742 if (!strcmp(env->get_string_arg(i->first, 0), "perturb-output"))
1743 d2::align::perturb_output();
1744 else if (!strcmp(env->get_string_arg(i->first, 0), "perturb-source"))
1745 d2::align::perturb_source();
1746 else
1747 assert(0);
1748 } else if (!strcmp(option_name, "fail")) {
1749 if (!strcmp(env->get_string_arg(i->first, 0), "fail-optimal"))
1750 d2::align::fail_optimal();
1751 else if (!strcmp(env->get_string_arg(i->first, 0), "fail-default"))
1752 d2::align::fail_default();
1753 else
1754 assert(0);
1755 } else if (!strcmp(option_name, "profile")) {
1756 ui::set_profile();
1757 } else if (!strcmp(option_name, "extend")) {
1758 if (env->get_int_arg(i->first, 0))
1759 extend = 1;
1760 else
1761 extend = 0;
1762 } else if (!strcmp(option_name, "oc")) {
1763 if (env->get_int_arg(i->first, 0))
1764 d3::scene::oc();
1765 else
1766 d3::scene::no_oc();
1767 } else if (!strcmp(option_name, "focus")) {
1769 double one = +1;
1770 double zero = +0;
1771 double inf = one / zero;
1773 assert (isinf(inf) && inf > 0);
1776 * Focus type
1779 unsigned int type = 0;
1780 double distance = 0;
1781 double px = 0, py = 0;
1783 if (!strcmp(env->get_string_arg(i->first, 1), "d")) {
1785 type = 0;
1787 distance = env->get_double_arg(i->first, 2);
1789 } else if (!strcmp(env->get_string_arg(i->first, 1), "p")) {
1791 type = 1;
1793 px = env->get_double_arg(i->first, 2);
1794 py = env->get_double_arg(i->first, 3);
1796 } else {
1797 bad_arg(option_name);
1801 * Options
1804 unsigned int ci = 0;
1805 double fr = 0;
1806 double ht = 0;
1807 double vt = 0;
1808 double sd = 0;
1809 double ed = inf;
1810 double sx = -inf;
1811 double ex = inf;
1812 double sy = -inf;
1813 double ey = inf;
1814 double ap = 3;
1815 unsigned int sc = 3;
1816 unsigned int fs = 0;
1817 unsigned int sr = 0;
1819 for (int arg_num = 4; env->is_arg(i->first, arg_num); arg_num++) {
1820 const char *option = env->get_string_arg(i->first, arg_num);
1821 if (!strncmp(option, "ci=", 3)) {
1822 if(sscanf(option + 3, "%u", &ci) != 1)
1823 bad_arg("--focus");
1824 } else if (!strncmp(option, "fr=", 3)) {
1825 if(sscanf(option + 3, "%lf", &fr) != 1)
1826 bad_arg("--focus");
1827 } else if (!strncmp(option, "ht=", 3)) {
1828 if(sscanf(option + 3, "%lf", &ht) != 1)
1829 bad_arg("--focus");
1830 } else if (!strncmp(option, "vt=", 3)) {
1831 if(sscanf(option + 3, "%lf", &vt) != 1)
1832 bad_arg("--focus");
1833 } else if (!strncmp(option, "sy=", 3)) {
1834 if(sscanf(option + 3, "%lf", &sy) != 1)
1835 bad_arg("--focus");
1836 } else if (!strncmp(option, "ey=", 3)) {
1837 if(sscanf(option + 3, "%lf", &ey) != 1)
1838 bad_arg("--focus");
1839 } else if (!strncmp(option, "sx=", 3)) {
1840 if(sscanf(option + 3, "%lf", &sx) != 1)
1841 bad_arg("--focus");
1842 } else if (!strncmp(option, "ex=", 3)) {
1843 if(sscanf(option + 3, "%lf", &ex) != 1)
1844 bad_arg("--focus");
1845 } else if (!strncmp(option, "sd=", 3)) {
1846 if(sscanf(option + 3, "%lf", &sd) != 1)
1847 bad_arg("--focus");
1848 } else if (!strncmp(option, "ed=", 3)) {
1849 if(sscanf(option + 3, "%lf", &ed) != 1)
1850 bad_arg("--focus");
1851 } else if (!strncmp(option, "ap=", 3)) {
1852 if(sscanf(option + 3, "%lf", &ap) != 1)
1853 bad_arg("--focus");
1854 } else if (!strncmp(option, "sc=", 3)) {
1855 if(sscanf(option + 3, "%u", &sc) != 1)
1856 bad_arg("--focus");
1857 } else if (!strncmp(option, "sr=", 3)) {
1858 if (!strcmp(option, "sr=aperture")) {
1859 sr = 0;
1860 } else if (!strcmp(option, "sr=pixel")) {
1861 sr = 1;
1862 } else
1863 bad_arg("--focus");
1865 } else if (!strncmp(option, "fs=", 3)) {
1866 if (!strcmp(option, "fs=mean")) {
1867 fs = 0;
1868 } else if (!strcmp(option, "fs=median")) {
1869 fs = 1;
1870 } else
1871 bad_arg("--focus");
1872 } else
1873 bad_arg("--focus");
1876 d3::focus::add_region(type, distance, px, py, ci, fr, ht, vt, sd, ed, sx, ex, sy, ey, ap, sc, fs, sr);
1878 } else if (!strcmp(option_name, "3ddp") || !strcmp(option_name, "3dvp")) {
1879 d2::align::keep();
1882 * Unsupported configurations
1885 if (ip_iterations)
1886 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1888 #if 0
1889 if (usm_multiplier)
1890 unsupported::fornow("3D modeling with unsharp mask");
1891 #endif
1894 * Initialize if necessary
1896 * Note: because their existence is checked as an
1897 * indicator of the presence of 3D arguments, we
1898 * initialize these structures here.
1901 if (d3_output == NULL) {
1902 d3_count = argc;
1903 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1904 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1907 unsigned int width, height;
1908 double view_angle;
1909 double x, y, z;
1910 double P, Y, R;
1912 width = env->get_unsigned_arg(i->first, 1);
1913 height = env->get_unsigned_arg(i->first, 2);
1914 view_angle = env->get_double_arg(i->first, 3);
1915 x = env->get_double_arg(i->first, 4);
1916 y = env->get_double_arg(i->first, 5);
1917 z = env->get_double_arg(i->first, 6);
1918 P = env->get_double_arg(i->first, 7);
1919 Y = env->get_double_arg(i->first, 8);
1920 R = env->get_double_arg(i->first, 9);
1922 view_angle *= M_PI / 180;
1923 P *= M_PI / 180;
1924 Y *= M_PI / 180;
1925 R *= M_PI / 180;
1927 d2::transformation t =
1928 d2::transformation::eu_identity();
1929 t.set_domain(height, width);
1930 d3::pt _pt(t, d3::et(y, x, z, Y, P, R), view_angle);
1932 if (!strcmp(option_name, "3dvp")) {
1933 d3_output_pt[env->get_string_arg(i->first, 10)] = _pt;
1934 } else if (!strcmp(option_name, "3ddp")) {
1935 d3_depth_pt[env->get_string_arg(i->first, 10)] = _pt;
1936 } else {
1937 assert(0);
1939 } else if (!strcmp(option_name, "3dv")) {
1940 d2::align::keep();
1942 unsigned int frame_no;
1945 * Unsupported configurations
1948 if (ip_iterations)
1949 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1951 #if 0
1952 if (usm_multiplier)
1953 unsupported::fornow("3D modeling with unsharp mask");
1954 #endif
1957 * Initialize if necessary
1960 if (d3_output == NULL) {
1961 d3_count = argc;
1962 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1963 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1966 frame_no = env->get_int_arg(i->first, 1);
1968 if (frame_no >= d3_count)
1969 ui::get()->error("--3dv argument 0 is too large");
1971 if (d3_output[frame_no] != NULL) {
1972 unsupported::fornow ("Writing a single 3D view to more than one output file");
1975 d3_output[frame_no] = env->get_string_arg(i->first, 2);
1977 } else if (!strcmp(option_name, "3dd")) {
1978 d2::align::keep();
1980 unsigned int frame_no;
1983 * Unsupported configurations
1986 if (ip_iterations)
1987 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1989 #if 0
1990 if (usm_multiplier)
1991 unsupported::fornow("3D modeling with unsharp mask");
1992 #endif
1995 * Initialize if necessary
1998 if (d3_output == NULL) {
1999 d3_count = argc;
2000 d3_output = (const char **) calloc(d3_count, sizeof(char *));
2001 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
2004 frame_no = env->get_int_arg(i->first, 1);
2006 if (frame_no >= d3_count)
2007 ui::get()->error("--3dd argument 0 is too large");
2009 if (d3_depth[frame_no] != NULL) {
2010 unsupported::fornow ("Writing a single frame's depth info to more than one output file");
2013 d3_depth[frame_no] = env->get_string_arg(i->first, 2);
2015 } else if (!strcmp(option_name, "view-angle")) {
2016 user_view_angle = env->get_double_arg(i->first, 1) * M_PI / 180;
2017 } else if (!strcmp(option_name, "cpf-load")) {
2018 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
2019 } else if (!strcmp(option_name, "accel")) {
2020 if (!strcmp(env->get_string_arg(i->first, 1), "gpu"))
2021 accel::set_gpu();
2022 else if (!strcmp(env->get_string_arg(i->first, 1), "cpu"))
2023 accel::set_cpu();
2024 else if (!strcmp(env->get_string_arg(i->first, 1), "accel"))
2025 accel::set_accel();
2026 else if (!strcmp(env->get_string_arg(i->first, 1), "auto"))
2027 accel::set_auto();
2028 else {
2029 fprintf(stderr, "Error: Unknown acceleration type '%s'\n",
2030 env->get_string_arg(i->first, 1));
2031 exit(1);
2033 } else if (!strcmp(option_name, "ui")) {
2034 if (!strcmp(env->get_string_arg(i->first, 1), "stream"))
2035 ui::set_stream();
2036 else if (!strcmp(env->get_string_arg(i->first, 1), "tty"))
2037 ui::set_tty();
2038 else if (!strcmp(env->get_string_arg(i->first, 1), "log"))
2039 ui::set_log();
2040 else if (!strcmp(env->get_string_arg(i->first, 1), "quiet"))
2041 ui::set_quiet();
2042 else {
2043 fprintf(stderr, "Error: Unknown user interface type '%s'\n",
2044 env->get_string_arg(i->first, 1));
2045 exit(1);
2047 } else if (!strcmp(option_name, "3d-fmr")) {
2048 d3::scene::fmr(env->get_double_arg(i->first, 1));
2049 } else if (!strcmp(option_name, "3d-dmr")) {
2050 d3::scene::dmr(env->get_double_arg(i->first, 1));
2051 } else if (!strcmp(option_name, "et")) {
2052 d3::scene::et(env->get_double_arg(i->first, 1));
2053 } else if (!strcmp(option_name, "st")) {
2054 d3::cpf::st(env->get_double_arg(i->first, 1));
2055 } else if (!strcmp(option_name, "di-lower")) {
2056 d3::scene::di_lower(env->get_double_arg(i->first, 1));
2057 } else if (!strcmp(option_name, "rc")) {
2058 d3::scene::rc(env->get_double_arg(i->first, 1));
2059 } else if (!strcmp(option_name, "do-try")) {
2060 d3::scene::do_try(env->get_double_arg(i->first, 1));
2061 } else if (!strcmp(option_name, "di-upper")) {
2062 d3::scene::di_upper(env->get_double_arg(i->first, 1));
2063 } else if (!strcmp(option_name, "fc")) {
2064 d3::scene::fc(env->get_double_arg(i->first, 1));
2065 } else if (!strcmp(option_name, "ecm")) {
2066 unsupported::discontinued("--ecm <x>");
2067 } else if (!strcmp(option_name, "acm")) {
2068 unsupported::discontinued("--acm <x>");
2069 } else if (!strcmp(option_name, "def-nn")) {
2070 d2::image_rw::def_nn(env->get_double_arg(i->first, 1));
2072 if (env->get_double_arg(i->first, 1) > 2) {
2073 fprintf(stderr, "\n\n*** Warning: --def-nn implementation is currently "
2074 "inefficient for large radii. ***\n\n");
2077 } else if (!strcmp(option_name, "fx")) {
2078 d3::scene::fx(env->get_double_arg(i->first, 1));
2079 } else if (!strcmp(option_name, "tcem")) {
2080 d3::scene::tcem(env->get_double_arg(i->first, 1));
2081 } else if (!strcmp(option_name, "oui")) {
2082 d3::scene::oui(env->get_unsigned_arg(i->first, 1));
2083 } else if (!strcmp(option_name, "pa")) {
2084 d3::scene::pa(env->get_unsigned_arg(i->first, 1));
2085 } else if (!strcmp(option_name, "pc")) {
2086 d3::scene::pc(env->get_string_arg(i->first, 1));
2087 } else if (!strcmp(option_name, "cw")) {
2088 d2::align::certainty_weighted(env->get_unsigned_arg(i->first, 0));
2089 } else if (!strcmp(option_name, "wm")) {
2090 if (wm_filename != NULL)
2091 ui::get()->error("only one weight map can be specified");
2093 wm_filename = env->get_string_arg(i->first, 1);
2094 wm_offsetx = env->get_int_arg(i->first, 2);
2095 wm_offsety = env->get_int_arg(i->first, 3);
2097 } else if (!strcmp(option_name, "fl")) {
2098 #ifdef USE_FFTW
2099 d2::align::set_frequency_cut(env->get_double_arg(i->first, 1),
2100 env->get_double_arg(i->first, 2),
2101 env->get_double_arg(i->first, 3));
2103 #else
2104 ui::get()->error_hint("--fl is not supported", "rebuild ALE with FFTW support");
2105 #endif
2106 } else if (!strcmp(option_name, "wmx")) {
2107 #ifdef USE_UNIX
2108 d2::align::set_wmx(env->get_string_arg(i->first, 1),
2109 env->get_string_arg(i->first, 2),
2110 env->get_string_arg(i->first, 3));
2111 #else
2112 ui::get()->error_hint("--wmx is not supported", "rebuild ALE with support for --wmx");
2113 #endif
2114 } else if (!strcmp(option_name, "flshow")) {
2115 d2::align::set_fl_show(env->get_string_arg(i->first, 1));
2116 } else if (!strcmp(option_name, "3dpx")) {
2118 d3px_parameters = (double *) local_realloc(d3px_parameters, (d3px_count + 1) * 6 * sizeof(double));
2120 for (int param = 0; param < 6; param++)
2121 d3px_parameters[6 * d3px_count + param] = env->get_double_arg(i->first, param + 1);
2124 * Swap x and y, since their internal meanings differ from their external meanings.
2127 for (int param = 0; param < 2; param++) {
2128 double temp = d3px_parameters[6 * d3px_count + 2 + param];
2129 d3px_parameters[6 * d3px_count + 2 + param] = d3px_parameters[6 * d3px_count + 0 + param];
2130 d3px_parameters[6 * d3px_count + 0 + param] = temp;
2135 * Increment counters
2138 d3px_count++;
2140 } else if (!strcmp(option_name, "ex") || !strcmp(option_name, "fex")) {
2142 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
2143 (ex_count + 1) * sizeof(d2::exclusion));
2145 ex_parameters[ex_count].type = (!strcmp(option_name, "ex"))
2146 ? d2::exclusion::RENDER
2147 : d2::exclusion::FRAME;
2150 * Get parameters, swapping x and y coordinates
2153 ex_parameters[ex_count].x[0] = env->get_int_arg(i->first, 1 + 2);
2154 ex_parameters[ex_count].x[1] = env->get_int_arg(i->first, 1 + 3);
2155 ex_parameters[ex_count].x[2] = env->get_int_arg(i->first, 1 + 0);
2156 ex_parameters[ex_count].x[3] = env->get_int_arg(i->first, 1 + 1);
2157 ex_parameters[ex_count].x[4] = env->get_int_arg(i->first, 1 + 4);
2158 ex_parameters[ex_count].x[5] = env->get_int_arg(i->first, 1 + 5);
2161 * Increment counters
2164 ex_count++;
2166 } else if (!strcmp(option_name, "crop") || !strcmp(option_name, "fcrop")) {
2168 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
2169 (ex_count + 4) * sizeof(d2::exclusion));
2171 for (int r = 0; r < 4; r++)
2172 ex_parameters[ex_count + r].type = (!strcmp(option_name, "crop"))
2173 ? d2::exclusion::RENDER
2174 : d2::exclusion::FRAME;
2177 int crop_args[6];
2179 for (int param = 0; param < 6; param++)
2180 crop_args[param] = env->get_int_arg(i->first, param + 1);
2183 * Construct exclusion regions from the crop area,
2184 * swapping x and y, since their internal meanings
2185 * differ from their external meanings.
2189 * Exclusion region 1: low x
2192 ex_parameters[ex_count + 0].x[0] = INT_MIN;
2193 ex_parameters[ex_count + 0].x[1] = crop_args[2] - 1;
2194 ex_parameters[ex_count + 0].x[2] = INT_MIN;
2195 ex_parameters[ex_count + 0].x[3] = INT_MAX;
2196 ex_parameters[ex_count + 0].x[4] = crop_args[4];
2197 ex_parameters[ex_count + 0].x[5] = crop_args[5];
2200 * Exclusion region 2: low y
2203 ex_parameters[ex_count + 1].x[0] = INT_MIN;
2204 ex_parameters[ex_count + 1].x[1] = INT_MAX;
2205 ex_parameters[ex_count + 1].x[2] = INT_MIN;
2206 ex_parameters[ex_count + 1].x[3] = crop_args[0] - 1;
2207 ex_parameters[ex_count + 1].x[4] = crop_args[4];
2208 ex_parameters[ex_count + 1].x[5] = crop_args[5];
2211 * Exclusion region 3: high y
2214 ex_parameters[ex_count + 2].x[0] = INT_MIN;
2215 ex_parameters[ex_count + 2].x[1] = INT_MAX;
2216 ex_parameters[ex_count + 2].x[2] = crop_args[1] + 1;
2217 ex_parameters[ex_count + 2].x[3] = INT_MAX;
2218 ex_parameters[ex_count + 2].x[4] = crop_args[4];
2219 ex_parameters[ex_count + 2].x[5] = crop_args[5];
2222 * Exclusion region 4: high x
2225 ex_parameters[ex_count + 3].x[0] = crop_args[3] + 1;
2226 ex_parameters[ex_count + 3].x[1] = INT_MAX;
2227 ex_parameters[ex_count + 3].x[2] = INT_MIN;
2228 ex_parameters[ex_count + 3].x[3] = INT_MAX;
2229 ex_parameters[ex_count + 3].x[4] = crop_args[4];
2230 ex_parameters[ex_count + 3].x[5] = crop_args[5];
2233 * Increment counters
2236 ex_count += 4;
2238 } else if (!strcmp(option_name, "exshow")) {
2239 ex_show = 1;
2240 } else if (!strcmp(option_name, "wt")) {
2241 d2::render::set_wt(env->get_double_arg(i->first, 1));
2242 } else if (!strcmp(option_name, "3d-chain")) {
2243 d3chain_type = env->get_string_arg(i->first, 1);
2244 } else if (!strcmp(option_name, "dchain")) {
2245 ochain_types[0] = env->get_string_arg(i->first, 1);
2246 } else if (!strcmp(option_name, "achain")) {
2247 achain_type = env->get_string_arg(i->first, 1);
2248 } else if (!strcmp(option_name, "afilter")) {
2249 afilter_type = env->get_string_arg(i->first, 1);
2250 } else if (!strcmp(option_name, "ochain")) {
2252 ochain = (d2::render **) local_realloc(ochain,
2253 (oc_count + 1) * sizeof(d2::render *));
2254 ochain_names = (const char **) local_realloc((void *)ochain_names,
2255 (oc_count + 1) * sizeof(const char *));
2256 ochain_types = (const char **) local_realloc((void *)ochain_types,
2257 (oc_count + 1) * sizeof(const char *));
2259 ochain_types[oc_count] = env->get_string_arg(i->first, 1);
2260 ochain_names[oc_count] = env->get_string_arg(i->first, 2);
2262 oc_count++;
2264 } else if (!strcmp(option_name, "visp")) {
2266 visp = (const char **) local_realloc((void *)visp, 4 *
2267 (vise_count + 1) * sizeof(const char *));
2269 for (int param = 0; param < 4; param++)
2270 visp[vise_count * 4 + param] = env->get_string_arg(i->first, param + 1);
2272 vise_count++;
2274 } else if (!strcmp(option_name, "cx")) {
2275 cx_parameter = env->get_int_arg(i->first, 0) ? env->get_double_arg(i->first, 1) : 0;
2276 } else if (!strcmp(option_name, "ip")) {
2277 unsupported::discontinued("--ip <r> <i>", "--lpsf box=<r> --ips <i>");
2278 } else if (!strcmp(option_name, "cache")) {
2279 cache = env->get_double_arg(i->first, 1);
2280 } else if (!strcmp(option_name, "resident")) {
2281 double resident = env->get_double_arg(i->first, 1);
2283 d2::image::set_resident(resident);
2285 } else if (!strcmp(option_name, "bayer")) {
2288 * External order is clockwise from top-left. Internal
2289 * order is counter-clockwise from top-left.
2292 const char *option = env->get_string_arg(i->first, 1);
2294 if (!strcmp(option, "rgbg")) {
2295 user_bayer = IMAGE_BAYER_RGBG;
2296 } else if (!strcmp(option, "bgrg")) {
2297 user_bayer = IMAGE_BAYER_BGRG;
2298 } else if (!strcmp(option, "gbgr")) {
2299 user_bayer = IMAGE_BAYER_GRGB;
2300 } else if (!strcmp(option, "grgb")) {
2301 user_bayer = IMAGE_BAYER_GBGR;
2302 } else if (!strcmp(option, "none")) {
2303 user_bayer = IMAGE_BAYER_NONE;
2304 } else {
2305 bad_arg("--bayer");
2308 } else if (!strcmp(option_name, "lpsf")) {
2309 psf[psf_linear] = env->get_string_arg(i->first, 1);
2310 } else if (!strcmp(option_name, "nlpsf")) {
2311 psf[psf_nonlinear] = env->get_string_arg(i->first, 1);
2312 } else if (!strcmp(option_name, "psf-match")) {
2314 psf_match = 1;
2316 for (int index = 0; index < 6; index++) {
2317 psf_match_args[index] = env->get_double_arg(i->first, index + 1);
2320 } else if (!strcmp(option_name, "device")) {
2321 device = env->get_string_arg(i->first, 1);
2322 #if 0
2323 } else if (!strcmp(option_name, "usm")) {
2325 if (d3_output != NULL)
2326 unsupported::fornow("3D modeling with unsharp mask");
2328 usm_multiplier = env->get_double_arg(i->first, 1);
2329 #endif
2331 } else if (!strcmp(option_name, "ipr")) {
2333 ip_iterations = env->get_int_arg(i->first, 1);
2335 ui::get()->warn("--ipr is deprecated. Use --ips instead");
2337 } else if (!strcmp(option_name, "cpp-err")) {
2338 if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2339 d3::cpf::err_median();
2340 else if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2341 d3::cpf::err_mean();
2342 } else if (!strcmp(option_name, "vp-adjust")) {
2343 if (env->get_int_arg(i->first, 0))
2344 d3::align::vp_adjust();
2345 else
2346 d3::align::vp_noadjust();
2347 } else if (!strcmp(option_name, "vo-adjust")) {
2348 if (env->get_int_arg(i->first, 0))
2349 d3::align::vo_adjust();
2350 else
2351 d3::align::vo_noadjust();
2352 } else if (!strcmp(option_name, "ip-statistic")) {
2353 if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2354 ip_use_median = 0;
2355 else if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2356 ip_use_median = 1;
2357 } else if (!strcmp(option_name, "ips")) {
2358 ip_iterations = env->get_int_arg(i->first, 1);
2359 } else if (!strcmp(option_name, "ip-wl")) {
2360 int limited = env->get_int_arg(i->first, 0);
2361 if (limited) {
2362 ipwl = env->get_double_arg(i->first, 1);
2363 } else {
2364 ipwl = 0;
2366 } else if (!strcmp(option_name, "ipc")) {
2367 unsupported::discontinued("--ipc <c> <i>", "--ips <i> --lpsf <c>", "--ips <i> --device <c>");
2368 } else if (!strcmp(option_name, "exp-extend")) {
2369 if (env->get_int_arg(i->first, 0))
2370 d2::image_rw::exp_scale();
2371 else
2372 d2::image_rw::exp_noscale();
2373 } else if (!strcmp(option_name, "exp-register")) {
2374 if (env->get_int_arg(i->first, 0) == 1) {
2375 exposure_register = 1;
2376 d2::align::exp_register();
2377 } else if (env->get_int_arg(i->first, 0) == 0) {
2378 exposure_register = 0;
2379 d2::align::exp_noregister();
2380 } else if (env->get_int_arg(i->first, 0) == 2) {
2381 exposure_register = 2;
2382 d2::align::exp_meta_only();
2384 } else if (!strcmp(option_name, "drizzle-only")) {
2385 unsupported::discontinued("--drizzle-only", "--dchain box:1");
2386 } else if (!strcmp(option_name, "subspace-traverse")) {
2387 unsupported::undocumented("--subspace-traverse");
2388 d3::scene::set_subspace_traverse();
2389 } else if (!strcmp(option_name, "3d-filter")) {
2390 if (env->get_int_arg(i->first, 0))
2391 d3::scene::filter();
2392 else
2393 d3::scene::nofilter();
2394 } else if (!strcmp(option_name, "occ-norm")) {
2395 if (env->get_int_arg(i->first, 0))
2396 d3::scene::nw();
2397 else
2398 d3::scene::no_nw();
2399 } else if (!strcmp(option_name, "inc")) {
2400 inc = env->get_int_arg(i->first, 0);
2401 } else if (!strcmp(option_name, "exp-mult")) {
2402 double exp_c, exp_r, exp_b;
2404 exp_c = env->get_double_arg(i->first, 1);
2405 exp_r = env->get_double_arg(i->first, 2);
2406 exp_b = env->get_double_arg(i->first, 3);
2408 exp_mult = d2::pixel(1/(exp_r * exp_c), 1/exp_c, 1/(exp_b * exp_c));
2410 } else if (!strcmp(option_name, "visp-scale")) {
2412 vise_scale_factor = env->get_double_arg(i->first, 1);
2414 if (vise_scale_factor <= 0.0)
2415 ui::get()->error("VISP scale must be greater than zero");
2417 if (!finite(vise_scale_factor))
2418 ui::get()->error("VISP scale must be finite");
2420 } else if (!strcmp(option_name, "scale")) {
2422 scale_factor = env->get_double_arg(i->first, 1);
2424 if (scale_factor <= 0)
2425 ui::get()->error("Scale factor must be greater than zero");
2427 if (!finite(scale_factor))
2428 ui::get()->error("Scale factor must be finite");
2430 } else if (!strcmp(option_name, "metric")) {
2431 d2::align::set_metric_exponent(env->get_double_arg(i->first, 1));
2432 } else if (!strcmp(option_name, "threshold")) {
2433 d2::align::set_match_threshold(env->get_double_arg(i->first, 1));
2434 } else if (!strcmp(option_name, "drizzle-diam")) {
2435 unsupported::discontinued("--drizzle-diam=<x>", "--dchain box:1");
2436 } else if (!strcmp(option_name, "perturb-lower")) {
2437 const char *option = env->get_string_arg(i->first, 1);
2438 double perturb_lower;
2439 int characters;
2440 sscanf(option, "%lf%n", &perturb_lower, &characters);
2441 if (perturb_lower <= 0)
2442 ui::get()->error("--perturb-lower= value is non-positive");
2444 if (*(option + characters) == '%')
2445 d2::align::set_perturb_lower(perturb_lower, 1);
2446 else
2447 d2::align::set_perturb_lower(perturb_lower, 0);
2448 } else if (!strcmp(option_name, "stepsize")) {
2449 ui::get()->warn("--stepsize is deprecated. Use --perturb-lower instead");
2450 d2::align::set_perturb_lower(env->get_double_arg(i->first, 1), 0);
2451 } else if (!strcmp(option_name, "va-upper")) {
2452 const char *option = env->get_string_arg(i->first, 1);
2453 double va_upper;
2454 int characters;
2455 sscanf(option, "%lf%n", &va_upper, &characters);
2456 if (*(option + characters) == '%')
2457 ui::get()->error("--va-upper= does not accept '%' arguments\n");
2458 else
2459 d3::cpf::set_va_upper(va_upper);
2460 } else if (!strcmp(option_name, "cpp-upper")) {
2461 const char *option = env->get_string_arg(i->first, 1);
2462 double perturb_upper;
2463 int characters;
2464 sscanf(option, "%lf%n", &perturb_upper, &characters);
2465 if (*(option + characters) == '%')
2466 ui::get()->error("--cpp-upper= does not currently accept '%' arguments\n");
2467 else
2468 d3::cpf::set_cpp_upper(perturb_upper);
2469 } else if (!strcmp(option_name, "cpp-lower")) {
2470 const char *option = env->get_string_arg(i->first, 1);
2471 double perturb_lower;
2472 int characters;
2473 sscanf(option, "%lf%n", &perturb_lower, &characters);
2474 if (*(option + characters) == '%')
2475 ui::get()->error("--cpp-lower= does not currently accept '%' arguments\n");
2476 else
2477 d3::cpf::set_cpp_lower(perturb_lower);
2478 } else if (!strcmp(option_name, "hf-enhance")) {
2479 unsupported::discontinued("--hf-enhance=<x>");
2480 } else if (!strcmp(option_name, "multi")) {
2481 d2::trans_multi::set_multi(env->get_string_arg(i->first, 1));
2482 } else if (!strcmp(option_name, "track")) {
2483 if (!strcmp(env->get_string_arg(i->first, 0), "none")) {
2484 d2::trans_multi::track_none();
2485 } else if (!strcmp(env->get_string_arg(i->first, 0), "primary")) {
2486 d2::trans_multi::track_primary();
2487 } else if (!strcmp(env->get_string_arg(i->first, 0), "point")) {
2488 d2::trans_multi::track_point(env->get_double_arg(i->first, 1),
2489 env->get_double_arg(i->first, 2));
2490 } else {
2491 assert(0);
2493 } else if (!strcmp(option_name, "gs")) {
2494 d2::align::gs(env->get_string_arg(i->first, 1));
2495 } else if (!strcmp(option_name, "rot-upper")) {
2496 d2::align::set_rot_max((int) floor(env->get_double_arg(i->first, 1)));
2497 } else if (!strcmp(option_name, "bda-mult")) {
2498 d2::align::set_bda_mult(env->get_double_arg(i->first, 1));
2499 } else if (!strcmp(option_name, "bda-rate")) {
2500 d2::align::set_bda_rate(env->get_double_arg(i->first, 1));
2501 } else if (!strcmp(option_name, "lod-preferred")) {
2502 d2::align::set_lod_preferred((int) floor(env->get_double_arg(i->first, 1)));
2503 } else if (!strcmp(option_name, "min-dimension")) {
2504 d2::align::set_min_dimension((int) ceil(env->get_double_arg(i->first, 1)));
2505 } else if (!strcmp(option_name, "cpf-load")) {
2506 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
2507 #if 0
2508 } else if (!strcmp(option_name, "model-load")) {
2509 d3::scene::load_model(env->get_string_arg(i->first, 1));
2510 } else if (!strcmp(option_name, "model-save")) {
2511 d3::scene::save_model(env->get_string_arg(i->first, 1));
2512 #endif
2513 } else if (!strcmp(option_name, "trans-load")) {
2514 d2::tload_delete(tload);
2515 tload = d2::tload_new(env->get_string_arg(i->first, 1));
2516 d2::align::set_tload(tload);
2517 } else if (!strcmp(option_name, "trans-save")) {
2518 tsave_delete(tsave);
2519 tsave = d2::tsave_new(env->get_string_arg(i->first, 1));
2520 d2::align::set_tsave(tsave);
2521 } else if (!strcmp(option_name, "3d-trans-load")) {
2522 d3::tload_delete(d3_tload);
2523 d3_tload = d3::tload_new(env->get_string_arg(i->first, 1));
2524 d3::align::set_tload(d3_tload);
2525 } else if (!strcmp(option_name, "3d-trans-save")) {
2526 d3::tsave_delete(d3_tsave);
2527 d3_tsave = d3::tsave_new(env->get_string_arg(i->first, 1));
2528 d3::align::set_tsave(d3_tsave);
2529 } else {
2530 assert(0);
2535 * Initialize the interface.
2538 ui::get();
2541 * Apply implication logic.
2544 if (extend == 0 && vise_count != 0) {
2545 implication::changed("VISP requires increased image extents.",
2546 "Image extension is now enabled.",
2547 "--extend");
2548 extend = 1;
2551 if (psf_match && ex_count)
2552 unsupported::fornow("PSF calibration with exclusion regions.");
2555 if (d3_output != NULL && ip_iterations != 0)
2556 unsupported::fornow("3D modeling with Irani-Peleg rendering");
2558 #if 0
2559 if (extend == 0 && d3_output != NULL) {
2560 implication::changed("3D modeling requires increased image extents.",
2561 "Image extension is now enabled.",
2562 "--extend");
2563 extend = 1;
2565 #endif
2567 #if 0
2568 if (cx_parameter != 0 && !exposure_register) {
2569 implication::changed("Certainty-based rendering requires exposure registration.",
2570 "Exposure registration is now enabled.",
2571 "--exp-register");
2572 d2::align::exp_register();
2573 exposure_register = 1;
2575 #endif
2578 * Set alignment class exclusion region static variables
2581 d2::align::set_exclusion(ex_parameters, ex_count);
2584 * Initialize renderer class statics.
2587 d2::render::render_init(ex_count, ex_parameters, ex_show, extend, scale_factor);
2590 * Set confidence
2593 d2::exposure::set_confidence(cx_parameter);
2596 * Keep transformations for Irani-Peleg, psf-match, and
2597 * VISE
2600 if (ip_iterations > 0 || psf_match || vise_count > 0) {
2601 d2::align::keep();
2605 * Initialize device-specific variables
2608 // int input_file_count = argc - i - 1;
2609 int input_file_count = files.size() - 1;
2611 ale_psf device_response[psf_N] = { NULL, NULL };
2612 d2::exposure **input_exposure = NULL;
2613 ale_pos view_angle = 43.7 * M_PI / 180;
2614 // ale_pos view_angle = 90 * M_PI / 180;
2615 input_exposure = (d2::exposure **)
2616 // malloc((argc - i - 1) * sizeof(d2::exposure *));
2617 malloc(input_file_count * sizeof(d2::exposure *));
2619 if (device != NULL) {
2620 if (!strcmp(device, "xvp610_640x480")) {
2621 device_response[psf_linear] = new xvp610_640x480::lpsf();
2622 device_response[psf_nonlinear] = new xvp610_640x480::nlpsf();
2623 for (int ii = 0; ii < input_file_count; ii++)
2624 input_exposure[ii] = new xvp610_640x480::exposure();
2625 view_angle = xvp610_640x480::view_angle();
2626 } else if (!strcmp(device, "xvp610_320x240")) {
2627 device_response[psf_linear] = new xvp610_320x240::lpsf();
2628 device_response[psf_nonlinear] = new xvp610_320x240::nlpsf();
2629 for (int ii = 0; ii < input_file_count; ii++)
2630 input_exposure[ii] = new xvp610_320x240::exposure();
2631 view_angle = xvp610_320x240::view_angle();
2632 } else if (!strcmp(device, "ov7620")) {
2633 device_response[psf_linear] = new ov7620_raw_linear::lpsf();
2634 device_response[psf_nonlinear] = NULL;
2635 for (int ii = 0; ii < input_file_count; ii++)
2636 input_exposure[ii] = new ov7620_raw_linear::exposure();
2637 d2::image_rw::set_default_bayer(IMAGE_BAYER_BGRG);
2638 } else if (!strcmp(device, "canon_300d")) {
2639 device_response[psf_linear] = new canon_300d_raw_linear::lpsf();
2640 device_response[psf_nonlinear] = NULL;
2641 for (int ii = 0; ii < input_file_count; ii++)
2642 input_exposure[ii] = new canon_300d_raw_linear::exposure();
2643 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2644 } else if (!strcmp(device, "nikon_d50")) {
2645 device_response[psf_linear] = nikon_d50::lpsf();
2646 device_response[psf_nonlinear] = nikon_d50::nlpsf();
2647 for (int ii = 0; ii < input_file_count; ii++)
2648 input_exposure[ii] = new nikon_d50::exposure();
2649 d2::image_rw::set_default_bayer( nikon_d50::bayer() );
2650 } else if (!strcmp(device, "canon_300d+85mm_1.8")) {
2651 device_response[psf_linear] = new canon_300d_raw_linear_85mm_1_8::lpsf();
2652 device_response[psf_nonlinear] = NULL;
2653 for (int ii = 0; ii < input_file_count; ii++)
2654 input_exposure[ii] = new canon_300d_raw_linear_85mm_1_8::exposure();
2655 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2656 view_angle = canon_300d_raw_linear_85mm_1_8::view_angle();
2657 } else if (!strcmp(device, "canon_300d+50mm_1.8")) {
2658 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_8::lpsf();
2659 device_response[psf_nonlinear] = NULL;
2660 for (int ii = 0; ii < input_file_count; ii++)
2661 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_8::exposure();
2662 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2663 view_angle = canon_300d_raw_linear_50mm_1_8::view_angle();
2664 } else if (!strcmp(device, "canon_300d+50mm_1.4")) {
2665 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4::lpsf();
2666 device_response[psf_nonlinear] = NULL;
2667 for (int ii = 0; ii < input_file_count; ii++)
2668 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4::exposure();
2669 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2670 view_angle = canon_300d_raw_linear_50mm_1_4::view_angle();
2671 } else if (!strcmp(device, "canon_300d+50mm_1.4@1.4")) {
2672 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4_1_4::lpsf();
2673 device_response[psf_nonlinear] = NULL;
2674 for (int ii = 0; ii < input_file_count; ii++)
2675 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4_1_4::exposure();
2676 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2677 view_angle = canon_300d_raw_linear_50mm_1_4_1_4::view_angle();
2678 } else {
2679 ui::get()->unknown_device(device);
2681 } else {
2682 for (int ii = 0; ii < input_file_count; ii++)
2683 input_exposure[ii] = new d2::exposure_default();
2687 * User-specified variables.
2690 if (user_view_angle != 0) {
2691 view_angle = user_view_angle;
2694 if (user_bayer != IMAGE_BAYER_DEFAULT) {
2695 d2::image_rw::set_default_bayer(user_bayer);
2699 * PSF-match exposure.
2701 if (psf_match) {
2702 delete input_exposure[input_file_count - 1];
2703 input_exposure[input_file_count - 1] = new d2::exposure_default();
2707 * Initialize output exposure
2710 d2::exposure *output_exposure = new d2::exposure_default();
2711 output_exposure->set_multiplier(exp_mult);
2714 * Configure the response function.
2717 ale_psf response[2] = {NULL, NULL};
2719 for (int n = 0; n < psf_N; n++ ) {
2720 if (psf[n] != NULL) {
2722 response[n] = ale_new_psf(accel::context(), psf[n]);
2725 * TODO: migrate PSF parser to Libale, and remove below code.
2728 response[n] = d2::psf_parse::get((n == psf_linear), psf[n]);
2730 } else if (device_response[n] != NULL) {
2733 * Device-specific response
2736 response[n] = device_response[n];
2738 } else {
2741 * Default point-spread function.
2744 if (n == psf_linear) {
2747 * Default lpsf is a box filter
2748 * of diameter 1.0 (radius
2749 * 0.5).
2752 response[n] = ale_new_psf(accel::context(), "box:1");
2755 * TODO: migrate PSF parser to Libale, and remove below code.
2758 response[n] = new d2::box(0.5);
2760 } else if (n == psf_nonlinear) {
2763 * nlpsf is disabled by default.
2766 response[n] = NULL;
2772 * First file argument. Print general file information as well
2773 * as information specific to this argument. Initialize image
2774 * file handler.
2777 // d2::image_rw::init(argc - i - 1, argv + i, argv[argc - 1], input_exposure, output_exposure);
2778 // ochain_names[0] = argv[argc - 1];
2780 const char **input_files = (const char **) malloc(sizeof(const char *) * input_file_count);
2781 for (int i = 0; i < input_file_count; i++) {
2782 input_files[i] = files[i].first;
2785 d2::image_rw::init(input_file_count, input_files, files[files.size() - 1].first,
2786 input_exposure, output_exposure);
2788 ale_sequence sequence = ale_new_sequence(seq_file, seq_trans, seq_ex, seq_status, (void *) this, cache);
2790 ochain_names[0] = files[files.size() - 1].first;
2793 * Handle control point data for alignment
2795 d2::align::set_cp_count(d3::cpf::count());
2796 for (unsigned int ii = 0; ii < d3::cpf::count(); ii++)
2797 d2::align::set_cp(ii, d3::cpf::get_2d(ii));
2800 * PSF-match bayer patterns.
2803 if (psf_match) {
2804 // d2::image_rw::set_specific_bayer(argc - i - 2, IMAGE_BAYER_NONE);
2805 d2::image_rw::set_specific_bayer(input_file_count - 1, IMAGE_BAYER_NONE);
2809 * Handle alignment weight map, if necessary
2812 if (wm_filename != NULL) {
2813 d2::image *weight_map;
2814 weight_map = d2::image_rw::read_image(wm_filename, new d2::exposure_linear());
2815 weight_map->set_offset(wm_offsety, wm_offsetx);
2816 d2::align::set_weight_map(weight_map);
2820 * Initialize alignment interpolant.
2823 if (strcmp(afilter_type, "internal"))
2824 d2::align::set_interpolant(d2::render_parse::get_SSF(afilter_type));
2827 * Initialize achain and ochain.
2830 achain = d2::render_parse::get(achain_type);
2832 for (int chain = 0; chain < oc_count; chain++)
2833 ochain[chain] = d2::render_parse::get(ochain_types[chain]);
2836 * Use merged renderings as reference images in
2837 * alignment.
2840 d2::align::set_reference(achain);
2843 * Tell the alignment class about the scale factor.
2846 d2::align::set_scale(scale_factor);
2849 * Initialize visp.
2852 d2::vise_core::set_scale(vise_scale_factor);
2854 for (int opt = 0; opt < vise_count; opt++) {
2855 d2::vise_core::add(d2::render_parse::get(visp[opt * 4 + 0]),
2856 visp[opt * 4 + 1],
2857 visp[opt * 4 + 2],
2858 visp[opt * 4 + 3]);
2862 * Initialize non-incremental renderers
2865 #if 0
2866 if (usm_multiplier != 0) {
2869 * Unsharp Mask renderer
2872 ochain[0] = new d2::usm(ochain[0], scale_factor,
2873 usm_multiplier, inc, response[psf_linear],
2874 response[psf_nonlinear], &input_exposure[0]);
2876 #endif
2878 if (ip_iterations != 0) {
2881 * Irani-Peleg renderer
2884 ochain[0] = new d2::ipc( ochain[0], ip_iterations,
2885 inc, response[psf_linear],
2886 response[psf_nonlinear],
2887 (exposure_register == 1), ip_use_median, ipwl);
2891 * Iterate through all files.
2894 ale_sequence_run(sequence, seq_step);
2897 * Output a summary match statistic.
2900 ui::get()->ale_2d_done((double) d2::align::match_summary());
2903 * Special case for point-spread function calibration
2904 * renderer. This renderer does not produce image
2905 * output. It is reserved for use with the
2906 * point-spread function calibration script
2907 * ale-psf-calibrate.
2910 if (psf_match) {
2913 * Point-spread function calibration renderer.
2914 * This renderer does not produce image output.
2915 * It is reserved for use with the point-spread
2916 * function calibration script
2917 * ale-psf-calibrate.
2920 fprintf(stderr, "\nIPC Calibration option enabled.\n\n");
2921 fprintf(stderr, "(This option is designed for use with a calibration script.)\n\n");
2924 * TODO: assign response values appropriately for
2925 * Libale, and remove the below code. This can
2926 * probably be done by passing a response object to
2927 * d2::align in the seq_step loop.
2930 ochain[0] = new d2::psf_calibrate(ochain[0],
2931 1, inc, response[psf_linear],
2932 response[psf_nonlinear],
2933 psf_match_args);
2935 double diff = ale_psf_error(ale_sequence_retain_image(sequence, input_file_count - 1), sequence);
2937 fprintf(stderr, "\n\nPSF Error:: %e\n\n", (double) diff);
2939 exit(0);
2944 * Do any post-processing and output final image
2946 * XXX: note that the Irani-Peleg renderer currently
2947 * returns zero for ochain[0]->sync(), since it writes
2948 * output internally when inc != 0.
2950 * XXX: Leave ochain[0] last, since this may allow disposal of
2951 * rendering structures not required by the Irani-Peleg
2952 * renderer.
2955 for (int opt = 1; opt < oc_count; opt++) {
2956 ale_render_stream_process(ochain[opt], sequence);
2958 if ((sync_updated || !inc) && !psf_match) {
2959 ui::get()->writing_output(opt);
2960 d2::image_rw::write_image(ochain_names[opt], ochain[opt]->get_image());
2964 if (oc_count > 0) {
2965 ale_render_stream_process(ochain[0], sequence);
2967 if ((sync_updated || !inc) && !psf_match) {
2968 ui::get()->writing_output(0);
2969 d2::image_rw::write_image(ochain_names[0], ochain[0]->get_image());
2974 * Perform any 3D tasks
2977 optimizations::begin_3d_work();
2979 if (d3_count > 0) {
2981 ui::get()->d3_start();
2983 d3::align::init_angle(view_angle);
2985 ui::get()->d3_init_view_angle((double) view_angle / M_PI * 180);
2987 d3::align::init_from_d2();
2989 if (d3::cpf::count() > 0) {
2990 ui::get()->d3_control_point_solve();
2991 d3::cpf::solve_3d();
2992 ui::get()->d3_control_point_solve_done();
2995 ui::get()->d3_final_view_angle(d3::align::angle_of(0) / M_PI * 180);
2997 d3::align::write_alignments();
2999 d3::scene::set_filter_type(d3chain_type);
3001 d3::scene::init_from_d2();
3003 ui::get()->d3_subdividing_space();
3004 d3::scene::make_space(d3_depth, d3_output, &d3_depth_pt, &d3_output_pt);
3005 ui::get()->d3_subdividing_space_done();
3007 ui::get()->d3_updating_occupancy();
3008 d3::scene::reduce_cost_to_search_depth(output_exposure, inc);
3009 ui::get()->d3_updating_occupancy_done();
3011 d3::scene::d3px(d3px_count, d3px_parameters);
3012 int view_count = 0;
3013 for (unsigned int i = 0; i < d2::image_rw::count(); i++) {
3014 assert (i < d3_count);
3016 if (d3_depth[i] != NULL) {
3017 ui::get()->d3_writing_output(d3_depth[i]);
3018 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
3019 const d2::image *im = d3::scene::depth(i);
3020 d2::image_rw::write_image(d3_depth[i], im, output_exposure, 1, 1);
3021 delete im;
3022 ui::get()->d3_writing_output_done();
3025 if (d3_output[i] != NULL) {
3026 ui::get()->d3_writing_output(d3_output[i]);
3027 const d2::image *im = d3::scene::view(i);
3028 d2::image_rw::write_image(d3_output[i], im, output_exposure);
3029 delete im;
3030 d3::focus::set_camera(view_count++);
3031 ui::get()->d3_writing_output_done();
3034 for (std::map<const char *, d3::pt>::iterator i = d3_output_pt.begin();
3035 i != d3_output_pt.end(); i++) {
3037 ui::get()->d3_writing_output(i->first);
3038 const d2::image *im = d3::scene::view(i->second);
3039 d2::image_rw::write_image(i->first, im, output_exposure);
3040 delete im;
3041 d3::focus::set_camera(view_count++);
3042 ui::get()->d3_writing_output_done();
3045 for (std::map<const char *, d3::pt>::iterator i = d3_depth_pt.begin();
3046 i != d3_depth_pt.end(); i++) {
3048 ui::get()->d3_writing_output(i->first);
3049 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
3050 const d2::image *im = d3::scene::depth(i->second);
3051 d2::image_rw::write_image(i->first, im, output_exposure, 1, 1);
3052 delete im;
3053 ui::get()->d3_writing_output_done();
3057 for (unsigned int i = d2::image_rw::count(); i < d3_count; i++) {
3058 if (d3_depth[i] != NULL) {
3059 fprintf(stderr, "\n\n*** Frame number for --3dd too high. ***\n\n");
3061 if (d3_output[i] != NULL) {
3062 fprintf(stderr, "\n\n*** Frame number for --3dv too high. ***\n\n");
3068 * Destroy the image file handler
3071 d2::image_rw::destroy();
3074 * Delete the transformation file structures, if any
3075 * exist.
3078 tsave_delete(tsave);
3079 tload_delete(tload);
3082 * We're done.
3085 exit(0);
3089 #endif