visibility determination
[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         if(time_msec - prev_turn >= TURN_INTERVAL) {
72                 if(input_state[INP_LTURN]) turn--;
73                 if(input_state[INP_RTURN]) turn++;
74
75                 if(turn) {
76                         turn_player(&player, turn);
77                         prev_turn = time_msec;
78                 }
79         }
80
81         if(time_msec - prev_step >= STEP_INTERVAL) {
82                 if(input_state[INP_FWD]) fwd++;
83                 if(input_state[INP_BACK]) fwd--;
84                 if(input_state[INP_LEFT]) right--;
85                 if(input_state[INP_RIGHT]) right++;
86
87                 if(fwd | right) {
88                         move_player(&player, right, fwd);
89                         prev_step = time_msec;
90                 }
91         }
92
93         upd_player_xform(&player);
94 }
95
96 void game_display(void)
97 {
98         float dt;
99         static long prev_msec;
100
101         dt = (prev_msec - time_msec) / 1000.0f;
102         prev_msec = time_msec;
103
104         update(dt);
105
106         glClearColor(0.1, 0.1, 0.1, 1);
107         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
108
109         cgm_midentity(proj_matrix);
110         cgm_mperspective(proj_matrix, cgm_deg_to_rad(80), win_aspect, 0.5, 500.0);
111         glMatrixMode(GL_PROJECTION);
112         glLoadMatrixf(proj_matrix);
113
114         glMatrixMode(GL_MODELVIEW);
115         glLoadIdentity();
116         glTranslatef(0, 0, -cam_dist);
117         glMultMatrixf(player.view_xform);
118
119         draw_level();
120
121         game_swap_buffers();
122         assert(glGetError() == GL_NO_ERROR);
123 }
124
125 static void draw_level(void)
126 {
127         int i;
128         struct cell *cell;
129         float xform[16];
130
131         glUseProgram(sdr_foo);
132
133         if(!player.vis) {
134                 upd_player_vis(&player);
135         }
136
137         cell = player.vis;
138         while(cell) {
139                 cgm_mtranslation(xform, cell->x * lvl.cell_size, 0, -cell->y * lvl.cell_size);
140
141                 glPushMatrix();
142                 glMultMatrixf(xform);
143
144                 if(cell->tile) {
145                         cgm_mrotation_y(xform, cell->tilerot * M_PI / 2.0f);
146
147                         glPushMatrix();
148                         glMultMatrixf(xform);
149                         draw_meshgroup(&cell->tile->mgrp);
150                         glPopMatrix();
151                 }
152
153                 for(i=0; i<cell->num_mgrp; i++) {
154                         draw_meshgroup(cell->mgrp + i);
155                 }
156                 glPopMatrix();
157
158                 cell = cell->next;
159         }
160
161         glUseProgram(0);
162 }
163
164 void game_reshape(int x, int y)
165 {
166         glViewport(0, 0, x, y);
167         win_width = x;
168         win_height = y;
169         win_aspect = (float)x / (float)y;
170 }
171
172 void game_keyboard(int key, int press)
173 {
174         if(press && key == 27) {
175                 game_quit();
176                 return;
177         }
178
179         /* TODO key remapping */
180         switch(key) {
181         case 'w':
182                 input_state[INP_FWD] = press;
183                 if(press) {
184                         move_player(&player, 0, 1);
185                         prev_step = time_msec;
186                 }
187                 break;
188
189         case 'a':
190                 input_state[INP_LEFT] = press;
191                 if(press) {
192                         move_player(&player, -1, 0);
193                         prev_step = time_msec;
194                 }
195                 break;
196
197         case 's':
198                 input_state[INP_BACK] = press;
199                 if(press) {
200                         move_player(&player, 0, -1);
201                         prev_step = time_msec;
202                 }
203                 break;
204
205         case 'd':
206                 input_state[INP_RIGHT] = press;
207                 if(press) {
208                         move_player(&player, 1, 0);
209                         prev_step = time_msec;
210                 }
211                 break;
212
213         case 'q':
214                 input_state[INP_LTURN] = press;
215                 if(press) {
216                         turn_player(&player, -1);
217                         prev_turn = time_msec;
218                 }
219                 break;
220
221         case 'e':
222                 input_state[INP_RTURN] = press;
223                 if(press) {
224                         turn_player(&player, 1);
225                         prev_turn = time_msec;
226                 }
227                 break;
228         }
229 }
230
231 void game_mbutton(int bn, int press, int x, int y)
232 {
233         bnstate[bn] = press;
234         mouse_x = x;
235         mouse_y = y;
236 }
237
238 void game_mmotion(int x, int y)
239 {
240         int dx = x - mouse_x;
241         int dy = y - mouse_y;
242         mouse_x = x;
243         mouse_y = y;
244
245         if(!(dx | dy)) return;
246
247         if(bnstate[0]) {
248                 player.theta += cgm_deg_to_rad(dx * 0.5f);
249                 player.phi -= cgm_deg_to_rad(dy * 0.5f);
250                 if(player.phi < -M_PI/2) player.phi = -M_PI/2;
251                 if(player.phi > M_PI/2) player.phi = M_PI/2;
252         }
253         if(bnstate[2]) {
254                 cam_dist += dy * 0.1;
255                 if(cam_dist < 0) cam_dist = 0;
256         }
257 }