better obj loading
[cyberay] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <GL/glut.h>
5 #include <cgmath/cgmath.h>
6 #include "mesh.h"
7
8 enum {
9         KEY_F1          = GLUT_KEY_F1 | 0x100,
10         KEY_F2          = GLUT_KEY_F2 | 0x100,
11         KEY_F3          = GLUT_KEY_F3 | 0x100,
12         KEY_F4          = GLUT_KEY_F4 | 0x100,
13         KEY_F5          = GLUT_KEY_F5 | 0x100,
14         KEY_F6          = GLUT_KEY_F6 | 0x100,
15         KEY_F7          = GLUT_KEY_F7 | 0x100,
16         KEY_F8          = GLUT_KEY_F8 | 0x100,
17         KEY_F9          = GLUT_KEY_F9 | 0x100,
18         KEY_F10         = GLUT_KEY_F10 | 0x100,
19         KEY_F11         = GLUT_KEY_F11 | 0x100,
20         KEY_F12         = GLUT_KEY_F12 | 0x100,
21         KEY_LEFT        = GLUT_KEY_LEFT | 0x100,
22         KEY_UP          = GLUT_KEY_UP | 0x100,
23         KEY_RIGHT       = GLUT_KEY_RIGHT | 0x100,
24         KEY_DOWN        = GLUT_KEY_DOWN | 0x100,
25         KEY_PGUP        = GLUT_KEY_PAGE_UP | 0x100,
26         KEY_PGDN        = GLUT_KEY_PAGE_DOWN | 0x100,
27         KEY_HOME        = GLUT_KEY_HOME | 0x100,
28         KEY_END         = GLUT_KEY_END | 0x100,
29         KEY_INS         = GLUT_KEY_INSERT | 0x100
30 };
31
32 enum { INP_FWD, INP_BACK, INP_RIGHT, INP_LEFT, INP_FIRE, NUM_INPUTS };
33
34 static int init(void);
35 static void cleanup(void);
36 static void display(void);
37 static void idle(void);
38 static void reshape(int x, int y);
39 static void keydown(unsigned char key, int x, int y);
40 static void keyup(unsigned char key, int x, int y);
41 static void skeydown(int key, int x, int y);
42 static void skeyup(int key, int x, int y);
43 static void mouse(int bn, int st, int x, int y);
44 static void motion(int x, int y);
45
46
47 static long start_time;
48
49 static float cam_theta, cam_phi;
50 static cgm_vec3 cam_pos = {0, -1.6, 0};
51 static float pxform[16];
52
53 static int mouse_x, mouse_y;
54 static int bnstate[8];
55
56 static int inpstate[NUM_INPUTS];
57
58 static int keymap[NUM_INPUTS][2] = {
59         {'w', KEY_UP},
60         {'s', KEY_DOWN},
61         {'d', KEY_RIGHT},
62         {'a', KEY_LEFT},
63         {' ', 0}
64 };
65
66 static struct scenefile scn;
67
68 int main(int argc, char **argv)
69 {
70         glutInit(&argc, argv);
71         glutInitWindowSize(1280, 800);
72         glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
73         glutCreateWindow("cyberay");
74
75         glutDisplayFunc(display);
76         glutIdleFunc(idle);
77         glutReshapeFunc(reshape);
78         glutKeyboardFunc(keydown);
79         glutKeyboardUpFunc(keyup);
80         glutSpecialFunc(skeydown);
81         glutSpecialUpFunc(skeyup);
82         glutMouseFunc(mouse);
83         glutMotionFunc(motion);
84         glutPassiveMotionFunc(motion);
85
86         if(init() == -1) {
87                 return 1;
88         }
89         atexit(cleanup);
90
91         glutMainLoop();
92         return 0;
93 }
94
95 static int init(void)
96 {
97         glEnable(GL_CULL_FACE);
98
99         glEnable(GL_DEPTH_TEST);
100         glEnable(GL_LIGHTING);
101         glEnable(GL_LIGHT0);
102
103         if(load_scenefile(&scn, "data/testlvl.obj") == -1) {
104                 return -1;
105         }
106
107         start_time = glutGet(GLUT_ELAPSED_TIME);
108         return 0;
109 }
110
111 static void cleanup(void)
112 {
113         destroy_scenefile(&scn);
114 }
115
116 #define WALK_SPEED 3.0f
117 static void update(void)
118 {
119         static unsigned int prev_upd;
120         unsigned int msec;
121         float dt, vfwd, vright;
122
123         msec = glutGet(GLUT_ELAPSED_TIME) - start_time;
124         dt = (float)(msec - prev_upd) / 1000.0f;
125         prev_upd = msec;
126
127         vfwd = vright = 0;
128
129         if(inpstate[INP_FWD]) {
130                 vfwd -= WALK_SPEED * dt;
131         }
132         if(inpstate[INP_BACK]) {
133                 vfwd += WALK_SPEED * dt;
134         }
135         if(inpstate[INP_RIGHT]) {
136                 vright -= WALK_SPEED * dt;
137         }
138         if(inpstate[INP_LEFT]) {
139                 vright += WALK_SPEED * dt;
140         }
141
142         cam_pos.x += cos(cam_theta) * vright + sin(cam_theta) * vfwd;
143         cam_pos.z += sin(cam_theta) * vright - cos(cam_theta) * vfwd;
144
145         cgm_midentity(pxform);
146         cgm_mtranslate(pxform, cam_pos.x, cam_pos.y, cam_pos.z);
147         cgm_mrotate_y(pxform, cam_theta);
148         cgm_mrotate_x(pxform, cam_phi);
149 }
150
151 static void display(void)
152 {
153         struct mesh *mesh;
154
155         update();
156
157         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
158
159         glMatrixMode(GL_MODELVIEW);
160         glLoadMatrixf(pxform);
161
162         mesh = scn.meshlist;
163         while(mesh) {
164                 float col[4];
165                 col[0] = mesh->mtl.color.x;
166                 col[1] = mesh->mtl.color.y;
167                 col[2] = mesh->mtl.color.z;
168                 col[3] = 1.0f;
169                 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col);
170
171                 draw_mesh(mesh);
172                 mesh = mesh->next;
173         }
174
175         glutSwapBuffers();
176         assert(glGetError() == GL_NO_ERROR);
177 }
178
179 static void idle(void)
180 {
181         glutPostRedisplay();
182 }
183
184 static void reshape(int x, int y)
185 {
186         glMatrixMode(GL_PROJECTION);
187         glLoadIdentity();
188         gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
189 }
190
191 static void keyb(int key, int press)
192 {
193         int i;
194
195         for(i=0; i<NUM_INPUTS; i++) {
196                 if(keymap[i][0] == key || keymap[i][1] == key) {
197                         inpstate[i] = press;
198                 }
199         }
200 }
201
202 static void keydown(unsigned char key, int x, int y)
203 {
204         if(key == 27) exit(0);
205         keyb(key, 1);
206 }
207
208 static void keyup(unsigned char key, int x, int y)
209 {
210         keyb(key, 0);
211 }
212
213 static void skeydown(int key, int x, int y)
214 {
215         keyb(key | 0x100, 1);
216 }
217
218 static void skeyup(int key, int x, int y)
219 {
220         keyb(key | 0x100, 0);
221 }
222
223 static void mouse(int bn, int st, int x, int y)
224 {
225         mouse_x = x;
226         mouse_y = y;
227         bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
228 }
229
230 static void motion(int x, int y)
231 {
232         int dx = x - mouse_x;
233         int dy = y - mouse_y;
234         mouse_x = x;
235         mouse_y = y;
236
237         if(!(dx | dy)) return;
238
239         if(bnstate[0]) {
240                 cam_theta += dx * 0.01;
241                 cam_phi += dy * 0.01;
242
243                 if(cam_phi < -M_PI) cam_phi = -M_PI;
244                 if(cam_phi > M_PI) cam_phi = M_PI;
245         }
246 }