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