865679c155c0aab3d9234ec1f0ebe168f64cc5fd
[antikythera] / src / gear.cc
1 #include <GL/glew.h>
2 #include "gear.h"
3 #include "meshgen.h"
4
5 Gear::Gear()
6         : axis(0, 0, 1)
7 {
8         pdist = 0;
9         angle = 0;
10         nteeth = 42;
11         radius = 80;
12         teeth_length = 5;
13         thickness = 5;
14         bevel = 1.5;
15         init_angle = 0;
16
17         mesh = 0;
18 }
19
20 Gear::~Gear()
21 {
22         delete mesh;
23 }
24
25 void Gear::set_teeth(int nt, float tooth_pitch)
26 {
27         float circ = tooth_pitch * nt;
28         radius = circ / (2.0 * M_PI);
29         nteeth = nt;
30         init_angle = get_angular_pitch() * 3.0 / 8.0;
31 }
32
33 float Gear::get_rotation() const
34 {
35         return fmod(init_angle + angle, M_PI * 2.0);
36 }
37
38 float Gear::get_angular_pitch() const
39 {
40         return 2.0 * M_PI / (float)nteeth;
41 }
42
43 void Gear::draw() const
44 {
45         if(!mesh) {
46                 if(!((Gear*)this)->gen_mesh()) {
47                         abort();
48                 }
49         }
50         calc_matrix();
51
52         glPushMatrix();
53         glMultMatrixf(xform[0]);
54
55         mesh->draw();
56
57         glPushAttrib(GL_ENABLE_BIT);
58         glDisable(GL_LIGHTING);
59
60         glLineWidth(2.0);
61         glBegin(GL_LINES);
62         glColor3f(0, 0, 1);
63         glVertex3f(0, 0, -10);
64         glVertex3f(0, 0, 10);
65         glEnd();
66         glPopAttrib();
67
68         glPopMatrix();
69 }
70
71 static Vec2 rev_pos(float u, float v, void *cls)
72 {
73         Gear *gear = (Gear*)cls;
74
75         float y = ((v - 1.0 / 3.0) / (1.0 / 3.0) - 0.5);
76         if(y < -0.5) y = -0.5;
77         if(y > 0.5) y = 0.5;
78         y *= gear->thickness;
79
80         if(v < 0.001 || v > 0.999) {
81                 return Vec2(0, -y);
82         }
83
84         float nt = (float)gear->nteeth * 4.0;
85
86         int part = (int)(u * nt) % 4;   /* 4 parts to a tooth /#\_ */
87         float t = fmod(u * nt * 4.0, 1.0);
88
89         float offs;
90         switch(part) {
91         case 0:
92                 offs = t;
93                 break;
94         case 1:
95                 offs = 1.0f;
96                 break;
97         case 2:
98                 offs = 1.0f - t;
99                 break;
100         case 3:
101                 offs = 0.0f;
102         }
103
104         float inner_rad = gear->radius - gear->teeth_length;
105         return Vec2(inner_rad + offs * gear->teeth_length, -y);
106 }
107
108 bool Gear::gen_mesh()
109 {
110         mesh = new Mesh;
111         gen_revol(mesh, nteeth * 4, 3, rev_pos, 0, this);
112         mesh->explode();
113         mesh->calc_face_normals();
114
115         Mat4 rot;
116         rot.rotation_x(M_PI / 2.0);
117         mesh->apply_xform(rot, rot);
118
119         mesh->set_vis_vecsize(6.0);
120         return true;
121 }
122
123 void Gear::calc_matrix() const
124 {
125         Vec3 up = Vec3(0, 1, 0);
126         if(1.0 - fabs(dot(up, axis)) < 1e-4) {
127                 up = Vec3(0, 0, -1);
128         }
129         Vec3 right = normalize(cross(up, axis));
130         up = cross(axis, right);
131
132         xform = Mat4(right, up, axis);
133         xform.rotate_z(get_rotation());
134         xform.translate(pos);
135 }