Added support for shaders written in non-legacy GLSL.

This commit is contained in:
binary1248 2018-05-20 14:06:24 +02:00
parent 1dcad60878
commit db7e683688
No known key found for this signature in database
GPG Key ID: E5E52A5D6082224A
18 changed files with 690 additions and 74 deletions

View File

@ -115,6 +115,12 @@ int main()
// Check whether the prerequisites are suppprted
bool prerequisitesSupported = sf::VertexBuffer::isAvailable() && sf::Shader::isAvailable();
// Bind the shader to SFML's drawable interface
terrainShader.setPositionAttribute ("positionAttribute")
.setColorAttribute ("colorAttribute")
.setTextureCoordinateAttribute("texCoordAttribute")
.setModelViewProjectionMatrix ("modelViewProjectionMatrix");
// Set up our graphics resources and set the status text accordingly
if (!prerequisitesSupported)
{

View File

@ -1,3 +1,5 @@
varying vec4 frontColor;
varying vec3 normal;
uniform float lightFactor;
@ -7,5 +9,5 @@ void main()
vec3 eyePosition = vec3(0.0, 0.0, 1.0);
vec3 halfVector = normalize(lightPosition + eyePosition);
float intensity = lightFactor + (1.0 - lightFactor) * dot(normalize(normal), normalize(halfVector));
gl_FragColor = gl_Color * vec4(intensity, intensity, intensity, 1.0);
gl_FragColor = frontColor * vec4(intensity, intensity, intensity, 1.0);
}

View File

@ -1,8 +1,16 @@
attribute vec2 positionAttribute;
attribute vec4 colorAttribute;
attribute vec2 texCoordAttribute;
uniform mat4 modelViewProjectionMatrix;
varying vec4 frontColor;
varying vec3 normal;
void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
normal = vec3(gl_MultiTexCoord0.xy, 1.0);
gl_Position = modelViewProjectionMatrix * vec4(positionAttribute, 0.0, 1.0);
frontColor = colorAttribute;
normal = vec3(texCoordAttribute, 1.0);
}

View File

@ -28,8 +28,15 @@ public:
return false;
m_sprite.setTexture(m_texture);
// Bind the shader to SFML's drawable interface
m_shader.setPositionAttribute ("positionAttribute")
.setColorAttribute ("colorAttribute")
.setTextureCoordinateAttribute("texCoordAttribute")
.setModelViewProjectionMatrix ("modelViewProjectionMatrix")
.setTextureMatrix ("textureMatrix");
// Load the shader
if (!m_shader.loadFromFile("resources/pixelate.frag", sf::Shader::Fragment))
if (!m_shader.loadFromFile("resources/pixelate.vert", "resources/pixelate.frag"))
return false;
m_shader.setUniform("texture", sf::Shader::CurrentTexture);
@ -92,6 +99,13 @@ public:
m_text.setCharacterSize(22);
m_text.setPosition(30, 20);
// Bind the shader to SFML's drawable interface
m_shader.setPositionAttribute ("positionAttribute")
.setColorAttribute ("colorAttribute")
.setTextureCoordinateAttribute("texCoordAttribute")
.setModelViewProjectionMatrix ("modelViewProjectionMatrix")
.setTextureMatrix ("textureMatrix");
// Load the shader
if (!m_shader.loadFromFile("resources/wave.vert", "resources/blur.frag"))
return false;
@ -145,6 +159,12 @@ public:
m_points.append(sf::Vertex(sf::Vector2f(x, y), sf::Color(r, g, b)));
}
// Bind the shader to SFML's drawable interface
m_shader.setPositionAttribute("positionAttribute")
.setColorAttribute ("colorAttribute")
.setModelViewMatrix ("modelViewMatrix")
.setProjectionMatrix ("projectionMatrix");
// Load the shader
if (!m_shader.loadFromFile("resources/storm.vert", "resources/blink.frag"))
return false;
@ -212,8 +232,15 @@ public:
m_entities.push_back(entity);
}
// Bind the shader to SFML's drawable interface
m_shader.setPositionAttribute ("positionAttribute")
.setColorAttribute ("colorAttribute")
.setTextureCoordinateAttribute("texCoordAttribute")
.setModelViewProjectionMatrix ("modelViewProjectionMatrix")
.setTextureMatrix ("textureMatrix");
// Load the shader
if (!m_shader.loadFromFile("resources/edge.frag", sf::Shader::Fragment))
if (!m_shader.loadFromFile("resources/edge.vert", "resources/edge.frag"))
return false;
m_shader.setUniform("texture", sf::Shader::CurrentTexture);
@ -290,6 +317,10 @@ public:
if (!m_logoTexture.loadFromFile("resources/logo.png"))
return false;
// Bind the shader to SFML's drawable interface
m_shader.setPositionAttribute ("positionAttribute")
.setModelViewProjectionMatrix("modelViewProjectionMatrix");
// Load the shader
if (!m_shader.loadFromFile("resources/billboard.vert", "resources/billboard.geom", "resources/billboard.frag"))
return false;

View File

@ -4,8 +4,10 @@ uniform sampler2D texture;
in vec2 tex_coord;
out vec4 fragColor;
void main()
{
// Read and apply a color from the texture
gl_FragColor = texture2D(texture, tex_coord);
fragColor = texture2D(texture, tex_coord);
}

View File

@ -1,5 +1,11 @@
#version 150
in vec2 positionAttribute;
uniform mat4 modelViewProjectionMatrix;
void main()
{
// Transform the vertex position
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_Position = modelViewProjectionMatrix * vec4(positionAttribute, 0.0, 1.0);
}

View File

@ -1,9 +1,10 @@
uniform sampler2D texture;
uniform float blink_alpha;
varying vec4 frontColor;
void main()
{
vec4 pixel = gl_Color;
vec4 pixel = frontColor;
pixel.a = blink_alpha;
gl_FragColor = pixel;
}

View File

@ -1,20 +1,23 @@
uniform sampler2D texture;
uniform float blur_radius;
varying vec4 texCoord;
varying vec4 frontColor;
void main()
{
vec2 offx = vec2(blur_radius, 0.0);
vec2 offy = vec2(0.0, blur_radius);
vec4 pixel = texture2D(texture, gl_TexCoord[0].xy) * 4.0 +
texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0;
vec4 pixel = texture2D(texture, texCoord.xy) * 4.0 +
texture2D(texture, texCoord.xy - offx) * 2.0 +
texture2D(texture, texCoord.xy + offx) * 2.0 +
texture2D(texture, texCoord.xy - offy) * 2.0 +
texture2D(texture, texCoord.xy + offy) * 2.0 +
texture2D(texture, texCoord.xy - offx - offy) * 1.0 +
texture2D(texture, texCoord.xy - offx + offy) * 1.0 +
texture2D(texture, texCoord.xy + offx - offy) * 1.0 +
texture2D(texture, texCoord.xy + offx + offy) * 1.0;
gl_FragColor = gl_Color * (pixel / 16.0);
gl_FragColor = frontColor * (pixel / 16.0);
}

View File

@ -1,29 +1,32 @@
uniform sampler2D texture;
uniform float edge_threshold;
varying vec4 texCoord;
varying vec4 frontColor;
void main()
{
const float offset = 1.0 / 512.0;
vec2 offx = vec2(offset, 0.0);
vec2 offy = vec2(0.0, offset);
vec4 hEdge = texture2D(texture, gl_TexCoord[0].xy - offy) * -2.0 +
texture2D(texture, gl_TexCoord[0].xy + offy) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy - offx - offy) * -1.0 +
texture2D(texture, gl_TexCoord[0].xy - offx + offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx - offy) * -1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx + offy) * 1.0;
vec4 hEdge = texture2D(texture, texCoord.xy - offy) * -2.0 +
texture2D(texture, texCoord.xy + offy) * 2.0 +
texture2D(texture, texCoord.xy - offx - offy) * -1.0 +
texture2D(texture, texCoord.xy - offx + offy) * 1.0 +
texture2D(texture, texCoord.xy + offx - offy) * -1.0 +
texture2D(texture, texCoord.xy + offx + offy) * 1.0;
vec4 vEdge = texture2D(texture, gl_TexCoord[0].xy - offx) * 2.0 +
texture2D(texture, gl_TexCoord[0].xy + offx) * -2.0 +
texture2D(texture, gl_TexCoord[0].xy - offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy - offx + offy) * -1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx - offy) * 1.0 +
texture2D(texture, gl_TexCoord[0].xy + offx + offy) * -1.0;
vec4 vEdge = texture2D(texture, texCoord.xy - offx) * 2.0 +
texture2D(texture, texCoord.xy + offx) * -2.0 +
texture2D(texture, texCoord.xy - offx - offy) * 1.0 +
texture2D(texture, texCoord.xy - offx + offy) * -1.0 +
texture2D(texture, texCoord.xy + offx - offy) * 1.0 +
texture2D(texture, texCoord.xy + offx + offy) * -1.0;
vec3 result = sqrt(hEdge.rgb * hEdge.rgb + vEdge.rgb * vEdge.rgb);
float edge = length(result);
vec4 pixel = gl_Color * texture2D(texture, gl_TexCoord[0].xy);
vec4 pixel = frontColor * texture2D(texture, texCoord.xy);
if (edge > (edge_threshold * 8.0))
pixel.rgb = vec3(0.0, 0.0, 0.0);
else

View File

@ -0,0 +1,19 @@
attribute vec2 positionAttribute;
attribute vec4 colorAttribute;
attribute vec2 texCoordAttribute;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 textureMatrix;
varying vec4 texCoord;
varying vec4 frontColor;
void main()
{
// Transform the vertex position
gl_Position = modelViewProjectionMatrix * vec4(positionAttribute, 0.0, 1.0);
frontColor = colorAttribute;
texCoord = textureMatrix * vec4(texCoordAttribute, 0.0, 1.0);
}

View File

@ -1,9 +1,12 @@
uniform sampler2D texture;
uniform float pixel_threshold;
varying vec4 texCoord;
varying vec4 frontColor;
void main()
{
float factor = 1.0 / (pixel_threshold + 0.001);
vec2 pos = floor(gl_TexCoord[0].xy * factor + 0.5) / factor;
gl_FragColor = texture2D(texture, pos) * gl_Color;
vec2 pos = floor(texCoord.xy * factor + 0.5) / factor;
gl_FragColor = texture2D(texture, pos) * frontColor;
}

View File

@ -0,0 +1,16 @@
attribute vec2 positionAttribute;
attribute vec4 colorAttribute;
attribute vec2 texCoordAttribute;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 textureMatrix;
varying vec4 texCoord;
varying vec4 frontColor;
void main()
{
gl_Position = modelViewProjectionMatrix * vec4(positionAttribute, 0.0, 1.0);
texCoord = textureMatrix * vec4(texCoordAttribute, 0.0, 1.0);
frontColor = colorAttribute;
}

View File

@ -2,9 +2,17 @@ uniform vec2 storm_position;
uniform float storm_total_radius;
uniform float storm_inner_radius;
attribute vec2 positionAttribute;
attribute vec4 colorAttribute;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
varying vec4 frontColor;
void main()
{
vec4 vertex = gl_ModelViewMatrix * gl_Vertex;
vec4 vertex = modelViewMatrix * vec4(positionAttribute, 0.0, 1.0);
vec2 offset = vertex.xy - storm_position;
float len = length(offset);
if (len < storm_total_radius)
@ -13,7 +21,6 @@ void main()
vertex.xy = storm_position + normalize(offset) * push_distance;
}
gl_Position = gl_ProjectionMatrix * vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
gl_Position = projectionMatrix * vertex;
frontColor = colorAttribute;
}

View File

@ -1,15 +1,25 @@
uniform float wave_phase;
uniform vec2 wave_amplitude;
attribute vec2 positionAttribute;
attribute vec4 colorAttribute;
attribute vec2 texCoordAttribute;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 textureMatrix;
varying vec4 texCoord;
varying vec4 frontColor;
void main()
{
vec4 vertex = gl_Vertex;
vertex.x += cos(gl_Vertex.y * 0.02 + wave_phase * 3.8) * wave_amplitude.x
+ sin(gl_Vertex.y * 0.02 + wave_phase * 6.3) * wave_amplitude.x * 0.3;
vertex.y += sin(gl_Vertex.x * 0.02 + wave_phase * 2.4) * wave_amplitude.y
+ cos(gl_Vertex.x * 0.02 + wave_phase * 5.2) * wave_amplitude.y * 0.3;
vec4 vertex = vec4(positionAttribute, 0.0, 1.0);
vertex.x += cos(positionAttribute.y * 0.02 + wave_phase * 3.8) * wave_amplitude.x
+ sin(positionAttribute.y * 0.02 + wave_phase * 6.3) * wave_amplitude.x * 0.3;
vertex.y += sin(positionAttribute.x * 0.02 + wave_phase * 2.4) * wave_amplitude.y
+ cos(positionAttribute.x * 0.02 + wave_phase * 5.2) * wave_amplitude.y * 0.3;
gl_Position = gl_ModelViewProjectionMatrix * vertex;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
gl_FrontColor = gl_Color;
gl_Position = modelViewProjectionMatrix * vertex;
texCoord = textureMatrix * vec4(texCoordAttribute, 0.0, 1.0);
frontColor = colorAttribute;
}

View File

@ -53,6 +53,17 @@ class SFML_GRAPHICS_API Shader : GlResource, NonCopyable
{
public:
////////////////////////////////////////////////////////////
/// \brief Vertex attribute indices
///
////////////////////////////////////////////////////////////
enum VertexAttributeIndices
{
PositionIndex = 0, ///< Position attribute index
ColorIndex = 1, ///< Color attribute index
TextureCoordinateIndex = 2 ///< Texture coordinate attribute index
};
////////////////////////////////////////////////////////////
/// \brief Types of shaders
///
@ -287,6 +298,118 @@ public:
////////////////////////////////////////////////////////////
bool loadFromStream(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream);
////////////////////////////////////////////////////////////
/// \brief Specify the name of the position attribute in GLSL
///
/// This function returns a reference to *this, so that calls
/// can be chained.
///
/// \param name Name of the position attribute in GLSL
///
/// \return Reference to *this
///
/// \see setColorAttribute, setTextureCoordinateAttribute, setModelViewMatrix,
/// setProjectionMatrix, setModelViewProjectionMatrix, setTextureMatrix
///
////////////////////////////////////////////////////////////
Shader& setPositionAttribute(const std::string& name);
////////////////////////////////////////////////////////////
/// \brief Specify the name of the color attribute in GLSL
///
/// This function returns a reference to *this, so that calls
/// can be chained.
///
/// \param name Name of the color attribute in GLSL
///
/// \return Reference to *this
///
/// \see setPositionAttribute, setTextureCoordinateAttribute, setModelViewMatrix,
/// setProjectionMatrix, setModelViewProjectionMatrix, setTextureMatrix
///
////////////////////////////////////////////////////////////
Shader& setColorAttribute(const std::string& name);
////////////////////////////////////////////////////////////
/// \brief Specify the name of the texture coordinate attribute in GLSL
///
/// This function returns a reference to *this, so that calls
/// can be chained.
///
/// \param name Name of the texture coordinate attribute in GLSL
///
/// \return Reference to *this
///
/// \see setPositionAttribute, setColorAttribute, setModelViewMatrix,
/// setProjectionMatrix, setModelViewProjectionMatrix, setTextureMatrix
///
////////////////////////////////////////////////////////////
Shader& setTextureCoordinateAttribute(const std::string& name);
////////////////////////////////////////////////////////////
/// \brief Specify the name of the modelview matrix uniform in GLSL
///
/// This function returns a reference to *this, so that calls
/// can be chained.
///
/// \param name Name of the modelview matrix uniform in GLSL
///
/// \return Reference to *this
///
/// \see setPositionAttribute, setColorAttribute, setTextureCoordinateAttribute,
/// setProjectionMatrix, setModelViewProjectionMatrix, setTextureMatrix
///
////////////////////////////////////////////////////////////
Shader& setModelViewMatrix(const std::string& name);
////////////////////////////////////////////////////////////
/// \brief Specify the name of the projection matrix uniform in GLSL
///
/// This function returns a reference to *this, so that calls
/// can be chained.
///
/// \param name Name of the projection matrix uniform in GLSL
///
/// \return Reference to *this
///
/// \see setPositionAttribute, setColorAttribute, setTextureCoordinateAttribute,
/// setModelViewMatrix, setModelViewProjectionMatrix, setTextureMatrix
///
////////////////////////////////////////////////////////////
Shader& setProjectionMatrix(const std::string& name);
////////////////////////////////////////////////////////////
/// \brief Specify the name of the pre-multiplied modelview-projection matrix uniform in GLSL
///
/// This function returns a reference to *this, so that calls
/// can be chained.
///
/// \param name Name of the pre-multiplied modelview-projection matrix uniform in GLSL
///
/// \return Reference to *this
///
/// \see setPositionAttribute, setColorAttribute, setTextureCoordinateAttribute,
/// setModelViewMatrix, setProjectionMatrix, setTextureMatrix
///
////////////////////////////////////////////////////////////
Shader& setModelViewProjectionMatrix(const std::string& name);
////////////////////////////////////////////////////////////
/// \brief Specify the name of the texture matrix uniform in GLSL
///
/// This function returns a reference to *this, so that calls
/// can be chained.
///
/// \param name Name of the texture matrix uniform in GLSL
///
/// \return Reference to *this
///
/// \see setPositionAttribute, setColorAttribute, setTextureCoordinateAttribute,
/// setModelViewMatrix, setProjectionMatrix, setModelViewProjectionMatrix
///
////////////////////////////////////////////////////////////
Shader& setTextureMatrix(const std::string& name);
////////////////////////////////////////////////////////////
/// \brief Specify value for \p float uniform
///
@ -693,6 +816,8 @@ public:
private:
friend class RenderTarget;
////////////////////////////////////////////////////////////
/// \brief Compile the shader(s) and create the program
///
@ -736,6 +861,14 @@ private:
////////////////////////////////////////////////////////////
struct UniformBinder;
////////////////////////////////////////////////////////////
/// \brief Shader to Drawable interface specification
///
/// Implementation is private in the .cpp file.
///
////////////////////////////////////////////////////////////
struct Interface;
////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////
@ -749,6 +882,11 @@ private:
int m_currentTexture; ///< Location of the current texture in the shader
TextureTable m_textures; ///< Texture variables in the shader, mapped to their location
UniformTable m_uniforms; ///< Parameters location cache
int m_modelViewMatrixIndex; ///< Index of the modelview matrix
int m_projectionMatrixIndex; ///< Index of the projection matrix
int m_modelViewProjectionMatrixIndex; ///< Index of the modelview-projection matrix
int m_textureMatrixIndex; ///< Index of the texture matrix
Interface* m_interface; ///< Shader to drawable interface specification
};
} // namespace sf

View File

@ -245,6 +245,11 @@
// Core since 2.0 - ARB_vertex_shader
#define GLEXT_vertex_shader sfogl_ext_ARB_vertex_shader
#define GLEXT_glVertexAttribPointer glVertexAttribPointerARB
#define GLEXT_glEnableVertexAttribArray glEnableVertexAttribArrayARB
#define GLEXT_glDisableVertexAttribArray glDisableVertexAttribArrayARB
#define GLEXT_glBindAttribLocation glBindAttribLocationARB
#define GLEXT_glGetAttribLocation glGetAttribLocationARB
#define GLEXT_GL_VERTEX_SHADER GL_VERTEX_SHADER_ARB
#define GLEXT_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB

View File

@ -147,7 +147,19 @@ void RenderTarget::clear(const Color& color)
if (isActive(m_id) || setActive(true))
{
// Unbind texture to fix RenderTexture preventing clear
applyTexture(NULL);
{
// Bind no texture
glCheck(glBindTexture(GL_TEXTURE_2D, 0));
// Reset the texture matrix
glCheck(glMatrixMode(GL_TEXTURE));
glCheck(glLoadIdentity());
// Go back to model-view mode
glCheck(glMatrixMode(GL_MODELVIEW));
m_cache.lastTextureId = 0;
}
glCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f));
glCheck(glClear(GL_COLOR_BUFFER_BIT));
@ -283,9 +295,19 @@ void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
if (!m_cache.enable || (enableTexCoordsArray != m_cache.texCoordsArrayEnabled))
{
if (enableTexCoordsArray)
{
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
if (Shader::isAvailable())
glCheck(GLEXT_glEnableVertexAttribArray(Shader::TextureCoordinateIndex));
}
else
{
glCheck(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
if (Shader::isAvailable())
glCheck(GLEXT_glDisableVertexAttribArray(Shader::TextureCoordinateIndex));
}
}
// If we switch between non-cache and cache mode or enable texture
@ -302,6 +324,15 @@ void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8));
if (enableTexCoordsArray)
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
if (Shader::isAvailable())
{
glCheck(GLEXT_glVertexAttribPointer(Shader::PositionIndex, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), data + 0));
glCheck(GLEXT_glVertexAttribPointer(Shader::ColorIndex, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), data + 8));
if (enableTexCoordsArray)
glCheck(GLEXT_glVertexAttribPointer(Shader::TextureCoordinateIndex, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), data + 12));
}
}
else if (enableTexCoordsArray && !m_cache.texCoordsArrayEnabled)
{
@ -309,6 +340,9 @@ void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
const char* data = reinterpret_cast<const char*>(m_cache.vertexCache);
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
if (Shader::isAvailable())
glCheck(GLEXT_glVertexAttribPointer(Shader::TextureCoordinateIndex, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), data + 12));
}
drawPrimitives(type, 0, vertexCount);
@ -368,12 +402,24 @@ void RenderTarget::draw(const VertexBuffer& vertexBuffer, std::size_t firstVerte
// Always enable texture coordinates
if (!m_cache.enable || !m_cache.texCoordsArrayEnabled)
{
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
if (Shader::isAvailable())
glCheck(GLEXT_glEnableVertexAttribArray(Shader::TextureCoordinateIndex));
}
glCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const void*>(0)));
glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), reinterpret_cast<const void*>(8)));
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<const void*>(12)));
if (Shader::isAvailable())
{
glCheck(GLEXT_glVertexAttribPointer(Shader::PositionIndex, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const void*>(0)));
glCheck(GLEXT_glVertexAttribPointer(Shader::ColorIndex, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), reinterpret_cast<const void*>(8)));
glCheck(GLEXT_glVertexAttribPointer(Shader::TextureCoordinateIndex, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const void*>(12)));
}
drawPrimitives(vertexBuffer.getPrimitiveType(), firstVertex, vertexCount);
// Unbind vertex buffer
@ -519,10 +565,29 @@ void RenderTarget::resetGLStates()
// Apply the default SFML states
applyBlendMode(BlendAlpha);
applyTexture(NULL);
// Bind no texture
glCheck(glBindTexture(GL_TEXTURE_2D, 0));
// Reset the texture matrix
glCheck(glMatrixMode(GL_TEXTURE));
glCheck(glLoadIdentity());
// Go back to model-view mode
glCheck(glMatrixMode(GL_MODELVIEW));
m_cache.lastTextureId = 0;
if (shaderAvailable)
{
applyShader(NULL);
// Enable all available vertex attribute arrays
glCheck(GLEXT_glEnableVertexAttribArray(Shader::PositionIndex));
glCheck(GLEXT_glEnableVertexAttribArray(Shader::ColorIndex));
glCheck(GLEXT_glEnableVertexAttribArray(Shader::TextureCoordinateIndex));
}
if (vertexBufferAvailable)
glCheck(VertexBuffer::bind(NULL));
@ -622,23 +687,16 @@ void RenderTarget::applyBlendMode(const BlendMode& mode)
////////////////////////////////////////////////////////////
void RenderTarget::applyTransform(const Transform& transform)
void RenderTarget::applyTransform(const Transform&)
{
// No need to call glMatrixMode(GL_MODELVIEW), it is always the
// current mode (for optimization purpose, since it's the most used)
if (transform == Transform::Identity)
glCheck(glLoadIdentity());
else
glCheck(glLoadMatrixf(transform.getMatrix()));
// Function kept for compatibility, no-op now
}
////////////////////////////////////////////////////////////
void RenderTarget::applyTexture(const Texture* texture)
void RenderTarget::applyTexture(const Texture*)
{
Texture::bind(texture, Texture::Pixels);
m_cache.lastTextureId = texture ? texture->m_cacheId : 0;
// Function kept for compatibility, no-op now
}
@ -652,19 +710,45 @@ void RenderTarget::applyShader(const Shader* shader)
////////////////////////////////////////////////////////////
void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states)
{
static const GLfloat identityMatrix[] =
{
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
// First set the persistent OpenGL states if it's the very first call
if (!m_cache.glStatesSet)
resetGLStates();
const GLfloat* modelViewMatrix = identityMatrix;
if (useVertexCache)
{
// Since vertices are transformed, we must use an identity transform to render them
if (!m_cache.enable || !m_cache.useVertexCache)
if (!m_cache.enable ||
!m_cache.useVertexCache ||
(states.shader && (states.shader->m_modelViewMatrixIndex >= 0)))
{
glCheck(glLoadIdentity());
modelViewMatrix = identityMatrix;
}
}
else
{
applyTransform(states.transform);
// No need to call glMatrixMode(GL_MODELVIEW), it is always the
// current mode (for optimization purpose, since it's the most used)
if (states.transform == Transform::Identity)
{
glCheck(glLoadIdentity());
modelViewMatrix = identityMatrix;
}
else
{
glCheck(glLoadMatrixf(states.transform.getMatrix()));
modelViewMatrix = states.transform.getMatrix();
}
}
// Apply the view
@ -675,8 +759,12 @@ void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states)
if (!m_cache.enable || (states.blendMode != m_cache.lastBlendMode))
applyBlendMode(states.blendMode);
bool applyStatesTexture = false;
// Apply the texture
if (!m_cache.enable || (states.texture && states.texture->m_fboAttachment))
if (!m_cache.enable ||
(states.texture && states.texture->m_fboAttachment) ||
(states.shader && (states.shader->m_textureMatrixIndex >= 0)))
{
// If the texture is an FBO attachment, always rebind it
// in order to inform the OpenGL driver that we want changes
@ -684,18 +772,105 @@ void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states)
// This saves us from having to call glFlush() in
// RenderTextureImplFBO which can be quite costly
// See: https://www.khronos.org/opengl/wiki/Memory_Model
applyTexture(states.texture);
applyStatesTexture = true;
}
else
{
Uint64 textureId = states.texture ? states.texture->m_cacheId : 0;
if (textureId != m_cache.lastTextureId)
applyTexture(states.texture);
applyStatesTexture = true;
}
// Temporary matrix we use to store both the texture matrix
// and if required the pre-multiplied modelview-projection matrix
GLfloat tempMatrix[16] =
{
1.f, 0.f, 0.f, 0.f,
0.f, 1.f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
0.f, 0.f, 0.f, 1.f
};
const GLfloat* textureMatrix = identityMatrix;
if (applyStatesTexture)
{
if (states.texture && states.texture->m_texture)
{
// Bind the texture
glCheck(glBindTexture(GL_TEXTURE_2D, states.texture->m_texture));
// If non-normalized coordinates (= pixels) are requested, we need to
// setup scale factors that convert the range [0 .. size] to [0 .. 1]
tempMatrix[0] = 1.f / states.texture->m_actualSize.x;
tempMatrix[5] = 1.f / states.texture->m_actualSize.y;
// If pixels are flipped we must invert the Y axis
if (states.texture->m_pixelsFlipped)
{
tempMatrix[5] = -tempMatrix[5];
tempMatrix[13] = static_cast<float>(states.texture->m_size.y) / states.texture->m_actualSize.y;
}
// Load the matrix
glCheck(glMatrixMode(GL_TEXTURE));
glCheck(glLoadMatrixf(tempMatrix));
textureMatrix = tempMatrix;
// Go back to model-view mode
glCheck(glMatrixMode(GL_MODELVIEW));
}
else
{
// Bind no texture
glCheck(glBindTexture(GL_TEXTURE_2D, 0));
// Reset the texture matrix
glCheck(glMatrixMode(GL_TEXTURE));
glCheck(glLoadIdentity());
textureMatrix = identityMatrix;
// Go back to model-view mode
glCheck(glMatrixMode(GL_MODELVIEW));
}
m_cache.lastTextureId = states.texture ? states.texture->m_cacheId : 0;
}
// Apply the shader
if (states.shader)
{
applyShader(states.shader);
// Set all available uniforms
if (states.shader->m_modelViewMatrixIndex >= 0)
glCheck(GLEXT_glUniformMatrix4fv(states.shader->m_modelViewMatrixIndex, 1, GL_FALSE, modelViewMatrix));
if (states.shader->m_projectionMatrixIndex >= 0)
glCheck(GLEXT_glUniformMatrix4fv(states.shader->m_projectionMatrixIndex, 1, GL_FALSE, m_view.getTransform().getMatrix()));
if (states.shader->m_textureMatrixIndex >= 0)
glCheck(GLEXT_glUniformMatrix4fv(states.shader->m_textureMatrixIndex, 1, GL_FALSE, textureMatrix));
if (states.shader->m_modelViewProjectionMatrixIndex >= 0)
{
const GLfloat* A = m_view.getTransform().getMatrix();
const GLfloat* B = modelViewMatrix;
for (int i = 0; i < 4 * 4; i += 4)
{
for (int j = 0; j < 4; ++j)
{
tempMatrix[i + j] = A[4 * 0 + j] * B[i + 0] +
A[4 * 1 + j] * B[i + 1] +
A[4 * 2 + j] * B[i + 2] +
A[4 * 3 + j] * B[i + 3];
}
}
glCheck(GLEXT_glUniformMatrix4fv(states.shader->m_modelViewProjectionMatrixIndex, 1, GL_FALSE, tempMatrix));
}
}
}
@ -722,7 +897,19 @@ void RenderTarget::cleanupDraw(const RenderStates& states)
// If the texture we used to draw belonged to a RenderTexture, then forcibly unbind that texture.
// This prevents a bug where some drivers do not clear RenderTextures properly.
if (states.texture && states.texture->m_fboAttachment)
applyTexture(NULL);
{
// Bind no texture
glCheck(glBindTexture(GL_TEXTURE_2D, 0));
// Reset the texture matrix
glCheck(glMatrixMode(GL_TEXTURE));
glCheck(glLoadIdentity());
// Go back to model-view mode
glCheck(glMatrixMode(GL_MODELVIEW));
m_cache.lastTextureId = 0;
}
// Re-enable the cache at the end of the draw if it was disabled
m_cache.enable = true;

View File

@ -218,12 +218,29 @@ struct Shader::UniformBinder : private NonCopyable
};
////////////////////////////////////////////////////////////
struct Shader::Interface
{
std::string positionAttribute;
std::string colorAttribute;
std::string texCoordAttribute;
std::string modelViewMatrix;
std::string projectionMatrix;
std::string modelViewProjectionMatrix;
std::string textureMatrix;
};
////////////////////////////////////////////////////////////
Shader::Shader() :
m_shaderProgram (0),
m_currentTexture (-1),
m_textures (),
m_uniforms ()
m_modelViewMatrixIndex (-1),
m_projectionMatrixIndex (-1),
m_modelViewProjectionMatrixIndex(-1),
m_textureMatrixIndex (-1),
m_interface (0)
{
}
@ -231,6 +248,9 @@ m_uniforms ()
////////////////////////////////////////////////////////////
Shader::~Shader()
{
// Destroy the interface specification if we created one
delete m_interface;
TransientContextLock lock;
// Destroy effect program
@ -422,6 +442,90 @@ bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& geomet
}
////////////////////////////////////////////////////////////
Shader& Shader::setPositionAttribute(const std::string& positionAttribute)
{
if (!m_interface)
m_interface = new Interface;
m_interface->positionAttribute = positionAttribute;
return *this;
}
////////////////////////////////////////////////////////////
Shader& Shader::setColorAttribute(const std::string& name)
{
if (!m_interface)
m_interface = new Interface;
m_interface->colorAttribute = name;
return *this;
}
////////////////////////////////////////////////////////////
Shader& Shader::setTextureCoordinateAttribute(const std::string& name)
{
if (!m_interface)
m_interface = new Interface;
m_interface->texCoordAttribute = name;
return *this;
}
////////////////////////////////////////////////////////////
Shader& Shader::setModelViewMatrix(const std::string& name)
{
if (!m_interface)
m_interface = new Interface;
m_interface->modelViewMatrix = name;
return *this;
}
////////////////////////////////////////////////////////////
Shader& Shader::setProjectionMatrix(const std::string& name)
{
if (!m_interface)
m_interface = new Interface;
m_interface->projectionMatrix = name;
return *this;
}
////////////////////////////////////////////////////////////
Shader& Shader::setModelViewProjectionMatrix(const std::string& name)
{
if (!m_interface)
m_interface = new Interface;
m_interface->modelViewProjectionMatrix = name;
return *this;
}
////////////////////////////////////////////////////////////
Shader& Shader::setTextureMatrix(const std::string& name)
{
if (!m_interface)
m_interface = new Interface;
m_interface->textureMatrix = name;
return *this;
}
////////////////////////////////////////////////////////////
void Shader::setUniform(const std::string& name, float x)
{
@ -855,6 +959,11 @@ bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCod
m_textures.clear();
m_uniforms.clear();
m_modelViewMatrixIndex = -1;
m_projectionMatrixIndex = -1;
m_modelViewProjectionMatrixIndex = -1;
m_textureMatrixIndex = -1;
// Create the program
GLEXT_GLhandle shaderProgram;
glCheck(shaderProgram = GLEXT_glCreateProgramObject());
@ -942,6 +1051,19 @@ bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCod
glCheck(GLEXT_glDeleteObject(fragmentShader));
}
// Bind all user-specified attributes to our pre-defined indices
if (m_interface)
{
if (!m_interface->positionAttribute.empty())
glCheck(GLEXT_glBindAttribLocation(shaderProgram, PositionIndex, m_interface->positionAttribute.c_str()));
if (!m_interface->colorAttribute.empty())
glCheck(GLEXT_glBindAttribLocation(shaderProgram, ColorIndex, m_interface->colorAttribute.c_str()));
if (!m_interface->texCoordAttribute.empty())
glCheck(GLEXT_glBindAttribLocation(shaderProgram, TextureCoordinateIndex, m_interface->texCoordAttribute.c_str()));
}
// Link the program
glCheck(GLEXT_glLinkProgram(shaderProgram));
@ -960,6 +1082,53 @@ bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCod
m_shaderProgram = castFromGlHandle(shaderProgram);
if (m_interface)
{
// Check if attribute binding resulted in the attributes having the indices we expect
if (!m_interface->positionAttribute.empty())
{
int location = -1;
glCheck(location = GLEXT_glGetAttribLocation(shaderProgram, m_interface->positionAttribute.c_str()));
if (location != PositionIndex)
err() << "Failed to bind vertex position attribute to index 0" << std::endl;
}
if (!m_interface->colorAttribute.empty())
{
int location = -1;
glCheck(location = GLEXT_glGetAttribLocation(shaderProgram, m_interface->colorAttribute.c_str()));
if (location != ColorIndex)
err() << "Failed to bind vertex color attribute to index 1" << std::endl;
}
if (!m_interface->texCoordAttribute.empty())
{
int location = -1;
glCheck(location = GLEXT_glGetAttribLocation(shaderProgram, m_interface->texCoordAttribute.c_str()));
if (location != TextureCoordinateIndex)
err() << "Failed to bind vertex texture coordinate attribute to index 2" << std::endl;
}
// Populate the drawable interface uniform indices
if (!m_interface->modelViewMatrix.empty())
m_modelViewMatrixIndex = getUniformLocation(m_interface->modelViewMatrix);
if (!m_interface->projectionMatrix.empty())
m_projectionMatrixIndex = getUniformLocation(m_interface->projectionMatrix);
if (!m_interface->modelViewProjectionMatrix.empty())
m_modelViewProjectionMatrixIndex = getUniformLocation(m_interface->modelViewProjectionMatrix);
if (!m_interface->textureMatrix.empty())
m_textureMatrixIndex = getUniformLocation(m_interface->textureMatrix);
}
// Force an OpenGL flush, so that the shader will appear updated
// in all contexts immediately (solves problems in multi-threaded apps)
glCheck(glFlush());