meshing recaclulation on the fly, picking, whatever
[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_LIGHT0);
71         glEnable(GL_NORMALIZE);
72
73         Mesh::use_custom_sdr_attr = false;
74
75         machine = new Machine;
76
77         const float pitch = 10.0f;
78
79         Gear *gear1 = new Gear;
80         gear1->pos = Vec3(-50, 0, 0);
81         gear1->set_teeth(16, pitch);
82         gear1->gen_mesh();
83         machine->add_gear(gear1);
84
85         Gear *gear2 = new Gear;
86         gear2->set_teeth(32, pitch);
87         gear2->pos = gear1->pos + Vec3(gear1->radius + gear2->radius - gear1->teeth_length * 0.75, 0, 0);
88         gear2->thickness = 5;
89         gear2->gen_mesh();
90         machine->add_gear(gear2);
91
92         Gear *gear3 = new Gear;
93         gear3->set_teeth(8, pitch);
94         gear3->pos = gear2->pos + Vec3(0, gear2->radius + gear3->radius - gear2->teeth_length * 0.75, 0);
95         gear3->gen_mesh();
96         machine->add_gear(gear3);
97
98         machine->add_motor(0, 1.0);
99
100         start_time = glutGet(GLUT_ELAPSED_TIME);
101         return true;
102 }
103
104 static void cleanup()
105 {
106         delete machine;
107 }
108
109 static void update(float dt)
110 {
111         machine->update(dt);
112
113         if(sel_gear) {
114         }
115
116         hover_gear = pick_gear(prev_mx, prev_my);
117 }
118
119 static void display()
120 {
121         unsigned int msec = glutGet(GLUT_ELAPSED_TIME) - start_time;
122         float dt = (float)(msec - prev_msec) / 1000.0f;
123         prev_msec = msec;
124
125         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
126
127         glMatrixMode(GL_MODELVIEW);
128         glLoadIdentity();
129         glTranslatef(0, 0, -cam_dist);
130         glRotatef(cam_phi, 1, 0, 0);
131         glRotatef(cam_theta, 0, 1, 0);
132
133         update(dt);
134
135         draw_gears();
136
137         glutSwapBuffers();
138         assert(glGetError() == GL_NO_ERROR);
139 }
140
141 static void idle()
142 {
143         glutPostRedisplay();
144 }
145
146 static void draw_gears()
147 {
148         /* world scale is in meters, gears are in millimeters, scale by 1/1000 */
149         glPushMatrix();
150         glScalef(0.001, 0.001, 0.001);
151
152         if(sel_gear || hover_gear) {
153                 glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_POLYGON_BIT);
154
155                 glDisable(GL_LIGHTING);
156                 glFrontFace(GL_CW);
157                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
158                 glLineWidth(3.0);
159
160                 if(sel_gear) {
161                         glColor3f(0.2, 1.0, 0.3);
162                         sel_gear->draw();
163                 } else {
164                         glColor3f(1.0, 0.75, 0.2);
165                         hover_gear->draw();
166                 }
167
168                 glPopAttrib();
169         }
170
171         machine->draw();
172
173         glPopMatrix();
174 }
175
176 static void reshape(int x, int y)
177 {
178         win_width = x;
179         win_height = y;
180
181         glViewport(0, 0, x, y);
182
183         glMatrixMode(GL_PROJECTION);
184         glLoadIdentity();
185         gluPerspective(50.0, (float)x / (float)y, 0.01, 100.0);
186 }
187
188 static void keyb(unsigned char key, int x, int y)
189 {
190         switch(key) {
191         case 27:
192                 exit(0);
193
194         case 'w':
195                 opt_gear_wireframe = !opt_gear_wireframe;
196                 glutPostRedisplay();
197                 break;
198         }
199 }
200
201 static void mouse(int bn, int st, int x, int y)
202 {
203         int bidx = bn - GLUT_LEFT_BUTTON;
204         bool down = st == GLUT_DOWN;
205
206         prev_mx = x;
207         prev_my = y;
208         bnstate[bidx] = down;
209
210         if(bidx == 0) {
211                 if(down) {
212                         sel_gear = pick_gear(x, y);
213                         sel_hit_pos = pick_hit.pos;
214                 } else {
215                         sel_gear = 0;
216                 }
217         }
218 }
219
220 static void motion(int x, int y)
221 {
222         int dx = x - prev_mx;
223         int dy = y - prev_my;
224         prev_mx = x;
225         prev_my = y;
226
227         if(!dx && !dy) return;
228
229         if(sel_gear) {
230                 float speed = 0.5;
231                 Vec3 offs = Vec3(dx * speed, -dy * speed, 0.0);
232                 offs = sel_gear->get_dir_matrix() * offs;
233
234                 sel_gear->set_position(sel_gear->get_position() + offs);
235                 machine->invalidate_meshing();
236
237         } else {
238                 if(bnstate[0]) {
239                         cam_theta += dx * 0.5;
240                         cam_phi += dy * 0.5;
241
242                         if(cam_phi < -90) cam_phi = -90;
243                         if(cam_phi > 90) cam_phi = 90;
244                         glutPostRedisplay();
245                 }
246                 if(bnstate[2]) {
247                         cam_dist += dy * 0.01;
248                         if(cam_dist < 0.0) cam_dist = 0.0;
249                         glutPostRedisplay();
250                 }
251         }
252 }
253
254 static void passive_motion(int x, int y)
255 {
256         prev_mx = x;
257         prev_my = y;
258 }
259
260 static Gear *pick_gear(int x, int y)
261 {
262         double pt[3];
263         double viewmat[16], projmat[16];
264         int vp[4];
265         Ray ray;
266
267         y = win_height - y;
268
269         glGetDoublev(GL_MODELVIEW_MATRIX, viewmat);
270         glGetDoublev(GL_PROJECTION_MATRIX, projmat);
271         glGetIntegerv(GL_VIEWPORT, vp);
272
273         gluUnProject(x, y, 0, viewmat, projmat, vp, pt, pt + 1, pt + 2);
274         ray.origin = Vec3(pt[0], pt[1], pt[2]) * 1000.0f;
275
276         gluUnProject(x, y, 1, viewmat, projmat, vp, pt, pt + 1, pt + 2);
277         ray.dir = Vec3(pt[0], pt[1], pt[2]) * 1000.0f - ray.origin;
278
279         return machine->intersect_gear(ray, &pick_hit);
280 }