Add support for sRGB capable framebuffers. (#175)

This commit is contained in:
binary1248 2015-10-01 10:13:16 +02:00 committed by Lukas Dürrenberger
parent c4956857fa
commit e00d160224
19 changed files with 437 additions and 183 deletions

View File

@ -5,6 +5,10 @@
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#ifndef GL_SRGB8_ALPHA8
#define GL_SRGB8_ALPHA8 0x8C43
#endif
////////////////////////////////////////////////////////////
/// Entry point of application
@ -14,178 +18,203 @@
////////////////////////////////////////////////////////////
int main()
{
// Request a 24-bits depth buffer when creating the window
sf::ContextSettings contextSettings;
contextSettings.depthBits = 24;
bool exit = false;
bool sRgb = false;
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML graphics with OpenGL", sf::Style::Default, contextSettings);
window.setVerticalSyncEnabled(true);
// Create a sprite for the background
sf::Texture backgroundTexture;
if (!backgroundTexture.loadFromFile("resources/background.jpg"))
return EXIT_FAILURE;
sf::Sprite background(backgroundTexture);
// Create some text to draw on top of our OpenGL object
sf::Font font;
if (!font.loadFromFile("resources/sansation.ttf"))
return EXIT_FAILURE;
sf::Text text("SFML / OpenGL demo", font);
text.setColor(sf::Color(255, 255, 255, 170));
text.setPosition(250.f, 450.f);
// Load an OpenGL texture.
// We could directly use a sf::Texture as an OpenGL texture (with its Bind() member function),
// but here we want more control on it (generate mipmaps, ...) so we create a new one from an image
GLuint texture = 0;
while(!exit)
{
sf::Image image;
if (!image.loadFromFile("resources/texture.jpg"))
// Request a 24-bits depth buffer when creating the window
sf::ContextSettings contextSettings;
contextSettings.depthBits = 24;
contextSettings.sRgbCapable = sRgb;
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML graphics with OpenGL", sf::Style::Default, contextSettings);
window.setVerticalSyncEnabled(true);
// Create a sprite for the background
sf::Texture backgroundTexture;
backgroundTexture.setSrgb(sRgb);
if (!backgroundTexture.loadFromFile("resources/background.jpg"))
return EXIT_FAILURE;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
sf::Sprite background(backgroundTexture);
// Enable Z-buffer read and write
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glClearDepth(1.f);
// Create some text to draw on top of our OpenGL object
sf::Font font;
if (!font.loadFromFile("resources/sansation.ttf"))
return EXIT_FAILURE;
sf::Text text("SFML / OpenGL demo", font);
sf::Text instructions("Press space to toggle sRGB conversion", font);
text.setColor(sf::Color(255, 255, 255, 170));
instructions.setColor(sf::Color(255, 255, 255, 170));
text.setPosition(250.f, 450.f);
instructions.setPosition(150.f, 500.f);
// Disable lighting
glDisable(GL_LIGHTING);
// Configure the viewport (the same size as the window)
glViewport(0, 0, window.getSize().x, window.getSize().y);
// Setup a perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat ratio = static_cast<float>(window.getSize().x) / window.getSize().y;
glFrustum(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
// Bind the texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
// Define a 3D cube (6 faces made of 2 triangles composed by 3 vertices)
static const GLfloat cube[] =
{
// positions // texture coordinates
-20, -20, -20, 0, 0,
-20, 20, -20, 1, 0,
-20, -20, 20, 0, 1,
-20, -20, 20, 0, 1,
-20, 20, -20, 1, 0,
-20, 20, 20, 1, 1,
20, -20, -20, 0, 0,
20, 20, -20, 1, 0,
20, -20, 20, 0, 1,
20, -20, 20, 0, 1,
20, 20, -20, 1, 0,
20, 20, 20, 1, 1,
-20, -20, -20, 0, 0,
20, -20, -20, 1, 0,
-20, -20, 20, 0, 1,
-20, -20, 20, 0, 1,
20, -20, -20, 1, 0,
20, -20, 20, 1, 1,
-20, 20, -20, 0, 0,
20, 20, -20, 1, 0,
-20, 20, 20, 0, 1,
-20, 20, 20, 0, 1,
20, 20, -20, 1, 0,
20, 20, 20, 1, 1,
-20, -20, -20, 0, 0,
20, -20, -20, 1, 0,
-20, 20, -20, 0, 1,
-20, 20, -20, 0, 1,
20, -20, -20, 1, 0,
20, 20, -20, 1, 1,
-20, -20, 20, 0, 0,
20, -20, 20, 1, 0,
-20, 20, 20, 0, 1,
-20, 20, 20, 0, 1,
20, -20, 20, 1, 0,
20, 20, 20, 1, 1
};
// Enable position and texture coordinates vertex components
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), cube);
glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), cube + 3);
// Disable normal and color vertex components
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
// Create a clock for measuring the time elapsed
sf::Clock clock;
// Start game loop
while (window.isOpen())
{
// Process events
sf::Event event;
while (window.pollEvent(event))
// Load an OpenGL texture.
// We could directly use a sf::Texture as an OpenGL texture (with its Bind() member function),
// but here we want more control on it (generate mipmaps, ...) so we create a new one from an image
GLuint texture = 0;
{
// Close window: exit
if (event.type == sf::Event::Closed)
window.close();
// Escape key: exit
if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
window.close();
// Adjust the viewport when the window is resized
if (event.type == sf::Event::Resized)
glViewport(0, 0, event.size.width, event.size.height);
sf::Image image;
if (!image.loadFromFile("resources/texture.jpg"))
return EXIT_FAILURE;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, sRgb ? GL_SRGB8_ALPHA8 : GL_RGBA, image.getSize().x, image.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
// Draw the background
window.pushGLStates();
window.draw(background);
window.popGLStates();
// Enable Z-buffer read and write
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glClearDepth(1.f);
// Clear the depth buffer
glClear(GL_DEPTH_BUFFER_BIT);
// Disable lighting
glDisable(GL_LIGHTING);
// We get the position of the mouse cursor, so that we can move the box accordingly
float x = sf::Mouse::getPosition(window).x * 200.f / window.getSize().x - 100.f;
float y = -sf::Mouse::getPosition(window).y * 200.f / window.getSize().y + 100.f;
// Configure the viewport (the same size as the window)
glViewport(0, 0, window.getSize().x, window.getSize().y);
// Apply some transformations
glMatrixMode(GL_MODELVIEW);
// Setup a perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(x, y, -100.f);
glRotatef(clock.getElapsedTime().asSeconds() * 50.f, 1.f, 0.f, 0.f);
glRotatef(clock.getElapsedTime().asSeconds() * 30.f, 0.f, 1.f, 0.f);
glRotatef(clock.getElapsedTime().asSeconds() * 90.f, 0.f, 0.f, 1.f);
GLfloat ratio = static_cast<float>(window.getSize().x) / window.getSize().y;
glFrustum(-ratio, ratio, -1.f, 1.f, 1.f, 500.f);
// Draw the cube
glDrawArrays(GL_TRIANGLES, 0, 36);
// Bind the texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
// Draw some text on top of our OpenGL object
window.pushGLStates();
window.draw(text);
window.popGLStates();
// Define a 3D cube (6 faces made of 2 triangles composed by 3 vertices)
static const GLfloat cube[] =
{
// positions // texture coordinates
-20, -20, -20, 0, 0,
-20, 20, -20, 1, 0,
-20, -20, 20, 0, 1,
-20, -20, 20, 0, 1,
-20, 20, -20, 1, 0,
-20, 20, 20, 1, 1,
// Finally, display the rendered frame on screen
window.display();
20, -20, -20, 0, 0,
20, 20, -20, 1, 0,
20, -20, 20, 0, 1,
20, -20, 20, 0, 1,
20, 20, -20, 1, 0,
20, 20, 20, 1, 1,
-20, -20, -20, 0, 0,
20, -20, -20, 1, 0,
-20, -20, 20, 0, 1,
-20, -20, 20, 0, 1,
20, -20, -20, 1, 0,
20, -20, 20, 1, 1,
-20, 20, -20, 0, 0,
20, 20, -20, 1, 0,
-20, 20, 20, 0, 1,
-20, 20, 20, 0, 1,
20, 20, -20, 1, 0,
20, 20, 20, 1, 1,
-20, -20, -20, 0, 0,
20, -20, -20, 1, 0,
-20, 20, -20, 0, 1,
-20, 20, -20, 0, 1,
20, -20, -20, 1, 0,
20, 20, -20, 1, 1,
-20, -20, 20, 0, 0,
20, -20, 20, 1, 0,
-20, 20, 20, 0, 1,
-20, 20, 20, 0, 1,
20, -20, 20, 1, 0,
20, 20, 20, 1, 1
};
// Enable position and texture coordinates vertex components
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 5 * sizeof(GLfloat), cube);
glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(GLfloat), cube + 3);
// Disable normal and color vertex components
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
// Create a clock for measuring the time elapsed
sf::Clock clock;
// Start game loop
while (window.isOpen())
{
// Process events
sf::Event event;
while (window.pollEvent(event))
{
// Close window: exit
if (event.type == sf::Event::Closed)
{
exit = true;
window.close();
}
// Escape key: exit
if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
{
exit = true;
window.close();
}
// Space key: toggle sRGB conversion
if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Space))
{
sRgb = !sRgb;
window.close();
}
// Adjust the viewport when the window is resized
if (event.type == sf::Event::Resized)
glViewport(0, 0, event.size.width, event.size.height);
}
// Draw the background
window.pushGLStates();
window.draw(background);
window.popGLStates();
// Clear the depth buffer
glClear(GL_DEPTH_BUFFER_BIT);
// We get the position of the mouse cursor, so that we can move the box accordingly
float x = sf::Mouse::getPosition(window).x * 200.f / window.getSize().x - 100.f;
float y = -sf::Mouse::getPosition(window).y * 200.f / window.getSize().y + 100.f;
// Apply some transformations
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(x, y, -100.f);
glRotatef(clock.getElapsedTime().asSeconds() * 50.f, 1.f, 0.f, 0.f);
glRotatef(clock.getElapsedTime().asSeconds() * 30.f, 0.f, 1.f, 0.f);
glRotatef(clock.getElapsedTime().asSeconds() * 90.f, 0.f, 0.f, 1.f);
// Draw the cube
glDrawArrays(GL_TRIANGLES, 0, 36);
// Draw some text on top of our OpenGL object
window.pushGLStates();
window.draw(text);
window.draw(instructions);
window.popGLStates();
// Finally, display the rendered frame on screen
window.display();
}
// Don't forget to destroy our texture
glDeleteTextures(1, &texture);
}
// Don't forget to destroy our texture
glDeleteTextures(1, &texture);
return EXIT_SUCCESS;
}

View File

@ -376,6 +376,41 @@ public:
////////////////////////////////////////////////////////////
bool isSmooth() const;
////////////////////////////////////////////////////////////
/// \brief Enable or disable conversion from sRGB
///
/// When providing texture data from an image file or memory, it can
/// either be stored in a linear color space or an sRGB color space.
/// Most digital images account for gamma correction already, so they
/// would need to be "uncorrected" back to linear color space before
/// being processed by the hardware. The hardware can automatically
/// convert it from the sRGB color space to a linear color space when
/// it gets sampled. When the rendered image gets output to the final
/// framebuffer, it gets converted back to sRGB.
///
/// After enabling or disabling sRGB conversion, make sure to reload
/// the texture data in order for the setting to take effect.
///
/// This option is only useful in conjunction with an sRGB capable
/// framebuffer. This can be requested during window creation.
///
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \see isSrgb
///
////////////////////////////////////////////////////////////
void setSrgb(bool sRgb);
////////////////////////////////////////////////////////////
/// \brief Tell whether the texture source is converted from sRGB or not
///
/// \return True if the texture source is converted from sRGB, false if not
///
/// \see setSrgb
///
////////////////////////////////////////////////////////////
bool isSrgb() const;
////////////////////////////////////////////////////////////
/// \brief Enable or disable repeating
///
@ -504,6 +539,7 @@ private:
Vector2u m_actualSize; ///< Actual texture size (can be greater than public size because of padding)
unsigned int m_texture; ///< Internal texture identifier
bool m_isSmooth; ///< Status of the smooth filter
bool m_sRgb; ///< Should the texture source be converted from sRGB?
bool m_isRepeated; ///< Is the texture in repeat mode?
mutable bool m_pixelsFlipped; ///< To work around the inconsistency in Y orientation
bool m_fboAttachment; ///< Is this texture owned by a framebuffer object?

View File

@ -55,15 +55,17 @@ struct ContextSettings
/// \param major Major number of the context version
/// \param minor Minor number of the context version
/// \param attributes Attribute flags of the context
/// \param sRgb sRGB capable framebuffer
///
////////////////////////////////////////////////////////////
explicit ContextSettings(unsigned int depth = 0, unsigned int stencil = 0, unsigned int antialiasing = 0, unsigned int major = 1, unsigned int minor = 1, unsigned int attributes = Default) :
explicit ContextSettings(unsigned int depth = 0, unsigned int stencil = 0, unsigned int antialiasing = 0, unsigned int major = 1, unsigned int minor = 1, unsigned int attributes = Default, bool sRgb = false) :
depthBits (depth),
stencilBits (stencil),
antialiasingLevel(antialiasing),
majorVersion (major),
minorVersion (minor),
attributeFlags (attributes)
attributeFlags (attributes),
sRgbCapable (sRgb)
{
}
@ -76,6 +78,7 @@ struct ContextSettings
unsigned int majorVersion; ///< Major number of the context version to create
unsigned int minorVersion; ///< Minor number of the context version to create
Uint32 attributeFlags; ///< The attribute flags to create the context with
bool sRgbCapable; ///< Whether the context framebuffer is sRGB capable
};
} // namespace sf

View File

@ -110,6 +110,10 @@
#define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES
#define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_OES
// Core since 3.0 - EXT_sRGB
#define GLEXT_texture_sRGB GL_EXT_sRGB
#define GLEXT_GL_SRGB8_ALPHA8 GL_SRGB8_ALPHA8_EXT
#else
#include <SFML/Graphics/GLLoader.hpp>
@ -208,6 +212,10 @@
#define GLEXT_blend_equation_separate sfogl_ext_EXT_blend_equation_separate
#define GLEXT_glBlendEquationSeparate glBlendEquationSeparateEXT
// Core since 2.1 - EXT_texture_sRGB
#define GLEXT_texture_sRGB sfogl_ext_EXT_texture_sRGB
#define GLEXT_GL_SRGB8_ALPHA8 GL_SRGB8_ALPHA8_EXT
// Core since 3.0 - EXT_framebuffer_object
#define GLEXT_framebuffer_object sfogl_ext_EXT_framebuffer_object
#define GLEXT_glBindRenderbuffer glBindRenderbufferEXT

View File

@ -13,5 +13,6 @@ ARB_vertex_shader
ARB_fragment_shader
ARB_texture_non_power_of_two
EXT_blend_equation_separate
EXT_texture_sRGB
EXT_framebuffer_object
ARB_geometry_shader4

View File

@ -45,6 +45,7 @@ int sfogl_ext_ARB_vertex_shader = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_fragment_shader = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
@ -835,7 +836,7 @@ typedef struct sfogl_StrToExtMap_s
PFN_LOADFUNCPOINTERS LoadExtension;
} sfogl_StrToExtMap;
static sfogl_StrToExtMap ExtensionMap[14] = {
static sfogl_StrToExtMap ExtensionMap[15] = {
{"GL_SGIS_texture_edge_clamp", &sfogl_ext_SGIS_texture_edge_clamp, NULL},
{"GL_EXT_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL},
{"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax},
@ -848,11 +849,12 @@ static sfogl_StrToExtMap ExtensionMap[14] = {
{"GL_ARB_fragment_shader", &sfogl_ext_ARB_fragment_shader, NULL},
{"GL_ARB_texture_non_power_of_two", &sfogl_ext_ARB_texture_non_power_of_two, NULL},
{"GL_EXT_blend_equation_separate", &sfogl_ext_EXT_blend_equation_separate, Load_EXT_blend_equation_separate},
{"GL_EXT_texture_sRGB", &sfogl_ext_EXT_texture_sRGB, NULL},
{"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object},
{"GL_ARB_geometry_shader4", &sfogl_ext_ARB_geometry_shader4, Load_ARB_geometry_shader4}
};
static int g_extensionMapSize = 14;
static int g_extensionMapSize = 15;
static void ClearExtensionVars()
@ -869,6 +871,7 @@ static void ClearExtensionVars()
sfogl_ext_ARB_fragment_shader = sfogl_LOAD_FAILED;
sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED;
sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
}

View File

@ -182,6 +182,7 @@ extern int sfogl_ext_ARB_vertex_shader;
extern int sfogl_ext_ARB_fragment_shader;
extern int sfogl_ext_ARB_texture_non_power_of_two;
extern int sfogl_ext_EXT_blend_equation_separate;
extern int sfogl_ext_EXT_texture_sRGB;
extern int sfogl_ext_EXT_framebuffer_object;
extern int sfogl_ext_ARB_geometry_shader4;
@ -309,6 +310,23 @@ extern int sfogl_ext_ARB_geometry_shader4;
#define GL_BLEND_EQUATION_ALPHA_EXT 0x883D
#define GL_BLEND_EQUATION_RGB_EXT 0x8009
#define GL_COMPRESSED_SLUMINANCE_ALPHA_EXT 0x8C4B
#define GL_COMPRESSED_SLUMINANCE_EXT 0x8C4A
#define GL_COMPRESSED_SRGB_ALPHA_EXT 0x8C49
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT 0x8C4D
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT 0x8C4E
#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F
#define GL_COMPRESSED_SRGB_EXT 0x8C48
#define GL_COMPRESSED_SRGB_S3TC_DXT1_EXT 0x8C4C
#define GL_SLUMINANCE8_ALPHA8_EXT 0x8C45
#define GL_SLUMINANCE8_EXT 0x8C47
#define GL_SLUMINANCE_ALPHA_EXT 0x8C44
#define GL_SLUMINANCE_EXT 0x8C46
#define GL_SRGB8_ALPHA8_EXT 0x8C43
#define GL_SRGB8_EXT 0x8C41
#define GL_SRGB_ALPHA_EXT 0x8C42
#define GL_SRGB_EXT 0x8C40
#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
@ -1185,6 +1203,7 @@ extern void (GL_FUNCPTR *sf_ptrc_glBlendEquationSeparateEXT)(GLenum, GLenum);
#define glBlendEquationSeparateEXT sf_ptrc_glBlendEquationSeparateEXT
#endif // GL_EXT_blend_equation_separate
#ifndef GL_EXT_framebuffer_object
#define GL_EXT_framebuffer_object 1
extern void (GL_FUNCPTR *sf_ptrc_glBindFramebufferEXT)(GLenum, GLuint);

View File

@ -84,6 +84,7 @@ m_size (0, 0),
m_actualSize (0, 0),
m_texture (0),
m_isSmooth (false),
m_sRgb (false),
m_isRepeated (false),
m_pixelsFlipped(false),
m_fboAttachment(false),
@ -98,6 +99,7 @@ m_size (0, 0),
m_actualSize (0, 0),
m_texture (0),
m_isSmooth (copy.m_isSmooth),
m_sRgb (copy.m_sRgb),
m_isRepeated (copy.m_isRepeated),
m_pixelsFlipped(false),
m_fboAttachment(false),
@ -185,9 +187,30 @@ bool Texture::create(unsigned int width, unsigned int height)
}
}
static bool textureSrgb = GLEXT_texture_sRGB;
if (m_sRgb && !textureSrgb)
{
static bool warned = false;
if (!warned)
{
#ifndef SFML_OPENGL_ES
err() << "OpenGL extension EXT_texture_sRGB unavailable" << std::endl;
#else
err() << "OpenGL ES extension EXT_sRGB unavailable" << std::endl;
#endif
err() << "Automatic sRGB to linear conversion disabled" << std::endl;
warned = true;
}
m_sRgb = false;
}
// Initialize the texture
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
glCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_actualSize.x, m_actualSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
glCheck(glTexImage2D(GL_TEXTURE_2D, 0, (m_sRgb ? GLEXT_GL_SRGB8_ALPHA8 : GL_RGBA), m_actualSize.x, m_actualSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
@ -479,6 +502,20 @@ bool Texture::isSmooth() const
}
////////////////////////////////////////////////////////////
void Texture::setSrgb(bool sRgb)
{
m_sRgb = sRgb;
}
////////////////////////////////////////////////////////////
bool Texture::isSrgb() const
{
return m_sRgb;
}
////////////////////////////////////////////////////////////
void Texture::setRepeated(bool repeated)
{

View File

@ -100,6 +100,10 @@
#define GL_CONTEXT_FLAGS 0x821E
#endif
#if !defined(GL_FRAMEBUFFER_SRGB)
#define GL_FRAMEBUFFER_SRGB 0x8DB9
#endif
#if !defined(GL_CONTEXT_FLAG_DEBUG_BIT)
#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
#endif
@ -176,7 +180,7 @@ void GlContext::globalInit()
// Create the shared context
sharedContext = new ContextType(NULL);
sharedContext->initialize();
sharedContext->initialize(ContextSettings());
// This call makes sure that:
// - the shared context is inactive (it must never be)
@ -221,7 +225,7 @@ GlContext* GlContext::create()
// Create the context
GlContext* context = new ContextType(sharedContext);
context->initialize();
context->initialize(ContextSettings());
return context;
}
@ -237,7 +241,7 @@ GlContext* GlContext::create(const ContextSettings& settings, const WindowImpl*
// Create the context
GlContext* context = new ContextType(sharedContext, settings, owner, bitsPerPixel);
context->initialize();
context->initialize(settings);
context->checkSettings(settings);
return context;
@ -254,7 +258,7 @@ GlContext* GlContext::create(const ContextSettings& settings, unsigned int width
// Create the context
GlContext* context = new ContextType(sharedContext, settings, width, height);
context->initialize();
context->initialize(settings);
context->checkSettings(settings);
return context;
@ -346,7 +350,7 @@ GlContext::GlContext()
////////////////////////////////////////////////////////////
int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated)
int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated, bool sRgb)
{
int colorDiff = static_cast<int>(bitsPerPixel) - colorBits;
int depthDiff = static_cast<int>(settings.depthBits) - depthBits;
@ -362,6 +366,10 @@ int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings&
// Aggregate the scores
int score = std::abs(colorDiff) + std::abs(depthDiff) + std::abs(stencilDiff) + std::abs(antialiasingDiff);
// If the user wants an sRGB capable format, try really hard to get one
if (settings.sRgbCapable && !sRgb)
score += 10000000;
// Make sure we prefer hardware acceleration over features
if (!accelerated)
score += 100000000;
@ -371,7 +379,7 @@ int GlContext::evaluateFormat(unsigned int bitsPerPixel, const ContextSettings&
////////////////////////////////////////////////////////////
void GlContext::initialize()
void GlContext::initialize(const ContextSettings& requestedSettings)
{
// Activate the context
setActive(true);
@ -468,9 +476,32 @@ void GlContext::initialize()
}
}
// Enable antialiasing if needed
if (m_settings.antialiasingLevel > 0)
// Enable anti-aliasing if requested by the user and supported
if ((requestedSettings.antialiasingLevel > 0) && (m_settings.antialiasingLevel > 0))
{
glEnable(GL_MULTISAMPLE);
}
else
{
m_settings.antialiasingLevel = 0;
}
// Enable sRGB if requested by the user and supported
if (requestedSettings.sRgbCapable && m_settings.sRgbCapable)
{
glEnable(GL_FRAMEBUFFER_SRGB);
// Check to see if the enable was successful
if (glIsEnabled(GL_FRAMEBUFFER_SRGB) == GL_FALSE)
{
err() << "Warning: Failed to enable GL_FRAMEBUFFER_SRGB" << std::endl;
m_settings.sRgbCapable = false;
}
}
else
{
m_settings.sRgbCapable = false;
}
}
@ -496,10 +527,11 @@ void GlContext::checkSettings(const ContextSettings& requestedSettings)
int requestedVersion = requestedSettings.majorVersion * 10 + requestedSettings.minorVersion;
if ((m_settings.attributeFlags != requestedSettings.attributeFlags) ||
(version < requestedVersion) ||
(version < requestedVersion) ||
(m_settings.stencilBits < requestedSettings.stencilBits) ||
(m_settings.antialiasingLevel < requestedSettings.antialiasingLevel) ||
(m_settings.depthBits < requestedSettings.depthBits))
(m_settings.depthBits < requestedSettings.depthBits) ||
(!m_settings.sRgbCapable && requestedSettings.sRgbCapable))
{
err() << "Warning: The created OpenGL context does not fully meet the settings that were requested" << std::endl;
err() << "Requested: version = " << requestedSettings.majorVersion << "." << requestedSettings.minorVersion
@ -509,6 +541,7 @@ void GlContext::checkSettings(const ContextSettings& requestedSettings)
<< std::boolalpha
<< " ; core = " << ((requestedSettings.attributeFlags & ContextSettings::Core) != 0)
<< " ; debug = " << ((requestedSettings.attributeFlags & ContextSettings::Debug) != 0)
<< " ; sRGB = " << requestedSettings.sRgbCapable
<< std::noboolalpha << std::endl;
err() << "Created: version = " << m_settings.majorVersion << "." << m_settings.minorVersion
<< " ; depth bits = " << m_settings.depthBits
@ -517,6 +550,7 @@ void GlContext::checkSettings(const ContextSettings& requestedSettings)
<< std::boolalpha
<< " ; core = " << ((m_settings.attributeFlags & ContextSettings::Core) != 0)
<< " ; debug = " << ((m_settings.attributeFlags & ContextSettings::Debug) != 0)
<< " ; sRGB = " << m_settings.sRgbCapable
<< std::noboolalpha << std::endl;
}
}

View File

@ -217,11 +217,12 @@ protected:
/// \param stencilBits Stencil bits of the configuration to evaluate
/// \param antialiasing Antialiasing level of the configuration to evaluate
/// \param accelerated Whether the pixel format is hardware accelerated
/// \param sRgb Whether the pixel format is sRGB capable
///
/// \return Score of the configuration
///
////////////////////////////////////////////////////////////
static int evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated);
static int evaluateFormat(unsigned int bitsPerPixel, const ContextSettings& settings, int colorBits, int depthBits, int stencilBits, int antialiasing, bool accelerated, bool sRgb);
////////////////////////////////////////////////////////////
// Member data
@ -232,9 +233,10 @@ private:
////////////////////////////////////////////////////////////
/// \brief Perform various initializations after the context construction
/// \param requestedSettings Requested settings during context creation
///
////////////////////////////////////////////////////////////
void initialize();
void initialize(const ContextSettings& requestedSettings);
////////////////////////////////////////////////////////////
/// \brief Check whether the context is compatible with the requested settings

View File

@ -242,6 +242,9 @@ void SFContext::createContext(SFContext* shared,
attrs.push_back((NSOpenGLPixelFormatAttribute)0); // end of array
// All OS X pixel formats are sRGB capable
m_settings.sRgbCapable = true;
// Create the pixel format.
NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attrs[0]];

View File

@ -320,7 +320,7 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
continue;
// Extract the components of the current visual
int red, green, blue, alpha, depth, stencil, multiSampling, samples;
int red, green, blue, alpha, depth, stencil, multiSampling, samples, sRgb;
glXGetConfig(display, &visuals[i], GLX_RED_SIZE, &red);
glXGetConfig(display, &visuals[i], GLX_GREEN_SIZE, &green);
glXGetConfig(display, &visuals[i], GLX_BLUE_SIZE, &blue);
@ -339,12 +339,21 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
samples = 0;
}
if ((sfglx_ext_EXT_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED) || (sfglx_ext_ARB_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED))
{
glXGetConfig(display, &visuals[i], GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &sRgb);
}
else
{
sRgb = 0;
}
// TODO: Replace this with proper acceleration detection
bool accelerated = true;
// Evaluate the visual
int color = red + green + blue + alpha;
int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0, accelerated);
int score = evaluateFormat(bitsPerPixel, settings, color, depth, stencil, multiSampling ? samples : 0, accelerated, sRgb == True);
// If it's better than the current best, make it the new best
if (score < bestScore)
@ -373,7 +382,7 @@ XVisualInfo GlxContext::selectBestVisual(::Display* display, unsigned int bitsPe
void GlxContext::updateSettingsFromVisualInfo(XVisualInfo* visualInfo)
{
// Update the creation settings from the chosen format
int depth, stencil, multiSampling, samples;
int depth, stencil, multiSampling, samples, sRgb;
glXGetConfig(m_display, visualInfo, GLX_DEPTH_SIZE, &depth);
glXGetConfig(m_display, visualInfo, GLX_STENCIL_SIZE, &stencil);
@ -388,9 +397,19 @@ void GlxContext::updateSettingsFromVisualInfo(XVisualInfo* visualInfo)
samples = 0;
}
if ((sfglx_ext_EXT_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED) || (sfglx_ext_ARB_framebuffer_sRGB == sfglx_LOAD_SUCCEEDED))
{
glXGetConfig(m_display, visualInfo, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &sRgb);
}
else
{
sRgb = 0;
}
m_settings.depthBits = static_cast<unsigned int>(depth);
m_settings.stencilBits = static_cast<unsigned int>(stencil);
m_settings.antialiasingLevel = multiSampling ? samples : 0;
m_settings.sRgbCapable = (sRgb == True);
}

View File

@ -40,6 +40,8 @@ static sf::GlFunctionPointer IntGetProcAddress(const char* name)
int sfglx_ext_EXT_swap_control = sfglx_LOAD_FAILED;
int sfglx_ext_MESA_swap_control = sfglx_LOAD_FAILED;
int sfglx_ext_SGI_swap_control = sfglx_LOAD_FAILED;
int sfglx_ext_EXT_framebuffer_sRGB = sfglx_LOAD_FAILED;
int sfglx_ext_ARB_framebuffer_sRGB = sfglx_LOAD_FAILED;
int sfglx_ext_ARB_multisample = sfglx_LOAD_FAILED;
int sfglx_ext_SGIX_pbuffer = sfglx_LOAD_FAILED;
int sfglx_ext_ARB_create_context = sfglx_LOAD_FAILED;
@ -124,17 +126,19 @@ typedef struct sfglx_StrToExtMap_s
PFN_LOADFUNCPOINTERS LoadExtension;
} sfglx_StrToExtMap;
static sfglx_StrToExtMap ExtensionMap[7] = {
static sfglx_StrToExtMap ExtensionMap[9] = {
{"GLX_EXT_swap_control", &sfglx_ext_EXT_swap_control, Load_EXT_swap_control},
{"GLX_MESA_swap_control", &sfglx_ext_MESA_swap_control, Load_MESA_swap_control},
{"GLX_SGI_swap_control", &sfglx_ext_SGI_swap_control, Load_SGI_swap_control},
{"GLX_EXT_framebuffer_sRGB", &sfglx_ext_EXT_framebuffer_sRGB, NULL},
{"GLX_ARB_framebuffer_sRGB", &sfglx_ext_ARB_framebuffer_sRGB, NULL},
{"GLX_ARB_multisample", &sfglx_ext_ARB_multisample, NULL},
{"GLX_SGIX_pbuffer", &sfglx_ext_SGIX_pbuffer, Load_SGIX_pbuffer},
{"GLX_ARB_create_context", &sfglx_ext_ARB_create_context, Load_ARB_create_context},
{"GLX_ARB_create_context_profile", &sfglx_ext_ARB_create_context_profile, NULL},
{"GLX_ARB_create_context_profile", &sfglx_ext_ARB_create_context_profile, NULL}
};
static int g_extensionMapSize = 7;
static int g_extensionMapSize = 9;
static sfglx_StrToExtMap* FindExtEntry(const char* extensionName)
@ -155,6 +159,8 @@ static void ClearExtensionVars(void)
sfglx_ext_EXT_swap_control = sfglx_LOAD_FAILED;
sfglx_ext_MESA_swap_control = sfglx_LOAD_FAILED;
sfglx_ext_SGI_swap_control = sfglx_LOAD_FAILED;
sfglx_ext_EXT_framebuffer_sRGB = sfglx_LOAD_FAILED;
sfglx_ext_ARB_framebuffer_sRGB = sfglx_LOAD_FAILED;
sfglx_ext_ARB_multisample = sfglx_LOAD_FAILED;
sfglx_ext_SGIX_pbuffer = sfglx_LOAD_FAILED;
sfglx_ext_ARB_create_context = sfglx_LOAD_FAILED;

View File

@ -144,6 +144,8 @@ extern "C" {
extern int sfglx_ext_EXT_swap_control;
extern int sfglx_ext_MESA_swap_control;
extern int sfglx_ext_SGI_swap_control;
extern int sfglx_ext_EXT_framebuffer_sRGB;
extern int sfglx_ext_ARB_framebuffer_sRGB;
extern int sfglx_ext_ARB_multisample;
extern int sfglx_ext_SGIX_pbuffer;
extern int sfglx_ext_ARB_create_context;
@ -152,6 +154,10 @@ extern int sfglx_ext_ARB_create_context_profile;
#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
#define GLX_SWAP_INTERVAL_EXT 0x20F1
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20B2
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
#define GLX_SAMPLES_ARB 100001
#define GLX_SAMPLE_BUFFERS_ARB 100000

View File

@ -6,6 +6,8 @@
EXT_swap_control
// MESA_swap_control
SGI_swap_control
EXT_framebuffer_sRGB
ARB_framebuffer_sRGB
GLX_ARB_multisample
GLX_SGIX_pbuffer
GLX_ARB_create_context

View File

@ -303,6 +303,18 @@ int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPix
}
}
int sRgbCapableValue = 0;
if ((sfwgl_ext_ARB_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED) || (sfwgl_ext_EXT_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED))
{
const int sRgbCapableAttribute = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
if (!wglGetPixelFormatAttribivARB(deviceContext, formats[i], PFD_MAIN_PLANE, 1, &sRgbCapableAttribute, &sRgbCapableValue))
{
err() << "Failed to retrieve pixel format sRGB capability information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
break;
}
}
if (pbuffer)
{
const int pbufferAttributes[] =
@ -324,7 +336,7 @@ int WglContext::selectBestPixelFormat(HDC deviceContext, unsigned int bitsPerPix
// Evaluate the current configuration
int color = values[0] + values[1] + values[2] + values[3];
int score = evaluateFormat(bitsPerPixel, settings, color, values[4], values[5], sampleValues[0] ? sampleValues[1] : 0, values[6] == WGL_FULL_ACCELERATION_ARB);
int score = evaluateFormat(bitsPerPixel, settings, color, values[4], values[5], sampleValues[0] ? sampleValues[1] : 0, values[6] == WGL_FULL_ACCELERATION_ARB, sRgbCapableValue == TRUE);
// Keep it if it's better than the current best
if (score < bestScore)
@ -444,6 +456,26 @@ void WglContext::updateSettingsFromPixelFormat()
{
m_settings.antialiasingLevel = 0;
}
if ((sfwgl_ext_ARB_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED) || (sfwgl_ext_EXT_framebuffer_sRGB == sfwgl_LOAD_SUCCEEDED))
{
const int sRgbCapableAttribute = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
int sRgbCapableValue = 0;
if (wglGetPixelFormatAttribivARB(m_deviceContext, format, PFD_MAIN_PLANE, 1, &sRgbCapableAttribute, &sRgbCapableValue))
{
m_settings.sRgbCapable = (sRgbCapableValue == TRUE);
}
else
{
err() << "Failed to retrieve pixel format sRGB capability information: " << getErrorString(GetLastError()).toAnsiString() << std::endl;
m_settings.sRgbCapable = false;
}
}
else
{
m_settings.sRgbCapable = false;
}
}
else
{

View File

@ -38,6 +38,8 @@ static sf::GlFunctionPointer IntGetProcAddress(const char* name)
}
int sfwgl_ext_EXT_swap_control = sfwgl_LOAD_FAILED;
int sfwgl_ext_EXT_framebuffer_sRGB = sfwgl_LOAD_FAILED;
int sfwgl_ext_ARB_framebuffer_sRGB = sfwgl_LOAD_FAILED;
int sfwgl_ext_ARB_multisample = sfwgl_LOAD_FAILED;
int sfwgl_ext_ARB_pixel_format = sfwgl_LOAD_FAILED;
int sfwgl_ext_ARB_pbuffer = sfwgl_LOAD_FAILED;
@ -127,16 +129,18 @@ typedef struct sfwgl_StrToExtMap_s
PFN_LOADFUNCPOINTERS LoadExtension;
} sfwgl_StrToExtMap;
static sfwgl_StrToExtMap ExtensionMap[6] = {
static sfwgl_StrToExtMap ExtensionMap[8] = {
{"WGL_EXT_swap_control", &sfwgl_ext_EXT_swap_control, Load_EXT_swap_control},
{"WGL_EXT_framebuffer_sRGB", &sfwgl_ext_EXT_framebuffer_sRGB, NULL},
{"WGL_ARB_framebuffer_sRGB", &sfwgl_ext_ARB_framebuffer_sRGB, NULL},
{"WGL_ARB_multisample", &sfwgl_ext_ARB_multisample, NULL},
{"WGL_ARB_pixel_format", &sfwgl_ext_ARB_pixel_format, Load_ARB_pixel_format},
{"WGL_ARB_pbuffer", &sfwgl_ext_ARB_pbuffer, Load_ARB_pbuffer},
{"WGL_ARB_create_context", &sfwgl_ext_ARB_create_context, Load_ARB_create_context},
{"WGL_ARB_create_context_profile", &sfwgl_ext_ARB_create_context_profile, NULL},
{"WGL_ARB_create_context_profile", &sfwgl_ext_ARB_create_context_profile, NULL}
};
static int g_extensionMapSize = 6;
static int g_extensionMapSize = 8;
static sfwgl_StrToExtMap* FindExtEntry(const char* extensionName)
@ -155,6 +159,8 @@ static sfwgl_StrToExtMap* FindExtEntry(const char* extensionName)
static void ClearExtensionVars(void)
{
sfwgl_ext_EXT_swap_control = sfwgl_LOAD_FAILED;
sfwgl_ext_EXT_framebuffer_sRGB = sfwgl_LOAD_FAILED;
sfwgl_ext_ARB_framebuffer_sRGB = sfwgl_LOAD_FAILED;
sfwgl_ext_ARB_multisample = sfwgl_LOAD_FAILED;
sfwgl_ext_ARB_pixel_format = sfwgl_LOAD_FAILED;
sfwgl_ext_ARB_pbuffer = sfwgl_LOAD_FAILED;

View File

@ -93,12 +93,18 @@ extern "C" {
#endif // __cplusplus
extern int sfwgl_ext_EXT_swap_control;
extern int sfwgl_ext_EXT_framebuffer_sRGB;
extern int sfwgl_ext_ARB_framebuffer_sRGB;
extern int sfwgl_ext_ARB_multisample;
extern int sfwgl_ext_ARB_pixel_format;
extern int sfwgl_ext_ARB_pbuffer;
extern int sfwgl_ext_ARB_create_context;
extern int sfwgl_ext_ARB_create_context_profile;
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x20A9
#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20A9
#define WGL_SAMPLES_ARB 0x2042
#define WGL_SAMPLE_BUFFERS_ARB 0x2041

View File

@ -4,6 +4,8 @@
// lua LoadGen.lua -style=pointer_c -spec=wgl -indent=space -prefix=sf -extfile=WglExtensions.txt WglExtensions
EXT_swap_control
EXT_framebuffer_sRGB
ARB_framebuffer_sRGB
WGL_ARB_multisample
WGL_ARB_pixel_format
WGL_ARB_pbuffer