+
+static void expected(ParserState *ps, const char *str)
+{
+ fprintf(stderr, "%s line %d error, expected: %s\n", ps->fname, ps->nline, str);
+ ++ps->nerrors;
+}
+
+static void set_var(ParserState *ps, const char *name, const Value &value)
+{
+ ps->var[name] = value;
+}
+
+static bool have_var(ParserState *ps, const char *name)
+{
+ return ps->var.find(name) != ps->var.end();
+}
+
+static const Value &get_var(ParserState *ps, const char *name)
+{
+ return ps->var[name];
+}
+
+static void print_value(const Value &val, FILE *fp)
+{
+ switch(val.type) {
+ case VAL_NUM:
+ fprintf(fp, "%f", val.v[0]);
+ break;
+
+ case VAL_VEC:
+ fprintf(fp, "[%f %f %f %f]", val.v[0], val.v[1], val.v[2], val.v[3]);
+ break;
+
+ case VAL_STR:
+ fprintf(fp, "\"%s\"", val.str);
+ break;
+
+ default:
+ fprintf(fp, "<invalid>");
+ }
+}
+
+// Gear-specific stuff
+
+static void update_gear_vars(ParserState *ps, Gear *gear)
+{
+ if(!ps->last_mod_var.empty()) {
+ const char *name = ps->last_mod_var.c_str();
+ set_gear_var(gear, name, get_var(ps, name));
+ ps->last_mod_var.clear();
+ return;
+ }
+
+ std::map<std::string, Value>::const_iterator it = ps->var.begin();
+ while(it != ps->var.end()) {
+ set_gear_var(gear, it->first.c_str(), it->second);
+ ++it;
+ }
+}
+
+
+#define ASSERT_TYPE(v, t) \
+ do { \
+ if((v).type != (t)) { \
+ fprintf(stderr, "type mismatch while trying to set %s to value: ", name); \
+ print_value(val, stderr); \
+ fputc('\n', stderr); \
+ return false; \
+ } \
+ } while(0)
+
+#define VVEC3(val) Vec3((val).v[0], (val).v[1], (val).v[2])
+#define VVEC4(val) Vec4((val).v[0], (val).v[1], (val).v[2], (val).v[3])
+
+static bool set_gear_var(Gear *gear, const char *name, const Value &val)
+{
+ if(strcmp(name, "position") == 0) {
+ ASSERT_TYPE(val, VAL_VEC);
+ gear->pos = VVEC3(val);
+
+ } else if(strcmp(name, "plane") == 0) {
+ ASSERT_TYPE(val, VAL_VEC);
+ gear->axis = VVEC3(val);
+ gear->pdist = val.v[3];
+
+ } else if(strcmp(name, "thickness") == 0) {
+ ASSERT_TYPE(val, VAL_NUM);
+ gear->thickness = val.v[0];
+
+ } else if(strcmp(name, "teeth") == 0) {
+ ASSERT_TYPE(val, VAL_NUM);
+ gear->set_teeth(val.v[0]); // set teeth and recalc radius
+
+ } else if(strcmp(name, "teeth_length") == 0) {
+ ASSERT_TYPE(val, VAL_NUM);
+ gear->teeth_length = val.v[0];
+
+ } else if(strcmp(name, "pitch") == 0) {
+ ASSERT_TYPE(val, VAL_NUM);
+ gear->set_teeth(gear->nteeth, val.v[0]); // set pitch and recalc radius
+
+ } else if(strcmp(name, "color") == 0) {
+ ASSERT_TYPE(val, VAL_VEC);
+ gear->color = VVEC3(val);
+
+ } else if(strcmp(name, "roughness") == 0) {
+ ASSERT_TYPE(val, VAL_NUM);
+ gear->roughness = val.v[0];
+
+ } else {
+ return false;
+ }
+
+ return true;
+}