0ebbe441282a3238a6336671f912a85ad2ed007c
[hair] / src / main.cc
1 #include <GL/glew.h>
2 #include <GL/glut.h>
3
4 #include <assert.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string>
8
9 #include <gmath/gmath.h>
10
11 #include "mesh.h"
12 #include "hair.h"
13 #include "object.h"
14
15 #define MAX_NUM_SPAWNS 800
16 #define THRESH 0.5
17
18 static bool init();
19 static void cleanup();
20 static void display();
21 static void reshape(int x, int y);
22 static void keydown(unsigned char key, int x, int y);
23 static void keyup(unsigned char key, int x, int y);
24 static void mouse(int bn, int st, int x, int y);
25 static void motion(int x, int y);
26 static void idle();
27
28 static unsigned int gen_grad_tex(int sz, const Vec3 &c0, const Vec3 &c1);
29 static void draw_text(const char *text, int x, int y, float sz, const Vec3 &color);
30
31 static std::vector<Mesh*> meshes;
32 static Mesh *mesh_head;
33 static Hair hair;
34
35 static unsigned int grad_tex;
36
37 static int win_width, win_height;
38 static float cam_theta, cam_phi = 25, cam_dist = 8;
39 static float head_rz, head_rx; /* rot angles x, z axis */
40 static Mat4 head_xform;
41 //static CollSphere coll_sphere; /* sphere used for collision detection */
42
43 int main(int argc, char **argv)
44 {
45         glutInit(&argc, argv);
46         glutInitWindowSize(800, 600);
47         glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
48         glutCreateWindow("hair test");
49
50         /* for the keydown, keyup functions to work */
51         glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
52
53         glutDisplayFunc(display);
54         glutReshapeFunc(reshape);
55         glutKeyboardFunc(keydown);
56         glutKeyboardUpFunc(keyup);
57         glutMouseFunc(mouse);
58         glutMotionFunc(motion);
59         glutIdleFunc(idle);
60
61         if(!init()) {
62                 return 1;
63         }
64         atexit(cleanup);
65
66         glutMainLoop();
67         return 0;
68 }
69
70 static bool init()
71 {
72         glewInit();
73
74         grad_tex = gen_grad_tex(32, Vec3(0, 0, 1), Vec3(0, 1, 0));
75
76         glEnable(GL_DEPTH_TEST);
77         glEnable(GL_CULL_FACE);
78 //      glEnable(GL_COLOR_MATERIAL);
79
80         glEnable(GL_LIGHTING);
81         glEnable(GL_LIGHT0);
82
83         glClearColor(0.5, 0.5, 0.5, 1);
84         meshes = load_meshes("data/head.fbx");
85         if (meshes.empty()) {
86                 fprintf(stderr, "Failed to load mesh.\n");
87                 return false;
88         }
89
90         for(size_t i=0; i<meshes.size(); i++) {
91                 meshes[i]->calc_bbox();
92 /*
93                 Vec3 v0 = meshes[i]->bbox.v0;
94                 Vec3 v1 = meshes[i]->bbox.v1;
95
96                 printf("mesh: %s\n", meshes[i]->name.c_str());
97                 printf("AABB mesh %d: v0: (%f, %f, %f) v1: (%f, %f, %f)\n",
98                                 (int)i, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z);
99 */
100                 meshes[i]->update_vbo(MESH_ALL);
101 /*
102                 printf("num vertices: %d num triangles: %d\n",
103                                 (int)meshes[i]->vertices.size(),
104                                 (int)meshes[i]->indices.size() / 3);
105 */
106                 if(meshes[i]->name == "head") {
107                         mesh_head = meshes[i];
108                 }
109         }
110         if(!mesh_head) {
111                 fprintf(stderr, "Failed to find the head mesh.\n");
112                 return false;
113         }
114
115 //      coll_sphere.radius = 1.0;
116 //      coll_sphere.center = Vec3(0, 0.6, 0.53);
117
118         if(!hair.init(mesh_head, MAX_NUM_SPAWNS, THRESH)) {
119                 fprintf(stderr, "Failed to initialize hair\n");
120                 return false;
121         }
122
123 //      hair.add_collider(&coll_sphere);
124
125         return true;
126 }
127
128 static void cleanup()
129 {
130         for(size_t i=0; i<meshes.size(); i++) {
131                 delete meshes[i];
132         }
133         glDeleteTextures(1, &grad_tex);
134 }
135
136 static void display()
137 {
138         static unsigned long prev_time;
139         unsigned long msec = glutGet(GLUT_ELAPSED_TIME);
140         float dt = (float)(msec - prev_time) / 1000.0;
141         prev_time = msec;
142
143         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
144
145         head_xform = Mat4::identity;
146         head_xform.rotate_x(gph::deg_to_rad(head_rx));
147         head_xform.rotate_z(-gph::deg_to_rad(head_rz));
148
149         glMatrixMode(GL_MODELVIEW);
150         glLoadIdentity();
151         glTranslatef(0, 0, -cam_dist);
152         glRotatef(cam_phi, 1, 0, 0);
153         glRotatef(cam_theta, 0, 1, 0);
154         /* multiplying with the head rot matrix */
155         glPushMatrix();
156         glMultMatrixf(head_xform[0]);
157 /*
158         glPushAttrib(GL_LINE_BIT);
159         glLineWidth(1);
160         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
161 */
162         for(size_t i=0; i<meshes.size(); i++) {
163                 if(!meshes[i]->mtl.tex || meshes[i]->mtl.tex_opaque)
164                         meshes[i]->draw();
165         }
166         for(size_t i=0; i<meshes.size(); i++) {
167                 if(meshes[i]->mtl.tex && !meshes[i]->mtl.tex_opaque)
168                         meshes[i]->draw();
169         }
170 /*
171         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
172         glPopAttrib();
173 */
174
175         glPopMatrix();
176
177         hair.set_transform(head_xform);
178         hair.update(dt);
179         hair.draw();
180
181 /*
182         glPushAttrib(GL_ENABLE_BIT);
183         glDisable(GL_DEPTH_TEST);
184         glDisable(GL_LIGHTING);
185         glBegin(GL_POINTS);
186         for (int i=0; i<500; i++) {
187                 Vec3 p;
188                 p.x = (float)rand() / RAND_MAX * 8 - 4;
189                 p.y = (float)rand() / RAND_MAX * 4;
190                 p.z = 0;
191
192                 Vec3 tmp = inverse(head_xform) * p;
193                 if(coll_sphere.contains(tmp)) {
194                         glColor3f(1, 0, 0);
195                 }
196                 else glColor3f(0, 1, 0);
197
198                 glVertex3f(p.x, p.y, p.z);
199         }
200         glEnd();
201         glPopAttrib();
202 */
203         float plane[4] = {
204                 0, 0, 0.5 / 350, 0.5
205         };
206
207         glPushMatrix();
208         glRotatef(90, 1, 0, 0);
209
210         glPushAttrib(GL_ENABLE_BIT);
211         glDisable(GL_LIGHTING);
212         glEnable(GL_TEXTURE_1D);
213         glBindTexture(GL_TEXTURE_1D, grad_tex);
214         glFrontFace(GL_CW);
215         glEnable(GL_TEXTURE_GEN_S);
216         glTexGenfv(GL_S, GL_OBJECT_PLANE, plane);
217         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
218         glColor3f(1, 1, 1);
219
220         glDepthMask(0);
221
222         glutSolidSphere(350, 16, 8);
223         glDisable(GL_TEXTURE_1D);
224
225         glColor3f(0.2, 0.2, 0.2);
226         glutWireSphere(350, 32, 16);
227
228         glDepthMask(1);
229         glFrontFace(GL_CCW);
230         glPopAttrib();
231
232         glPopMatrix();
233
234         draw_text("Hold h to move the head with the mouse!", 15, 15, 0.0015 * win_width, Vec3(0, 0, 0));
235         draw_text("Hold h to move the head with the mouse!", 12, 17, 0.0015 * win_width, Vec3(0.8, 0.5, 0.7));
236
237         glutSwapBuffers();
238         assert(glGetError() == GL_NO_ERROR);
239 }
240
241 static void reshape(int x, int y)
242 {
243         glViewport(0, 0, x, y);
244         win_width = x;
245         win_height = y;
246
247         glMatrixMode(GL_PROJECTION);
248         glLoadIdentity();
249         gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
250 }
251
252 static bool hpressed;
253 static void keydown(unsigned char key, int /*x*/, int /*y*/)
254 {
255         switch(key) {
256         case 'h':
257         case 'H':
258                 hpressed = true;
259                 break;
260         case 27:
261                 exit(0);
262         default:
263                 break;
264         }
265 }
266
267 static void keyup(unsigned char key, int /*x*/, int /*y*/)
268 {
269         switch(key) {
270         case 'h':
271         case 'H':
272                 hpressed = false;
273                 break;
274         default:
275                 break;
276         }
277 }
278
279 bool bnstate[8];
280 int prev_x, prev_y;
281
282 static void mouse(int bn, int st, int x, int y)
283 {
284         bnstate[bn] = st == GLUT_DOWN;
285         prev_x = x;
286         prev_y = y;
287 }
288
289 static void motion(int x, int y)
290 {
291         int dx = x - prev_x;
292         int dy = y - prev_y;
293         prev_x = x;
294         prev_y = y;
295
296         if(!dx && !dy) return;
297
298         if(hpressed) {
299                 if(bnstate[0]) {
300                         head_rz += dx * 0.5;
301                         head_rx += dy * 0.5;
302
303                         if(head_rx < -45) head_rx = -45;
304                         if(head_rx > 45) head_rx = 45;
305
306                         if(head_rz < -90) head_rz = -90;
307                         if(head_rz > 90) head_rz = 30;
308                 }
309         }
310         else {
311                 if(bnstate[0]) {
312                         cam_theta += dx * 0.5;
313                         cam_phi += dy * 0.5;
314
315                         if(cam_phi < -90) cam_phi = -90;
316                         if(cam_phi > 90) cam_phi = 90;
317                 }
318                 if(bnstate[2]) {
319                         cam_dist += dy * 0.1;
320                         if(cam_dist < 0) cam_dist = 0;
321                 }
322         }
323 }
324
325 static void idle()
326 {
327         glutPostRedisplay();
328 }
329
330 static unsigned int gen_grad_tex(int sz, const Vec3 &c0, const Vec3 &c1)
331 {
332         unsigned char *pixels = new unsigned char[sz * 3];
333         for(int i=0; i<sz; i++) {
334                 float t = (float)i / (float)(sz - 1);
335                 Vec3 color = c0 + (c1 - c0) * t;
336                 pixels[i * 3] = color.x * 255;
337                 pixels[i * 3 + 1] = color.y * 255;
338                 pixels[i * 3 + 2] = color.z * 255;
339         }
340
341         unsigned int tex;
342         glGenTextures(1, &tex);
343         glBindTexture(GL_TEXTURE_1D, tex);
344
345         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
346         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
347         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
348
349         glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, sz, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
350
351         delete [] pixels;
352
353         return tex;
354 }
355
356 static void draw_text(const char *text, int x, int y, float sz, const Vec3 &color)
357 {
358         glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT);
359
360         glDisable(GL_DEPTH_TEST);
361         glDisable(GL_LIGHTING);
362         glLineWidth(3);
363         glPointSize(3);
364
365         glMatrixMode(GL_PROJECTION);
366         glPushMatrix();
367         glLoadIdentity();
368         glOrtho(0, win_width, 0, win_height, -1, 1);
369
370         glMatrixMode(GL_MODELVIEW);
371         glPushMatrix();
372         glLoadIdentity();
373         glTranslatef(x, y, 0);
374         glScalef(0.1 * sz, 0.1 * sz, 1);
375
376         glColor3f(color.x, color.y, color.z);
377         while(*text != '\0') {
378                 glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, *text);
379                 text++;
380         }
381
382         glMatrixMode(GL_PROJECTION);
383         glPopMatrix();
384
385         glMatrixMode(GL_MODELVIEW);
386         glPopMatrix();
387
388         glPopAttrib();
389 }