- added subgear linkage
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Wed, 21 Sep 2016 21:50:35 +0000 (00:50 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Wed, 21 Sep 2016 21:50:35 +0000 (00:50 +0300)
- simplified gear positioning

src/gear.cc
src/gear.h
src/geom.cc
src/machine.cc
src/machine.h
src/main.cc

index c916e76..697610d 100644 (file)
@@ -16,6 +16,8 @@ Gear::Gear()
        init_angle = 0;
        xform_valid = false;
 
+       supergear = 0;
+
        mesh = 0;
 }
 
@@ -24,6 +26,41 @@ 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; i<nsubgears; i++) {
+               if(subgears[i] == g) {
+                       subgears.erase(subgears.begin() + i);
+                       g->supergear = 0;
+                       return true;
+               }
+       }
+       return false;
+}
+
+Gear *Gear::get_super() const
+{
+       return supergear;
+}
+
 void Gear::set_angular_offset(float offs)
 {
        init_angle = offs;
@@ -55,8 +92,15 @@ const Vec3 &Gear::get_axis() const
 
 void Gear::set_position(const Vec3 &pos)
 {
-       this->pos = pos;
-       xform_valid = false;
+       if(!supergear) {
+               this->pos = pos;
+               xform_valid = false;
+       } else {
+               if(fabs(this->pos.z - pos.z) > 1e-5) {
+                       this->pos.z = pos.z;
+                       xform_valid = false;
+               }
+       }
 }
 
 const Vec3 &Gear::get_position() const
@@ -66,13 +110,8 @@ const Vec3 &Gear::get_position() const
 
 Vec3 Gear::get_global_position() const
 {
-       return pos;     // TODO
-}
-
-Vec3 Gear::get_planar_position() const
-{
-       Mat4 inv_xform = transpose(get_dir_matrix());
-       return inv_xform * pos;
+       const Mat4 &m = get_matrix();
+       return m * Vec3(0, 0, 0);
 }
 
 void Gear::set_angle(float angle)
@@ -88,8 +127,7 @@ float Gear::get_angle() const
 
 float Gear::get_vis_rotation() const
 {
-       float fix_crooked_teeth = get_angular_pitch() * 3.0 / 8.0;
-       return fmod(init_angle + fix_crooked_teeth + angle, M_PI * 2.0);
+       return fmod(init_angle + angle, M_PI * 2.0);
 }
 
 const Mat4 &Gear::get_matrix() const
@@ -224,8 +262,11 @@ bool Gear::gen_mesh()
        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);
@@ -246,4 +287,7 @@ void Gear::calc_matrix() const
        xform = dir_xform;
        xform.rotate_z(get_vis_rotation());
        xform.translate(pos);
+
+       axel_xform = dir_xform;
+       axel_xform.translate(pos);
 }
index 7f230e4..1247a14 100644 (file)
@@ -39,7 +39,7 @@ class Gear {
 private:
        Mesh *mesh;
 
-       mutable Mat4 xform, dir_xform;
+       mutable Mat4 xform, dir_xform, axel_xform;
        mutable bool xform_valid;
        void calc_matrix() const;
 
@@ -65,12 +65,18 @@ public:
 
        float bevel;    // bevel size
 
+       Gear *supergear;
+       std::vector<Gear*> subgears;
        std::vector<GearPin> pins;
        std::vector<GearSlot> 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;
 
index 23391a7..a6b26e8 100644 (file)
@@ -244,6 +244,7 @@ bool Plane::intersect(const Ray &ray, HitPoint *hit) const
                Vec3 ptdir = pt - ray.origin;
                float t = dot(normal, ptdir) / ndotdir;
 
+               hit->dist = t;
                hit->pos = ray.origin + ray.dir * t;
                hit->normal = normal;
                hit->obj = this;
index d6bb338..313540d 100644 (file)
@@ -30,6 +30,10 @@ Machine::~Machine()
 
 void Machine::add_gear(Gear *g)
 {
+       if(gearidx.find(g) != gearidx.end()) {
+               return; // already have this gear
+       }
+       gearidx[g] = gears.size();
        gears.push_back(g);
        meshing_valid = false;
 }
@@ -67,14 +71,17 @@ void Machine::calc_meshing()
        // we're going to need the planar position of each gear on its plane, so let's cache it
        Vec3 *ppos = (Vec3*)alloca(ngears * sizeof *ppos);
        for(int i=0; i<ngears; i++) {
-               ppos[i] = gears[i]->get_planar_position();
+               ppos[i] = gears[i]->get_position();
        }
 
        for(int i=0; i<ngears; i++) {
                for(int j=i; j<ngears; j++) {
                        meshing[i][j] = meshing[j][i] = false;
 
-                       if(i == j) continue;
+                       if(i == j || gears[i]->get_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
@@ -105,9 +112,9 @@ void Machine::calc_meshing()
        // 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; i<ngears; i++) {
-               float rnd = gears[i]->angle + gears[i]->get_angular_pitch() / 2.0;
+               /*float rnd = gears[i]->angle + 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_angle(snap);*/
                gears[i]->set_angular_offset(0);
        }
 
@@ -130,30 +137,56 @@ void Machine::calc_meshing()
                        }
                }
        }
+
+       /*
+       printf("meshing graph\n");
+       for(int i=0; i<ngears; i++) {
+               putchar(' ');
+               for(int j=0; j<ngears; j++) {
+                       printf("| %d ", meshing[i][j] ? 1 : 0);
+               }
+               printf("|\n");
+       }
+       */
 }
 
 void Machine::update_gear(int idx, float angle)
 {
+       Gear *gear = gears[idx];
+
        if(visited[idx]) {
-               if(delta_angle(angle, gears[idx]->angle) > 0.25 / gears[idx]->nteeth) {
+               if(delta_angle(angle, gear->angle) > 0.25 / gear->nteeth) {
                        fprintf(stderr, "warning: trying to transmit different values to gear %s (%d)\n",
-                                       gears[idx]->name.c_str(), idx);
-                       gears[idx]->angle = 0;
+                                       gear->name.c_str(), idx);
+                       gear->angle = 0;
                }
                return;
        }
 
-       gears[idx]->set_angle(angle);
+       gear->set_angle(angle);
        visited[idx] = true;
 
+       // propagate to meshing gears (depth-first)
        int ngears = (int)gears.size();
        for(int i=0; i<ngears; i++) {
                if(!meshing[idx][i]) continue;
                assert(idx != i);
 
-               float ratio = -(float)gears[idx]->nteeth / (float)gears[i]->nteeth;
+               float ratio = -(float)gear->nteeth / (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; i<nsub; i++) {
+               int subidx = gearidx[gear->subgears[i]];
+               update_gear(subidx, angle);
+       }
 }
 
 void Machine::update(float dt)
index 86caa48..e0f2155 100644 (file)
@@ -2,6 +2,7 @@
 #define MACHINE_H_
 
 #include <vector>
+#include <map>
 #include "gear.h"
 
 struct Motor {
@@ -12,6 +13,7 @@ struct Motor {
 class Machine {
 private:
        std::vector<Gear*> gears;
+       std::map<Gear*, int> gearidx;
        bool **meshing;
        bool meshing_valid;
        bool *visited;  /* used for update_gear */
index ce8466e..5dd2857 100644 (file)
@@ -67,7 +67,6 @@ static bool init()
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
        glEnable(GL_LIGHTING);
-       glEnable(GL_LIGHT0);
        glEnable(GL_NORMALIZE);
 
        Mesh::use_custom_sdr_attr = false;
@@ -95,6 +94,13 @@ static bool init()
        gear3->gen_mesh();
        machine->add_gear(gear3);
 
+       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);
+
        machine->add_motor(0, 1.0);
 
        start_time = glutGet(GLUT_ELAPSED_TIME);
@@ -116,6 +122,18 @@ static void update(float dt)
        hover_gear = pick_gear(prev_mx, prev_my);
 }
 
+static void set_light(int idx, const Vec3 &pos, const Vec3 &color)
+{
+       unsigned int lt = GL_LIGHT0 + idx;
+       float posv[] = { pos.x, pos.y, pos.z, 1 };
+       float colv[] = { color.x, color.y, color.z, 1 };
+
+       glEnable(lt);
+       glLightfv(lt, GL_POSITION, posv);
+       glLightfv(lt, GL_DIFFUSE, colv);
+       glLightfv(lt, GL_SPECULAR, colv);
+}
+
 static void display()
 {
        unsigned int msec = glutGet(GLUT_ELAPSED_TIME) - start_time;
@@ -130,6 +148,10 @@ static void display()
        glRotatef(cam_phi, 1, 0, 0);
        glRotatef(cam_theta, 0, 1, 0);
 
+       set_light(0, Vec3(-50, 75, 100), Vec3(1.0, 0.8, 0.7) * 0.8);
+       set_light(1, Vec3(100, 0, 30), Vec3(0.6, 0.7, 1.0) * 0.6);
+       set_light(2, Vec3(-10, -10, 60), Vec3(0.8, 1.0, 0.8) * 0.3);
+
        update(dt);
 
        draw_gears();