infinite terrain experiments
[shady.git] / shady.cpp
blob391c552741e1bbf0a8bb8c703ba23dd68583e55d
2 #define GL_GLEXT_PROTOTYPES 1
3 extern "C" {
4 #include <GL/gl.h>
5 #include <GL/glext.h>
6 #include <GL/freeglut.h>
7 #include <sys/time.h>
8 #include <unistd.h>
11 // Number of frames to use to calculate average fps.
12 static const int FPS_SMOOTHING = 20;
14 // Safety zone to use when warping the mouse pointer.
15 static const int MOUSE_BORDER = 40;
17 // Uncomment to visualize normals.
18 //#define DRAW_NORMALS
20 #include "shady.hpp"
21 #include "transform.hpp"
22 #include "output.hpp"
23 #include "world.hpp"
24 #include "renderer.hpp"
26 #include <cstdlib>
27 #include <ctime>
29 #include <string>
30 #include <vector>
31 using std::string;
32 using std::vector;
34 #include <cassert>
36 #include <boost/lexical_cast.hpp>
37 using boost::lexical_cast;
39 #include <sstream>
40 using std::stringstream;
42 #include <boost/foreach.hpp>
45 class Shady::_Private {
47 friend class Shady;
49 _Private(const vector<string> & _pps) : renderer(_pps) {
50 posx = posy = 0.0;
51 posz = 1.0;
52 viewx = viewy = viewz = 0.0;
54 radius = 1.0;
55 var = 1.0;
57 warped = false;
60 ~_Private() {
63 Renderer renderer;
65 World world;
67 /**
68 * Move the player x units towards the viewx direction and y units to the right.
70 void movePlayer(float x, float y);
72 // Player position.
73 float posx;
74 float posy;
75 float posz;
77 // View rotation.
78 float viewx;
79 float viewy;
80 float viewz;
82 void renderHud(float tshadow, float tscene, float tpp);
84 GLuint width;
85 GLuint height;
87 float radius;
88 float var;
90 // To be able to tell how much the mouse moved.
91 int mousePosX;
92 int mousePosY;
94 bool warped;
98 Shady::Shady(const vector<string> & pps) : _p(new _Private(pps)) {
101 Shady::~Shady() {
102 delete _p;
105 bool Shady::init() {
107 _p->width = glutGet(GLUT_WINDOW_WIDTH);
108 _p->height = glutGet(GLUT_WINDOW_HEIGHT);
110 if(!_p->renderer.init(_p->width, _p->height)) {
111 ERROR("initializing the rendering system");
112 return false;
115 _p->renderer.resized(_p->width, _p->height);
117 if(!_p->world.init()) {
118 ERROR("initializing the world system");
119 return false;
122 // generate an initial world
123 _p->world.generate();
125 return true;
128 void Shady::resized(int w, int h) {
130 _p->width = w;
131 _p->height = h;
133 _p->renderer.resized(w, h);
137 static void renderBitmapString(float x, float y, void * font, const string & str) {
138 glRasterPos2i(x, y);
139 BOOST_FOREACH(char c, str) {
140 glutBitmapCharacter(font, c);
144 static string toString(float d) {
145 stringstream ss;
146 ss.precision(2);
147 ss.setf(std::ios::fixed, std::ios::floatfield);
148 ss << d;
149 return ss.str();
152 float accurateTime() {
153 timeval t;
154 gettimeofday(&t, 0);
155 return (float)t.tv_sec + (float)t.tv_usec/1000000.0;
158 float timeSinceStart() {
159 static float start = accurateTime();
160 return accurateTime() - start;
163 void Shady::_Private::renderHud(float tshadow, float tscene, float tpp) {
165 tshadow *= 1000;
166 tscene *= 1000;
167 tpp *= 1000;
169 glDisable(GL_DEPTH_TEST);
171 glUseProgram(0);
172 glBindTexture(GL_TEXTURE_2D, 0);
174 glMatrixMode(GL_MODELVIEW);
175 glLoadIdentity();
177 glMatrixMode(GL_PROJECTION);
178 glPushMatrix();
179 glLoadIdentity();
180 glOrtho(0, width, height, 0, -1, 1);
182 //get time and fps
183 static float lasttimes[FPS_SMOOTHING];
184 float now = timeSinceStart();
185 float fps = FPS_SMOOTHING / (now - lasttimes[FPS_SMOOTHING - 1]);
186 for(int i= (FPS_SMOOTHING - 1); i >= 0; i--) {
187 lasttimes[i] = lasttimes[i - 1];
189 lasttimes[0] = now;
191 // Display values.
192 glColor3d(1.0, 1.0, 1.0);
193 const int yo = 15;
194 const int ys = 14;
195 int k = 0;
197 //fix the "posz always 1 on hud" bug
198 //FIXME this whole posz / realposz thing isn't so good
199 float posz = this->posz + world.heightAt(posy, -posx);
201 #define STR(a) # a
202 #define SHOW(var) renderBitmapString(8, yo + (k++ * ys), GLUT_BITMAP_HELVETICA_12, STR(var) "=" + toString(var))
204 SHOW(posx);
205 SHOW(posy);
206 SHOW(posz);
207 SHOW(viewx);
208 SHOW(viewy);
209 SHOW(viewz);
210 SHOW(radius);
211 SHOW(var);
212 SHOW(now);
213 SHOW(fps);
214 SHOW(tshadow);
215 SHOW(tscene);
216 SHOW(tpp);
218 glEnable(GL_DEPTH_TEST);
220 glPopMatrix();
224 void Shady::render() {
226 float t1 = accurateTime();
228 _p->renderer.renderShadowmap(_p->world);
230 float t2 = accurateTime();
232 transform camera = t_rotateZ(r(_p->viewz)) * t_rotateX(r(_p->viewy)) * t_rotateY(r(_p->viewx));
233 camera *= t_translate(vec(-_p->posy, -(_p->posz + _p->world.heightAt(_p->posy, -_p->posx)), _p->posx));
235 _p->renderer.renderScene(camera, _p->world);
237 float t3 = accurateTime();
239 _p->renderer.postprocess(_p->radius, _p->var, timeSinceStart());
241 float t4 = accurateTime();
243 _p->renderHud(t2 - t1, t3 - t2, t4 - t3);
244 checkGl("rendering hud");
248 void Shady::mouseClicked(int button, int state, int x, int y) {
250 // OUT("mouse clicked %d %d at %d,%d", button, state, x, y);
252 if(button == GLUT_LEFT_BUTTON) {
253 if(state == GLUT_DOWN) {
254 _p->mousePosX = x;
255 _p->mousePosY = y;
256 glutSetCursor(GLUT_CURSOR_NONE);
257 } else {
258 assert(state == GLUT_UP);
259 glutSetCursor(GLUT_CURSOR_INHERIT);
265 static float angle(float a) {
266 while(a < -180.0) {
267 a += 360.0;
269 while(a >= 180.0) {
270 a -= 360.0;
272 return a;
275 void Shady::mouseDragged(int x, int y) {
277 // OUT("mouse dragged from %d,%d to %d,%d", _p->mousePosX, _p->mousePosY, x, y);
279 if(_p->warped) {
280 // OUT("ignoring mouse move");
281 _p->warped = false;
282 return;
285 _p->viewx = angle(_p->viewx - (((float)(_p->mousePosX - x)) / 3.0));
287 // Control viewy using arrow keys.
288 _p->viewy = angle(_p->viewy - (((float)(_p->mousePosY - y)) / 3.0));
290 // Keep mouse within the client area while dragging.
291 if(x < MOUSE_BORDER || ((int)(_p->width) - x) < MOUSE_BORDER
292 || y < MOUSE_BORDER || ((int)(_p->height) - y) < MOUSE_BORDER) {
293 int cx = _p->width / 2;
294 int cy = _p->height / 2;
295 // OUT("warping to %d,%d", cx, cy);
296 _p->mousePosX = cx;
297 _p->mousePosY = cy;
298 _p->warped = true;
299 glutWarpPointer(cx, cy);
300 } else {
301 _p->mousePosX = x;
302 _p->mousePosY = y;
307 #define POS_DELTA 0.3
308 #define HEIGHT_DELTA 0.3
309 #define VIEW_DELTA 2
310 #define ZOOM_FACTOR 1.05
312 #define R_DELTA 0.1
313 #define VAR_DELTA 0.1
315 void Shady::normalKeyPressed(unsigned char key, int x, int y) {
317 // OUT("normal key: %c", key);
319 switch(key) {
321 case ' ':
322 _p->world.generate();
323 break;
325 case '\b':
326 _p->viewx = _p->viewy = _p->viewz = 0.0;
327 _p->posx = _p->posy = 0.0;
328 _p->posz = 1.0;
329 break;
331 case 'w':
332 case 'W':
333 _p->movePlayer(POS_DELTA, 0.0);
334 break;
336 case 's':
337 case 'S':
338 _p->movePlayer(-POS_DELTA, 0.0);
339 break;
341 case 'd':
342 case 'D':
343 _p->movePlayer(0.0, POS_DELTA);
344 break;
346 case 'a':
347 case 'A':
348 _p->movePlayer(0.0, -POS_DELTA);
349 break;
351 case 'q':
352 case 'Q':
353 _p->posz -= HEIGHT_DELTA;
354 if(_p->posz < 0.0) {
355 _p->posz = 0.0;
357 break;
359 case 'e':
360 case 'E':
361 _p->posz += HEIGHT_DELTA;
362 break;
364 case '+':
365 case '=':
366 _p->radius += R_DELTA;
367 break;
369 case '-':
370 case '_':
371 _p->radius -= R_DELTA;
372 break;
374 case '*':
375 _p->var += VAR_DELTA;
376 break;
378 case '/':
379 _p->var -= VAR_DELTA;
380 break;
386 void Shady::specialKeyPressed(int key, int x, int y) {
388 // OUT("special key: %d", key);
390 switch(key) {
392 case GLUT_KEY_UP:
393 _p->viewy = angle(_p->viewy + VIEW_DELTA);
394 break;
396 case GLUT_KEY_DOWN:
397 _p->viewy = angle(_p->viewy - VIEW_DELTA);
398 break;
400 case GLUT_KEY_RIGHT:
401 _p->viewz = angle(_p->viewz + VIEW_DELTA);
402 break;
404 case GLUT_KEY_LEFT:
405 _p->viewz = angle(_p->viewz - VIEW_DELTA);
406 break;
412 void Shady::_Private::movePlayer(float dx, float dy) {
414 vec delta(dx, dy, 0.0);
416 delta = t_rotateZ(r(viewx))(delta);
418 this->posx += delta.x;
419 this->posy += delta.y;