ale, gpu.h, gpu.cc: Add code for initializing the GPU with GLUT, as well
[Ale.git] / ui / input.h
blob1e6c36ce86871354cbe245e1baab25105e841d53
1 // Copyright 2002, 2003, 2004, 2005, 2006 David Hilvert <dhilvert@auricle.dyndns.org>,
2 // <dhilvert@ugcs.caltech.edu>
4 /* This file is part of the Anti-Lamenessing Engine.
6 The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 The Anti-Lamenessing Engine is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with the Anti-Lamenessing Engine; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #ifndef __input_h__
22 #define __input_h__
25 * ANSI C and POSIX include files.
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <assert.h>
32 #include <time.h>
33 // #include <math.h>
34 #include <stack>
35 #include <map>
37 #include "../ale_math.h"
40 * Interface files
43 #include "ui.h"
44 #include "accel.h"
45 #include "unsupported.h"
46 #include "implication.h"
49 * Configuration
52 #if HAVE_CONFIG_H
53 # include <config.h>
54 #endif
57 * GNU extensions
60 extern "C" {
61 #include "string_.h"
65 * Types
68 #include "../ale_pos.h"
69 #include "../ale_real.h"
72 * 2D include files
75 #include "../d2.h"
78 * 3D include files
81 #include "../d3.h"
84 * Thread include files
87 #include "../thread.h"
90 * Device configuration files
93 #include "../device/xvp610_320x240.h"
94 #include "../device/xvp610_640x480.h"
95 #include "../device/ov7620_raw_linear.h"
96 #include "../device/canon_300d_raw_linear.h"
97 #include "../device/canon_300d_raw_linear_85mm_1_8.h"
98 #include "../device/canon_300d_raw_linear_50mm_1_8.h"
99 #include "../device/canon_300d_raw_linear_50mm_1_4.h"
100 #include "../device/canon_300d_raw_linear_50mm_1_4_1_4.h"
101 #include "../device/nikon_d50.h"
104 * Help files
107 #include "help.h"
109 class input {
112 * Flag for global options.
115 static int global_options;
118 * Helper functions.
122 * Argument counter.
124 * Counts instances of a given option.
126 static unsigned int arg_count(int argc, const char *argv[], const char *arg) {
127 unsigned int count = 0;
128 for (int i = 0; i < argc; i++) {
129 if (!strcmp(argv[i], arg))
130 count++;
131 else if (!strcmp(argv[i], "--"))
132 return count;
134 return count;
138 * Argument prefix counter.
140 * Counts instances of a given option prefix.
142 static unsigned int arg_prefix_count(int argc, const char *argv[], const char *pfix) {
143 unsigned int count = 0;
144 for (int i = 0; i < argc; i++) {
145 if (!strncmp(argv[i], pfix, strlen(pfix)))
146 count++;
147 else if (!strcmp(argv[i], "--"))
148 return count;
150 return count;
154 * Reallocation function
156 static void *local_realloc(void *ptr, size_t size) {
157 void *new_ptr = realloc(ptr, size);
159 if (new_ptr == NULL)
160 ui::get()->memory_error_location("main()");
162 return new_ptr;
166 * Not enough arguments function.
168 static void not_enough(const char *opt_name) {
169 ui::get()->cli_not_enough(opt_name);
173 * Bad argument function
175 static void bad_arg(const char *opt_name) {
176 ui::get()->cli_bad_arg(opt_name);
180 * String comparison class.
183 class compare_strings {
184 public:
185 int operator()(const char *A, const char *B) const {
186 return strcmp(A, B) < 0;
191 * Environment structures.
193 * XXX: It's arguable that these should be public members of the
194 * 'input' class in order to allow passing environment values to other
195 * classes, but, since we're currently using them only to prepare state
196 * for an internal 'input' function, they can stay private for now. A
197 * more nuanced approach will likely be required later.
200 class environment {
201 static std::stack<environment *> environment_stack;
202 static std::set<environment *> environment_set;
204 std::map<const char *, const char *, compare_strings> environment_map;
207 * Internal set operations do not protect any data.
210 void internal_set(const char *name, const char *value) {
211 environment_map[name] = value;
214 void internal_unset(const char *name) {
215 environment_map.erase(name);
218 const char *internal_convert_pointer(const void *pointer) {
219 int chars = sizeof(void *) * 2 + 3;
220 char *c = (char *) malloc(sizeof(char) * chars);
222 assert(c);
224 if (!c)
225 ui::get()->memory_error_location("environment::set_ptr");
227 int count = snprintf(c, chars, "%p", pointer);
229 assert (count >= 0 && count < chars);
231 return c;
234 void internal_set_ptr(const char *name, const void *pointer) {
235 internal_set(name, internal_convert_pointer(pointer));
239 * Check for restricted names.
242 int name_ok(const char *name) {
243 if (!strcmp(name, "---chain") || !strcmp(name, "---this"))
244 return 0;
246 return 1;
249 void name_check(const char *name) {
250 if (!name_ok(name)) {
251 fprintf(stderr, "Bad set operation.");
252 assert(0);
253 exit(1);
257 public:
260 * Get the environment map.
263 std::map<const char *, const char *, compare_strings> &get_map() {
264 return environment_map;
268 * Public set operations restrict valid names.
271 void set(const char *name, const char *value) {
272 name_check(name);
273 internal_set(name, value);
276 void unset(const char *name) {
277 name_check(name);
278 internal_unset(name);
281 void set_ptr(const char *name, const void *pointer) {
282 name_check(name);
283 internal_set_ptr(name, pointer);
286 const char *get(const char *name) {
287 if (environment_map.count(name) == 0)
288 return NULL;
290 return environment_map[name];
294 * Make an environment substructure. Note that since deep
295 * structures are currently referenced rather than copied when
296 * the stack is pushed, there is no current need for any
297 * chaining mechanism.
299 void make_substructure(const char *name) {
300 environment *s = new environment;
301 set_ptr(name, s);
302 environment_set.insert(s);
305 static int is_env(const char *name) {
306 void *ptr_value;
307 sscanf(name, "%p", &ptr_value);
310 * Check for bad pointers.
313 if (!environment_set.count((environment *) ptr_value)) {
314 return 0;
317 return 1;
320 const char *get_option_name(const char *name) {
321 if (strncmp(name, "0 ", strlen("0 ")))
322 return NULL;
324 name += strlen("0 ");
326 if (!isdigit(name[0]))
327 return NULL;
329 while (isdigit(name[0]))
330 name++;
332 if (!isspace(name[0]))
333 return NULL;
335 while (isspace(name[0]))
336 name++;
338 if (!isalnum(name[0]))
339 return NULL;
341 return name;
344 int is_option(const char *name) {
345 return (get_option_name(name) != NULL);
348 int is_arg(const char *name, unsigned int arg) {
349 assert (is_option(name));
351 int length = strlen(name) + 3 * sizeof(unsigned int);
353 char *desired_string = (char *) malloc(sizeof(char) * length);
355 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
357 int result = environment_map.count(desired_string);
359 free(desired_string);
361 return result > 0;
364 void remove_arg(const char *name, unsigned int arg) {
365 assert (is_option(name));
366 assert (is_arg(name, arg));
368 int length = strlen(name) + 3 * sizeof(unsigned int);
370 char *desired_string = (char *) malloc(sizeof(char) * length);
372 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
374 environment_map.erase(desired_string);
377 const char *get_string_arg(const char *name, unsigned int arg) {
378 assert (is_option(name));
380 int length = strlen(name) + 3 * sizeof(unsigned int);
382 char *desired_string = (char *) malloc(sizeof(char) * length);
384 snprintf(desired_string, length, "%u %s", arg, name + strlen("0 "));
386 const char *result = environment_map[desired_string];
388 assert (result);
390 free(desired_string);
392 return result;
395 long int get_long_arg(const char *name, unsigned int arg) {
396 assert (is_option(name));
398 const char *string = get_string_arg(name, arg);
399 char *endptr;
401 long int result = strtol(string, &endptr, 0);
403 if (endptr[0] != '\0') {
404 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
405 exit(1);
408 return result;
411 int get_int_arg(const char *name, unsigned int arg) {
412 return (int) get_long_arg(name, arg);
415 unsigned int get_unsigned_arg(const char *name, unsigned int arg) {
416 long int result = get_long_arg(name, arg);
418 if (result < 0) {
419 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
420 exit(1);
423 return (unsigned int) result;
426 double get_double_arg(const char *name, unsigned int arg) {
427 assert (is_option(name));
429 const char *string = get_string_arg(name, arg);
430 char *endptr;
432 double result = strtod(string, &endptr);
434 if (endptr[0] != '\0') {
435 fprintf(stderr, "\n\nError: bad argument in `%s'.\n\n", get_option_name(name));
436 exit(1);
439 return result;
442 static environment *get_env(const char *name) {
444 assert(name);
446 void *ptr_value;
447 sscanf(name, "%p", &ptr_value);
450 * Check for bad pointers.
453 if (!environment_set.count((environment *) ptr_value)) {
454 assert(0);
455 fprintf(stderr, "Bad environment pointer.\n");
456 exit(1);
459 return (environment *) ptr_value;
463 * Prepend to a list.
465 void prepend(const char *list, const char *element) {
466 environment *d = get_env(get(list));
467 make_substructure(list);
468 get_env(get(list))->set("a", element);
469 get_env(get(list))->set_ptr("d", d);
472 void prepend_ptr(const char *list, void *ptr) {
473 prepend(list, internal_convert_pointer(ptr));
477 * Clone the environment.
479 environment *clone() {
480 environment *e = new environment();
482 for (std::map<const char *, const char *, compare_strings>::iterator i = environment_map.begin();
483 i != environment_map.end(); i++) {
485 if (!name_ok(i->first))
486 continue;
488 if (is_env(i->second)) {
489 e->set_ptr(i->first, get_env(i->second)->clone());
490 } else {
491 e->set(i->first, i->second);
495 return e;
498 static environment *top() {
499 if (environment_stack.empty()) {
500 environment_stack.push(new environment);
501 environment_set.insert(environment_stack.top());
503 return environment_stack.top();
506 static void push() {
507 environment *e = new environment;
509 e->environment_map = environment_stack.top()->environment_map;
511 e->internal_set_ptr("---chain", environment_stack.top());
512 e->internal_set_ptr("---this", e);
513 e->make_substructure("---dup");
515 environment_stack.push(e);
516 environment_set.insert(e);
519 static void dup_second() {
520 environment_stack.top()->prepend_ptr("---dup",
521 environment::get_env(environment_stack.top()->get("---chain")));
524 static void push_and_dup_output() {
525 push();
526 dup_second();
529 static void pop() {
530 assert(!environment_stack.empty());
533 * Execution environments should never be referenced by
534 * structures further up the call chain, so they can
535 * safely be deleted. (XXX: In particular, while
536 * lexical scoping may require copying of execution
537 * environments from lower on the call chain, there is
538 * no obvious reason that a reference should be used in
539 * this case; a shallow copy should be used instead.)
542 environment_set.erase(environment_stack.top());
543 delete environment_stack.top();
545 environment_stack.pop();
549 * Set with duplication.
552 void set_with_dup(const char *name, const char *value) {
553 set(name, value);
555 if (!get("---dup"))
556 return;
558 environment *dup_item = get_env(get("---dup"));
560 assert (dup_item);
562 while (dup_item->get("a")) {
563 get_env(dup_item->get("a"))->set_with_dup(name, value);
564 assert(dup_item->get("d"));
565 dup_item = get_env(dup_item->get("d"));
566 assert(dup_item);
572 * Read tokens from a stream.
574 class token_reader {
575 public:
577 * Get the next token
579 virtual const char *get() = 0;
582 * Peek at the next token.
585 virtual const char *peek() = 0;
588 * Divert the stream until the next occurrence of TOKEN.
590 virtual token_reader *divert(const char *open_token, const char *close_token) = 0;
592 virtual int expects_exactly_one_option(void) {
593 return 0;
596 virtual ~token_reader() {
600 class argument_parsing_token_reader : public token_reader {
601 const char *index;
602 const char *separators;
603 public:
604 argument_parsing_token_reader(const char *s) {
605 index = s;
606 separators = "=";
609 int expects_exactly_one_option(void) {
610 return 1;
613 virtual const char *get() {
614 int length = strcspn(index, separators);
616 if (length == 0)
617 return NULL;
619 const char *result = strndup(index, length);
620 index += length;
622 if (strspn(index, separators) >= 1)
623 index++;
625 separators = ",";
627 return result;
630 virtual const char *peek() {
631 int length = strcspn(index, separators);
633 if (length == 0)
634 return NULL;
636 const char *result = strndup(index, length);
638 return result;
641 virtual token_reader *divert(const char *open_token, const char *close_token) {
642 assert(0);
643 return NULL;
647 class cstring_token_reader : public token_reader {
648 const char *separators;
649 const char *string;
650 int ephemeral;
652 cstring_token_reader(const char *s, int ephemeral) {
653 assert(ephemeral == 1);
655 separators = "\n \t";
656 string = s;
657 this->ephemeral = 1;
660 public:
661 cstring_token_reader(const char *s) {
662 separators = "\n \t";
663 string = s;
664 ephemeral = 0;
667 const char *get() {
669 string += strspn(string, separators);
671 size_t length_to_next = strcspn(string, separators);
673 if (length_to_next == 0)
674 return NULL;
676 const char *result = strndup(string, length_to_next);
678 string += length_to_next;
680 return result;
683 const char *peek() {
684 string += strspn(string, separators);
686 size_t length_to_next = strcspn(string, separators);
688 if (length_to_next == 0)
689 return NULL;
691 return strndup(string, length_to_next);
694 cstring_token_reader *divert(const char *open_token, const char *close_token) {
696 * This function might be broken.
699 assert(0);
701 int search = 0;
702 int next = strcspn(string, separators);
703 int depth = 0;
705 while (*(string + search) != '\0' &&
706 (depth || strcmp(close_token, (string + search)))) {
707 if (!strcmp(close_token, (string + search)))
708 depth--;
709 if (!strcmp(open_token, (string + search)))
710 depth++;
711 search = next;
712 next = strcspn((string + next), separators);
715 if (*(string + search) == '\0') {
716 fprintf(stderr, "Parse error: End of scope not found.");
717 exit(1);
720 cstring_token_reader *result = new cstring_token_reader(strndup(string, search), 1);
722 string += search;
725 * Eat the closing token.
728 get();
730 return result;
733 ~cstring_token_reader() {
734 if (ephemeral)
735 free((void *) string);
739 class cli_token_reader : public token_reader {
741 int arg_index;
742 int argc;
743 const char **argv;
745 public:
746 cli_token_reader(int c, const char *v[]) {
747 argc = c;
748 argv = v;
749 arg_index = 0;
752 const char *get() {
754 if (arg_index < argc)
755 return argv[arg_index++];
756 else
757 return NULL;
761 const char *peek() {
763 if (arg_index < argc)
764 return argv[arg_index];
765 else
766 return NULL;
770 cli_token_reader *divert(const char *open_token, const char *close_token) {
771 int search = 0;
772 int depth = 0;
774 while (arg_index + search < argc
775 && (depth || strcmp(argv[arg_index + search], close_token))) {
776 if (!strcmp(close_token, argv[arg_index + search]))
777 depth--;
778 if (!strcmp(open_token, argv[arg_index + search]))
779 depth++;
780 search++;
783 if (arg_index + search == argc) {
784 fprintf(stderr, "Parse error: end of scope not found.\n");
785 exit(1);
788 cli_token_reader *result = new cli_token_reader(search, argv + arg_index);
790 arg_index += search;
793 * Eat the closing token.
796 get();
798 return result;
803 struct simple_option {
804 const char *name;
805 const char *map_name;
806 const char *map_value;
807 int arg_count;
808 int multi;
811 static const char *supported_nonglobal_option_table[];
812 static const char *focus_prefixes[];
813 static simple_option simple_option_table[];
815 static int option_name_match(const char *unadorned, const char *token, int require_ornamentation = 1) {
816 int strip_max = 2;
818 if (!strcmp(unadorned, token) && !require_ornamentation)
819 return 1;
821 while (token[0] == '-' && strip_max) {
822 token++;
823 strip_max--;
824 if (!strcmp(unadorned, token))
825 return 1;
828 return 0;
831 static int is_scope_operator(const char *string) {
832 if (!strcmp("{", string)
833 || !strcmp("}", string)
834 || !strcmp("[", string)
835 || !strcmp("]", string)
836 || !strcmp("<", string)
837 || !strcmp(">", string))
838 return 1;
840 return 0;
843 static const char *option_name_gen(const char *unadorned, const char *map_name, int arg_num, int multi) {
844 static unsigned int multi_counter = 0;
846 if (map_name) {
847 unadorned = map_name;
850 int length = (strlen(unadorned) + sizeof(unsigned int) * 3 + sizeof(int) * 3 + 2) + 1;
852 char *result = (char *) malloc(sizeof(char) * length);
854 assert (result);
856 if (!multi) {
857 snprintf(result, length, "%u 0 %s", arg_num, unadorned);
858 } else {
861 * XXX: This assumes that generating calls for
862 * options other than 0 exist in the same
863 * multiplicity group as the most recently
864 * generated 0-option multiplicity.
867 if (arg_num == 0)
868 multi_counter++;
870 snprintf(result, length, "%u %u %s", arg_num, multi_counter, unadorned);
873 return result;
876 static environment *genv;
878 static const char *get_next(token_reader *tr, const char *option_name) {
879 const char *argument = tr->get();
881 if (argument == NULL) {
882 fprintf(stderr, "\n\nError: not enough arguments for `%s'.\n\n", option_name);
883 exit(1);
886 return argument;
889 static int table_contains(const char **haystack, const char *needle, int prefix_length = 0) {
891 if (needle == NULL)
892 return 0;
894 while (*haystack != NULL) {
895 if (prefix_length == 0 && !strcmp(*haystack, needle))
896 return 1;
897 if (prefix_length > 0 && !strncmp(*haystack, needle, prefix_length))
898 return 1;
899 haystack++;
902 return 0;
905 static int option_is_identical(environment *a, environment *b, const char *option_name) {
906 if (!a->is_option(option_name) || !b->is_option(option_name))
907 return 0;
909 int option_number = 0;
911 while (a->is_arg(option_name, option_number) || b->is_arg(option_name, option_number)) {
912 if (!a->is_arg(option_name, option_number)
913 || !b->is_arg(option_name, option_number))
914 return 0;
916 const char *a_str = a->get_string_arg(option_name, option_number);
917 const char *b_str = b->get_string_arg(option_name, option_number);
919 if (strcmp(a_str, b_str))
920 return 0;
922 option_number++;
925 return 1;
928 static void remove_option(environment *a, const char *option_name) {
929 assert(a->is_option(option_name));
931 int option_number = 0;
933 while (a->is_arg(option_name, option_number)) {
934 a->remove_arg(option_name, option_number);
935 option_number++;
939 static void remove_nonglobals(environment *a) {
940 assert(a);
942 std::stack<const char *> removal_stack;
944 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
945 i != a->get_map().end(); i++) {
947 if (!a->is_option(i->first))
948 continue;
950 if (!table_contains(supported_nonglobal_option_table, a->get_option_name(i->first)))
951 continue;
953 removal_stack.push(i->first);
956 while (!removal_stack.empty()) {
957 remove_option(a, removal_stack.top());
958 removal_stack.pop();
962 static void option_intersect(environment *a, environment *b) {
963 assert(a);
964 assert(b);
966 std::stack<const char *> removal_stack;
968 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
969 i != a->get_map().end(); i++) {
971 if (!a->is_option(i->first))
972 continue;
974 if (option_is_identical(a, b, i->first))
975 continue;
977 removal_stack.push(i->first);
980 while (!removal_stack.empty()) {
981 remove_option(a, removal_stack.top());
982 removal_stack.pop();
986 static void option_difference(environment *a, environment *b) {
987 assert(a);
988 assert(b);
990 std::stack<const char *> removal_stack;
992 for (std::map<const char *, const char *, compare_strings>::iterator i = a->get_map().begin();
993 i != a->get_map().end(); i++) {
995 if (!a->is_option(i->first))
996 continue;
998 if (!option_is_identical(a, b, i->first))
999 continue;
1001 removal_stack.push(i->first);
1004 while (!removal_stack.empty()) {
1005 remove_option(a, removal_stack.top());
1006 removal_stack.pop();
1010 static void evaluate_stream(token_reader *tr,
1011 std::vector<std::pair<const char *, environment *> > *files) {
1012 const char *token;
1013 int end_of_options = 0;
1015 while ((token = tr->get())) {
1018 * Check for nesting
1021 if (!strcmp(token, "{") && !end_of_options) {
1022 environment::push_and_dup_output();
1023 token_reader *tr_nest = tr->divert("{", "}");
1024 evaluate_stream(tr_nest, files);
1025 delete tr_nest;
1026 environment::pop();
1027 } else if (!strcmp(token, "[") && !end_of_options) {
1028 global_options = 0;
1029 environment::push();
1030 token_reader *tr_nest = tr->divert("[", "]");
1031 evaluate_stream(tr_nest, files);
1032 delete tr_nest;
1033 environment::pop();
1034 } else if (!strcmp(token, "<") && !end_of_options) {
1035 environment *dup_list = environment::get_env(environment::top()->get("---dup"));
1036 assert (dup_list != NULL);
1037 dup_list = dup_list->clone();
1039 environment::dup_second();
1040 token_reader *tr_nest = tr->divert("<", ">");
1041 evaluate_stream(tr_nest, files);
1042 delete tr_nest;
1044 environment::top()->set_ptr("---dup", dup_list);
1048 * Check for non-whitespace argument separators
1051 else if (!end_of_options && token && token[0] == '-' && strchr(token, '=')) {
1052 environment::push_and_dup_output();
1053 token_reader *tr_nest = new argument_parsing_token_reader(token);
1054 evaluate_stream(tr_nest, files);
1055 delete tr_nest;
1056 environment::pop();
1060 * Trap the end-of-option indicator.
1063 else if (!strcmp(token, "--")) {
1064 global_options = 0;
1065 end_of_options = 1;
1069 * Check for options and filenames
1072 else {
1074 * Handle filenames.
1077 if (strncmp("-", token, strlen("-")) || end_of_options) {
1079 assert(files);
1081 global_options = 0;
1082 files->push_back(std::pair<const char *, environment *>(strdup(token),
1083 environment::top()->clone()));
1085 if (tr->expects_exactly_one_option() && tr->get()) {
1086 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1087 exit(1);
1090 continue;
1094 * Handle focus option.
1097 if (option_name_match("focus", token)) {
1099 environment *target;
1100 target = environment::top();
1102 target->set_with_dup(option_name_gen("focus", NULL, 0, 0), "1");
1104 const char *option = get_next(tr, "focus");
1106 target->set_with_dup(option_name_gen("focus", NULL, 1, 0), option);
1108 if (!strcmp(option, "d")) {
1109 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1110 get_next(tr, "focus"));
1111 } else if (!strcmp(option, "p")) {
1112 target->set_with_dup(option_name_gen("focus", NULL, 2, 0),
1113 get_next(tr, "focus"));
1114 target->set_with_dup(option_name_gen("focus", NULL, 3, 0),
1115 get_next(tr, "focus"));
1116 } else
1117 bad_arg("focus");
1119 int arg = 0;
1121 while (table_contains(focus_prefixes, tr->peek(), 3)) {
1122 target->set_with_dup(option_name_gen("focus", NULL, 4 + arg, 0),
1123 get_next(tr, "focus"));
1124 arg++;
1127 continue;
1131 * Handle simple options.
1134 int found_option = 0;
1135 for (int i = 0; simple_option_table[i].name; i++) {
1136 if (!option_name_match(simple_option_table[i].name, token))
1137 continue;
1140 * Handle the match case.
1143 found_option = 1;
1146 * Determine which environment should be modified
1149 environment *target;
1150 target = environment::top();
1153 * Store information required for
1154 * handling the local case later.
1157 const char *map_value = "1";
1159 if (simple_option_table[i].map_value) {
1160 map_value = simple_option_table[i].map_value;
1161 } else if (simple_option_table[i].map_name) {
1162 map_value = simple_option_table[i].name;
1165 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1166 simple_option_table[i].map_name,
1168 simple_option_table[i].multi),
1169 map_value);
1171 for (int j = 0; j < simple_option_table[i].arg_count; j++) {
1172 const char *option = tr->get();
1174 if (option == NULL) {
1175 fprintf(stderr, "\n\nError: not enough options for `%s'.\n\n", token);
1176 exit(1);
1180 * Reject scope operators as options,
1181 * at least for now.
1184 if (is_scope_operator(option)) {
1185 fprintf(stderr, "\n\nError: illegal argument to `%s'.\n\n", token);
1186 exit(1);
1189 target->set_with_dup(option_name_gen(simple_option_table[i].name,
1190 simple_option_table[i].map_name,
1191 j + 1,
1192 simple_option_table[i].multi),
1193 option);
1198 * Trap illegal options.
1201 if (!found_option)
1202 ui::get()->illegal_option(token);
1205 if (tr->expects_exactly_one_option() && tr->get()) {
1206 fprintf(stderr, "\n\nError: Too many arguments for `%s'.\n\n", token);
1207 exit(1);
1212 public:
1214 * Input handler.
1216 * Does one of two things:
1218 * (1) Output version information if called with '--version'
1220 * (2) Read options and file arguments, and if the arguments are correct,
1221 * write output. If an error is detected, print the usage statement.
1225 static void handle(int argc, const char *argv[], const char *package, const char *short_version, const char *version) {
1228 * Initialize help object
1231 help hi(package, argv[0], short_version);
1234 * Output version information if --version appears
1235 * on the command line.
1238 if (arg_count(argc, argv, "--version")) {
1240 * Output the version
1243 fprintf(stdout, "%s", version);
1246 * Output relevant environment variables
1249 fprintf(stdout, "Environment:\n");
1251 const char *env_names[] = {
1252 "ALE_BIN",
1253 "DCRAW",
1254 "EXIF_UTILITY",
1255 "ALE_COUNT_THREADS",
1256 "PAGER",
1257 "ALE_SOFT_GPU",
1258 "ALE_GL_UI_DEFAULT",
1259 "ALE_GPU_ACCEL_DEFAULT",
1260 NULL
1263 for (int i = 0; env_names[i]; i++) {
1264 char *value = getenv(env_names[i]);
1266 fprintf(stdout, " %s=%s\n",
1267 env_names[i], value ? value : "");
1270 return;
1274 * Handle help options
1277 if (arg_prefix_count(argc, argv, "--h"))
1278 for (int i = 1; i < argc; i++) {
1279 int all = !strcmp(argv[i], "--hA");
1280 int is_help_option = !strncmp(argv[i], "--h", strlen("--h"));
1281 int found_help = 0;
1283 if (!strcmp(argv[i], "--hu") || all)
1284 hi.usage(), found_help = 1;
1285 if (!strcmp(argv[i], "--hq") || all)
1286 hi.defaults(), found_help = 1;
1287 if (!strcmp(argv[i], "--hf") || all)
1288 hi.file(), found_help = 1;
1289 if (!strcmp(argv[i], "--he") || all)
1290 hi.exclusion(), found_help = 1;
1291 if (!strcmp(argv[i], "--ha") || all)
1292 hi.alignment(), found_help = 1;
1293 if (!strcmp(argv[i], "--hr") || all)
1294 hi.rendering(), found_help = 1;
1295 if (!strcmp(argv[i], "--hx") || all)
1296 hi.exposure(), found_help = 1;
1297 if (!strcmp(argv[i], "--ht") || all)
1298 hi.tdf(), found_help = 1;
1299 if (!strcmp(argv[i], "--hl") || all)
1300 hi.filtering(), found_help = 1;
1301 if (!strcmp(argv[i], "--hd") || all)
1302 hi.device(), found_help = 1;
1303 if (!strcmp(argv[i], "--hi") || all)
1304 hi.interface(), found_help = 1;
1305 if (!strcmp(argv[i], "--hv") || all)
1306 hi.visp(), found_help = 1;
1307 if (!strcmp(argv[i], "--hc") || all)
1308 hi.cp(), found_help = 1;
1309 if (!strcmp(argv[i], "--h3") || all)
1310 hi.d3(), found_help = 1;
1311 if (!strcmp(argv[i], "--hs") || all)
1312 hi.scope(), found_help = 1;
1313 if (!strcmp(argv[i], "--hp") || all)
1314 hi.process(), found_help = 1;
1315 if (!strcmp(argv[i], "--hz") || all)
1316 hi.undocumented(), found_help = 1;
1318 if (is_help_option && !found_help)
1319 hi.usage();
1322 * Check for the end-of-options marker, a non-option argument,
1323 * or the end of arguments. In all of these cases, we exit.
1326 if (!strcmp(argv[i], "--")
1327 || strncmp(argv[i], "--", strlen("--"))
1328 || i == argc - 1)
1329 return;
1333 * Undocumented projective transformation utility
1336 if (arg_count(argc, argv, "--ptcalc") > 0) {
1337 fprintf(stderr, "\n\n*** Warning: this feature is not documented ***\n\n");
1338 printf("Enter: w h tlx tly blx bly brx bry trx try x y\n\n");
1340 double w, h, tlx, tly, blx, bly, brx, bry, trx, tr_y, x, y;
1342 printf("> ");
1344 if (scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf",
1345 &w, &h, &tlx, &tly, &blx, &bly, &brx, &bry, &trx, &tr_y, &x, &y) != 12) {
1347 fprintf(stderr, "Error reading input.\n");
1348 exit(1);
1351 d2::image *i = d2::new_image_ale_real((int)h, (int)w, 3);
1352 d2::transformation t = d2::transformation::gpt_identity(i, 1);
1353 d2::point q[4] = {
1354 d2::point(tly, tlx),
1355 d2::point(bly, blx),
1356 d2::point(bry, brx),
1357 d2::point(tr_y, trx)
1359 t.gpt_set(q);
1361 d2::point a(y, x), b;
1363 b = t.transform_scaled(a);
1365 printf("TRANSFORM t(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1367 b = t.scaled_inverse_transform(a);
1369 printf("INVERSE t^-1(a): (%f, %f)\n", (double) b[1], (double) b[0]);
1371 exit(0);
1375 * Thread initialization.
1378 thread::init();
1381 * Flags and variables
1384 double scale_factor = 1;
1385 double vise_scale_factor = 1;
1386 #if 0
1387 double usm_multiplier = 0.0;
1388 #endif
1389 int extend = 0;
1390 struct d2::tload_t *tload = NULL;
1391 struct d2::tsave_t *tsave = NULL;
1392 struct d3::tload_t *d3_tload = NULL;
1393 struct d3::tsave_t *d3_tsave = NULL;
1394 int ip_iterations = 0;
1395 int ip_use_median = 0;
1396 double ipwl = 0;
1397 enum { psf_linear, psf_nonlinear, psf_N };
1398 const char *psf[psf_N] = {NULL, NULL};
1399 const char *device = NULL;
1400 int psf_match = 0;
1401 double psf_match_args[6];
1402 int inc = 0;
1403 int exposure_register = 1;
1404 const char *wm_filename = NULL;
1405 int wm_offsetx = 0, wm_offsety = 0;
1406 double cx_parameter = 1;
1407 double *d3px_parameters = NULL;
1408 int d3px_count = 0;
1409 d2::exclusion *ex_parameters = NULL;
1410 int ex_count = 0;
1411 int ex_show = 0;
1412 d2::render *achain;
1413 const char *achain_type = "triangle:2";
1414 const char *afilter_type = "internal";
1415 d2::render **ochain = NULL;
1416 const char **ochain_names = NULL;
1417 const char **ochain_types = NULL;
1418 const char *d3chain_type = NULL;
1419 int oc_count = 0;
1420 const char **visp = NULL;
1421 int vise_count = 0;
1422 const char **d3_output = NULL;
1423 const char **d3_depth = NULL;
1424 unsigned int d3_count = 0;
1425 double user_view_angle = 0;
1426 int user_bayer = IMAGE_BAYER_DEFAULT;
1427 d2::pixel exp_mult = d2::pixel(1, 1, 1);
1428 std::map<const char *, d3::pt> d3_output_pt;
1429 std::map<const char *, d3::pt> d3_depth_pt;
1432 * dchain is ochain[0].
1435 ochain = (d2::render **) local_realloc(ochain,
1436 (oc_count + 1) * sizeof(d2::render *));
1437 ochain_names = (const char **) local_realloc((void *)ochain_names,
1438 (oc_count + 1) * sizeof(const char *));
1439 ochain_types = (const char **) local_realloc((void *)ochain_types,
1440 (oc_count + 1) * sizeof(const char *));
1442 ochain_types[0] = "sinc*lanc:8";
1444 oc_count = 1;
1447 * Handle default settings
1450 if (arg_prefix_count(argc, argv, "--q") > 0)
1451 ui::get()->error("Default settings --q* are no longer recognized.");
1453 #define FIXED16 4
1454 #if ALE_COLORS == FIXED16
1455 const char *defaults =
1456 "--dchain auto:triangle:2,fine:box:1,triangle:2 "
1457 "--achain triangle:2 "
1458 "--ips 0 "
1459 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ";
1460 #else
1461 const char *defaults =
1462 "--dchain auto:triangle:2,fine:box:1,triangle:2 "
1463 "--achain triangle:2 "
1464 "--ips 1 "
1465 "--3d-chain fine:triangle:2,fine:gauss:0.75,triangle:2 ";
1466 #endif
1467 #undef FIXED16
1469 token_reader *default_reader = new cstring_token_reader(defaults);
1471 evaluate_stream(default_reader, NULL);
1474 * Set basic program information in the environment.
1477 environment::top()->set_with_dup("---package", package);
1478 environment::top()->set_with_dup("---short-version", short_version);
1479 environment::top()->set_with_dup("---version", version);
1480 environment::top()->set_with_dup("---invocation", argv[0]);
1483 * Initialize the top-level token-reader and generate
1484 * an environment variable for it.
1487 token_reader *tr = new cli_token_reader(argc - 1, argv + 1);
1488 environment::top()->set_ptr("---token-reader", tr);
1491 * Evaluate the command-line arguments to generate environment
1492 * structures.
1495 std::vector<std::pair<const char *, environment *> > files;
1497 evaluate_stream(tr, &files);
1500 * If there are fewer than two files, then output usage information.
1503 if (files.size() < 2) {
1504 hi.usage();
1505 exit(1);
1509 * Extract the global environment and check non-globals
1510 * against a list of supported non-global options.
1513 genv = files[0].second->clone();
1515 remove_nonglobals(genv);
1517 for (unsigned int i = 0; i < files.size(); i++) {
1518 option_intersect(genv, files[i].second);
1521 for (unsigned int i = 0; i < files.size(); i++) {
1522 option_difference(files[i].second, genv);
1524 for (std::map<const char *, const char *>::iterator j = files[i].second->get_map().begin();
1525 j != files[i].second->get_map().end(); j++) {
1527 environment *env = files[i].second;
1529 if (!env->is_option(j->first))
1530 continue;
1532 const char *option_name = env->get_option_name(j->first);
1534 if (!table_contains(supported_nonglobal_option_table, option_name)) {
1535 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
1536 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
1537 option_name);
1538 exit(1);
1544 * Iterate through the global environment,
1545 * looking for options.
1548 for (std::map<const char *, const char *>::iterator i = genv->get_map().begin();
1549 i != genv->get_map().end(); i++) {
1551 environment *env = genv;
1553 if (!env->is_option(i->first))
1554 continue;
1556 const char *option_name = env->get_option_name(i->first);
1558 if (!strcmp(option_name, "default")) {
1560 * Do nothing. Defaults have already been set.
1562 } else if (!strcmp(option_name, "bpc")) {
1563 if (!strcmp(env->get_string_arg(i->first, 0), "8bpc"))
1564 d2::image_rw::depth8();
1565 else if (!strcmp(env->get_string_arg(i->first, 0), "16bpc"))
1566 d2::image_rw::depth16();
1567 else
1568 assert(0);
1569 } else if (!strcmp(option_name, "format")) {
1570 if (!strcmp(env->get_string_arg(i->first, 0), "plain"))
1571 d2::image_rw::ppm_plain();
1572 else if (!strcmp(env->get_string_arg(i->first, 0), "raw"))
1573 d2::image_rw::ppm_raw();
1574 else if (!strcmp(env->get_string_arg(i->first, 0), "auto"))
1575 d2::image_rw::ppm_auto();
1576 else
1577 assert(0);
1578 } else if (!strcmp(option_name, "align")) {
1579 if (!strcmp(env->get_string_arg(i->first, 0), "align-all"))
1580 d2::align::all();
1581 else if (!strcmp(env->get_string_arg(i->first, 0), "align-green"))
1582 d2::align::green();
1583 else if (!strcmp(env->get_string_arg(i->first, 0), "align-sum"))
1584 d2::align::sum();
1585 else
1586 assert(0);
1587 } else if (!strcmp(option_name, "transformation")) {
1588 if (!strcmp(env->get_string_arg(i->first, 0), "translation"))
1589 d2::align::class_translation();
1590 else if (!strcmp(env->get_string_arg(i->first, 0), "euclidean"))
1591 d2::align::class_euclidean();
1592 else if (!strcmp(env->get_string_arg(i->first, 0), "projective"))
1593 d2::align::class_projective();
1594 else
1595 assert(0);
1596 } else if (!strcmp(option_name, "transformation-default")) {
1597 if (!strcmp(env->get_string_arg(i->first, 0), "identity"))
1598 d2::align::initial_default_identity();
1599 else if (!strcmp(env->get_string_arg(i->first, 0), "follow"))
1600 d2::align::initial_default_follow();
1601 else
1602 assert(0);
1603 } else if (!strcmp(option_name, "perturb")) {
1604 if (!strcmp(env->get_string_arg(i->first, 0), "perturb-output"))
1605 d2::align::perturb_output();
1606 else if (!strcmp(env->get_string_arg(i->first, 0), "perturb-source"))
1607 d2::align::perturb_source();
1608 else
1609 assert(0);
1610 } else if (!strcmp(option_name, "fail")) {
1611 if (!strcmp(env->get_string_arg(i->first, 0), "fail-optimal"))
1612 d2::align::fail_optimal();
1613 else if (!strcmp(env->get_string_arg(i->first, 0), "fail-default"))
1614 d2::align::fail_default();
1615 else
1616 assert(0);
1617 } else if (!strcmp(option_name, "profile")) {
1618 ui::set_profile();
1619 } else if (!strcmp(option_name, "extend")) {
1620 if (env->get_int_arg(i->first, 0))
1621 extend = 1;
1622 else
1623 extend = 0;
1624 } else if (!strcmp(option_name, "oc")) {
1625 if (env->get_int_arg(i->first, 0))
1626 d3::scene::oc();
1627 else
1628 d3::scene::no_oc();
1629 } else if (!strcmp(option_name, "focus")) {
1631 double one = +1;
1632 double zero = +0;
1633 double inf = one / zero;
1635 assert (isinf(inf) && inf > 0);
1638 * Focus type
1641 unsigned int type = 0;
1642 double distance = 0;
1643 double px = 0, py = 0;
1645 if (!strcmp(env->get_string_arg(i->first, 1), "d")) {
1647 type = 0;
1649 distance = env->get_double_arg(i->first, 2);
1651 } else if (!strcmp(env->get_string_arg(i->first, 1), "p")) {
1653 type = 1;
1655 px = env->get_double_arg(i->first, 2);
1656 py = env->get_double_arg(i->first, 3);
1658 } else {
1659 bad_arg(option_name);
1663 * Options
1666 unsigned int ci = 0;
1667 double fr = 0;
1668 double ht = 0;
1669 double vt = 0;
1670 double sd = 0;
1671 double ed = inf;
1672 double sx = -inf;
1673 double ex = inf;
1674 double sy = -inf;
1675 double ey = inf;
1676 double ap = 3;
1677 unsigned int sc = 3;
1678 unsigned int fs = 0;
1679 unsigned int sr = 0;
1681 for (int arg_num = 4; env->is_arg(i->first, arg_num); arg_num++) {
1682 const char *option = env->get_string_arg(i->first, arg_num);
1683 if (!strncmp(option, "ci=", 3)) {
1684 if(sscanf(option + 3, "%u", &ci) != 1)
1685 bad_arg("--focus");
1686 } else if (!strncmp(option, "fr=", 3)) {
1687 if(sscanf(option + 3, "%lf", &fr) != 1)
1688 bad_arg("--focus");
1689 } else if (!strncmp(option, "ht=", 3)) {
1690 if(sscanf(option + 3, "%lf", &ht) != 1)
1691 bad_arg("--focus");
1692 } else if (!strncmp(option, "vt=", 3)) {
1693 if(sscanf(option + 3, "%lf", &vt) != 1)
1694 bad_arg("--focus");
1695 } else if (!strncmp(option, "sy=", 3)) {
1696 if(sscanf(option + 3, "%lf", &sy) != 1)
1697 bad_arg("--focus");
1698 } else if (!strncmp(option, "ey=", 3)) {
1699 if(sscanf(option + 3, "%lf", &ey) != 1)
1700 bad_arg("--focus");
1701 } else if (!strncmp(option, "sx=", 3)) {
1702 if(sscanf(option + 3, "%lf", &sx) != 1)
1703 bad_arg("--focus");
1704 } else if (!strncmp(option, "ex=", 3)) {
1705 if(sscanf(option + 3, "%lf", &ex) != 1)
1706 bad_arg("--focus");
1707 } else if (!strncmp(option, "sd=", 3)) {
1708 if(sscanf(option + 3, "%lf", &sd) != 1)
1709 bad_arg("--focus");
1710 } else if (!strncmp(option, "ed=", 3)) {
1711 if(sscanf(option + 3, "%lf", &ed) != 1)
1712 bad_arg("--focus");
1713 } else if (!strncmp(option, "ap=", 3)) {
1714 if(sscanf(option + 3, "%lf", &ap) != 1)
1715 bad_arg("--focus");
1716 } else if (!strncmp(option, "sc=", 3)) {
1717 if(sscanf(option + 3, "%u", &sc) != 1)
1718 bad_arg("--focus");
1719 } else if (!strncmp(option, "sr=", 3)) {
1720 if (!strcmp(option, "sr=aperture")) {
1721 sr = 0;
1722 } else if (!strcmp(option, "sr=pixel")) {
1723 sr = 1;
1724 } else
1725 bad_arg("--focus");
1727 } else if (!strncmp(option, "fs=", 3)) {
1728 if (!strcmp(option, "fs=mean")) {
1729 fs = 0;
1730 } else if (!strcmp(option, "fs=median")) {
1731 fs = 1;
1732 } else
1733 bad_arg("--focus");
1734 } else
1735 bad_arg("--focus");
1738 d3::focus::add_region(type, distance, px, py, ci, fr, ht, vt, sd, ed, sx, ex, sy, ey, ap, sc, fs, sr);
1740 } else if (!strcmp(option_name, "3ddp") || !strcmp(option_name, "3dvp")) {
1741 d2::align::keep();
1744 * Unsupported configurations
1747 if (ip_iterations)
1748 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1750 #if 0
1751 if (usm_multiplier)
1752 unsupported::fornow("3D modeling with unsharp mask");
1753 #endif
1756 * Initialize if necessary
1758 * Note: because their existence is checked as an
1759 * indicator of the presence of 3D arguments, we
1760 * initialize these structures here.
1763 if (d3_output == NULL) {
1764 d3_count = argc;
1765 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1766 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1769 unsigned int width, height;
1770 double view_angle;
1771 double x, y, z;
1772 double P, Y, R;
1774 width = env->get_unsigned_arg(i->first, 1);
1775 height = env->get_unsigned_arg(i->first, 2);
1776 view_angle = env->get_double_arg(i->first, 3);
1777 x = env->get_double_arg(i->first, 4);
1778 y = env->get_double_arg(i->first, 5);
1779 z = env->get_double_arg(i->first, 6);
1780 P = env->get_double_arg(i->first, 7);
1781 Y = env->get_double_arg(i->first, 8);
1782 R = env->get_double_arg(i->first, 9);
1784 view_angle *= M_PI / 180;
1785 P *= M_PI / 180;
1786 Y *= M_PI / 180;
1787 R *= M_PI / 180;
1789 d2::transformation t =
1790 d2::transformation::eu_identity();
1791 t.set_domain(height, width);
1792 d3::pt _pt(t, d3::et(y, x, z, Y, P, R), view_angle);
1794 if (!strcmp(option_name, "3dvp")) {
1795 d3_output_pt[env->get_string_arg(i->first, 10)] = _pt;
1796 } else if (!strcmp(option_name, "3ddp")) {
1797 d3_depth_pt[env->get_string_arg(i->first, 10)] = _pt;
1798 } else {
1799 assert(0);
1801 } else if (!strcmp(option_name, "3dv")) {
1802 d2::align::keep();
1804 unsigned int frame_no;
1807 * Unsupported configurations
1810 if (ip_iterations)
1811 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1813 #if 0
1814 if (usm_multiplier)
1815 unsupported::fornow("3D modeling with unsharp mask");
1816 #endif
1819 * Initialize if necessary
1822 if (d3_output == NULL) {
1823 d3_count = argc;
1824 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1825 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1828 frame_no = env->get_int_arg(i->first, 1);
1830 if (frame_no >= d3_count)
1831 ui::get()->error("--3dv argument 0 is too large");
1833 if (d3_output[frame_no] != NULL) {
1834 unsupported::fornow ("Writing a single 3D view to more than one output file");
1837 d3_output[frame_no] = env->get_string_arg(i->first, 2);
1839 } else if (!strcmp(option_name, "3dd")) {
1840 d2::align::keep();
1842 unsigned int frame_no;
1845 * Unsupported configurations
1848 if (ip_iterations)
1849 unsupported::fornow("3D modeling with Irani-Peleg rendering");
1851 #if 0
1852 if (usm_multiplier)
1853 unsupported::fornow("3D modeling with unsharp mask");
1854 #endif
1857 * Initialize if necessary
1860 if (d3_output == NULL) {
1861 d3_count = argc;
1862 d3_output = (const char **) calloc(d3_count, sizeof(char *));
1863 d3_depth = (const char **) calloc(d3_count, sizeof(char *));
1866 frame_no = env->get_int_arg(i->first, 1);
1868 if (frame_no >= d3_count)
1869 ui::get()->error("--3dd argument 0 is too large");
1871 if (d3_depth[frame_no] != NULL) {
1872 unsupported::fornow ("Writing a single frame's depth info to more than one output file");
1875 d3_depth[frame_no] = env->get_string_arg(i->first, 2);
1877 } else if (!strcmp(option_name, "view-angle")) {
1878 user_view_angle = env->get_double_arg(i->first, 1) * M_PI / 180;
1879 } else if (!strcmp(option_name, "cpf-load")) {
1880 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
1881 } else if (!strcmp(option_name, "accel")) {
1882 if (!strcmp(env->get_string_arg(i->first, 1), "gpu"))
1883 accel::set_gpu();
1884 else if (!strcmp(env->get_string_arg(i->first, 1), "none"))
1885 accel::set_none();
1886 else if (!strcmp(env->get_string_arg(i->first, 1), "auto"))
1887 accel::set_auto();
1888 else {
1889 fprintf(stderr, "Error: Unknown acceleration type '%s'\n",
1890 env->get_string_arg(i->first, 1));
1891 exit(1);
1893 } else if (!strcmp(option_name, "ui")) {
1894 if (!strcmp(env->get_string_arg(i->first, 1), "stream"))
1895 ui::set_stream();
1896 else if (!strcmp(env->get_string_arg(i->first, 1), "tty"))
1897 ui::set_tty();
1898 else if (!strcmp(env->get_string_arg(i->first, 1), "log"))
1899 ui::set_log();
1900 else if (!strcmp(env->get_string_arg(i->first, 1), "quiet"))
1901 ui::set_quiet();
1902 else if (!strcmp(env->get_string_arg(i->first, 1), "gl"))
1903 ui::set_gl();
1904 else if (!strcmp(env->get_string_arg(i->first, 1), "auto"))
1905 ui::set_auto();
1906 else {
1907 fprintf(stderr, "Error: Unknown user interface type '%s'\n",
1908 env->get_string_arg(i->first, 1));
1909 exit(1);
1911 } else if (!strcmp(option_name, "3d-fmr")) {
1912 d3::scene::fmr(env->get_double_arg(i->first, 1));
1913 } else if (!strcmp(option_name, "3d-dmr")) {
1914 d3::scene::dmr(env->get_double_arg(i->first, 1));
1915 } else if (!strcmp(option_name, "et")) {
1916 d3::scene::et(env->get_double_arg(i->first, 1));
1917 } else if (!strcmp(option_name, "st")) {
1918 d3::cpf::st(env->get_double_arg(i->first, 1));
1919 } else if (!strcmp(option_name, "di-lower")) {
1920 d3::scene::di_lower(env->get_double_arg(i->first, 1));
1921 } else if (!strcmp(option_name, "rc")) {
1922 d3::scene::rc(env->get_double_arg(i->first, 1));
1923 } else if (!strcmp(option_name, "do-try")) {
1924 d3::scene::do_try(env->get_double_arg(i->first, 1));
1925 } else if (!strcmp(option_name, "di-upper")) {
1926 d3::scene::di_upper(env->get_double_arg(i->first, 1));
1927 } else if (!strcmp(option_name, "fc")) {
1928 d3::scene::fc(env->get_double_arg(i->first, 1));
1929 } else if (!strcmp(option_name, "ecm")) {
1930 unsupported::discontinued("--ecm <x>");
1931 } else if (!strcmp(option_name, "acm")) {
1932 unsupported::discontinued("--acm <x>");
1933 } else if (!strcmp(option_name, "def-nn")) {
1934 d2::image_rw::def_nn(env->get_double_arg(i->first, 1));
1936 if (env->get_double_arg(i->first, 1) > 2) {
1937 fprintf(stderr, "\n\n*** Warning: --def-nn implementation is currently "
1938 "inefficient for large radii. ***\n\n");
1941 } else if (!strcmp(option_name, "fx")) {
1942 d3::scene::fx(env->get_double_arg(i->first, 1));
1943 } else if (!strcmp(option_name, "tcem")) {
1944 d3::scene::tcem(env->get_double_arg(i->first, 1));
1945 } else if (!strcmp(option_name, "oui")) {
1946 d3::scene::oui(env->get_unsigned_arg(i->first, 1));
1947 } else if (!strcmp(option_name, "pa")) {
1948 d3::scene::pa(env->get_unsigned_arg(i->first, 1));
1949 } else if (!strcmp(option_name, "pc")) {
1950 d3::scene::pc(env->get_string_arg(i->first, 1));
1951 } else if (!strcmp(option_name, "cw")) {
1952 d2::align::certainty_weighted(env->get_unsigned_arg(i->first, 0));
1953 } else if (!strcmp(option_name, "wm")) {
1954 if (wm_filename != NULL)
1955 ui::get()->error("only one weight map can be specified");
1957 wm_filename = env->get_string_arg(i->first, 1);
1958 wm_offsetx = env->get_int_arg(i->first, 2);
1959 wm_offsety = env->get_int_arg(i->first, 3);
1961 } else if (!strcmp(option_name, "fl")) {
1962 #ifdef USE_FFTW
1963 d2::align::set_frequency_cut(env->get_double_arg(i->first, 1),
1964 env->get_double_arg(i->first, 2),
1965 env->get_double_arg(i->first, 3));
1967 #else
1968 ui::get()->error_hint("--fl is not supported", "rebuild ALE with FFTW support");
1969 #endif
1970 } else if (!strcmp(option_name, "wmx")) {
1971 #ifdef USE_UNIX
1972 d2::align::set_wmx(env->get_string_arg(i->first, 1),
1973 env->get_string_arg(i->first, 2),
1974 env->get_string_arg(i->first, 3));
1975 #else
1976 ui::get()->error_hint("--wmx is not supported", "rebuild ALE with support for --wmx");
1977 #endif
1978 } else if (!strcmp(option_name, "flshow")) {
1979 d2::align::set_fl_show(env->get_string_arg(i->first, 1));
1980 } else if (!strcmp(option_name, "3dpx")) {
1982 d3px_parameters = (double *) local_realloc(d3px_parameters, (d3px_count + 1) * 6 * sizeof(double));
1984 for (int param = 0; param < 6; param++)
1985 d3px_parameters[6 * d3px_count + param] = env->get_double_arg(i->first, param + 1);
1988 * Swap x and y, since their internal meanings differ from their external meanings.
1991 for (int param = 0; param < 2; param++) {
1992 double temp = d3px_parameters[6 * d3px_count + 2 + param];
1993 d3px_parameters[6 * d3px_count + 2 + param] = d3px_parameters[6 * d3px_count + 0 + param];
1994 d3px_parameters[6 * d3px_count + 0 + param] = temp;
1999 * Increment counters
2002 d3px_count++;
2004 } else if (!strcmp(option_name, "ex") || !strcmp(option_name, "fex")) {
2006 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
2007 (ex_count + 1) * sizeof(d2::exclusion));
2009 ex_parameters[ex_count].type = (!strcmp(option_name, "ex"))
2010 ? d2::exclusion::RENDER
2011 : d2::exclusion::FRAME;
2014 * Get parameters, swapping x and y coordinates
2017 ex_parameters[ex_count].x[0] = env->get_int_arg(i->first, 1 + 2);
2018 ex_parameters[ex_count].x[1] = env->get_int_arg(i->first, 1 + 3);
2019 ex_parameters[ex_count].x[2] = env->get_int_arg(i->first, 1 + 0);
2020 ex_parameters[ex_count].x[3] = env->get_int_arg(i->first, 1 + 1);
2021 ex_parameters[ex_count].x[4] = env->get_int_arg(i->first, 1 + 4);
2022 ex_parameters[ex_count].x[5] = env->get_int_arg(i->first, 1 + 5);
2025 * Increment counters
2028 ex_count++;
2030 } else if (!strcmp(option_name, "crop") || !strcmp(option_name, "fcrop")) {
2032 ex_parameters = (d2::exclusion *) local_realloc(ex_parameters,
2033 (ex_count + 4) * sizeof(d2::exclusion));
2035 for (int r = 0; r < 4; r++)
2036 ex_parameters[ex_count + r].type = (!strcmp(option_name, "crop"))
2037 ? d2::exclusion::RENDER
2038 : d2::exclusion::FRAME;
2041 int crop_args[6];
2043 for (int param = 0; param < 6; param++)
2044 crop_args[param] = env->get_int_arg(i->first, param + 1);
2047 * Construct exclusion regions from the crop area,
2048 * swapping x and y, since their internal meanings
2049 * differ from their external meanings.
2053 * Exclusion region 1: low x
2056 ex_parameters[ex_count + 0].x[0] = INT_MIN;
2057 ex_parameters[ex_count + 0].x[1] = crop_args[2] - 1;
2058 ex_parameters[ex_count + 0].x[2] = INT_MIN;
2059 ex_parameters[ex_count + 0].x[3] = INT_MAX;
2060 ex_parameters[ex_count + 0].x[4] = crop_args[4];
2061 ex_parameters[ex_count + 0].x[5] = crop_args[5];
2064 * Exclusion region 2: low y
2067 ex_parameters[ex_count + 1].x[0] = INT_MIN;
2068 ex_parameters[ex_count + 1].x[1] = INT_MAX;
2069 ex_parameters[ex_count + 1].x[2] = INT_MIN;
2070 ex_parameters[ex_count + 1].x[3] = crop_args[0] - 1;
2071 ex_parameters[ex_count + 1].x[4] = crop_args[4];
2072 ex_parameters[ex_count + 1].x[5] = crop_args[5];
2075 * Exclusion region 3: high y
2078 ex_parameters[ex_count + 2].x[0] = INT_MIN;
2079 ex_parameters[ex_count + 2].x[1] = INT_MAX;
2080 ex_parameters[ex_count + 2].x[2] = crop_args[1] + 1;
2081 ex_parameters[ex_count + 2].x[3] = INT_MAX;
2082 ex_parameters[ex_count + 2].x[4] = crop_args[4];
2083 ex_parameters[ex_count + 2].x[5] = crop_args[5];
2086 * Exclusion region 4: high x
2089 ex_parameters[ex_count + 3].x[0] = crop_args[3] + 1;
2090 ex_parameters[ex_count + 3].x[1] = INT_MAX;
2091 ex_parameters[ex_count + 3].x[2] = INT_MIN;
2092 ex_parameters[ex_count + 3].x[3] = INT_MAX;
2093 ex_parameters[ex_count + 3].x[4] = crop_args[4];
2094 ex_parameters[ex_count + 3].x[5] = crop_args[5];
2097 * Increment counters
2100 ex_count += 4;
2102 } else if (!strcmp(option_name, "exshow")) {
2103 ex_show = 1;
2104 } else if (!strcmp(option_name, "wt")) {
2105 d2::render::set_wt(env->get_double_arg(i->first, 1));
2106 } else if (!strcmp(option_name, "3d-chain")) {
2107 d3chain_type = env->get_string_arg(i->first, 1);
2108 } else if (!strcmp(option_name, "dchain")) {
2109 ochain_types[0] = env->get_string_arg(i->first, 1);
2110 } else if (!strcmp(option_name, "achain")) {
2111 achain_type = env->get_string_arg(i->first, 1);
2112 } else if (!strcmp(option_name, "afilter")) {
2113 afilter_type = env->get_string_arg(i->first, 1);
2114 } else if (!strcmp(option_name, "ochain")) {
2116 ochain = (d2::render **) local_realloc(ochain,
2117 (oc_count + 1) * sizeof(d2::render *));
2118 ochain_names = (const char **) local_realloc((void *)ochain_names,
2119 (oc_count + 1) * sizeof(const char *));
2120 ochain_types = (const char **) local_realloc((void *)ochain_types,
2121 (oc_count + 1) * sizeof(const char *));
2123 ochain_types[oc_count] = env->get_string_arg(i->first, 1);
2124 ochain_names[oc_count] = env->get_string_arg(i->first, 2);
2126 oc_count++;
2128 } else if (!strcmp(option_name, "visp")) {
2130 visp = (const char **) local_realloc((void *)visp, 4 *
2131 (vise_count + 1) * sizeof(const char *));
2133 for (int param = 0; param < 4; param++)
2134 visp[vise_count * 4 + param] = env->get_string_arg(i->first, param + 1);
2136 vise_count++;
2138 } else if (!strcmp(option_name, "cx")) {
2139 cx_parameter = env->get_int_arg(i->first, 0) ? env->get_double_arg(i->first, 1) : 0;
2140 } else if (!strcmp(option_name, "ip")) {
2141 unsupported::discontinued("--ip <r> <i>", "--lpsf box=<r> --ips <i>");
2142 } else if (!strcmp(option_name, "cache")) {
2143 double cache = env->get_double_arg(i->first, 1);
2145 d2::image_rw::set_cache(cache);
2147 } else if (!strcmp(option_name, "resident")) {
2148 double resident = env->get_double_arg(i->first, 1);
2150 d2::image::set_resident(resident);
2152 } else if (!strcmp(option_name, "bayer")) {
2155 * External order is clockwise from top-left. Internal
2156 * order is counter-clockwise from top-left.
2159 const char *option = env->get_string_arg(i->first, 1);
2161 if (!strcmp(option, "rgbg")) {
2162 user_bayer = IMAGE_BAYER_RGBG;
2163 } else if (!strcmp(option, "bgrg")) {
2164 user_bayer = IMAGE_BAYER_BGRG;
2165 } else if (!strcmp(option, "gbgr")) {
2166 user_bayer = IMAGE_BAYER_GRGB;
2167 } else if (!strcmp(option, "grgb")) {
2168 user_bayer = IMAGE_BAYER_GBGR;
2169 } else if (!strcmp(option, "none")) {
2170 user_bayer = IMAGE_BAYER_NONE;
2171 } else {
2172 bad_arg("--bayer");
2175 } else if (!strcmp(option_name, "lpsf")) {
2176 psf[psf_linear] = env->get_string_arg(i->first, 1);
2177 } else if (!strcmp(option_name, "nlpsf")) {
2178 psf[psf_nonlinear] = env->get_string_arg(i->first, 1);
2179 } else if (!strcmp(option_name, "psf-match")) {
2181 psf_match = 1;
2183 for (int index = 0; index < 6; index++) {
2184 psf_match_args[index] = env->get_double_arg(i->first, index + 1);
2187 } else if (!strcmp(option_name, "device")) {
2188 device = env->get_string_arg(i->first, 1);
2189 #if 0
2190 } else if (!strcmp(option_name, "usm")) {
2192 if (d3_output != NULL)
2193 unsupported::fornow("3D modeling with unsharp mask");
2195 usm_multiplier = env->get_double_arg(i->first, 1);
2196 #endif
2198 } else if (!strcmp(option_name, "ipr")) {
2200 ip_iterations = env->get_int_arg(i->first, 1);
2202 ui::get()->warn("--ipr is deprecated. Use --ips instead");
2204 } else if (!strcmp(option_name, "cpp-err")) {
2205 if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2206 d3::cpf::err_median();
2207 else if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2208 d3::cpf::err_mean();
2209 } else if (!strcmp(option_name, "vp-adjust")) {
2210 if (env->get_int_arg(i->first, 0))
2211 d3::align::vp_adjust();
2212 else
2213 d3::align::vp_noadjust();
2214 } else if (!strcmp(option_name, "vo-adjust")) {
2215 if (env->get_int_arg(i->first, 0))
2216 d3::align::vo_adjust();
2217 else
2218 d3::align::vo_noadjust();
2219 } else if (!strcmp(option_name, "ip-statistic")) {
2220 if (!strcmp(env->get_string_arg(i->first, 0), "mean"))
2221 ip_use_median = 0;
2222 else if (!strcmp(env->get_string_arg(i->first, 0), "median"))
2223 ip_use_median = 1;
2224 } else if (!strcmp(option_name, "ips")) {
2225 ip_iterations = env->get_int_arg(i->first, 1);
2226 } else if (!strcmp(option_name, "ip-wl")) {
2227 int limited = env->get_int_arg(i->first, 0);
2228 if (limited) {
2229 ipwl = env->get_double_arg(i->first, 1);
2230 } else {
2231 ipwl = 0;
2233 } else if (!strcmp(option_name, "ipc")) {
2234 unsupported::discontinued("--ipc <c> <i>", "--ips <i> --lpsf <c>", "--ips <i> --device <c>");
2235 } else if (!strcmp(option_name, "exp-extend")) {
2236 if (env->get_int_arg(i->first, 0))
2237 d2::image_rw::exp_scale();
2238 else
2239 d2::image_rw::exp_noscale();
2240 } else if (!strcmp(option_name, "exp-register")) {
2241 if (env->get_int_arg(i->first, 0) == 1) {
2242 exposure_register = 1;
2243 d2::align::exp_register();
2244 } else if (env->get_int_arg(i->first, 0) == 0) {
2245 exposure_register = 0;
2246 d2::align::exp_noregister();
2247 } else if (env->get_int_arg(i->first, 0) == 2) {
2248 exposure_register = 2;
2249 d2::align::exp_meta_only();
2251 } else if (!strcmp(option_name, "drizzle-only")) {
2252 unsupported::discontinued("--drizzle-only", "--dchain box:1");
2253 } else if (!strcmp(option_name, "subspace-traverse")) {
2254 unsupported::undocumented("--subspace-traverse");
2255 d3::scene::set_subspace_traverse();
2256 } else if (!strcmp(option_name, "3d-filter")) {
2257 if (env->get_int_arg(i->first, 0))
2258 d3::scene::filter();
2259 else
2260 d3::scene::nofilter();
2261 } else if (!strcmp(option_name, "occ-norm")) {
2262 if (env->get_int_arg(i->first, 0))
2263 d3::scene::nw();
2264 else
2265 d3::scene::no_nw();
2266 } else if (!strcmp(option_name, "inc")) {
2267 inc = env->get_int_arg(i->first, 0);
2268 } else if (!strcmp(option_name, "exp-mult")) {
2269 double exp_c, exp_r, exp_b;
2271 exp_c = env->get_double_arg(i->first, 1);
2272 exp_r = env->get_double_arg(i->first, 2);
2273 exp_b = env->get_double_arg(i->first, 3);
2275 exp_mult = d2::pixel(1/(exp_r * exp_c), 1/exp_c, 1/(exp_b * exp_c));
2277 } else if (!strcmp(option_name, "visp-scale")) {
2279 vise_scale_factor = env->get_double_arg(i->first, 1);
2281 if (vise_scale_factor <= 0.0)
2282 ui::get()->error("VISP scale must be greater than zero");
2284 if (!finite(vise_scale_factor))
2285 ui::get()->error("VISP scale must be finite");
2287 } else if (!strcmp(option_name, "scale")) {
2289 scale_factor = env->get_double_arg(i->first, 1);
2291 if (scale_factor <= 0)
2292 ui::get()->error("Scale factor must be greater than zero");
2294 if (!finite(scale_factor))
2295 ui::get()->error("Scale factor must be finite");
2297 } else if (!strcmp(option_name, "metric")) {
2298 d2::align::set_metric_exponent(env->get_double_arg(i->first, 1));
2299 } else if (!strcmp(option_name, "threshold")) {
2300 d2::align::set_match_threshold(env->get_double_arg(i->first, 1));
2301 } else if (!strcmp(option_name, "drizzle-diam")) {
2302 unsupported::discontinued("--drizzle-diam=<x>", "--dchain box:1");
2303 } else if (!strcmp(option_name, "perturb-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 (perturb_lower <= 0)
2309 ui::get()->error("--perturb-lower= value is non-positive");
2311 if (*(option + characters) == '%')
2312 d2::align::set_perturb_lower(perturb_lower, 1);
2313 else
2314 d2::align::set_perturb_lower(perturb_lower, 0);
2315 } else if (!strcmp(option_name, "stepsize")) {
2316 ui::get()->warn("--stepsize is deprecated. Use --perturb-lower instead");
2317 d2::align::set_perturb_lower(env->get_double_arg(i->first, 1), 0);
2318 } else if (!strcmp(option_name, "va-upper")) {
2319 const char *option = env->get_string_arg(i->first, 1);
2320 double va_upper;
2321 int characters;
2322 sscanf(option, "%lf%n", &va_upper, &characters);
2323 if (*(option + characters) == '%')
2324 ui::get()->error("--va-upper= does not accept '%' arguments\n");
2325 else
2326 d3::cpf::set_va_upper(va_upper);
2327 } else if (!strcmp(option_name, "cpp-upper")) {
2328 const char *option = env->get_string_arg(i->first, 1);
2329 double perturb_upper;
2330 int characters;
2331 sscanf(option, "%lf%n", &perturb_upper, &characters);
2332 if (*(option + characters) == '%')
2333 ui::get()->error("--cpp-upper= does not currently accept '%' arguments\n");
2334 else
2335 d3::cpf::set_cpp_upper(perturb_upper);
2336 } else if (!strcmp(option_name, "cpp-lower")) {
2337 const char *option = env->get_string_arg(i->first, 1);
2338 double perturb_lower;
2339 int characters;
2340 sscanf(option, "%lf%n", &perturb_lower, &characters);
2341 if (*(option + characters) == '%')
2342 ui::get()->error("--cpp-lower= does not currently accept '%' arguments\n");
2343 else
2344 d3::cpf::set_cpp_lower(perturb_lower);
2345 } else if (!strcmp(option_name, "hf-enhance")) {
2346 unsupported::discontinued("--hf-enhance=<x>");
2347 } else if (!strcmp(option_name, "multi")) {
2348 d2::trans_multi::set_multi(env->get_string_arg(i->first, 1));
2349 } else if (!strcmp(option_name, "gs")) {
2350 d2::align::gs(env->get_string_arg(i->first, 1));
2351 } else if (!strcmp(option_name, "rot-upper")) {
2352 d2::align::set_rot_max((int) floor(env->get_double_arg(i->first, 1)));
2353 } else if (!strcmp(option_name, "bda-mult")) {
2354 d2::align::set_bda_mult(env->get_double_arg(i->first, 1));
2355 } else if (!strcmp(option_name, "bda-rate")) {
2356 d2::align::set_bda_rate(env->get_double_arg(i->first, 1));
2357 } else if (!strcmp(option_name, "lod-preferred")) {
2358 d2::align::set_lod_preferred((int) floor(env->get_double_arg(i->first, 1)));
2359 } else if (!strcmp(option_name, "min-dimension")) {
2360 d2::align::set_min_dimension((int) ceil(env->get_double_arg(i->first, 1)));
2361 } else if (!strcmp(option_name, "cpf-load")) {
2362 d3::cpf::init_loadfile(env->get_string_arg(i->first, 1));
2363 #if 0
2364 } else if (!strcmp(option_name, "model-load")) {
2365 d3::scene::load_model(env->get_string_arg(i->first, 1));
2366 } else if (!strcmp(option_name, "model-save")) {
2367 d3::scene::save_model(env->get_string_arg(i->first, 1));
2368 #endif
2369 } else if (!strcmp(option_name, "trans-load")) {
2370 d2::tload_delete(tload);
2371 tload = d2::tload_new(env->get_string_arg(i->first, 1));
2372 d2::align::set_tload(tload);
2373 } else if (!strcmp(option_name, "trans-save")) {
2374 tsave_delete(tsave);
2375 tsave = d2::tsave_new(env->get_string_arg(i->first, 1));
2376 d2::align::set_tsave(tsave);
2377 } else if (!strcmp(option_name, "3d-trans-load")) {
2378 d3::tload_delete(d3_tload);
2379 d3_tload = d3::tload_new(env->get_string_arg(i->first, 1));
2380 d3::align::set_tload(d3_tload);
2381 } else if (!strcmp(option_name, "3d-trans-save")) {
2382 d3::tsave_delete(d3_tsave);
2383 d3_tsave = d3::tsave_new(env->get_string_arg(i->first, 1));
2384 d3::align::set_tsave(d3_tsave);
2385 } else {
2386 assert(0);
2391 * Apply implication logic.
2394 if (extend == 0 && vise_count != 0) {
2395 implication::changed("VISP requires increased image extents.",
2396 "Image extension is now enabled.",
2397 "--extend");
2398 extend = 1;
2401 if (psf_match && ex_count)
2402 unsupported::fornow("PSF calibration with exclusion regions.");
2405 if (d3_output != NULL && ip_iterations != 0)
2406 unsupported::fornow("3D modeling with Irani-Peleg rendering");
2408 #if 0
2409 if (extend == 0 && d3_output != NULL) {
2410 implication::changed("3D modeling requires increased image extents.",
2411 "Image extension is now enabled.",
2412 "--extend");
2413 extend = 1;
2415 #endif
2417 #if 0
2418 if (cx_parameter != 0 && !exposure_register) {
2419 implication::changed("Certainty-based rendering requires exposure registration.",
2420 "Exposure registration is now enabled.",
2421 "--exp-register");
2422 d2::align::exp_register();
2423 exposure_register = 1;
2425 #endif
2428 * Set alignment class exclusion region static variables
2431 d2::align::set_exclusion(ex_parameters, ex_count);
2434 * Initialize renderer class statics.
2437 d2::render::render_init(ex_count, ex_parameters, ex_show, extend, scale_factor);
2440 * Set confidence
2443 d2::exposure::set_confidence(cx_parameter);
2446 * Keep transformations for Irani-Peleg, psf-match, and
2447 * VISE
2450 if (ip_iterations > 0 || psf_match || vise_count > 0) {
2451 d2::align::keep();
2455 * Initialize device-specific variables
2458 // int input_file_count = argc - i - 1;
2459 int input_file_count = files.size() - 1;
2461 d2::psf *device_response[psf_N] = { NULL, NULL };
2462 d2::exposure **input_exposure = NULL;
2463 ale_pos view_angle = 43.7 * M_PI / 180;
2464 // ale_pos view_angle = 90 * M_PI / 180;
2465 input_exposure = (d2::exposure **)
2466 // malloc((argc - i - 1) * sizeof(d2::exposure *));
2467 malloc(input_file_count * sizeof(d2::exposure *));
2469 if (device != NULL) {
2470 if (!strcmp(device, "xvp610_640x480")) {
2471 device_response[psf_linear] = new xvp610_640x480::lpsf();
2472 device_response[psf_nonlinear] = new xvp610_640x480::nlpsf();
2473 for (int ii = 0; ii < input_file_count; ii++)
2474 input_exposure[ii] = new xvp610_640x480::exposure();
2475 view_angle = xvp610_640x480::view_angle();
2476 } else if (!strcmp(device, "xvp610_320x240")) {
2477 device_response[psf_linear] = new xvp610_320x240::lpsf();
2478 device_response[psf_nonlinear] = new xvp610_320x240::nlpsf();
2479 for (int ii = 0; ii < input_file_count; ii++)
2480 input_exposure[ii] = new xvp610_320x240::exposure();
2481 view_angle = xvp610_320x240::view_angle();
2482 } else if (!strcmp(device, "ov7620")) {
2483 device_response[psf_linear] = new ov7620_raw_linear::lpsf();
2484 device_response[psf_nonlinear] = NULL;
2485 for (int ii = 0; ii < input_file_count; ii++)
2486 input_exposure[ii] = new ov7620_raw_linear::exposure();
2487 d2::image_rw::set_default_bayer(IMAGE_BAYER_BGRG);
2488 } else if (!strcmp(device, "canon_300d")) {
2489 device_response[psf_linear] = new canon_300d_raw_linear::lpsf();
2490 device_response[psf_nonlinear] = NULL;
2491 for (int ii = 0; ii < input_file_count; ii++)
2492 input_exposure[ii] = new canon_300d_raw_linear::exposure();
2493 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2494 } else if (!strcmp(device, "nikon_d50")) {
2495 device_response[psf_linear] = nikon_d50::lpsf();
2496 device_response[psf_nonlinear] = nikon_d50::nlpsf();
2497 for (int ii = 0; ii < input_file_count; ii++)
2498 input_exposure[ii] = new nikon_d50::exposure();
2499 d2::image_rw::set_default_bayer( nikon_d50::bayer() );
2500 } else if (!strcmp(device, "canon_300d+85mm_1.8")) {
2501 device_response[psf_linear] = new canon_300d_raw_linear_85mm_1_8::lpsf();
2502 device_response[psf_nonlinear] = NULL;
2503 for (int ii = 0; ii < input_file_count; ii++)
2504 input_exposure[ii] = new canon_300d_raw_linear_85mm_1_8::exposure();
2505 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2506 view_angle = canon_300d_raw_linear_85mm_1_8::view_angle();
2507 } else if (!strcmp(device, "canon_300d+50mm_1.8")) {
2508 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_8::lpsf();
2509 device_response[psf_nonlinear] = NULL;
2510 for (int ii = 0; ii < input_file_count; ii++)
2511 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_8::exposure();
2512 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2513 view_angle = canon_300d_raw_linear_50mm_1_8::view_angle();
2514 } else if (!strcmp(device, "canon_300d+50mm_1.4")) {
2515 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4::lpsf();
2516 device_response[psf_nonlinear] = NULL;
2517 for (int ii = 0; ii < input_file_count; ii++)
2518 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4::exposure();
2519 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2520 view_angle = canon_300d_raw_linear_50mm_1_4::view_angle();
2521 } else if (!strcmp(device, "canon_300d+50mm_1.4@1.4")) {
2522 device_response[psf_linear] = new canon_300d_raw_linear_50mm_1_4_1_4::lpsf();
2523 device_response[psf_nonlinear] = NULL;
2524 for (int ii = 0; ii < input_file_count; ii++)
2525 input_exposure[ii] = new canon_300d_raw_linear_50mm_1_4_1_4::exposure();
2526 d2::image_rw::set_default_bayer(IMAGE_BAYER_RGBG);
2527 view_angle = canon_300d_raw_linear_50mm_1_4_1_4::view_angle();
2528 } else {
2529 ui::get()->unknown_device(device);
2531 } else {
2532 for (int ii = 0; ii < input_file_count; ii++)
2533 input_exposure[ii] = new d2::exposure_default();
2537 * User-specified variables.
2540 if (user_view_angle != 0) {
2541 view_angle = user_view_angle;
2544 if (user_bayer != IMAGE_BAYER_DEFAULT) {
2545 d2::image_rw::set_default_bayer(user_bayer);
2549 * PSF-match exposure.
2551 if (psf_match) {
2552 delete input_exposure[input_file_count - 1];
2553 input_exposure[input_file_count - 1] = new d2::exposure_default();
2557 * Initialize output exposure
2560 d2::exposure *output_exposure = new d2::exposure_default();
2561 output_exposure->set_multiplier(exp_mult);
2564 * Configure the response function.
2567 d2::psf *response[2] = {NULL, NULL};
2569 for (int n = 0; n < psf_N; n++ ) {
2570 if (psf[n] != NULL) {
2572 response[n] = d2::psf_parse::get((n == psf_linear), psf[n]);
2574 } else if (device_response[n] != NULL) {
2577 * Device-specific response
2580 response[n] = device_response[n];
2582 } else {
2585 * Default point-spread function.
2588 if (n == psf_linear) {
2591 * Default lpsf is a box filter
2592 * of diameter 1.0 (radius
2593 * 0.5).
2596 response[n] = new d2::box(0.5);
2598 } else if (n == psf_nonlinear) {
2601 * nlpsf is disabled by default.
2604 response[n] = NULL;
2610 * First file argument. Print general file information as well
2611 * as information specific to this argument. Initialize image
2612 * file handler.
2615 // d2::image_rw::init(argc - i - 1, argv + i, argv[argc - 1], input_exposure, output_exposure);
2616 // ochain_names[0] = argv[argc - 1];
2618 const char **input_files = (const char **) malloc(sizeof(const char *) * input_file_count);
2619 for (int i = 0; i < input_file_count; i++) {
2620 input_files[i] = files[i].first;
2623 d2::image_rw::init(input_file_count, input_files, files[files.size() - 1].first,
2624 input_exposure, output_exposure);
2626 ochain_names[0] = files[files.size() - 1].first;
2629 * Handle control point data for alignment
2631 d2::align::set_cp_count(d3::cpf::count());
2632 for (unsigned int ii = 0; ii < d3::cpf::count(); ii++)
2633 d2::align::set_cp(ii, d3::cpf::get_2d(ii));
2636 * PSF-match bayer patterns.
2639 if (psf_match) {
2640 // d2::image_rw::set_specific_bayer(argc - i - 2, IMAGE_BAYER_NONE);
2641 d2::image_rw::set_specific_bayer(input_file_count - 1, IMAGE_BAYER_NONE);
2645 * Handle alignment weight map, if necessary
2648 if (wm_filename != NULL) {
2649 d2::image *weight_map;
2650 weight_map = d2::image_rw::read_image(wm_filename, new d2::exposure_linear());
2651 weight_map->set_offset(wm_offsety, wm_offsetx);
2652 d2::align::set_weight_map(weight_map);
2656 * Initialize alignment interpolant.
2659 if (strcmp(afilter_type, "internal"))
2660 d2::align::set_interpolant(d2::render_parse::get_SSF(afilter_type));
2663 * Initialize achain and ochain.
2666 achain = d2::render_parse::get(achain_type);
2668 for (int chain = 0; chain < oc_count; chain++)
2669 ochain[chain] = d2::render_parse::get(ochain_types[chain]);
2672 * Use merged renderings as reference images in
2673 * alignment.
2676 d2::align::set_reference(achain);
2679 * Tell the alignment class about the scale factor.
2682 d2::align::set_scale(scale_factor);
2685 * Initialize visp.
2688 d2::vise_core::set_scale(vise_scale_factor);
2690 for (int opt = 0; opt < vise_count; opt++) {
2691 d2::vise_core::add(d2::render_parse::get(visp[opt * 4 + 0]),
2692 visp[opt * 4 + 1],
2693 visp[opt * 4 + 2],
2694 visp[opt * 4 + 3]);
2698 * Initialize non-incremental renderers
2701 #if 0
2702 if (usm_multiplier != 0) {
2705 * Unsharp Mask renderer
2708 ochain[0] = new d2::usm(ochain[0], scale_factor,
2709 usm_multiplier, inc, response[psf_linear],
2710 response[psf_nonlinear], &input_exposure[0]);
2712 #endif
2714 if (psf_match) {
2717 * Point-spread function calibration renderer.
2718 * This renderer does not produce image output.
2719 * It is reserved for use with the point-spread
2720 * function calibration script
2721 * ale-psf-calibrate.
2724 ochain[0] = new d2::psf_calibrate(ochain[0],
2725 1, inc, response[psf_linear],
2726 response[psf_nonlinear],
2727 psf_match_args);
2729 } else if (ip_iterations != 0) {
2732 * Irani-Peleg renderer
2735 ochain[0] = new d2::ipc( ochain[0], ip_iterations,
2736 inc, response[psf_linear],
2737 response[psf_nonlinear],
2738 (exposure_register == 1), ip_use_median, ipwl);
2742 * Iterate through all files.
2745 for (unsigned int j = 0; j < d2::image_rw::count(); j++) {
2748 * Iterate through non-global options
2751 environment *env = files[j].second;
2753 for (std::map<const char *, const char *>::iterator i = env->get_map().begin();
2754 i != env->get_map().end(); i++) {
2756 if (!env->is_option(i->first))
2757 continue;
2759 const char *option_name = env->get_option_name(i->first);
2761 if (!strcmp(option_name, "mc")) {
2762 d2::align::mc(env->get_double_arg(i->first, 1));
2763 } else if (!strcmp(option_name, "md")) {
2764 d2::trans_multi::set_md(env->get_double_arg(i->first, 1));
2765 } else if (!strcmp(option_name, "ma-cert")) {
2766 d2::align::set_ma_cert(env->get_double_arg(i->first, 1));
2767 } else if (!strcmp(option_name, "mi")) {
2768 d2::trans_multi::set_mi(env->get_double_arg(i->first, 1));
2769 } else if (!strcmp(option_name, "gs-mo")) {
2770 const char *option = env->get_string_arg(i->first, 1);
2771 double gs_mo;
2772 int characters;
2773 sscanf(option, "%lf%n", &gs_mo, &characters);
2774 if (*(option + characters) == '%')
2775 d2::align::gs_mo(gs_mo, 1);
2776 else
2777 d2::align::gs_mo(gs_mo, 0);
2778 } else if (!strcmp(option_name, "ev")) {
2779 double ev = env->get_double_arg(i->first, 1);
2780 double gain_value = pow(2, -ev);
2782 if (j == 0)
2783 d2::exposure::set_gain_reference(gain_value);
2784 else
2785 input_exposure[j]->set_gain_multiplier(
2786 (double) d2::exposure::get_gain_reference()
2787 / gain_value);
2789 } else if (!strcmp(option_name, "black")) {
2790 double black = env->get_double_arg(i->first, 1);
2791 input_exposure[j]->set_black_level(black);
2792 } else if (!strcmp(option_name, "perturb-upper")) {
2793 const char *option = env->get_string_arg(i->first, 1);
2794 double perturb_upper;
2795 int characters;
2796 sscanf(option, "%lf%n", &perturb_upper, &characters);
2797 if (*(option + characters) == '%')
2798 d2::align::set_perturb_upper(perturb_upper, 1);
2799 else
2800 d2::align::set_perturb_upper(perturb_upper, 0);
2801 } else if (!strcmp(option_name, "threads")) {
2802 thread::set_count((unsigned int) env->get_int_arg(i->first, 1));
2803 } else if (!strcmp(option_name, "per-cpu")) {
2804 thread::set_per_cpu((unsigned int) env->get_int_arg(i->first, 1));
2805 } else {
2807 * This error should be encountered earlier.
2810 assert(0);
2812 fprintf(stderr, "\n\nError: option `%s' must be applied globally.", option_name);
2813 fprintf(stderr, "\n\nHint: Move option `%s' prior to file and scope operators.\n\n",
2814 option_name);
2815 exit(1);
2821 if (j == 0) {
2824 * Write comment information about original frame and
2825 * target image to the transformation save file, if we
2826 * have one.
2829 const d2::image *im = d2::image_rw::open(0);
2830 // tsave_orig(tsave, argv[i], im->avg_channel_magnitude());
2831 // tsave_target(tsave, argv[argc - 1]);
2832 tsave_orig(tsave, files[0].first, im->avg_channel_magnitude());
2833 tsave_target(tsave, files[files.size() - 1].first);
2834 d2::image_rw::close(0);
2837 * Handle the original frame.
2840 // ui::get()->original_frame_start(argv[i]);
2841 ui::get()->original_frame_start(files[0].first);
2843 for (int opt = 0; opt < oc_count; opt++) {
2844 ui::get()->set_orender_current(opt);
2845 ochain[opt]->sync(0);
2846 if (inc) {
2847 ui::get()->writing_output(opt);
2848 d2::image_rw::write_image(ochain_names[opt],
2849 ochain[opt]->get_image(0));
2853 d2::vise_core::frame_queue_add(0);
2855 ui::get()->original_frame_done();
2857 continue;
2861 * Handle supplemental frames.
2864 const char *name = d2::image_rw::name(j);
2866 ui::get()->supplemental_frame_start(name);
2869 * Write comment information about the
2870 * supplemental frame to the transformation
2871 * save file, if we have one.
2874 tsave_info (tsave, name);
2876 const d2::image *im = d2::image_rw::open(j);
2877 d2::pixel apm = im->avg_channel_magnitude();
2878 tsave_apm(tsave, apm[0], apm[1], apm[2]);
2879 d2::image_rw::close(j);
2881 for (int opt = 0; opt < oc_count; opt++) {
2882 ui::get()->set_orender_current(opt);
2883 ochain[opt]->sync(j);
2884 if (inc) {
2885 ui::get()->writing_output(opt);
2886 d2::image_rw::write_image(ochain_names[opt],
2887 ochain[opt]->get_image(j));
2891 d2::vise_core::frame_queue_add(j);
2893 ui::get()->supplemental_frame_done();
2897 * Do any post-processing and output final image
2899 * XXX: note that the Irani-Peleg renderer currently
2900 * returns zero for ochain[0]->sync(), since it writes
2901 * output internally when inc != 0.
2903 * XXX: Leave ochain[0] last, since this may allow disposal of
2904 * rendering structures not required by the Irani-Peleg
2905 * renderer.
2908 for (int opt = 1; opt < oc_count; opt++)
2909 if ((ochain[opt]->sync() || !inc) && !psf_match) {
2910 ui::get()->writing_output(opt);
2911 d2::image_rw::write_image(ochain_names[opt], ochain[opt]->get_image());
2914 if (oc_count > 0)
2915 if ((ochain[0]->sync() || !inc) && !psf_match) {
2916 ui::get()->writing_output(0);
2917 d2::image_rw::write_image(ochain_names[0], ochain[0]->get_image());
2921 * Output a summary match statistic.
2924 ui::get()->ale_2d_done((double) d2::align::match_summary());
2927 * Perform any 3D tasks
2930 optimizations::begin_3d_work();
2932 if (d3_count > 0) {
2934 ui::get()->d3_start();
2936 d3::align::init_angle(view_angle);
2938 ui::get()->d3_init_view_angle((double) view_angle / M_PI * 180);
2940 d3::align::init_from_d2();
2942 if (d3::cpf::count() > 0) {
2943 ui::get()->d3_control_point_solve();
2944 d3::cpf::solve_3d();
2945 ui::get()->d3_control_point_solve_done();
2948 ui::get()->d3_final_view_angle(d3::align::angle_of(0) / M_PI * 180);
2950 d3::align::write_alignments();
2952 d3::scene::set_filter_type(d3chain_type);
2954 d3::scene::init_from_d2();
2956 ui::get()->d3_subdividing_space();
2957 d3::scene::make_space(d3_depth, d3_output, &d3_depth_pt, &d3_output_pt);
2958 ui::get()->d3_subdividing_space_done();
2960 ui::get()->d3_updating_occupancy();
2961 d3::scene::reduce_cost_to_search_depth(output_exposure, inc);
2962 ui::get()->d3_updating_occupancy_done();
2964 d3::scene::d3px(d3px_count, d3px_parameters);
2965 int view_count = 0;
2966 for (unsigned int i = 0; i < d2::image_rw::count(); i++) {
2967 assert (i < d3_count);
2969 if (d3_depth[i] != NULL) {
2970 ui::get()->d3_writing_output(d3_depth[i]);
2971 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
2972 const d2::image *im = d3::scene::depth(i);
2973 d2::image_rw::write_image(d3_depth[i], im, output_exposure, 1, 1);
2974 delete im;
2975 ui::get()->d3_writing_output_done();
2978 if (d3_output[i] != NULL) {
2979 ui::get()->d3_writing_output(d3_output[i]);
2980 const d2::image *im = d3::scene::view(i);
2981 d2::image_rw::write_image(d3_output[i], im, output_exposure);
2982 delete im;
2983 d3::focus::set_camera(view_count++);
2984 ui::get()->d3_writing_output_done();
2987 for (std::map<const char *, d3::pt>::iterator i = d3_output_pt.begin();
2988 i != d3_output_pt.end(); i++) {
2990 ui::get()->d3_writing_output(i->first);
2991 const d2::image *im = d3::scene::view(i->second);
2992 d2::image_rw::write_image(i->first, im, output_exposure);
2993 delete im;
2994 d3::focus::set_camera(view_count++);
2995 ui::get()->d3_writing_output_done();
2998 for (std::map<const char *, d3::pt>::iterator i = d3_depth_pt.begin();
2999 i != d3_depth_pt.end(); i++) {
3001 ui::get()->d3_writing_output(i->first);
3002 ui::get()->d3_render_status(0, 0, -1, -1, -1, -1, 0);
3003 const d2::image *im = d3::scene::depth(i->second);
3004 d2::image_rw::write_image(i->first, im, output_exposure, 1, 1);
3005 delete im;
3006 ui::get()->d3_writing_output_done();
3010 for (unsigned int i = d2::image_rw::count(); i < d3_count; i++) {
3011 if (d3_depth[i] != NULL) {
3012 fprintf(stderr, "\n\n*** Frame number for --3dd too high. ***\n\n");
3014 if (d3_output[i] != NULL) {
3015 fprintf(stderr, "\n\n*** Frame number for --3dv too high. ***\n\n");
3021 * Destroy the image file handler
3024 d2::image_rw::destroy();
3027 * Delete the transformation file structures, if any
3028 * exist.
3031 tsave_delete(tsave);
3032 tload_delete(tload);
3035 * We're done.
3038 exit(0);
3042 #endif