added func_coaxial
[antikythera] / src / mparser.cc
index 10ea6ba..91b1b80 100644 (file)
@@ -81,6 +81,7 @@ static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const
 
 // built-in functions
 static bool func_adjacent(ParserState *ps);
+static bool func_coaxial(ParserState *ps);
 
 
 bool parse_machine(Machine *mcn, const char *fname)
@@ -100,6 +101,7 @@ bool parse_machine(Machine *mcn, const char *fname)
 
        // init built-in function table
        set_func(&pstate, "adjacent", func_adjacent, 2);
+       set_func(&pstate, "coaxial", func_coaxial, 2);
 
        nextchar(&pstate);
        bool res = machine(&pstate);
@@ -602,6 +604,10 @@ static bool end_gear(ParserState *ps)
        printf("DBG: adding gear: %s\n", gear->name.c_str());
        ps->gears[gear->name] = gear;
        ps->mcn->add_gear(gear);
+
+       if(!ps->cur_gear.empty()) {
+               ps->cur_gear.top()->attach(gear);
+       }
        return true;
 }
 
@@ -717,15 +723,15 @@ static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const
 // built-in functions
 static bool func_adjacent(ParserState *ps)
 {
-       Value val_dir = ps->val.top(); ps->val.pop();
+       Value val_angle = ps->val.top(); ps->val.pop();
        Value val_gear_name = ps->val.top(); ps->val.pop();
 
        if(val_gear_name.type != VAL_STR) {
                expected(ps, "gear name (string) as 1st arg to adjacent");
                return false;
        }
-       if(val_dir.type != VAL_VEC) {
-               expected(ps, "direction vector as 2nd arg to adjacent");
+       if(val_angle.type != VAL_NUM) {
+               expected(ps, "angle as 2nd arg to adjacent");
                return false;
        }
 
@@ -741,11 +747,50 @@ static bool func_adjacent(ParserState *ps)
                return false;
        }
 
-       Vec3 dir = Vec3(val_dir.v[0], val_dir.v[1], val_dir.v[2]);
+       Mat4 xform;
+       xform.rotation(deg_to_rad(val_angle.v[0]), gother->axis);
+       Vec3 dir = xform * Vec3(0, 1, 0);
 
        float sum_radii = gthis->radius + gother->radius;
        float avg_teeth_len = (gthis->teeth_length + gother->teeth_length) * 0.5;
-       Vec3 pos = gother->pos + normalize(dir) * (sum_radii - avg_teeth_len * 0.75);
+       Vec3 pos = gother->pos + dir * (sum_radii - avg_teeth_len * 0.75);
+
+       Value res;
+       res.type = VAL_VEC;
+       res.v[0] = pos.x;
+       res.v[1] = pos.y;
+       res.v[2] = pos.z;
+       ps->val.push(res);
+       return true;
+}
+
+static bool func_coaxial(ParserState *ps)
+{
+       Value val_dist = ps->val.top(); ps->val.pop();
+       Value val_gear_name = ps->val.top(); ps->val.pop();
+
+       if(val_gear_name.type != VAL_STR) {
+               expected(ps, "gear name (string) as 1st arg to func_coaxial");
+               return false;
+       }
+       if(val_dist.type != VAL_NUM) {
+               expected(ps, "stacking distance as 2nd arg to func_coaxial");
+               return false;
+       }
+
+       Gear *gthis = this_gear(ps);
+       if(!gthis) {
+               errmsg(ps, "coaxial: called outside of a gear block");
+               return false;
+       }
+
+       Gear *gother = ps->gears[val_gear_name.s];
+       if(!gother) {
+               errmsg(ps, "coaxial: gear \"%s\" not found", val_gear_name.s.c_str());
+               return false;
+       }
+
+       Vec3 pos = gother->pos + gother->axis * val_dist.v[0];
 
        Value res;
        res.type = VAL_VEC;