2 #define GL_GLEXT_PROTOTYPES 1
6 #include <GL/freeglut.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
21 #include "transform.hpp"
24 #include "renderer.hpp"
36 #include <boost/lexical_cast.hpp>
37 using boost::lexical_cast
;
40 using std::stringstream
;
42 #include <boost/foreach.hpp>
45 class Shady::_Private
{
49 _Private(const vector
<string
> & _pps
) : renderer(_pps
) {
52 viewx
= viewy
= viewz
= 0.0;
68 * Move the player x units towards the viewx direction and y units to the right.
70 void movePlayer(float x
, float y
);
82 void renderHud(float tshadow
, float tscene
, float tpp
);
90 // To be able to tell how much the mouse moved.
98 Shady::Shady(const vector
<string
> & pps
) : _p(new _Private(pps
)) {
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");
115 _p
->renderer
.resized(_p
->width
, _p
->height
);
117 if(!_p
->world
.init()) {
118 ERROR("initializing the world system");
122 // generate an initial world
123 _p
->world
.generate();
128 void Shady::resized(int w
, int h
) {
133 _p
->renderer
.resized(w
, h
);
137 static void renderBitmapString(float x
, float y
, void * font
, const string
& str
) {
139 BOOST_FOREACH(char c
, str
) {
140 glutBitmapCharacter(font
, c
);
144 static string
toString(float d
) {
147 ss
.setf(std::ios::fixed
, std::ios::floatfield
);
152 float accurateTime() {
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
) {
169 glDisable(GL_DEPTH_TEST
);
172 glBindTexture(GL_TEXTURE_2D
, 0);
174 glMatrixMode(GL_MODELVIEW
);
177 glMatrixMode(GL_PROJECTION
);
180 glOrtho(0, width
, height
, 0, -1, 1);
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];
192 glColor3d(1.0, 1.0, 1.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
);
202 #define SHOW(var) renderBitmapString(8, yo + (k++ * ys), GLUT_BITMAP_HELVETICA_12, STR(var) "=" + toString(var))
218 glEnable(GL_DEPTH_TEST
);
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
) {
256 glutSetCursor(GLUT_CURSOR_NONE
);
258 assert(state
== GLUT_UP
);
259 glutSetCursor(GLUT_CURSOR_INHERIT
);
265 static float angle(float 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);
280 // OUT("ignoring mouse move");
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);
299 glutWarpPointer(cx
, cy
);
307 #define POS_DELTA 0.3
308 #define HEIGHT_DELTA 0.3
310 #define ZOOM_FACTOR 1.05
313 #define VAR_DELTA 0.1
315 void Shady::normalKeyPressed(unsigned char key
, int x
, int y
) {
317 // OUT("normal key: %c", key);
322 _p
->world
.generate();
326 _p
->viewx
= _p
->viewy
= _p
->viewz
= 0.0;
327 _p
->posx
= _p
->posy
= 0.0;
333 _p
->movePlayer(POS_DELTA
, 0.0);
338 _p
->movePlayer(-POS_DELTA
, 0.0);
343 _p
->movePlayer(0.0, POS_DELTA
);
348 _p
->movePlayer(0.0, -POS_DELTA
);
353 _p
->posz
-= HEIGHT_DELTA
;
361 _p
->posz
+= HEIGHT_DELTA
;
366 _p
->radius
+= R_DELTA
;
371 _p
->radius
-= R_DELTA
;
375 _p
->var
+= VAR_DELTA
;
379 _p
->var
-= VAR_DELTA
;
386 void Shady::specialKeyPressed(int key
, int x
, int y
) {
388 // OUT("special key: %d", key);
393 _p
->viewy
= angle(_p
->viewy
+ VIEW_DELTA
);
397 _p
->viewy
= angle(_p
->viewy
- VIEW_DELTA
);
401 _p
->viewz
= angle(_p
->viewz
+ VIEW_DELTA
);
405 _p
->viewz
= angle(_p
->viewz
- VIEW_DELTA
);
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
;