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