diff options
Diffstat (limited to 'src/main.c')
| -rw-r--r-- | src/main.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..c81f1d6 --- /dev/null +++ b/src/main.c @@ -0,0 +1,237 @@ +#include <stdio.h> +#include <stdlib.h> +#include <inttypes.h> +#include <getopt.h> +#include <unistd.h> +#include "util/container.h" +#include "util/file.h" +#include "util/err.h" +#include "scene.h" +#include "parse.h" +#include "render.h" +#include "print.h" + +#include "draw/opengl.h" + +enum param_type +{ + PARAM_OUT = 1 << 0, + PARAM_SIZE = 1 << 1, + PARAM_FPS = 1 << 2, + PARAM_LIVE = 1 << 3, + PARAM_VERBOSE = 1 << 4, +}; + +struct params +{ + unsigned int flags; + str infile; + str outfile; + unsigned int size[2]; + unsigned int fps; + option(double) live; +}; + +static void run(struct registry *reg, struct params *params) +{ + FILE *srcfile; + str srcpath; + if (array_eq(params->infile, S("-"))) { + srcfile = stdin; + srcpath = S("<stdin>"); + } else { + srcpath = params->infile; + srcfile = file_open(params->infile, "r"); + if (!srcfile) + eprintf("'%.*s': failed to open scene file\n", PSTR(params->infile)); + } + + str contents = file_read(srcfile); + fclose(srcfile); + + struct source src; + struct scene scene; + + source_init(&src, srcpath, contents); + scene_init(&scene); + parse_scene(&src, &scene, reg); + + if (params->flags & PARAM_VERBOSE) + print_scene(stderr, &scene, SCENE_PARSED); + + scene_bind(&scene, &src, reg); + registry_free(reg); + + if (params->flags & PARAM_VERBOSE) + print_scene(stderr, &scene, SCENE_BOUND); + + if (params->flags & PARAM_OUT) + scene.outfile = params->outfile; + + if (params->flags & PARAM_SIZE) { + scene.size[0] = params->size[0]; + scene.size[1] = params->size[1]; + } + + if (params->flags & PARAM_FPS) + scene.fps = params->fps; + + if (params->flags & PARAM_LIVE) { + scene.live.present = true; + scene.live.data = params->live.present ? params->live.data : 1.0; + } + + if (params->flags & PARAM_VERBOSE) + print_scene(stderr, &scene, SCENE_BOUND); + + struct draw_backend *draw = &draw_backend_opengl; + draw->init(scene.size); + scene_load(&scene, &src, draw); + + if (params->flags & PARAM_VERBOSE) + print_scene(stderr, &scene, SCENE_LOADED); + + FILE *outfile; + if (scene.outfile.len) { + if (array_eq(scene.outfile, S("-"))) { + outfile = stdout; + } else { + outfile = file_open(scene.outfile, "wb"); + if (!outfile) + eprintf("'%.*s': failed to open output\n", PSTR(scene.outfile)); + } + } else { + if (isatty(STDOUT_FILENO)) + eprintf("no output file specified; refusing to write video data to TTY\n"); + outfile = stdout; + } + + struct nut_writer out; + nut_write_start(&out, outfile, scene.fps, scene.size); + + render_scene(&scene, draw, &out); + + nut_write_end(&out); + fclose(outfile); + draw->cleanup(); + scene_free(&scene); + source_free(&src); +} + +static const char *help_text = +"usage: %s [options] <scenefile>\n" +" -o | --out <outfile> File to write resulting .nut video to. A default may be provided by the\n" +" scene file. Otherwise, video is written to stdout unless stdout is a\n" +" tty.\n" +" -s | --size WxH Dimensions of the video. A default may be provided by the scene file.\n" +" Otherwise, 100x100 is used.\n" +" -f | --fps fps Fps of the video. A default may be provided by the scene file.\n" +" Otherwise, 25 is used.\n" +" -D | --define key=value Set variable key to value. Variables are declared in the scene file and\n" +" may or may not have defaults. Variables without defaults have to\n" +" be defined via command line.\n" +" -l | --live [<seconds>] Enable live mode where video is rendered in real time instead of as\n" +" fast as possible. A buffer time in seconds can be provided\n" +" (default: 1.0). Video will be rendered ahead of time by this amount.\n" +" -v | --verbose Print debugging information.\n" +" -h | --help Display this help text.\n"; + +int main(int argc, char **argv) +{ + struct registry reg = {}; + struct params params = {}; + + static struct option options[] = { + {"out", required_argument, 0, 'o' }, + {"size", required_argument, 0, 's' }, + {"fps", required_argument, 0, 'f' }, + {"define", required_argument, 0, 'D' }, + {"live", optional_argument, 0, 'l' }, + {"verbose", no_argument, 0, 'v' }, + {"help", no_argument, 0, 'h' }, + {0, 0, 0, 0 } + }; + + int c; + while ((c = getopt_long(argc, argv, "o:s:f:D:l::vh", options, nullptr)) != -1) { + if (c == 'l' && optarg == NULL && optind < argc && argv[optind][0] != '-') + optarg = argv[optind++]; + + str arg; + if (optarg) + arg = str_intro(optarg); + + switch (c) { + case 'o': + params.flags |= PARAM_OUT; + params.outfile = arg; + break; + case 's': { + str s_w, s_h; + long w, h; + if (!str_split(arg, S("x"), &s_w, &s_h)) + eprintf("'%.*s': size must contain an 'x'\n", PSTR(arg)); + if (!str_parse_int(s_w, &w) || w <= 0) + eprintf("'%.*s': invalid width\n", PSTR(s_w)); + if (!str_parse_int(s_w, &h) || h <= 0) + eprintf("'%.*s': invalid height\n", PSTR(s_h)); + params.flags |= PARAM_SIZE; + params.size[0] = w; + params.size[1] = h; + break; + } + case 'f': { + long fps; + if (!str_parse_int(arg, &fps) || fps <= 0) + eprintf("'%.*s': invalid fps\n", PSTR(arg)); + params.flags |= PARAM_FPS; + params.fps = fps; + break; + } + case 'D': { + str key, val; + if (!str_split(arg, S("="), &key, &val)) + eprintf("'%.*s': definition must contain an '='\n", PSTR(arg)); + bool succ; + map_insert(®.raw_vars, key, val, &succ); + if (!succ) + eprintf("'%.*s': already defined\n", PSTR(key)); + break; + } + case 'l': + params.flags |= PARAM_LIVE; + if (optarg) { + double buffer; + if (!str_parse_double(arg, &buffer) || buffer < 0) + eprintf("'%.*s': invalid buffer time\n", PSTR(arg)); + params.live.present = true; + params.live.data = buffer; + } + break; + case 'v': + params.flags |= PARAM_VERBOSE; + break; + case 'h': + fprintf(stderr, help_text, argv[0]); + exit(EXIT_SUCCESS); + break; + case '?': + eprintf("'%s': invalid option (see -h)\n", argv[optind]); + break; + case ':': + eprintf("'%s': missing argument (see -h)\n", argv[optind]); + break; + } + } + + int remain_args = argc-optind; + if (remain_args > 1) + eprintf("too many arguments (see -h)\n"); + if (remain_args < 1) + eprintf("missing scene file (see -h)\n"); + + params.infile = str_intro(argv[optind]); + + run(®, ¶ms); + return EXIT_SUCCESS; +} |
