wall noise and arbitrary render resolution option
[raydungeon] / src / scr_game.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include "opengl.h"
5 #include "cgmath/cgmath.h"
6 #include "game.h"
7 #include "sdr.h"
8 #include "level.h"
9 #include "util.h"
10 #include "options.h"
11
12 static int ginit(void);
13 static void gdestroy(void);
14 static int gstart(void);
15 static void gstop(void);
16 static void gdisplay(void);
17 static void greshape(int x, int y);
18 static void gkeyb(int key, int press);
19 static void gmouse(int bn, int press, int x, int y);
20 static void gmotion(int x, int y);
21
22 struct game_screen scr_game = {
23         "game",
24         ginit, gdestroy,
25         gstart, gstop,
26         gdisplay, greshape,
27         gkeyb, gmouse, gmotion
28 };
29
30 static struct level *lvl;
31
32 static float proj_mat[16], view_mat[16];
33
34 static float cam_theta, cam_phi, cam_dist;
35 static cgm_vec3 cam_pan;
36
37 static unsigned int sdr;
38
39 static int rbuf_width, rbuf_height;
40 static unsigned int fbo, rbuf_col, rbuf_zbuf;
41
42
43 static int ginit(void)
44 {
45         return 0;
46 }
47
48 static void gdestroy(void)
49 {
50         glDeleteRenderbuffers(1, &rbuf_col);
51         glDeleteRenderbuffers(1, &rbuf_zbuf);
52         glDeleteFramebuffers(1, &fbo);
53 }
54
55 static int gstart(void)
56 {
57         lvl = malloc_nf(sizeof *lvl);
58         init_level(lvl);
59         if(load_level(lvl, "data/test.lvl") == -1) {
60                 return -1;
61         }
62         cam_pan.x = -lvl->sx * lvl->scale;
63         cam_pan.y = 0;
64         cam_pan.z = -lvl->sy * lvl->scale;
65
66         glEnable(GL_DEPTH_TEST);
67
68         if(lvl->sdf_src) {
69                 add_shader_footer(GL_FRAGMENT_SHADER, lvl->sdf_src);
70         } else {
71                 add_shader_header(GL_FRAGMENT_SHADER, "#define TEST_SDF\n");
72         }
73         if(!(sdr = create_program_load("sdr/raydungeon.v.glsl", "sdr/raydungeon.p.glsl"))) {
74                 return -1;
75         }
76         clear_shader_footer(GL_FRAGMENT_SHADER);
77         glUseProgram(sdr);
78         return 0;
79 }
80
81 static void gstop(void)
82 {
83         destroy_level(lvl);
84         free(lvl);
85
86         free_program(sdr);
87 }
88
89 static void gdisplay(void)
90 {
91         int i, j;
92         float x, y;
93         struct level_cell *cell;
94
95         glBindFramebuffer(GL_FRAMEBUFFER, fbo);
96         glViewport(0, 0, rbuf_width, rbuf_height);
97
98         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
99
100         cgm_mtranslation(view_mat, 0, 0, -cam_dist);
101         cgm_mprerotate_x(view_mat, cam_phi);
102         cgm_mprerotate_y(view_mat, cam_theta);
103         cgm_mpretranslate(view_mat, cam_pan.x, cam_pan.y, cam_pan.z);
104         glMatrixMode(GL_MODELVIEW);
105         glLoadMatrixf(view_mat);
106
107         glUseProgram(sdr);
108
109         glBegin(GL_TRIANGLES);
110         glTexCoord2f(0, 0); glVertex2f(-1, -1);
111         glTexCoord2f(2, 0); glVertex2f(3, -1);
112         glTexCoord2f(0, 2); glVertex2f(-1, 3);
113         glEnd();
114
115         glUseProgram(0);
116
117
118         cell = lvl->cells;
119         glBegin(GL_QUADS);
120         glColor3f(1, 1, 1);
121         glNormal3f(0, 1, 0);
122         for(i=0; i<lvl->ysz; i++) {
123                 y = (float)i * lvl->scale;
124                 for(j=0; j<lvl->xsz; j++) {
125                         x = (float)j * lvl->scale;
126                         if(cell->type) {
127                                 glVertex3f(x - 0.48 * lvl->scale, -1, y - 0.48 * lvl->scale);
128                                 glVertex3f(x + 0.48 * lvl->scale, -1, y - 0.48 * lvl->scale);
129                                 glVertex3f(x + 0.48 * lvl->scale, -1, y + 0.48 * lvl->scale);
130                                 glVertex3f(x - 0.48 * lvl->scale, -1, y + 0.48 * lvl->scale);
131                         }
132                         cell++;
133                 }
134         }
135         glEnd();
136
137         glViewport(0, 0, win_width, win_height);
138         glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
139         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
140         glBlitFramebuffer(0, 0, rbuf_width, rbuf_height, 0, 0, win_width, win_height,
141                         GL_COLOR_BUFFER_BIT, GL_NEAREST);
142         glBindFramebuffer(GL_FRAMEBUFFER, 0);
143 }
144
145 static void greshape(int x, int y)
146 {
147         cgm_mperspective(proj_mat, cgm_deg_to_rad(60), win_aspect, 0.5, 200.0);
148         glMatrixMode(GL_PROJECTION);
149         glLoadMatrixf(proj_mat);
150
151         rbuf_width = ((int)(x * opt.gfx.render_res) + 3) & 0xfffffc;
152         rbuf_height = ((int)(y * opt.gfx.render_res) + 3) & 0xfffffc;
153         printf("render buffer %dx%d\n", rbuf_width, rbuf_height);
154
155         if(!fbo) {
156                 glGenFramebuffers(1, &fbo);
157                 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
158
159                 glGenRenderbuffers(1, &rbuf_col);
160                 glBindRenderbuffer(GL_RENDERBUFFER, rbuf_col);
161                 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, rbuf_width, rbuf_height);
162                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbuf_col);
163
164                 glGenRenderbuffers(1, &rbuf_zbuf);
165                 glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zbuf);
166                 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rbuf_width, rbuf_height);
167                 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbuf_zbuf);
168
169                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
170         } else {
171                 glBindRenderbuffer(GL_RENDERBUFFER, rbuf_col);
172                 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, rbuf_width, rbuf_height);
173
174                 glBindRenderbuffer(GL_RENDERBUFFER, rbuf_zbuf);
175                 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rbuf_width, rbuf_height);
176         }
177 }
178
179 static void gkeyb(int key, int press)
180 {
181         if(press) {
182                 switch(key) {
183                 case '`':
184                         if(!fullscr) {
185                                 game_grabmouse(-1);     /* toggle */
186                         }
187                         break;
188
189                 default:
190                         break;
191                 }
192         }
193 }
194
195 static void gmouse(int bn, int press, int x, int y)
196 {
197 }
198
199 static void gmotion(int x, int y)
200 {
201         int dx = x - mouse_x;
202         int dy = y - mouse_y;
203
204         if(!(dx | dy)) return;
205
206         if(mouse_state[0]) {
207                 cam_theta += dx * 0.02;
208                 cam_phi += dy * 0.02;
209                 if(cam_phi < -M_PI/2) cam_phi = -M_PI/2;
210                 if(cam_phi > M_PI/2) cam_phi = M_PI/2;
211         }
212         if(mouse_state[1]) {
213                 float up[3], right[3];
214
215                 up[0] = -sin(cam_theta) * sin(cam_phi);
216                 up[1] = -cos(cam_phi);
217                 up[2] = cos(cam_theta) * sin(cam_phi);
218                 right[0] = cos(cam_theta);
219                 right[1] = 0;
220                 right[2] = sin(cam_theta);
221
222                 cam_pan.x += (right[0] * dx + up[0] * dy) * 0.01;
223                 cam_pan.y += up[1] * dy * 0.01;
224                 cam_pan.z += (right[2] * dx + up[2] * dy) * 0.01;
225         }
226         if(mouse_state[2]) {
227                 cam_dist += dy * 0.01;
228                 if(cam_dist < 0) cam_dist = 0;
229         }
230 }