#include "game.h"
+#include "optcfg.h"
struct level lvl;
+struct options opt;
+
+enum { OPT_SIZE, OPT_HELP };
+
+static struct optcfg_option options[] = {
+ {'s', "size", OPT_SIZE, "rendering resolution (WxH)"},
+ {'h', "help", OPT_HELP, "print usage and exit"},
+ OPTCFG_OPTIONS_END
+};
+
+static int opt_handler(struct optcfg *o, int opt, void *cls);
+
+int init_options(int argc, char **argv)
+{
+ struct optcfg *optcfg;
+
+ opt.width = 1280;
+ opt.height = 800;
+
+ optcfg = optcfg_init(options);
+ optcfg_set_opt_callback(optcfg, opt_handler, argv[0]);
+ optcfg_parse_config_file(optcfg, "cyberay.conf");
+ if(optcfg_parse_args(optcfg, argc, argv) == -1) {
+ return -1;
+ }
+
+ optcfg_destroy(optcfg);
+ return 0;
+}
+
+static int opt_handler(struct optcfg *o, int optid, void *cls)
+{
+ char *val;
+
+ switch(optid) {
+ case OPT_SIZE:
+ if(!(val = optcfg_next_value(o)) || sscanf(val, "%dx%d", &opt.width, &opt.height) != 2) {
+ fprintf(stderr, "size: expected <width>x<height>\n");
+ return -1;
+ }
+ break;
+
+ case OPT_HELP:
+ printf("Usage: %s [options]\n", (char*)cls);
+ printf("Options:\n");
+ optcfg_print_options(o);
+ exit(0);
+ }
+ return 0;
+}
#include "level.h"
+struct options {
+ int width, height;
+};
+
extern struct level lvl;
+extern struct options opt;
+
+int init_options(int argc, char **argv);
#endif /* GAME_H_ */
static long start_time;
static float cam_theta, cam_phi;
-static cgm_vec3 cam_pos = {0, -1.6, 0};
+static cgm_vec3 cam_pos = {0, 1.6, 0};
static int mouse_x, mouse_y;
static int bnstate[8];
int main(int argc, char **argv)
{
glutInit(&argc, argv);
- glutInitWindowSize(1280, 800);
- glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+
+ if(init_options(argc, argv) == -1) {
+ return 1;
+ }
+
+ glutInitWindowSize(opt.width, opt.height);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("cyberay");
glutDisplayFunc(display);
glEnable(GL_CULL_FACE);
- /*
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- */
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
vfwd += WALK_SPEED * dt;
}
if(inpstate[INP_RIGHT]) {
- vright -= WALK_SPEED * dt;
+ vright += WALK_SPEED * dt;
}
if(inpstate[INP_LEFT]) {
- vright += WALK_SPEED * dt;
+ vright -= WALK_SPEED * dt;
}
cam_pos.x += cos(cam_theta) * vright + sin(cam_theta) * vfwd;
- cam_pos.z += sin(cam_theta) * vright - cos(cam_theta) * vfwd;
+ cam_pos.z += -sin(cam_theta) * vright + cos(cam_theta) * vfwd;
cgm_midentity(view_xform);
- cgm_mtranslate(view_xform, cam_pos.x, cam_pos.y, cam_pos.z);
- cgm_mrotate_y(view_xform, cam_theta);
cgm_mrotate_x(view_xform, cam_phi);
+ cgm_mrotate_y(view_xform, cam_theta);
+ cgm_mtranslate(view_xform, cam_pos.x, cam_pos.y, cam_pos.z);
}
static void display(void)
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
+ glTexCoord2f(0, 1);
glVertex2f(-1, -1);
- glTexCoord2f(1, 0);
- glVertex2f(1, -1);
glTexCoord2f(1, 1);
+ glVertex2f(1, -1);
+ glTexCoord2f(1, 0);
glVertex2f(1, 1);
- glTexCoord2f(0, 1);
+ glTexCoord2f(0, 0);
glVertex2f(-1, 1);
glEnd();
- /*
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadMatrixf(view_xform);
-
- draw_level(&lvl);
- */
-
glutSwapBuffers();
assert(glGetError() == GL_NO_ERROR);
}
static void reshape(int x, int y)
{
glViewport(0, 0, x, y);
- /*
- float proj[16];
-
- cgm_mperspective(proj, cgm_deg_to_rad(50.0f), (float)x / (float)y, 0.5, 500.0);
-
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(proj);
- */
if(x > tex_width || y > tex_height) {
tex_width = nextpow2(x);
if(!(dx | dy)) return;
if(bnstate[0]) {
- cam_theta += dx * 0.01;
- cam_phi += dy * 0.01;
+ cam_theta -= dx * 0.01;
+ cam_phi -= dy * 0.01;
if(cam_phi < -M_PI) cam_phi = -M_PI;
if(cam_phi > M_PI) cam_phi = M_PI;
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef WIN32
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+#include "optcfg.h"
+
+struct optcfg {
+ struct optcfg_option *optlist;
+
+ optcfg_opt_callback opt_func;
+ void *opt_cls;
+ optcfg_arg_callback arg_func;
+ void *arg_cls;
+
+ int err_abort;
+
+ /* argument parsing state */
+ char **argv;
+ int argidx;
+ int disable_opt;
+
+ /* config file parsing state */
+ const char *cfg_fname;
+ int cfg_nline;
+ char *cfg_value;
+};
+
+static int get_opt(struct optcfg *oc, const char *s, int *disable_opt);
+static char *skip_spaces(char *s);
+static void strip_comments(char *s);
+static void strip_trailing_spaces(char *s);
+static char *parse_keyval(char *line);
+
+
+struct optcfg *optcfg_init(struct optcfg_option *optv)
+{
+ struct optcfg *oc;
+
+ if(!(oc = calloc(1, sizeof *oc))) {
+ return 0;
+ }
+ oc->optlist = optv;
+ oc->err_abort = 1;
+ return oc;
+}
+
+void optcfg_destroy(struct optcfg *oc)
+{
+ memset(oc, 0, sizeof *oc);
+ free(oc);
+}
+
+void optcfg_set_opt_callback(struct optcfg *oc, optcfg_opt_callback func, void *cls)
+{
+ oc->opt_func = func;
+ oc->opt_cls = cls;
+}
+
+void optcfg_set_arg_callback(struct optcfg *oc, optcfg_arg_callback func, void *cls)
+{
+ oc->arg_func = func;
+ oc->arg_cls = cls;
+}
+
+void optcfg_set_error_action(struct optcfg *oc, int act)
+{
+ if(act == OPTCFG_ERROR_FAIL) {
+ oc->err_abort = 1;
+ } else if(act == OPTCFG_ERROR_IGNORE) {
+ oc->err_abort = 0;
+ }
+}
+
+int optcfg_parse_args(struct optcfg *oc, int argc, char **argv)
+{
+ int i;
+
+ oc->argv = argv;
+
+ for(i=1; i<argc; i++) {
+ oc->argidx = i;
+
+ if(argv[i][0] == '-') {
+ if(oc->opt_func) {
+ int o = get_opt(oc, argv[i], &oc->disable_opt);
+ if(o == -1 || oc->opt_func(oc, o, oc->opt_cls) == -1) {
+ if(oc->err_abort) {
+ fprintf(stderr, "unexpected option: %s\n", argv[i]);
+ return -1;
+ }
+ }
+ } else {
+ fprintf(stderr, "unexpected option: %s\n", argv[i]);
+ if(oc->err_abort) {
+ return -1;
+ }
+ }
+ } else {
+ if(oc->arg_func) {
+ if(oc->arg_func(oc, argv[i], oc->arg_cls) == -1) {
+ if(oc->err_abort) {
+ fprintf(stderr, "unexpected argument: %s\n", argv[i]);
+ return -1;
+ }
+ }
+ } else {
+ fprintf(stderr, "unexpected argument: %s\n", argv[i]);
+ if(oc->err_abort) {
+ return -1;
+ }
+ }
+ }
+
+ i = oc->argidx;
+ }
+
+ oc->argidx = 0; /* done parsing args */
+ return 0;
+}
+
+int optcfg_parse_config_file(struct optcfg *oc, const char *fname)
+{
+ int res;
+ FILE *fp = fopen(fname, "rb");
+ if(!fp) {
+ return -1;
+ }
+
+ oc->cfg_fname = fname;
+ res = optcfg_parse_config_stream(oc, fp);
+ oc->cfg_fname = 0;
+ fclose(fp);
+ return res;
+}
+
+int optcfg_parse_config_stream(struct optcfg *oc, FILE *fp)
+{
+ char buf[512];
+
+ oc->cfg_nline = 0;
+ while(fgets(buf, sizeof buf, fp)) {
+ ++oc->cfg_nline;
+
+ if(optcfg_parse_config_line(oc, buf) == -1) {
+ if(oc->err_abort) {
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+int optcfg_parse_config_line(struct optcfg *oc, const char *line)
+{
+ int opt, len;
+ char *start, *val, *buf;
+
+ len = strlen(line);
+ buf = alloca(len + 1);
+ memcpy(buf, line, len + 1);
+
+ start = skip_spaces(buf);
+ strip_comments(start);
+ strip_trailing_spaces(start);
+ if(!*start) {
+ return 0;
+ }
+
+ if(!(val = parse_keyval(start))) {
+ fprintf(stderr, "error parsing %s line %d: invalid syntax\n", oc->cfg_fname ? oc->cfg_fname : "", oc->cfg_nline);
+ return -1;
+ }
+ oc->cfg_value = val;
+ if((opt = get_opt(oc, start, 0)) == -1) {
+ fprintf(stderr, "error parsing %s line %d: unknown option: %s\n", oc->cfg_fname ? oc->cfg_fname : "",
+ oc->cfg_nline, start);
+ return -1;
+ }
+
+ if(oc->opt_func) {
+ if(oc->opt_func(oc, opt, oc->opt_cls) == -1) {
+ return -1;
+ }
+ }
+ oc->cfg_value = 0;
+ return 0;
+}
+
+int optcfg_enabled_value(struct optcfg *oc, int *enabledp)
+{
+ if(oc->argidx) {
+ *enabledp = ~oc->disable_opt & 1;
+ } else {
+ char *val = optcfg_next_value(oc);
+ if(optcfg_bool_value(val, enabledp) == -1) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+char *optcfg_next_value(struct optcfg *oc)
+{
+ if(oc->argidx) { /* we're in the middle of parsing arguments, so get the next one */
+ return oc->argv[++oc->argidx];
+ }
+ if(oc->cfg_value) {
+ char *val = oc->cfg_value;
+ oc->cfg_value = 0;
+ return val;
+ }
+ return 0;
+}
+
+void optcfg_print_options(struct optcfg *oc)
+{
+ int i;
+ for(i=0; oc->optlist[i].opt != -1; i++) {
+ struct optcfg_option *opt = oc->optlist + i;
+
+ if(opt->c) {
+ printf(" -%c", opt->c);
+ } else {
+ printf(" ");
+ }
+ if(opt->s) {
+ printf("%c-%s: ", opt->c ? ',' : ' ', opt->s);
+ } else {
+ printf(": ");
+ }
+ printf("%s\n", opt->desc ? opt->desc : "undocumented");
+ }
+}
+
+int optcfg_bool_value(char *s, int *valret)
+{
+ if(strcasecmp(s, "yes") == 0 || strcasecmp(s, "true") == 0 || strcmp(s, "1") == 0) {
+ *valret = 1;
+ return 0;
+ }
+ if(strcasecmp(s, "no") == 0 || strcasecmp(s, "false") == 0 || strcmp(s, "0") == 0) {
+ *valret = 0;
+ return 0;
+ }
+ return -1;
+}
+
+int optcfg_int_value(char *str, int *valret)
+{
+ char *endp;
+ *valret = strtol(str, &endp, 0);
+ if(endp == str) {
+ return -1;
+ }
+ return 0;
+}
+
+int optcfg_float_value(char *str, float *valret)
+{
+ char *endp;
+ *valret = strtod(str, &endp);
+ if(endp == str) {
+ return -1;
+ }
+ return 0;
+}
+
+
+
+static int get_opt(struct optcfg *oc, const char *arg, int *disable_opt)
+{
+ int i, ndashes = 0;
+
+ while(*arg && *arg == '-') {
+ ++ndashes;
+ ++arg;
+ }
+
+ if(ndashes > 2) {
+ arg -= ndashes;
+ ndashes = 0;
+ }
+
+ if(disable_opt) {
+ if(ndashes && (strstr(arg, "no-") == arg || strstr(arg, "disable-") == arg)) {
+ *disable_opt = 1;
+ arg = strchr(arg, '-') + 1; /* guaranteed to exist at this point */
+ } else {
+ *disable_opt = 0;
+ }
+ }
+
+ if(arg[1]) { /* match long options */
+ for(i=0; oc->optlist[i].opt != -1; i++) {
+ if(strcmp(arg, oc->optlist[i].s) == 0) {
+ return i;
+ }
+ }
+ } else {
+ for(i=0; oc->optlist[i].opt != -1; i++) {
+ if(arg[0] == oc->optlist[i].c) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+static char *skip_spaces(char *s)
+{
+ while(*s && isspace(*s)) ++s;
+ return s;
+}
+
+static void strip_comments(char *s)
+{
+ while(*s && *s != '#') ++s;
+ if(*s == '#') *s = 0;
+}
+
+static void strip_trailing_spaces(char *s)
+{
+ char *end = s + strlen(s) - 1;
+ while(end >= s && isspace(*end)) {
+ *end-- = 0;
+ }
+}
+
+static char *parse_keyval(char *line)
+{
+ char *val;
+ char *eq = strchr(line, '=');
+ if(!eq) return 0;
+
+ *eq = 0;
+ strip_trailing_spaces(line);
+ val = skip_spaces(eq + 1);
+ strip_trailing_spaces(val);
+
+ if(!*line || !*val) {
+ return 0;
+ }
+ return val;
+}
--- /dev/null
+/* generic unified commandline option and config file parsing library */
+#ifndef LIBOPTCFG_H_
+#define LIBOPTCFG_H_
+
+#include <stdio.h>
+
+struct optcfg;
+
+struct optcfg_option {
+ char c; /* short (optional): used only for argument parsing */
+ const char *s; /* long: used for long options and config files */
+ int opt; /* the corresponding option enumeration */
+ const char *desc; /* text description for printing usage information */
+};
+
+#define OPTCFG_OPTIONS_END {0, 0, -1, 0}
+
+typedef int (*optcfg_opt_callback)(struct optcfg *oc, int opt, void *cls);
+typedef int (*optcfg_arg_callback)(struct optcfg *oc, const char *arg, void *cls);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* initialize the optcfg object with a valid option vector terminated by an
+ * entry with an opt value of -1 (other fields ignored for termination purposes)
+ *
+ * Example:
+ * struct optcfg_option options[] = {
+ * {'f', "foo", OPT_FOO, "Makes sure the foo is bar"},
+ * {'h', "help", OPT_HELP, "Print usage information and exit"},
+ * OPTCFG_OPTIONS_END
+ * };
+ * struct optcfg *oc = optcfg_init(options);
+ */
+struct optcfg *optcfg_init(struct optcfg_option *optv);
+void optcfg_destroy(struct optcfg *oc);
+
+/* The parse_* functions call the option callback for each option.
+ *
+ * The option callback can then call optcfg_next_value to retrieve any
+ * values attached to this option. When optcfg_next_value returns 0, there
+ * are no more values available.
+ * The option callback must return 0 for success, and -1 to abort parsing.
+ */
+void optcfg_set_opt_callback(struct optcfg *oc, optcfg_opt_callback func, void *cls);
+/* the argument callback is only called from optcfg_parse_args(), when a non-option
+ * argument is encountered (an argument not starting with a dash)
+ */
+void optcfg_set_arg_callback(struct optcfg *oc, optcfg_arg_callback func, void *cls);
+
+enum { OPTCFG_ERROR_FAIL, OPTCFG_ERROR_IGNORE };
+void optcfg_set_error_action(struct optcfg *oc, int act);
+
+int optcfg_parse_args(struct optcfg *oc, int argc, char **argv);
+int optcfg_parse_config_file(struct optcfg *oc, const char *fname);
+int optcfg_parse_config_stream(struct optcfg *oc, FILE *fp);
+int optcfg_parse_config_line(struct optcfg *oc, const char *line);
+/* TODO custom I/O callback version of config file parsing */
+
+/* special value function which returns if the option is enabled or disabled
+ * For config files it works similar to calling optcfg_next_value, and
+ * optcfg_bool_value in sequence.
+ * For argument parsing however, it doesn't consume further arguments. Merely
+ * the presence of the option makes it enabled, and its presence with a -no-
+ * or -disable- prefix disables it.
+ */
+int optcfg_enabled_value(struct optcfg *oc, int *enabledp);
+
+/* call optcfg_next_value in the option callback to retrieve the next value
+ * of the current option. returns 0 if there is no next value.
+ */
+char *optcfg_next_value(struct optcfg *oc);
+
+/* helper function which can be used to print the available options */
+void optcfg_print_options(struct optcfg *oc);
+
+/* helper functions to convert value strings to typed values
+ * returns 0 for success and value is returned through the valret pointer,
+ * otherwise it returns -1 for type mismatch, and valret contents are undefined
+ */
+int optcfg_bool_value(char *str, int *valret); /* accepts yes/no, true/false, 1/0 */
+int optcfg_int_value(char *str, int *valret);
+int optcfg_float_value(char *str, float *valret);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBOPTCFG_H_ */