From a58455a92c7ecab980cbe1b7e282aeb6bfe7e889 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Thu, 20 Oct 2016 22:04:17 +0300 Subject: [PATCH] refactoring --- .gitignore | 4 +- Makefile | 26 +- src/gear.cc | 309 ------------------ src/gear.h | 116 ------- src/machine.cc | 269 ---------------- src/machine.h | 43 --- src/machine/gear.cc | 309 ++++++++++++++++++ src/machine/gear.h | 116 +++++++ src/machine/machine.cc | 269 ++++++++++++++++ src/machine/machine.h | 43 +++ src/machine/mparser.cc | 819 ++++++++++++++++++++++++++++++++++++++++++++++++ src/machine/mparser.h | 9 + src/main.cc | 37 +-- src/mparser.cc | 819 ------------------------------------------------ src/mparser.h | 9 - 15 files changed, 1588 insertions(+), 1609 deletions(-) delete mode 100644 src/gear.cc delete mode 100644 src/gear.h delete mode 100644 src/machine.cc delete mode 100644 src/machine.h create mode 100644 src/machine/gear.cc create mode 100644 src/machine/gear.h create mode 100644 src/machine/machine.cc create mode 100644 src/machine/machine.h create mode 100644 src/machine/mparser.cc create mode 100644 src/machine/mparser.h delete mode 100644 src/mparser.cc delete mode 100644 src/mparser.h diff --git a/.gitignore b/.gitignore index fe1e9f6..6871807 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ *.o *.swp *.d -anti +demo +data/ +.clang_complete diff --git a/Makefile b/Makefile index 228e095..3c0cb0a 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,32 @@ -src = $(wildcard src/*.cc) -csrc = $(wildcard src/*.c) +src = $(wildcard src/*.cc) $(wildcard src/machine/*.cc) +csrc = $(wildcard src/*.c) $(wildcard src/machine/*.c) obj = $(src:.cc=.o) $(csrc:.c=.o) dep = $(obj:.o=.d) -bin = anti +bin = demo -CFLAGS = -pedantic -Wall -g -I/usr/local/include -CXXFLAGS = -std=c++11 -pedantic -Wall -g -I/usr/local/include -LDFLAGS = -L/usr/local/lib $(libgl_$(sys)) -lm -lgmath -lvmath -limago -lresman -lpthread +opt = -O0 +dbg = -g + +incpath = -Isrc -Isrc/machine -I/usr/local/include +libpath = -L/usr/local/lib + +warn = -pedantic -Wall + +CFLAGS = $(warn) $(opt) $(dbg) $(incpath) +CXXFLAGS = -std=c++11 $(warn) $(opt) $(dbg) $(incpath) +LDFLAGS = $(libpath) $(libgl_$(sys)) -lm -lgmath -lvmath -limago -lresman -lpthread sys = $(shell uname -s) libgl_Linux = -lGL -lGLU -lglut -lGLEW libgl_Darwin = -framework OpenGL -framework GLUT -lGLEW -$(bin): $(obj) +$(bin): .clang_complete $(obj) $(CXX) -o $@ $(obj) $(LDFLAGS) +.clang_complete: Makefile + rm -f $@ + for i in $(CXXFLAGS); do echo $$i >>$@; done + -include $(dep) %.d: %.c diff --git a/src/gear.cc b/src/gear.cc deleted file mode 100644 index 6a34815..0000000 --- a/src/gear.cc +++ /dev/null @@ -1,309 +0,0 @@ -#include -#include -#include "gear.h" -#include "meshgen.h" -#include "app.h" - -Gear::Gear() - : axis(0, 0, 1) -{ - pdist = 0; - angle = 0; - teeth_length = 5; - thickness = 5; - bevel = 1.5; - init_angle = 0; - xform_valid = false; - - set_teeth(42, 10); - - supergear = 0; - - mesh = 0; - - color = Vec3(0.6, 0.6, 0.6); - roughness = 1.0; - metallic = false; -} - -Gear::~Gear() -{ - delete mesh; -} - -void Gear::attach(Gear *g) -{ - if(g->supergear) { - if(g->supergear == this) { - return; - } - g->supergear->detach(g); - } - g->supergear = this; - subgears.push_back(g); - - // make co-axial - g->axis = axis; - g->pos.x = pos.x; - g->pos.y = pos.y; -} - -bool Gear::detach(Gear *g) -{ - int nsubgears = (int)subgears.size(); - for(int i=0; isupergear = 0; - return true; - } - } - return false; -} - -Gear *Gear::get_super() const -{ - return supergear; -} - -void Gear::set_angular_offset(float offs) -{ - init_angle = offs; - xform_valid = false; -} - -float Gear::get_angular_offset() const -{ - return init_angle; -} - -void Gear::set_teeth(int nt, float tooth_pitch) -{ - if(tooth_pitch <= 0) { - tooth_pitch = this->tooth_pitch; - } else { - this->tooth_pitch = tooth_pitch; - } - float circ = tooth_pitch * nt; - radius = circ / (2.0 * M_PI); - nteeth = nt; -} - -void Gear::set_axis(const Vec3 &axis) -{ - this->axis = normalize(axis); - xform_valid = false; -} - -const Vec3 &Gear::get_axis() const -{ - return axis; -} - -void Gear::set_position(const Vec3 &pos) -{ - if(!supergear) { - this->pos = pos; - } else { - this->pos = supergear->pos; - this->pos.z = pos.z; - } - xform_valid = false; - - for(int i=0; i<(int)subgears.size(); i++) { - Vec3 subpos = this->pos; - subpos.z = subgears[i]->pos.z; - subgears[i]->set_position(subpos); - } -} - -const Vec3 &Gear::get_position() const -{ - return pos; -} - -Vec3 Gear::get_global_position() const -{ - const Mat4 &m = get_matrix(); - return m * Vec3(0, 0, 0); -} - -void Gear::set_angle(float angle) -{ - this->angle = angle; - xform_valid = false; -} - -float Gear::get_angle() const -{ - return angle; -} - -float Gear::get_vis_rotation() const -{ - return fmod(init_angle + angle, M_PI * 2.0); -} - -const Mat4 &Gear::get_matrix() const -{ - if(!xform_valid) { - calc_matrix(); - xform_valid = true; - } - return xform; -} - -const Mat4 &Gear::get_dir_matrix() const -{ - if(!xform_valid) { - calc_matrix(); - xform_valid = true; - } - return dir_xform; -} - -float Gear::get_angular_pitch() const -{ - return 2.0 * M_PI / (float)nteeth; -} - -void Gear::draw() const -{ - if(!mesh) { - if(!((Gear*)this)->gen_mesh()) { - abort(); - } - } - if(!xform_valid) { - calc_matrix(); - } - - glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_LIGHTING_BIT); - - glPushMatrix(); - glMultMatrixf(xform[0]); - - if(opt_gear_wireframe) { - glPolygonOffset(1, 1); - glEnable(GL_POLYGON_OFFSET_FILL); - } - - Vec3 diffuse = metallic ? Vec3(0, 0, 0) : color; - float col[] = {diffuse.x, diffuse.y, diffuse.z, 1.0}; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); - - Vec3 specular = (metallic ? color : Vec3(1, 1, 1)) * (1.0 - roughness); - float scol[] = {specular.x, specular.y, specular.z, 1.0}; - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol); - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 1.0 + (1.0 - roughness) * 60.0); - - mesh->draw(); - - glDisable(GL_LIGHTING); - - if(opt_gear_wireframe) { - glColor3f(0.2, 0.4, 1.0); - mesh->draw_wire(); - } - - glPopMatrix(); - glPopAttrib(); -} - -void Gear::draw_wire(float wire_width) const -{ - if(!mesh) { - if(!((Gear*)this)->gen_mesh()) { - abort(); - } - } - if(!xform_valid) { - calc_matrix(); - } - - glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT); - glLineWidth(wire_width); - glDisable(GL_LIGHTING); - - glPushMatrix(); - glMultMatrixf(xform[0]); - - mesh->draw_wire(); - - glPopMatrix(); - glPopAttrib(); -} - -static Vec2 rev_pos(float u, float v, void *cls) -{ - Gear *gear = (Gear*)cls; - - float y = ((v - 1.0 / 3.0) / (1.0 / 3.0) - 0.5); - if(y < -0.5) y = -0.5; - if(y > 0.5) y = 0.5; - y *= gear->thickness; - - if(v < 0.001 || v > 0.999) { - return Vec2(0, -y); - } - - float nt = (float)gear->nteeth * 4.0; - - int part = (int)(u * nt) % 4; /* 4 parts to a tooth /#\_ */ - float t = fmod(u * nt * 4.0, 1.0); - - float offs; - switch(part) { - case 0: - offs = t; - break; - case 1: - offs = 1.0f; - break; - case 2: - offs = 1.0f - t; - break; - case 3: - offs = 0.0f; - } - - float inner_rad = gear->radius - gear->teeth_length; - return Vec2(inner_rad + offs * gear->teeth_length, -y); -} - -bool Gear::gen_mesh() -{ - mesh = new Mesh; - gen_revol(mesh, nteeth * 4, 3, rev_pos, 0, this); - mesh->explode(); - mesh->calc_face_normals(); - - float fix_tooth_up = get_angular_pitch() * 3.0 / 8.0; - - Mat4 rot; - rot.rotation_x(M_PI / 2.0); - rot.rotate_z(fix_tooth_up); - mesh->apply_xform(rot, rot); - - mesh->set_vis_vecsize(6.0); - return true; -} - -void Gear::calc_matrix() const -{ - Vec3 up = Vec3(0, 1, 0); - if(1.0 - fabs(dot(up, axis)) < 1e-4) { - up = Vec3(0, 0, -1); - } - Vec3 right = normalize(cross(up, axis)); - up = cross(axis, right); - - dir_xform = Mat4(right, up, axis); - - xform = dir_xform; - xform.rotate_z(get_vis_rotation()); - xform.translate(pos); - - axel_xform = dir_xform; - axel_xform.translate(pos); -} diff --git a/src/gear.h b/src/gear.h deleted file mode 100644 index fac245c..0000000 --- a/src/gear.h +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef GEAR_H_ -#define GEAR_H_ - -#include -#include -#include -#include "mesh.h" - -/* distance unit: millimeters - * angle unit: radians - */ - -class Gear; -struct GearPin; -struct GearSlot; - -struct GearPin { - float radius; - float height; - - Gear *parent; - /* position in polar coordinates on the parent gear */ - float pos_dist, pos_angle; - - GearSlot *conn_slot; /* slot connection */ -}; - -struct GearSlot { - float radius, length; - - Gear *parent; - /* position in polar coordinates on the parent gear */ - float pos_dist_min, pos_dist_max, pos_angle; - - GearPin *conn_pin; /* pin connection */ -}; - -class Gear { -private: - Mesh *mesh; - - mutable Mat4 xform, dir_xform, axel_xform; - mutable bool xform_valid; - void calc_matrix() const; - - float contour(float u); - -public: - - /* TODO hide most of this shit, especially the stuff which invalidate - * the transformation matrices - */ - std::string name; - Vec3 pos, axis; // implicitly defines a plane eqn. - float pdist; // derived: distance of plane from origin - - float init_angle; // initial starting angle - float angle; // current angle of the gear - - int nteeth; // number of teeth - float tooth_pitch; - - float radius; // total radius of the gear, including teeth - float teeth_length; // how far teeth extend past the radius - float thickness; // thickness of the gear along the Z axis - - float bevel; // bevel size - - // visual surface properties - Vec3 color; - float roughness; - bool metallic; - - Gear *supergear; - std::vector subgears; - std::vector pins; - std::vector slots; - - Gear(); - ~Gear(); - - void attach(Gear *g); - bool detach(Gear *g); - Gear *get_super() const; - - void set_angular_offset(float offs); - float get_angular_offset() const; - - // sets the supplied number of teeth, and calculates the radius - // of the gear, to achieve the required tooth pitch - void set_teeth(int nt, float tooth_pitch = 0.0f); - void set_axis(const Vec3 &axis); - const Vec3 &get_axis() const; - void set_position(const Vec3 &pos); - const Vec3 &get_position() const; - Vec3 get_global_position() const; // taking parent gear into account - - Vec3 get_planar_position() const; // 2D pos of gear on its plane - - void set_angle(float angle); - float get_angle() const; - - float get_vis_rotation() const; - const Mat4 &get_matrix() const; - const Mat4 &get_dir_matrix() const; - - // returns the angle (in radians) from one tooth to the next - float get_angular_pitch() const; - - void draw() const; - void draw_wire(float line_width = 1.0f) const; - - bool gen_mesh(); -}; - -#endif // GEAR_H_ diff --git a/src/machine.cc b/src/machine.cc deleted file mode 100644 index 441826e..0000000 --- a/src/machine.cc +++ /dev/null @@ -1,269 +0,0 @@ -#include -#include -#include -#include -#include -#include "opengl.h" -#include "machine.h" - -static float delta_angle(float a, float b); - -Machine::Machine() -{ - meshing = 0; - meshing_valid = false; - visited = 0; -} - -Machine::~Machine() -{ - int ngears = (int)gears.size(); - for(int i=0; i::const_iterator it = gearidx.find(g); - if(it == gearidx.end()) { - return -1; - } - return it->second; -} - -void Machine::invalidate_meshing() -{ - meshing_valid = false; -} - -void Machine::calc_meshing() -{ - int ngears = (int)gears.size(); - - if(!meshing) { - meshing = new bool*[ngears]; - meshing[0] = new bool[ngears * ngears]; - - for(int i=1; iget_position(); - } - - for(int i=0; iget_super() == gears[j] || gears[j]->get_super() == gears[i]) { - // don't attempt meshing if it's the same gear, or they are attached to each other - continue; - } - - if(1.0 - fabs(dot(gears[i]->axis, gears[j]->axis)) < 1e-5) { - // co-planar, just check Z range after inverse-transforming to the XY plane - if(fabs(ppos[i].z - ppos[j].z) > (gears[i]->thickness + gears[j]->thickness) / 2.0) { - continue; - } - // Z interval match, check distance - float dsq = length_sq(ppos[i].xy() - ppos[j].xy()); - - float outer_rad_sum = gears[i]->radius + gears[j]->radius; - float inner_rad_sum = outer_rad_sum - gears[i]->teeth_length - gears[j]->teeth_length; - - if(dsq <= outer_rad_sum * outer_rad_sum && dsq >= inner_rad_sum * inner_rad_sum) { - //printf("connecting co-planar gears %d - %d\n", i, j); - meshing[i][j] = meshing[j][i] = true; - } - - } else { - /* TODO: not co-planar - * - calc line of intersection between the two planes - * - find distance of each gear to that line - * - profit... - */ - } - } - } - - // fix the initial angles so that teeth mesh as best as possible - // should work in one pass as long as the gear train is not impossible - for(int i=0; iangle + gears[i]->get_angular_pitch() / 2.0; - float snap = rnd - fmod(rnd, gears[i]->get_angular_pitch()); - gears[i]->set_angle(snap);*/ - gears[i]->set_angular_offset(0); - } - - for(int i=0; iinit_angle + rel_angle) / gears[i]->get_angular_pitch() + 100.0, 1.0); - float frac_j = fmod((gears[j]->init_angle - rel_angle) / gears[j]->get_angular_pitch() + 100.0, 1.0); - assert(frac_i >= 0.0 && frac_j >= 0.0); - float delta = frac_j - frac_i; - - float correction = 0.5 - delta; - float prev_offs = gears[j]->get_angular_offset(); - gears[j]->set_angular_offset(prev_offs + correction * gears[j]->get_angular_pitch()); - } - } - } - - /* - printf("meshing graph\n"); - for(int i=0; iangle) > 0.25 / gear->nteeth) { - fprintf(stderr, "warning: trying to transmit different values to gear %s (%d)\n", - gear->name.c_str(), idx); - gear->angle = 0; - } - return; - } - - gear->set_angle(angle); - visited[idx] = true; - - // propagate to meshing gears (depth-first) - int ngears = (int)gears.size(); - for(int i=0; inteeth / (float)gears[i]->nteeth; - update_gear(i, angle * ratio); - } - - // propagate to rigidly attached gears - if(gear->supergear) { - int supidx = gearidx[gear->supergear]; - update_gear(supidx, angle); - } - - int nsub = (int)gear->subgears.size(); - for(int i=0; isubgears[i]]; - update_gear(subidx, angle); - } -} - -void Machine::update(float dt) -{ - int ngears = (int)gears.size(); - - if(!meshing_valid) { - calc_meshing(); - meshing_valid = true; - } - - memset(visited, 0, ngears * sizeof *visited); - for(size_t i=0; iangle + dt * motors[i].speed); - } -} - -void Machine::draw() const -{ - for(size_t i=0; idraw(); - } - - float dcol[] = {0.4, 0.4, 0.4, 1.0}; - float scol[] = {0, 0, 0, 0}; - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dcol); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol); - - glBegin(GL_QUADS); - glNormal3f(0, 1, 0); - glVertex3f(-300, -100, 300); - glVertex3f(300, -100, 300); - glVertex3f(300, -100, -300); - glVertex3f(-300, -100, -300); - glEnd(); -} - -Gear *Machine::intersect_gear(const Ray &ray, HitPoint *hitp) const -{ - Gear *res = 0; - HitPoint nearest; - nearest.dist = FLT_MAX; - - for(size_t i=0; iget_global_position(); - float rad = gears[i]->radius; - - Plane plane = Plane(pos, gears[i]->axis); - - HitPoint hit; - if(plane.intersect(ray, &hit) && hit.dist < nearest.dist && - length_sq(hit.pos - pos) <= rad * rad) { - nearest = hit; - res = gears[i]; - } - } - - if(hitp) *hitp = nearest; - return res; -} - -static float delta_angle(float a, float b) -{ - float api = fmod(a + M_PI, 2.0 * M_PI); - float bpi = fmod(b + M_PI, 2.0 * M_PI); - return std::min(fabs(a - b), fabs(api - bpi)); -} diff --git a/src/machine.h b/src/machine.h deleted file mode 100644 index 097157d..0000000 --- a/src/machine.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef MACHINE_H_ -#define MACHINE_H_ - -#include -#include -#include "gear.h" - -struct Motor { - float speed; /* signed to denote direction, in Hz */ - int drive; /* which gear it drives */ -}; - -class Machine { -private: - std::vector gears; - std::map gearidx; - bool **meshing; - bool meshing_valid; - bool *visited; /* used for update_gear */ - - std::vector motors; - - void update_gear(int idx, float angle); - -public: - Machine(); - ~Machine(); - - void add_gear(Gear *g); /* takes ownership */ - void add_motor(int gearidx, float speed_hz); - - int get_gear_index(Gear *g) const; - - void invalidate_meshing(); - void calc_meshing(); - - void update(float dt); - void draw() const; - - Gear *intersect_gear(const Ray &ray, HitPoint *hitp = 0) const; -}; - -#endif // MACHINE_H_ diff --git a/src/machine/gear.cc b/src/machine/gear.cc new file mode 100644 index 0000000..6a34815 --- /dev/null +++ b/src/machine/gear.cc @@ -0,0 +1,309 @@ +#include +#include +#include "gear.h" +#include "meshgen.h" +#include "app.h" + +Gear::Gear() + : axis(0, 0, 1) +{ + pdist = 0; + angle = 0; + teeth_length = 5; + thickness = 5; + bevel = 1.5; + init_angle = 0; + xform_valid = false; + + set_teeth(42, 10); + + supergear = 0; + + mesh = 0; + + color = Vec3(0.6, 0.6, 0.6); + roughness = 1.0; + metallic = false; +} + +Gear::~Gear() +{ + delete mesh; +} + +void Gear::attach(Gear *g) +{ + if(g->supergear) { + if(g->supergear == this) { + return; + } + g->supergear->detach(g); + } + g->supergear = this; + subgears.push_back(g); + + // make co-axial + g->axis = axis; + g->pos.x = pos.x; + g->pos.y = pos.y; +} + +bool Gear::detach(Gear *g) +{ + int nsubgears = (int)subgears.size(); + for(int i=0; isupergear = 0; + return true; + } + } + return false; +} + +Gear *Gear::get_super() const +{ + return supergear; +} + +void Gear::set_angular_offset(float offs) +{ + init_angle = offs; + xform_valid = false; +} + +float Gear::get_angular_offset() const +{ + return init_angle; +} + +void Gear::set_teeth(int nt, float tooth_pitch) +{ + if(tooth_pitch <= 0) { + tooth_pitch = this->tooth_pitch; + } else { + this->tooth_pitch = tooth_pitch; + } + float circ = tooth_pitch * nt; + radius = circ / (2.0 * M_PI); + nteeth = nt; +} + +void Gear::set_axis(const Vec3 &axis) +{ + this->axis = normalize(axis); + xform_valid = false; +} + +const Vec3 &Gear::get_axis() const +{ + return axis; +} + +void Gear::set_position(const Vec3 &pos) +{ + if(!supergear) { + this->pos = pos; + } else { + this->pos = supergear->pos; + this->pos.z = pos.z; + } + xform_valid = false; + + for(int i=0; i<(int)subgears.size(); i++) { + Vec3 subpos = this->pos; + subpos.z = subgears[i]->pos.z; + subgears[i]->set_position(subpos); + } +} + +const Vec3 &Gear::get_position() const +{ + return pos; +} + +Vec3 Gear::get_global_position() const +{ + const Mat4 &m = get_matrix(); + return m * Vec3(0, 0, 0); +} + +void Gear::set_angle(float angle) +{ + this->angle = angle; + xform_valid = false; +} + +float Gear::get_angle() const +{ + return angle; +} + +float Gear::get_vis_rotation() const +{ + return fmod(init_angle + angle, M_PI * 2.0); +} + +const Mat4 &Gear::get_matrix() const +{ + if(!xform_valid) { + calc_matrix(); + xform_valid = true; + } + return xform; +} + +const Mat4 &Gear::get_dir_matrix() const +{ + if(!xform_valid) { + calc_matrix(); + xform_valid = true; + } + return dir_xform; +} + +float Gear::get_angular_pitch() const +{ + return 2.0 * M_PI / (float)nteeth; +} + +void Gear::draw() const +{ + if(!mesh) { + if(!((Gear*)this)->gen_mesh()) { + abort(); + } + } + if(!xform_valid) { + calc_matrix(); + } + + glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_LIGHTING_BIT); + + glPushMatrix(); + glMultMatrixf(xform[0]); + + if(opt_gear_wireframe) { + glPolygonOffset(1, 1); + glEnable(GL_POLYGON_OFFSET_FILL); + } + + Vec3 diffuse = metallic ? Vec3(0, 0, 0) : color; + float col[] = {diffuse.x, diffuse.y, diffuse.z, 1.0}; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); + + Vec3 specular = (metallic ? color : Vec3(1, 1, 1)) * (1.0 - roughness); + float scol[] = {specular.x, specular.y, specular.z, 1.0}; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 1.0 + (1.0 - roughness) * 60.0); + + mesh->draw(); + + glDisable(GL_LIGHTING); + + if(opt_gear_wireframe) { + glColor3f(0.2, 0.4, 1.0); + mesh->draw_wire(); + } + + glPopMatrix(); + glPopAttrib(); +} + +void Gear::draw_wire(float wire_width) const +{ + if(!mesh) { + if(!((Gear*)this)->gen_mesh()) { + abort(); + } + } + if(!xform_valid) { + calc_matrix(); + } + + glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT); + glLineWidth(wire_width); + glDisable(GL_LIGHTING); + + glPushMatrix(); + glMultMatrixf(xform[0]); + + mesh->draw_wire(); + + glPopMatrix(); + glPopAttrib(); +} + +static Vec2 rev_pos(float u, float v, void *cls) +{ + Gear *gear = (Gear*)cls; + + float y = ((v - 1.0 / 3.0) / (1.0 / 3.0) - 0.5); + if(y < -0.5) y = -0.5; + if(y > 0.5) y = 0.5; + y *= gear->thickness; + + if(v < 0.001 || v > 0.999) { + return Vec2(0, -y); + } + + float nt = (float)gear->nteeth * 4.0; + + int part = (int)(u * nt) % 4; /* 4 parts to a tooth /#\_ */ + float t = fmod(u * nt * 4.0, 1.0); + + float offs; + switch(part) { + case 0: + offs = t; + break; + case 1: + offs = 1.0f; + break; + case 2: + offs = 1.0f - t; + break; + case 3: + offs = 0.0f; + } + + float inner_rad = gear->radius - gear->teeth_length; + return Vec2(inner_rad + offs * gear->teeth_length, -y); +} + +bool Gear::gen_mesh() +{ + mesh = new Mesh; + gen_revol(mesh, nteeth * 4, 3, rev_pos, 0, this); + mesh->explode(); + mesh->calc_face_normals(); + + float fix_tooth_up = get_angular_pitch() * 3.0 / 8.0; + + Mat4 rot; + rot.rotation_x(M_PI / 2.0); + rot.rotate_z(fix_tooth_up); + mesh->apply_xform(rot, rot); + + mesh->set_vis_vecsize(6.0); + return true; +} + +void Gear::calc_matrix() const +{ + Vec3 up = Vec3(0, 1, 0); + if(1.0 - fabs(dot(up, axis)) < 1e-4) { + up = Vec3(0, 0, -1); + } + Vec3 right = normalize(cross(up, axis)); + up = cross(axis, right); + + dir_xform = Mat4(right, up, axis); + + xform = dir_xform; + xform.rotate_z(get_vis_rotation()); + xform.translate(pos); + + axel_xform = dir_xform; + axel_xform.translate(pos); +} diff --git a/src/machine/gear.h b/src/machine/gear.h new file mode 100644 index 0000000..fac245c --- /dev/null +++ b/src/machine/gear.h @@ -0,0 +1,116 @@ +#ifndef GEAR_H_ +#define GEAR_H_ + +#include +#include +#include +#include "mesh.h" + +/* distance unit: millimeters + * angle unit: radians + */ + +class Gear; +struct GearPin; +struct GearSlot; + +struct GearPin { + float radius; + float height; + + Gear *parent; + /* position in polar coordinates on the parent gear */ + float pos_dist, pos_angle; + + GearSlot *conn_slot; /* slot connection */ +}; + +struct GearSlot { + float radius, length; + + Gear *parent; + /* position in polar coordinates on the parent gear */ + float pos_dist_min, pos_dist_max, pos_angle; + + GearPin *conn_pin; /* pin connection */ +}; + +class Gear { +private: + Mesh *mesh; + + mutable Mat4 xform, dir_xform, axel_xform; + mutable bool xform_valid; + void calc_matrix() const; + + float contour(float u); + +public: + + /* TODO hide most of this shit, especially the stuff which invalidate + * the transformation matrices + */ + std::string name; + Vec3 pos, axis; // implicitly defines a plane eqn. + float pdist; // derived: distance of plane from origin + + float init_angle; // initial starting angle + float angle; // current angle of the gear + + int nteeth; // number of teeth + float tooth_pitch; + + float radius; // total radius of the gear, including teeth + float teeth_length; // how far teeth extend past the radius + float thickness; // thickness of the gear along the Z axis + + float bevel; // bevel size + + // visual surface properties + Vec3 color; + float roughness; + bool metallic; + + Gear *supergear; + std::vector subgears; + std::vector pins; + std::vector slots; + + Gear(); + ~Gear(); + + void attach(Gear *g); + bool detach(Gear *g); + Gear *get_super() const; + + void set_angular_offset(float offs); + float get_angular_offset() const; + + // sets the supplied number of teeth, and calculates the radius + // of the gear, to achieve the required tooth pitch + void set_teeth(int nt, float tooth_pitch = 0.0f); + void set_axis(const Vec3 &axis); + const Vec3 &get_axis() const; + void set_position(const Vec3 &pos); + const Vec3 &get_position() const; + Vec3 get_global_position() const; // taking parent gear into account + + Vec3 get_planar_position() const; // 2D pos of gear on its plane + + void set_angle(float angle); + float get_angle() const; + + float get_vis_rotation() const; + const Mat4 &get_matrix() const; + const Mat4 &get_dir_matrix() const; + + // returns the angle (in radians) from one tooth to the next + float get_angular_pitch() const; + + void draw() const; + void draw_wire(float line_width = 1.0f) const; + + bool gen_mesh(); +}; + +#endif // GEAR_H_ diff --git a/src/machine/machine.cc b/src/machine/machine.cc new file mode 100644 index 0000000..441826e --- /dev/null +++ b/src/machine/machine.cc @@ -0,0 +1,269 @@ +#include +#include +#include +#include +#include +#include "opengl.h" +#include "machine.h" + +static float delta_angle(float a, float b); + +Machine::Machine() +{ + meshing = 0; + meshing_valid = false; + visited = 0; +} + +Machine::~Machine() +{ + int ngears = (int)gears.size(); + for(int i=0; i::const_iterator it = gearidx.find(g); + if(it == gearidx.end()) { + return -1; + } + return it->second; +} + +void Machine::invalidate_meshing() +{ + meshing_valid = false; +} + +void Machine::calc_meshing() +{ + int ngears = (int)gears.size(); + + if(!meshing) { + meshing = new bool*[ngears]; + meshing[0] = new bool[ngears * ngears]; + + for(int i=1; iget_position(); + } + + for(int i=0; iget_super() == gears[j] || gears[j]->get_super() == gears[i]) { + // don't attempt meshing if it's the same gear, or they are attached to each other + continue; + } + + if(1.0 - fabs(dot(gears[i]->axis, gears[j]->axis)) < 1e-5) { + // co-planar, just check Z range after inverse-transforming to the XY plane + if(fabs(ppos[i].z - ppos[j].z) > (gears[i]->thickness + gears[j]->thickness) / 2.0) { + continue; + } + // Z interval match, check distance + float dsq = length_sq(ppos[i].xy() - ppos[j].xy()); + + float outer_rad_sum = gears[i]->radius + gears[j]->radius; + float inner_rad_sum = outer_rad_sum - gears[i]->teeth_length - gears[j]->teeth_length; + + if(dsq <= outer_rad_sum * outer_rad_sum && dsq >= inner_rad_sum * inner_rad_sum) { + //printf("connecting co-planar gears %d - %d\n", i, j); + meshing[i][j] = meshing[j][i] = true; + } + + } else { + /* TODO: not co-planar + * - calc line of intersection between the two planes + * - find distance of each gear to that line + * - profit... + */ + } + } + } + + // fix the initial angles so that teeth mesh as best as possible + // should work in one pass as long as the gear train is not impossible + for(int i=0; iangle + gears[i]->get_angular_pitch() / 2.0; + float snap = rnd - fmod(rnd, gears[i]->get_angular_pitch()); + gears[i]->set_angle(snap);*/ + gears[i]->set_angular_offset(0); + } + + for(int i=0; iinit_angle + rel_angle) / gears[i]->get_angular_pitch() + 100.0, 1.0); + float frac_j = fmod((gears[j]->init_angle - rel_angle) / gears[j]->get_angular_pitch() + 100.0, 1.0); + assert(frac_i >= 0.0 && frac_j >= 0.0); + float delta = frac_j - frac_i; + + float correction = 0.5 - delta; + float prev_offs = gears[j]->get_angular_offset(); + gears[j]->set_angular_offset(prev_offs + correction * gears[j]->get_angular_pitch()); + } + } + } + + /* + printf("meshing graph\n"); + for(int i=0; iangle) > 0.25 / gear->nteeth) { + fprintf(stderr, "warning: trying to transmit different values to gear %s (%d)\n", + gear->name.c_str(), idx); + gear->angle = 0; + } + return; + } + + gear->set_angle(angle); + visited[idx] = true; + + // propagate to meshing gears (depth-first) + int ngears = (int)gears.size(); + for(int i=0; inteeth / (float)gears[i]->nteeth; + update_gear(i, angle * ratio); + } + + // propagate to rigidly attached gears + if(gear->supergear) { + int supidx = gearidx[gear->supergear]; + update_gear(supidx, angle); + } + + int nsub = (int)gear->subgears.size(); + for(int i=0; isubgears[i]]; + update_gear(subidx, angle); + } +} + +void Machine::update(float dt) +{ + int ngears = (int)gears.size(); + + if(!meshing_valid) { + calc_meshing(); + meshing_valid = true; + } + + memset(visited, 0, ngears * sizeof *visited); + for(size_t i=0; iangle + dt * motors[i].speed); + } +} + +void Machine::draw() const +{ + for(size_t i=0; idraw(); + } + + float dcol[] = {0.4, 0.4, 0.4, 1.0}; + float scol[] = {0, 0, 0, 0}; + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dcol); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, scol); + + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-300, -100, 300); + glVertex3f(300, -100, 300); + glVertex3f(300, -100, -300); + glVertex3f(-300, -100, -300); + glEnd(); +} + +Gear *Machine::intersect_gear(const Ray &ray, HitPoint *hitp) const +{ + Gear *res = 0; + HitPoint nearest; + nearest.dist = FLT_MAX; + + for(size_t i=0; iget_global_position(); + float rad = gears[i]->radius; + + Plane plane = Plane(pos, gears[i]->axis); + + HitPoint hit; + if(plane.intersect(ray, &hit) && hit.dist < nearest.dist && + length_sq(hit.pos - pos) <= rad * rad) { + nearest = hit; + res = gears[i]; + } + } + + if(hitp) *hitp = nearest; + return res; +} + +static float delta_angle(float a, float b) +{ + float api = fmod(a + M_PI, 2.0 * M_PI); + float bpi = fmod(b + M_PI, 2.0 * M_PI); + return std::min(fabs(a - b), fabs(api - bpi)); +} diff --git a/src/machine/machine.h b/src/machine/machine.h new file mode 100644 index 0000000..097157d --- /dev/null +++ b/src/machine/machine.h @@ -0,0 +1,43 @@ +#ifndef MACHINE_H_ +#define MACHINE_H_ + +#include +#include +#include "gear.h" + +struct Motor { + float speed; /* signed to denote direction, in Hz */ + int drive; /* which gear it drives */ +}; + +class Machine { +private: + std::vector gears; + std::map gearidx; + bool **meshing; + bool meshing_valid; + bool *visited; /* used for update_gear */ + + std::vector motors; + + void update_gear(int idx, float angle); + +public: + Machine(); + ~Machine(); + + void add_gear(Gear *g); /* takes ownership */ + void add_motor(int gearidx, float speed_hz); + + int get_gear_index(Gear *g) const; + + void invalidate_meshing(); + void calc_meshing(); + + void update(float dt); + void draw() const; + + Gear *intersect_gear(const Ray &ray, HitPoint *hitp = 0) const; +}; + +#endif // MACHINE_H_ diff --git a/src/machine/mparser.cc b/src/machine/mparser.cc new file mode 100644 index 0000000..260b303 --- /dev/null +++ b/src/machine/mparser.cc @@ -0,0 +1,819 @@ +#include +#include +#include +#include +#include +#include +#include "mparser.h" +#include "machine.h" + +enum ValueType { VAL_NUM, VAL_VEC, VAL_STR }; +struct Value { + ValueType type; + std::string s; + float v[4]; +}; + +struct ParserState; + +typedef bool (*Func)(ParserState*); + +struct FuncDesc { + Func func; + int arity; +}; + +struct ParserState { + FILE *fp; + const char *fname; + int nline, nerrors; + Machine *mcn; + + int nextc; + int savedc; + + std::stack val; + std::map var; + std::map func; + + std::map gears; + std::vector cur_gear; + Motor *cur_motor; +}; + +#define MAX_ID_LEN 31 + +static bool machine(ParserState *ps); +static bool expect(ParserState *ps, char c); +static bool statement(ParserState *ps); +static bool expression(ParserState *ps); +static bool term(ParserState *ps); +static bool vector(ParserState *ps); +static bool function(ParserState *ps, const char *name); + +static char *get_ident(ParserState *ps, char *buf, int bsz); +static bool get_number(ParserState *ps, float *num); +static char *get_string(ParserState *ps, char *buf, int bsz); + +static bool nextchar(ParserState *ps); +//static void putback(ParserState *ps, char c); + +static void errmsg(ParserState *ps, const char *fmt, ...); +static void expected(ParserState *ps, const char *str); + +static void set_var(ParserState *ps, const char *name, const Value &value); +static bool have_var(ParserState *ps, const char *name); +static const Value &get_var(ParserState *ps, const char *name); + +static void set_func(ParserState *ps, const char *name, Func func, int nargs = 0); +static bool have_func(ParserState *ps, const char *name); +static Func get_func(ParserState *ps, const char *name); +static int get_func_arity(ParserState *ps, const char *name); + +static Gear *begin_gear(ParserState *ps); +static bool end_gear(ParserState *ps); +static Gear *this_gear(ParserState *ps); +static Gear *find_gear(ParserState *ps, const char *name); +static void update_gear_vars(ParserState *ps, Gear *gear); +static bool set_gear_var(Gear *gear, const char *name, const Value &val); + +static void update_motor_vars(ParserState *ps, Motor *motor); +static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val); + +// built-in functions +static bool func_adjacent(ParserState *ps); +static bool func_coaxial(ParserState *ps); + + +bool parse_machine(Machine *mcn, const char *fname) +{ + FILE *fp = fopen(fname, "rb"); + if(!fp) return false; + + ParserState pstate; + pstate.fname = fname; + pstate.nline = 1; + pstate.nerrors = 0; + pstate.fp = fp; + pstate.mcn = mcn; + pstate.nextc = 0; + pstate.savedc = -1; + pstate.cur_motor = 0; + + // 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); + fclose(fp); + return res; +} + +static bool machine(ParserState *ps) +{ + char tok[MAX_ID_LEN + 1]; + if(strcmp(get_ident(ps, tok, sizeof tok), "machine") != 0) { + expected(ps, "machine"); + return false; + } + expect(ps, '{'); + + while(ps->nextc != '}') { + if(!statement(ps)) { + return false; + } + } + expect(ps, '}'); + return true; +} + +static bool expect(ParserState *ps, char c) +{ + if(c != ps->nextc) { + char buf[2] = {0, 0}; + buf[0] = c; + expected(ps, buf); + return false; + } + nextchar(ps); + return true; +} + +static bool statement(ParserState *ps) +{ + char id[MAX_ID_LEN + 1]; + if(!get_ident(ps, id, sizeof id)) { + return false; + } + + if(strcmp(id, "gear") == 0) { + if(!expect(ps, '{')) { + return false; + } + + Gear *gear = begin_gear(ps); + if(!gear) return false; + + update_gear_vars(ps, gear); + + while(ps->nextc != '}') { + if(!statement(ps)) { + return false; + } + } + expect(ps, '}'); + + if(!end_gear(ps)) { + return false; + } + return true; + } + + if(strcmp(id, "motor") == 0) { + if(!expect(ps, '{')) { + return false; + } + if(ps->cur_motor) { + errmsg(ps, "nested motors not allowed"); + return false; + } + + ps->cur_motor = new Motor; + update_motor_vars(ps, ps->cur_motor); + + while(ps->nextc != '}') { + if(!statement(ps)) { + return false; + } + } + expect(ps, '}'); + + ps->mcn->add_motor(ps->cur_motor->drive, ps->cur_motor->speed); + delete ps->cur_motor; + ps->cur_motor = 0; + return true; + } + + if(ps->nextc == '=') { + expect(ps, '='); + if(!expression(ps)) { + return false; + } + expect(ps, ';'); + + set_var(ps, id, ps->val.top()); + ps->val.pop(); + return true; + } + + expected(ps, "expression"); + return false; +} + +static bool expression(ParserState *ps) +{ + return term(ps); // TODO expand +} + +static bool term(ParserState *ps) +{ + if(ps->nextc == '+') { + expect(ps, '+'); + return expression(ps); + } + if(ps->nextc == '-') { + expect(ps, '-'); + if(!expression(ps)) { + return false; + } + + Value &v = ps->val.top(); + switch(v.type) { + case VAL_VEC: + v.v[3] = -v.v[3]; + v.v[2] = -v.v[2]; + v.v[1] = -v.v[1]; + case VAL_NUM: + v.v[0] = -v.v[0]; + break; + + default: + expected(ps, "number or vector after an unary -"); + return false; + } + return true; + } + if(isalpha(ps->nextc)) { + char buf[MAX_ID_LEN]; + if(!get_ident(ps, buf, sizeof buf)) { + return false; + } + + if(ps->nextc == '(') { + if(!function(ps, buf)) { + return false; + } + } else if(have_var(ps, buf)) { + ps->val.push(get_var(ps, buf)); + } else { + errmsg(ps, "unknown identifier: %s", buf); + return false; + } + return true; + } + if(isdigit(ps->nextc)) { + float num; + if(!get_number(ps, &num)) { + return false; + } + + Value v; + v.type = VAL_NUM; + v.v[0] = num; + ps->val.push(v); + return true; + } + if(ps->nextc == '[') { + return vector(ps); + } + if(ps->nextc == '"') { + char buf[MAX_ID_LEN]; + if(!get_string(ps, buf, sizeof buf)) { + return false; + } + + Value v; + v.type = VAL_STR; + v.s = buf; + ps->val.push(v); + return true; + } + + expected(ps, "term"); + return false; +} + +static bool vector(ParserState *ps) +{ + int nelem; + if(!expect(ps, '[') || + !expression(ps) || + !expect(ps, ',') || + !expression(ps) || + !expect(ps, ',') || + !expression(ps)) { + return false; + } + + if(ps->nextc == ']') { + expect(ps, ']'); + nelem = 3; + } else { + if(!expect(ps, ',') || !expression(ps) || !expect(ps, ']')) { + return false; + } + nelem = 4; + } + + Value vec; + vec.type = VAL_VEC; + vec.v[3] = 1.0f; + + for(int i=0; ival.top(); + if(tmp.type != VAL_NUM) { + expected(ps, "numbers as vector elements"); + return false; + } + vec.v[nelem - i - 1] = tmp.v[0]; + ps->val.pop(); + } + + ps->val.push(vec); + return true; +} + +static bool function(ParserState *ps, const char *name) +{ + if(!expect(ps, '(')) { + return false; + } + + if(!have_func(ps, name)) { + errmsg(ps, "unknown function: %s", name); + return false; + } + + int nargs = 0; + while(ps->nextc != ')') { + if(nargs && !expect(ps, ',')) { + return false; + } + if(!expression(ps)) { + return false; + } + ++nargs; + } + expect(ps, ')'); + + int arity = get_func_arity(ps, name); + if(arity != nargs) { + errmsg(ps, "function %s expects %d arguments", name, arity); + return false; + } + Func func = get_func(ps, name); + assert(func); + + if(!func(ps)) { + errmsg(ps, "function %s failed", name); + return false; + } + return true; +} + +static char *get_ident(ParserState *ps, char *buf, int bsz) +{ + char *ptr = buf; + if(!isalpha(ps->nextc)) { + expected(ps, "identifier"); + return 0; + } + while(isalnum(ps->nextc) || ps->nextc == '_') { + if(bsz > 1) { + *ptr++ = ps->nextc; + --bsz; + } + nextchar(ps); + } + *ptr = 0; + printf("get_ident -> \"%s\"\n", buf); + return buf; +} + +static bool get_number(ParserState *ps, float *num) +{ + char buf[256], *ptr = buf, *end = buf + sizeof buf; + bool found_point = false; + + if(!isdigit(ps->nextc)) { + expected(ps, "number"); + return false; + } + + while(isdigit(ps->nextc) || (ps->nextc == '.' && !found_point)) { + if(ptr < end) { + *ptr++ = ps->nextc; + } + if(ps->nextc == '.') { + found_point = true; + } + nextchar(ps); + } + *ptr = 0; + + *num = atof(buf); + printf("get_number -> %f\n", *num); + return true; +} + +static char *get_string(ParserState *ps, char *buf, int bsz) +{ + char *ptr = buf; + if(!expect(ps, '"')) { + return 0; + } + + while(ps->nextc != -1 && ps->nextc != '"') { + if(bsz > 1) { + *ptr++ = ps->nextc; + --bsz; + } + if((ps->nextc = fgetc(ps->fp)) == '\n') { + ++ps->nline; + } + } + *ptr = 0; + + if(ps->nextc == -1) { + return 0; + } + nextchar(ps); + + printf("get_string -> \"%s\"\n", buf); + return buf; +} + +static bool skip_line(ParserState *ps) +{ + int c; + while((c = fgetc(ps->fp)) != -1 && c != '\n'); + if(c != -1) { + ps->nextc = fgetc(ps->fp); + return true; + } + return false; +} + +static bool nextchar(ParserState *ps) +{ + if(ps->savedc != -1) { + ps->nextc = ps->savedc; + ps->savedc = -1; + return true; + } + + while((ps->nextc = fgetc(ps->fp)) != -1) { + if(ps->nextc == '#') { + if(!skip_line(ps)) { + return false; + } + ++ps->nline; + } + if(!isspace(ps->nextc)) { + break; + } + if(ps->nextc == '\n') { + ++ps->nline; + } + } + + /*if(ps->nextc != -1) { + printf("DBG: nextchar -> %c\n", ps->nextc); + } else { + printf("DBG: nextchar -> EOF\n"); + }*/ + return ps->nextc != -1; +} + +/*static void putback(ParserState *ps, char c) +{ + ps->savedc = ps->nextc; + ps->nextc = c; +}*/ + +static void errmsg(ParserState *ps, const char *fmt, ...) +{ + fprintf(stderr, "%s line %d error: ", ps->fname, ps->nline); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fputc('\n', stderr); +} + +static void expected(ParserState *ps, const char *str) +{ + errmsg(ps, "expected: %s", str); + ++ps->nerrors; +} + +static void set_var(ParserState *ps, const char *name, const Value &value) +{ + ps->var[name] = value; + + Gear *gear = this_gear(ps); + if(gear) { + set_gear_var(gear, name, value); + } + + if(ps->cur_motor) { + set_motor_var(ps, ps->cur_motor, 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 set_func(ParserState *ps, const char *name, Func func, int nargs) +{ + FuncDesc fdesc; + fdesc.func = func; + fdesc.arity = nargs; + ps->func[name] = fdesc; +} + +static bool have_func(ParserState *ps, const char *name) +{ + return ps->func.find(name) != ps->func.end(); +} + +static Func get_func(ParserState *ps, const char *name) +{ + return ps->func[name].func; +} + +static int get_func_arity(ParserState *ps, const char *name) +{ + return ps->func[name].arity; +} + +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.s.c_str()); + break; + + default: + fprintf(fp, ""); + } +} + +// Gear-specific stuff + +static Gear *begin_gear(ParserState *ps) +{ + Gear *res = new Gear; + ps->cur_gear.push_back(res); + return res; +} + +static bool end_gear(ParserState *ps) +{ + if(ps->cur_gear.empty()) { + errmsg(ps, "parser error: unbalanced end_gear"); + return false; + } + Gear *gear = ps->cur_gear.back(); + ps->cur_gear.pop_back(); + + printf("DBG: end_gear: %s\n", gear->name.c_str()); + + if(gear->name.empty() || ps->gears[gear->name]) { + char buf[32]; + sprintf(buf, "gear%04d", (int)ps->gears.size()); + gear->name = buf; + } + 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.back()->attach(gear); + } + return true; +} + +static Gear *this_gear(ParserState *ps) +{ + return ps->cur_gear.empty() ? 0 : ps->cur_gear.back(); +} + +static Gear *find_gear(ParserState *ps, const char *name) +{ + // search progressively wider lexical scopes + std::vector::const_reverse_iterator it = ps->cur_gear.rbegin(); + while(it != ps->cur_gear.rend()) { + Gear *g = *it++; + if(g->name == std::string(name)) { + return g; + } + } + + return ps->gears[name]; +} + +static void update_gear_vars(ParserState *ps, Gear *gear) +{ + std::map::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, "name") == 0) { + ASSERT_TYPE(val, VAL_STR); + gear->name = val.s; + + } else 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]; + printf("setting plane eqn: %f %f %f %f\n", val.v[0], val.v[1], val.v[2], 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; +} + + +// motor stuff + +static void update_motor_vars(ParserState *ps, Motor *motor) +{ + std::map::const_iterator it = ps->var.begin(); + while(it != ps->var.end()) { + set_motor_var(ps, motor, it->first.c_str(), it->second); + ++it; + } +} + +static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val) +{ + if(strcmp(name, "drive") == 0) { + ASSERT_TYPE(val, VAL_STR); + Gear *gear = ps->gears[val.s]; + if(!gear) { + errmsg(ps, "undefined gear: %s", val.s.c_str()); + return false; + } + int idx = ps->mcn->get_gear_index(gear); + assert(idx >= 0); + motor->drive = idx; + + } else if(strcmp(name, "speed") == 0) { + ASSERT_TYPE(val, VAL_NUM); + motor->speed = val.v[0]; + + } else { + return false; + } + return true; +} + + +// built-in functions +static bool func_adjacent(ParserState *ps) +{ + 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_angle.type != VAL_NUM) { + expected(ps, "angle as 2nd arg to adjacent"); + return false; + } + + Gear *gthis = this_gear(ps); + if(!gthis) { + errmsg(ps, "adjacent: called outside of a gear block"); + return false; + } + + Gear *gother = ps->gears[val_gear_name.s]; + if(!gother) { + errmsg(ps, "adjacent: gear \"%s\" not found", val_gear_name.s.c_str()); + return false; + } + + 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 + 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 = find_gear(ps, val_gear_name.s.c_str()); + if(!gother) { + errmsg(ps, "coaxial: gear \"%s\" not found", val_gear_name.s.c_str()); + return false; + } + + float avg_thickness = (gthis->thickness + gother->thickness) * 0.5; + Vec3 pos = gother->pos + gother->axis * val_dist.v[0] * avg_thickness; + + 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; +} diff --git a/src/machine/mparser.h b/src/machine/mparser.h new file mode 100644 index 0000000..eb64f1b --- /dev/null +++ b/src/machine/mparser.h @@ -0,0 +1,9 @@ +#ifndef MPARSER_H_ +#define MPARSER_H_ + +#include +#include "machine.h" + +bool parse_machine(Machine *mcn, const char *fname); + +#endif /* MPARSER_H_ */ diff --git a/src/main.cc b/src/main.cc index 6a296b9..4ef90c0 100644 --- a/src/main.cc +++ b/src/main.cc @@ -57,7 +57,7 @@ int main(int argc, char **argv) glutInitWindowSize(1024, 768); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | GLUT_MULTISAMPLE); - glutCreateWindow("Antikythera"); + glutCreateWindow("demo"); glutDisplayFunc(display); glutIdleFunc(idle); @@ -94,41 +94,6 @@ static bool init() return false; } - /* - const float pitch = 10.0f; - - Gear *gear1 = new Gear; - gear1->pos = Vec3(-50, 0, 0); - gear1->set_teeth(16, pitch); - gear1->gen_mesh(); - gear1->color = Vec3(0.35, 0.6, 0.8); - machine->add_gear(gear1); - - Gear *gear2 = new Gear; - gear2->set_teeth(32, pitch); - gear2->pos = gear1->pos + Vec3(gear1->radius + gear2->radius - gear1->teeth_length * 0.75, 0, 0); - gear2->thickness = 5; - gear2->gen_mesh(); - machine->add_gear(gear2); - - Gear *gear3 = new Gear; - gear3->set_teeth(8, pitch); - gear3->pos = gear2->pos + Vec3(0, gear2->radius + gear3->radius - gear2->teeth_length * 0.75, 0); - gear3->gen_mesh(); - machine->add_gear(gear3); - gear3->color = Vec3(0.5, 0.8, 0.6); - - Gear *subgear = new Gear; - subgear->set_teeth(10, pitch); - subgear->pos = Vec3(0, 0, (gear2->thickness + subgear->thickness) / 2 + 1); - subgear->gen_mesh(); - gear2->attach(subgear); - machine->add_gear(subgear); - subgear->color = Vec3(0.8, 0.7, 0.5); - */ - - //machine->add_motor(0, 1.0); - // shadows init_shadow(2048); diff --git a/src/mparser.cc b/src/mparser.cc deleted file mode 100644 index 4079533..0000000 --- a/src/mparser.cc +++ /dev/null @@ -1,819 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "mparser.h" -#include "machine.h" - -enum ValueType { VAL_NUM, VAL_VEC, VAL_STR }; -struct Value { - ValueType type; - std::string s; - float v[4]; -}; - -struct ParserState; - -typedef bool (*Func)(ParserState*); - -struct FuncDesc { - Func func; - int arity; -}; - -struct ParserState { - FILE *fp; - const char *fname; - int nline, nerrors; - Machine *mcn; - - int nextc; - int savedc; - - std::stack val; - std::map var; - std::map func; - - std::map gears; - std::vector cur_gear; - Motor *cur_motor; -}; - -#define MAX_ID_LEN 31 - -static bool machine(ParserState *ps); -static bool expect(ParserState *ps, char c); -static bool statement(ParserState *ps); -static bool expression(ParserState *ps); -static bool term(ParserState *ps); -static bool vector(ParserState *ps); -static bool function(ParserState *ps, const char *name); - -static char *get_ident(ParserState *ps, char *buf, int bsz); -static bool get_number(ParserState *ps, float *num); -static char *get_string(ParserState *ps, char *buf, int bsz); - -static bool nextchar(ParserState *ps); -static void putback(ParserState *ps, char c); - -static void errmsg(ParserState *ps, const char *fmt, ...); -static void expected(ParserState *ps, const char *str); - -static void set_var(ParserState *ps, const char *name, const Value &value); -static bool have_var(ParserState *ps, const char *name); -static const Value &get_var(ParserState *ps, const char *name); - -static void set_func(ParserState *ps, const char *name, Func func, int nargs = 0); -static bool have_func(ParserState *ps, const char *name); -static Func get_func(ParserState *ps, const char *name); -static int get_func_arity(ParserState *ps, const char *name); - -static Gear *begin_gear(ParserState *ps); -static bool end_gear(ParserState *ps); -static Gear *this_gear(ParserState *ps); -static Gear *find_gear(ParserState *ps, const char *name); -static void update_gear_vars(ParserState *ps, Gear *gear); -static bool set_gear_var(Gear *gear, const char *name, const Value &val); - -static void update_motor_vars(ParserState *ps, Motor *motor); -static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val); - -// built-in functions -static bool func_adjacent(ParserState *ps); -static bool func_coaxial(ParserState *ps); - - -bool parse_machine(Machine *mcn, const char *fname) -{ - FILE *fp = fopen(fname, "rb"); - if(!fp) return false; - - ParserState pstate; - pstate.fname = fname; - pstate.nline = 1; - pstate.nerrors = 0; - pstate.fp = fp; - pstate.mcn = mcn; - pstate.nextc = 0; - pstate.savedc = -1; - pstate.cur_motor = 0; - - // 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); - fclose(fp); - return res; -} - -static bool machine(ParserState *ps) -{ - char tok[MAX_ID_LEN + 1]; - if(strcmp(get_ident(ps, tok, sizeof tok), "machine") != 0) { - expected(ps, "machine"); - return false; - } - expect(ps, '{'); - - while(ps->nextc != '}') { - if(!statement(ps)) { - return false; - } - } - expect(ps, '}'); - return true; -} - -static bool expect(ParserState *ps, char c) -{ - if(c != ps->nextc) { - char buf[2] = {0, 0}; - buf[0] = c; - expected(ps, buf); - return false; - } - nextchar(ps); - return true; -} - -static bool statement(ParserState *ps) -{ - char id[MAX_ID_LEN + 1]; - if(!get_ident(ps, id, sizeof id)) { - return false; - } - - if(strcmp(id, "gear") == 0) { - if(!expect(ps, '{')) { - return false; - } - - Gear *gear = begin_gear(ps); - if(!gear) return false; - - update_gear_vars(ps, gear); - - while(ps->nextc != '}') { - if(!statement(ps)) { - return false; - } - } - expect(ps, '}'); - - if(!end_gear(ps)) { - return false; - } - return true; - } - - if(strcmp(id, "motor") == 0) { - if(!expect(ps, '{')) { - return false; - } - if(ps->cur_motor) { - errmsg(ps, "nested motors not allowed"); - return false; - } - - ps->cur_motor = new Motor; - update_motor_vars(ps, ps->cur_motor); - - while(ps->nextc != '}') { - if(!statement(ps)) { - return false; - } - } - expect(ps, '}'); - - ps->mcn->add_motor(ps->cur_motor->drive, ps->cur_motor->speed); - delete ps->cur_motor; - ps->cur_motor = 0; - return true; - } - - if(ps->nextc == '=') { - expect(ps, '='); - if(!expression(ps)) { - return false; - } - expect(ps, ';'); - - set_var(ps, id, ps->val.top()); - ps->val.pop(); - return true; - } - - expected(ps, "expression"); - return false; -} - -static bool expression(ParserState *ps) -{ - return term(ps); // TODO expand -} - -static bool term(ParserState *ps) -{ - if(ps->nextc == '+') { - expect(ps, '+'); - return expression(ps); - } - if(ps->nextc == '-') { - expect(ps, '-'); - if(!expression(ps)) { - return false; - } - - Value &v = ps->val.top(); - switch(v.type) { - case VAL_VEC: - v.v[3] = -v.v[3]; - v.v[2] = -v.v[2]; - v.v[1] = -v.v[1]; - case VAL_NUM: - v.v[0] = -v.v[0]; - break; - - default: - expected(ps, "number or vector after an unary -"); - return false; - } - return true; - } - if(isalpha(ps->nextc)) { - char buf[MAX_ID_LEN]; - if(!get_ident(ps, buf, sizeof buf)) { - return false; - } - - if(ps->nextc == '(') { - if(!function(ps, buf)) { - return false; - } - } else if(have_var(ps, buf)) { - ps->val.push(get_var(ps, buf)); - } else { - errmsg(ps, "unknown identifier: %s", buf); - return false; - } - return true; - } - if(isdigit(ps->nextc)) { - float num; - if(!get_number(ps, &num)) { - return false; - } - - Value v; - v.type = VAL_NUM; - v.v[0] = num; - ps->val.push(v); - return true; - } - if(ps->nextc == '[') { - return vector(ps); - } - if(ps->nextc == '"') { - char buf[MAX_ID_LEN]; - if(!get_string(ps, buf, sizeof buf)) { - return false; - } - - Value v; - v.type = VAL_STR; - v.s = buf; - ps->val.push(v); - return true; - } - - expected(ps, "term"); - return false; -} - -static bool vector(ParserState *ps) -{ - int nelem; - if(!expect(ps, '[') || - !expression(ps) || - !expect(ps, ',') || - !expression(ps) || - !expect(ps, ',') || - !expression(ps)) { - return false; - } - - if(ps->nextc == ']') { - expect(ps, ']'); - nelem = 3; - } else { - if(!expect(ps, ',') || !expression(ps) || !expect(ps, ']')) { - return false; - } - nelem = 4; - } - - Value vec; - vec.type = VAL_VEC; - vec.v[3] = 1.0f; - - for(int i=0; ival.top(); - if(tmp.type != VAL_NUM) { - expected(ps, "numbers as vector elements"); - return false; - } - vec.v[nelem - i - 1] = tmp.v[0]; - ps->val.pop(); - } - - ps->val.push(vec); - return true; -} - -static bool function(ParserState *ps, const char *name) -{ - if(!expect(ps, '(')) { - return false; - } - - if(!have_func(ps, name)) { - errmsg(ps, "unknown function: %s", name); - return false; - } - - int nargs = 0; - while(ps->nextc != ')') { - if(nargs && !expect(ps, ',')) { - return false; - } - if(!expression(ps)) { - return false; - } - ++nargs; - } - expect(ps, ')'); - - int arity = get_func_arity(ps, name); - if(arity != nargs) { - errmsg(ps, "function %s expects %d arguments", name, arity); - return false; - } - Func func = get_func(ps, name); - assert(func); - - if(!func(ps)) { - errmsg(ps, "function %s failed", name); - return false; - } - return true; -} - -static char *get_ident(ParserState *ps, char *buf, int bsz) -{ - char *ptr = buf; - if(!isalpha(ps->nextc)) { - expected(ps, "identifier"); - return 0; - } - while(isalnum(ps->nextc) || ps->nextc == '_') { - if(bsz > 1) { - *ptr++ = ps->nextc; - --bsz; - } - nextchar(ps); - } - *ptr = 0; - printf("get_ident -> \"%s\"\n", buf); - return buf; -} - -static bool get_number(ParserState *ps, float *num) -{ - char buf[256], *ptr = buf, *end = buf + sizeof buf; - bool found_point = false; - - if(!isdigit(ps->nextc)) { - expected(ps, "number"); - return false; - } - - while(isdigit(ps->nextc) || (ps->nextc == '.' && !found_point)) { - if(ptr < end) { - *ptr++ = ps->nextc; - } - if(ps->nextc == '.') { - found_point = true; - } - nextchar(ps); - } - *ptr = 0; - - *num = atof(buf); - printf("get_number -> %f\n", *num); - return true; -} - -static char *get_string(ParserState *ps, char *buf, int bsz) -{ - char *ptr = buf; - if(!expect(ps, '"')) { - return 0; - } - - while(ps->nextc != -1 && ps->nextc != '"') { - if(bsz > 1) { - *ptr++ = ps->nextc; - --bsz; - } - if((ps->nextc = fgetc(ps->fp)) == '\n') { - ++ps->nline; - } - } - *ptr = 0; - - if(ps->nextc == -1) { - return 0; - } - nextchar(ps); - - printf("get_string -> \"%s\"\n", buf); - return buf; -} - -static bool skip_line(ParserState *ps) -{ - int c; - while((c = fgetc(ps->fp)) != -1 && c != '\n'); - if(c != -1) { - ps->nextc = fgetc(ps->fp); - return true; - } - return false; -} - -static bool nextchar(ParserState *ps) -{ - if(ps->savedc != -1) { - ps->nextc = ps->savedc; - ps->savedc = -1; - return true; - } - - while((ps->nextc = fgetc(ps->fp)) != -1) { - if(ps->nextc == '#') { - if(!skip_line(ps)) { - return false; - } - ++ps->nline; - } - if(!isspace(ps->nextc)) { - break; - } - if(ps->nextc == '\n') { - ++ps->nline; - } - } - - /*if(ps->nextc != -1) { - printf("DBG: nextchar -> %c\n", ps->nextc); - } else { - printf("DBG: nextchar -> EOF\n"); - }*/ - return ps->nextc != -1; -} - -static void putback(ParserState *ps, char c) -{ - ps->savedc = ps->nextc; - ps->nextc = c; -} - -static void errmsg(ParserState *ps, const char *fmt, ...) -{ - fprintf(stderr, "%s line %d error: ", ps->fname, ps->nline); - - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - - fputc('\n', stderr); -} - -static void expected(ParserState *ps, const char *str) -{ - errmsg(ps, "expected: %s", str); - ++ps->nerrors; -} - -static void set_var(ParserState *ps, const char *name, const Value &value) -{ - ps->var[name] = value; - - Gear *gear = this_gear(ps); - if(gear) { - set_gear_var(gear, name, value); - } - - if(ps->cur_motor) { - set_motor_var(ps, ps->cur_motor, 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 set_func(ParserState *ps, const char *name, Func func, int nargs) -{ - FuncDesc fdesc; - fdesc.func = func; - fdesc.arity = nargs; - ps->func[name] = fdesc; -} - -static bool have_func(ParserState *ps, const char *name) -{ - return ps->func.find(name) != ps->func.end(); -} - -static Func get_func(ParserState *ps, const char *name) -{ - return ps->func[name].func; -} - -static int get_func_arity(ParserState *ps, const char *name) -{ - return ps->func[name].arity; -} - -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.s.c_str()); - break; - - default: - fprintf(fp, ""); - } -} - -// Gear-specific stuff - -static Gear *begin_gear(ParserState *ps) -{ - Gear *res = new Gear; - ps->cur_gear.push_back(res); - return res; -} - -static bool end_gear(ParserState *ps) -{ - if(ps->cur_gear.empty()) { - errmsg(ps, "parser error: unbalanced end_gear"); - return false; - } - Gear *gear = ps->cur_gear.back(); - ps->cur_gear.pop_back(); - - printf("DBG: end_gear: %s\n", gear->name.c_str()); - - if(gear->name.empty() || ps->gears[gear->name]) { - char buf[32]; - sprintf(buf, "gear%04d", (int)ps->gears.size()); - gear->name = buf; - } - 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.back()->attach(gear); - } - return true; -} - -static Gear *this_gear(ParserState *ps) -{ - return ps->cur_gear.empty() ? 0 : ps->cur_gear.back(); -} - -static Gear *find_gear(ParserState *ps, const char *name) -{ - // search progressively wider lexical scopes - std::vector::const_reverse_iterator it = ps->cur_gear.rbegin(); - while(it != ps->cur_gear.rend()) { - Gear *g = *it++; - if(g->name == std::string(name)) { - return g; - } - } - - return ps->gears[name]; -} - -static void update_gear_vars(ParserState *ps, Gear *gear) -{ - std::map::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, "name") == 0) { - ASSERT_TYPE(val, VAL_STR); - gear->name = val.s; - - } else 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]; - printf("setting plane eqn: %f %f %f %f\n", val.v[0], val.v[1], val.v[2], 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; -} - - -// motor stuff - -static void update_motor_vars(ParserState *ps, Motor *motor) -{ - std::map::const_iterator it = ps->var.begin(); - while(it != ps->var.end()) { - set_motor_var(ps, motor, it->first.c_str(), it->second); - ++it; - } -} - -static bool set_motor_var(ParserState *ps, Motor *motor, const char *name, const Value &val) -{ - if(strcmp(name, "drive") == 0) { - ASSERT_TYPE(val, VAL_STR); - Gear *gear = ps->gears[val.s]; - if(!gear) { - errmsg(ps, "undefined gear: %s", val.s.c_str()); - return false; - } - int idx = ps->mcn->get_gear_index(gear); - assert(idx >= 0); - motor->drive = idx; - - } else if(strcmp(name, "speed") == 0) { - ASSERT_TYPE(val, VAL_NUM); - motor->speed = val.v[0]; - - } else { - return false; - } - return true; -} - - -// built-in functions -static bool func_adjacent(ParserState *ps) -{ - 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_angle.type != VAL_NUM) { - expected(ps, "angle as 2nd arg to adjacent"); - return false; - } - - Gear *gthis = this_gear(ps); - if(!gthis) { - errmsg(ps, "adjacent: called outside of a gear block"); - return false; - } - - Gear *gother = ps->gears[val_gear_name.s]; - if(!gother) { - errmsg(ps, "adjacent: gear \"%s\" not found", val_gear_name.s.c_str()); - return false; - } - - 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 + 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 = find_gear(ps, val_gear_name.s.c_str()); - if(!gother) { - errmsg(ps, "coaxial: gear \"%s\" not found", val_gear_name.s.c_str()); - return false; - } - - float avg_thickness = (gthis->thickness + gother->thickness) * 0.5; - Vec3 pos = gother->pos + gother->axis * val_dist.v[0] * avg_thickness; - - 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; -} diff --git a/src/mparser.h b/src/mparser.h deleted file mode 100644 index eb64f1b..0000000 --- a/src/mparser.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef MPARSER_H_ -#define MPARSER_H_ - -#include -#include "machine.h" - -bool parse_machine(Machine *mcn, const char *fname); - -#endif /* MPARSER_H_ */ -- 1.7.10.4