1
2////////////////////////////////////////////////////////////
3// Headers
4////////////////////////////////////////////////////////////
5#include <SFML/Graphics.hpp>
6
7#define GLAD_GL_IMPLEMENTATION
8#include "gl.h"
9
10#ifdef SFML_SYSTEM_IOS
11#include <SFML/Main.hpp>
12#endif
13
14#ifndef GL_SRGB8_ALPHA8
15#define GL_SRGB8_ALPHA8 0x8C43
16#endif
17
18std::string resourcesDir()
19{
20#ifdef SFML_SYSTEM_IOS
21 return "";
22#else
23 return "resources/";
24#endif
25}
26
27////////////////////////////////////////////////////////////
28/// Entry point of application
29///
30/// \return Application exit code
31///
32////////////////////////////////////////////////////////////
33int main()
34{
35 bool exit = false;
36 bool sRgb = false;
37
38 while (!exit)
39 {
40 // Request a 24-bits depth buffer when creating the window
41 sf::ContextSettings contextSettings;
42 contextSettings.depthBits = 24;
43 contextSettings.sRgbCapable = sRgb;
44
45 // Create the main window
46 sf::RenderWindow window(sf::VideoMode(800, 600), "SFML graphics with OpenGL", sf::Style::Default, contextSettings);
47 window.setVerticalSyncEnabled(true);
48
49 // Create a sprite for the background
50 sf::Texture backgroundTexture;
51 backgroundTexture.setSrgb(sRgb);
52 if (!backgroundTexture.loadFromFile(resourcesDir() + "background.jpg"))
53 return EXIT_FAILURE;
54 sf::Sprite background(backgroundTexture);
55
56 // Create some text to draw on top of our OpenGL object
57 sf::Font font;
58 if (!font.loadFromFile(resourcesDir() + "sansation.ttf"))
59 return EXIT_FAILURE;
60 sf::Text text("SFML / OpenGL demo", font);
61 sf::Text sRgbInstructions("Press space to toggle sRGB conversion", font);
62 sf::Text mipmapInstructions("Press return to toggle mipmapping", font);
63 text.setFillColor(sf::Color(255, 255, 255, 170));
64 sRgbInstructions.setFillColor(sf::Color(255, 255, 255, 170));
65 mipmapInstructions.setFillColor(sf::Color(255, 255, 255, 170));
66 text.setPosition(250.f, 450.f);
67 sRgbInstructions.setPosition(150.f, 500.f);
68 mipmapInstructions.setPosition(180.f, 550.f);
69
70 // Load a texture to apply to our 3D cube
71 sf::Texture texture;
72 if (!texture.loadFromFile(resourcesDir() + "texture.jpg"))
73 return EXIT_FAILURE;
74
75 // Attempt to generate a mipmap for our cube texture
76 // We don't check the return value here since
77 // mipmapping is purely optional in this example
78 texture.generateMipmap();
79
80 // Make the window the active window for OpenGL calls
81 window.setActive(true);
82
83 // Load OpenGL or OpenGL ES entry points using glad
84#ifdef SFML_OPENGL_ES
85 gladLoadGLES1(reinterpret_cast<GLADloadfunc>(sf::Context::getFunction));
86#else
87 gladLoadGL(reinterpret_cast<GLADloadfunc>(sf::Context::getFunction));
88#endif
89
90 // Enable Z-buffer read and write
91 glEnable(GL_DEPTH_TEST);
92 glDepthMask(GL_TRUE);
93#ifdef SFML_OPENGL_ES
94 glClearDepthf(1.f);
95#else
96 glClearDepth(1.f);
97#endif
98
99 // Disable lighting
100 glDisable(GL_LIGHTING);
101
102 // Configure the viewport (the same size as the window)
103 glViewport(0, 0, window.getSize().x, window.getSize().y);
104
105 // Setup a perspective projection
106 glMatrixMode(GL_PROJECTION);
107 glLoadIdentity();
108 GLfloat ratio = static_cast<float>(window.getSize().x) / window.getSize().y;
109#ifdef SFML_OPENGL_ES
110 glFrustumf(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
111#else
112 glFrustum(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
113#endif
114
115 // Bind the texture
116 glEnable(GL_TEXTURE_2D);
117 sf::Texture::bind(&texture);
118
119 // Define a 3D cube (6 faces made of 2 triangles composed by 3 vertices)
120 static const GLfloat cube[] =
121 {
122 // positions // texture coordinates
123 -20, -20, -20, 0, 0,
124 -20, 20, -20, 1, 0,
125 -20, -20, 20, 0, 1,
126 -20, -20, 20, 0, 1,
127 -20, 20, -20, 1, 0,
128 -20, 20, 20, 1, 1,
129
130 20, -20, -20, 0, 0,
131 20, 20, -20, 1, 0,
132 20, -20, 20, 0, 1,
133 20, -20, 20, 0, 1,
134 20, 20, -20, 1, 0,
135 20, 20, 20, 1, 1,
136
137 -20, -20, -20, 0, 0,
138 20, -20, -20, 1, 0,
139 -20, -20, 20, 0, 1,
140 -20, -20, 20, 0, 1,
141 20, -20, -20, 1, 0,
142 20, -20, 20, 1, 1,
143
144 -20, 20, -20, 0, 0,
145 20, 20, -20, 1, 0,
146 -20, 20, 20, 0, 1,
147 -20, 20, 20, 0, 1,
148 20, 20, -20, 1, 0,
149 20, 20, 20, 1, 1,
150
151 -20, -20, -20, 0, 0,
152 20, -20, -20, 1, 0,
153 -20, 20, -20, 0, 1,
154 -20, 20, -20, 0, 1,
155 20, -20, -20, 1, 0,
156 20, 20, -20, 1, 1,
157
158 -20, -20, 20, 0, 0,
159 20, -20, 20, 1, 0,
160 -20, 20, 20, 0, 1,
161 -20, 20, 20, 0, 1,
162 20, -20, 20, 1, 0,
163 20, 20, 20, 1, 1
164 };
165
166 // Enable position and texture coordinates vertex components
167 glEnableClientState(GL_VERTEX_ARRAY);
168 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
169 glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), cube);
170 glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), cube + 3);
171
172 // Disable normal and color vertex components
173 glDisableClientState(GL_NORMAL_ARRAY);
174 glDisableClientState(GL_COLOR_ARRAY);
175
176 // Make the window no longer the active window for OpenGL calls
177 window.setActive(false);
178
179 // Create a clock for measuring the time elapsed
180 sf::Clock clock;
181
182 // Flag to track whether mipmapping is currently enabled
183 bool mipmapEnabled = true;
184
185 // Start game loop
186 while (window.isOpen())
187 {
188 // Process events
189 sf::Event event;
190 while (window.pollEvent(event))
191 {
192 // Close window: exit
193 if (event.type == sf::Event::Closed)
194 {
195 exit = true;
196 window.close();
197 }
198
199 // Escape key: exit
200 if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
201 {
202 exit = true;
203 window.close();
204 }
205
206 // Return key: toggle mipmapping
207 if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Enter))
208 {
209 if (mipmapEnabled)
210 {
211 // We simply reload the texture to disable mipmapping
212 if (!texture.loadFromFile(resourcesDir() + "texture.jpg"))
213 return EXIT_FAILURE;
214
215 mipmapEnabled = false;
216 }
217 else
218 {
219 texture.generateMipmap();
220
221 mipmapEnabled = true;
222 }
223 }
224
225 // Space key: toggle sRGB conversion
226 if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space))
227 {
228 sRgb = !sRgb;
229 window.close();
230 }
231
232 // Adjust the viewport when the window is resized
233 if (event.type == sf::Event::Resized)
234 {
235 sf::Vector2u textureSize = backgroundTexture.getSize();
236
237 // Make the window the active window for OpenGL calls
238 window.setActive(true);
239
240 glViewport(0, 0, event.size.width, event.size.height);
241 glMatrixMode(GL_PROJECTION);
242 glLoadIdentity();
243 GLfloat ratio = static_cast<float>(event.size.width) / event.size.height;
244#ifdef SFML_OPENGL_ES
245 glFrustumf(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
246#else
247 glFrustum(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
248#endif
249
250 // Make the window no longer the active window for OpenGL calls
251 window.setActive(false);
252
253 sf::View view;
254 view.setSize(textureSize.x, textureSize.y);
255 view.setCenter(textureSize.x/2.f, textureSize.y/2.f);
256 window.setView(view);
257 }
258 }
259
260 // Draw the background
261 window.pushGLStates();
262 window.draw(background);
263 window.popGLStates();
264
265 // Make the window the active window for OpenGL calls
266 window.setActive(true);
267
268 // Clear the depth buffer
269 glClear(GL_DEPTH_BUFFER_BIT);
270
271 // We get the position of the mouse cursor (or touch), so that we can move the box accordingly
272 sf::Vector2i pos;
273
274 #ifdef SFML_SYSTEM_IOS
275 pos = sf::Touch::getPosition(0);
276 #else
277 pos = sf::Mouse::getPosition();
278 #endif
279
280 float x = pos.x * 200.f / window.getSize().x - 100.f;
281 float y = -pos.y * 200.f / window.getSize().y + 100.f;
282
283 // Apply some transformations
284 glMatrixMode(GL_MODELVIEW);
285 glLoadIdentity();
286 glTranslatef(x, y, -100.f);
287 glRotatef(clock.getElapsedTime().asSeconds() * 50.f, 1.f, 0.f, 0.f);
288 glRotatef(clock.getElapsedTime().asSeconds() * 30.f, 0.f, 1.f, 0.f);
289 glRotatef(clock.getElapsedTime().asSeconds() * 90.f, 0.f, 0.f, 1.f);
290
291 // Draw the cube
292 glDrawArrays(GL_TRIANGLES, 0, 36);
293
294 // Make the window no longer the active window for OpenGL calls
295 window.setActive(false);
296
297 // Draw some text on top of our OpenGL object
298 window.pushGLStates();
299 window.draw(text);
300 window.draw(sRgbInstructions);
301 window.draw(mipmapInstructions);
302 window.popGLStates();
303
304 // Finally, display the rendered frame on screen
305 window.display();
306 }
307 }
308
309 return EXIT_SUCCESS;
310}
311