Add draft user manual chapter on control points.
[Ale.git] / ui / input.h
blob3b3030f38fa9b97335b216cac7125cc306e84634
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 2 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>
38 * Interface files
41 #include "ui.h"
42 #include "unsupported.h"
43 #include "implication.h"
46 * Configuration
49 #if HAVE_CONFIG_H
50 # include <config.h>
51 #endif
54 * GNU extensions
57 extern "C" {
58 #include "strndup.h"
62 * Types
65 #include "../ale_pos.h"
66 #include "../ale_real.h"
69 * 2D include files
72 #include "../d2.h"
75 * 3D include files
78 #include "../d3.h"
81 * Thread include files
84 #include "../thread.h"
87 * Device configuration files
90 #include "../device/xvp610_320x240.h"
91 #include "../device/xvp610_640x480.h"
92 #include "../device/ov7620_raw_linear.h"
93 #include "../device/canon_300d_raw_linear.h"
94 #include "../device/canon_300d_raw_linear_85mm_1_8.h"
95 #include "../device/canon_300d_raw_linear_50mm_1_8.h"
96 #include "../device/canon_300d_raw_linear_50mm_1_4.h"
97 #include "../device/canon_300d_raw_linear_50mm_1_4_1_4.h"
100 * Help files
103 #include "help.h"
105 class input {
108 * Flag for global options.
111 static int global_options;
114 * Helper functions.
118 * Argument counter.
120 * Counts instances of a given option.
122 static unsigned int arg_count(int argc, const char *argv[], const char *arg) {
123 unsigned int count = 0;
124 for (int i = 0; i < argc; i++) {
125 if (!strcmp(argv[i], arg))
126 count++;
127 else if (!strcmp(argv[i], "--"))
128 return count;
130 return count;
134 * Argument prefix counter.
136 * Counts instances of a given option prefix.
138 static unsigned int arg_prefix_count(int argc, const char *argv[], const char *pfix) {
139 unsigned int count = 0;
140 for (int i = 0; i < argc; i++) {
141 if (!strncmp(argv[i], pfix, strlen(pfix)))
142 count++;
143 else if (!strcmp(argv[i], "--"))
144 return count;
146 return count;
150 * Reallocation function
152 static void *local_realloc(void *ptr, size_t size) {
153 void *new_ptr = realloc(ptr, size);
155 if (new_ptr == NULL)
156 ui::get()->memory_error_location("main()");
158 return new_ptr;
162 * Not enough arguments function.
164 static void not_enough(const char *opt_name) {
165 ui::get()->cli_not_enough(opt_name);
169 * Bad argument function
171 static void bad_arg(const char *opt_name) {
172 ui::get()->cli_bad_arg(opt_name);
176 * String comparison class.
179 class compare_strings {
180 public:
181 int operator()(const char *A, const char *B) const {
182 return strcmp(A, B) < 0;
187 * Environment structures.
189 * XXX: It's arguable that these should be public members of the
190 * 'input' class in order to allow passing environment values to other
191 * classes, but, since we're currently using them only to prepare state
192 * for an internal 'input' function, they can stay private for now. A
193 * more nuanced approach will likely be required later.
196 class environment {
197 static std::stack<environment *> environment_stack;
198 static std::set<environment *> environment_set;
200 std::map<const char *, const char *, compare_strings> environment_map;
203 * Internal set operations do not protect any data.
206 void internal_set(const char *name, const char *value) {
207 environment_map[name] = value;
210 void internal_unset(const char *name) {
211 environment_map.erase(name);
214 const char *internal_convert_pointer(const void *pointer) {
215 int chars = sizeof(void *) * 2 + 3;
216 char *c = (char *) malloc(sizeof(char) * chars);
218 assert(c);
220 if (!c)
221 ui::get()->memory_error_location("environment::set_ptr");
223 int count = snprintf(c, chars, "%p", pointer);
225 assert (count >= 0 && count < chars);
227 return c;
230 void internal_set_ptr(const char *name, const void *pointer) {
231 internal_set(name, internal_convert_pointer(pointer));
235 * Check for restricted names.
238 int name_ok(const char *name) {
239 if (!strcmp(name, "---chain") || !strcmp(name, "---this"))
240 return 0;
242 return 1;
245 void name_check(const char *name) {
246 if (!name_ok(name)) {
247 fprintf(stderr, "Bad set operation.");
248 assert(0);
249 exit(1);
253 public:
256 * Get the environment map.
259 std::map<const char *, const char *, compare_strings> &get_map() {
260 return environment_map;
264 * Public set operations restrict valid names.
267 void set(const char *name, const char *value) {
268 name_check(name);
269 internal_set(name, value);
272 void unset(const char *name) {
273 name_check(name);
274 internal_unset(name);
277 void set_ptr(const char *name, const void *pointer) {
278 name_check(name);
279 internal_set_ptr(name, pointer);
282 const char *get(const char *name) {
283 if (environment_map.count(name) == 0)
284 return NULL;
286 return environment_map[name];
290 * Make an environment substructure. Note that since deep
291 * structures are currently referenced rather than copied when
292 * the stack is pushed, there is no current need for any
293 * chaining mechanism.
295 void make_substructure(const char *name) {
296 environment *s = new environment;
297 set_ptr(name, s);
298 environment_set.insert(s);
301 static int is_env(const char *name) {
302 void *ptr_value;
303 sscanf(name, "%p", &ptr_value);
306 * Check for bad pointers.
309 if (!environment_set.count((environment *) ptr_value)) {
310 return 0;
313 return 1;
316 const char *get_option_name(const char *name) {
317 if (strncmp(name, "0 ", strlen("0 ")))
318 return NULL;
320 name += strlen("0 ");
322 if (!isdigit(name[0]))
323 return NULL;
325 while (isdigit(name[0]))
326 name++;
328 if (!isspace(name[0]))
329 return NULL;
331 while (isspace(name[0]))
332 name++;
334 if (!isalnum(name[0]))
335 return NULL;
337 return name;
340 int is_option(const char *name) {
341 return (get_option_name(name) != NULL);
344 int is_arg(const char *name, unsigned int arg) {
345 assert (is_option(name));
347 int length = strlen(name) + 3 * sizeof(unsigned int);
349 char *desired_string = (char *) malloc(sizeof(char) * length);
351 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
353 int result = environment_map.count(desired_string);
355 free(desired_string);
357 return result > 0;
360 void remove_arg(const char *name, unsigned int arg) {
361 assert (is_option(name));
362 assert (is_arg(name, arg));
364 int length = strlen(name) + 3 * sizeof(unsigned int);
366 char *desired_string = (char *) malloc(sizeof(char) * length);
368 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
370 environment_map.erase(desired_string);
373 const char *get_string_arg(const char *name, unsigned int arg) {
374 assert (is_option(name));
376 int length = strlen(name) + 3 * sizeof(unsigned int);
378 char *desired_string = (char *) malloc(sizeof(char) * length);
380 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
382 const char *result = environment_map[desired_string];
384 assert (result);
386 free(desired_string);
388 return result;
391 long int get_long_arg(const char *name, unsigned int arg) {
392 assert (is_option(name));
394 const char *string = get_string_arg(name, arg);
395 char *endptr;
397 long int result = strtol(string, &endptr, 0);
399 if (endptr[0] != '\0') {
400 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
401 exit(1);
404 return result;
407 int get_int_arg(const char *name, unsigned int arg) {
408 return (int) get_long_arg(name, arg);
411 unsigned int get_unsigned_arg(const char *name, unsigned int arg) {
412 long int result = get_long_arg(name, arg);
414 if (result < 0) {
415 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
416 exit(1);
419 return (unsigned int) result;
422 double get_double_arg(const char *name, unsigned int arg) {
423 assert (is_option(name));
425 const char *string = get_string_arg(name, arg);
426 char *endptr;
428 double result = strtod(string, &endptr);
430 if (endptr[0] != '\0') {
431 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
432 exit(1);
435 return result;
438 static environment *get_env(const char *name) {
440 assert(name);
442 void *ptr_value;
443 sscanf(name, "%p", &ptr_value);
446 * Check for bad pointers.
449 if (!environment_set.count((environment *) ptr_value)) {
450 assert(0);
451 fprintf(stderr, "Bad environment pointer.\n");
452 exit(1);
455 return (environment *) ptr_value;
459 * Prepend to a list.
461 void prepend(const char *list, const char *element) {
462 environment *d = get_env(get(list));
463 make_substructure(list);
464 get_env(get(list))->set("a", element);
465 get_env(get(list))->set_ptr("d", d);
468 void prepend_ptr(const char *list, void *ptr) {
469 prepend(list, internal_convert_pointer(ptr));
473 * Clone the environment.
475 environment *clone() {
476 environment *e = new environment();
478 for (std::map<const char *, const char *, compare_strings>::iterator i = environment_map.begin();
479 i != environment_map.end(); i++) {
481 if (!name_ok(i->first))
482 continue;
484 if (is_env(i->second)) {
485 e->set_ptr(i->first, get_env(i->second)->clone());
486 } else {
487 e->set(i->first, i->second);
491 return e;
494 static environment *top() {
495 if (environment_stack.empty()) {
496 environment_stack.push(new environment);
497 environment_set.insert(environment_stack.top());
499 return environment_stack.top();
502 static void push() {
503 environment *e = new environment;
505 e->environment_map = environment_stack.top()->environment_map;
507 e->internal_set_ptr("---chain", environment_stack.top());
508 e->internal_set_ptr("---this", e);
509 e->make_substructure("---dup");
511 environment_stack.push(e);
512 environment_set.insert(e);
515 static void dup_second() {
516 environment_stack.top()->prepend_ptr("---dup",
517 environment::get_env(environment_stack.top()->get("---chain")));
520 static void push_and_dup_output() {
521 push();
522 dup_second();
525 static void pop() {
526 assert(!environment_stack.empty());
529 * Execution environments should never be referenced by
530 * structures further up the call chain, so they can
531 * safely be deleted. (XXX: In particular, while
532 * lexical scoping may require copying of execution
533 * environments from lower on the call chain, there is
534 * no obvious reason that a reference should be used in
535 * this case; a shallow copy should be used instead.)
538 environment_set.erase(environment_stack.top());
539 delete environment_stack.top();
541 environment_stack.pop();
545 * Set with duplication.
548 void set_with_dup(const char *name, const char *value) {
549 set(name, value);
551 if (!get("---dup"))
552 return;
554 environment *dup_item = get_env(get("---dup"));
556 assert (dup_item);
558 while (dup_item->get("a")) {
559 get_env(dup_item->get("a"))->set_with_dup(name, value);
560 assert(dup_item->get("d"));
561 dup_item = get_env(dup_item->get("d"));
562 assert(dup_item);
568 * Read tokens from a stream.
570 class token_reader {
571 public:
573 * Get the next token
575 virtual const char *get() = 0;
578 * Peek at the next token.
581 virtual const char *peek() = 0;
584 * Divert the stream until the next occurrence of TOKEN.
586 virtual token_reader *divert(const char *open_token, const char *close_token) = 0;
588 virtual int expects_exactly_one_option(void) {
589 return 0;
592 virtual ~token_reader() {
596 class argument_parsing_token_reader : public token_reader {
597 const char *index;
598 const char *separators;
599 public:
600 argument_parsing_token_reader(const char *s) {
601 index = s;
602 separators = "=";
605 int expects_exactly_one_option(void) {
606 return 1;
609 virtual const char *get() {
610 int length = strcspn(index, separators);
612 if (length == 0)
613 return NULL;
615 const char *result = strndup(index, length);
616 index += length;
618 if (strspn(index, separators) >= 1)
619 index++;
621 separators = ",";
623 return result;
626 virtual const char *peek() {
627 int length = strcspn(index, separators);
629 if (length == 0)
630 return NULL;
632 const char *result = strndup(index, length);
634 return result;
637 virtual token_reader *divert(const char *open_token, const char *close_token) {
638 assert(0);
639 return NULL;
643 class cstring_token_reader : public token_reader {
644 const char *separators;
645 const char *string;
646 int ephemeral;
648 cstring_token_reader(const char *s, int ephemeral) {
649 assert(ephemeral == 1);
651 separators = "\n \t";
652 string = s;
653 this->ephemeral = 1;
656 public:
657 cstring_token_reader(const char *s) {
658 separators = "\n \t";
659 string = s;
660 ephemeral = 0;
663 const char *get() {
665 string += strspn(string, separators);
667 size_t length_to_next = strcspn(string, separators);
669 if (length_to_next == 0)
670 return NULL;
672 const char *result = strndup(string, length_to_next);
674 string += length_to_next;
676 return result;
679 const char *peek() {
680 string += strspn(string, separators);
682 size_t length_to_next = strcspn(string, separators);
684 if (length_to_next == 0)
685 return NULL;
687 return strndup(string, length_to_next);
690 cstring_token_reader *divert(const char *open_token, const char *close_token) {
692 * This function might be broken.
695 assert(0);
697 int search = 0;
698 int next = strcspn(string, separators);
699 int depth = 0;
701 while (*(string + search) != '\0' &&
702 (depth || strcmp(close_token, (string + search)))) {
703 if (!strcmp(close_token, (string + search)))
704 depth--;
705 if (!strcmp(open_token, (string + search)))
706 depth++;
707 search = next;
708 next = strcspn((string + next), separators);
711 if (*(string + search) == '\0') {
712 fprintf(stderr, "Parse error: End of scope not found.");
713 exit(1);
716 cstring_token_reader *result = new cstring_token_reader(strndup(string, search), 1);
718 string += search;
721 * Eat the closing token.
724 get();
726 return result;
729 ~cstring_token_reader() {
730 if (ephemeral)
731 free((void *) string);
735 class cli_token_reader : public token_reader {
737 int arg_index;
738 int argc;
739 const char **argv;
741 public:
742 cli_token_reader(int c, const char *v[]) {
743 argc = c;
744 argv = v;
745 arg_index = 0;
748 const char *get() {
750 if (arg_index < argc)
751 return argv[arg_index++];
752 else
753 return NULL;
757 const char *peek() {
759 if (arg_index < argc)
760 return argv[arg_index];
761 else
762 return NULL;
766 cli_token_reader *divert(const char *open_token, const char *close_token) {
767 int search = 0;
768 int depth = 0;
770 while (arg_index + search < argc
771 && (depth || strcmp(argv[arg_index + search], close_token))) {
772 if (!strcmp(close_token, argv[arg_index + search]))
773 depth--;
774 if (!strcmp(open_token, argv[arg_index + search]))
775 depth++;
776 search++;
779 if (arg_index + search == argc) {
780 fprintf(stderr, "Parse error: end of scope not found.\n");
781 exit(1);
784 cli_token_reader *result = new cli_token_reader(search, argv + arg_index);
786 arg_index += search;
789 * Eat the closing token.
792 get();
794 return result;
799 struct simple_option {
800 const char *name;
801 const char *map_name;
802 const char *map_value;
803 int arg_count;
804 int multi;
807 static const char *supported_nonglobal_option_table[];
808 static const char *focus_prefixes[];
809 static simple_option simple_option_table[];
811 static int option_name_match(const char *unadorned, const char *token, int require_ornamentation = 1) {
812 int strip_max = 2;
814 if (!strcmp(unadorned, token) && !require_ornamentation)
815 return 1;
817 while (token[0] == '-' && strip_max) {
818 token++;
819 strip_max--;
820 if (!strcmp(unadorned, token))
821 return 1;
824 return 0;
827 static int is_scope_operator(const char *string) {
828 if (!strcmp("{", string)
829 || !strcmp("}", string)
830 || !strcmp("[", string)
831 || !strcmp("]", string)
832 || !strcmp("<", string)
833 || !strcmp(">", string))
834 return 1;
836 return 0;
839 static const char *option_name_gen(const char *unadorned, const char *map_name, int arg_num, int multi) {
840 static unsigned int multi_counter = 0;
842 if (map_name) {
843 unadorned = map_name;
846 int length = (strlen(unadorned) + sizeof(unsigned int) * 3 + sizeof(int) * 3 + 2) + 1;
848 char *result = (char *) malloc(sizeof(char) * length);
850 assert (result);
852 if (!multi) {
853 snprintf(result, length, "%u 0 %s", arg_num, unadorned);
854 } else {
857 * XXX: This assumes that generating calls for
858 * options other than 0 exist in the same
859 * multiplicity group as the most recently
860 * generated 0-option multiplicity.
863 if (arg_num == 0)
864 multi_counter++;
866 snprintf(result, length, "%u %u %s", arg_num, multi_counter, unadorned);
869 return result;
872 static environment *genv;
874 static const char *get_next(token_reader *tr, const char *option_name) {
875 const char *argument = tr->get();
877 if (argument == NULL) {
878 fprintf(stderr, "\n\nError: not enough arguments for `%s'.\n\n", option_name);
879 exit(1);
882 return argument;
885 static int table_contains(const char **haystack, const char *needle, int prefix_length = 0) {
887 if (needle == NULL)
888 return 0;
890 while (*haystack != NULL) {
891 if (prefix_length == 0 && !strcmp(*haystack, needle))
892 return 1;
893 if (prefix_length > 0 && !strncmp(*haystack, needle, prefix_length))
894 return 1;
895 haystack++;
898 return 0;
901 static int option_is_identical(environment *a, environment *b, const char *option_name) {
902 if (!a->is_option(option_name) || !b->is_option(option_name))
903 return 0;
905 int option_number = 0;
907 while (a->is_arg(option_name, option_number) || b->is_arg(option_name, option_number)) {
908 if (!a->is_arg(option_name, option_number)
909 || !b->is_arg(option_name, option_number))
910 return 0;
912 const char *a_str = a->get_string_arg(option_name, option_number);
913 const char *b_str = b->get_string_arg(option_name, option_number);
915 if (strcmp(a_str, b_str))
916 return 0;
918 option_number++;
921 return 1;
924 static void remove_option(environment *a, const char *option_name) {
925 assert(a->is_option(option_name));
927 int option_number = 0;
929 while (a->is_arg(option_name, option_number)) {
930 a->remove_arg(option_name, option_number);
931 option_number++;
935 static void remove_nonglobals(environment *a) {
936 assert(a);
938 std::stack<const char *> removal_stack;
940 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
941 i != a->get_map().end(); i++) {
943 if (!a->is_option(i->first))
944 continue;
946 if (!table_contains(supported_nonglobal_option_table, a->get_option_name(i->first)))
947 continue;
949 removal_stack.push(i->first);
952 while (!removal_stack.empty()) {
953 remove_option(a, removal_stack.top());
954 removal_stack.pop();
958 static void option_intersect(environment *a, environment *b) {
959 assert(a);
960 assert(b);
962 std::stack<const char *> removal_stack;
964 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
965 i != a->get_map().end(); i++) {
967 if (!a->is_option(i->first))
968 continue;
970 if (option_is_identical(a, b, i->first))
971 continue;
973 removal_stack.push(i->first);
976 while (!removal_stack.empty()) {
977 remove_option(a, removal_stack.top());
978 removal_stack.pop();
982 static void option_difference(environment *a, environment *b) {
983 assert(a);
984 assert(b);
986 std::stack<const char *> removal_stack;
988 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
989 i != a->get_map().end(); i++) {
991 if (!a->is_option(i->first))
992 continue;
994 if (!option_is_identical(a, b, i->first))
995 continue;
997 removal_stack.push(i->first);
1000 while (!removal_stack.empty()) {
1001 remove_option(a, removal_stack.top());
1002 removal_stack.pop();
1006 static void evaluate_stream(token_reader *tr,
1007 std::vector<std::pair<const char *, environment *> > *files) {
1008 const char *token;
1009 int end_of_options = 0;
1011 while ((token = tr->get())) {
1014 * Check for nesting
1017 if (!strcmp(token, "{") && !end_of_options) {
1018 environment::push_and_dup_output();
1019 token_reader *tr_nest = tr->divert("{", "}");
1020 evaluate_stream(tr_nest, files);
1021 delete tr_nest;
1022 environment::pop();
1023 } else if (!strcmp(token, "[") && !end_of_options) {
1024 global_options = 0;
1025 environment::push();
1026 token_reader *tr_nest = tr->divert("[", "]");
1027 evaluate_stream(tr_nest, files);
1028 delete tr_nest;
1029 environment::pop();
1030 } else if (!strcmp(token, "<") && !end_of_options) {
1031 environment *dup_list = environment::get_env(environment::top()->get("---dup"));
1032 assert (dup_list != NULL);
1033 dup_list = dup_list->clone();
1035 environment::dup_second();
1036 token_reader *tr_nest = tr->divert("<", ">");
1037 evaluate_stream(tr_nest, files);
1038 delete tr_nest;
1040 environment::top()->set_ptr("---dup", dup_list);
1044 * Check for non-whitespace argument separators
1047 else if (!end_of_options && token && token[0] == '-' && strchr(token, '=')) {
1048 environment::push_and_dup_output();
1049 token_reader *tr_nest = new argument_parsing_token_reader(token);
1050 evaluate_stream(tr_nest, files);
1051 delete tr_nest;
1052 environment::pop();
1056 * Trap the end-of-option indicator.
1059 else if (!strcmp(token, "--")) {
1060 global_options = 0;
1061 end_of_options = 1;
1065 * Check for options and filenames
1068 else {
1070 * Handle filenames.
1073 if (strncmp("-", token, strlen("-")) || end_of_options) {
1075 assert(files);
1077 global_options = 0;
1078 files->push_back(std::pair<const char *, environment *>(strdup(token),
1079 environment::top()->clone()));
1081 if (tr->expects_exactly_one_option() && tr->get()) {
1082 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1083 exit(1);
1086 continue;
1090 * Handle focus option.
1093 if (option_name_match("focus", token)) {
1095 environment *target;
1096 target = environment::top();
1098 target->set_with_dup(option_name_gen("focus", NULL, 0, 0), "1");
1100 const char *option = get_next(tr, "focus");
1102 target->set_with_dup(option_name_gen("focus", NULL, 1, 0), option);
1104 if (!strcmp(option, "d")) {
1105 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1106 get_next(tr, "focus"));
1107 } else if (!strcmp(option, "p")) {
1108 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1109 get_next(tr, "focus"));
1110 target->set_with_dup(option_name_gen("focus", NULL, 3, 0),
1111 get_next(tr, "focus"));
1112 } else
1113 bad_arg("focus");
1115 int arg = 0;
1117 while (table_contains(focus_prefixes, tr->peek(), 3)) {
1118 target->set_with_dup(option_name_gen("focus", NULL, 4 + arg, 0),
1119 get_next(tr, "focus"));
1120 arg++;
1123 continue;
1127 * Handle simple options.
1130 int found_option = 0;
1131 for (int i = 0; simple_option_table[i].name; i++) {
1132 if (!option_name_match(simple_option_table[i].name, token))
1133 continue;
1136 * Handle the match case.
1139 found_option = 1;
1142 * Determine which environment should be modified
1145 environment *target;
1146 target = environment::top();
1149 * Store information required for
1150 * handling the local case later.
1153 const char *map_value = "1";
1155 if (simple_option_table[i].map_value) {
1156 map_value = simple_option_table[i].map_value;
1157 } else if (simple_option_table[i].map_name) {
1158 map_value = simple_option_table[i].name;
1161 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1162 simple_option_table[i].map_name,
1164 simple_option_table[i].multi),
1165 map_value);
1167 for (int j = 0; j < simple_option_table[i].arg_count; j++) {
1168 const char *option = tr->get();
1170 if (option == NULL) {
1171 fprintf(stderr, "\n\nError: not enough options for `%s'.\n\n", token);
1172 exit(1);
1176 * Reject scope operators as options,
1177 * at least for now.
1180 if (is_scope_operator(option)) {
1181 fprintf(stderr, "\n\nError: illegal argument to `%s'.\n\n", token);
1182 exit(1);
1185 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1186 simple_option_table[i].map_name,
1187 j + 1,
1188 simple_option_table[i].multi),
1189 option);
1194 * Trap illegal options.
1197 if (!found_option)
1198 ui::get()->illegal_option(token);
1201 if (tr->expects_exactly_one_option() && tr->get()) {
1202 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1203 exit(1);
1208 public:
1210 * Input handler.
1212 * Does one of two things:
1214 * (1) Output version information if called with '--version'
1216 * (2) Read options and file arguments, and if the arguments are correct,
1217 * write output. If an error is detected, print the usage statement.
1221 static void handle(int argc, const char *argv[], const char *package, const char *short_version, const char *version) {
1224 * Initialize help object
1227 help hi(package, argv[0], short_version);
1230 * Output version information if --version appears
1231 * on the command line.
1234 if (arg_count(argc, argv, "--version")) {
1236 * Output the version
1239 fprintf(stdout, "%s", version);
1241 return;
1245 * Handle help options
1248 if (arg_prefix_count(argc, argv, "--h"))
1249 for (int i = 1; i < argc; i++) {
1250 int all = !strcmp(argv[i], "--hA");
1251 int is_help_option = !strncmp(argv[i], "--h", strlen("--h"));
1252 int found_help = 0;
1254 if (!strcmp(argv[i], "--hu") || all)
1255 hi.usage(), found_help = 1;
1256 if (!strcmp(argv[i], "--hq") || all)
1257 hi.defaults(), found_help = 1;
1258 if (!strcmp(argv[i], "--hf") || all)
1259 hi.file(), found_help = 1;
1260 if (!strcmp(argv[i], "--he") || all)
1261 hi.exclusion(), found_help = 1;
1262 if (!strcmp(argv[i], "--ha") || all)
1263 hi.alignment(), found_help = 1;
1264 if (!strcmp(argv[i], "--hr") || all)
1265 hi.rendering(), found_help = 1;
1266 if (!strcmp(argv[i], "--hx") || all)
1267 hi.exposure(), found_help = 1;
1268 if (!strcmp(argv[i], "--ht") || all)
1269 hi.tdf(), found_help = 1;
1270 if (!strcmp(argv[i], "--hl") || all)
1271 hi.filtering(), found_help = 1;
1272 if (!strcmp(argv[i], "--hd") || all)
1273 hi.device(), found_help = 1;
1274 if (!strcmp(argv[i], "--hi") || all)
1275 hi.interface(), found_help = 1;
1276 if (!strcmp(argv[i], "--hv") || all)
1277 hi.visp(), found_help = 1;
1278 if (!strcmp(argv[i], "--hc") || all)
1279 hi.cp(), found_help = 1;
1280 if (!strcmp(argv[i], "--h3") || all)
1281 hi.d3(), found_help = 1;
1282 if (!strcmp(argv[i], "--hs") || all)
1283 hi.scope(), found_help = 1;
1284 if (!strcmp(argv[i], "--hp") || all)
1285 hi.process(), found_help = 1;
1286 if (!strcmp(argv[i], "--hz") || all)
1287 hi.undocumented(), found_help = 1;
1289 if (is_help_option && !found_help)
1290 hi.usage();
1293 * Check for the end-of-options marker, a non-option argument,
1294 * or the end of arguments. In all of these cases, we exit.
1297 if (!strcmp(argv[i], "--")
1298 || strncmp(argv[i], "--", strlen("--"))
1299 || i == argc - 1)
1300 return;
1304 * Undocumented projective transformation utility
1307 if (arg_count(argc, argv, "--ptcalc") > 0) {
1308 fprintf(stderr, "\n\n*** Warning: this feature is not documented ***\n\n");
1309 printf("Enter: w h tlx tly blx bly brx bry trx try x y\n\n");
1311 double w, h, tlx, tly, blx, bly, brx, bry, trx, tr_y, x, y;
1313 printf("> ");
1315 if (scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
1316 &w, &h, &tlx, &tly, &blx, &bly, &brx, &bry, &trx, &tr_y, &x, &y) != 12) {
1318 fprintf(stderr, "Error reading input.\n");
1319 exit(1);
1322 d2::image *i = new d2::image_ale_real((int)h, (int)w, 3);
1323 d2::transformation t = d2::transformation::gpt_identity(i, 1);
1324 d2::point q[4] = {
1325 d2::point(tly, tlx),
1326 d2::point(bly, blx),
1327 d2::point(bry, brx),
1328 d2::point(tr_y, trx)
1330 t.gpt_set(q);
1332 d2::point a(y, x), b;
1334 b = t.transform_scaled(a);
1336 printf("TRANSFORM t(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1338 b = t.scaled_inverse_transform(a);
1340 printf("INVERSE t^-1(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1342 exit(0);
1346 * Thread initialization.
1349 thread::init();
1352 * Flags and variables
1355 double scale_factor = 1;
1356 double vise_scale_factor = 1;
1357 #if 0
1358 double usm_multiplier = 0.0;
1359 #endif
1360 int extend = 0;
1361 struct d2::tload_t *tload = NULL;
1362 struct d2::tsave_t *tsave = NULL;
1363 struct d3::tload_t *d3_tload = NULL;
1364 struct d3::tsave_t *d3_tsave = NULL;
1365 int ip_iterations = 0;
1366 int ip_use_median = 0;
1367 enum { psf_linear, psf_nonlinear, psf_N };
1368 const char *psf[psf_N] = {NULL, NULL};
1369 const char *device = NULL;
1370 int psf_match = 0;
1371 double psf_match_args[6];
1372 int inc = 1;
1373 int exposure_register = 1;
1374 const char *wm_filename = NULL;
1375 int wm_offsetx = 0, wm_offsety = 0;
1376 double cx_parameter = 0;
1377 double *d3px_parameters = NULL;
1378 int d3px_count = 0;
1379 d2::exclusion *ex_parameters = NULL;
1380 int ex_count = 0;
1381 int ex_show = 0;
1382 d2::render *achain;
1383 const char *achain_type = "triangle:2";
1384 const char *afilter_type = "internal";
1385 d2::render **ochain = NULL;
1386 const char **ochain_names = NULL;
1387 const char **ochain_types = NULL;
1388 const char *d3chain_type = NULL;
1389 int oc_count = 0;
1390 const char **visp = NULL;
1391 int vise_count = 0;
1392 const char **d3_output = NULL;
1393 const char **d3_depth = NULL;
1394 unsigned int d3_count = 0;
1395 double user_view_angle = 0;
1396 int user_bayer = IMAGE_BAYER_DEFAULT;
1397 d2::pixel exp_mult = d2::pixel(1, 1, 1);
1398 std::map<const char *, d3::pt> d3_output_pt;
1399 std::map<const char *, d3::pt> d3_depth_pt;
1402 * dchain is ochain[0].
1405 ochain = (d2::render **) local_realloc(ochain,
1406 (oc_count + 1) * sizeof(d2::render *));
1407 ochain_names = (const char **) local_realloc((void *)ochain_names,
1408 (oc_count + 1) * sizeof(const char *));
1409 ochain_types = (const char **) local_realloc((void *)ochain_types,
1410 (oc_count + 1) * sizeof(const char *));
1412 ochain_types[0] = "sinc*lanc:8";
1414 oc_count = 1;
1417 * Handle default settings
1420 if (arg_prefix_count(argc, argv, "--q") > 1)
1421 ui::get()->error("more than one default setting option --q* was specified");
1423 const char *defaults[] = {
1424 "--dchain fine:box:1,triangle:2 "
1425 "--achain triangle:2 "
1426 "--ips 0 "
1427 "--exp-noextend "
1428 "--no-cx "
1429 "--3d-chain fine:box:1,triangle:2",
1431 "--dchain sinc*lanc:6 "
1432 "--achain sinc*lanc:6 "
1433 "--ips 0 "
1434 "--exp-noextend "
1435 "--no-cx "
1436 "--3d-chain sinc*lanc:6 ",
1438 "--dchain median:fine:sinc*lanc:8,triangle:2 "
1439 "--achain triangle:2 "
1440 "--ips 0 "
1441 "--exp-noextend "
1442 "--no-cx "
1443 "--3d-chain median:fine:sinc*lanc:8,triangle:2 ",
1445 "--dchain triangle:2 "
1446 "--achain triangle:2 "
1447 "--ips 4 "
1448 "--exp-noextend "
1449 "--no-cx "
1450 "--3d-chain median:fine:sinc*lanc:8,triangle:2 ",
1452 "--dchain triangle:2 "
1453 "--achain triangle:2 "
1454 "--ips 6 "
1455 "--exp-extend "
1456 "--cx 0.7 "
1457 "--3d-chain median:fine:sinc*lanc:8,triangle:2 "
1460 int default_index;
1461 if (arg_count(argc, argv, "--q0")) {
1462 default_index = 0;
1463 } else if (arg_count(argc, argv, "--qn")) {
1464 default_index = 1;
1465 } else if (arg_count(argc, argv, "--q1")) {
1466 default_index = 2;
1467 } else if (arg_count(argc, argv, "--q2")) {
1468 default_index = 3;
1469 } else if (arg_count(argc, argv, "--qr")) {
1470 default_index = 4;
1471 } else {
1473 * Same as --q0
1475 default_index = 0;
1478 token_reader *default_reader = new cstring_token_reader(defaults[default_index]);
1480 evaluate_stream(default_reader, NULL);
1483 * Set basic program information in the environment.
1486 environment::top()->set_with_dup("---package", package);
1487 environment::top()->set_with_dup("---short-version", short_version);
1488 environment::top()->set_with_dup("---version", version);
1489 environment::top()->set_with_dup("---invocation", argv[0]);
1492 * Initialize the top-level token-reader and generate
1493 * an environment variable for it.
1496 token_reader *tr = new cli_token_reader(argc - 1, argv + 1);
1497 environment::top()->set_ptr("---token-reader", tr);
1500 * Evaluate the command-line arguments to generate environment
1501 * structures.
1504 std::vector<std::pair<const char *, environment *> > files;
1506 evaluate_stream(tr, &files);
1509 * If there are fewer than two files, then output usage information.
1512 if (files.size() < 2) {
1513 hi.usage();
1514 exit(1);
1518 * Extract the global environment and check non-globals
1519 * against a list of supported non-global options.
1522 genv = files[0].second->clone();
1524 remove_nonglobals(genv);
1526 for (unsigned int i = 0; i < files.size(); i++) {
1527 option_intersect(genv, files[i].second);
1530 for (unsigned int i = 0; i < files.size(); i++) {
1531 option_difference(files[i].second, genv);
1533 for (std::map<const char *, const char *>::iterator j = files[i].second->get_map().begin();
1534 j != files[i].second->get_map().end(); j++) {
1536 environment *env = files[i].second;
1538 if (!env->is_option(j->first))
1539 continue;
1541 const char *option_name = env->get_option_name(j->first);
1543 if (!table_contains(supported_nonglobal_option_table, option_name)) {
1544 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
1545 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
1546 option_name);
1547 exit(1);
1553 * Iterate through the global environment,
1554 * looking for options.
1557 for (std::map<const char *, const char *>::iterator i = genv->get_map().begin();
1558 i != genv->get_map().end(); i++) {
1560 environment *env = genv;
1562 if (!env->is_option(i->first))
1563 continue;
1565 const char *option_name = env->get_option_name(i->first);
1567 if (!strcmp(option_name, "default")) {
1569 * Do nothing. Defaults have already been set.
1571 } else if (!strcmp(option_name, "bpc")) {
1572 if (!strcmp(env->get_string_arg(i->first, 0), "8bpc"))
1573 d2::image_rw::depth8();
1574 else if (!strcmp(env->get_string_arg(i->first, 0), "16bpc"))
1575 d2::image_rw::depth16();
1576 else
1577 assert(0);
1578 } else if (!strcmp(option_name, "format")) {
1579 if (!strcmp(env->get_string_arg(i->first, 0), "plain"))
1580 d2::image_rw::ppm_plain();
1581 else if (!strcmp(env->get_string_arg(i->first, 0), "raw"))
1582 d2::image_rw::ppm_raw();
1583 else if (!strcmp(env->get_string_arg(i->first, 0), "auto"))
1584 d2::image_rw::ppm_auto();
1585 else
1586 assert(0);
1587 } else if (!strcmp(option_name, "align")) {
1588 if (!strcmp(env->get_string_arg(i->first, 0), "align-all"))
1589 d2::align::all();
1590 else if (!strcmp(env->get_string_arg(i->first, 0), "align-green"))
1591 d2::align::green();
1592 else if (!strcmp(env->get_string_arg(i->first, 0), "align-sum"))
1593 d2::align::sum();
1594 else
1595 assert(0);
1596 } else if (!strcmp(option_name, "transformation")) {
1597 if (!strcmp(env->get_string_arg(i->first, 0), "translation"))
1598 d2::align::class_translation();
1599 else if (!strcmp(env->get_string_arg(i->first, 0), "euclidean"))
1600 d2::align::class_euclidean();
1601 else if (!strcmp(env->get_string_arg(i->first, 0), "projective"))
1602 d2::align::class_projective();
1603 else
1604 assert(0);
1605 } else if (!strcmp(option_name, "transformation-default")) {
1606 if (!strcmp(env->get_string_arg(i->first, 0), "identity"))
1607 d2::align::initial_default_identity();
1608 else if (!strcmp(env->get_string_arg(i->first, 0), "follow"))
1609 d2::align::initial_default_follow();
1610 else
1611 assert(0);
1612 } else if (!strcmp(option_name, "perturb")) {
1613 if (!strcmp(env->get_string_arg(i->first, 0), "perturb-output"))
1614 d2::align::perturb_output();
1615 else if (!strcmp(env->get_string_arg(i->first, 0), "perturb-source"))
1616 d2::align::perturb_source();
1617 else
1618 assert(0);
1619 } else if (!strcmp(option_name, "fail")) {
1620 if (!strcmp(env->get_string_arg(i->first, 0), "fail-optimal"))
1621 d2::align::fail_optimal();
1622 else if (!strcmp(env->get_string_arg(i->first, 0), "fail-default"))
1623 d2::align::fail_default();
1624 else
1625 assert(0);
1626 } else if (!strcmp(option_name, "profile")) {
1627 ui::set_profile();
1628 } else if (!strcmp(option_name, "extend")) {
1629 if (env->get_int_arg(i->first, 0))
1630 extend = 1;
1631 else
1632 extend = 0;
1633 } else if (!strcmp(option_name, "oc")) {
1634 if (env->get_int_arg(i->first, 0))
1635 d3::scene::oc();
1636 else
1637 d3::scene::no_oc();
1638 } else if (!strcmp(option_name, "gs")) {
1639 d2::align::gs(env->get_string_arg(i->first, 1));
1640 } else if (!strcmp(option_name, "gs-mo")) {
1641 d2::align::gs_mo(env->get_unsigned_arg(i->first, 1));
1642 } else if (!strcmp(option_name, "focus")) {
1644 double one = +1;
1645 double zero = +0;
1646 double inf = one / zero;
1648 assert (isinf(inf) == +1);
1651 * Focus type
1654 unsigned int type = 0;
1655 double distance = 0;
1656 double px = 0, py = 0;
1658 if (!strcmp(env->get_string_arg(i->first, 1), "d")) {
1660 type = 0;
1662 distance = env->get_double_arg(i->first, 2);
1664 } else if (!strcmp(env->get_string_arg(i->first, 1), "p")) {
1666 type = 1;
1668 px = env->get_double_arg(i->first, 2);
1669 py = env->get_double_arg(i->first, 3);
1671 } else {
1672 bad_arg(option_name);
1676 * Options
1679 unsigned int ci = 0;
1680 double fr = 0;
1681 double ht = 0;
1682 double vt = 0;
1683 double sd = 0;
1684 double ed = inf;
1685 double sx = -inf;
1686 double ex = inf;
1687 double sy = -inf;
1688 double ey = inf;
1689 double ap = 3;
1690 unsigned int sc = 3;
1691 unsigned int fs = 0;
1692 unsigned int sr = 0;
1694 for (int arg_num = 4; env->is_arg(i->first, arg_num); arg_num++) {
1695 const char *option = env->get_string_arg(i->first, arg_num);
1696 if (!strncmp(option, "ci=", 3)) {
1697 if(sscanf(option + 3, "%u", &ci) != 1)
1698 bad_arg("--focus");
1699 } else if (!strncmp(option, "fr=", 3)) {
1700 if(sscanf(option + 3, "%lf", &fr) != 1)
1701 bad_arg("--focus");
1702 } else if (!strncmp(option, "ht=", 3)) {
1703 if(sscanf(option + 3, "%lf", &ht) != 1)
1704 bad_arg("--focus");
1705 } else if (!strncmp(option, "vt=", 3)) {
1706 if(sscanf(option + 3, "%lf", &vt) != 1)
1707 bad_arg("--focus");
1708 } else if (!strncmp(option, "sy=", 3)) {
1709 if(sscanf(option + 3, "%lf", &sy) != 1)
1710 bad_arg("--focus");
1711 } else if (!strncmp(option, "ey=", 3)) {
1712 if(sscanf(option + 3, "%lf", &ey) != 1)
1713 bad_arg("--focus");
1714 } else if (!strncmp(option, "sx=", 3)) {
1715 if(sscanf(option + 3, "%lf", &sx) != 1)
1716 bad_arg("--focus");
1717 } else if (!strncmp(option, "ex=", 3)) {
1718 if(sscanf(option + 3, "%lf", &ex) != 1)
1719 bad_arg("--focus");
1720 } else if (!strncmp(option, "sd=", 3)) {
1721 if(sscanf(option + 3, "%lf", &sd) != 1)
1722 bad_arg("--focus");
1723 } else if (!strncmp(option, "ed=", 3)) {
1724 if(sscanf(option + 3, "%lf", &ed) != 1)
1725 bad_arg("--focus");
1726 } else if (!strncmp(option, "ap=", 3)) {
1727 if(sscanf(option + 3, "%lf", &ap) != 1)
1728 bad_arg("--focus");
1729 } else if (!strncmp(option, "sc=", 3)) {
1730 if(sscanf(option + 3, "%u", &sc) != 1)
1731 bad_arg("--focus");
1732 } else if (!strncmp(option, "sr=", 3)) {
1733 if (!strcmp(option, "sr=aperture")) {
1734 sr = 0;
1735 } else if (!strcmp(option, "sr=pixel")) {
1736 sr = 1;
1737 } else
1738 bad_arg("--focus");
1740 } else if (!strncmp(option, "fs=", 3)) {
1741 if (!strcmp(option, "fs=mean")) {
1742 fs = 0;
1743 } else if (!strcmp(option, "fs=median")) {
1744 fs = 1;
1745 } else
1746 bad_arg("--focus");
1747 } else
1748 bad_arg("--focus");
1751 d3::focus::add_region(type, distance, px, py, ci, fr, ht, vt, sd, ed, sx, ex, sy, ey, ap, sc, fs, sr);
1753 } else if (!strcmp(option_name, "3ddp") || !strcmp(option_name, "3dvp")) {
1754 d2::align::keep();
1757 * Unsupported configurations
1760 if (ip_iterations)
1761 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1763 #if 0
1764 if (usm_multiplier)
1765 unsupported::fornow("3D modeling with unsharp mask");
1766 #endif
1769 * Initialize if necessary
1771 * Note: because their existence is checked as an
1772 * indicator of the presence of 3D arguments, we
1773 * initialize these structures here.
1776 if (d3_output == NULL) {
1777 d3_count = argc;
1778 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1779 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1782 unsigned int width, height;
1783 double view_angle;
1784 double x, y, z;
1785 double P, Y, R;
1787 width = env->get_unsigned_arg(i->first, 1);
1788 height = env->get_unsigned_arg(i->first, 2);
1789 view_angle = env->get_double_arg(i->first, 3);
1790 x = env->get_double_arg(i->first, 4);
1791 y = env->get_double_arg(i->first, 5);
1792 z = env->get_double_arg(i->first, 6);
1793 P = env->get_double_arg(i->first, 7);
1794 Y = env->get_double_arg(i->first, 8);
1795 R = env->get_double_arg(i->first, 9);
1797 view_angle *= M_PI / 180;
1798 P *= M_PI / 180;
1799 Y *= M_PI / 180;
1800 R *= M_PI / 180;
1802 d2::transformation t =
1803 d2::transformation::eu_identity();
1804 t.set_domain(height, width);
1805 d3::pt _pt(t, d3::et(y, x, z, Y, P, R), view_angle);
1807 if (!strcmp(option_name, "3dvp")) {
1808 d3_output_pt[env->get_string_arg(i->first, 10)] = _pt;
1809 } else if (!strcmp(option_name, "3ddp")) {
1810 d3_depth_pt[env->get_string_arg(i->first, 10)] = _pt;
1811 } else {
1812 assert(0);
1814 } else if (!strcmp(option_name, "3dv")) {
1815 d2::align::keep();
1817 unsigned int frame_no;
1820 * Unsupported configurations
1823 if (ip_iterations)
1824 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1826 #if 0
1827 if (usm_multiplier)
1828 unsupported::fornow("3D modeling with unsharp mask");
1829 #endif
1832 * Initialize if necessary
1835 if (d3_output == NULL) {
1836 d3_count = argc;
1837 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1838 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1841 frame_no = env->get_int_arg(i->first, 1);
1843 if (frame_no >= d3_count)
1844 ui::get()->error("--3dv argument 0 is too large");
1846 if (d3_output[frame_no] != NULL) {
1847 unsupported::fornow ("Writing a single 3D view to more than one output file");
1850 d3_output[frame_no] = env->get_string_arg(i->first, 2);
1852 } else if (!strcmp(option_name, "3dd")) {
1853 d2::align::keep();
1855 unsigned int frame_no;
1858 * Unsupported configurations
1861 if (ip_iterations)
1862 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1864 #if 0
1865 if (usm_multiplier)
1866 unsupported::fornow("3D modeling with unsharp mask");
1867 #endif
1870 * Initialize if necessary
1873 if (d3_output == NULL) {
1874 d3_count = argc;
1875 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1876 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1879 frame_no = env->get_int_arg(i->first, 1);
1881 if (frame_no >= d3_count)
1882 ui::get()->error("--3dd argument 0 is too large");
1884 if (d3_depth[frame_no] != NULL) {
1885 unsupported::fornow ("Writing a single frame's depth info to more than one output file");
1888 d3_depth[frame_no] = env->get_string_arg(i->first, 2);
1890 } else if (!strcmp(option_name, "view-angle")) {
1891 user_view_angle = env->get_double_arg(i->first, 1) * M_PI / 180;
1892 } else if (!strcmp(option_name, "cpf-load")) {
1893 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
1894 } else if (!strcmp(option_name, "ui")) {
1895 if (!strcmp(env->get_string_arg(i->first, 1), "stream"))
1896 ui::set_stream();
1897 else if (!strcmp(env->get_string_arg(i->first, 1), "tty"))
1898 ui::set_tty();
1899 else
1900 assert(0);
1901 } else if (!strcmp(option_name, "3d-fmr")) {
1902 d3::scene::fmr(env->get_double_arg(i->first, 1));
1903 } else if (!strcmp(option_name, "3d-dmr")) {
1904 d3::scene::dmr(env->get_double_arg(i->first, 1));
1905 } else if (!strcmp(option_name, "et")) {
1906 d3::scene::et(env->get_double_arg(i->first, 1));
1907 } else if (!strcmp(option_name, "st")) {
1908 d3::cpf::st(env->get_double_arg(i->first, 1));
1909 } else if (!strcmp(option_name, "di-lower")) {
1910 d3::scene::di_lower(env->get_double_arg(i->first, 1));
1911 } else if (!strcmp(option_name, "rc")) {
1912 d3::scene::rc(env->get_double_arg(i->first, 1));
1913 } else if (!strcmp(option_name, "do-try")) {
1914 d3::scene::do_try(env->get_double_arg(i->first, 1));
1915 } else if (!strcmp(option_name, "di-upper")) {
1916 d3::scene::di_upper(env->get_double_arg(i->first, 1));
1917 } else if (!strcmp(option_name, "fc")) {
1918 d3::scene::fc(env->get_double_arg(i->first, 1));
1919 } else if (!strcmp(option_name, "ecm")) {
1920 unsupported::discontinued("--ecm <x>");
1921 } else if (!strcmp(option_name, "acm")) {
1922 unsupported::discontinued("--acm <x>");
1923 } else if (!strcmp(option_name, "def-nn")) {
1924 d2::image_rw::def_nn(env->get_double_arg(i->first, 1));
1926 if (env->get_double_arg(i->first, 1) > 2) {
1927 fprintf(stderr, "\n\n*** Warning: --def-nn implementation is currently "
1928 "inefficient for large radii. ***\n\n");
1931 } else if (!strcmp(option_name, "fx")) {
1932 d3::scene::fx(env->get_double_arg(i->first, 1));
1933 } else if (!strcmp(option_name, "tcem")) {
1934 d3::scene::tcem(env->get_double_arg(i->first, 1));
1935 } else if (!strcmp(option_name, "oui")) {
1936 d3::scene::oui(env->get_unsigned_arg(i->first, 1));
1937 } else if (!strcmp(option_name, "pa")) {
1938 d3::scene::pa(env->get_unsigned_arg(i->first, 1));
1939 } else if (!strcmp(option_name, "pc")) {
1940 d3::scene::pc(env->get_string_arg(i->first, 1));
1941 } else if (!strcmp(option_name, "cw")) {
1942 d2::align::certainty_weighted(env->get_unsigned_arg(i->first, 0));
1943 } else if (!strcmp(option_name, "wm")) {
1944 if (wm_filename != NULL)
1945 ui::get()->error("only one weight map can be specified");
1947 wm_filename = env->get_string_arg(i->first, 1);
1948 wm_offsetx = env->get_int_arg(i->first, 2);
1949 wm_offsety = env->get_int_arg(i->first, 3);
1951 } else if (!strcmp(option_name, "fl")) {
1952 #ifdef USE_FFTW
1953 d2::align::set_frequency_cut(env->get_double_arg(i->first, 1),
1954 env->get_double_arg(i->first, 2),
1955 env->get_double_arg(i->first, 3));
1957 #else
1958 ui::get()->error_hint("--fl is not supported", "rebuild ALE with FFTW support");
1959 #endif
1960 } else if (!strcmp(option_name, "wmx")) {
1961 #ifdef USE_UNIX
1962 d2::align::set_wmx(env->get_string_arg(i->first, 1),
1963 env->get_string_arg(i->first, 2),
1964 env->get_string_arg(i->first, 3));
1965 #else
1966 ui::get()->error_hint("--wmx is not supported", "rebuild ALE with support for --wmx");
1967 #endif
1968 } else if (!strcmp(option_name, "flshow")) {
1969 d2::align::set_fl_show(env->get_string_arg(i->first, 1));
1970 } else if (!strcmp(option_name, "3dpx")) {
1972 d3px_parameters = (double *) local_realloc(d3px_parameters, (d3px_count + 1) * 6 * sizeof(double));
1974 for (int param = 0; param < 6; param++)
1975 d3px_parameters[6 * d3px_count + param] = env->get_double_arg(i->first, param + 1);
1978 * Swap x and y, since their internal meanings differ from their external meanings.
1981 for (int param = 0; param < 2; param++) {
1982 double temp = d3px_parameters[6 * d3px_count + 2 + param];
1983 d3px_parameters[6 * d3px_count + 2 + param] = d3px_parameters[6 * d3px_count + 0 + param];
1984 d3px_parameters[6 * d3px_count + 0 + param] = temp;
1989 * Increment counters
1992 d3px_count++;
1994 } else if (!strcmp(option_name, "ex") || !strcmp(option_name, "fex")) {
1996 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
1997 (ex_count + 1) * sizeof(d2::exclusion));
1999 ex_parameters[ex_count].type = (!strcmp(option_name, "ex"))
2000 ? d2::exclusion::RENDER
2001 : d2::exclusion::FRAME;
2004 * Get parameters, swapping x and y coordinates
2007 ex_parameters[ex_count].x[0] = env->get_int_arg(i->first, 1 + 2);
2008 ex_parameters[ex_count].x[1] = env->get_int_arg(i->first, 1 + 3);
2009 ex_parameters[ex_count].x[2] = env->get_int_arg(i->first, 1 + 0);
2010 ex_parameters[ex_count].x[3] = env->get_int_arg(i->first, 1 + 1);
2011 ex_parameters[ex_count].x[4] = env->get_int_arg(i->first, 1 + 4);
2012 ex_parameters[ex_count].x[5] = env->get_int_arg(i->first, 1 + 5);
2015 * Increment counters
2018 ex_count++;
2020 } else if (!strcmp(option_name, "crop") || !strcmp(option_name, "fcrop")) {
2022 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
2023 (ex_count + 4) * sizeof(d2::exclusion));
2025 for (int r = 0; r < 4; r++)
2026 ex_parameters[ex_count + r].type = (!strcmp(option_name, "crop"))
2027 ? d2::exclusion::RENDER
2028 : d2::exclusion::FRAME;
2031 int crop_args[6];
2033 for (int param = 0; param < 6; param++)
2034 crop_args[param] = env->get_int_arg(i->first, param + 1);
2037 * Construct exclusion regions from the crop area,
2038 * swapping x and y, since their internal meanings
2039 * differ from their external meanings.
2043 * Exclusion region 1: low x
2046 ex_parameters[ex_count + 0].x[0] = INT_MIN;
2047 ex_parameters[ex_count + 0].x[1] = crop_args[2] - 1;
2048 ex_parameters[ex_count + 0].x[2] = INT_MIN;
2049 ex_parameters[ex_count + 0].x[3] = INT_MAX;
2050 ex_parameters[ex_count + 0].x[4] = crop_args[4];
2051 ex_parameters[ex_count + 0].x[5] = crop_args[5];
2054 * Exclusion region 2: low y
2057 ex_parameters[ex_count + 1].x[0] = INT_MIN;
2058 ex_parameters[ex_count + 1].x[1] = INT_MAX;
2059 ex_parameters[ex_count + 1].x[2] = INT_MIN;
2060 ex_parameters[ex_count + 1].x[3] = crop_args[0] - 1;
2061 ex_parameters[ex_count + 1].x[4] = crop_args[4];
2062 ex_parameters[ex_count + 1].x[5] = crop_args[5];
2065 * Exclusion region 3: high y
2068 ex_parameters[ex_count + 2].x[0] = INT_MIN;
2069 ex_parameters[ex_count + 2].x[1] = INT_MAX;
2070 ex_parameters[ex_count + 2].x[2] = crop_args[1] + 1;
2071 ex_parameters[ex_count + 2].x[3] = INT_MAX;
2072 ex_parameters[ex_count + 2].x[4] = crop_args[4];
2073 ex_parameters[ex_count + 2].x[5] = crop_args[5];
2076 * Exclusion region 4: high x
2079 ex_parameters[ex_count + 3].x[0] = crop_args[3] + 1;
2080 ex_parameters[ex_count + 3].x[1] = INT_MAX;
2081 ex_parameters[ex_count + 3].x[2] = INT_MIN;
2082 ex_parameters[ex_count + 3].x[3] = INT_MAX;
2083 ex_parameters[ex_count + 3].x[4] = crop_args[4];
2084 ex_parameters[ex_count + 3].x[5] = crop_args[5];
2087 * Increment counters
2090 ex_count += 4;
2092 } else if (!strcmp(option_name, "exshow")) {
2093 ex_show = 1;
2094 } else if (!strcmp(option_name, "wt")) {
2095 d2::render::set_wt(env->get_double_arg(i->first, 1));
2096 } else if (!strcmp(option_name, "3d-chain")) {
2097 d3chain_type = env->get_string_arg(i->first, 1);
2098 } else if (!strcmp(option_name, "dchain")) {
2099 ochain_types[0] = env->get_string_arg(i->first, 1);
2100 } else if (!strcmp(option_name, "achain")) {
2101 achain_type = env->get_string_arg(i->first, 1);
2102 } else if (!strcmp(option_name, "afilter")) {
2103 afilter_type = env->get_string_arg(i->first, 1);
2104 } else if (!strcmp(option_name, "ochain")) {
2106 ochain = (d2::render **) local_realloc(ochain,
2107 (oc_count + 1) * sizeof(d2::render *));
2108 ochain_names = (const char **) local_realloc((void *)ochain_names,
2109 (oc_count + 1) * sizeof(const char *));
2110 ochain_types = (const char **) local_realloc((void *)ochain_types,
2111 (oc_count + 1) * sizeof(const char *));
2113 ochain_types[oc_count] = env->get_string_arg(i->first, 1);
2114 ochain_names[oc_count] = env->get_string_arg(i->first, 2);
2116 oc_count++;
2118 } else if (!strcmp(option_name, "visp")) {
2120 visp = (const char **) local_realloc((void *)visp, 4 *
2121 (vise_count + 1) * sizeof(const char *));
2123 for (int param = 0; param < 4; param++)
2124 visp[vise_count * 4 + param] = env->get_string_arg(i->first, param + 1);
2126 vise_count++;
2128 } else if (!strcmp(option_name, "cx")) {
2129 cx_parameter = env->get_int_arg(i->first, 0) ? env->get_double_arg(i->first, 1) : 0;
2130 } else if (!strcmp(option_name, "ip")) {
2131 unsupported::discontinued("--ip <r> <i>", "--lpsf box=<r> --ips <i>");
2132 } else if (!strcmp(option_name, "bayer")) {
2135 * External order is clockwise from top-left. Internal
2136 * order is counter-clockwise from top-left.
2139 const char *option = env->get_string_arg(i->first, 1);
2141 if (!strcmp(option, "rgbg")) {
2142 user_bayer = IMAGE_BAYER_RGBG;
2143 } else if (!strcmp(option, "bgrg")) {
2144 user_bayer = IMAGE_BAYER_BGRG;
2145 } else if (!strcmp(option, "gbgr")) {
2146 user_bayer = IMAGE_BAYER_GRGB;
2147 } else if (!strcmp(option, "grgb")) {
2148 user_bayer = IMAGE_BAYER_GBGR;
2149 } else if (!strcmp(option, "none")) {
2150 user_bayer = IMAGE_BAYER_NONE;
2151 } else {
2152 bad_arg("--bayer");
2155 } else if (!strcmp(option_name, "lpsf")) {
2156 psf[psf_linear] = env->get_string_arg(i->first, 1);
2157 } else if (!strcmp(option_name, "nlpsf")) {
2158 psf[psf_nonlinear] = env->get_string_arg(i->first, 1);
2159 } else if (!strcmp(option_name, "psf-match")) {
2161 psf_match = 1;
2163 for (int index = 0; index < 6; index++) {
2164 psf_match_args[index] = env->get_double_arg(i->first, index + 1);
2167 } else if (!strcmp(option_name, "device")) {
2168 device = env->get_string_arg(i->first, 1);
2169 #if 0
2170 } else if (!strcmp(option_name, "usm")) {
2172 if (d3_output != NULL)
2173 unsupported::fornow("3D modeling with unsharp mask");
2175 usm_multiplier = env->get_double_arg(i->first, 1);
2176 #endif
2178 } else if (!strcmp(option_name, "ipr")) {
2180 ip_iterations = env->get_int_arg(i->first, 1);
2182 ui::get()->warn("--ipr is deprecated. Use --ips instead");
2184 } else if (!strcmp(option_name, "cpp-err")) {
2185 if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2186 d3::cpf::err_median();
2187 else if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2188 d3::cpf::err_mean();
2189 } else if (!strcmp(option_name, "vp-adjust")) {
2190 if (env->get_int_arg(i->first, 0))
2191 d3::align::vp_adjust();
2192 else
2193 d3::align::vp_noadjust();
2194 } else if (!strcmp(option_name, "vo-adjust")) {
2195 if (env->get_int_arg(i->first, 0))
2196 d3::align::vo_adjust();
2197 else
2198 d3::align::vo_noadjust();
2199 } else if (!strcmp(option_name, "ip-statistic")) {
2200 if (!strcmp(env->get_string_arg(i->first, 1), "mean"))
2201 ip_use_median = 0;
2202 else if (!strcmp(env->get_string_arg(i->first, 1), "median"))
2203 ip_use_median = 1;
2204 } else if (!strcmp(option_name, "ips")) {
2205 ip_iterations = env->get_int_arg(i->first, 1);
2206 } else if (!strcmp(option_name, "ipc")) {
2207 unsupported::discontinued("--ipc <c> <i>", "--ips <i> --lpsf <c>", "--ips <i> --device <c>");
2208 } else if (!strcmp(option_name, "exp-extend")) {
2209 if (env->get_int_arg(i->first, 0))
2210 d2::image_rw::exp_scale();
2211 else
2212 d2::image_rw::exp_noscale();
2213 } else if (!strcmp(option_name, "exp-register")) {
2214 if (env->get_int_arg(i->first, 0) == 1) {
2215 exposure_register = 1;
2216 d2::align::exp_register();
2217 } else if (env->get_int_arg(i->first, 0) == 0) {
2218 exposure_register = 0;
2219 d2::align::exp_noregister();
2220 } else if (env->get_int_arg(i->first, 0) == 2) {
2221 exposure_register = 2;
2222 d2::align::exp_meta_only();
2224 } else if (!strcmp(option_name, "drizzle-only")) {
2225 unsupported::discontinued("--drizzle-only", "--dchain box:1");
2226 } else if (!strcmp(option_name, "subspace-traverse")) {
2227 unsupported::undocumented("--subspace-traverse");
2228 d3::scene::set_subspace_traverse();
2229 } else if (!strcmp(option_name, "3d-filter")) {
2230 if (env->get_int_arg(i->first, 0))
2231 d3::scene::filter();
2232 else
2233 d3::scene::nofilter();
2234 } else if (!strcmp(option_name, "occ-norm")) {
2235 if (env->get_int_arg(i->first, 0))
2236 d3::scene::nw();
2237 else
2238 d3::scene::no_nw();
2239 } else if (!strcmp(option_name, "inc")) {
2240 inc = env->get_int_arg(i->first, 0);
2241 } else if (!strcmp(option_name, "exp-mult")) {
2242 double exp_c, exp_r, exp_b;
2244 exp_c = env->get_double_arg(i->first, 1);
2245 exp_r = env->get_double_arg(i->first, 2);
2246 exp_b = env->get_double_arg(i->first, 3);
2248 exp_mult = d2::pixel(1/(exp_r * exp_c), 1/exp_c, 1/(exp_b * exp_c));
2250 } else if (!strcmp(option_name, "visp-scale")) {
2252 vise_scale_factor = env->get_double_arg(i->first, 1);
2254 if (vise_scale_factor <= 0.0)
2255 ui::get()->error("VISP scale must be greater than zero");
2257 if (!finite(vise_scale_factor))
2258 ui::get()->error("VISP scale must be finite");
2260 } else if (!strcmp(option_name, "scale")) {
2262 scale_factor = env->get_double_arg(i->first, 1);
2264 if (scale_factor <= 0)
2265 ui::get()->error("Scale factor must be greater than zero");
2267 if (!finite(scale_factor))
2268 ui::get()->error("Scale factor must be finite");
2270 } else if (!strcmp(option_name, "metric")) {
2271 d2::align::set_metric_exponent(env->get_double_arg(i->first, 1));
2272 } else if (!strcmp(option_name, "threshold")) {
2273 d2::align::set_match_threshold(env->get_double_arg(i->first, 1));
2274 } else if (!strcmp(option_name, "drizzle-diam")) {
2275 unsupported::discontinued("--drizzle-diam=<x>", "--dchain box:1");
2276 } else if (!strcmp(option_name, "perturb-lower")) {
2277 const char *option = env->get_string_arg(i->first, 1);
2278 double perturb_lower;
2279 int characters;
2280 sscanf(option, "%lf%n", &perturb_lower, &characters);
2281 if (perturb_lower <= 0)
2282 ui::get()->error("--perturb-lower= value is non-positive");
2284 if (*(option + characters) == '%')
2285 d2::align::set_perturb_lower(perturb_lower, 1);
2286 else
2287 d2::align::set_perturb_lower(perturb_lower, 0);
2288 } else if (!strcmp(option_name, "stepsize")) {
2289 ui::get()->warn("--stepsize is deprecated. Use --perturb-lower instead");
2290 d2::align::set_perturb_lower(env->get_double_arg(i->first, 1), 0);
2291 } else if (!strcmp(option_name, "va-upper")) {
2292 const char *option = env->get_string_arg(i->first, 1);
2293 double va_upper;
2294 int characters;
2295 sscanf(option, "%lf%n", &va_upper, &characters);
2296 if (*(option + characters) == '%')
2297 ui::get()->error("--va-upper= does not accept '%' arguments\n");
2298 else
2299 d3::cpf::set_va_upper(va_upper);
2300 } else if (!strcmp(option_name, "cpp-upper")) {
2301 const char *option = env->get_string_arg(i->first, 1);
2302 double perturb_upper;
2303 int characters;
2304 sscanf(option, "%lf%n", &perturb_upper, &characters);
2305 if (*(option + characters) == '%')
2306 ui::get()->error("--cpp-upper= does not currently accept '%' arguments\n");
2307 else
2308 d3::cpf::set_cpp_upper(perturb_upper);
2309 } else if (!strcmp(option_name, "cpp-lower")) {
2310 const char *option = env->get_string_arg(i->first, 1);
2311 double perturb_lower;
2312 int characters;
2313 sscanf(option, "%lf%n", &perturb_lower, &characters);
2314 if (*(option + characters) == '%')
2315 ui::get()->error("--cpp-lower= does not currently accept '%' arguments\n");
2316 else
2317 d3::cpf::set_cpp_lower(perturb_lower);
2318 } else if (!strcmp(option_name, "hf-enhance")) {
2319 unsupported::discontinued("--hf-enhance=<x>");
2320 } else if (!strcmp(option_name, "rot-upper")) {
2321 d2::align::set_rot_max((int) floor(env->get_double_arg(i->first, 1)));
2322 } else if (!strcmp(option_name, "bda-mult")) {
2323 d2::align::set_bda_mult(env->get_double_arg(i->first, 1));
2324 } else if (!strcmp(option_name, "bda-rate")) {
2325 d2::align::set_bda_rate(env->get_double_arg(i->first, 1));
2326 } else if (!strcmp(option_name, "lod-max")) {
2327 d2::align::set_lod_max((int) floor(env->get_double_arg(i->first, 1)));
2328 } else if (!strcmp(option_name, "cpf-load")) {
2329 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
2330 #if 0
2331 } else if (!strcmp(option_name, "model-load")) {
2332 d3::scene::load_model(env->get_string_arg(i->first, 1));
2333 } else if (!strcmp(option_name, "model-save")) {
2334 d3::scene::save_model(env->get_string_arg(i->first, 1));
2335 #endif
2336 } else if (!strcmp(option_name, "trans-load")) {
2337 d2::tload_delete(tload);
2338 tload = d2::tload_new(env->get_string_arg(i->first, 1));
2339 d2::align::set_tload(tload);
2340 } else if (!strcmp(option_name, "trans-save")) {
2341 tsave_delete(tsave);
2342 tsave = d2::tsave_new(env->get_string_arg(i->first, 1));
2343 d2::align::set_tsave(tsave);
2344 } else if (!strcmp(option_name, "3d-trans-load")) {
2345 d3::tload_delete(d3_tload);
2346 d3_tload = d3::tload_new(env->get_string_arg(i->first, 1));
2347 d3::align::set_tload(d3_tload);
2348 } else if (!strcmp(option_name, "3d-trans-save")) {
2349 d3::tsave_delete(d3_tsave);
2350 d3_tsave = d3::tsave_new(env->get_string_arg(i->first, 1));
2351 d3::align::set_tsave(d3_tsave);
2352 } else {
2353 assert(0);
2358 * Apply implication logic.
2361 if (extend == 0 && vise_count != 0) {
2362 implication::changed("VISP requires increased image extents.",
2363 "Image extension is now enabled.",
2364 "--extend");
2365 extend = 1;
2368 if (psf_match && ex_count)
2369 unsupported::fornow("PSF calibration with exclusion regions.");
2372 if (d3_output != NULL && ip_iterations != 0)
2373 unsupported::fornow("3D modeling with Irani-Peleg rendering");
2375 #if 0
2376 if (extend == 0 && d3_output != NULL) {
2377 implication::changed("3D modeling requires increased image extents.",
2378 "Image extension is now enabled.",
2379 "--extend");
2380 extend = 1;
2382 #endif
2384 if (cx_parameter != 0 && !exposure_register) {
2385 implication::changed("Certainty-based rendering requires exposure registration.",
2386 "Exposure registration is now enabled.",
2387 "--exp-register");
2388 d2::align::exp_register();
2389 exposure_register = 1;
2393 * Set alignment class exclusion region static variables
2396 d2::align::set_exclusion(ex_parameters, ex_count);
2399 * Initialize renderer class statics.
2402 d2::render::render_init(ex_count, ex_parameters, ex_show, extend, scale_factor);
2405 * Set confidence
2408 d2::exposure::set_confidence(cx_parameter);
2411 * Keep transformations for Irani-Peleg, psf-match, and
2412 * VISE
2415 if (ip_iterations > 0 || psf_match || vise_count > 0) {
2416 d2::align::keep();
2420 * Initialize device-specific variables
2423 // int input_file_count = argc - i - 1;
2424 int input_file_count = files.size() - 1;
2426 d2::psf *device_response[psf_N] = { NULL, NULL };
2427 d2::exposure **input_exposure = NULL;
2428 ale_pos view_angle = 43.7 * M_PI / 180;
2429 // ale_pos view_angle = 90 * M_PI / 180;
2430 input_exposure = (d2::exposure **)
2431 // malloc((argc - i - 1) * sizeof(d2::exposure *));
2432 malloc(input_file_count * sizeof(d2::exposure *));
2434 if (device != NULL) {
2435 if (!strcmp(device, "xvp610_640x480")) {
2436 device_response[psf_linear] = new xvp610_640x480::lpsf();
2437 device_response[psf_nonlinear] = new xvp610_640x480::nlpsf();
2438 for (int ii = 0; ii < input_file_count; ii++)
2439 input_exposure[ii] = new xvp610_640x480::exposure();
2440 view_angle = xvp610_640x480::view_angle();
2441 } else if (!strcmp(device, "xvp610_320x240")) {
2442 device_response[psf_linear] = new xvp610_320x240::lpsf();
2443 device_response[psf_nonlinear] = new xvp610_320x240::nlpsf();
2444 for (int ii = 0; ii < input_file_count; ii++)
2445 input_exposure[ii] = new xvp610_320x240::exposure();
2446 view_angle = xvp610_320x240::view_angle();
2447 } else if (!strcmp(device, "ov7620_raw_linear")) {
2448 device_response[psf_linear] = new ov7620_raw_linear::lpsf();
2449 device_response[psf_nonlinear] = NULL;
2450 for (int ii = 0; ii < input_file_count; ii++)
2451 input_exposure[ii] = new ov7620_raw_linear::exposure();
2452 d2::image_rw::set_default_bayer(IMAGE_BAYER_BGRG);
2453 } else if (!strcmp(device, "canon_300d_raw_linear")) {
2454 device_response[psf_linear] = new canon_300d_raw_linear::lpsf();
2455 device_response[psf_nonlinear] = NULL;
2456 for (int ii = 0; ii < input_file_count; ii++)
2457 input_exposure[ii] = new canon_300d_raw_linear::exposure();
2458 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2459 } else if (!strcmp(device, "canon_300d_raw_linear+85mm_1.8")) {
2460 device_response[psf_linear] = new canon_300d_raw_linear_85mm_1_8::lpsf();
2461 device_response[psf_nonlinear] = NULL;
2462 for (int ii = 0; ii < input_file_count; ii++)
2463 input_exposure[ii] = new canon_300d_raw_linear_85mm_1_8::exposure();
2464 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2465 view_angle = canon_300d_raw_linear_85mm_1_8::view_angle();
2466 } else if (!strcmp(device, "canon_300d_raw_linear+50mm_1.8")) {
2467 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_8::lpsf();
2468 device_response[psf_nonlinear] = NULL;
2469 for (int ii = 0; ii < input_file_count; ii++)
2470 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_8::exposure();
2471 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2472 view_angle = canon_300d_raw_linear_50mm_1_8::view_angle();
2473 } else if (!strcmp(device, "canon_300d_raw_linear+50mm_1.4")) {
2474 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4::lpsf();
2475 device_response[psf_nonlinear] = NULL;
2476 for (int ii = 0; ii < input_file_count; ii++)
2477 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4::exposure();
2478 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2479 view_angle = canon_300d_raw_linear_50mm_1_4::view_angle();
2480 } else if (!strcmp(device, "canon_300d_raw_linear+50mm_1.4@1.4")) {
2481 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4_1_4::lpsf();
2482 device_response[psf_nonlinear] = NULL;
2483 for (int ii = 0; ii < input_file_count; ii++)
2484 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4_1_4::exposure();
2485 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2486 view_angle = canon_300d_raw_linear_50mm_1_4_1_4::view_angle();
2487 } else {
2488 ui::get()->unknown_device(device);
2490 } else {
2491 for (int ii = 0; ii < input_file_count; ii++)
2492 input_exposure[ii] = new d2::exposure_default();
2496 * User-specified variables.
2499 if (user_view_angle != 0) {
2500 view_angle = user_view_angle;
2503 if (user_bayer != IMAGE_BAYER_DEFAULT) {
2504 d2::image_rw::set_default_bayer(user_bayer);
2508 * PSF-match exposure.
2510 if (psf_match) {
2511 delete input_exposure[input_file_count - 1];
2512 input_exposure[input_file_count - 1] = new d2::exposure_default();
2516 * Initialize output exposure
2519 d2::exposure *output_exposure = new d2::exposure_default();
2520 output_exposure->set_multiplier(exp_mult);
2523 * Configure the response function.
2526 d2::psf *response[2] = {NULL, NULL};
2528 for (int n = 0; n < psf_N; n++ ) {
2529 if (psf[n] != NULL) {
2531 response[n] = d2::psf_parse::get((n == psf_linear), psf[n]);
2533 } else if (device_response[n] != NULL) {
2536 * Device-specific response
2539 response[n] = device_response[n];
2541 } else {
2544 * Default point-spread function.
2547 if (n == psf_linear) {
2550 * Default lpsf is a box filter
2551 * of diameter 1.0 (radius
2552 * 0.5).
2555 response[n] = new d2::box(0.5);
2557 } else if (n == psf_nonlinear) {
2560 * nlpsf is disabled by default.
2563 response[n] = NULL;
2569 * First file argument. Print general file information as well
2570 * as information specific to this argument. Initialize image
2571 * file handler.
2574 // d2::image_rw::init(argc - i - 1, argv + i, argv[argc - 1], input_exposure, output_exposure);
2575 // ochain_names[0] = argv[argc - 1];
2577 const char **input_files = (const char **) malloc(sizeof(const char *) * input_file_count);
2578 for (int i = 0; i < input_file_count; i++) {
2579 input_files[i] = files[i].first;
2582 d2::image_rw::init(input_file_count, input_files, files[files.size() - 1].first,
2583 input_exposure, output_exposure);
2585 ochain_names[0] = files[files.size() - 1].first;
2588 * Handle control point data for alignment
2590 d2::align::set_cp_count(d3::cpf::count());
2591 for (unsigned int ii = 0; ii < d3::cpf::count(); ii++)
2592 d2::align::set_cp(ii, d3::cpf::get_2d(ii));
2595 * PSF-match bayer patterns.
2598 if (psf_match) {
2599 // d2::image_rw::set_specific_bayer(argc - i - 2, IMAGE_BAYER_NONE);
2600 d2::image_rw::set_specific_bayer(input_file_count - 1, IMAGE_BAYER_NONE);
2604 * Handle alignment weight map, if necessary
2607 if (wm_filename != NULL) {
2608 d2::image *weight_map;
2609 weight_map = d2::image_rw::read_image(wm_filename, new d2::exposure_linear());
2610 weight_map->set_offset(wm_offsety, wm_offsetx);
2611 d2::align::set_weight_map(weight_map);
2615 * Write comment information about original frame and
2616 * target image to the transformation save file, if we
2617 * have one.
2620 const d2::image *im = d2::image_rw::open(0);
2621 // tsave_orig(tsave, argv[i], im->avg_channel_magnitude());
2622 // tsave_target(tsave, argv[argc - 1]);
2623 tsave_orig(tsave, files[0].first, im->avg_channel_magnitude());
2624 tsave_target(tsave, files[files.size() - 1].first);
2625 d2::image_rw::close(0);
2628 * Initialize alignment interpolant.
2631 if (afilter_type != "internal")
2632 d2::align::set_interpolant(d2::render_parse::get_SSF(afilter_type));
2635 * Initialize achain and ochain.
2638 achain = d2::render_parse::get(achain_type);
2640 for (int chain = 0; chain < oc_count; chain++)
2641 ochain[chain] = d2::render_parse::get(ochain_types[chain]);
2644 * Use merged renderings as reference images in
2645 * alignment.
2648 d2::align::set_reference(achain);
2651 * Tell the alignment class about the scale factor.
2654 d2::align::set_scale(scale_factor);
2657 * Initialize visp.
2660 d2::vise_core::set_scale(vise_scale_factor);
2662 for (int opt = 0; opt < vise_count; opt++) {
2663 d2::vise_core::add(d2::render_parse::get(visp[opt * 4 + 0]),
2664 visp[opt * 4 + 1],
2665 visp[opt * 4 + 2],
2666 visp[opt * 4 + 3]);
2670 * Initialize non-incremental renderers
2673 #if 0
2674 if (usm_multiplier != 0) {
2677 * Unsharp Mask renderer
2680 ochain[0] = new d2::usm(ochain[0], scale_factor,
2681 usm_multiplier, inc, response[psf_linear],
2682 response[psf_nonlinear], &input_exposure[0]);
2684 #endif
2686 if (psf_match) {
2689 * Point-spread function calibration renderer.
2690 * This renderer does not produce image output.
2691 * It is reserved for use with the point-spread
2692 * function calibration script
2693 * ale-psf-calibrate.
2696 ochain[0] = new d2::psf_calibrate(ochain[0],
2697 1, inc, response[psf_linear],
2698 response[psf_nonlinear],
2699 psf_match_args);
2701 } else if (ip_iterations != 0) {
2704 * Irani-Peleg renderer
2707 ochain[0] = new d2::ipc( ochain[0], ip_iterations,
2708 inc, response[psf_linear],
2709 response[psf_nonlinear],
2710 (exposure_register == 1), ip_use_median);
2714 * Iterate through all files.
2717 for (unsigned int j = 0; j < d2::image_rw::count(); j++) {
2720 * Iterate through non-global options
2723 environment *env = files[j].second;
2725 for (std::map<const char *, const char *>::iterator i = env->get_map().begin();
2726 i != env->get_map().end(); i++) {
2728 if (!env->is_option(i->first))
2729 continue;
2731 const char *option_name = env->get_option_name(i->first);
2733 if (!strcmp(option_name, "mc")) {
2734 int type = env->get_int_arg(i->first, 0);
2735 d2::align::mc((type == 2) ? env->get_double_arg(i->first, 1) / 100
2736 : (double) type);
2737 } else if (!strcmp(option_name, "mcd-removal")) {
2738 d2::align::mcd_limit(env->get_int_arg(i->first, 1));
2739 } else if (!strcmp(option_name, "perturb-upper")) {
2740 const char *option = env->get_string_arg(i->first, 1);
2741 double perturb_upper;
2742 int characters;
2743 sscanf(option, "%lf%n", &perturb_upper, &characters);
2744 if (*(option + characters) == '%')
2745 d2::align::set_perturb_upper(perturb_upper, 1);
2746 else
2747 d2::align::set_perturb_upper(perturb_upper, 0);
2748 } else if (!strcmp(option_name, "threads")) {
2749 thread::set_count((unsigned int) env->get_int_arg(i->first, 1));
2750 } else if (!strcmp(option_name, "per-cpu")) {
2751 thread::set_per_cpu((unsigned int) env->get_int_arg(i->first, 1));
2752 } else {
2754 * This error should be encountered earlier.
2757 assert(0);
2759 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
2760 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
2761 option_name);
2762 exit(1);
2768 if (j == 0) {
2770 * Handle the original frame.
2773 // ui::get()->original_frame_start(argv[i]);
2774 ui::get()->original_frame_start(files[0].first);
2776 for (int opt = 0; opt < oc_count; opt++) {
2777 ui::get()->set_orender_current(opt);
2778 ochain[opt]->sync(0);
2779 if (inc) {
2780 ui::get()->writing_output(opt);
2781 d2::image_rw::write_image(ochain_names[opt],
2782 ochain[opt]->get_image(0));
2786 d2::vise_core::frame_queue_add(0);
2788 ui::get()->original_frame_done();
2790 continue;
2794 * Handle supplemental frames.
2797 const char *name = d2::image_rw::name(j);
2799 ui::get()->supplemental_frame_start(name);
2802 * Write comment information about the
2803 * supplemental frame to the transformation
2804 * save file, if we have one.
2807 tsave_info (tsave, name);
2809 const d2::image *im = d2::image_rw::open(j);
2810 d2::pixel apm = im->avg_channel_magnitude();
2811 tsave_apm(tsave, apm[0], apm[1], apm[2]);
2812 d2::image_rw::close(j);
2814 for (int opt = 0; opt < oc_count; opt++) {
2815 ui::get()->set_orender_current(opt);
2816 ochain[opt]->sync(j);
2817 if (inc) {
2818 ui::get()->writing_output(opt);
2819 d2::image_rw::write_image(ochain_names[opt],
2820 ochain[opt]->get_image(j));
2824 d2::vise_core::frame_queue_add(j);
2826 ui::get()->supplemental_frame_done();
2830 * Do any post-processing and output final image
2832 * XXX: note that non-incremental renderers currently
2833 * return zero for ochain[0]->sync(), since they write
2834 * output internally when inc != 0.
2837 for (int opt = 0; opt < oc_count; opt++)
2838 if ((ochain[opt]->sync() || !inc) && !psf_match)
2839 d2::image_rw::write_image(ochain_names[opt], ochain[opt]->get_image());
2842 * Output a summary match statistic.
2845 ui::get()->ale_2d_done((double) d2::align::match_summary());
2848 * Perform any 3D tasks
2851 optimizations::begin_3d_work();
2853 if (d3_count > 0) {
2855 ui::get()->d3_start();
2857 d3::align::init_angle(view_angle);
2859 ui::get()->d3_init_view_angle(view_angle / M_PI * 180);
2861 d3::align::init_from_d2();
2863 if (d3::cpf::count() > 0) {
2864 ui::get()->d3_control_point_solve();
2865 d3::cpf::solve_3d();
2866 ui::get()->d3_control_point_solve_done();
2869 ui::get()->d3_final_view_angle(d3::align::angle_of(0) / M_PI * 180);
2871 d3::align::write_alignments();
2873 d3::scene::set_filter_type(d3chain_type);
2875 d3::scene::init_from_d2();
2877 ui::get()->d3_subdividing_space();
2878 d3::scene::make_space(d3_depth, d3_output, &d3_depth_pt, &d3_output_pt);
2879 ui::get()->d3_subdividing_space_done();
2881 ui::get()->d3_updating_occupancy();
2882 d3::scene::reduce_cost_to_search_depth(output_exposure, inc);
2883 ui::get()->d3_updating_occupancy_done();
2885 d3::scene::d3px(d3px_count, d3px_parameters);
2886 int view_count = 0;
2887 for (unsigned int i = 0; i < d2::image_rw::count(); i++) {
2888 assert (i < d3_count);
2890 if (d3_depth[i] != NULL) {
2891 ui::get()->d3_writing_output(d3_depth[i]);
2892 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2893 const d2::image *im = d3::scene::depth(i);
2894 d2::image_rw::write_image(d3_depth[i], im, output_exposure, 1, 1);
2895 delete im;
2896 ui::get()->d3_writing_output_done();
2899 if (d3_output[i] != NULL) {
2900 ui::get()->d3_writing_output(d3_output[i]);
2901 const d2::image *im = d3::scene::view(i);
2902 d2::image_rw::write_image(d3_output[i], im, output_exposure);
2903 delete im;
2904 d3::focus::set_camera(view_count++);
2905 ui::get()->d3_writing_output_done();
2908 for (std::map<const char *, d3::pt>::iterator i = d3_output_pt.begin();
2909 i != d3_output_pt.end(); i++) {
2911 ui::get()->d3_writing_output(i->first);
2912 const d2::image *im = d3::scene::view(i->second);
2913 d2::image_rw::write_image(i->first, im, output_exposure);
2914 delete im;
2915 d3::focus::set_camera(view_count++);
2916 ui::get()->d3_writing_output_done();
2919 for (std::map<const char *, d3::pt>::iterator i = d3_depth_pt.begin();
2920 i != d3_depth_pt.end(); i++) {
2922 ui::get()->d3_writing_output(i->first);
2923 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2924 const d2::image *im = d3::scene::depth(i->second);
2925 d2::image_rw::write_image(i->first, im, output_exposure, 1, 1);
2926 delete im;
2927 ui::get()->d3_writing_output_done();
2931 for (unsigned int i = d2::image_rw::count(); i < d3_count; i++) {
2932 if (d3_depth[i] != NULL) {
2933 fprintf(stderr, "\n\n*** Frame number for --3dd too high. ***\n\n");
2935 if (d3_output[i] != NULL) {
2936 fprintf(stderr, "\n\n*** Frame number for --3dv too high. ***\n\n");
2942 * Destroy the image file handler
2945 d2::image_rw::destroy();
2948 * Delete the transformation file structures, if any
2949 * exist.
2952 tsave_delete(tsave);
2953 tload_delete(tload);
2956 * We're done.
2959 exit(0);
2963 #endif