- added subgear linkage
[antikythera] / src / main.cc
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <GL/glew.h>
5 #ifdef __APPLE__
6 #include <GLUT/glut.h>
7 #else
8 #include <GL/glut.h>
9 #endif
10 #include "app.h"
11 #include "machine.h"
12
13 static bool init();
14 static void cleanup();
15 static void display();
16 static void idle();
17 static void draw_gears();
18 static void reshape(int x, int y);
19 static void keyb(unsigned char key, int x, int y);
20 static void mouse(int bn, int st, int x, int y);
21 static void motion(int x, int y);
22 static void passive_motion(int x, int y);
23 static Gear *pick_gear(int x, int y);
24
25 static int win_width, win_height;
26
27 static float cam_dist = 0.5;
28 static float cam_theta, cam_phi;
29 static int prev_mx, prev_my;
30 static bool bnstate[8];
31
32 static unsigned int start_time, prev_msec;
33 static Machine *machine;
34 static Gear *hover_gear, *sel_gear;
35 static HitPoint pick_hit;
36 static Vec3 sel_hit_pos;
37
38 int main(int argc, char **argv)
39 {
40         glutInitWindowSize(1024, 768);
41         glutInit(&argc, argv);
42         glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | GLUT_MULTISAMPLE);
43         glutCreateWindow("Antikythera");
44
45         glutDisplayFunc(display);
46         glutIdleFunc(idle);
47         glutReshapeFunc(reshape);
48         glutKeyboardFunc(keyb);
49         glutMouseFunc(mouse);
50         glutMotionFunc(motion);
51         glutPassiveMotionFunc(passive_motion);
52
53         if(!init()) {
54                 return 1;
55         }
56         atexit(cleanup);
57
58         glutMainLoop();
59         return 0;
60 }
61
62 static bool init()
63 {
64         glewInit();
65
66         glEnable(GL_MULTISAMPLE);
67         glEnable(GL_DEPTH_TEST);
68         glEnable(GL_CULL_FACE);
69         glEnable(GL_LIGHTING);
70         glEnable(GL_NORMALIZE);
71
72         Mesh::use_custom_sdr_attr = false;
73
74         machine = new Machine;
75
76         const float pitch = 10.0f;
77
78         Gear *gear1 = new Gear;
79         gear1->pos = Vec3(-50, 0, 0);
80         gear1->set_teeth(16, pitch);
81         gear1->gen_mesh();
82         machine->add_gear(gear1);
83
84         Gear *gear2 = new Gear;
85         gear2->set_teeth(32, pitch);
86         gear2->pos = gear1->pos + Vec3(gear1->radius + gear2->radius - gear1->teeth_length * 0.75, 0, 0);
87         gear2->thickness = 5;
88         gear2->gen_mesh();
89         machine->add_gear(gear2);
90
91         Gear *gear3 = new Gear;
92         gear3->set_teeth(8, pitch);
93         gear3->pos = gear2->pos + Vec3(0, gear2->radius + gear3->radius - gear2->teeth_length * 0.75, 0);
94         gear3->gen_mesh();
95         machine->add_gear(gear3);
96
97         Gear *subgear = new Gear;
98         subgear->set_teeth(10, pitch);
99         subgear->pos = Vec3(0, 0, (gear2->thickness + subgear->thickness) / 2 + 1);
100         subgear->gen_mesh();
101         gear2->attach(subgear);
102         machine->add_gear(subgear);
103
104         machine->add_motor(0, 1.0);
105
106         start_time = glutGet(GLUT_ELAPSED_TIME);
107         return true;
108 }
109
110 static void cleanup()
111 {
112         delete machine;
113 }
114
115 static void update(float dt)
116 {
117         machine->update(dt);
118
119         if(sel_gear) {
120         }
121
122         hover_gear = pick_gear(prev_mx, prev_my);
123 }
124
125 static void set_light(int idx, const Vec3 &pos, const Vec3 &color)
126 {
127         unsigned int lt = GL_LIGHT0 + idx;
128         float posv[] = { pos.x, pos.y, pos.z, 1 };
129         float colv[] = { color.x, color.y, color.z, 1 };
130
131         glEnable(lt);
132         glLightfv(lt, GL_POSITION, posv);
133         glLightfv(lt, GL_DIFFUSE, colv);
134         glLightfv(lt, GL_SPECULAR, colv);
135 }
136
137 static void display()
138 {
139         unsigned int msec = glutGet(GLUT_ELAPSED_TIME) - start_time;
140         float dt = (float)(msec - prev_msec) / 1000.0f;
141         prev_msec = msec;
142
143         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
144
145         glMatrixMode(GL_MODELVIEW);
146         glLoadIdentity();
147         glTranslatef(0, 0, -cam_dist);
148         glRotatef(cam_phi, 1, 0, 0);
149         glRotatef(cam_theta, 0, 1, 0);
150
151         set_light(0, Vec3(-50, 75, 100), Vec3(1.0, 0.8, 0.7) * 0.8);
152         set_light(1, Vec3(100, 0, 30), Vec3(0.6, 0.7, 1.0) * 0.6);
153         set_light(2, Vec3(-10, -10, 60), Vec3(0.8, 1.0, 0.8) * 0.3);
154
155         update(dt);
156
157         draw_gears();
158
159         glutSwapBuffers();
160         assert(glGetError() == GL_NO_ERROR);
161 }
162
163 static void idle()
164 {
165         glutPostRedisplay();
166 }
167
168 static void draw_gears()
169 {
170         /* world scale is in meters, gears are in millimeters, scale by 1/1000 */
171         glPushMatrix();
172         glScalef(0.001, 0.001, 0.001);
173
174         if(sel_gear || hover_gear) {
175                 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_POLYGON_BIT);
176
177                 glDisable(GL_LIGHTING);
178                 glFrontFace(GL_CW);
179                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
180                 glLineWidth(3.0);
181
182                 if(sel_gear) {
183                         glColor3f(0.2, 1.0, 0.3);
184                         sel_gear->draw();
185                 } else {
186                         glColor3f(1.0, 0.75, 0.2);
187                         hover_gear->draw();
188                 }
189
190                 glPopAttrib();
191         }
192
193         machine->draw();
194
195         glPopMatrix();
196 }
197
198 static void reshape(int x, int y)
199 {
200         win_width = x;
201         win_height = y;
202
203         glViewport(0, 0, x, y);
204
205         glMatrixMode(GL_PROJECTION);
206         glLoadIdentity();
207         gluPerspective(50.0, (float)x / (float)y, 0.01, 100.0);
208 }
209
210 static void keyb(unsigned char key, int x, int y)
211 {
212         switch(key) {
213         case 27:
214                 exit(0);
215
216         case 'w':
217                 opt_gear_wireframe = !opt_gear_wireframe;
218                 glutPostRedisplay();
219                 break;
220         }
221 }
222
223 static void mouse(int bn, int st, int x, int y)
224 {
225         int bidx = bn - GLUT_LEFT_BUTTON;
226         bool down = st == GLUT_DOWN;
227
228         prev_mx = x;
229         prev_my = y;
230         bnstate[bidx] = down;
231
232         if(bidx == 0) {
233                 if(down) {
234                         sel_gear = pick_gear(x, y);
235                         sel_hit_pos = pick_hit.pos;
236                 } else {
237                         sel_gear = 0;
238                 }
239         }
240
241         if(bidx == 3 || bidx == 4) {    /* wheel */
242                 if(hover_gear) {
243                         float dz = bidx == 4 ? 1 : -1;
244                         hover_gear->set_position(hover_gear->get_position() + hover_gear->get_axis() * dz);
245                         machine->invalidate_meshing();
246                 }
247         }
248 }
249
250 static void motion(int x, int y)
251 {
252         int dx = x - prev_mx;
253         int dy = y - prev_my;
254         prev_mx = x;
255         prev_my = y;
256
257         if(!dx && !dy) return;
258
259         if(sel_gear) {
260                 float speed = 0.5;
261                 Vec3 offs = Vec3(dx * speed, -dy * speed, 0.0);
262                 offs = sel_gear->get_dir_matrix() * offs;
263
264                 sel_gear->set_position(sel_gear->get_position() + offs);
265                 machine->invalidate_meshing();
266
267         } else {
268                 if(bnstate[0]) {
269                         cam_theta += dx * 0.5;
270                         cam_phi += dy * 0.5;
271
272                         if(cam_phi < -90) cam_phi = -90;
273                         if(cam_phi > 90) cam_phi = 90;
274                         glutPostRedisplay();
275                 }
276                 if(bnstate[2]) {
277                         cam_dist += dy * 0.01;
278                         if(cam_dist < 0.0) cam_dist = 0.0;
279                         glutPostRedisplay();
280                 }
281         }
282 }
283
284 static void passive_motion(int x, int y)
285 {
286         prev_mx = x;
287         prev_my = y;
288 }
289
290 static Gear *pick_gear(int x, int y)
291 {
292         double pt[3];
293         double viewmat[16], projmat[16];
294         int vp[4];
295         Ray ray;
296
297         y = win_height - y;
298
299         glGetDoublev(GL_MODELVIEW_MATRIX, viewmat);
300         glGetDoublev(GL_PROJECTION_MATRIX, projmat);
301         glGetIntegerv(GL_VIEWPORT, vp);
302
303         gluUnProject(x, y, 0, viewmat, projmat, vp, pt, pt + 1, pt + 2);
304         ray.origin = Vec3(pt[0], pt[1], pt[2]) * 1000.0f;
305
306         gluUnProject(x, y, 1, viewmat, projmat, vp, pt, pt + 1, pt + 2);
307         ray.dir = Vec3(pt[0], pt[1], pt[2]) * 1000.0f - ray.origin;
308
309         return machine->intersect_gear(ray, &pick_hit);
310 }