shadows, textures, resource managers... shaders...
[antikythera] / src / gear.cc
index f6872cf..c00b411 100644 (file)
@@ -16,7 +16,13 @@ Gear::Gear()
        init_angle = 0;
        xform_valid = false;
 
+       supergear = 0;
+
        mesh = 0;
+
+       color = Vec3(0.6, 0.6, 0.6);
+       roughness = 1.0;
+       metallic = false;
 }
 
 Gear::~Gear()
@@ -24,6 +30,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;
@@ -48,10 +89,26 @@ void Gear::set_axis(const Vec3 &axis)
        xform_valid = false;
 }
 
+const Vec3 &Gear::get_axis() const
+{
+       return axis;
+}
+
 void Gear::set_position(const Vec3 &pos)
 {
-       this->pos = 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
@@ -61,13 +118,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)
@@ -83,8 +135,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
@@ -121,7 +172,7 @@ void Gear::draw() const
                calc_matrix();
        }
 
-       glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
+       glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_LIGHTING_BIT);
 
        glPushMatrix();
        glMultMatrixf(xform[0]);
@@ -131,6 +182,15 @@ void Gear::draw() const
                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);
@@ -140,13 +200,6 @@ void Gear::draw() const
                mesh->draw_wire();
        }
 
-       glLineWidth(2.0);
-       glBegin(GL_LINES);
-       glColor3f(0, 0, 1);
-       glVertex3f(0, 0, -10);
-       glVertex3f(0, 0, 10);
-       glEnd();
-
        glPopMatrix();
        glPopAttrib();
 }
@@ -219,8 +272,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);
@@ -241,4 +297,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);
 }