1 //
2 // Copyright (C) 2009 Nick Gasson
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 //
17
18 #include <GL/glew.h> // Must be included before other GL headers
19
20 #include "OpenGLHelper.hpp"
21 #include "ILogger.hpp"
22 #include "IConfig.hpp"
23
24 #include <stdexcept>
25
26 #include <GL/gl.h>
27 #include <GL/glu.h>
28
29 #include <boost/lexical_cast.hpp>
30
checkGLError()31 void checkGLError()
32 {
33 using namespace boost;
34
35 GLenum error = glGetError();
36 if (error != GL_NO_ERROR) {
37 throw runtime_error
38 ("OpenGL error: " + lexical_cast<string>(gluErrorString(error)));
39 }
40 }
41
drawGLScene(IWindowPtr a_window,IGraphicsPtr a_context,IScreenPtr a_screen)42 void drawGLScene(IWindowPtr a_window, IGraphicsPtr a_context, IScreenPtr a_screen)
43 {
44 using namespace boost;
45
46 // Set up for 3D mode
47 glMatrixMode(GL_PROJECTION);
48 glLoadIdentity();
49
50 const int w = a_window->width();
51 const int h = a_window->height();
52
53 IConfigPtr cfg = get_config();
54 gluPerspective(45.0f, (GLfloat)w/(GLfloat)h,
55 cfg->get<float>("NearClip"),
56 cfg->get<float>("FarClip"));
57
58 glMatrixMode(GL_MODELVIEW);
59 glLoadIdentity();
60
61 // Set default state
62 glEnable(GL_DEPTH_TEST);
63 glEnable(GL_TEXTURE_2D);
64 glEnable(GL_CULL_FACE);
65
66 glEnable(GL_LIGHTING);
67 glEnable(GL_LIGHT0);
68
69 // Clear the screen
70 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
71 glLoadIdentity();
72
73 // Draw the 3D part
74 a_screen->display(a_context);
75
76 // Set up for 2D
77 glMatrixMode(GL_PROJECTION);
78 glLoadIdentity();
79 gluOrtho2D(0.0f, (GLfloat)w, (GLfloat)h, 0.0f);
80 glMatrixMode(GL_MODELVIEW);
81 glLoadIdentity();
82
83 // Set 2D defaults
84 glDisable(GL_LIGHTING);
85 glDisable(GL_DEPTH_TEST);
86 glEnable(GL_BLEND);
87 glDisable(GL_TEXTURE_2D);
88 glDisable(GL_CULL_FACE);
89
90 // Draw the 2D part
91 a_screen->overlay();
92
93 // Check for OpenGL errors
94 checkGLError();
95 }
96
97 // Report the current OpenGL version
printGLVersion()98 void printGLVersion()
99 {
100 log() << "OpenGL version: " << glGetString(GL_VERSION);
101 log() << "GLEW version: " << glewGetString(GLEW_VERSION);
102 }
103
104 // Set initial OpenGL options
initGL()105 void initGL()
106 {
107 using namespace boost;
108
109 glShadeModel(GL_SMOOTH);
110 glClearDepth(1.0f);
111 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
112 glDepthFunc(GL_LEQUAL);
113 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
114
115 // Clear to the sky colour
116 //glClear_color(0.6f, 0.7f, 0.8f, 1.0f);
117 glClearColor(176.0f/255.0f, 196.0f/255.0f, 222.0f/255.0f, 1.0f);
118
119 // Check for OpenGL extensions
120 GLenum err = glewInit();
121 if (err != GLEW_OK)
122 throw runtime_error("GLEW initialisation failed: "
123 + lexical_cast<string>(glewGetErrorString(err)));
124
125 }
126
127 // Set the current viewport
resizeGLScene(IWindowPtr a_window)128 void resizeGLScene(IWindowPtr a_window)
129 {
130 glViewport(0, 0, a_window->width(), a_window->height());
131 }
132
begin_pick(IWindowPtr a_window,unsigned * a_buffer,int x,int y)133 void begin_pick(IWindowPtr a_window, unsigned* a_buffer, int x, int y)
134 {
135 // Set up selection buffer
136 glSelectBuffer(128, a_buffer);
137
138 // Get viewport coordinates
139 GLint viewport_coords[4];
140 glGetIntegerv(GL_VIEWPORT, viewport_coords);
141
142 // Switch to projection matrix
143 glMatrixMode(GL_PROJECTION);
144 glPushMatrix();
145
146 // Render the objects, but don't change the frame buffer
147 glRenderMode(GL_SELECT);
148 glLoadIdentity();
149
150 // Set picking matrix
151 gluPickMatrix(x, viewport_coords[3] - y, 2, 2, viewport_coords);
152
153 // Just set the perspective
154 IConfigPtr cfg = get_config();
155 gluPerspective(45.0f, (GLfloat)(a_window->width())/(GLfloat)(a_window->height()),
156 cfg->get<float>("NearClip"),
157 cfg->get<float>("FarClip"));
158
159 glMatrixMode(GL_MODELVIEW);
160 glInitNames();
161
162 // Let the user render their stuff
163 glLoadIdentity();
164 }
165
end_pick(unsigned * a_buffer)166 unsigned end_pick(unsigned* a_buffer)
167 {
168 int objects_found = glRenderMode(GL_RENDER);
169
170 // Go back to normal
171 glMatrixMode(GL_PROJECTION);
172 glPopMatrix();
173 glMatrixMode(GL_MODELVIEW);
174
175 // See if we found any objects
176 if (objects_found > 0) {
177 // Find the object with the lowest depth
178 unsigned int lowest_depth = a_buffer[1];
179 int selected_object = a_buffer[3];
180
181 // Go through all the objects found
182 for (int i = 1; i < objects_found; i++) {
183 // See if it's closer than the current nearest
184 if (a_buffer[(i*4) + 1] < lowest_depth) { // 4 values for each object
185 lowest_depth = a_buffer[(i * 4) + 1];
186 selected_object = a_buffer[(i * 4) + 3];
187 }
188 }
189
190 // Return closest object
191 return selected_object;
192 }
193 else
194 return 0;
195 }
196