/* main.c * * Copyright (C) 2005 by Andy Goth . * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "qbism.h" /* Allocates memory or else. */ void* xmalloc(size_t bytes) { void* result = malloc(bytes); if (result == NULL) { perror("malloc"); exit(EXIT_FAILURE); } return result; } /* Reallocates memory or else. */ void* xrealloc(void* buf, size_t bytes) { void* result = realloc(buf, bytes); if (result == NULL) { perror("realloc"); exit(EXIT_FAILURE); } return result; } typedef enum { OPT_INQBE, OPT_INQBM, OPT_OUTQBE, OPT_OUTQBM, OPT_OUTIMG, OPT_OVERSAMP, OPT_SIZE, OPT_REGS, OPT_STEPS, OPT_COUNT } opt_t; static char* opt_names[] = { "-inqbe", "-inqbm", "-outqbe", "-outqbm", "-outimg", "-oversamp", "-size", "-regs", "-steps" }; static FILE* my_open(char* name, char* mode) { FILE* fd; if (strcmp(name, "-") == 0) { if (strcmp(mode, "r") == 0) { fd = stdin; } else { fd = stdout; } } else { fd = fopen(name, mode); if (fd == NULL) { perror(name); exit(EXIT_FAILURE); } } return fd; } static void my_close(FILE* fd) { if (fd != stdin && fd != stdout) { if (fclose(fd) == EOF) { perror("fclose"); exit(EXIT_FAILURE); } } } /* Repeals gravity. */ int main(int argc, char** argv) { FILE* fd; int width, height, oversample; int i, j; int split; algo_t algo = {NULL, 36, 12}; char* opts[OPT_COUNT] = {NULL}; /* Defaults. */ opts[OPT_OVERSAMP] = "1"; opts[OPT_SIZE] = "640x480"; opts[OPT_OUTIMG] = "-"; opts[OPT_REGS] = "6"; opts[OPT_STEPS] = "36"; /* Check if help is requested. */ if (argc > 1 && ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "-help") == 0) || (strcmp(argv[1], "--help") == 0))) { printf("Usage: qbism [OPTION]...\n" "Use learning for evil.\n" "\n" " -inqbe FILE run the algorithm in the QBE FILE\n" " -inqbm FILE run the algorithm in the QBM FILE\n" " -outqbe FILE save the algorithm in QBE format to FILE\n" " -outqbm FILE save the algorithm in QBM format to FILE\n" " -outimg FILE render the image in MIFF format to FILE\n" " -oversamp NUM sample NUMxNUM points per pixel\n" " -size WIDTHxHEIGHT render at WIDTH by HEIGHT pixels\n" " -regs NUM for random algorithms, use NUM registers\n" " -steps NUM for random algorithms, use NUM steps\n" " -h, -help display this message\n" " -v, -version print the version information\n" "\n" "If neither -inqbe nor -inqbm are specified, a random algorithm is\n" "generated and used to render the image. Otherwise the algorithm\n" "stored in the QBE or QBM file is used.\n" "\n" "Specify - as FILE to use stdin or stdout. By default, the output\n" "image is written to stdout; pipe through display or convert (from\n" "ImageMagick) for the desired effect.\n" "\n" "Report features to Andy Goth .\n"); return EXIT_SUCCESS; } /* Check if the version number is requested. */ if (argc > 1 && ((strcmp(argv[1], "-v") == 0) || (strcmp(argv[1], "-version") == 0) || (strcmp(argv[1], "--version") == 0))) { printf("qbism 0.3\n"); return EXIT_SUCCESS; } /* Check that every option has a parameter. */ if ((argc - 1) % 2 != 0) { fprintf(stderr, "Option \"%s\" has no parameter\n", argv[argc - 1]); return EXIT_FAILURE; } /* Get all parameters. */ for (i = 1; i < argc; i += 2) { for (j = 0; j < OPT_COUNT; ++j) { if (strcmp(argv[i], opt_names[j]) == 0) { opts[j] = argv[i + 1]; break; } } if (j == OPT_COUNT) { fprintf(stderr, "Unknown option \"%s\"\n", argv[i]); return EXIT_FAILURE; } } /* Check for disallowed combinations. */ if (opts[OPT_INQBE] != NULL && opts[OPT_INQBM] != NULL) { fprintf(stderr, "Cannot specify both -inqbe and -inqbm\n"); return EXIT_FAILURE; } /* Interpret numeric options. */ if (sscanf(opts[OPT_OVERSAMP], "%d", &oversample) != 1) { fprintf(stderr, "Bad oversample value \"%s\"\n", opts[OPT_OVERSAMP]); return EXIT_FAILURE; } if (sscanf(opts[OPT_SIZE], "%dx%d", &width, &height) != 2) { fprintf(stderr, "Bad size \"%s\"\n", opts[OPT_SIZE]); return EXIT_FAILURE; } if (sscanf(opts[OPT_REGS], "%d", &algo.num_regs) != 1 || algo.num_regs < 1) { fprintf(stderr, "Bad register count \"%s\"\n", opts[OPT_REGS]); return EXIT_FAILURE; } if (sscanf(opts[OPT_STEPS], "%d", &algo.num_steps) != 1 || algo.num_steps < 0) { fprintf(stderr, "Bad step count \"%s\"\n", opts[OPT_STEPS]); return EXIT_FAILURE; } /* Read/generate an algorithm. */ if (opts[OPT_INQBE] != NULL) { fd = my_open(opts[OPT_INQBE], "r"); algo_read_qbe(&algo, fd); my_close(fd); } else if (opts[OPT_INQBM] != NULL) { fprintf(stderr, "Unimplemented!\n"); } else { /* Generate a random transformation sequence. */ srandom(time(NULL)); algo.seq = xmalloc(sizeof(*algo.seq) * algo.num_steps); for (i = 0; i < algo.num_steps; ++i) { algo.seq[i].opcode = random() % XOP_COUNT; algo.seq[i].source = random() % algo.num_regs; algo.seq[i].control = random() % algo.num_regs; algo.seq[i].dest = random() % algo.num_regs; } } /* If so requested, write out the algorithm. */ if (opts[OPT_OUTQBE] != NULL) { fd = my_open(opts[OPT_OUTQBE], "w"); algo_write_qbe(&algo, fd); my_close(fd); } else if (opts[OPT_OUTQBM] != NULL) { fprintf(stderr, "Unimplemented!\n"); } /* Render! */ fd = my_open(opts[OPT_OUTIMG], "w"); qbism_render(&algo, width, height, oversample, fd); my_close(fd); return EXIT_SUCCESS; } /* vim: set ts=4 sts=4 sw=4 tw=80 et: */