X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fmachine%2Fgear.cc;fp=src%2Fmachine%2Fgear.cc;h=6a34815498ec8dfa3c7b1413fa890b7d9fae0b77;hb=a58455a92c7ecab980cbe1b7e282aeb6bfe7e889;hp=0000000000000000000000000000000000000000;hpb=21d0490039c490c6abcc80ebf2142a3376f2be43;p=laserbrain_demo 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); +}