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