Allow --gs-mo to be specified as a percentage, make 44% default, and make --gs all...
[Ale.git] / ui / input.h
blobf49e17c890abeeda20fca23f19e80cd0d27b5698
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 "string_.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"
98 #include "../device/nikon_d50.h"
101 * Help files
104 #include "help.h"
106 class input {
109 * Flag for global options.
112 static int global_options;
115 * Helper functions.
119 * Argument counter.
121 * Counts instances of a given option.
123 static unsigned int arg_count(int argc, const char *argv[], const char *arg) {
124 unsigned int count = 0;
125 for (int i = 0; i < argc; i++) {
126 if (!strcmp(argv[i], arg))
127 count++;
128 else if (!strcmp(argv[i], "--"))
129 return count;
131 return count;
135 * Argument prefix counter.
137 * Counts instances of a given option prefix.
139 static unsigned int arg_prefix_count(int argc, const char *argv[], const char *pfix) {
140 unsigned int count = 0;
141 for (int i = 0; i < argc; i++) {
142 if (!strncmp(argv[i], pfix, strlen(pfix)))
143 count++;
144 else if (!strcmp(argv[i], "--"))
145 return count;
147 return count;
151 * Reallocation function
153 static void *local_realloc(void *ptr, size_t size) {
154 void *new_ptr = realloc(ptr, size);
156 if (new_ptr == NULL)
157 ui::get()->memory_error_location("main()");
159 return new_ptr;
163 * Not enough arguments function.
165 static void not_enough(const char *opt_name) {
166 ui::get()->cli_not_enough(opt_name);
170 * Bad argument function
172 static void bad_arg(const char *opt_name) {
173 ui::get()->cli_bad_arg(opt_name);
177 * String comparison class.
180 class compare_strings {
181 public:
182 int operator()(const char *A, const char *B) const {
183 return strcmp(A, B) < 0;
188 * Environment structures.
190 * XXX: It's arguable that these should be public members of the
191 * 'input' class in order to allow passing environment values to other
192 * classes, but, since we're currently using them only to prepare state
193 * for an internal 'input' function, they can stay private for now. A
194 * more nuanced approach will likely be required later.
197 class environment {
198 static std::stack<environment *> environment_stack;
199 static std::set<environment *> environment_set;
201 std::map<const char *, const char *, compare_strings> environment_map;
204 * Internal set operations do not protect any data.
207 void internal_set(const char *name, const char *value) {
208 environment_map[name] = value;
211 void internal_unset(const char *name) {
212 environment_map.erase(name);
215 const char *internal_convert_pointer(const void *pointer) {
216 int chars = sizeof(void *) * 2 + 3;
217 char *c = (char *) malloc(sizeof(char) * chars);
219 assert(c);
221 if (!c)
222 ui::get()->memory_error_location("environment::set_ptr");
224 int count = snprintf(c, chars, "%p", pointer);
226 assert (count >= 0 && count < chars);
228 return c;
231 void internal_set_ptr(const char *name, const void *pointer) {
232 internal_set(name, internal_convert_pointer(pointer));
236 * Check for restricted names.
239 int name_ok(const char *name) {
240 if (!strcmp(name, "---chain") || !strcmp(name, "---this"))
241 return 0;
243 return 1;
246 void name_check(const char *name) {
247 if (!name_ok(name)) {
248 fprintf(stderr, "Bad set operation.");
249 assert(0);
250 exit(1);
254 public:
257 * Get the environment map.
260 std::map<const char *, const char *, compare_strings> &get_map() {
261 return environment_map;
265 * Public set operations restrict valid names.
268 void set(const char *name, const char *value) {
269 name_check(name);
270 internal_set(name, value);
273 void unset(const char *name) {
274 name_check(name);
275 internal_unset(name);
278 void set_ptr(const char *name, const void *pointer) {
279 name_check(name);
280 internal_set_ptr(name, pointer);
283 const char *get(const char *name) {
284 if (environment_map.count(name) == 0)
285 return NULL;
287 return environment_map[name];
291 * Make an environment substructure. Note that since deep
292 * structures are currently referenced rather than copied when
293 * the stack is pushed, there is no current need for any
294 * chaining mechanism.
296 void make_substructure(const char *name) {
297 environment *s = new environment;
298 set_ptr(name, s);
299 environment_set.insert(s);
302 static int is_env(const char *name) {
303 void *ptr_value;
304 sscanf(name, "%p", &ptr_value);
307 * Check for bad pointers.
310 if (!environment_set.count((environment *) ptr_value)) {
311 return 0;
314 return 1;
317 const char *get_option_name(const char *name) {
318 if (strncmp(name, "0 ", strlen("0 ")))
319 return NULL;
321 name += strlen("0 ");
323 if (!isdigit(name[0]))
324 return NULL;
326 while (isdigit(name[0]))
327 name++;
329 if (!isspace(name[0]))
330 return NULL;
332 while (isspace(name[0]))
333 name++;
335 if (!isalnum(name[0]))
336 return NULL;
338 return name;
341 int is_option(const char *name) {
342 return (get_option_name(name) != NULL);
345 int is_arg(const char *name, unsigned int arg) {
346 assert (is_option(name));
348 int length = strlen(name) + 3 * sizeof(unsigned int);
350 char *desired_string = (char *) malloc(sizeof(char) * length);
352 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
354 int result = environment_map.count(desired_string);
356 free(desired_string);
358 return result > 0;
361 void remove_arg(const char *name, unsigned int arg) {
362 assert (is_option(name));
363 assert (is_arg(name, arg));
365 int length = strlen(name) + 3 * sizeof(unsigned int);
367 char *desired_string = (char *) malloc(sizeof(char) * length);
369 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
371 environment_map.erase(desired_string);
374 const char *get_string_arg(const char *name, unsigned int arg) {
375 assert (is_option(name));
377 int length = strlen(name) + 3 * sizeof(unsigned int);
379 char *desired_string = (char *) malloc(sizeof(char) * length);
381 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
383 const char *result = environment_map[desired_string];
385 assert (result);
387 free(desired_string);
389 return result;
392 long int get_long_arg(const char *name, unsigned int arg) {
393 assert (is_option(name));
395 const char *string = get_string_arg(name, arg);
396 char *endptr;
398 long int result = strtol(string, &endptr, 0);
400 if (endptr[0] != '\0') {
401 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
402 exit(1);
405 return result;
408 int get_int_arg(const char *name, unsigned int arg) {
409 return (int) get_long_arg(name, arg);
412 unsigned int get_unsigned_arg(const char *name, unsigned int arg) {
413 long int result = get_long_arg(name, arg);
415 if (result < 0) {
416 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
417 exit(1);
420 return (unsigned int) result;
423 double get_double_arg(const char *name, unsigned int arg) {
424 assert (is_option(name));
426 const char *string = get_string_arg(name, arg);
427 char *endptr;
429 double result = strtod(string, &endptr);
431 if (endptr[0] != '\0') {
432 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
433 exit(1);
436 return result;
439 static environment *get_env(const char *name) {
441 assert(name);
443 void *ptr_value;
444 sscanf(name, "%p", &ptr_value);
447 * Check for bad pointers.
450 if (!environment_set.count((environment *) ptr_value)) {
451 assert(0);
452 fprintf(stderr, "Bad environment pointer.\n");
453 exit(1);
456 return (environment *) ptr_value;
460 * Prepend to a list.
462 void prepend(const char *list, const char *element) {
463 environment *d = get_env(get(list));
464 make_substructure(list);
465 get_env(get(list))->set("a", element);
466 get_env(get(list))->set_ptr("d", d);
469 void prepend_ptr(const char *list, void *ptr) {
470 prepend(list, internal_convert_pointer(ptr));
474 * Clone the environment.
476 environment *clone() {
477 environment *e = new environment();
479 for (std::map<const char *, const char *, compare_strings>::iterator i = environment_map.begin();
480 i != environment_map.end(); i++) {
482 if (!name_ok(i->first))
483 continue;
485 if (is_env(i->second)) {
486 e->set_ptr(i->first, get_env(i->second)->clone());
487 } else {
488 e->set(i->first, i->second);
492 return e;
495 static environment *top() {
496 if (environment_stack.empty()) {
497 environment_stack.push(new environment);
498 environment_set.insert(environment_stack.top());
500 return environment_stack.top();
503 static void push() {
504 environment *e = new environment;
506 e->environment_map = environment_stack.top()->environment_map;
508 e->internal_set_ptr("---chain", environment_stack.top());
509 e->internal_set_ptr("---this", e);
510 e->make_substructure("---dup");
512 environment_stack.push(e);
513 environment_set.insert(e);
516 static void dup_second() {
517 environment_stack.top()->prepend_ptr("---dup",
518 environment::get_env(environment_stack.top()->get("---chain")));
521 static void push_and_dup_output() {
522 push();
523 dup_second();
526 static void pop() {
527 assert(!environment_stack.empty());
530 * Execution environments should never be referenced by
531 * structures further up the call chain, so they can
532 * safely be deleted. (XXX: In particular, while
533 * lexical scoping may require copying of execution
534 * environments from lower on the call chain, there is
535 * no obvious reason that a reference should be used in
536 * this case; a shallow copy should be used instead.)
539 environment_set.erase(environment_stack.top());
540 delete environment_stack.top();
542 environment_stack.pop();
546 * Set with duplication.
549 void set_with_dup(const char *name, const char *value) {
550 set(name, value);
552 if (!get("---dup"))
553 return;
555 environment *dup_item = get_env(get("---dup"));
557 assert (dup_item);
559 while (dup_item->get("a")) {
560 get_env(dup_item->get("a"))->set_with_dup(name, value);
561 assert(dup_item->get("d"));
562 dup_item = get_env(dup_item->get("d"));
563 assert(dup_item);
569 * Read tokens from a stream.
571 class token_reader {
572 public:
574 * Get the next token
576 virtual const char *get() = 0;
579 * Peek at the next token.
582 virtual const char *peek() = 0;
585 * Divert the stream until the next occurrence of TOKEN.
587 virtual token_reader *divert(const char *open_token, const char *close_token) = 0;
589 virtual int expects_exactly_one_option(void) {
590 return 0;
593 virtual ~token_reader() {
597 class argument_parsing_token_reader : public token_reader {
598 const char *index;
599 const char *separators;
600 public:
601 argument_parsing_token_reader(const char *s) {
602 index = s;
603 separators = "=";
606 int expects_exactly_one_option(void) {
607 return 1;
610 virtual const char *get() {
611 int length = strcspn(index, separators);
613 if (length == 0)
614 return NULL;
616 const char *result = strndup(index, length);
617 index += length;
619 if (strspn(index, separators) >= 1)
620 index++;
622 separators = ",";
624 return result;
627 virtual const char *peek() {
628 int length = strcspn(index, separators);
630 if (length == 0)
631 return NULL;
633 const char *result = strndup(index, length);
635 return result;
638 virtual token_reader *divert(const char *open_token, const char *close_token) {
639 assert(0);
640 return NULL;
644 class cstring_token_reader : public token_reader {
645 const char *separators;
646 const char *string;
647 int ephemeral;
649 cstring_token_reader(const char *s, int ephemeral) {
650 assert(ephemeral == 1);
652 separators = "\n \t";
653 string = s;
654 this->ephemeral = 1;
657 public:
658 cstring_token_reader(const char *s) {
659 separators = "\n \t";
660 string = s;
661 ephemeral = 0;
664 const char *get() {
666 string += strspn(string, separators);
668 size_t length_to_next = strcspn(string, separators);
670 if (length_to_next == 0)
671 return NULL;
673 const char *result = strndup(string, length_to_next);
675 string += length_to_next;
677 return result;
680 const char *peek() {
681 string += strspn(string, separators);
683 size_t length_to_next = strcspn(string, separators);
685 if (length_to_next == 0)
686 return NULL;
688 return strndup(string, length_to_next);
691 cstring_token_reader *divert(const char *open_token, const char *close_token) {
693 * This function might be broken.
696 assert(0);
698 int search = 0;
699 int next = strcspn(string, separators);
700 int depth = 0;
702 while (*(string + search) != '\0' &&
703 (depth || strcmp(close_token, (string + search)))) {
704 if (!strcmp(close_token, (string + search)))
705 depth--;
706 if (!strcmp(open_token, (string + search)))
707 depth++;
708 search = next;
709 next = strcspn((string + next), separators);
712 if (*(string + search) == '\0') {
713 fprintf(stderr, "Parse error: End of scope not found.");
714 exit(1);
717 cstring_token_reader *result = new cstring_token_reader(strndup(string, search), 1);
719 string += search;
722 * Eat the closing token.
725 get();
727 return result;
730 ~cstring_token_reader() {
731 if (ephemeral)
732 free((void *) string);
736 class cli_token_reader : public token_reader {
738 int arg_index;
739 int argc;
740 const char **argv;
742 public:
743 cli_token_reader(int c, const char *v[]) {
744 argc = c;
745 argv = v;
746 arg_index = 0;
749 const char *get() {
751 if (arg_index < argc)
752 return argv[arg_index++];
753 else
754 return NULL;
758 const char *peek() {
760 if (arg_index < argc)
761 return argv[arg_index];
762 else
763 return NULL;
767 cli_token_reader *divert(const char *open_token, const char *close_token) {
768 int search = 0;
769 int depth = 0;
771 while (arg_index + search < argc
772 && (depth || strcmp(argv[arg_index + search], close_token))) {
773 if (!strcmp(close_token, argv[arg_index + search]))
774 depth--;
775 if (!strcmp(open_token, argv[arg_index + search]))
776 depth++;
777 search++;
780 if (arg_index + search == argc) {
781 fprintf(stderr, "Parse error: end of scope not found.\n");
782 exit(1);
785 cli_token_reader *result = new cli_token_reader(search, argv + arg_index);
787 arg_index += search;
790 * Eat the closing token.
793 get();
795 return result;
800 struct simple_option {
801 const char *name;
802 const char *map_name;
803 const char *map_value;
804 int arg_count;
805 int multi;
808 static const char *supported_nonglobal_option_table[];
809 static const char *focus_prefixes[];
810 static simple_option simple_option_table[];
812 static int option_name_match(const char *unadorned, const char *token, int require_ornamentation = 1) {
813 int strip_max = 2;
815 if (!strcmp(unadorned, token) && !require_ornamentation)
816 return 1;
818 while (token[0] == '-' && strip_max) {
819 token++;
820 strip_max--;
821 if (!strcmp(unadorned, token))
822 return 1;
825 return 0;
828 static int is_scope_operator(const char *string) {
829 if (!strcmp("{", string)
830 || !strcmp("}", string)
831 || !strcmp("[", string)
832 || !strcmp("]", string)
833 || !strcmp("<", string)
834 || !strcmp(">", string))
835 return 1;
837 return 0;
840 static const char *option_name_gen(const char *unadorned, const char *map_name, int arg_num, int multi) {
841 static unsigned int multi_counter = 0;
843 if (map_name) {
844 unadorned = map_name;
847 int length = (strlen(unadorned) + sizeof(unsigned int) * 3 + sizeof(int) * 3 + 2) + 1;
849 char *result = (char *) malloc(sizeof(char) * length);
851 assert (result);
853 if (!multi) {
854 snprintf(result, length, "%u 0 %s", arg_num, unadorned);
855 } else {
858 * XXX: This assumes that generating calls for
859 * options other than 0 exist in the same
860 * multiplicity group as the most recently
861 * generated 0-option multiplicity.
864 if (arg_num == 0)
865 multi_counter++;
867 snprintf(result, length, "%u %u %s", arg_num, multi_counter, unadorned);
870 return result;
873 static environment *genv;
875 static const char *get_next(token_reader *tr, const char *option_name) {
876 const char *argument = tr->get();
878 if (argument == NULL) {
879 fprintf(stderr, "\n\nError: not enough arguments for `%s'.\n\n", option_name);
880 exit(1);
883 return argument;
886 static int table_contains(const char **haystack, const char *needle, int prefix_length = 0) {
888 if (needle == NULL)
889 return 0;
891 while (*haystack != NULL) {
892 if (prefix_length == 0 && !strcmp(*haystack, needle))
893 return 1;
894 if (prefix_length > 0 && !strncmp(*haystack, needle, prefix_length))
895 return 1;
896 haystack++;
899 return 0;
902 static int option_is_identical(environment *a, environment *b, const char *option_name) {
903 if (!a->is_option(option_name) || !b->is_option(option_name))
904 return 0;
906 int option_number = 0;
908 while (a->is_arg(option_name, option_number) || b->is_arg(option_name, option_number)) {
909 if (!a->is_arg(option_name, option_number)
910 || !b->is_arg(option_name, option_number))
911 return 0;
913 const char *a_str = a->get_string_arg(option_name, option_number);
914 const char *b_str = b->get_string_arg(option_name, option_number);
916 if (strcmp(a_str, b_str))
917 return 0;
919 option_number++;
922 return 1;
925 static void remove_option(environment *a, const char *option_name) {
926 assert(a->is_option(option_name));
928 int option_number = 0;
930 while (a->is_arg(option_name, option_number)) {
931 a->remove_arg(option_name, option_number);
932 option_number++;
936 static void remove_nonglobals(environment *a) {
937 assert(a);
939 std::stack<const char *> removal_stack;
941 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
942 i != a->get_map().end(); i++) {
944 if (!a->is_option(i->first))
945 continue;
947 if (!table_contains(supported_nonglobal_option_table, a->get_option_name(i->first)))
948 continue;
950 removal_stack.push(i->first);
953 while (!removal_stack.empty()) {
954 remove_option(a, removal_stack.top());
955 removal_stack.pop();
959 static void option_intersect(environment *a, environment *b) {
960 assert(a);
961 assert(b);
963 std::stack<const char *> removal_stack;
965 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
966 i != a->get_map().end(); i++) {
968 if (!a->is_option(i->first))
969 continue;
971 if (option_is_identical(a, b, i->first))
972 continue;
974 removal_stack.push(i->first);
977 while (!removal_stack.empty()) {
978 remove_option(a, removal_stack.top());
979 removal_stack.pop();
983 static void option_difference(environment *a, environment *b) {
984 assert(a);
985 assert(b);
987 std::stack<const char *> removal_stack;
989 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
990 i != a->get_map().end(); i++) {
992 if (!a->is_option(i->first))
993 continue;
995 if (!option_is_identical(a, b, i->first))
996 continue;
998 removal_stack.push(i->first);
1001 while (!removal_stack.empty()) {
1002 remove_option(a, removal_stack.top());
1003 removal_stack.pop();
1007 static void evaluate_stream(token_reader *tr,
1008 std::vector<std::pair<const char *, environment *> > *files) {
1009 const char *token;
1010 int end_of_options = 0;
1012 while ((token = tr->get())) {
1015 * Check for nesting
1018 if (!strcmp(token, "{") && !end_of_options) {
1019 environment::push_and_dup_output();
1020 token_reader *tr_nest = tr->divert("{", "}");
1021 evaluate_stream(tr_nest, files);
1022 delete tr_nest;
1023 environment::pop();
1024 } else if (!strcmp(token, "[") && !end_of_options) {
1025 global_options = 0;
1026 environment::push();
1027 token_reader *tr_nest = tr->divert("[", "]");
1028 evaluate_stream(tr_nest, files);
1029 delete tr_nest;
1030 environment::pop();
1031 } else if (!strcmp(token, "<") && !end_of_options) {
1032 environment *dup_list = environment::get_env(environment::top()->get("---dup"));
1033 assert (dup_list != NULL);
1034 dup_list = dup_list->clone();
1036 environment::dup_second();
1037 token_reader *tr_nest = tr->divert("<", ">");
1038 evaluate_stream(tr_nest, files);
1039 delete tr_nest;
1041 environment::top()->set_ptr("---dup", dup_list);
1045 * Check for non-whitespace argument separators
1048 else if (!end_of_options && token && token[0] == '-' && strchr(token, '=')) {
1049 environment::push_and_dup_output();
1050 token_reader *tr_nest = new argument_parsing_token_reader(token);
1051 evaluate_stream(tr_nest, files);
1052 delete tr_nest;
1053 environment::pop();
1057 * Trap the end-of-option indicator.
1060 else if (!strcmp(token, "--")) {
1061 global_options = 0;
1062 end_of_options = 1;
1066 * Check for options and filenames
1069 else {
1071 * Handle filenames.
1074 if (strncmp("-", token, strlen("-")) || end_of_options) {
1076 assert(files);
1078 global_options = 0;
1079 files->push_back(std::pair<const char *, environment *>(strdup(token),
1080 environment::top()->clone()));
1082 if (tr->expects_exactly_one_option() && tr->get()) {
1083 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1084 exit(1);
1087 continue;
1091 * Handle focus option.
1094 if (option_name_match("focus", token)) {
1096 environment *target;
1097 target = environment::top();
1099 target->set_with_dup(option_name_gen("focus", NULL, 0, 0), "1");
1101 const char *option = get_next(tr, "focus");
1103 target->set_with_dup(option_name_gen("focus", NULL, 1, 0), option);
1105 if (!strcmp(option, "d")) {
1106 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1107 get_next(tr, "focus"));
1108 } else if (!strcmp(option, "p")) {
1109 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1110 get_next(tr, "focus"));
1111 target->set_with_dup(option_name_gen("focus", NULL, 3, 0),
1112 get_next(tr, "focus"));
1113 } else
1114 bad_arg("focus");
1116 int arg = 0;
1118 while (table_contains(focus_prefixes, tr->peek(), 3)) {
1119 target->set_with_dup(option_name_gen("focus", NULL, 4 + arg, 0),
1120 get_next(tr, "focus"));
1121 arg++;
1124 continue;
1128 * Handle simple options.
1131 int found_option = 0;
1132 for (int i = 0; simple_option_table[i].name; i++) {
1133 if (!option_name_match(simple_option_table[i].name, token))
1134 continue;
1137 * Handle the match case.
1140 found_option = 1;
1143 * Determine which environment should be modified
1146 environment *target;
1147 target = environment::top();
1150 * Store information required for
1151 * handling the local case later.
1154 const char *map_value = "1";
1156 if (simple_option_table[i].map_value) {
1157 map_value = simple_option_table[i].map_value;
1158 } else if (simple_option_table[i].map_name) {
1159 map_value = simple_option_table[i].name;
1162 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1163 simple_option_table[i].map_name,
1165 simple_option_table[i].multi),
1166 map_value);
1168 for (int j = 0; j < simple_option_table[i].arg_count; j++) {
1169 const char *option = tr->get();
1171 if (option == NULL) {
1172 fprintf(stderr, "\n\nError: not enough options for `%s'.\n\n", token);
1173 exit(1);
1177 * Reject scope operators as options,
1178 * at least for now.
1181 if (is_scope_operator(option)) {
1182 fprintf(stderr, "\n\nError: illegal argument to `%s'.\n\n", token);
1183 exit(1);
1186 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1187 simple_option_table[i].map_name,
1188 j + 1,
1189 simple_option_table[i].multi),
1190 option);
1195 * Trap illegal options.
1198 if (!found_option)
1199 ui::get()->illegal_option(token);
1202 if (tr->expects_exactly_one_option() && tr->get()) {
1203 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1204 exit(1);
1209 public:
1211 * Input handler.
1213 * Does one of two things:
1215 * (1) Output version information if called with '--version'
1217 * (2) Read options and file arguments, and if the arguments are correct,
1218 * write output. If an error is detected, print the usage statement.
1222 static void handle(int argc, const char *argv[], const char *package, const char *short_version, const char *version) {
1225 * Initialize help object
1228 help hi(package, argv[0], short_version);
1231 * Output version information if --version appears
1232 * on the command line.
1235 if (arg_count(argc, argv, "--version")) {
1237 * Output the version
1240 fprintf(stdout, "%s", version);
1242 return;
1246 * Handle help options
1249 if (arg_prefix_count(argc, argv, "--h"))
1250 for (int i = 1; i < argc; i++) {
1251 int all = !strcmp(argv[i], "--hA");
1252 int is_help_option = !strncmp(argv[i], "--h", strlen("--h"));
1253 int found_help = 0;
1255 if (!strcmp(argv[i], "--hu") || all)
1256 hi.usage(), found_help = 1;
1257 if (!strcmp(argv[i], "--hq") || all)
1258 hi.defaults(), found_help = 1;
1259 if (!strcmp(argv[i], "--hf") || all)
1260 hi.file(), found_help = 1;
1261 if (!strcmp(argv[i], "--he") || all)
1262 hi.exclusion(), found_help = 1;
1263 if (!strcmp(argv[i], "--ha") || all)
1264 hi.alignment(), found_help = 1;
1265 if (!strcmp(argv[i], "--hr") || all)
1266 hi.rendering(), found_help = 1;
1267 if (!strcmp(argv[i], "--hx") || all)
1268 hi.exposure(), found_help = 1;
1269 if (!strcmp(argv[i], "--ht") || all)
1270 hi.tdf(), found_help = 1;
1271 if (!strcmp(argv[i], "--hl") || all)
1272 hi.filtering(), found_help = 1;
1273 if (!strcmp(argv[i], "--hd") || all)
1274 hi.device(), found_help = 1;
1275 if (!strcmp(argv[i], "--hi") || all)
1276 hi.interface(), found_help = 1;
1277 if (!strcmp(argv[i], "--hv") || all)
1278 hi.visp(), found_help = 1;
1279 if (!strcmp(argv[i], "--hc") || all)
1280 hi.cp(), found_help = 1;
1281 if (!strcmp(argv[i], "--h3") || all)
1282 hi.d3(), found_help = 1;
1283 if (!strcmp(argv[i], "--hs") || all)
1284 hi.scope(), found_help = 1;
1285 if (!strcmp(argv[i], "--hp") || all)
1286 hi.process(), found_help = 1;
1287 if (!strcmp(argv[i], "--hz") || all)
1288 hi.undocumented(), found_help = 1;
1290 if (is_help_option && !found_help)
1291 hi.usage();
1294 * Check for the end-of-options marker, a non-option argument,
1295 * or the end of arguments. In all of these cases, we exit.
1298 if (!strcmp(argv[i], "--")
1299 || strncmp(argv[i], "--", strlen("--"))
1300 || i == argc - 1)
1301 return;
1305 * Undocumented projective transformation utility
1308 if (arg_count(argc, argv, "--ptcalc") > 0) {
1309 fprintf(stderr, "\n\n*** Warning: this feature is not documented ***\n\n");
1310 printf("Enter: w h tlx tly blx bly brx bry trx try x y\n\n");
1312 double w, h, tlx, tly, blx, bly, brx, bry, trx, tr_y, x, y;
1314 printf("> ");
1316 if (scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
1317 &w, &h, &tlx, &tly, &blx, &bly, &brx, &bry, &trx, &tr_y, &x, &y) != 12) {
1319 fprintf(stderr, "Error reading input.\n");
1320 exit(1);
1323 d2::image *i = new d2::image_ale_real((int)h, (int)w, 3);
1324 d2::transformation t = d2::transformation::gpt_identity(i, 1);
1325 d2::point q[4] = {
1326 d2::point(tly, tlx),
1327 d2::point(bly, blx),
1328 d2::point(bry, brx),
1329 d2::point(tr_y, trx)
1331 t.gpt_set(q);
1333 d2::point a(y, x), b;
1335 b = t.transform_scaled(a);
1337 printf("TRANSFORM t(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1339 b = t.scaled_inverse_transform(a);
1341 printf("INVERSE t^-1(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1343 exit(0);
1347 * Thread initialization.
1350 thread::init();
1353 * Flags and variables
1356 double scale_factor = 1;
1357 double vise_scale_factor = 1;
1358 #if 0
1359 double usm_multiplier = 0.0;
1360 #endif
1361 int extend = 0;
1362 struct d2::tload_t *tload = NULL;
1363 struct d2::tsave_t *tsave = NULL;
1364 struct d3::tload_t *d3_tload = NULL;
1365 struct d3::tsave_t *d3_tsave = NULL;
1366 int ip_iterations = 0;
1367 int ip_use_median = 0;
1368 double ipwl = 0;
1369 enum { psf_linear, psf_nonlinear, psf_N };
1370 const char *psf[psf_N] = {NULL, NULL};
1371 const char *device = NULL;
1372 int psf_match = 0;
1373 double psf_match_args[6];
1374 int inc = 1;
1375 int exposure_register = 1;
1376 const char *wm_filename = NULL;
1377 int wm_offsetx = 0, wm_offsety = 0;
1378 double cx_parameter = 1;
1379 double *d3px_parameters = NULL;
1380 int d3px_count = 0;
1381 d2::exclusion *ex_parameters = NULL;
1382 int ex_count = 0;
1383 int ex_show = 0;
1384 d2::render *achain;
1385 const char *achain_type = "triangle:2";
1386 const char *afilter_type = "internal";
1387 d2::render **ochain = NULL;
1388 const char **ochain_names = NULL;
1389 const char **ochain_types = NULL;
1390 const char *d3chain_type = NULL;
1391 int oc_count = 0;
1392 const char **visp = NULL;
1393 int vise_count = 0;
1394 const char **d3_output = NULL;
1395 const char **d3_depth = NULL;
1396 unsigned int d3_count = 0;
1397 double user_view_angle = 0;
1398 int user_bayer = IMAGE_BAYER_DEFAULT;
1399 d2::pixel exp_mult = d2::pixel(1, 1, 1);
1400 std::map<const char *, d3::pt> d3_output_pt;
1401 std::map<const char *, d3::pt> d3_depth_pt;
1404 * dchain is ochain[0].
1407 ochain = (d2::render **) local_realloc(ochain,
1408 (oc_count + 1) * sizeof(d2::render *));
1409 ochain_names = (const char **) local_realloc((void *)ochain_names,
1410 (oc_count + 1) * sizeof(const char *));
1411 ochain_types = (const char **) local_realloc((void *)ochain_types,
1412 (oc_count + 1) * sizeof(const char *));
1414 ochain_types[0] = "sinc*lanc:8";
1416 oc_count = 1;
1419 * Handle default settings
1422 if (arg_prefix_count(argc, argv, "--q") > 1)
1423 ui::get()->error("more than one default setting option --q* was specified");
1425 const char *defaults[] = {
1426 "--dchain fine:triangle:2,triangle:2 "
1427 "--achain triangle:2 "
1428 "--ips 0 "
1429 "--3d-chain fine:triangle:2,triangle:2 ",
1431 "--dchain sinc*lanc:6 "
1432 "--achain sinc*lanc:6 "
1433 "--ips 0 "
1434 "--3d-chain sinc*lanc:6 ",
1436 "--dchain fine:triangle:2,fine:gauss:0.75,triangle:2 "
1437 "--achain triangle:2 "
1438 "--ips 0 "
1439 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ",
1441 "--dchain triangle:2 "
1442 "--achain triangle:2 "
1443 "--ips 4 "
1444 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ",
1447 int default_index;
1448 if (arg_count(argc, argv, "--q0")) {
1449 default_index = 0;
1450 } else if (arg_count(argc, argv, "--qn")) {
1451 default_index = 1;
1452 } else if (arg_count(argc, argv, "--q1")) {
1453 default_index = 2;
1454 } else if (arg_count(argc, argv, "--q2")) {
1455 default_index = 3;
1456 } else if (arg_count(argc, argv, "--qr")) {
1457 default_index = 4;
1458 } else {
1460 * Same as --q2
1462 default_index = 3;
1465 token_reader *default_reader = new cstring_token_reader(defaults[default_index]);
1467 evaluate_stream(default_reader, NULL);
1470 * Set basic program information in the environment.
1473 environment::top()->set_with_dup("---package", package);
1474 environment::top()->set_with_dup("---short-version", short_version);
1475 environment::top()->set_with_dup("---version", version);
1476 environment::top()->set_with_dup("---invocation", argv[0]);
1479 * Initialize the top-level token-reader and generate
1480 * an environment variable for it.
1483 token_reader *tr = new cli_token_reader(argc - 1, argv + 1);
1484 environment::top()->set_ptr("---token-reader", tr);
1487 * Evaluate the command-line arguments to generate environment
1488 * structures.
1491 std::vector<std::pair<const char *, environment *> > files;
1493 evaluate_stream(tr, &files);
1496 * If there are fewer than two files, then output usage information.
1499 if (files.size() < 2) {
1500 hi.usage();
1501 exit(1);
1505 * Extract the global environment and check non-globals
1506 * against a list of supported non-global options.
1509 genv = files[0].second->clone();
1511 remove_nonglobals(genv);
1513 for (unsigned int i = 0; i < files.size(); i++) {
1514 option_intersect(genv, files[i].second);
1517 for (unsigned int i = 0; i < files.size(); i++) {
1518 option_difference(files[i].second, genv);
1520 for (std::map<const char *, const char *>::iterator j = files[i].second->get_map().begin();
1521 j != files[i].second->get_map().end(); j++) {
1523 environment *env = files[i].second;
1525 if (!env->is_option(j->first))
1526 continue;
1528 const char *option_name = env->get_option_name(j->first);
1530 if (!table_contains(supported_nonglobal_option_table, option_name)) {
1531 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
1532 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
1533 option_name);
1534 exit(1);
1540 * Iterate through the global environment,
1541 * looking for options.
1544 for (std::map<const char *, const char *>::iterator i = genv->get_map().begin();
1545 i != genv->get_map().end(); i++) {
1547 environment *env = genv;
1549 if (!env->is_option(i->first))
1550 continue;
1552 const char *option_name = env->get_option_name(i->first);
1554 if (!strcmp(option_name, "default")) {
1556 * Do nothing. Defaults have already been set.
1558 } else if (!strcmp(option_name, "bpc")) {
1559 if (!strcmp(env->get_string_arg(i->first, 0), "8bpc"))
1560 d2::image_rw::depth8();
1561 else if (!strcmp(env->get_string_arg(i->first, 0), "16bpc"))
1562 d2::image_rw::depth16();
1563 else
1564 assert(0);
1565 } else if (!strcmp(option_name, "format")) {
1566 if (!strcmp(env->get_string_arg(i->first, 0), "plain"))
1567 d2::image_rw::ppm_plain();
1568 else if (!strcmp(env->get_string_arg(i->first, 0), "raw"))
1569 d2::image_rw::ppm_raw();
1570 else if (!strcmp(env->get_string_arg(i->first, 0), "auto"))
1571 d2::image_rw::ppm_auto();
1572 else
1573 assert(0);
1574 } else if (!strcmp(option_name, "align")) {
1575 if (!strcmp(env->get_string_arg(i->first, 0), "align-all"))
1576 d2::align::all();
1577 else if (!strcmp(env->get_string_arg(i->first, 0), "align-green"))
1578 d2::align::green();
1579 else if (!strcmp(env->get_string_arg(i->first, 0), "align-sum"))
1580 d2::align::sum();
1581 else
1582 assert(0);
1583 } else if (!strcmp(option_name, "transformation")) {
1584 if (!strcmp(env->get_string_arg(i->first, 0), "translation"))
1585 d2::align::class_translation();
1586 else if (!strcmp(env->get_string_arg(i->first, 0), "euclidean"))
1587 d2::align::class_euclidean();
1588 else if (!strcmp(env->get_string_arg(i->first, 0), "projective"))
1589 d2::align::class_projective();
1590 else
1591 assert(0);
1592 } else if (!strcmp(option_name, "transformation-default")) {
1593 if (!strcmp(env->get_string_arg(i->first, 0), "identity"))
1594 d2::align::initial_default_identity();
1595 else if (!strcmp(env->get_string_arg(i->first, 0), "follow"))
1596 d2::align::initial_default_follow();
1597 else
1598 assert(0);
1599 } else if (!strcmp(option_name, "perturb")) {
1600 if (!strcmp(env->get_string_arg(i->first, 0), "perturb-output"))
1601 d2::align::perturb_output();
1602 else if (!strcmp(env->get_string_arg(i->first, 0), "perturb-source"))
1603 d2::align::perturb_source();
1604 else
1605 assert(0);
1606 } else if (!strcmp(option_name, "fail")) {
1607 if (!strcmp(env->get_string_arg(i->first, 0), "fail-optimal"))
1608 d2::align::fail_optimal();
1609 else if (!strcmp(env->get_string_arg(i->first, 0), "fail-default"))
1610 d2::align::fail_default();
1611 else
1612 assert(0);
1613 } else if (!strcmp(option_name, "profile")) {
1614 ui::set_profile();
1615 } else if (!strcmp(option_name, "extend")) {
1616 if (env->get_int_arg(i->first, 0))
1617 extend = 1;
1618 else
1619 extend = 0;
1620 } else if (!strcmp(option_name, "oc")) {
1621 if (env->get_int_arg(i->first, 0))
1622 d3::scene::oc();
1623 else
1624 d3::scene::no_oc();
1625 } else if (!strcmp(option_name, "focus")) {
1627 double one = +1;
1628 double zero = +0;
1629 double inf = one / zero;
1631 assert (isinf(inf) && inf > 0);
1634 * Focus type
1637 unsigned int type = 0;
1638 double distance = 0;
1639 double px = 0, py = 0;
1641 if (!strcmp(env->get_string_arg(i->first, 1), "d")) {
1643 type = 0;
1645 distance = env->get_double_arg(i->first, 2);
1647 } else if (!strcmp(env->get_string_arg(i->first, 1), "p")) {
1649 type = 1;
1651 px = env->get_double_arg(i->first, 2);
1652 py = env->get_double_arg(i->first, 3);
1654 } else {
1655 bad_arg(option_name);
1659 * Options
1662 unsigned int ci = 0;
1663 double fr = 0;
1664 double ht = 0;
1665 double vt = 0;
1666 double sd = 0;
1667 double ed = inf;
1668 double sx = -inf;
1669 double ex = inf;
1670 double sy = -inf;
1671 double ey = inf;
1672 double ap = 3;
1673 unsigned int sc = 3;
1674 unsigned int fs = 0;
1675 unsigned int sr = 0;
1677 for (int arg_num = 4; env->is_arg(i->first, arg_num); arg_num++) {
1678 const char *option = env->get_string_arg(i->first, arg_num);
1679 if (!strncmp(option, "ci=", 3)) {
1680 if(sscanf(option + 3, "%u", &ci) != 1)
1681 bad_arg("--focus");
1682 } else if (!strncmp(option, "fr=", 3)) {
1683 if(sscanf(option + 3, "%lf", &fr) != 1)
1684 bad_arg("--focus");
1685 } else if (!strncmp(option, "ht=", 3)) {
1686 if(sscanf(option + 3, "%lf", &ht) != 1)
1687 bad_arg("--focus");
1688 } else if (!strncmp(option, "vt=", 3)) {
1689 if(sscanf(option + 3, "%lf", &vt) != 1)
1690 bad_arg("--focus");
1691 } else if (!strncmp(option, "sy=", 3)) {
1692 if(sscanf(option + 3, "%lf", &sy) != 1)
1693 bad_arg("--focus");
1694 } else if (!strncmp(option, "ey=", 3)) {
1695 if(sscanf(option + 3, "%lf", &ey) != 1)
1696 bad_arg("--focus");
1697 } else if (!strncmp(option, "sx=", 3)) {
1698 if(sscanf(option + 3, "%lf", &sx) != 1)
1699 bad_arg("--focus");
1700 } else if (!strncmp(option, "ex=", 3)) {
1701 if(sscanf(option + 3, "%lf", &ex) != 1)
1702 bad_arg("--focus");
1703 } else if (!strncmp(option, "sd=", 3)) {
1704 if(sscanf(option + 3, "%lf", &sd) != 1)
1705 bad_arg("--focus");
1706 } else if (!strncmp(option, "ed=", 3)) {
1707 if(sscanf(option + 3, "%lf", &ed) != 1)
1708 bad_arg("--focus");
1709 } else if (!strncmp(option, "ap=", 3)) {
1710 if(sscanf(option + 3, "%lf", &ap) != 1)
1711 bad_arg("--focus");
1712 } else if (!strncmp(option, "sc=", 3)) {
1713 if(sscanf(option + 3, "%u", &sc) != 1)
1714 bad_arg("--focus");
1715 } else if (!strncmp(option, "sr=", 3)) {
1716 if (!strcmp(option, "sr=aperture")) {
1717 sr = 0;
1718 } else if (!strcmp(option, "sr=pixel")) {
1719 sr = 1;
1720 } else
1721 bad_arg("--focus");
1723 } else if (!strncmp(option, "fs=", 3)) {
1724 if (!strcmp(option, "fs=mean")) {
1725 fs = 0;
1726 } else if (!strcmp(option, "fs=median")) {
1727 fs = 1;
1728 } else
1729 bad_arg("--focus");
1730 } else
1731 bad_arg("--focus");
1734 d3::focus::add_region(type, distance, px, py, ci, fr, ht, vt, sd, ed, sx, ex, sy, ey, ap, sc, fs, sr);
1736 } else if (!strcmp(option_name, "3ddp") || !strcmp(option_name, "3dvp")) {
1737 d2::align::keep();
1740 * Unsupported configurations
1743 if (ip_iterations)
1744 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1746 #if 0
1747 if (usm_multiplier)
1748 unsupported::fornow("3D modeling with unsharp mask");
1749 #endif
1752 * Initialize if necessary
1754 * Note: because their existence is checked as an
1755 * indicator of the presence of 3D arguments, we
1756 * initialize these structures here.
1759 if (d3_output == NULL) {
1760 d3_count = argc;
1761 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1762 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1765 unsigned int width, height;
1766 double view_angle;
1767 double x, y, z;
1768 double P, Y, R;
1770 width = env->get_unsigned_arg(i->first, 1);
1771 height = env->get_unsigned_arg(i->first, 2);
1772 view_angle = env->get_double_arg(i->first, 3);
1773 x = env->get_double_arg(i->first, 4);
1774 y = env->get_double_arg(i->first, 5);
1775 z = env->get_double_arg(i->first, 6);
1776 P = env->get_double_arg(i->first, 7);
1777 Y = env->get_double_arg(i->first, 8);
1778 R = env->get_double_arg(i->first, 9);
1780 view_angle *= M_PI / 180;
1781 P *= M_PI / 180;
1782 Y *= M_PI / 180;
1783 R *= M_PI / 180;
1785 d2::transformation t =
1786 d2::transformation::eu_identity();
1787 t.set_domain(height, width);
1788 d3::pt _pt(t, d3::et(y, x, z, Y, P, R), view_angle);
1790 if (!strcmp(option_name, "3dvp")) {
1791 d3_output_pt[env->get_string_arg(i->first, 10)] = _pt;
1792 } else if (!strcmp(option_name, "3ddp")) {
1793 d3_depth_pt[env->get_string_arg(i->first, 10)] = _pt;
1794 } else {
1795 assert(0);
1797 } else if (!strcmp(option_name, "3dv")) {
1798 d2::align::keep();
1800 unsigned int frame_no;
1803 * Unsupported configurations
1806 if (ip_iterations)
1807 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1809 #if 0
1810 if (usm_multiplier)
1811 unsupported::fornow("3D modeling with unsharp mask");
1812 #endif
1815 * Initialize if necessary
1818 if (d3_output == NULL) {
1819 d3_count = argc;
1820 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1821 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1824 frame_no = env->get_int_arg(i->first, 1);
1826 if (frame_no >= d3_count)
1827 ui::get()->error("--3dv argument 0 is too large");
1829 if (d3_output[frame_no] != NULL) {
1830 unsupported::fornow ("Writing a single 3D view to more than one output file");
1833 d3_output[frame_no] = env->get_string_arg(i->first, 2);
1835 } else if (!strcmp(option_name, "3dd")) {
1836 d2::align::keep();
1838 unsigned int frame_no;
1841 * Unsupported configurations
1844 if (ip_iterations)
1845 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1847 #if 0
1848 if (usm_multiplier)
1849 unsupported::fornow("3D modeling with unsharp mask");
1850 #endif
1853 * Initialize if necessary
1856 if (d3_output == NULL) {
1857 d3_count = argc;
1858 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1859 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1862 frame_no = env->get_int_arg(i->first, 1);
1864 if (frame_no >= d3_count)
1865 ui::get()->error("--3dd argument 0 is too large");
1867 if (d3_depth[frame_no] != NULL) {
1868 unsupported::fornow ("Writing a single frame's depth info to more than one output file");
1871 d3_depth[frame_no] = env->get_string_arg(i->first, 2);
1873 } else if (!strcmp(option_name, "view-angle")) {
1874 user_view_angle = env->get_double_arg(i->first, 1) * M_PI / 180;
1875 } else if (!strcmp(option_name, "cpf-load")) {
1876 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
1877 } else if (!strcmp(option_name, "ui")) {
1878 if (!strcmp(env->get_string_arg(i->first, 1), "stream"))
1879 ui::set_stream();
1880 else if (!strcmp(env->get_string_arg(i->first, 1), "tty"))
1881 ui::set_tty();
1882 else if (!strcmp(env->get_string_arg(i->first, 1), "log"))
1883 ui::set_log();
1884 else if (!strcmp(env->get_string_arg(i->first, 1), "quiet"))
1885 ui::set_quiet();
1886 else
1887 assert(0);
1888 } else if (!strcmp(option_name, "3d-fmr")) {
1889 d3::scene::fmr(env->get_double_arg(i->first, 1));
1890 } else if (!strcmp(option_name, "3d-dmr")) {
1891 d3::scene::dmr(env->get_double_arg(i->first, 1));
1892 } else if (!strcmp(option_name, "et")) {
1893 d3::scene::et(env->get_double_arg(i->first, 1));
1894 } else if (!strcmp(option_name, "st")) {
1895 d3::cpf::st(env->get_double_arg(i->first, 1));
1896 } else if (!strcmp(option_name, "di-lower")) {
1897 d3::scene::di_lower(env->get_double_arg(i->first, 1));
1898 } else if (!strcmp(option_name, "rc")) {
1899 d3::scene::rc(env->get_double_arg(i->first, 1));
1900 } else if (!strcmp(option_name, "do-try")) {
1901 d3::scene::do_try(env->get_double_arg(i->first, 1));
1902 } else if (!strcmp(option_name, "di-upper")) {
1903 d3::scene::di_upper(env->get_double_arg(i->first, 1));
1904 } else if (!strcmp(option_name, "fc")) {
1905 d3::scene::fc(env->get_double_arg(i->first, 1));
1906 } else if (!strcmp(option_name, "ecm")) {
1907 unsupported::discontinued("--ecm <x>");
1908 } else if (!strcmp(option_name, "acm")) {
1909 unsupported::discontinued("--acm <x>");
1910 } else if (!strcmp(option_name, "def-nn")) {
1911 d2::image_rw::def_nn(env->get_double_arg(i->first, 1));
1913 if (env->get_double_arg(i->first, 1) > 2) {
1914 fprintf(stderr, "\n\n*** Warning: --def-nn implementation is currently "
1915 "inefficient for large radii. ***\n\n");
1918 } else if (!strcmp(option_name, "fx")) {
1919 d3::scene::fx(env->get_double_arg(i->first, 1));
1920 } else if (!strcmp(option_name, "tcem")) {
1921 d3::scene::tcem(env->get_double_arg(i->first, 1));
1922 } else if (!strcmp(option_name, "oui")) {
1923 d3::scene::oui(env->get_unsigned_arg(i->first, 1));
1924 } else if (!strcmp(option_name, "pa")) {
1925 d3::scene::pa(env->get_unsigned_arg(i->first, 1));
1926 } else if (!strcmp(option_name, "pc")) {
1927 d3::scene::pc(env->get_string_arg(i->first, 1));
1928 } else if (!strcmp(option_name, "cw")) {
1929 d2::align::certainty_weighted(env->get_unsigned_arg(i->first, 0));
1930 } else if (!strcmp(option_name, "wm")) {
1931 if (wm_filename != NULL)
1932 ui::get()->error("only one weight map can be specified");
1934 wm_filename = env->get_string_arg(i->first, 1);
1935 wm_offsetx = env->get_int_arg(i->first, 2);
1936 wm_offsety = env->get_int_arg(i->first, 3);
1938 } else if (!strcmp(option_name, "fl")) {
1939 #ifdef USE_FFTW
1940 d2::align::set_frequency_cut(env->get_double_arg(i->first, 1),
1941 env->get_double_arg(i->first, 2),
1942 env->get_double_arg(i->first, 3));
1944 #else
1945 ui::get()->error_hint("--fl is not supported", "rebuild ALE with FFTW support");
1946 #endif
1947 } else if (!strcmp(option_name, "wmx")) {
1948 #ifdef USE_UNIX
1949 d2::align::set_wmx(env->get_string_arg(i->first, 1),
1950 env->get_string_arg(i->first, 2),
1951 env->get_string_arg(i->first, 3));
1952 #else
1953 ui::get()->error_hint("--wmx is not supported", "rebuild ALE with support for --wmx");
1954 #endif
1955 } else if (!strcmp(option_name, "flshow")) {
1956 d2::align::set_fl_show(env->get_string_arg(i->first, 1));
1957 } else if (!strcmp(option_name, "3dpx")) {
1959 d3px_parameters = (double *) local_realloc(d3px_parameters, (d3px_count + 1) * 6 * sizeof(double));
1961 for (int param = 0; param < 6; param++)
1962 d3px_parameters[6 * d3px_count + param] = env->get_double_arg(i->first, param + 1);
1965 * Swap x and y, since their internal meanings differ from their external meanings.
1968 for (int param = 0; param < 2; param++) {
1969 double temp = d3px_parameters[6 * d3px_count + 2 + param];
1970 d3px_parameters[6 * d3px_count + 2 + param] = d3px_parameters[6 * d3px_count + 0 + param];
1971 d3px_parameters[6 * d3px_count + 0 + param] = temp;
1976 * Increment counters
1979 d3px_count++;
1981 } else if (!strcmp(option_name, "ex") || !strcmp(option_name, "fex")) {
1983 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
1984 (ex_count + 1) * sizeof(d2::exclusion));
1986 ex_parameters[ex_count].type = (!strcmp(option_name, "ex"))
1987 ? d2::exclusion::RENDER
1988 : d2::exclusion::FRAME;
1991 * Get parameters, swapping x and y coordinates
1994 ex_parameters[ex_count].x[0] = env->get_int_arg(i->first, 1 + 2);
1995 ex_parameters[ex_count].x[1] = env->get_int_arg(i->first, 1 + 3);
1996 ex_parameters[ex_count].x[2] = env->get_int_arg(i->first, 1 + 0);
1997 ex_parameters[ex_count].x[3] = env->get_int_arg(i->first, 1 + 1);
1998 ex_parameters[ex_count].x[4] = env->get_int_arg(i->first, 1 + 4);
1999 ex_parameters[ex_count].x[5] = env->get_int_arg(i->first, 1 + 5);
2002 * Increment counters
2005 ex_count++;
2007 } else if (!strcmp(option_name, "crop") || !strcmp(option_name, "fcrop")) {
2009 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
2010 (ex_count + 4) * sizeof(d2::exclusion));
2012 for (int r = 0; r < 4; r++)
2013 ex_parameters[ex_count + r].type = (!strcmp(option_name, "crop"))
2014 ? d2::exclusion::RENDER
2015 : d2::exclusion::FRAME;
2018 int crop_args[6];
2020 for (int param = 0; param < 6; param++)
2021 crop_args[param] = env->get_int_arg(i->first, param + 1);
2024 * Construct exclusion regions from the crop area,
2025 * swapping x and y, since their internal meanings
2026 * differ from their external meanings.
2030 * Exclusion region 1: low x
2033 ex_parameters[ex_count + 0].x[0] = INT_MIN;
2034 ex_parameters[ex_count + 0].x[1] = crop_args[2] - 1;
2035 ex_parameters[ex_count + 0].x[2] = INT_MIN;
2036 ex_parameters[ex_count + 0].x[3] = INT_MAX;
2037 ex_parameters[ex_count + 0].x[4] = crop_args[4];
2038 ex_parameters[ex_count + 0].x[5] = crop_args[5];
2041 * Exclusion region 2: low y
2044 ex_parameters[ex_count + 1].x[0] = INT_MIN;
2045 ex_parameters[ex_count + 1].x[1] = INT_MAX;
2046 ex_parameters[ex_count + 1].x[2] = INT_MIN;
2047 ex_parameters[ex_count + 1].x[3] = crop_args[0] - 1;
2048 ex_parameters[ex_count + 1].x[4] = crop_args[4];
2049 ex_parameters[ex_count + 1].x[5] = crop_args[5];
2052 * Exclusion region 3: high y
2055 ex_parameters[ex_count + 2].x[0] = INT_MIN;
2056 ex_parameters[ex_count + 2].x[1] = INT_MAX;
2057 ex_parameters[ex_count + 2].x[2] = crop_args[1] + 1;
2058 ex_parameters[ex_count + 2].x[3] = INT_MAX;
2059 ex_parameters[ex_count + 2].x[4] = crop_args[4];
2060 ex_parameters[ex_count + 2].x[5] = crop_args[5];
2063 * Exclusion region 4: high x
2066 ex_parameters[ex_count + 3].x[0] = crop_args[3] + 1;
2067 ex_parameters[ex_count + 3].x[1] = INT_MAX;
2068 ex_parameters[ex_count + 3].x[2] = INT_MIN;
2069 ex_parameters[ex_count + 3].x[3] = INT_MAX;
2070 ex_parameters[ex_count + 3].x[4] = crop_args[4];
2071 ex_parameters[ex_count + 3].x[5] = crop_args[5];
2074 * Increment counters
2077 ex_count += 4;
2079 } else if (!strcmp(option_name, "exshow")) {
2080 ex_show = 1;
2081 } else if (!strcmp(option_name, "wt")) {
2082 d2::render::set_wt(env->get_double_arg(i->first, 1));
2083 } else if (!strcmp(option_name, "3d-chain")) {
2084 d3chain_type = env->get_string_arg(i->first, 1);
2085 } else if (!strcmp(option_name, "dchain")) {
2086 ochain_types[0] = env->get_string_arg(i->first, 1);
2087 } else if (!strcmp(option_name, "achain")) {
2088 achain_type = env->get_string_arg(i->first, 1);
2089 } else if (!strcmp(option_name, "afilter")) {
2090 afilter_type = env->get_string_arg(i->first, 1);
2091 } else if (!strcmp(option_name, "ochain")) {
2093 ochain = (d2::render **) local_realloc(ochain,
2094 (oc_count + 1) * sizeof(d2::render *));
2095 ochain_names = (const char **) local_realloc((void *)ochain_names,
2096 (oc_count + 1) * sizeof(const char *));
2097 ochain_types = (const char **) local_realloc((void *)ochain_types,
2098 (oc_count + 1) * sizeof(const char *));
2100 ochain_types[oc_count] = env->get_string_arg(i->first, 1);
2101 ochain_names[oc_count] = env->get_string_arg(i->first, 2);
2103 oc_count++;
2105 } else if (!strcmp(option_name, "visp")) {
2107 visp = (const char **) local_realloc((void *)visp, 4 *
2108 (vise_count + 1) * sizeof(const char *));
2110 for (int param = 0; param < 4; param++)
2111 visp[vise_count * 4 + param] = env->get_string_arg(i->first, param + 1);
2113 vise_count++;
2115 } else if (!strcmp(option_name, "cx")) {
2116 cx_parameter = env->get_int_arg(i->first, 0) ? env->get_double_arg(i->first, 1) : 0;
2117 } else if (!strcmp(option_name, "ip")) {
2118 unsupported::discontinued("--ip <r> <i>", "--lpsf box=<r> --ips <i>");
2119 } else if (!strcmp(option_name, "bayer")) {
2122 * External order is clockwise from top-left. Internal
2123 * order is counter-clockwise from top-left.
2126 const char *option = env->get_string_arg(i->first, 1);
2128 if (!strcmp(option, "rgbg")) {
2129 user_bayer = IMAGE_BAYER_RGBG;
2130 } else if (!strcmp(option, "bgrg")) {
2131 user_bayer = IMAGE_BAYER_BGRG;
2132 } else if (!strcmp(option, "gbgr")) {
2133 user_bayer = IMAGE_BAYER_GRGB;
2134 } else if (!strcmp(option, "grgb")) {
2135 user_bayer = IMAGE_BAYER_GBGR;
2136 } else if (!strcmp(option, "none")) {
2137 user_bayer = IMAGE_BAYER_NONE;
2138 } else {
2139 bad_arg("--bayer");
2142 } else if (!strcmp(option_name, "lpsf")) {
2143 psf[psf_linear] = env->get_string_arg(i->first, 1);
2144 } else if (!strcmp(option_name, "nlpsf")) {
2145 psf[psf_nonlinear] = env->get_string_arg(i->first, 1);
2146 } else if (!strcmp(option_name, "psf-match")) {
2148 psf_match = 1;
2150 for (int index = 0; index < 6; index++) {
2151 psf_match_args[index] = env->get_double_arg(i->first, index + 1);
2154 } else if (!strcmp(option_name, "device")) {
2155 device = env->get_string_arg(i->first, 1);
2156 #if 0
2157 } else if (!strcmp(option_name, "usm")) {
2159 if (d3_output != NULL)
2160 unsupported::fornow("3D modeling with unsharp mask");
2162 usm_multiplier = env->get_double_arg(i->first, 1);
2163 #endif
2165 } else if (!strcmp(option_name, "ipr")) {
2167 ip_iterations = env->get_int_arg(i->first, 1);
2169 ui::get()->warn("--ipr is deprecated. Use --ips instead");
2171 } else if (!strcmp(option_name, "cpp-err")) {
2172 if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2173 d3::cpf::err_median();
2174 else if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2175 d3::cpf::err_mean();
2176 } else if (!strcmp(option_name, "vp-adjust")) {
2177 if (env->get_int_arg(i->first, 0))
2178 d3::align::vp_adjust();
2179 else
2180 d3::align::vp_noadjust();
2181 } else if (!strcmp(option_name, "vo-adjust")) {
2182 if (env->get_int_arg(i->first, 0))
2183 d3::align::vo_adjust();
2184 else
2185 d3::align::vo_noadjust();
2186 } else if (!strcmp(option_name, "ip-statistic")) {
2187 if (!strcmp(env->get_string_arg(i->first, 1), "mean"))
2188 ip_use_median = 0;
2189 else if (!strcmp(env->get_string_arg(i->first, 1), "median"))
2190 ip_use_median = 1;
2191 } else if (!strcmp(option_name, "ips")) {
2192 ip_iterations = env->get_int_arg(i->first, 1);
2193 } else if (!strcmp(option_name, "ip-wl")) {
2194 int limited = env->get_int_arg(i->first, 0);
2195 if (limited) {
2196 ipwl = env->get_double_arg(i->first, 1);
2197 } else {
2198 ipwl = 0;
2200 } else if (!strcmp(option_name, "ipc")) {
2201 unsupported::discontinued("--ipc <c> <i>", "--ips <i> --lpsf <c>", "--ips <i> --device <c>");
2202 } else if (!strcmp(option_name, "exp-extend")) {
2203 if (env->get_int_arg(i->first, 0))
2204 d2::image_rw::exp_scale();
2205 else
2206 d2::image_rw::exp_noscale();
2207 } else if (!strcmp(option_name, "exp-register")) {
2208 if (env->get_int_arg(i->first, 0) == 1) {
2209 exposure_register = 1;
2210 d2::align::exp_register();
2211 } else if (env->get_int_arg(i->first, 0) == 0) {
2212 exposure_register = 0;
2213 d2::align::exp_noregister();
2214 } else if (env->get_int_arg(i->first, 0) == 2) {
2215 exposure_register = 2;
2216 d2::align::exp_meta_only();
2218 } else if (!strcmp(option_name, "drizzle-only")) {
2219 unsupported::discontinued("--drizzle-only", "--dchain box:1");
2220 } else if (!strcmp(option_name, "subspace-traverse")) {
2221 unsupported::undocumented("--subspace-traverse");
2222 d3::scene::set_subspace_traverse();
2223 } else if (!strcmp(option_name, "3d-filter")) {
2224 if (env->get_int_arg(i->first, 0))
2225 d3::scene::filter();
2226 else
2227 d3::scene::nofilter();
2228 } else if (!strcmp(option_name, "occ-norm")) {
2229 if (env->get_int_arg(i->first, 0))
2230 d3::scene::nw();
2231 else
2232 d3::scene::no_nw();
2233 } else if (!strcmp(option_name, "inc")) {
2234 inc = env->get_int_arg(i->first, 0);
2235 } else if (!strcmp(option_name, "exp-mult")) {
2236 double exp_c, exp_r, exp_b;
2238 exp_c = env->get_double_arg(i->first, 1);
2239 exp_r = env->get_double_arg(i->first, 2);
2240 exp_b = env->get_double_arg(i->first, 3);
2242 exp_mult = d2::pixel(1/(exp_r * exp_c), 1/exp_c, 1/(exp_b * exp_c));
2244 } else if (!strcmp(option_name, "visp-scale")) {
2246 vise_scale_factor = env->get_double_arg(i->first, 1);
2248 if (vise_scale_factor <= 0.0)
2249 ui::get()->error("VISP scale must be greater than zero");
2251 if (!finite(vise_scale_factor))
2252 ui::get()->error("VISP scale must be finite");
2254 } else if (!strcmp(option_name, "scale")) {
2256 scale_factor = env->get_double_arg(i->first, 1);
2258 if (scale_factor <= 0)
2259 ui::get()->error("Scale factor must be greater than zero");
2261 if (!finite(scale_factor))
2262 ui::get()->error("Scale factor must be finite");
2264 } else if (!strcmp(option_name, "metric")) {
2265 d2::align::set_metric_exponent(env->get_double_arg(i->first, 1));
2266 } else if (!strcmp(option_name, "threshold")) {
2267 d2::align::set_match_threshold(env->get_double_arg(i->first, 1));
2268 } else if (!strcmp(option_name, "drizzle-diam")) {
2269 unsupported::discontinued("--drizzle-diam=<x>", "--dchain box:1");
2270 } else if (!strcmp(option_name, "perturb-lower")) {
2271 const char *option = env->get_string_arg(i->first, 1);
2272 double perturb_lower;
2273 int characters;
2274 sscanf(option, "%lf%n", &perturb_lower, &characters);
2275 if (perturb_lower <= 0)
2276 ui::get()->error("--perturb-lower= value is non-positive");
2278 if (*(option + characters) == '%')
2279 d2::align::set_perturb_lower(perturb_lower, 1);
2280 else
2281 d2::align::set_perturb_lower(perturb_lower, 0);
2282 } else if (!strcmp(option_name, "stepsize")) {
2283 ui::get()->warn("--stepsize is deprecated. Use --perturb-lower instead");
2284 d2::align::set_perturb_lower(env->get_double_arg(i->first, 1), 0);
2285 } else if (!strcmp(option_name, "va-upper")) {
2286 const char *option = env->get_string_arg(i->first, 1);
2287 double va_upper;
2288 int characters;
2289 sscanf(option, "%lf%n", &va_upper, &characters);
2290 if (*(option + characters) == '%')
2291 ui::get()->error("--va-upper= does not accept '%' arguments\n");
2292 else
2293 d3::cpf::set_va_upper(va_upper);
2294 } else if (!strcmp(option_name, "cpp-upper")) {
2295 const char *option = env->get_string_arg(i->first, 1);
2296 double perturb_upper;
2297 int characters;
2298 sscanf(option, "%lf%n", &perturb_upper, &characters);
2299 if (*(option + characters) == '%')
2300 ui::get()->error("--cpp-upper= does not currently accept '%' arguments\n");
2301 else
2302 d3::cpf::set_cpp_upper(perturb_upper);
2303 } else if (!strcmp(option_name, "cpp-lower")) {
2304 const char *option = env->get_string_arg(i->first, 1);
2305 double perturb_lower;
2306 int characters;
2307 sscanf(option, "%lf%n", &perturb_lower, &characters);
2308 if (*(option + characters) == '%')
2309 ui::get()->error("--cpp-lower= does not currently accept '%' arguments\n");
2310 else
2311 d3::cpf::set_cpp_lower(perturb_lower);
2312 } else if (!strcmp(option_name, "hf-enhance")) {
2313 unsupported::discontinued("--hf-enhance=<x>");
2314 } else if (!strcmp(option_name, "rot-upper")) {
2315 d2::align::set_rot_max((int) floor(env->get_double_arg(i->first, 1)));
2316 } else if (!strcmp(option_name, "bda-mult")) {
2317 d2::align::set_bda_mult(env->get_double_arg(i->first, 1));
2318 } else if (!strcmp(option_name, "bda-rate")) {
2319 d2::align::set_bda_rate(env->get_double_arg(i->first, 1));
2320 } else if (!strcmp(option_name, "lod-max")) {
2321 d2::align::set_lod_max((int) floor(env->get_double_arg(i->first, 1)));
2322 } else if (!strcmp(option_name, "cpf-load")) {
2323 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
2324 #if 0
2325 } else if (!strcmp(option_name, "model-load")) {
2326 d3::scene::load_model(env->get_string_arg(i->first, 1));
2327 } else if (!strcmp(option_name, "model-save")) {
2328 d3::scene::save_model(env->get_string_arg(i->first, 1));
2329 #endif
2330 } else if (!strcmp(option_name, "trans-load")) {
2331 d2::tload_delete(tload);
2332 tload = d2::tload_new(env->get_string_arg(i->first, 1));
2333 d2::align::set_tload(tload);
2334 } else if (!strcmp(option_name, "trans-save")) {
2335 tsave_delete(tsave);
2336 tsave = d2::tsave_new(env->get_string_arg(i->first, 1));
2337 d2::align::set_tsave(tsave);
2338 } else if (!strcmp(option_name, "3d-trans-load")) {
2339 d3::tload_delete(d3_tload);
2340 d3_tload = d3::tload_new(env->get_string_arg(i->first, 1));
2341 d3::align::set_tload(d3_tload);
2342 } else if (!strcmp(option_name, "3d-trans-save")) {
2343 d3::tsave_delete(d3_tsave);
2344 d3_tsave = d3::tsave_new(env->get_string_arg(i->first, 1));
2345 d3::align::set_tsave(d3_tsave);
2346 } else {
2347 assert(0);
2352 * Apply implication logic.
2355 if (extend == 0 && vise_count != 0) {
2356 implication::changed("VISP requires increased image extents.",
2357 "Image extension is now enabled.",
2358 "--extend");
2359 extend = 1;
2362 if (psf_match && ex_count)
2363 unsupported::fornow("PSF calibration with exclusion regions.");
2366 if (d3_output != NULL && ip_iterations != 0)
2367 unsupported::fornow("3D modeling with Irani-Peleg rendering");
2369 #if 0
2370 if (extend == 0 && d3_output != NULL) {
2371 implication::changed("3D modeling requires increased image extents.",
2372 "Image extension is now enabled.",
2373 "--extend");
2374 extend = 1;
2376 #endif
2378 #if 0
2379 if (cx_parameter != 0 && !exposure_register) {
2380 implication::changed("Certainty-based rendering requires exposure registration.",
2381 "Exposure registration is now enabled.",
2382 "--exp-register");
2383 d2::align::exp_register();
2384 exposure_register = 1;
2386 #endif
2389 * Set alignment class exclusion region static variables
2392 d2::align::set_exclusion(ex_parameters, ex_count);
2395 * Initialize renderer class statics.
2398 d2::render::render_init(ex_count, ex_parameters, ex_show, extend, scale_factor);
2401 * Set confidence
2404 d2::exposure::set_confidence(cx_parameter);
2407 * Keep transformations for Irani-Peleg, psf-match, and
2408 * VISE
2411 if (ip_iterations > 0 || psf_match || vise_count > 0) {
2412 d2::align::keep();
2416 * Initialize device-specific variables
2419 // int input_file_count = argc - i - 1;
2420 int input_file_count = files.size() - 1;
2422 d2::psf *device_response[psf_N] = { NULL, NULL };
2423 d2::exposure **input_exposure = NULL;
2424 ale_pos view_angle = 43.7 * M_PI / 180;
2425 // ale_pos view_angle = 90 * M_PI / 180;
2426 input_exposure = (d2::exposure **)
2427 // malloc((argc - i - 1) * sizeof(d2::exposure *));
2428 malloc(input_file_count * sizeof(d2::exposure *));
2430 if (device != NULL) {
2431 if (!strcmp(device, "xvp610_640x480")) {
2432 device_response[psf_linear] = new xvp610_640x480::lpsf();
2433 device_response[psf_nonlinear] = new xvp610_640x480::nlpsf();
2434 for (int ii = 0; ii < input_file_count; ii++)
2435 input_exposure[ii] = new xvp610_640x480::exposure();
2436 view_angle = xvp610_640x480::view_angle();
2437 } else if (!strcmp(device, "xvp610_320x240")) {
2438 device_response[psf_linear] = new xvp610_320x240::lpsf();
2439 device_response[psf_nonlinear] = new xvp610_320x240::nlpsf();
2440 for (int ii = 0; ii < input_file_count; ii++)
2441 input_exposure[ii] = new xvp610_320x240::exposure();
2442 view_angle = xvp610_320x240::view_angle();
2443 } else if (!strcmp(device, "ov7620")) {
2444 device_response[psf_linear] = new ov7620_raw_linear::lpsf();
2445 device_response[psf_nonlinear] = NULL;
2446 for (int ii = 0; ii < input_file_count; ii++)
2447 input_exposure[ii] = new ov7620_raw_linear::exposure();
2448 d2::image_rw::set_default_bayer(IMAGE_BAYER_BGRG);
2449 } else if (!strcmp(device, "canon_300d")) {
2450 device_response[psf_linear] = new canon_300d_raw_linear::lpsf();
2451 device_response[psf_nonlinear] = NULL;
2452 for (int ii = 0; ii < input_file_count; ii++)
2453 input_exposure[ii] = new canon_300d_raw_linear::exposure();
2454 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2455 } else if (!strcmp(device, "nikon_d50")) {
2456 device_response[psf_linear] = nikon_d50::lpsf();
2457 device_response[psf_nonlinear] = nikon_d50::nlpsf();
2458 for (int ii = 0; ii < input_file_count; ii++)
2459 input_exposure[ii] = new nikon_d50::exposure();
2460 d2::image_rw::set_default_bayer( nikon_d50::bayer() );
2461 } else if (!strcmp(device, "canon_300d+85mm_1.8")) {
2462 device_response[psf_linear] = new canon_300d_raw_linear_85mm_1_8::lpsf();
2463 device_response[psf_nonlinear] = NULL;
2464 for (int ii = 0; ii < input_file_count; ii++)
2465 input_exposure[ii] = new canon_300d_raw_linear_85mm_1_8::exposure();
2466 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2467 view_angle = canon_300d_raw_linear_85mm_1_8::view_angle();
2468 } else if (!strcmp(device, "canon_300d+50mm_1.8")) {
2469 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_8::lpsf();
2470 device_response[psf_nonlinear] = NULL;
2471 for (int ii = 0; ii < input_file_count; ii++)
2472 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_8::exposure();
2473 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2474 view_angle = canon_300d_raw_linear_50mm_1_8::view_angle();
2475 } else if (!strcmp(device, "canon_300d+50mm_1.4")) {
2476 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4::lpsf();
2477 device_response[psf_nonlinear] = NULL;
2478 for (int ii = 0; ii < input_file_count; ii++)
2479 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4::exposure();
2480 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2481 view_angle = canon_300d_raw_linear_50mm_1_4::view_angle();
2482 } else if (!strcmp(device, "canon_300d+50mm_1.4@1.4")) {
2483 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4_1_4::lpsf();
2484 device_response[psf_nonlinear] = NULL;
2485 for (int ii = 0; ii < input_file_count; ii++)
2486 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4_1_4::exposure();
2487 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2488 view_angle = canon_300d_raw_linear_50mm_1_4_1_4::view_angle();
2489 } else {
2490 ui::get()->unknown_device(device);
2492 } else {
2493 for (int ii = 0; ii < input_file_count; ii++)
2494 input_exposure[ii] = new d2::exposure_default();
2498 * User-specified variables.
2501 if (user_view_angle != 0) {
2502 view_angle = user_view_angle;
2505 if (user_bayer != IMAGE_BAYER_DEFAULT) {
2506 d2::image_rw::set_default_bayer(user_bayer);
2510 * PSF-match exposure.
2512 if (psf_match) {
2513 delete input_exposure[input_file_count - 1];
2514 input_exposure[input_file_count - 1] = new d2::exposure_default();
2518 * Initialize output exposure
2521 d2::exposure *output_exposure = new d2::exposure_default();
2522 output_exposure->set_multiplier(exp_mult);
2525 * Configure the response function.
2528 d2::psf *response[2] = {NULL, NULL};
2530 for (int n = 0; n < psf_N; n++ ) {
2531 if (psf[n] != NULL) {
2533 response[n] = d2::psf_parse::get((n == psf_linear), psf[n]);
2535 } else if (device_response[n] != NULL) {
2538 * Device-specific response
2541 response[n] = device_response[n];
2543 } else {
2546 * Default point-spread function.
2549 if (n == psf_linear) {
2552 * Default lpsf is a box filter
2553 * of diameter 1.0 (radius
2554 * 0.5).
2557 response[n] = new d2::box(0.5);
2559 } else if (n == psf_nonlinear) {
2562 * nlpsf is disabled by default.
2565 response[n] = NULL;
2571 * First file argument. Print general file information as well
2572 * as information specific to this argument. Initialize image
2573 * file handler.
2576 // d2::image_rw::init(argc - i - 1, argv + i, argv[argc - 1], input_exposure, output_exposure);
2577 // ochain_names[0] = argv[argc - 1];
2579 const char **input_files = (const char **) malloc(sizeof(const char *) * input_file_count);
2580 for (int i = 0; i < input_file_count; i++) {
2581 input_files[i] = files[i].first;
2584 d2::image_rw::init(input_file_count, input_files, files[files.size() - 1].first,
2585 input_exposure, output_exposure);
2587 ochain_names[0] = files[files.size() - 1].first;
2590 * Handle control point data for alignment
2592 d2::align::set_cp_count(d3::cpf::count());
2593 for (unsigned int ii = 0; ii < d3::cpf::count(); ii++)
2594 d2::align::set_cp(ii, d3::cpf::get_2d(ii));
2597 * PSF-match bayer patterns.
2600 if (psf_match) {
2601 // d2::image_rw::set_specific_bayer(argc - i - 2, IMAGE_BAYER_NONE);
2602 d2::image_rw::set_specific_bayer(input_file_count - 1, IMAGE_BAYER_NONE);
2606 * Handle alignment weight map, if necessary
2609 if (wm_filename != NULL) {
2610 d2::image *weight_map;
2611 weight_map = d2::image_rw::read_image(wm_filename, new d2::exposure_linear());
2612 weight_map->set_offset(wm_offsety, wm_offsetx);
2613 d2::align::set_weight_map(weight_map);
2617 * Write comment information about original frame and
2618 * target image to the transformation save file, if we
2619 * have one.
2622 const d2::image *im = d2::image_rw::open(0);
2623 // tsave_orig(tsave, argv[i], im->avg_channel_magnitude());
2624 // tsave_target(tsave, argv[argc - 1]);
2625 tsave_orig(tsave, files[0].first, im->avg_channel_magnitude());
2626 tsave_target(tsave, files[files.size() - 1].first);
2627 d2::image_rw::close(0);
2630 * Initialize alignment interpolant.
2633 if (afilter_type != "internal")
2634 d2::align::set_interpolant(d2::render_parse::get_SSF(afilter_type));
2637 * Initialize achain and ochain.
2640 achain = d2::render_parse::get(achain_type);
2642 for (int chain = 0; chain < oc_count; chain++)
2643 ochain[chain] = d2::render_parse::get(ochain_types[chain]);
2646 * Use merged renderings as reference images in
2647 * alignment.
2650 d2::align::set_reference(achain);
2653 * Tell the alignment class about the scale factor.
2656 d2::align::set_scale(scale_factor);
2659 * Initialize visp.
2662 d2::vise_core::set_scale(vise_scale_factor);
2664 for (int opt = 0; opt < vise_count; opt++) {
2665 d2::vise_core::add(d2::render_parse::get(visp[opt * 4 + 0]),
2666 visp[opt * 4 + 1],
2667 visp[opt * 4 + 2],
2668 visp[opt * 4 + 3]);
2672 * Initialize non-incremental renderers
2675 #if 0
2676 if (usm_multiplier != 0) {
2679 * Unsharp Mask renderer
2682 ochain[0] = new d2::usm(ochain[0], scale_factor,
2683 usm_multiplier, inc, response[psf_linear],
2684 response[psf_nonlinear], &input_exposure[0]);
2686 #endif
2688 if (psf_match) {
2691 * Point-spread function calibration renderer.
2692 * This renderer does not produce image output.
2693 * It is reserved for use with the point-spread
2694 * function calibration script
2695 * ale-psf-calibrate.
2698 ochain[0] = new d2::psf_calibrate(ochain[0],
2699 1, inc, response[psf_linear],
2700 response[psf_nonlinear],
2701 psf_match_args);
2703 } else if (ip_iterations != 0) {
2706 * Irani-Peleg renderer
2709 ochain[0] = new d2::ipc( ochain[0], ip_iterations,
2710 inc, response[psf_linear],
2711 response[psf_nonlinear],
2712 (exposure_register == 1), ip_use_median, ipwl);
2716 * Iterate through all files.
2719 for (unsigned int j = 0; j < d2::image_rw::count(); j++) {
2722 * Iterate through non-global options
2725 environment *env = files[j].second;
2727 for (std::map<const char *, const char *>::iterator i = env->get_map().begin();
2728 i != env->get_map().end(); i++) {
2730 if (!env->is_option(i->first))
2731 continue;
2733 const char *option_name = env->get_option_name(i->first);
2735 if (!strcmp(option_name, "mc")) {
2736 int type = env->get_int_arg(i->first, 0);
2737 d2::align::mc((type == 2) ? env->get_double_arg(i->first, 1) / 100
2738 : (double) type);
2739 } else if (!strcmp(option_name, "ma-card")) {
2740 int card = env->get_int_arg(i->first, 1);
2741 if (card < 1)
2742 ui::get()->error("--ma-card requires a positive integer");
2743 d2::align::ma_card(card);
2744 } else if (!strcmp(option_name, "ma-cont")) {
2745 d2::align::ma_cont(env->get_double_arg(i->first, 1));
2746 } else if (!strcmp(option_name, "gs")) {
2747 d2::align::gs(env->get_string_arg(i->first, 1));
2748 } else if (!strcmp(option_name, "gs-mo")) {
2749 const char *option = env->get_string_arg(i->first, 1);
2750 double gs_mo;
2751 int characters;
2752 sscanf(option, "%lf%n", &gs_mo, &characters);
2753 if (*(option + characters) == '%')
2754 d2::align::gs_mo(gs_mo, 1);
2755 else
2756 d2::align::gs_mo(gs_mo, 0);
2757 } else if (!strcmp(option_name, "ev")) {
2758 double ev = env->get_double_arg(i->first, 1);
2759 double gain_value = pow(2, -ev);
2761 if (j == 0)
2762 d2::exposure::set_gain_reference(gain_value);
2763 else
2764 input_exposure[j]->set_gain_multiplier(
2765 d2::exposure::get_gain_reference()
2766 / gain_value);
2768 } else if (!strcmp(option_name, "black")) {
2769 double black = env->get_double_arg(i->first, 1);
2770 input_exposure[j]->set_black_level(black);
2771 } else if (!strcmp(option_name, "mcd-removal")) {
2772 d2::align::mcd_limit(env->get_int_arg(i->first, 1));
2773 } else if (!strcmp(option_name, "perturb-upper")) {
2774 const char *option = env->get_string_arg(i->first, 1);
2775 double perturb_upper;
2776 int characters;
2777 sscanf(option, "%lf%n", &perturb_upper, &characters);
2778 if (*(option + characters) == '%')
2779 d2::align::set_perturb_upper(perturb_upper, 1);
2780 else
2781 d2::align::set_perturb_upper(perturb_upper, 0);
2782 } else if (!strcmp(option_name, "threads")) {
2783 thread::set_count((unsigned int) env->get_int_arg(i->first, 1));
2784 } else if (!strcmp(option_name, "per-cpu")) {
2785 thread::set_per_cpu((unsigned int) env->get_int_arg(i->first, 1));
2786 } else {
2788 * This error should be encountered earlier.
2791 assert(0);
2793 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
2794 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
2795 option_name);
2796 exit(1);
2802 if (j == 0) {
2804 * Handle the original frame.
2807 // ui::get()->original_frame_start(argv[i]);
2808 ui::get()->original_frame_start(files[0].first);
2810 for (int opt = 0; opt < oc_count; opt++) {
2811 ui::get()->set_orender_current(opt);
2812 ochain[opt]->sync(0);
2813 if (inc) {
2814 ui::get()->writing_output(opt);
2815 d2::image_rw::write_image(ochain_names[opt],
2816 ochain[opt]->get_image(0));
2820 d2::vise_core::frame_queue_add(0);
2822 ui::get()->original_frame_done();
2824 continue;
2828 * Handle supplemental frames.
2831 const char *name = d2::image_rw::name(j);
2833 ui::get()->supplemental_frame_start(name);
2836 * Write comment information about the
2837 * supplemental frame to the transformation
2838 * save file, if we have one.
2841 tsave_info (tsave, name);
2843 const d2::image *im = d2::image_rw::open(j);
2844 d2::pixel apm = im->avg_channel_magnitude();
2845 tsave_apm(tsave, apm[0], apm[1], apm[2]);
2846 d2::image_rw::close(j);
2848 for (int opt = 0; opt < oc_count; opt++) {
2849 ui::get()->set_orender_current(opt);
2850 ochain[opt]->sync(j);
2851 if (inc) {
2852 ui::get()->writing_output(opt);
2853 d2::image_rw::write_image(ochain_names[opt],
2854 ochain[opt]->get_image(j));
2858 d2::vise_core::frame_queue_add(j);
2860 ui::get()->supplemental_frame_done();
2864 * Do any post-processing and output final image
2866 * XXX: note that non-incremental renderers currently
2867 * return zero for ochain[0]->sync(), since they write
2868 * output internally when inc != 0.
2871 for (int opt = 0; opt < oc_count; opt++)
2872 if ((ochain[opt]->sync() || !inc) && !psf_match)
2873 d2::image_rw::write_image(ochain_names[opt], ochain[opt]->get_image());
2876 * Output a summary match statistic.
2879 ui::get()->ale_2d_done((double) d2::align::match_summary());
2882 * Perform any 3D tasks
2885 optimizations::begin_3d_work();
2887 if (d3_count > 0) {
2889 ui::get()->d3_start();
2891 d3::align::init_angle(view_angle);
2893 ui::get()->d3_init_view_angle(view_angle / M_PI * 180);
2895 d3::align::init_from_d2();
2897 if (d3::cpf::count() > 0) {
2898 ui::get()->d3_control_point_solve();
2899 d3::cpf::solve_3d();
2900 ui::get()->d3_control_point_solve_done();
2903 ui::get()->d3_final_view_angle(d3::align::angle_of(0) / M_PI * 180);
2905 d3::align::write_alignments();
2907 d3::scene::set_filter_type(d3chain_type);
2909 d3::scene::init_from_d2();
2911 ui::get()->d3_subdividing_space();
2912 d3::scene::make_space(d3_depth, d3_output, &d3_depth_pt, &d3_output_pt);
2913 ui::get()->d3_subdividing_space_done();
2915 ui::get()->d3_updating_occupancy();
2916 d3::scene::reduce_cost_to_search_depth(output_exposure, inc);
2917 ui::get()->d3_updating_occupancy_done();
2919 d3::scene::d3px(d3px_count, d3px_parameters);
2920 int view_count = 0;
2921 for (unsigned int i = 0; i < d2::image_rw::count(); i++) {
2922 assert (i < d3_count);
2924 if (d3_depth[i] != NULL) {
2925 ui::get()->d3_writing_output(d3_depth[i]);
2926 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2927 const d2::image *im = d3::scene::depth(i);
2928 d2::image_rw::write_image(d3_depth[i], im, output_exposure, 1, 1);
2929 delete im;
2930 ui::get()->d3_writing_output_done();
2933 if (d3_output[i] != NULL) {
2934 ui::get()->d3_writing_output(d3_output[i]);
2935 const d2::image *im = d3::scene::view(i);
2936 d2::image_rw::write_image(d3_output[i], im, output_exposure);
2937 delete im;
2938 d3::focus::set_camera(view_count++);
2939 ui::get()->d3_writing_output_done();
2942 for (std::map<const char *, d3::pt>::iterator i = d3_output_pt.begin();
2943 i != d3_output_pt.end(); i++) {
2945 ui::get()->d3_writing_output(i->first);
2946 const d2::image *im = d3::scene::view(i->second);
2947 d2::image_rw::write_image(i->first, im, output_exposure);
2948 delete im;
2949 d3::focus::set_camera(view_count++);
2950 ui::get()->d3_writing_output_done();
2953 for (std::map<const char *, d3::pt>::iterator i = d3_depth_pt.begin();
2954 i != d3_depth_pt.end(); i++) {
2956 ui::get()->d3_writing_output(i->first);
2957 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2958 const d2::image *im = d3::scene::depth(i->second);
2959 d2::image_rw::write_image(i->first, im, output_exposure, 1, 1);
2960 delete im;
2961 ui::get()->d3_writing_output_done();
2965 for (unsigned int i = d2::image_rw::count(); i < d3_count; i++) {
2966 if (d3_depth[i] != NULL) {
2967 fprintf(stderr, "\n\n*** Frame number for --3dd too high. ***\n\n");
2969 if (d3_output[i] != NULL) {
2970 fprintf(stderr, "\n\n*** Frame number for --3dv too high. ***\n\n");
2976 * Destroy the image file handler
2979 d2::image_rw::destroy();
2982 * Delete the transformation file structures, if any
2983 * exist.
2986 tsave_delete(tsave);
2987 tload_delete(tload);
2990 * We're done.
2993 exit(0);
2997 #endif