did I fix the meshing now?
[antikythera] / src / gear.cc
1 #include <GL/glew.h>
2 #include "gear.h"
3 #include "meshgen.h"
4 #include "app.h"
5
6 Gear::Gear()
7         : axis(0, 0, 1)
8 {
9         pdist = 0;
10         angle = 0;
11         nteeth = 42;
12         radius = 80;
13         teeth_length = 5;
14         thickness = 5;
15         bevel = 1.5;
16         init_angle = 0;
17         xform_valid = false;
18
19         mesh = 0;
20 }
21
22 Gear::~Gear()
23 {
24         delete mesh;
25 }
26
27 void Gear::set_angular_offset(float offs)
28 {
29         init_angle = offs;
30         xform_valid = false;
31 }
32
33 float Gear::get_angular_offset() const
34 {
35         return init_angle;
36 }
37
38 void Gear::set_teeth(int nt, float tooth_pitch)
39 {
40         float circ = tooth_pitch * nt;
41         radius = circ / (2.0 * M_PI);
42         nteeth = nt;
43 }
44
45 void Gear::set_axis(const Vec3 &axis)
46 {
47         this->axis = normalize(axis);
48         xform_valid = false;
49 }
50
51 void Gear::set_position(const Vec3 &pos)
52 {
53         this->pos = pos;
54         xform_valid = false;
55 }
56
57 const Vec3 &Gear::get_position() const
58 {
59         return pos;
60 }
61
62 Vec3 Gear::get_global_position() const
63 {
64         return pos;     // TODO
65 }
66
67 Vec3 Gear::get_planar_position() const
68 {
69         Mat4 inv_xform = transpose(get_dir_matrix());
70         return inv_xform * pos;
71 }
72
73 void Gear::set_angle(float angle)
74 {
75         this->angle = angle;
76         xform_valid = false;
77 }
78
79 float Gear::get_angle() const
80 {
81         return angle;
82 }
83
84 float Gear::get_vis_rotation() const
85 {
86         float fix_crooked_teeth = get_angular_pitch() * 3.0 / 8.0;
87         return fmod(init_angle + fix_crooked_teeth + angle, M_PI * 2.0);
88 }
89
90 const Mat4 &Gear::get_matrix() const
91 {
92         if(!xform_valid) {
93                 calc_matrix();
94                 xform_valid = true;
95         }
96         return xform;
97 }
98
99 const Mat4 &Gear::get_dir_matrix() const
100 {
101         if(!xform_valid) {
102                 calc_matrix();
103                 xform_valid = true;
104         }
105         return dir_xform;
106 }
107
108 float Gear::get_angular_pitch() const
109 {
110         return 2.0 * M_PI / (float)nteeth;
111 }
112
113 void Gear::draw() const
114 {
115         if(!mesh) {
116                 if(!((Gear*)this)->gen_mesh()) {
117                         abort();
118                 }
119         }
120         if(!xform_valid) {
121                 calc_matrix();
122         }
123
124         glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
125
126         glPushMatrix();
127         glMultMatrixf(xform[0]);
128
129         if(opt_gear_wireframe) {
130                 glPolygonOffset(1, 1);
131                 glEnable(GL_POLYGON_OFFSET_FILL);
132         }
133
134         mesh->draw();
135
136         glDisable(GL_LIGHTING);
137
138         if(opt_gear_wireframe) {
139                 glColor3f(0.2, 0.4, 1.0);
140                 mesh->draw_wire();
141         }
142
143         glLineWidth(2.0);
144         glBegin(GL_LINES);
145         glColor3f(0, 0, 1);
146         glVertex3f(0, 0, -10);
147         glVertex3f(0, 0, 10);
148         glEnd();
149
150         glPopMatrix();
151         glPopAttrib();
152 }
153
154 void Gear::draw_wire(float wire_width) const
155 {
156         if(!mesh) {
157                 if(!((Gear*)this)->gen_mesh()) {
158                         abort();
159                 }
160         }
161         if(!xform_valid) {
162                 calc_matrix();
163         }
164
165         glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT);
166         glLineWidth(wire_width);
167         glDisable(GL_LIGHTING);
168
169         glPushMatrix();
170         glMultMatrixf(xform[0]);
171
172         mesh->draw_wire();
173
174         glPopMatrix();
175         glPopAttrib();
176 }
177
178 static Vec2 rev_pos(float u, float v, void *cls)
179 {
180         Gear *gear = (Gear*)cls;
181
182         float y = ((v - 1.0 / 3.0) / (1.0 / 3.0) - 0.5);
183         if(y < -0.5) y = -0.5;
184         if(y > 0.5) y = 0.5;
185         y *= gear->thickness;
186
187         if(v < 0.001 || v > 0.999) {
188                 return Vec2(0, -y);
189         }
190
191         float nt = (float)gear->nteeth * 4.0;
192
193         int part = (int)(u * nt) % 4;   /* 4 parts to a tooth /#\_ */
194         float t = fmod(u * nt * 4.0, 1.0);
195
196         float offs;
197         switch(part) {
198         case 0:
199                 offs = t;
200                 break;
201         case 1:
202                 offs = 1.0f;
203                 break;
204         case 2:
205                 offs = 1.0f - t;
206                 break;
207         case 3:
208                 offs = 0.0f;
209         }
210
211         float inner_rad = gear->radius - gear->teeth_length;
212         return Vec2(inner_rad + offs * gear->teeth_length, -y);
213 }
214
215 bool Gear::gen_mesh()
216 {
217         mesh = new Mesh;
218         gen_revol(mesh, nteeth * 4, 3, rev_pos, 0, this);
219         mesh->explode();
220         mesh->calc_face_normals();
221
222         Mat4 rot;
223         rot.rotation_x(M_PI / 2.0);
224         mesh->apply_xform(rot, rot);
225
226         mesh->set_vis_vecsize(6.0);
227         return true;
228 }
229
230 void Gear::calc_matrix() const
231 {
232         Vec3 up = Vec3(0, 1, 0);
233         if(1.0 - fabs(dot(up, axis)) < 1e-4) {
234                 up = Vec3(0, 0, -1);
235         }
236         Vec3 right = normalize(cross(up, axis));
237         up = cross(axis, right);
238
239         dir_xform = Mat4(right, up, axis);
240
241         xform = dir_xform;
242         xform.rotate_z(get_vis_rotation());
243         xform.translate(pos);
244 }