d2::trans_multi: Add --mi option (useful for debugging multi-alignment
[Ale.git] / ui / input.h
blob9236394859802dc9439bc4505b6153712b9a62d4
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 "unsupported.h"
45 #include "implication.h"
48 * Configuration
51 #if HAVE_CONFIG_H
52 # include <config.h>
53 #endif
56 * GNU extensions
59 extern "C" {
60 #include "string_.h"
64 * Types
67 #include "../ale_pos.h"
68 #include "../ale_real.h"
71 * 2D include files
74 #include "../d2.h"
77 * 3D include files
80 #include "../d3.h"
83 * Thread include files
86 #include "../thread.h"
89 * Device configuration files
92 #include "../device/xvp610_320x240.h"
93 #include "../device/xvp610_640x480.h"
94 #include "../device/ov7620_raw_linear.h"
95 #include "../device/canon_300d_raw_linear.h"
96 #include "../device/canon_300d_raw_linear_85mm_1_8.h"
97 #include "../device/canon_300d_raw_linear_50mm_1_8.h"
98 #include "../device/canon_300d_raw_linear_50mm_1_4.h"
99 #include "../device/canon_300d_raw_linear_50mm_1_4_1_4.h"
100 #include "../device/nikon_d50.h"
103 * Help files
106 #include "help.h"
108 class input {
111 * Flag for global options.
114 static int global_options;
117 * Helper functions.
121 * Argument counter.
123 * Counts instances of a given option.
125 static unsigned int arg_count(int argc, const char *argv[], const char *arg) {
126 unsigned int count = 0;
127 for (int i = 0; i < argc; i++) {
128 if (!strcmp(argv[i], arg))
129 count++;
130 else if (!strcmp(argv[i], "--"))
131 return count;
133 return count;
137 * Argument prefix counter.
139 * Counts instances of a given option prefix.
141 static unsigned int arg_prefix_count(int argc, const char *argv[], const char *pfix) {
142 unsigned int count = 0;
143 for (int i = 0; i < argc; i++) {
144 if (!strncmp(argv[i], pfix, strlen(pfix)))
145 count++;
146 else if (!strcmp(argv[i], "--"))
147 return count;
149 return count;
153 * Reallocation function
155 static void *local_realloc(void *ptr, size_t size) {
156 void *new_ptr = realloc(ptr, size);
158 if (new_ptr == NULL)
159 ui::get()->memory_error_location("main()");
161 return new_ptr;
165 * Not enough arguments function.
167 static void not_enough(const char *opt_name) {
168 ui::get()->cli_not_enough(opt_name);
172 * Bad argument function
174 static void bad_arg(const char *opt_name) {
175 ui::get()->cli_bad_arg(opt_name);
179 * String comparison class.
182 class compare_strings {
183 public:
184 int operator()(const char *A, const char *B) const {
185 return strcmp(A, B) < 0;
190 * Environment structures.
192 * XXX: It's arguable that these should be public members of the
193 * 'input' class in order to allow passing environment values to other
194 * classes, but, since we're currently using them only to prepare state
195 * for an internal 'input' function, they can stay private for now. A
196 * more nuanced approach will likely be required later.
199 class environment {
200 static std::stack<environment *> environment_stack;
201 static std::set<environment *> environment_set;
203 std::map<const char *, const char *, compare_strings> environment_map;
206 * Internal set operations do not protect any data.
209 void internal_set(const char *name, const char *value) {
210 environment_map[name] = value;
213 void internal_unset(const char *name) {
214 environment_map.erase(name);
217 const char *internal_convert_pointer(const void *pointer) {
218 int chars = sizeof(void *) * 2 + 3;
219 char *c = (char *) malloc(sizeof(char) * chars);
221 assert(c);
223 if (!c)
224 ui::get()->memory_error_location("environment::set_ptr");
226 int count = snprintf(c, chars, "%p", pointer);
228 assert (count >= 0 && count < chars);
230 return c;
233 void internal_set_ptr(const char *name, const void *pointer) {
234 internal_set(name, internal_convert_pointer(pointer));
238 * Check for restricted names.
241 int name_ok(const char *name) {
242 if (!strcmp(name, "---chain") || !strcmp(name, "---this"))
243 return 0;
245 return 1;
248 void name_check(const char *name) {
249 if (!name_ok(name)) {
250 fprintf(stderr, "Bad set operation.");
251 assert(0);
252 exit(1);
256 public:
259 * Get the environment map.
262 std::map<const char *, const char *, compare_strings> &get_map() {
263 return environment_map;
267 * Public set operations restrict valid names.
270 void set(const char *name, const char *value) {
271 name_check(name);
272 internal_set(name, value);
275 void unset(const char *name) {
276 name_check(name);
277 internal_unset(name);
280 void set_ptr(const char *name, const void *pointer) {
281 name_check(name);
282 internal_set_ptr(name, pointer);
285 const char *get(const char *name) {
286 if (environment_map.count(name) == 0)
287 return NULL;
289 return environment_map[name];
293 * Make an environment substructure. Note that since deep
294 * structures are currently referenced rather than copied when
295 * the stack is pushed, there is no current need for any
296 * chaining mechanism.
298 void make_substructure(const char *name) {
299 environment *s = new environment;
300 set_ptr(name, s);
301 environment_set.insert(s);
304 static int is_env(const char *name) {
305 void *ptr_value;
306 sscanf(name, "%p", &ptr_value);
309 * Check for bad pointers.
312 if (!environment_set.count((environment *) ptr_value)) {
313 return 0;
316 return 1;
319 const char *get_option_name(const char *name) {
320 if (strncmp(name, "0 ", strlen("0 ")))
321 return NULL;
323 name += strlen("0 ");
325 if (!isdigit(name[0]))
326 return NULL;
328 while (isdigit(name[0]))
329 name++;
331 if (!isspace(name[0]))
332 return NULL;
334 while (isspace(name[0]))
335 name++;
337 if (!isalnum(name[0]))
338 return NULL;
340 return name;
343 int is_option(const char *name) {
344 return (get_option_name(name) != NULL);
347 int is_arg(const char *name, unsigned int arg) {
348 assert (is_option(name));
350 int length = strlen(name) + 3 * sizeof(unsigned int);
352 char *desired_string = (char *) malloc(sizeof(char) * length);
354 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
356 int result = environment_map.count(desired_string);
358 free(desired_string);
360 return result > 0;
363 void remove_arg(const char *name, unsigned int arg) {
364 assert (is_option(name));
365 assert (is_arg(name, arg));
367 int length = strlen(name) + 3 * sizeof(unsigned int);
369 char *desired_string = (char *) malloc(sizeof(char) * length);
371 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
373 environment_map.erase(desired_string);
376 const char *get_string_arg(const char *name, unsigned int arg) {
377 assert (is_option(name));
379 int length = strlen(name) + 3 * sizeof(unsigned int);
381 char *desired_string = (char *) malloc(sizeof(char) * length);
383 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
385 const char *result = environment_map[desired_string];
387 assert (result);
389 free(desired_string);
391 return result;
394 long int get_long_arg(const char *name, unsigned int arg) {
395 assert (is_option(name));
397 const char *string = get_string_arg(name, arg);
398 char *endptr;
400 long int result = strtol(string, &endptr, 0);
402 if (endptr[0] != '\0') {
403 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
404 exit(1);
407 return result;
410 int get_int_arg(const char *name, unsigned int arg) {
411 return (int) get_long_arg(name, arg);
414 unsigned int get_unsigned_arg(const char *name, unsigned int arg) {
415 long int result = get_long_arg(name, arg);
417 if (result < 0) {
418 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
419 exit(1);
422 return (unsigned int) result;
425 double get_double_arg(const char *name, unsigned int arg) {
426 assert (is_option(name));
428 const char *string = get_string_arg(name, arg);
429 char *endptr;
431 double result = strtod(string, &endptr);
433 if (endptr[0] != '\0') {
434 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
435 exit(1);
438 return result;
441 static environment *get_env(const char *name) {
443 assert(name);
445 void *ptr_value;
446 sscanf(name, "%p", &ptr_value);
449 * Check for bad pointers.
452 if (!environment_set.count((environment *) ptr_value)) {
453 assert(0);
454 fprintf(stderr, "Bad environment pointer.\n");
455 exit(1);
458 return (environment *) ptr_value;
462 * Prepend to a list.
464 void prepend(const char *list, const char *element) {
465 environment *d = get_env(get(list));
466 make_substructure(list);
467 get_env(get(list))->set("a", element);
468 get_env(get(list))->set_ptr("d", d);
471 void prepend_ptr(const char *list, void *ptr) {
472 prepend(list, internal_convert_pointer(ptr));
476 * Clone the environment.
478 environment *clone() {
479 environment *e = new environment();
481 for (std::map<const char *, const char *, compare_strings>::iterator i = environment_map.begin();
482 i != environment_map.end(); i++) {
484 if (!name_ok(i->first))
485 continue;
487 if (is_env(i->second)) {
488 e->set_ptr(i->first, get_env(i->second)->clone());
489 } else {
490 e->set(i->first, i->second);
494 return e;
497 static environment *top() {
498 if (environment_stack.empty()) {
499 environment_stack.push(new environment);
500 environment_set.insert(environment_stack.top());
502 return environment_stack.top();
505 static void push() {
506 environment *e = new environment;
508 e->environment_map = environment_stack.top()->environment_map;
510 e->internal_set_ptr("---chain", environment_stack.top());
511 e->internal_set_ptr("---this", e);
512 e->make_substructure("---dup");
514 environment_stack.push(e);
515 environment_set.insert(e);
518 static void dup_second() {
519 environment_stack.top()->prepend_ptr("---dup",
520 environment::get_env(environment_stack.top()->get("---chain")));
523 static void push_and_dup_output() {
524 push();
525 dup_second();
528 static void pop() {
529 assert(!environment_stack.empty());
532 * Execution environments should never be referenced by
533 * structures further up the call chain, so they can
534 * safely be deleted. (XXX: In particular, while
535 * lexical scoping may require copying of execution
536 * environments from lower on the call chain, there is
537 * no obvious reason that a reference should be used in
538 * this case; a shallow copy should be used instead.)
541 environment_set.erase(environment_stack.top());
542 delete environment_stack.top();
544 environment_stack.pop();
548 * Set with duplication.
551 void set_with_dup(const char *name, const char *value) {
552 set(name, value);
554 if (!get("---dup"))
555 return;
557 environment *dup_item = get_env(get("---dup"));
559 assert (dup_item);
561 while (dup_item->get("a")) {
562 get_env(dup_item->get("a"))->set_with_dup(name, value);
563 assert(dup_item->get("d"));
564 dup_item = get_env(dup_item->get("d"));
565 assert(dup_item);
571 * Read tokens from a stream.
573 class token_reader {
574 public:
576 * Get the next token
578 virtual const char *get() = 0;
581 * Peek at the next token.
584 virtual const char *peek() = 0;
587 * Divert the stream until the next occurrence of TOKEN.
589 virtual token_reader *divert(const char *open_token, const char *close_token) = 0;
591 virtual int expects_exactly_one_option(void) {
592 return 0;
595 virtual ~token_reader() {
599 class argument_parsing_token_reader : public token_reader {
600 const char *index;
601 const char *separators;
602 public:
603 argument_parsing_token_reader(const char *s) {
604 index = s;
605 separators = "=";
608 int expects_exactly_one_option(void) {
609 return 1;
612 virtual const char *get() {
613 int length = strcspn(index, separators);
615 if (length == 0)
616 return NULL;
618 const char *result = strndup(index, length);
619 index += length;
621 if (strspn(index, separators) >= 1)
622 index++;
624 separators = ",";
626 return result;
629 virtual const char *peek() {
630 int length = strcspn(index, separators);
632 if (length == 0)
633 return NULL;
635 const char *result = strndup(index, length);
637 return result;
640 virtual token_reader *divert(const char *open_token, const char *close_token) {
641 assert(0);
642 return NULL;
646 class cstring_token_reader : public token_reader {
647 const char *separators;
648 const char *string;
649 int ephemeral;
651 cstring_token_reader(const char *s, int ephemeral) {
652 assert(ephemeral == 1);
654 separators = "\n \t";
655 string = s;
656 this->ephemeral = 1;
659 public:
660 cstring_token_reader(const char *s) {
661 separators = "\n \t";
662 string = s;
663 ephemeral = 0;
666 const char *get() {
668 string += strspn(string, separators);
670 size_t length_to_next = strcspn(string, separators);
672 if (length_to_next == 0)
673 return NULL;
675 const char *result = strndup(string, length_to_next);
677 string += length_to_next;
679 return result;
682 const char *peek() {
683 string += strspn(string, separators);
685 size_t length_to_next = strcspn(string, separators);
687 if (length_to_next == 0)
688 return NULL;
690 return strndup(string, length_to_next);
693 cstring_token_reader *divert(const char *open_token, const char *close_token) {
695 * This function might be broken.
698 assert(0);
700 int search = 0;
701 int next = strcspn(string, separators);
702 int depth = 0;
704 while (*(string + search) != '\0' &&
705 (depth || strcmp(close_token, (string + search)))) {
706 if (!strcmp(close_token, (string + search)))
707 depth--;
708 if (!strcmp(open_token, (string + search)))
709 depth++;
710 search = next;
711 next = strcspn((string + next), separators);
714 if (*(string + search) == '\0') {
715 fprintf(stderr, "Parse error: End of scope not found.");
716 exit(1);
719 cstring_token_reader *result = new cstring_token_reader(strndup(string, search), 1);
721 string += search;
724 * Eat the closing token.
727 get();
729 return result;
732 ~cstring_token_reader() {
733 if (ephemeral)
734 free((void *) string);
738 class cli_token_reader : public token_reader {
740 int arg_index;
741 int argc;
742 const char **argv;
744 public:
745 cli_token_reader(int c, const char *v[]) {
746 argc = c;
747 argv = v;
748 arg_index = 0;
751 const char *get() {
753 if (arg_index < argc)
754 return argv[arg_index++];
755 else
756 return NULL;
760 const char *peek() {
762 if (arg_index < argc)
763 return argv[arg_index];
764 else
765 return NULL;
769 cli_token_reader *divert(const char *open_token, const char *close_token) {
770 int search = 0;
771 int depth = 0;
773 while (arg_index + search < argc
774 && (depth || strcmp(argv[arg_index + search], close_token))) {
775 if (!strcmp(close_token, argv[arg_index + search]))
776 depth--;
777 if (!strcmp(open_token, argv[arg_index + search]))
778 depth++;
779 search++;
782 if (arg_index + search == argc) {
783 fprintf(stderr, "Parse error: end of scope not found.\n");
784 exit(1);
787 cli_token_reader *result = new cli_token_reader(search, argv + arg_index);
789 arg_index += search;
792 * Eat the closing token.
795 get();
797 return result;
802 struct simple_option {
803 const char *name;
804 const char *map_name;
805 const char *map_value;
806 int arg_count;
807 int multi;
810 static const char *supported_nonglobal_option_table[];
811 static const char *focus_prefixes[];
812 static simple_option simple_option_table[];
814 static int option_name_match(const char *unadorned, const char *token, int require_ornamentation = 1) {
815 int strip_max = 2;
817 if (!strcmp(unadorned, token) && !require_ornamentation)
818 return 1;
820 while (token[0] == '-' && strip_max) {
821 token++;
822 strip_max--;
823 if (!strcmp(unadorned, token))
824 return 1;
827 return 0;
830 static int is_scope_operator(const char *string) {
831 if (!strcmp("{", string)
832 || !strcmp("}", string)
833 || !strcmp("[", string)
834 || !strcmp("]", string)
835 || !strcmp("<", string)
836 || !strcmp(">", string))
837 return 1;
839 return 0;
842 static const char *option_name_gen(const char *unadorned, const char *map_name, int arg_num, int multi) {
843 static unsigned int multi_counter = 0;
845 if (map_name) {
846 unadorned = map_name;
849 int length = (strlen(unadorned) + sizeof(unsigned int) * 3 + sizeof(int) * 3 + 2) + 1;
851 char *result = (char *) malloc(sizeof(char) * length);
853 assert (result);
855 if (!multi) {
856 snprintf(result, length, "%u 0 %s", arg_num, unadorned);
857 } else {
860 * XXX: This assumes that generating calls for
861 * options other than 0 exist in the same
862 * multiplicity group as the most recently
863 * generated 0-option multiplicity.
866 if (arg_num == 0)
867 multi_counter++;
869 snprintf(result, length, "%u %u %s", arg_num, multi_counter, unadorned);
872 return result;
875 static environment *genv;
877 static const char *get_next(token_reader *tr, const char *option_name) {
878 const char *argument = tr->get();
880 if (argument == NULL) {
881 fprintf(stderr, "\n\nError: not enough arguments for `%s'.\n\n", option_name);
882 exit(1);
885 return argument;
888 static int table_contains(const char **haystack, const char *needle, int prefix_length = 0) {
890 if (needle == NULL)
891 return 0;
893 while (*haystack != NULL) {
894 if (prefix_length == 0 && !strcmp(*haystack, needle))
895 return 1;
896 if (prefix_length > 0 && !strncmp(*haystack, needle, prefix_length))
897 return 1;
898 haystack++;
901 return 0;
904 static int option_is_identical(environment *a, environment *b, const char *option_name) {
905 if (!a->is_option(option_name) || !b->is_option(option_name))
906 return 0;
908 int option_number = 0;
910 while (a->is_arg(option_name, option_number) || b->is_arg(option_name, option_number)) {
911 if (!a->is_arg(option_name, option_number)
912 || !b->is_arg(option_name, option_number))
913 return 0;
915 const char *a_str = a->get_string_arg(option_name, option_number);
916 const char *b_str = b->get_string_arg(option_name, option_number);
918 if (strcmp(a_str, b_str))
919 return 0;
921 option_number++;
924 return 1;
927 static void remove_option(environment *a, const char *option_name) {
928 assert(a->is_option(option_name));
930 int option_number = 0;
932 while (a->is_arg(option_name, option_number)) {
933 a->remove_arg(option_name, option_number);
934 option_number++;
938 static void remove_nonglobals(environment *a) {
939 assert(a);
941 std::stack<const char *> removal_stack;
943 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
944 i != a->get_map().end(); i++) {
946 if (!a->is_option(i->first))
947 continue;
949 if (!table_contains(supported_nonglobal_option_table, a->get_option_name(i->first)))
950 continue;
952 removal_stack.push(i->first);
955 while (!removal_stack.empty()) {
956 remove_option(a, removal_stack.top());
957 removal_stack.pop();
961 static void option_intersect(environment *a, environment *b) {
962 assert(a);
963 assert(b);
965 std::stack<const char *> removal_stack;
967 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
968 i != a->get_map().end(); i++) {
970 if (!a->is_option(i->first))
971 continue;
973 if (option_is_identical(a, b, i->first))
974 continue;
976 removal_stack.push(i->first);
979 while (!removal_stack.empty()) {
980 remove_option(a, removal_stack.top());
981 removal_stack.pop();
985 static void option_difference(environment *a, environment *b) {
986 assert(a);
987 assert(b);
989 std::stack<const char *> removal_stack;
991 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
992 i != a->get_map().end(); i++) {
994 if (!a->is_option(i->first))
995 continue;
997 if (!option_is_identical(a, b, i->first))
998 continue;
1000 removal_stack.push(i->first);
1003 while (!removal_stack.empty()) {
1004 remove_option(a, removal_stack.top());
1005 removal_stack.pop();
1009 static void evaluate_stream(token_reader *tr,
1010 std::vector<std::pair<const char *, environment *> > *files) {
1011 const char *token;
1012 int end_of_options = 0;
1014 while ((token = tr->get())) {
1017 * Check for nesting
1020 if (!strcmp(token, "{") && !end_of_options) {
1021 environment::push_and_dup_output();
1022 token_reader *tr_nest = tr->divert("{", "}");
1023 evaluate_stream(tr_nest, files);
1024 delete tr_nest;
1025 environment::pop();
1026 } else if (!strcmp(token, "[") && !end_of_options) {
1027 global_options = 0;
1028 environment::push();
1029 token_reader *tr_nest = tr->divert("[", "]");
1030 evaluate_stream(tr_nest, files);
1031 delete tr_nest;
1032 environment::pop();
1033 } else if (!strcmp(token, "<") && !end_of_options) {
1034 environment *dup_list = environment::get_env(environment::top()->get("---dup"));
1035 assert (dup_list != NULL);
1036 dup_list = dup_list->clone();
1038 environment::dup_second();
1039 token_reader *tr_nest = tr->divert("<", ">");
1040 evaluate_stream(tr_nest, files);
1041 delete tr_nest;
1043 environment::top()->set_ptr("---dup", dup_list);
1047 * Check for non-whitespace argument separators
1050 else if (!end_of_options && token && token[0] == '-' && strchr(token, '=')) {
1051 environment::push_and_dup_output();
1052 token_reader *tr_nest = new argument_parsing_token_reader(token);
1053 evaluate_stream(tr_nest, files);
1054 delete tr_nest;
1055 environment::pop();
1059 * Trap the end-of-option indicator.
1062 else if (!strcmp(token, "--")) {
1063 global_options = 0;
1064 end_of_options = 1;
1068 * Check for options and filenames
1071 else {
1073 * Handle filenames.
1076 if (strncmp("-", token, strlen("-")) || end_of_options) {
1078 assert(files);
1080 global_options = 0;
1081 files->push_back(std::pair<const char *, environment *>(strdup(token),
1082 environment::top()->clone()));
1084 if (tr->expects_exactly_one_option() && tr->get()) {
1085 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1086 exit(1);
1089 continue;
1093 * Handle focus option.
1096 if (option_name_match("focus", token)) {
1098 environment *target;
1099 target = environment::top();
1101 target->set_with_dup(option_name_gen("focus", NULL, 0, 0), "1");
1103 const char *option = get_next(tr, "focus");
1105 target->set_with_dup(option_name_gen("focus", NULL, 1, 0), option);
1107 if (!strcmp(option, "d")) {
1108 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1109 get_next(tr, "focus"));
1110 } else if (!strcmp(option, "p")) {
1111 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1112 get_next(tr, "focus"));
1113 target->set_with_dup(option_name_gen("focus", NULL, 3, 0),
1114 get_next(tr, "focus"));
1115 } else
1116 bad_arg("focus");
1118 int arg = 0;
1120 while (table_contains(focus_prefixes, tr->peek(), 3)) {
1121 target->set_with_dup(option_name_gen("focus", NULL, 4 + arg, 0),
1122 get_next(tr, "focus"));
1123 arg++;
1126 continue;
1130 * Handle simple options.
1133 int found_option = 0;
1134 for (int i = 0; simple_option_table[i].name; i++) {
1135 if (!option_name_match(simple_option_table[i].name, token))
1136 continue;
1139 * Handle the match case.
1142 found_option = 1;
1145 * Determine which environment should be modified
1148 environment *target;
1149 target = environment::top();
1152 * Store information required for
1153 * handling the local case later.
1156 const char *map_value = "1";
1158 if (simple_option_table[i].map_value) {
1159 map_value = simple_option_table[i].map_value;
1160 } else if (simple_option_table[i].map_name) {
1161 map_value = simple_option_table[i].name;
1164 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1165 simple_option_table[i].map_name,
1167 simple_option_table[i].multi),
1168 map_value);
1170 for (int j = 0; j < simple_option_table[i].arg_count; j++) {
1171 const char *option = tr->get();
1173 if (option == NULL) {
1174 fprintf(stderr, "\n\nError: not enough options for `%s'.\n\n", token);
1175 exit(1);
1179 * Reject scope operators as options,
1180 * at least for now.
1183 if (is_scope_operator(option)) {
1184 fprintf(stderr, "\n\nError: illegal argument to `%s'.\n\n", token);
1185 exit(1);
1188 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1189 simple_option_table[i].map_name,
1190 j + 1,
1191 simple_option_table[i].multi),
1192 option);
1197 * Trap illegal options.
1200 if (!found_option)
1201 ui::get()->illegal_option(token);
1204 if (tr->expects_exactly_one_option() && tr->get()) {
1205 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1206 exit(1);
1211 public:
1213 * Input handler.
1215 * Does one of two things:
1217 * (1) Output version information if called with '--version'
1219 * (2) Read options and file arguments, and if the arguments are correct,
1220 * write output. If an error is detected, print the usage statement.
1224 static void handle(int argc, const char *argv[], const char *package, const char *short_version, const char *version) {
1227 * Initialize help object
1230 help hi(package, argv[0], short_version);
1233 * Output version information if --version appears
1234 * on the command line.
1237 if (arg_count(argc, argv, "--version")) {
1239 * Output the version
1242 fprintf(stdout, "%s", version);
1244 return;
1248 * Handle help options
1251 if (arg_prefix_count(argc, argv, "--h"))
1252 for (int i = 1; i < argc; i++) {
1253 int all = !strcmp(argv[i], "--hA");
1254 int is_help_option = !strncmp(argv[i], "--h", strlen("--h"));
1255 int found_help = 0;
1257 if (!strcmp(argv[i], "--hu") || all)
1258 hi.usage(), found_help = 1;
1259 if (!strcmp(argv[i], "--hq") || all)
1260 hi.defaults(), found_help = 1;
1261 if (!strcmp(argv[i], "--hf") || all)
1262 hi.file(), found_help = 1;
1263 if (!strcmp(argv[i], "--he") || all)
1264 hi.exclusion(), found_help = 1;
1265 if (!strcmp(argv[i], "--ha") || all)
1266 hi.alignment(), found_help = 1;
1267 if (!strcmp(argv[i], "--hr") || all)
1268 hi.rendering(), found_help = 1;
1269 if (!strcmp(argv[i], "--hx") || all)
1270 hi.exposure(), found_help = 1;
1271 if (!strcmp(argv[i], "--ht") || all)
1272 hi.tdf(), found_help = 1;
1273 if (!strcmp(argv[i], "--hl") || all)
1274 hi.filtering(), found_help = 1;
1275 if (!strcmp(argv[i], "--hd") || all)
1276 hi.device(), found_help = 1;
1277 if (!strcmp(argv[i], "--hi") || all)
1278 hi.interface(), found_help = 1;
1279 if (!strcmp(argv[i], "--hv") || all)
1280 hi.visp(), found_help = 1;
1281 if (!strcmp(argv[i], "--hc") || all)
1282 hi.cp(), found_help = 1;
1283 if (!strcmp(argv[i], "--h3") || all)
1284 hi.d3(), found_help = 1;
1285 if (!strcmp(argv[i], "--hs") || all)
1286 hi.scope(), found_help = 1;
1287 if (!strcmp(argv[i], "--hp") || all)
1288 hi.process(), found_help = 1;
1289 if (!strcmp(argv[i], "--hz") || all)
1290 hi.undocumented(), found_help = 1;
1292 if (is_help_option && !found_help)
1293 hi.usage();
1296 * Check for the end-of-options marker, a non-option argument,
1297 * or the end of arguments. In all of these cases, we exit.
1300 if (!strcmp(argv[i], "--")
1301 || strncmp(argv[i], "--", strlen("--"))
1302 || i == argc - 1)
1303 return;
1307 * Undocumented projective transformation utility
1310 if (arg_count(argc, argv, "--ptcalc") > 0) {
1311 fprintf(stderr, "\n\n*** Warning: this feature is not documented ***\n\n");
1312 printf("Enter: w h tlx tly blx bly brx bry trx try x y\n\n");
1314 double w, h, tlx, tly, blx, bly, brx, bry, trx, tr_y, x, y;
1316 printf("> ");
1318 if (scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
1319 &w, &h, &tlx, &tly, &blx, &bly, &brx, &bry, &trx, &tr_y, &x, &y) != 12) {
1321 fprintf(stderr, "Error reading input.\n");
1322 exit(1);
1325 d2::image *i = d2::new_image_ale_real((int)h, (int)w, 3);
1326 d2::transformation t = d2::transformation::gpt_identity(i, 1);
1327 d2::point q[4] = {
1328 d2::point(tly, tlx),
1329 d2::point(bly, blx),
1330 d2::point(bry, brx),
1331 d2::point(tr_y, trx)
1333 t.gpt_set(q);
1335 d2::point a(y, x), b;
1337 b = t.transform_scaled(a);
1339 printf("TRANSFORM t(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1341 b = t.scaled_inverse_transform(a);
1343 printf("INVERSE t^-1(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1345 exit(0);
1349 * Thread initialization.
1352 thread::init();
1355 * Flags and variables
1358 double scale_factor = 1;
1359 double vise_scale_factor = 1;
1360 #if 0
1361 double usm_multiplier = 0.0;
1362 #endif
1363 int extend = 0;
1364 struct d2::tload_t *tload = NULL;
1365 struct d2::tsave_t *tsave = NULL;
1366 struct d3::tload_t *d3_tload = NULL;
1367 struct d3::tsave_t *d3_tsave = NULL;
1368 int ip_iterations = 0;
1369 int ip_use_median = 0;
1370 double ipwl = 0;
1371 enum { psf_linear, psf_nonlinear, psf_N };
1372 const char *psf[psf_N] = {NULL, NULL};
1373 const char *device = NULL;
1374 int psf_match = 0;
1375 double psf_match_args[6];
1376 int inc = 0;
1377 int exposure_register = 1;
1378 const char *wm_filename = NULL;
1379 int wm_offsetx = 0, wm_offsety = 0;
1380 double cx_parameter = 1;
1381 double *d3px_parameters = NULL;
1382 int d3px_count = 0;
1383 d2::exclusion *ex_parameters = NULL;
1384 int ex_count = 0;
1385 int ex_show = 0;
1386 d2::render *achain;
1387 const char *achain_type = "triangle:2";
1388 const char *afilter_type = "internal";
1389 d2::render **ochain = NULL;
1390 const char **ochain_names = NULL;
1391 const char **ochain_types = NULL;
1392 const char *d3chain_type = NULL;
1393 int oc_count = 0;
1394 const char **visp = NULL;
1395 int vise_count = 0;
1396 const char **d3_output = NULL;
1397 const char **d3_depth = NULL;
1398 unsigned int d3_count = 0;
1399 double user_view_angle = 0;
1400 int user_bayer = IMAGE_BAYER_DEFAULT;
1401 d2::pixel exp_mult = d2::pixel(1, 1, 1);
1402 std::map<const char *, d3::pt> d3_output_pt;
1403 std::map<const char *, d3::pt> d3_depth_pt;
1406 * dchain is ochain[0].
1409 ochain = (d2::render **) local_realloc(ochain,
1410 (oc_count + 1) * sizeof(d2::render *));
1411 ochain_names = (const char **) local_realloc((void *)ochain_names,
1412 (oc_count + 1) * sizeof(const char *));
1413 ochain_types = (const char **) local_realloc((void *)ochain_types,
1414 (oc_count + 1) * sizeof(const char *));
1416 ochain_types[0] = "sinc*lanc:8";
1418 oc_count = 1;
1421 * Handle default settings
1424 if (arg_prefix_count(argc, argv, "--q") > 0)
1425 ui::get()->error("Default settings --q* are no longer recognized.");
1427 #define FIXED16 4
1428 #if ALE_COLORS == FIXED16
1429 const char *defaults =
1430 "--dchain auto:triangle:2,fine:box:1,triangle:2 "
1431 "--achain triangle:2 "
1432 "--ips 0 "
1433 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ";
1434 #else
1435 const char *defaults =
1436 "--dchain auto:triangle:2,fine:box:1,triangle:2 "
1437 "--achain triangle:2 "
1438 "--ips 1 "
1439 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ";
1440 #endif
1441 #undef FIXED16
1443 token_reader *default_reader = new cstring_token_reader(defaults);
1445 evaluate_stream(default_reader, NULL);
1448 * Set basic program information in the environment.
1451 environment::top()->set_with_dup("---package", package);
1452 environment::top()->set_with_dup("---short-version", short_version);
1453 environment::top()->set_with_dup("---version", version);
1454 environment::top()->set_with_dup("---invocation", argv[0]);
1457 * Initialize the top-level token-reader and generate
1458 * an environment variable for it.
1461 token_reader *tr = new cli_token_reader(argc - 1, argv + 1);
1462 environment::top()->set_ptr("---token-reader", tr);
1465 * Evaluate the command-line arguments to generate environment
1466 * structures.
1469 std::vector<std::pair<const char *, environment *> > files;
1471 evaluate_stream(tr, &files);
1474 * If there are fewer than two files, then output usage information.
1477 if (files.size() < 2) {
1478 hi.usage();
1479 exit(1);
1483 * Extract the global environment and check non-globals
1484 * against a list of supported non-global options.
1487 genv = files[0].second->clone();
1489 remove_nonglobals(genv);
1491 for (unsigned int i = 0; i < files.size(); i++) {
1492 option_intersect(genv, files[i].second);
1495 for (unsigned int i = 0; i < files.size(); i++) {
1496 option_difference(files[i].second, genv);
1498 for (std::map<const char *, const char *>::iterator j = files[i].second->get_map().begin();
1499 j != files[i].second->get_map().end(); j++) {
1501 environment *env = files[i].second;
1503 if (!env->is_option(j->first))
1504 continue;
1506 const char *option_name = env->get_option_name(j->first);
1508 if (!table_contains(supported_nonglobal_option_table, option_name)) {
1509 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
1510 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
1511 option_name);
1512 exit(1);
1518 * Iterate through the global environment,
1519 * looking for options.
1522 for (std::map<const char *, const char *>::iterator i = genv->get_map().begin();
1523 i != genv->get_map().end(); i++) {
1525 environment *env = genv;
1527 if (!env->is_option(i->first))
1528 continue;
1530 const char *option_name = env->get_option_name(i->first);
1532 if (!strcmp(option_name, "default")) {
1534 * Do nothing. Defaults have already been set.
1536 } else if (!strcmp(option_name, "bpc")) {
1537 if (!strcmp(env->get_string_arg(i->first, 0), "8bpc"))
1538 d2::image_rw::depth8();
1539 else if (!strcmp(env->get_string_arg(i->first, 0), "16bpc"))
1540 d2::image_rw::depth16();
1541 else
1542 assert(0);
1543 } else if (!strcmp(option_name, "format")) {
1544 if (!strcmp(env->get_string_arg(i->first, 0), "plain"))
1545 d2::image_rw::ppm_plain();
1546 else if (!strcmp(env->get_string_arg(i->first, 0), "raw"))
1547 d2::image_rw::ppm_raw();
1548 else if (!strcmp(env->get_string_arg(i->first, 0), "auto"))
1549 d2::image_rw::ppm_auto();
1550 else
1551 assert(0);
1552 } else if (!strcmp(option_name, "align")) {
1553 if (!strcmp(env->get_string_arg(i->first, 0), "align-all"))
1554 d2::align::all();
1555 else if (!strcmp(env->get_string_arg(i->first, 0), "align-green"))
1556 d2::align::green();
1557 else if (!strcmp(env->get_string_arg(i->first, 0), "align-sum"))
1558 d2::align::sum();
1559 else
1560 assert(0);
1561 } else if (!strcmp(option_name, "transformation")) {
1562 if (!strcmp(env->get_string_arg(i->first, 0), "translation"))
1563 d2::align::class_translation();
1564 else if (!strcmp(env->get_string_arg(i->first, 0), "euclidean"))
1565 d2::align::class_euclidean();
1566 else if (!strcmp(env->get_string_arg(i->first, 0), "projective"))
1567 d2::align::class_projective();
1568 else
1569 assert(0);
1570 } else if (!strcmp(option_name, "transformation-default")) {
1571 if (!strcmp(env->get_string_arg(i->first, 0), "identity"))
1572 d2::align::initial_default_identity();
1573 else if (!strcmp(env->get_string_arg(i->first, 0), "follow"))
1574 d2::align::initial_default_follow();
1575 else
1576 assert(0);
1577 } else if (!strcmp(option_name, "perturb")) {
1578 if (!strcmp(env->get_string_arg(i->first, 0), "perturb-output"))
1579 d2::align::perturb_output();
1580 else if (!strcmp(env->get_string_arg(i->first, 0), "perturb-source"))
1581 d2::align::perturb_source();
1582 else
1583 assert(0);
1584 } else if (!strcmp(option_name, "fail")) {
1585 if (!strcmp(env->get_string_arg(i->first, 0), "fail-optimal"))
1586 d2::align::fail_optimal();
1587 else if (!strcmp(env->get_string_arg(i->first, 0), "fail-default"))
1588 d2::align::fail_default();
1589 else
1590 assert(0);
1591 } else if (!strcmp(option_name, "profile")) {
1592 ui::set_profile();
1593 } else if (!strcmp(option_name, "extend")) {
1594 if (env->get_int_arg(i->first, 0))
1595 extend = 1;
1596 else
1597 extend = 0;
1598 } else if (!strcmp(option_name, "oc")) {
1599 if (env->get_int_arg(i->first, 0))
1600 d3::scene::oc();
1601 else
1602 d3::scene::no_oc();
1603 } else if (!strcmp(option_name, "focus")) {
1605 double one = +1;
1606 double zero = +0;
1607 double inf = one / zero;
1609 assert (isinf(inf) && inf > 0);
1612 * Focus type
1615 unsigned int type = 0;
1616 double distance = 0;
1617 double px = 0, py = 0;
1619 if (!strcmp(env->get_string_arg(i->first, 1), "d")) {
1621 type = 0;
1623 distance = env->get_double_arg(i->first, 2);
1625 } else if (!strcmp(env->get_string_arg(i->first, 1), "p")) {
1627 type = 1;
1629 px = env->get_double_arg(i->first, 2);
1630 py = env->get_double_arg(i->first, 3);
1632 } else {
1633 bad_arg(option_name);
1637 * Options
1640 unsigned int ci = 0;
1641 double fr = 0;
1642 double ht = 0;
1643 double vt = 0;
1644 double sd = 0;
1645 double ed = inf;
1646 double sx = -inf;
1647 double ex = inf;
1648 double sy = -inf;
1649 double ey = inf;
1650 double ap = 3;
1651 unsigned int sc = 3;
1652 unsigned int fs = 0;
1653 unsigned int sr = 0;
1655 for (int arg_num = 4; env->is_arg(i->first, arg_num); arg_num++) {
1656 const char *option = env->get_string_arg(i->first, arg_num);
1657 if (!strncmp(option, "ci=", 3)) {
1658 if(sscanf(option + 3, "%u", &ci) != 1)
1659 bad_arg("--focus");
1660 } else if (!strncmp(option, "fr=", 3)) {
1661 if(sscanf(option + 3, "%lf", &fr) != 1)
1662 bad_arg("--focus");
1663 } else if (!strncmp(option, "ht=", 3)) {
1664 if(sscanf(option + 3, "%lf", &ht) != 1)
1665 bad_arg("--focus");
1666 } else if (!strncmp(option, "vt=", 3)) {
1667 if(sscanf(option + 3, "%lf", &vt) != 1)
1668 bad_arg("--focus");
1669 } else if (!strncmp(option, "sy=", 3)) {
1670 if(sscanf(option + 3, "%lf", &sy) != 1)
1671 bad_arg("--focus");
1672 } else if (!strncmp(option, "ey=", 3)) {
1673 if(sscanf(option + 3, "%lf", &ey) != 1)
1674 bad_arg("--focus");
1675 } else if (!strncmp(option, "sx=", 3)) {
1676 if(sscanf(option + 3, "%lf", &sx) != 1)
1677 bad_arg("--focus");
1678 } else if (!strncmp(option, "ex=", 3)) {
1679 if(sscanf(option + 3, "%lf", &ex) != 1)
1680 bad_arg("--focus");
1681 } else if (!strncmp(option, "sd=", 3)) {
1682 if(sscanf(option + 3, "%lf", &sd) != 1)
1683 bad_arg("--focus");
1684 } else if (!strncmp(option, "ed=", 3)) {
1685 if(sscanf(option + 3, "%lf", &ed) != 1)
1686 bad_arg("--focus");
1687 } else if (!strncmp(option, "ap=", 3)) {
1688 if(sscanf(option + 3, "%lf", &ap) != 1)
1689 bad_arg("--focus");
1690 } else if (!strncmp(option, "sc=", 3)) {
1691 if(sscanf(option + 3, "%u", &sc) != 1)
1692 bad_arg("--focus");
1693 } else if (!strncmp(option, "sr=", 3)) {
1694 if (!strcmp(option, "sr=aperture")) {
1695 sr = 0;
1696 } else if (!strcmp(option, "sr=pixel")) {
1697 sr = 1;
1698 } else
1699 bad_arg("--focus");
1701 } else if (!strncmp(option, "fs=", 3)) {
1702 if (!strcmp(option, "fs=mean")) {
1703 fs = 0;
1704 } else if (!strcmp(option, "fs=median")) {
1705 fs = 1;
1706 } else
1707 bad_arg("--focus");
1708 } else
1709 bad_arg("--focus");
1712 d3::focus::add_region(type, distance, px, py, ci, fr, ht, vt, sd, ed, sx, ex, sy, ey, ap, sc, fs, sr);
1714 } else if (!strcmp(option_name, "3ddp") || !strcmp(option_name, "3dvp")) {
1715 d2::align::keep();
1718 * Unsupported configurations
1721 if (ip_iterations)
1722 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1724 #if 0
1725 if (usm_multiplier)
1726 unsupported::fornow("3D modeling with unsharp mask");
1727 #endif
1730 * Initialize if necessary
1732 * Note: because their existence is checked as an
1733 * indicator of the presence of 3D arguments, we
1734 * initialize these structures here.
1737 if (d3_output == NULL) {
1738 d3_count = argc;
1739 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1740 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1743 unsigned int width, height;
1744 double view_angle;
1745 double x, y, z;
1746 double P, Y, R;
1748 width = env->get_unsigned_arg(i->first, 1);
1749 height = env->get_unsigned_arg(i->first, 2);
1750 view_angle = env->get_double_arg(i->first, 3);
1751 x = env->get_double_arg(i->first, 4);
1752 y = env->get_double_arg(i->first, 5);
1753 z = env->get_double_arg(i->first, 6);
1754 P = env->get_double_arg(i->first, 7);
1755 Y = env->get_double_arg(i->first, 8);
1756 R = env->get_double_arg(i->first, 9);
1758 view_angle *= M_PI / 180;
1759 P *= M_PI / 180;
1760 Y *= M_PI / 180;
1761 R *= M_PI / 180;
1763 d2::transformation t =
1764 d2::transformation::eu_identity();
1765 t.set_domain(height, width);
1766 d3::pt _pt(t, d3::et(y, x, z, Y, P, R), view_angle);
1768 if (!strcmp(option_name, "3dvp")) {
1769 d3_output_pt[env->get_string_arg(i->first, 10)] = _pt;
1770 } else if (!strcmp(option_name, "3ddp")) {
1771 d3_depth_pt[env->get_string_arg(i->first, 10)] = _pt;
1772 } else {
1773 assert(0);
1775 } else if (!strcmp(option_name, "3dv")) {
1776 d2::align::keep();
1778 unsigned int frame_no;
1781 * Unsupported configurations
1784 if (ip_iterations)
1785 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1787 #if 0
1788 if (usm_multiplier)
1789 unsupported::fornow("3D modeling with unsharp mask");
1790 #endif
1793 * Initialize if necessary
1796 if (d3_output == NULL) {
1797 d3_count = argc;
1798 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1799 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1802 frame_no = env->get_int_arg(i->first, 1);
1804 if (frame_no >= d3_count)
1805 ui::get()->error("--3dv argument 0 is too large");
1807 if (d3_output[frame_no] != NULL) {
1808 unsupported::fornow ("Writing a single 3D view to more than one output file");
1811 d3_output[frame_no] = env->get_string_arg(i->first, 2);
1813 } else if (!strcmp(option_name, "3dd")) {
1814 d2::align::keep();
1816 unsigned int frame_no;
1819 * Unsupported configurations
1822 if (ip_iterations)
1823 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1825 #if 0
1826 if (usm_multiplier)
1827 unsupported::fornow("3D modeling with unsharp mask");
1828 #endif
1831 * Initialize if necessary
1834 if (d3_output == NULL) {
1835 d3_count = argc;
1836 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1837 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1840 frame_no = env->get_int_arg(i->first, 1);
1842 if (frame_no >= d3_count)
1843 ui::get()->error("--3dd argument 0 is too large");
1845 if (d3_depth[frame_no] != NULL) {
1846 unsupported::fornow ("Writing a single frame's depth info to more than one output file");
1849 d3_depth[frame_no] = env->get_string_arg(i->first, 2);
1851 } else if (!strcmp(option_name, "view-angle")) {
1852 user_view_angle = env->get_double_arg(i->first, 1) * M_PI / 180;
1853 } else if (!strcmp(option_name, "cpf-load")) {
1854 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
1855 } else if (!strcmp(option_name, "ui")) {
1856 if (!strcmp(env->get_string_arg(i->first, 1), "stream"))
1857 ui::set_stream();
1858 else if (!strcmp(env->get_string_arg(i->first, 1), "tty"))
1859 ui::set_tty();
1860 else if (!strcmp(env->get_string_arg(i->first, 1), "log"))
1861 ui::set_log();
1862 else if (!strcmp(env->get_string_arg(i->first, 1), "quiet"))
1863 ui::set_quiet();
1864 else {
1865 fprintf(stderr, "Error: Unknown user interface type '%s'\n",
1866 env->get_string_arg(i->first, 1));
1867 exit(1);
1869 } else if (!strcmp(option_name, "3d-fmr")) {
1870 d3::scene::fmr(env->get_double_arg(i->first, 1));
1871 } else if (!strcmp(option_name, "3d-dmr")) {
1872 d3::scene::dmr(env->get_double_arg(i->first, 1));
1873 } else if (!strcmp(option_name, "et")) {
1874 d3::scene::et(env->get_double_arg(i->first, 1));
1875 } else if (!strcmp(option_name, "st")) {
1876 d3::cpf::st(env->get_double_arg(i->first, 1));
1877 } else if (!strcmp(option_name, "di-lower")) {
1878 d3::scene::di_lower(env->get_double_arg(i->first, 1));
1879 } else if (!strcmp(option_name, "rc")) {
1880 d3::scene::rc(env->get_double_arg(i->first, 1));
1881 } else if (!strcmp(option_name, "do-try")) {
1882 d3::scene::do_try(env->get_double_arg(i->first, 1));
1883 } else if (!strcmp(option_name, "di-upper")) {
1884 d3::scene::di_upper(env->get_double_arg(i->first, 1));
1885 } else if (!strcmp(option_name, "fc")) {
1886 d3::scene::fc(env->get_double_arg(i->first, 1));
1887 } else if (!strcmp(option_name, "ecm")) {
1888 unsupported::discontinued("--ecm <x>");
1889 } else if (!strcmp(option_name, "acm")) {
1890 unsupported::discontinued("--acm <x>");
1891 } else if (!strcmp(option_name, "def-nn")) {
1892 d2::image_rw::def_nn(env->get_double_arg(i->first, 1));
1894 if (env->get_double_arg(i->first, 1) > 2) {
1895 fprintf(stderr, "\n\n*** Warning: --def-nn implementation is currently "
1896 "inefficient for large radii. ***\n\n");
1899 } else if (!strcmp(option_name, "fx")) {
1900 d3::scene::fx(env->get_double_arg(i->first, 1));
1901 } else if (!strcmp(option_name, "tcem")) {
1902 d3::scene::tcem(env->get_double_arg(i->first, 1));
1903 } else if (!strcmp(option_name, "oui")) {
1904 d3::scene::oui(env->get_unsigned_arg(i->first, 1));
1905 } else if (!strcmp(option_name, "pa")) {
1906 d3::scene::pa(env->get_unsigned_arg(i->first, 1));
1907 } else if (!strcmp(option_name, "pc")) {
1908 d3::scene::pc(env->get_string_arg(i->first, 1));
1909 } else if (!strcmp(option_name, "cw")) {
1910 d2::align::certainty_weighted(env->get_unsigned_arg(i->first, 0));
1911 } else if (!strcmp(option_name, "wm")) {
1912 if (wm_filename != NULL)
1913 ui::get()->error("only one weight map can be specified");
1915 wm_filename = env->get_string_arg(i->first, 1);
1916 wm_offsetx = env->get_int_arg(i->first, 2);
1917 wm_offsety = env->get_int_arg(i->first, 3);
1919 } else if (!strcmp(option_name, "fl")) {
1920 #ifdef USE_FFTW
1921 d2::align::set_frequency_cut(env->get_double_arg(i->first, 1),
1922 env->get_double_arg(i->first, 2),
1923 env->get_double_arg(i->first, 3));
1925 #else
1926 ui::get()->error_hint("--fl is not supported", "rebuild ALE with FFTW support");
1927 #endif
1928 } else if (!strcmp(option_name, "wmx")) {
1929 #ifdef USE_UNIX
1930 d2::align::set_wmx(env->get_string_arg(i->first, 1),
1931 env->get_string_arg(i->first, 2),
1932 env->get_string_arg(i->first, 3));
1933 #else
1934 ui::get()->error_hint("--wmx is not supported", "rebuild ALE with support for --wmx");
1935 #endif
1936 } else if (!strcmp(option_name, "flshow")) {
1937 d2::align::set_fl_show(env->get_string_arg(i->first, 1));
1938 } else if (!strcmp(option_name, "3dpx")) {
1940 d3px_parameters = (double *) local_realloc(d3px_parameters, (d3px_count + 1) * 6 * sizeof(double));
1942 for (int param = 0; param < 6; param++)
1943 d3px_parameters[6 * d3px_count + param] = env->get_double_arg(i->first, param + 1);
1946 * Swap x and y, since their internal meanings differ from their external meanings.
1949 for (int param = 0; param < 2; param++) {
1950 double temp = d3px_parameters[6 * d3px_count + 2 + param];
1951 d3px_parameters[6 * d3px_count + 2 + param] = d3px_parameters[6 * d3px_count + 0 + param];
1952 d3px_parameters[6 * d3px_count + 0 + param] = temp;
1957 * Increment counters
1960 d3px_count++;
1962 } else if (!strcmp(option_name, "ex") || !strcmp(option_name, "fex")) {
1964 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
1965 (ex_count + 1) * sizeof(d2::exclusion));
1967 ex_parameters[ex_count].type = (!strcmp(option_name, "ex"))
1968 ? d2::exclusion::RENDER
1969 : d2::exclusion::FRAME;
1972 * Get parameters, swapping x and y coordinates
1975 ex_parameters[ex_count].x[0] = env->get_int_arg(i->first, 1 + 2);
1976 ex_parameters[ex_count].x[1] = env->get_int_arg(i->first, 1 + 3);
1977 ex_parameters[ex_count].x[2] = env->get_int_arg(i->first, 1 + 0);
1978 ex_parameters[ex_count].x[3] = env->get_int_arg(i->first, 1 + 1);
1979 ex_parameters[ex_count].x[4] = env->get_int_arg(i->first, 1 + 4);
1980 ex_parameters[ex_count].x[5] = env->get_int_arg(i->first, 1 + 5);
1983 * Increment counters
1986 ex_count++;
1988 } else if (!strcmp(option_name, "crop") || !strcmp(option_name, "fcrop")) {
1990 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
1991 (ex_count + 4) * sizeof(d2::exclusion));
1993 for (int r = 0; r < 4; r++)
1994 ex_parameters[ex_count + r].type = (!strcmp(option_name, "crop"))
1995 ? d2::exclusion::RENDER
1996 : d2::exclusion::FRAME;
1999 int crop_args[6];
2001 for (int param = 0; param < 6; param++)
2002 crop_args[param] = env->get_int_arg(i->first, param + 1);
2005 * Construct exclusion regions from the crop area,
2006 * swapping x and y, since their internal meanings
2007 * differ from their external meanings.
2011 * Exclusion region 1: low x
2014 ex_parameters[ex_count + 0].x[0] = INT_MIN;
2015 ex_parameters[ex_count + 0].x[1] = crop_args[2] - 1;
2016 ex_parameters[ex_count + 0].x[2] = INT_MIN;
2017 ex_parameters[ex_count + 0].x[3] = INT_MAX;
2018 ex_parameters[ex_count + 0].x[4] = crop_args[4];
2019 ex_parameters[ex_count + 0].x[5] = crop_args[5];
2022 * Exclusion region 2: low y
2025 ex_parameters[ex_count + 1].x[0] = INT_MIN;
2026 ex_parameters[ex_count + 1].x[1] = INT_MAX;
2027 ex_parameters[ex_count + 1].x[2] = INT_MIN;
2028 ex_parameters[ex_count + 1].x[3] = crop_args[0] - 1;
2029 ex_parameters[ex_count + 1].x[4] = crop_args[4];
2030 ex_parameters[ex_count + 1].x[5] = crop_args[5];
2033 * Exclusion region 3: high y
2036 ex_parameters[ex_count + 2].x[0] = INT_MIN;
2037 ex_parameters[ex_count + 2].x[1] = INT_MAX;
2038 ex_parameters[ex_count + 2].x[2] = crop_args[1] + 1;
2039 ex_parameters[ex_count + 2].x[3] = INT_MAX;
2040 ex_parameters[ex_count + 2].x[4] = crop_args[4];
2041 ex_parameters[ex_count + 2].x[5] = crop_args[5];
2044 * Exclusion region 4: high x
2047 ex_parameters[ex_count + 3].x[0] = crop_args[3] + 1;
2048 ex_parameters[ex_count + 3].x[1] = INT_MAX;
2049 ex_parameters[ex_count + 3].x[2] = INT_MIN;
2050 ex_parameters[ex_count + 3].x[3] = INT_MAX;
2051 ex_parameters[ex_count + 3].x[4] = crop_args[4];
2052 ex_parameters[ex_count + 3].x[5] = crop_args[5];
2055 * Increment counters
2058 ex_count += 4;
2060 } else if (!strcmp(option_name, "exshow")) {
2061 ex_show = 1;
2062 } else if (!strcmp(option_name, "wt")) {
2063 d2::render::set_wt(env->get_double_arg(i->first, 1));
2064 } else if (!strcmp(option_name, "3d-chain")) {
2065 d3chain_type = env->get_string_arg(i->first, 1);
2066 } else if (!strcmp(option_name, "dchain")) {
2067 ochain_types[0] = env->get_string_arg(i->first, 1);
2068 } else if (!strcmp(option_name, "achain")) {
2069 achain_type = env->get_string_arg(i->first, 1);
2070 } else if (!strcmp(option_name, "afilter")) {
2071 afilter_type = env->get_string_arg(i->first, 1);
2072 } else if (!strcmp(option_name, "ochain")) {
2074 ochain = (d2::render **) local_realloc(ochain,
2075 (oc_count + 1) * sizeof(d2::render *));
2076 ochain_names = (const char **) local_realloc((void *)ochain_names,
2077 (oc_count + 1) * sizeof(const char *));
2078 ochain_types = (const char **) local_realloc((void *)ochain_types,
2079 (oc_count + 1) * sizeof(const char *));
2081 ochain_types[oc_count] = env->get_string_arg(i->first, 1);
2082 ochain_names[oc_count] = env->get_string_arg(i->first, 2);
2084 oc_count++;
2086 } else if (!strcmp(option_name, "visp")) {
2088 visp = (const char **) local_realloc((void *)visp, 4 *
2089 (vise_count + 1) * sizeof(const char *));
2091 for (int param = 0; param < 4; param++)
2092 visp[vise_count * 4 + param] = env->get_string_arg(i->first, param + 1);
2094 vise_count++;
2096 } else if (!strcmp(option_name, "cx")) {
2097 cx_parameter = env->get_int_arg(i->first, 0) ? env->get_double_arg(i->first, 1) : 0;
2098 } else if (!strcmp(option_name, "ip")) {
2099 unsupported::discontinued("--ip <r> <i>", "--lpsf box=<r> --ips <i>");
2100 } else if (!strcmp(option_name, "cache")) {
2101 double cache = env->get_double_arg(i->first, 1);
2103 d2::image_rw::set_cache(cache);
2105 } else if (!strcmp(option_name, "resident")) {
2106 double resident = env->get_double_arg(i->first, 1);
2108 d2::image::set_resident(resident);
2110 } else if (!strcmp(option_name, "bayer")) {
2113 * External order is clockwise from top-left. Internal
2114 * order is counter-clockwise from top-left.
2117 const char *option = env->get_string_arg(i->first, 1);
2119 if (!strcmp(option, "rgbg")) {
2120 user_bayer = IMAGE_BAYER_RGBG;
2121 } else if (!strcmp(option, "bgrg")) {
2122 user_bayer = IMAGE_BAYER_BGRG;
2123 } else if (!strcmp(option, "gbgr")) {
2124 user_bayer = IMAGE_BAYER_GRGB;
2125 } else if (!strcmp(option, "grgb")) {
2126 user_bayer = IMAGE_BAYER_GBGR;
2127 } else if (!strcmp(option, "none")) {
2128 user_bayer = IMAGE_BAYER_NONE;
2129 } else {
2130 bad_arg("--bayer");
2133 } else if (!strcmp(option_name, "lpsf")) {
2134 psf[psf_linear] = env->get_string_arg(i->first, 1);
2135 } else if (!strcmp(option_name, "nlpsf")) {
2136 psf[psf_nonlinear] = env->get_string_arg(i->first, 1);
2137 } else if (!strcmp(option_name, "psf-match")) {
2139 psf_match = 1;
2141 for (int index = 0; index < 6; index++) {
2142 psf_match_args[index] = env->get_double_arg(i->first, index + 1);
2145 } else if (!strcmp(option_name, "device")) {
2146 device = env->get_string_arg(i->first, 1);
2147 #if 0
2148 } else if (!strcmp(option_name, "usm")) {
2150 if (d3_output != NULL)
2151 unsupported::fornow("3D modeling with unsharp mask");
2153 usm_multiplier = env->get_double_arg(i->first, 1);
2154 #endif
2156 } else if (!strcmp(option_name, "ipr")) {
2158 ip_iterations = env->get_int_arg(i->first, 1);
2160 ui::get()->warn("--ipr is deprecated. Use --ips instead");
2162 } else if (!strcmp(option_name, "cpp-err")) {
2163 if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2164 d3::cpf::err_median();
2165 else if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2166 d3::cpf::err_mean();
2167 } else if (!strcmp(option_name, "vp-adjust")) {
2168 if (env->get_int_arg(i->first, 0))
2169 d3::align::vp_adjust();
2170 else
2171 d3::align::vp_noadjust();
2172 } else if (!strcmp(option_name, "vo-adjust")) {
2173 if (env->get_int_arg(i->first, 0))
2174 d3::align::vo_adjust();
2175 else
2176 d3::align::vo_noadjust();
2177 } else if (!strcmp(option_name, "ip-statistic")) {
2178 if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2179 ip_use_median = 0;
2180 else if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2181 ip_use_median = 1;
2182 } else if (!strcmp(option_name, "ips")) {
2183 ip_iterations = env->get_int_arg(i->first, 1);
2184 } else if (!strcmp(option_name, "ip-wl")) {
2185 int limited = env->get_int_arg(i->first, 0);
2186 if (limited) {
2187 ipwl = env->get_double_arg(i->first, 1);
2188 } else {
2189 ipwl = 0;
2191 } else if (!strcmp(option_name, "ipc")) {
2192 unsupported::discontinued("--ipc <c> <i>", "--ips <i> --lpsf <c>", "--ips <i> --device <c>");
2193 } else if (!strcmp(option_name, "exp-extend")) {
2194 if (env->get_int_arg(i->first, 0))
2195 d2::image_rw::exp_scale();
2196 else
2197 d2::image_rw::exp_noscale();
2198 } else if (!strcmp(option_name, "exp-register")) {
2199 if (env->get_int_arg(i->first, 0) == 1) {
2200 exposure_register = 1;
2201 d2::align::exp_register();
2202 } else if (env->get_int_arg(i->first, 0) == 0) {
2203 exposure_register = 0;
2204 d2::align::exp_noregister();
2205 } else if (env->get_int_arg(i->first, 0) == 2) {
2206 exposure_register = 2;
2207 d2::align::exp_meta_only();
2209 } else if (!strcmp(option_name, "drizzle-only")) {
2210 unsupported::discontinued("--drizzle-only", "--dchain box:1");
2211 } else if (!strcmp(option_name, "subspace-traverse")) {
2212 unsupported::undocumented("--subspace-traverse");
2213 d3::scene::set_subspace_traverse();
2214 } else if (!strcmp(option_name, "3d-filter")) {
2215 if (env->get_int_arg(i->first, 0))
2216 d3::scene::filter();
2217 else
2218 d3::scene::nofilter();
2219 } else if (!strcmp(option_name, "occ-norm")) {
2220 if (env->get_int_arg(i->first, 0))
2221 d3::scene::nw();
2222 else
2223 d3::scene::no_nw();
2224 } else if (!strcmp(option_name, "inc")) {
2225 inc = env->get_int_arg(i->first, 0);
2226 } else if (!strcmp(option_name, "exp-mult")) {
2227 double exp_c, exp_r, exp_b;
2229 exp_c = env->get_double_arg(i->first, 1);
2230 exp_r = env->get_double_arg(i->first, 2);
2231 exp_b = env->get_double_arg(i->first, 3);
2233 exp_mult = d2::pixel(1/(exp_r * exp_c), 1/exp_c, 1/(exp_b * exp_c));
2235 } else if (!strcmp(option_name, "visp-scale")) {
2237 vise_scale_factor = env->get_double_arg(i->first, 1);
2239 if (vise_scale_factor <= 0.0)
2240 ui::get()->error("VISP scale must be greater than zero");
2242 if (!finite(vise_scale_factor))
2243 ui::get()->error("VISP scale must be finite");
2245 } else if (!strcmp(option_name, "scale")) {
2247 scale_factor = env->get_double_arg(i->first, 1);
2249 if (scale_factor <= 0)
2250 ui::get()->error("Scale factor must be greater than zero");
2252 if (!finite(scale_factor))
2253 ui::get()->error("Scale factor must be finite");
2255 } else if (!strcmp(option_name, "metric")) {
2256 d2::align::set_metric_exponent(env->get_double_arg(i->first, 1));
2257 } else if (!strcmp(option_name, "threshold")) {
2258 d2::align::set_match_threshold(env->get_double_arg(i->first, 1));
2259 } else if (!strcmp(option_name, "drizzle-diam")) {
2260 unsupported::discontinued("--drizzle-diam=<x>", "--dchain box:1");
2261 } else if (!strcmp(option_name, "perturb-lower")) {
2262 const char *option = env->get_string_arg(i->first, 1);
2263 double perturb_lower;
2264 int characters;
2265 sscanf(option, "%lf%n", &perturb_lower, &characters);
2266 if (perturb_lower <= 0)
2267 ui::get()->error("--perturb-lower= value is non-positive");
2269 if (*(option + characters) == '%')
2270 d2::align::set_perturb_lower(perturb_lower, 1);
2271 else
2272 d2::align::set_perturb_lower(perturb_lower, 0);
2273 } else if (!strcmp(option_name, "stepsize")) {
2274 ui::get()->warn("--stepsize is deprecated. Use --perturb-lower instead");
2275 d2::align::set_perturb_lower(env->get_double_arg(i->first, 1), 0);
2276 } else if (!strcmp(option_name, "va-upper")) {
2277 const char *option = env->get_string_arg(i->first, 1);
2278 double va_upper;
2279 int characters;
2280 sscanf(option, "%lf%n", &va_upper, &characters);
2281 if (*(option + characters) == '%')
2282 ui::get()->error("--va-upper= does not accept '%' arguments\n");
2283 else
2284 d3::cpf::set_va_upper(va_upper);
2285 } else if (!strcmp(option_name, "cpp-upper")) {
2286 const char *option = env->get_string_arg(i->first, 1);
2287 double perturb_upper;
2288 int characters;
2289 sscanf(option, "%lf%n", &perturb_upper, &characters);
2290 if (*(option + characters) == '%')
2291 ui::get()->error("--cpp-upper= does not currently accept '%' arguments\n");
2292 else
2293 d3::cpf::set_cpp_upper(perturb_upper);
2294 } else if (!strcmp(option_name, "cpp-lower")) {
2295 const char *option = env->get_string_arg(i->first, 1);
2296 double perturb_lower;
2297 int characters;
2298 sscanf(option, "%lf%n", &perturb_lower, &characters);
2299 if (*(option + characters) == '%')
2300 ui::get()->error("--cpp-lower= does not currently accept '%' arguments\n");
2301 else
2302 d3::cpf::set_cpp_lower(perturb_lower);
2303 } else if (!strcmp(option_name, "hf-enhance")) {
2304 unsupported::discontinued("--hf-enhance=<x>");
2305 } else if (!strcmp(option_name, "gs")) {
2306 d2::align::gs(env->get_string_arg(i->first, 1));
2307 } else if (!strcmp(option_name, "rot-upper")) {
2308 d2::align::set_rot_max((int) floor(env->get_double_arg(i->first, 1)));
2309 } else if (!strcmp(option_name, "bda-mult")) {
2310 d2::align::set_bda_mult(env->get_double_arg(i->first, 1));
2311 } else if (!strcmp(option_name, "bda-rate")) {
2312 d2::align::set_bda_rate(env->get_double_arg(i->first, 1));
2313 } else if (!strcmp(option_name, "lod-preferred")) {
2314 d2::align::set_lod_preferred((int) floor(env->get_double_arg(i->first, 1)));
2315 } else if (!strcmp(option_name, "min-dimension")) {
2316 d2::align::set_min_dimension((int) ceil(env->get_double_arg(i->first, 1)));
2317 } else if (!strcmp(option_name, "cpf-load")) {
2318 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
2319 #if 0
2320 } else if (!strcmp(option_name, "model-load")) {
2321 d3::scene::load_model(env->get_string_arg(i->first, 1));
2322 } else if (!strcmp(option_name, "model-save")) {
2323 d3::scene::save_model(env->get_string_arg(i->first, 1));
2324 #endif
2325 } else if (!strcmp(option_name, "trans-load")) {
2326 d2::tload_delete(tload);
2327 tload = d2::tload_new(env->get_string_arg(i->first, 1));
2328 d2::align::set_tload(tload);
2329 } else if (!strcmp(option_name, "trans-save")) {
2330 tsave_delete(tsave);
2331 tsave = d2::tsave_new(env->get_string_arg(i->first, 1));
2332 d2::align::set_tsave(tsave);
2333 } else if (!strcmp(option_name, "3d-trans-load")) {
2334 d3::tload_delete(d3_tload);
2335 d3_tload = d3::tload_new(env->get_string_arg(i->first, 1));
2336 d3::align::set_tload(d3_tload);
2337 } else if (!strcmp(option_name, "3d-trans-save")) {
2338 d3::tsave_delete(d3_tsave);
2339 d3_tsave = d3::tsave_new(env->get_string_arg(i->first, 1));
2340 d3::align::set_tsave(d3_tsave);
2341 } else {
2342 assert(0);
2347 * Apply implication logic.
2350 if (extend == 0 && vise_count != 0) {
2351 implication::changed("VISP requires increased image extents.",
2352 "Image extension is now enabled.",
2353 "--extend");
2354 extend = 1;
2357 if (psf_match && ex_count)
2358 unsupported::fornow("PSF calibration with exclusion regions.");
2361 if (d3_output != NULL && ip_iterations != 0)
2362 unsupported::fornow("3D modeling with Irani-Peleg rendering");
2364 #if 0
2365 if (extend == 0 && d3_output != NULL) {
2366 implication::changed("3D modeling requires increased image extents.",
2367 "Image extension is now enabled.",
2368 "--extend");
2369 extend = 1;
2371 #endif
2373 #if 0
2374 if (cx_parameter != 0 && !exposure_register) {
2375 implication::changed("Certainty-based rendering requires exposure registration.",
2376 "Exposure registration is now enabled.",
2377 "--exp-register");
2378 d2::align::exp_register();
2379 exposure_register = 1;
2381 #endif
2384 * Set alignment class exclusion region static variables
2387 d2::align::set_exclusion(ex_parameters, ex_count);
2390 * Initialize renderer class statics.
2393 d2::render::render_init(ex_count, ex_parameters, ex_show, extend, scale_factor);
2396 * Set confidence
2399 d2::exposure::set_confidence(cx_parameter);
2402 * Keep transformations for Irani-Peleg, psf-match, and
2403 * VISE
2406 if (ip_iterations > 0 || psf_match || vise_count > 0) {
2407 d2::align::keep();
2411 * Initialize device-specific variables
2414 // int input_file_count = argc - i - 1;
2415 int input_file_count = files.size() - 1;
2417 d2::psf *device_response[psf_N] = { NULL, NULL };
2418 d2::exposure **input_exposure = NULL;
2419 ale_pos view_angle = 43.7 * M_PI / 180;
2420 // ale_pos view_angle = 90 * M_PI / 180;
2421 input_exposure = (d2::exposure **)
2422 // malloc((argc - i - 1) * sizeof(d2::exposure *));
2423 malloc(input_file_count * sizeof(d2::exposure *));
2425 if (device != NULL) {
2426 if (!strcmp(device, "xvp610_640x480")) {
2427 device_response[psf_linear] = new xvp610_640x480::lpsf();
2428 device_response[psf_nonlinear] = new xvp610_640x480::nlpsf();
2429 for (int ii = 0; ii < input_file_count; ii++)
2430 input_exposure[ii] = new xvp610_640x480::exposure();
2431 view_angle = xvp610_640x480::view_angle();
2432 } else if (!strcmp(device, "xvp610_320x240")) {
2433 device_response[psf_linear] = new xvp610_320x240::lpsf();
2434 device_response[psf_nonlinear] = new xvp610_320x240::nlpsf();
2435 for (int ii = 0; ii < input_file_count; ii++)
2436 input_exposure[ii] = new xvp610_320x240::exposure();
2437 view_angle = xvp610_320x240::view_angle();
2438 } else if (!strcmp(device, "ov7620")) {
2439 device_response[psf_linear] = new ov7620_raw_linear::lpsf();
2440 device_response[psf_nonlinear] = NULL;
2441 for (int ii = 0; ii < input_file_count; ii++)
2442 input_exposure[ii] = new ov7620_raw_linear::exposure();
2443 d2::image_rw::set_default_bayer(IMAGE_BAYER_BGRG);
2444 } else if (!strcmp(device, "canon_300d")) {
2445 device_response[psf_linear] = new canon_300d_raw_linear::lpsf();
2446 device_response[psf_nonlinear] = NULL;
2447 for (int ii = 0; ii < input_file_count; ii++)
2448 input_exposure[ii] = new canon_300d_raw_linear::exposure();
2449 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2450 } else if (!strcmp(device, "nikon_d50")) {
2451 device_response[psf_linear] = nikon_d50::lpsf();
2452 device_response[psf_nonlinear] = nikon_d50::nlpsf();
2453 for (int ii = 0; ii < input_file_count; ii++)
2454 input_exposure[ii] = new nikon_d50::exposure();
2455 d2::image_rw::set_default_bayer( nikon_d50::bayer() );
2456 } else if (!strcmp(device, "canon_300d+85mm_1.8")) {
2457 device_response[psf_linear] = new canon_300d_raw_linear_85mm_1_8::lpsf();
2458 device_response[psf_nonlinear] = NULL;
2459 for (int ii = 0; ii < input_file_count; ii++)
2460 input_exposure[ii] = new canon_300d_raw_linear_85mm_1_8::exposure();
2461 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2462 view_angle = canon_300d_raw_linear_85mm_1_8::view_angle();
2463 } else if (!strcmp(device, "canon_300d+50mm_1.8")) {
2464 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_8::lpsf();
2465 device_response[psf_nonlinear] = NULL;
2466 for (int ii = 0; ii < input_file_count; ii++)
2467 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_8::exposure();
2468 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2469 view_angle = canon_300d_raw_linear_50mm_1_8::view_angle();
2470 } else if (!strcmp(device, "canon_300d+50mm_1.4")) {
2471 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4::lpsf();
2472 device_response[psf_nonlinear] = NULL;
2473 for (int ii = 0; ii < input_file_count; ii++)
2474 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4::exposure();
2475 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2476 view_angle = canon_300d_raw_linear_50mm_1_4::view_angle();
2477 } else if (!strcmp(device, "canon_300d+50mm_1.4@1.4")) {
2478 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4_1_4::lpsf();
2479 device_response[psf_nonlinear] = NULL;
2480 for (int ii = 0; ii < input_file_count; ii++)
2481 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4_1_4::exposure();
2482 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2483 view_angle = canon_300d_raw_linear_50mm_1_4_1_4::view_angle();
2484 } else {
2485 ui::get()->unknown_device(device);
2487 } else {
2488 for (int ii = 0; ii < input_file_count; ii++)
2489 input_exposure[ii] = new d2::exposure_default();
2493 * User-specified variables.
2496 if (user_view_angle != 0) {
2497 view_angle = user_view_angle;
2500 if (user_bayer != IMAGE_BAYER_DEFAULT) {
2501 d2::image_rw::set_default_bayer(user_bayer);
2505 * PSF-match exposure.
2507 if (psf_match) {
2508 delete input_exposure[input_file_count - 1];
2509 input_exposure[input_file_count - 1] = new d2::exposure_default();
2513 * Initialize output exposure
2516 d2::exposure *output_exposure = new d2::exposure_default();
2517 output_exposure->set_multiplier(exp_mult);
2520 * Configure the response function.
2523 d2::psf *response[2] = {NULL, NULL};
2525 for (int n = 0; n < psf_N; n++ ) {
2526 if (psf[n] != NULL) {
2528 response[n] = d2::psf_parse::get((n == psf_linear), psf[n]);
2530 } else if (device_response[n] != NULL) {
2533 * Device-specific response
2536 response[n] = device_response[n];
2538 } else {
2541 * Default point-spread function.
2544 if (n == psf_linear) {
2547 * Default lpsf is a box filter
2548 * of diameter 1.0 (radius
2549 * 0.5).
2552 response[n] = new d2::box(0.5);
2554 } else if (n == psf_nonlinear) {
2557 * nlpsf is disabled by default.
2560 response[n] = NULL;
2566 * First file argument. Print general file information as well
2567 * as information specific to this argument. Initialize image
2568 * file handler.
2571 // d2::image_rw::init(argc - i - 1, argv + i, argv[argc - 1], input_exposure, output_exposure);
2572 // ochain_names[0] = argv[argc - 1];
2574 const char **input_files = (const char **) malloc(sizeof(const char *) * input_file_count);
2575 for (int i = 0; i < input_file_count; i++) {
2576 input_files[i] = files[i].first;
2579 d2::image_rw::init(input_file_count, input_files, files[files.size() - 1].first,
2580 input_exposure, output_exposure);
2582 ochain_names[0] = files[files.size() - 1].first;
2585 * Handle control point data for alignment
2587 d2::align::set_cp_count(d3::cpf::count());
2588 for (unsigned int ii = 0; ii < d3::cpf::count(); ii++)
2589 d2::align::set_cp(ii, d3::cpf::get_2d(ii));
2592 * PSF-match bayer patterns.
2595 if (psf_match) {
2596 // d2::image_rw::set_specific_bayer(argc - i - 2, IMAGE_BAYER_NONE);
2597 d2::image_rw::set_specific_bayer(input_file_count - 1, IMAGE_BAYER_NONE);
2601 * Handle alignment weight map, if necessary
2604 if (wm_filename != NULL) {
2605 d2::image *weight_map;
2606 weight_map = d2::image_rw::read_image(wm_filename, new d2::exposure_linear());
2607 weight_map->set_offset(wm_offsety, wm_offsetx);
2608 d2::align::set_weight_map(weight_map);
2612 * Initialize alignment interpolant.
2615 if (strcmp(afilter_type, "internal"))
2616 d2::align::set_interpolant(d2::render_parse::get_SSF(afilter_type));
2619 * Initialize achain and ochain.
2622 achain = d2::render_parse::get(achain_type);
2624 for (int chain = 0; chain < oc_count; chain++)
2625 ochain[chain] = d2::render_parse::get(ochain_types[chain]);
2628 * Use merged renderings as reference images in
2629 * alignment.
2632 d2::align::set_reference(achain);
2635 * Tell the alignment class about the scale factor.
2638 d2::align::set_scale(scale_factor);
2641 * Initialize visp.
2644 d2::vise_core::set_scale(vise_scale_factor);
2646 for (int opt = 0; opt < vise_count; opt++) {
2647 d2::vise_core::add(d2::render_parse::get(visp[opt * 4 + 0]),
2648 visp[opt * 4 + 1],
2649 visp[opt * 4 + 2],
2650 visp[opt * 4 + 3]);
2654 * Initialize non-incremental renderers
2657 #if 0
2658 if (usm_multiplier != 0) {
2661 * Unsharp Mask renderer
2664 ochain[0] = new d2::usm(ochain[0], scale_factor,
2665 usm_multiplier, inc, response[psf_linear],
2666 response[psf_nonlinear], &input_exposure[0]);
2668 #endif
2670 if (psf_match) {
2673 * Point-spread function calibration renderer.
2674 * This renderer does not produce image output.
2675 * It is reserved for use with the point-spread
2676 * function calibration script
2677 * ale-psf-calibrate.
2680 ochain[0] = new d2::psf_calibrate(ochain[0],
2681 1, inc, response[psf_linear],
2682 response[psf_nonlinear],
2683 psf_match_args);
2685 } else if (ip_iterations != 0) {
2688 * Irani-Peleg renderer
2691 ochain[0] = new d2::ipc( ochain[0], ip_iterations,
2692 inc, response[psf_linear],
2693 response[psf_nonlinear],
2694 (exposure_register == 1), ip_use_median, ipwl);
2698 * Iterate through all files.
2701 for (unsigned int j = 0; j < d2::image_rw::count(); j++) {
2704 * Iterate through non-global options
2707 environment *env = files[j].second;
2709 for (std::map<const char *, const char *>::iterator i = env->get_map().begin();
2710 i != env->get_map().end(); i++) {
2712 if (!env->is_option(i->first))
2713 continue;
2715 const char *option_name = env->get_option_name(i->first);
2717 if (!strcmp(option_name, "mc")) {
2718 d2::align::mc(env->get_double_arg(i->first, 1));
2719 } else if (!strcmp(option_name, "md")) {
2720 d2::trans_multi::set_md(env->get_double_arg(i->first, 1));
2721 } else if (!strcmp(option_name, "ma-cert")) {
2722 d2::align::set_ma_cert(env->get_double_arg(i->first, 1));
2723 } else if (!strcmp(option_name, "mi")) {
2724 d2::trans_multi::set_mi(env->get_double_arg(i->first, 1));
2725 } else if (!strcmp(option_name, "gs-mo")) {
2726 const char *option = env->get_string_arg(i->first, 1);
2727 double gs_mo;
2728 int characters;
2729 sscanf(option, "%lf%n", &gs_mo, &characters);
2730 if (*(option + characters) == '%')
2731 d2::align::gs_mo(gs_mo, 1);
2732 else
2733 d2::align::gs_mo(gs_mo, 0);
2734 } else if (!strcmp(option_name, "ev")) {
2735 double ev = env->get_double_arg(i->first, 1);
2736 double gain_value = pow(2, -ev);
2738 if (j == 0)
2739 d2::exposure::set_gain_reference(gain_value);
2740 else
2741 input_exposure[j]->set_gain_multiplier(
2742 (double) d2::exposure::get_gain_reference()
2743 / gain_value);
2745 } else if (!strcmp(option_name, "black")) {
2746 double black = env->get_double_arg(i->first, 1);
2747 input_exposure[j]->set_black_level(black);
2748 } else if (!strcmp(option_name, "perturb-upper")) {
2749 const char *option = env->get_string_arg(i->first, 1);
2750 double perturb_upper;
2751 int characters;
2752 sscanf(option, "%lf%n", &perturb_upper, &characters);
2753 if (*(option + characters) == '%')
2754 d2::align::set_perturb_upper(perturb_upper, 1);
2755 else
2756 d2::align::set_perturb_upper(perturb_upper, 0);
2757 } else if (!strcmp(option_name, "threads")) {
2758 thread::set_count((unsigned int) env->get_int_arg(i->first, 1));
2759 } else if (!strcmp(option_name, "per-cpu")) {
2760 thread::set_per_cpu((unsigned int) env->get_int_arg(i->first, 1));
2761 } else {
2763 * This error should be encountered earlier.
2766 assert(0);
2768 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
2769 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
2770 option_name);
2771 exit(1);
2777 if (j == 0) {
2780 * Write comment information about original frame and
2781 * target image to the transformation save file, if we
2782 * have one.
2785 const d2::image *im = d2::image_rw::open(0);
2786 // tsave_orig(tsave, argv[i], im->avg_channel_magnitude());
2787 // tsave_target(tsave, argv[argc - 1]);
2788 tsave_orig(tsave, files[0].first, im->avg_channel_magnitude());
2789 tsave_target(tsave, files[files.size() - 1].first);
2790 d2::image_rw::close(0);
2793 * Handle the original frame.
2796 // ui::get()->original_frame_start(argv[i]);
2797 ui::get()->original_frame_start(files[0].first);
2799 for (int opt = 0; opt < oc_count; opt++) {
2800 ui::get()->set_orender_current(opt);
2801 ochain[opt]->sync(0);
2802 if (inc) {
2803 ui::get()->writing_output(opt);
2804 d2::image_rw::write_image(ochain_names[opt],
2805 ochain[opt]->get_image(0));
2809 d2::vise_core::frame_queue_add(0);
2811 ui::get()->original_frame_done();
2813 continue;
2817 * Handle supplemental frames.
2820 const char *name = d2::image_rw::name(j);
2822 ui::get()->supplemental_frame_start(name);
2825 * Write comment information about the
2826 * supplemental frame to the transformation
2827 * save file, if we have one.
2830 tsave_info (tsave, name);
2832 const d2::image *im = d2::image_rw::open(j);
2833 d2::pixel apm = im->avg_channel_magnitude();
2834 tsave_apm(tsave, apm[0], apm[1], apm[2]);
2835 d2::image_rw::close(j);
2837 for (int opt = 0; opt < oc_count; opt++) {
2838 ui::get()->set_orender_current(opt);
2839 ochain[opt]->sync(j);
2840 if (inc) {
2841 ui::get()->writing_output(opt);
2842 d2::image_rw::write_image(ochain_names[opt],
2843 ochain[opt]->get_image(j));
2847 d2::vise_core::frame_queue_add(j);
2849 ui::get()->supplemental_frame_done();
2853 * Do any post-processing and output final image
2855 * XXX: note that the Irani-Peleg renderer currently
2856 * returns zero for ochain[0]->sync(), since it writes
2857 * output internally when inc != 0.
2859 * XXX: Leave ochain[0] last, since this may allow disposal of
2860 * rendering structures not required by the Irani-Peleg
2861 * renderer.
2864 for (int opt = 1; opt < oc_count; opt++)
2865 if ((ochain[opt]->sync() || !inc) && !psf_match) {
2866 ui::get()->writing_output(opt);
2867 d2::image_rw::write_image(ochain_names[opt], ochain[opt]->get_image());
2870 if (oc_count > 0)
2871 if ((ochain[0]->sync() || !inc) && !psf_match) {
2872 ui::get()->writing_output(0);
2873 d2::image_rw::write_image(ochain_names[0], ochain[0]->get_image());
2877 * Output a summary match statistic.
2880 ui::get()->ale_2d_done((double) d2::align::match_summary());
2883 * Perform any 3D tasks
2886 optimizations::begin_3d_work();
2888 if (d3_count > 0) {
2890 ui::get()->d3_start();
2892 d3::align::init_angle(view_angle);
2894 ui::get()->d3_init_view_angle((double) view_angle / M_PI * 180);
2896 d3::align::init_from_d2();
2898 if (d3::cpf::count() > 0) {
2899 ui::get()->d3_control_point_solve();
2900 d3::cpf::solve_3d();
2901 ui::get()->d3_control_point_solve_done();
2904 ui::get()->d3_final_view_angle(d3::align::angle_of(0) / M_PI * 180);
2906 d3::align::write_alignments();
2908 d3::scene::set_filter_type(d3chain_type);
2910 d3::scene::init_from_d2();
2912 ui::get()->d3_subdividing_space();
2913 d3::scene::make_space(d3_depth, d3_output, &d3_depth_pt, &d3_output_pt);
2914 ui::get()->d3_subdividing_space_done();
2916 ui::get()->d3_updating_occupancy();
2917 d3::scene::reduce_cost_to_search_depth(output_exposure, inc);
2918 ui::get()->d3_updating_occupancy_done();
2920 d3::scene::d3px(d3px_count, d3px_parameters);
2921 int view_count = 0;
2922 for (unsigned int i = 0; i < d2::image_rw::count(); i++) {
2923 assert (i < d3_count);
2925 if (d3_depth[i] != NULL) {
2926 ui::get()->d3_writing_output(d3_depth[i]);
2927 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2928 const d2::image *im = d3::scene::depth(i);
2929 d2::image_rw::write_image(d3_depth[i], im, output_exposure, 1, 1);
2930 delete im;
2931 ui::get()->d3_writing_output_done();
2934 if (d3_output[i] != NULL) {
2935 ui::get()->d3_writing_output(d3_output[i]);
2936 const d2::image *im = d3::scene::view(i);
2937 d2::image_rw::write_image(d3_output[i], im, output_exposure);
2938 delete im;
2939 d3::focus::set_camera(view_count++);
2940 ui::get()->d3_writing_output_done();
2943 for (std::map<const char *, d3::pt>::iterator i = d3_output_pt.begin();
2944 i != d3_output_pt.end(); i++) {
2946 ui::get()->d3_writing_output(i->first);
2947 const d2::image *im = d3::scene::view(i->second);
2948 d2::image_rw::write_image(i->first, im, output_exposure);
2949 delete im;
2950 d3::focus::set_camera(view_count++);
2951 ui::get()->d3_writing_output_done();
2954 for (std::map<const char *, d3::pt>::iterator i = d3_depth_pt.begin();
2955 i != d3_depth_pt.end(); i++) {
2957 ui::get()->d3_writing_output(i->first);
2958 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2959 const d2::image *im = d3::scene::depth(i->second);
2960 d2::image_rw::write_image(i->first, im, output_exposure, 1, 1);
2961 delete im;
2962 ui::get()->d3_writing_output_done();
2966 for (unsigned int i = d2::image_rw::count(); i < d3_count; i++) {
2967 if (d3_depth[i] != NULL) {
2968 fprintf(stderr, "\n\n*** Frame number for --3dd too high. ***\n\n");
2970 if (d3_output[i] != NULL) {
2971 fprintf(stderr, "\n\n*** Frame number for --3dv too high. ***\n\n");
2977 * Destroy the image file handler
2980 d2::image_rw::destroy();
2983 * Delete the transformation file structures, if any
2984 * exist.
2987 tsave_delete(tsave);
2988 tload_delete(tload);
2991 * We're done.
2994 exit(0);
2998 #endif