- added glutIgnoreKeyRepeat in miniglut
[vrlugburz] / src / game.c
1 #include <stdio.h>
2 #include <assert.h>
3 #include "cgmath/cgmath.h"
4 #include "game.h"
5 #include "opengl.h"
6 #include "level.h"
7 #include "player.h"
8 #include "scenefile.h"
9 #include "sdr.h"
10
11 static void draw_level(void);
12
13 struct level lvl;
14 struct player player;
15
16 int win_width, win_height;
17 float win_aspect;
18 int mouse_x, mouse_y;
19 int bnstate[8];
20
21 float cam_dist;
22 float view_matrix[16], proj_matrix[16];
23
24 unsigned int sdr_foo;
25
26 static long prev_step, prev_turn;
27
28 int game_init(void)
29 {
30         if(init_opengl() == -1) {
31                 return -1;
32         }
33
34         glEnable(GL_DEPTH_TEST);
35         glEnable(GL_CULL_FACE);
36
37         if(!(sdr_foo = create_program_load("sdr/foo.v.glsl", "sdr/foo.p.glsl"))) {
38                 return -1;
39         }
40         glBindAttribLocation(sdr_foo, MESH_ATTR_VERTEX, "apos");
41         glBindAttribLocation(sdr_foo, MESH_ATTR_NORMAL, "anorm");
42         glBindAttribLocation(sdr_foo, MESH_ATTR_TANGENT, "atang");
43         glBindAttribLocation(sdr_foo, MESH_ATTR_TEXCOORD, "atex");
44         link_program(sdr_foo);
45
46         if(load_level(&lvl, "data/test.lvl") == -1) {
47                 return -1;
48         }
49
50         init_player(&player);
51         player.lvl = &lvl;
52         player.cx = lvl.px;
53         player.cy = lvl.py;
54
55         return 0;
56 }
57
58 void game_shutdown(void)
59 {
60         destroy_level(&lvl);
61         free_program(sdr_foo);
62 }
63
64 #define STEP_INTERVAL   250
65 #define TURN_INTERVAL   500
66
67 void update(float dt)
68 {
69         int fwd = 0, right = 0, turn = 0;
70
71         /*
72         cgm_vec3 vdir = {0, 0, -1};
73
74         cgm_vmul_m3v3(&vdir, player.view_xform);
75
76         player.dir = (int)(2.0f * (-atan2(vdir.z, vdir.x) + M_PI) / M_PI + 0.5f) & 3;
77         */
78
79         if(time_msec - prev_turn >= TURN_INTERVAL) {
80                 if(input_state[INP_LTURN]) turn--;
81                 if(input_state[INP_RTURN]) turn++;
82
83                 if(turn) {
84                         turn_player(&player, turn);
85                         prev_turn = time_msec;
86                 }
87         }
88
89         if(time_msec - prev_step >= STEP_INTERVAL) {
90                 if(input_state[INP_FWD]) fwd++;
91                 if(input_state[INP_BACK]) fwd--;
92                 if(input_state[INP_LEFT]) right--;
93                 if(input_state[INP_RIGHT]) right++;
94
95                 if(fwd | right) {
96                         move_player(&player, right, fwd);
97                         prev_step = time_msec;
98                 }
99         }
100
101         upd_player_xform(&player);
102 }
103
104 void game_display(void)
105 {
106         float dt;
107         static long prev_msec;
108
109         dt = (prev_msec - time_msec) / 1000.0f;
110         prev_msec = time_msec;
111
112         update(dt);
113
114         glClearColor(0.1, 0.1, 0.1, 1);
115         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
116
117         cgm_midentity(proj_matrix);
118         cgm_mperspective(proj_matrix, cgm_deg_to_rad(80), win_aspect, 0.5, 500.0);
119         glMatrixMode(GL_PROJECTION);
120         glLoadMatrixf(proj_matrix);
121
122         glMatrixMode(GL_MODELVIEW);
123         glLoadIdentity();
124         glTranslatef(0, 0, -cam_dist);
125         glMultMatrixf(player.view_xform);
126
127         draw_level();
128
129         game_swap_buffers();
130         assert(glGetError() == GL_NO_ERROR);
131 }
132
133 static void draw_level(void)
134 {
135         int i, j, k;
136         struct cell *cell;
137         float xform[16];
138
139         glUseProgram(sdr_foo);
140
141         cell = lvl.cells;
142         for(i=0; i<lvl.height; i++) {
143                 for(j=0; j<lvl.width; j++) {
144                         cgm_mtranslation(xform, j * lvl.cell_size, 0, -i * lvl.cell_size);
145
146                         glPushMatrix();
147                         glMultMatrixf(xform);
148
149                         if(cell->tile) {
150                                 cgm_mrotation_y(xform, cell->tilerot * M_PI / 2.0f);
151
152                                 glPushMatrix();
153                                 glMultMatrixf(xform);
154                                 draw_meshgroup(&cell->tile->mgrp);
155                                 glPopMatrix();
156                         }
157
158                         for(k=0; k<cell->num_mgrp; k++) {
159                                 draw_meshgroup(cell->mgrp + k);
160                         }
161                         cell++;
162
163                         glPopMatrix();
164                 }
165         }
166
167         glUseProgram(0);
168 }
169
170 void game_reshape(int x, int y)
171 {
172         glViewport(0, 0, x, y);
173         win_width = x;
174         win_height = y;
175         win_aspect = (float)x / (float)y;
176 }
177
178 void game_keyboard(int key, int press)
179 {
180         if(press && key == 27) {
181                 game_quit();
182                 return;
183         }
184
185         /* TODO key remapping */
186         switch(key) {
187         case 'w':
188                 input_state[INP_FWD] = press;
189                 if(press) {
190                         move_player(&player, 0, 1);
191                         prev_step = time_msec;
192                 }
193                 break;
194
195         case 'a':
196                 input_state[INP_LEFT] = press;
197                 if(press) {
198                         move_player(&player, -1, 0);
199                         prev_step = time_msec;
200                 }
201                 break;
202
203         case 's':
204                 input_state[INP_BACK] = press;
205                 if(press) {
206                         move_player(&player, 0, -1);
207                         prev_step = time_msec;
208                 }
209                 break;
210
211         case 'd':
212                 input_state[INP_RIGHT] = press;
213                 if(press) {
214                         move_player(&player, 1, 0);
215                         prev_step = time_msec;
216                 }
217                 break;
218
219         case 'q':
220                 input_state[INP_LTURN] = press;
221                 if(press) {
222                         turn_player(&player, -1);
223                         prev_turn = time_msec;
224                         player.dir = (player.dir + 3) & 3;
225                 }
226                 break;
227
228         case 'e':
229                 input_state[INP_RTURN] = press;
230                 if(press) {
231                         turn_player(&player, 1);
232                         prev_turn = time_msec;
233                         player.dir = (player.dir + 1) & 3;
234                 }
235                 break;
236         }
237 }
238
239 void game_mbutton(int bn, int press, int x, int y)
240 {
241         bnstate[bn] = press;
242         mouse_x = x;
243         mouse_y = y;
244 }
245
246 void game_mmotion(int x, int y)
247 {
248         int dx = x - mouse_x;
249         int dy = y - mouse_y;
250         mouse_x = x;
251         mouse_y = y;
252
253         if(!(dx | dy)) return;
254
255         if(bnstate[0]) {
256                 player.theta -= cgm_deg_to_rad(dx * 0.5f);
257                 player.phi -= cgm_deg_to_rad(dy * 0.5f);
258                 if(player.phi < -M_PI/2) player.phi = -M_PI/2;
259                 if(player.phi > M_PI/2) player.phi = M_PI/2;
260         }
261         if(bnstate[2]) {
262                 cam_dist += dy * 0.1;
263                 if(cam_dist < 0) cam_dist = 0;
264         }
265 }