/
pgr.cpp
260 lines (223 loc) · 7.42 KB
/
pgr.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*
* LoD terrain generation and displaying
* Svoboda Petr, Vojvoda Jakub
*
* 2014
*
*/
#include "pgr.h"
#include <vector>
#include <fstream>
#include <iterator>
#ifdef _MSC_VER
# pragma comment(lib, "SDL.lib")
# pragma comment(lib, "OpenGL32.lib")
# ifndef USE_GLEE
# pragma comment(lib, "glew32.lib")
# endif //USE_GLEE
#endif //_MSC_VER
// Extern var for camera
extern glm::vec3 camera;
extern glm::vec3 cam_velocity;
// Error handling
const char * getGlErrorString(GLenum error)
{
#define ERROR(e) case e : return #e
switch(error)
{
ERROR(GL_NO_ERROR);
ERROR(GL_INVALID_ENUM);
ERROR(GL_INVALID_VALUE);
ERROR(GL_INVALID_OPERATION);
ERROR(GL_INVALID_FRAMEBUFFER_OPERATION);
ERROR(GL_OUT_OF_MEMORY);
default :
return "UNKNOWN_GL_ERROR";
}
#undef ERROR
}
// Shaders
// Load whole file and return it as std::string
std::string loadFile(const char * const file)
{
std::ifstream stream(file);
if(stream.fail()) throw std::runtime_error(std::string("Can't open \'") + file + "\'");
return std::string(std::istream_iterator<char>(stream >> std::noskipws), std::istream_iterator<char>());
}
// Common shader log code
#ifndef USE_GLEE
std::string getInfoLog(GLuint id, PFNGLGETSHADERIVPROC getLen, PFNGLGETSHADERINFOLOGPROC getLog)
#else
std::string getInfoLog(GLuint id, GLEEPFNGLGETSHADERIVPROC getLen, GLEEPFNGLGETSHADERINFOLOGPROC getLog)
#endif //USE_GLEE
{
assert(getLen != NULL);
assert(getLog != NULL);
GLint length = -1;
getLen(id, GL_INFO_LOG_LENGTH, &length);
assert(length >= 0);
std::vector<GLchar> log(length);
getLog(id, length, NULL, &log[0]);
assert(glGetError() == GL_NO_ERROR);
return std::string(&log[0]);
}
GLuint compileShader(const GLenum type, const char * source)
{
GLuint shader = glCreateShader(type);
if(shader == 0) throw GL_Exception("glCreateShader failed");
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
std::cout << getShaderInfoLog(shader);
int compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if(compileStatus == GL_FALSE) throw std::runtime_error("shader compilation failed");
return shader;
}
GLuint linkShader(size_t count, ...)
{
// Create program object
GLuint program = glCreateProgram();
if(program == 0) throw GL_Exception("glCreateProgram failed");
// Attach arguments
va_list args;
va_start(args, count);
for(size_t i = 0; i < count; ++i)
{
glAttachShader(program, va_arg(args, GLuint));
}
va_end(args);
// Link program and check for errors
glLinkProgram(program);
std::cout << getProgramInfoLog(program);
int linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if(linkStatus == GL_FALSE) throw std::runtime_error("shader linking failed");
return program;
}
void SurfaceImage2D(GLenum target, GLint level, GLint internalformat, SDL_Surface * surface)
{
glPixelStorei(GL_UNPACK_ALIGNMENT,4);
if( (surface->format->Rmask == 0xff0000) &&
(surface->format->Gmask == 0xff00) &&
(surface->format->Bmask == 0xff) &&
(surface->format->Amask == 0))
{
glTexImage2D(target, level, internalformat, surface->w, surface->h, 0, GL_BGR, GL_UNSIGNED_BYTE, surface->pixels);
}
else if((surface->format->Rmask == 0xff) &&
(surface->format->Gmask == 0xff00) &&
(surface->format->Bmask == 0xff0000) &&
(surface->format->Amask == 0))
{
glTexImage2D(target, level, internalformat, surface->w, surface->h, 0, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels);
}
else
{
throw std::runtime_error("unsupported surface format");
}
}
SDL_Surface * init(unsigned width, unsigned height, unsigned color, unsigned depth, unsigned stencil)
{
// Set OpenGL attributes
if(SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, color) < 0) throw SDL_Exception();
if(SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depth) < 0) throw SDL_Exception();
if(SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencil) < 0) throw SDL_Exception();
if(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) < 0) throw SDL_Exception();
// Create window
SDL_Surface * screen = SDL_SetVideoMode(width, height, color, SDL_OPENGL | SDL_RESIZABLE);
if(screen == NULL) throw SDL_Exception();
#ifndef USE_GLEE
// Init extensions
GLenum error = glewInit();
if(error != GLEW_OK)
throw std::runtime_error(std::string("GLEW : Init failed : ") + (const char*)glewGetErrorString(error));
#endif //USE_GLEE
// Call init code
onInit();
onWindowResized(width, height);
return screen;
}
// Simple main loop
void mainLoop()
{
// Window is not minimized
bool active = true;
for(;;)// Infinite loop
{
SDL_Event event;
// Wait for event
if(SDL_WaitEvent(&event) == 0) throw SDL_Exception();
// Screen needs redraw
bool redraw = false;
// Handle all waiting events
do
{
camera += cam_velocity;
// Call proper event handlers
switch(event.type)
{
case SDL_ACTIVEEVENT : // Stop redraw when minimized
if(event.active.state == SDL_APPACTIVE)
active = event.active.gain;
break;
case SDL_KEYDOWN :
onKeyDown(event.key.keysym.sym, event.key.keysym.mod);
break;
case SDL_KEYUP :
onKeyUp(event.key.keysym.sym, event.key.keysym.mod);
break;
case SDL_MOUSEMOTION :
onMouseMove(event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel, event.motion.state);
break;
case SDL_MOUSEBUTTONDOWN :
onMouseDown(event.button.button, event.button.x, event.button.y);
break;
case SDL_MOUSEBUTTONUP :
onMouseUp(event.button.button, event.button.x, event.button.y);
break;
case SDL_QUIT :
return; // End main loop
case SDL_VIDEORESIZE :
onWindowResized(event.resize.w, event.resize.h);
break;
case SDL_VIDEOEXPOSE :
redraw = true;
break;
default : // Do nothing
break;
}
} while(SDL_PollEvent(&event) == 1);
// Optionally redraw window
if(active && redraw) onWindowRedraw();
}
}
// Animation main loop
// period - maximum time between redraws in ms
void mainLoop(unsigned period)
{
// This main loop requires timer support
if(SDL_InitSubSystem(SDL_INIT_TIMER) < 0) throw SDL_Exception();
// Create redraw timer
class RedrawTimer
{
private :
SDL_TimerID id;
static Uint32 callback(Uint32 interval, void *)
{
redraw();
return interval;
}
public :
RedrawTimer(unsigned interval)
: id(SDL_AddTimer(interval, callback, NULL))
{
if(id == NULL) throw SDL_Exception();
}
~RedrawTimer()
{
if(id != NULL) SDL_RemoveTimer(id);
}
} redrawTimer(period);
// Start simple main loop
mainLoop();
}