added forces + damping, k factors
[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
14 #define MAX_NUM_SPAWNS 400
15 #define THRESH 0.5
16
17 static bool init();
18 static void cleanup();
19 static void display();
20 static void reshape(int x, int y);
21 static void keydown(unsigned char key, int x, int y);
22 static void keyup(unsigned char key, int x, int y);
23 static void mouse(int bn, int st, int x, int y);
24 static void motion(int x, int y);
25 static void idle();
26
27 static std::vector<Mesh*> meshes;
28 static Mesh *mesh_head;
29 static Hair hair;
30
31 static int win_width, win_height;
32 static float cam_theta, cam_phi = 25, cam_dist = 8;
33 static float head_rz, head_rx; /* rot angles x, z axis */
34 static Mat4 head_xform;
35
36 int main(int argc, char **argv)
37 {
38         glutInit(&argc, argv);
39         glutInitWindowSize(800, 600);
40         glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
41         glutCreateWindow("hair test");
42
43         /* for the keydown, keyup functions to work */
44         glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF);
45
46         glutDisplayFunc(display);
47         glutReshapeFunc(reshape);
48         glutKeyboardFunc(keydown);
49         glutKeyboardUpFunc(keyup);
50         glutMouseFunc(mouse);
51         glutMotionFunc(motion);
52         glutIdleFunc(idle);
53
54         if(!init()) {
55                 return 1;
56         }
57         atexit(cleanup);
58
59         glutMainLoop();
60         return 0;
61 }
62
63 static bool init()
64 {
65         glewInit();
66
67         glEnable(GL_DEPTH_TEST);
68         glEnable(GL_CULL_FACE);
69         glEnable(GL_COLOR_MATERIAL);
70
71         glEnable(GL_LIGHTING);
72         glEnable(GL_LIGHT0);
73
74         glClearColor(0.5, 0.5, 0.5, 1);
75         meshes = load_meshes("data/head.fbx");
76         if (meshes.empty()) {
77                 fprintf(stderr, "Failed to load mesh.\n");
78                 return false;
79         }
80
81         for(size_t i=0; i<meshes.size(); i++) {
82                 meshes[i]->calc_bbox();
83 /*
84                 Vec3 v0 = meshes[i]->bbox.v0;
85                 Vec3 v1 = meshes[i]->bbox.v1;
86
87                 printf("mesh: %s\n", meshes[i]->name.c_str());
88                 printf("AABB mesh %d: v0: (%f, %f, %f) v1: (%f, %f, %f)\n",
89                                 (int)i, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z);
90 */
91                 meshes[i]->update_vbo(MESH_ALL);
92 /*
93                 printf("num vertices: %d num triangles: %d\n",
94                                 (int)meshes[i]->vertices.size(),
95                                 (int)meshes[i]->indices.size() / 3);
96 */
97                 if(meshes[i]->name == "head") {
98                         mesh_head = meshes[i];
99                 }
100         }
101         if(!mesh_head) {
102                 fprintf(stderr, "Failed to find the head mesh.\n");
103                 return false;
104         }
105
106         if(!hair.init(mesh_head, MAX_NUM_SPAWNS, THRESH)) {
107                 fprintf(stderr, "Failed to initialize hair\n");
108                 return false;
109         }
110
111         return true;
112 }
113
114 static void cleanup()
115 {
116         for(size_t i=0; i<meshes.size(); i++) {
117                 delete meshes[i];
118         }
119 }
120
121 static void display()
122 {
123         static unsigned long prev_time;
124         unsigned long msec = glutGet(GLUT_ELAPSED_TIME);
125         float dt = (float)(msec - prev_time) / 1000.0;
126         prev_time = msec;
127
128         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
129
130         head_xform = Mat4::identity;
131         head_xform.rotate_x(gph::deg_to_rad(head_rx));
132         head_xform.rotate_z(-gph::deg_to_rad(head_rz));
133
134         glMatrixMode(GL_MODELVIEW);
135         glLoadIdentity();
136         glTranslatef(0, 0, -cam_dist);
137         glRotatef(cam_phi, 1, 0, 0);
138         glRotatef(cam_theta, 0, 1, 0);
139         /* multiplying with the head rot matrix */
140         glPushMatrix();
141         glMultMatrixf(head_xform[0]);
142         for(size_t i=0; i<meshes.size(); i++) {
143                 meshes[i]->draw();
144         }
145         glPopMatrix();
146
147         hair.set_transform(head_xform);
148         hair.update(dt);
149         hair.draw();
150
151         glutSwapBuffers();
152         assert(glGetError() == GL_NO_ERROR);
153 }
154
155 static void reshape(int x, int y)
156 {
157         glViewport(0, 0, x, y);
158         win_width = x;
159         win_height = y;
160
161         glMatrixMode(GL_PROJECTION);
162         glLoadIdentity();
163         gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
164 }
165
166 static bool hpressed;
167 static void keydown(unsigned char key, int /*x*/, int /*y*/)
168 {
169         switch(key) {
170         case 'h':
171         case 'H':
172                 hpressed = true;
173                 break;
174         case 27:
175                 exit(0);
176         default:
177                 break;
178         }
179 }
180
181 static void keyup(unsigned char key, int /*x*/, int /*y*/)
182 {
183         switch(key) {
184         case 'h':
185         case 'H':
186                 hpressed = false;
187                 break;
188         default:
189                 break;
190         }
191 }
192
193 bool bnstate[8];
194 int prev_x, prev_y;
195
196 static void mouse(int bn, int st, int x, int y)
197 {
198         bnstate[bn] = st == GLUT_DOWN;
199         prev_x = x;
200         prev_y = y;
201 }
202
203 static void motion(int x, int y)
204 {
205         int dx = x - prev_x;
206         int dy = y - prev_y;
207         prev_x = x;
208         prev_y = y;
209
210         if(!dx && !dy) return;
211
212         if(hpressed) {
213                 if(bnstate[0]) {
214                         head_rz += dx * 0.5;
215                         head_rx += dy * 0.5;
216
217                         if(head_rx < -45) head_rx = -45;
218                         if(head_rx > 45) head_rx = 45;
219
220                         if(head_rz < -90) head_rz = -90;
221                         if(head_rz > 90) head_rz = 30;
222                 }
223         }
224         else {
225                 if(bnstate[0]) {
226                         cam_theta += dx * 0.5;
227                         cam_phi += dy * 0.5;
228
229                         if(cam_phi < -90) cam_phi = -90;
230                         if(cam_phi > 90) cam_phi = 90;
231                 }
232                 if(bnstate[2]) {
233                         cam_dist += dy * 0.1;
234                         if(cam_dist < 0) cam_dist = 0;
235                 }
236         }
237 }
238
239 static void idle()
240 {
241         glutPostRedisplay();
242 }