FS#25 - Change sf::PostFx to a more general purpose pixel shader class (sf::Shader)

Updated the PostFx sample, renamed to Shader
Renamed all the static X::CanUseX() functions to X::IsAvailable() to make the API more consistent
Moved .def files from /build/VC200X to /src in CSFML
Minors fixes in CSFML

git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1258 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
LaurentGom 2009-11-03 09:04:40 +00:00
parent 63e07cec84
commit d7bd00afc0
125 changed files with 1606 additions and 2348 deletions

View file

@ -62,7 +62,7 @@ SoundRecorder::~SoundRecorder()
void SoundRecorder::Start(unsigned int sampleRate)
{
// Check if the device can do audio capture
if (!CanCapture())
if (!IsAvailable())
{
std::cerr << "Failed to start capture : your system cannot capture audio data (call SoundRecorder::CanCapture to check it)" << std::endl;
return;
@ -119,7 +119,7 @@ unsigned int SoundRecorder::GetSampleRate() const
////////////////////////////////////////////////////////////
bool SoundRecorder::CanCapture()
bool SoundRecorder::IsAvailable()
{
return priv::AudioDevice::IsExtensionSupported("ALC_EXT_CAPTURE");
}

View file

@ -27,6 +27,8 @@
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Batch.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/Shader.hpp>
#include <SFML/Graphics/GeometryRenderer.hpp>
#include <SFML/Graphics/GLCheck.hpp>
@ -35,8 +37,9 @@ namespace sf
namespace priv
{
////////////////////////////////////////////////////////////
Batch::Batch(const Image* texture, Blend::Mode blendMode, const IntRect& viewport) :
Batch::Batch(const Image* texture, const Shader* shader, Blend::Mode blendMode, const IntRect& viewport) :
myTexture (texture),
myShader (shader),
myBlendMode(blendMode),
myViewport (viewport),
myStart (0),
@ -46,9 +49,10 @@ myCount (0)
////////////////////////////////////////////////////////////
bool Batch::Matches(const Image* texture, Blend::Mode blendMode, const IntRect& viewport) const
bool Batch::Matches(const Image* texture, const Shader* shader, Blend::Mode blendMode, const IntRect& viewport) const
{
return myTexture == texture &&
myShader == shader &&
myBlendMode == blendMode &&
myViewport.Left == viewport.Left &&
myViewport.Top == viewport.Top &&
@ -72,21 +76,7 @@ void Batch::End(std::size_t index)
////////////////////////////////////////////////////////////
std::size_t Batch::GetStartIndex() const
{
return myStart;
}
////////////////////////////////////////////////////////////
std::size_t Batch::GetIndexCount() const
{
return myCount;
}
////////////////////////////////////////////////////////////
void Batch::ApplyStates() const
void Batch::Render(GeometryRenderer& renderer) const
{
// Set the viewport
GLCheck(glViewport(myViewport.Left, myViewport.Top, myViewport.GetSize().x, myViewport.GetSize().y));
@ -116,6 +106,17 @@ void Batch::ApplyStates() const
myTexture->Bind();
else
GLCheck(glDisable(GL_TEXTURE_2D));
// Bind the pixel shader
if (myShader)
myShader->Bind();
// Render the triangles
renderer.RenderTriangles(myStart, myCount);
// Disable the pixel shader
if (myShader)
myShader->Unbind();
}
} // namespace priv

View file

@ -36,9 +36,12 @@
namespace sf
{
class Image;
class Shader;
namespace priv
{
class GeometryRenderer;
////////////////////////////////////////////////////////////
/// \brief Batch of geometry / render states to render
///
@ -50,22 +53,24 @@ public :
////////////////////////////////////////////////////////////
/// \brief Construct the batch with its render states
///
/// \param texture Texture to use
/// \param texture Texture to use
/// \param shader Pixel shader
/// \param blendMode Blending mode
/// \param viewport Target viewport
/// \param viewport Target viewport
///
////////////////////////////////////////////////////////////
Batch(const Image* texture = NULL, Blend::Mode blendMode = Blend::Alpha, const IntRect& viewport = IntRect());
Batch(const Image* texture, const Shader* shader, Blend::Mode blendMode, const IntRect& viewport);
////////////////////////////////////////////////////////////
/// \brief Check if the batch matches a set of render states
///
/// \param texture Texture to use
/// \param texture Texture to use
/// \param shader Pixel shader
/// \param blendMode Blending mode
/// \param viewport Target viewport
/// \param viewport Target viewport
///
////////////////////////////////////////////////////////////
bool Matches(const Image* texture, Blend::Mode blendMode, const IntRect& viewport) const;
bool Matches(const Image* texture, const Shader* shader, Blend::Mode blendMode, const IntRect& viewport) const;
////////////////////////////////////////////////////////////
/// \brief Setup the start index of the batch
@ -84,37 +89,24 @@ public :
void End(std::size_t index);
////////////////////////////////////////////////////////////
/// \brief Return the start index of the batch
/// \brief Render the contents of the batch
///
/// \return Start index
/// \param renderer Renderer to use for rendering
///
////////////////////////////////////////////////////////////
std::size_t GetStartIndex() const;
////////////////////////////////////////////////////////////
/// \brief Return the number of indices to render with this batch
///
/// \return Index count
///
////////////////////////////////////////////////////////////
std::size_t GetIndexCount() const;
////////////////////////////////////////////////////////////
/// \brief Apply the render states of the batch
///
////////////////////////////////////////////////////////////
void ApplyStates() const;
void Render(GeometryRenderer& renderer) const;
private :
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
const Image* myTexture; ///< Texture used by the batch
Blend::Mode myBlendMode; ///< Blending mode used by the batch
IntRect myViewport; ///< Target viewport for the batch
std::size_t myStart; ///< Index of the first index to render with this batch
std::size_t myCount; ///< Number of indices to render with this batch
const Image* myTexture; ///< Texture used by the batch
const Shader* myShader; ///< Pixel shader used by the batch
Blend::Mode myBlendMode; ///< Blending mode used by the batch
IntRect myViewport; ///< Target viewport for the batch
std::size_t myStart; ///< Index of the first index to render with this batch
std::size_t myCount; ///< Number of indices to render with this batch
};
} // namespace priv

View file

@ -69,10 +69,10 @@ public :
/// This function is called once before all the triangles
/// are rendered.
///
/// \param vertices Pointer to the vertex array
/// \param vertices Pointer to the vertex array
/// \param verticesCount Number of vertices to render
/// \param indices Pointer to the index array
/// \param indicesCount Number of indices to render
/// \param indices Pointer to the index array
/// \param indicesCount Number of indices to render
///
////////////////////////////////////////////////////////////
virtual void Begin(const float* vertices, std::size_t verticesCount, const unsigned int* indices, std::size_t indicesCount) = 0;

View file

@ -59,7 +59,7 @@ RenderImage::~RenderImage()
bool RenderImage::Create(unsigned int width, unsigned int height, bool depthBuffer)
{
// Make sure that render-images are supported
if (!CanUseRenderImage())
if (!IsAvailable())
{
std::cerr << "Impossible to create render image (your system doesn't support this feature)" << std::endl;
return false;
@ -158,7 +158,7 @@ const Image& RenderImage::GetImage() const
////////////////////////////////////////////////////////////
/// Check whether the system supports render images or not
////////////////////////////////////////////////////////////
bool RenderImage::CanUseRenderImage()
bool RenderImage::IsAvailable()
{
return priv::RenderImageImplFBO::IsSupported() ||
priv::RenderImageImplPBuffer::IsSupported();

View file

@ -165,18 +165,25 @@ void RenderQueue::SetTexture(const Image* texture)
}
////////////////////////////////////////////////////////////
void RenderQueue::SetShader(const Shader* shader)
{
myCurrentShader = shader;
}
////////////////////////////////////////////////////////////
void RenderQueue::BeginBatch()
{
// Check if the current batch differs from the new render states
if (!myCurrentBatch || !myCurrentBatch->Matches(myCurrentTexture, myCurrentBlendMode, myCurrentViewport))
if (!myCurrentBatch || !myCurrentBatch->Matches(myCurrentTexture, myCurrentShader, myCurrentBlendMode, myCurrentViewport))
{
// Close the current batch
if (myCurrentBatch)
myCurrentBatch->End(myCurrentIndexCount);
// Create a new one
priv::Batch batch(myCurrentTexture, myCurrentBlendMode, myCurrentViewport);
priv::Batch batch(myCurrentTexture, myCurrentShader, myCurrentBlendMode, myCurrentViewport);
myBatches.push_back(batch);
myCurrentBatch = &myBatches.back();
myCurrentBatch->Begin(myCurrentIndexCount);
@ -300,10 +307,7 @@ void RenderQueue::Render()
// Render the batches in order
for (BatchArray::const_iterator it = myBatches.begin(); it != myBatches.end(); ++it)
{
it->ApplyStates();
myRenderer->RenderTriangles(it->GetStartIndex(), it->GetIndexCount());
}
it->Render(*myRenderer);
// Stop rendering
myRenderer->End();
@ -325,13 +329,10 @@ void RenderQueue::Render()
////////////////////////////////////////////////////////////
void RenderQueue::Clear()
{
// Reset the vertex and index counts
myCurrentVertexCount = 0;
myCurrentIndexCount = 0;
// Clear the batches
myBatches.clear();
myCurrentBatch = NULL;
myCurrentVertexCount = 0;
myCurrentIndexCount = 0;
}
} // namespace sf

View file

@ -85,6 +85,34 @@ void RenderTarget::Draw(const Drawable& object)
// Setup the projection matrix
myRenderQueue.SetProjection(myCurrentView->GetMatrix());
// Setup the shader
myRenderQueue.SetShader(NULL);
// Let the object draw itself
object.Draw(*this, myRenderQueue);
// Restore the previous render states
myRenderQueue.PopStates();
}
////////////////////////////////////////////////////////////
/// Draw something into the target with a shader
////////////////////////////////////////////////////////////
void RenderTarget::Draw(const Drawable& object, const Shader& shader)
{
// Save the current render states
myRenderQueue.PushStates();
// Setup the viewport
myRenderQueue.SetViewport(GetViewport(*myCurrentView));
// Setup the projection matrix
myRenderQueue.SetProjection(myCurrentView->GetMatrix());
// Setup the shader
myRenderQueue.SetShader(&shader);
// Let the object draw itself
object.Draw(*this, myRenderQueue);

View file

@ -26,54 +26,45 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/PostFX.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Shader.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <fstream>
#include <iostream>
#include <set>
#include <sstream>
namespace sf
{
////////////////////////////////////////////////////////////
/// Default constructor
// Static member data
////////////////////////////////////////////////////////////
PostFX::PostFX() :
myShaderProgram(0)
const Image Shader::CurrentTexture;
////////////////////////////////////////////////////////////
Shader::Shader() :
myShaderProgram (0),
myCurrentTexture(-1)
{
// Make sure that GLEW is initialized
priv::EnsureGlewInit();
// No filtering on frame buffer
myFrameBuffer.SetSmooth(false);
}
////////////////////////////////////////////////////////////
/// Copy constructor
////////////////////////////////////////////////////////////
PostFX::PostFX(const PostFX& copy) :
Drawable (copy),
Shader::Shader(const Shader& copy) :
myShaderProgram (0),
myCurrentTexture(copy.myCurrentTexture),
myTextures (copy.myTextures),
myFragmentShader(copy.myFragmentShader),
myFrameBuffer (copy.myFrameBuffer)
myFragmentShader(copy.myFragmentShader)
{
// No filtering on frame buffer
myFrameBuffer.SetSmooth(false);
// Create the shaders and the program
if (copy.myShaderProgram)
CreateProgram();
CompileProgram();
}
////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////
PostFX::~PostFX()
Shader::~Shader()
{
// Destroy effect program
if (myShaderProgram)
@ -82,50 +73,39 @@ PostFX::~PostFX()
////////////////////////////////////////////////////////////
/// Load the effect from a file
////////////////////////////////////////////////////////////
bool PostFX::LoadFromFile(const std::string& filename)
bool Shader::LoadFromFile(const std::string& filename)
{
// Open the file
std::ifstream file(filename.c_str());
if (!file)
{
std::cerr << "Failed to open effect file \"" << filename << "\"" << std::endl;
std::cerr << "Failed to open shader file \"" << filename << "\"" << std::endl;
return false;
}
// Apply the preprocessing pass to the fragment shader code
myFragmentShader = PreprocessEffect(file);
// Read the shader code from the file
std::string line;
while (std::getline(file, line))
myFragmentShader += line + "\n";
// Create the shaders and the program
CreateProgram();
return myShaderProgram != 0;
return CompileProgram();
}
////////////////////////////////////////////////////////////
/// Load the effect from a text in memory
////////////////////////////////////////////////////////////
bool PostFX::LoadFromMemory(const std::string& effect)
bool Shader::LoadFromMemory(const std::string& shader)
{
// Open a stream and copy the effect code
std::istringstream stream(effect.c_str());
// Apply the preprocessing pass to the fragment shader code
myFragmentShader = PreprocessEffect(stream);
// Save the shader code
myFragmentShader = shader;
// Create the shaders and the program
CreateProgram();
return myShaderProgram != 0;
return CompileProgram();
}
////////////////////////////////////////////////////////////
/// Change a parameter of the effect (1 float)
////////////////////////////////////////////////////////////
void PostFX::SetParameter(const std::string& name, float x)
void Shader::SetParameter(const std::string& name, float x)
{
if (myShaderProgram)
{
@ -137,7 +117,7 @@ void PostFX::SetParameter(const std::string& name, float x)
if (location != -1)
GLCheck(glUniform1fARB(location, x));
else
std::cerr << "Parameter \"" << name << "\" not found in post-effect" << std::endl;
std::cerr << "Parameter \"" << name << "\" not found in shader" << std::endl;
// Disable program
GLCheck(glUseProgramObjectARB(0));
@ -146,9 +126,7 @@ void PostFX::SetParameter(const std::string& name, float x)
////////////////////////////////////////////////////////////
/// Change a parameter of the effect (2 floats)
////////////////////////////////////////////////////////////
void PostFX::SetParameter(const std::string& name, float x, float y)
void Shader::SetParameter(const std::string& name, float x, float y)
{
if (myShaderProgram)
{
@ -160,7 +138,7 @@ void PostFX::SetParameter(const std::string& name, float x, float y)
if (location != -1)
GLCheck(glUniform2fARB(location, x, y));
else
std::cerr << "Parameter \"" << name << "\" not found in post-effect" << std::endl;
std::cerr << "Parameter \"" << name << "\" not found in shader" << std::endl;
// Disable program
GLCheck(glUseProgramObjectARB(0));
@ -169,9 +147,7 @@ void PostFX::SetParameter(const std::string& name, float x, float y)
////////////////////////////////////////////////////////////
/// Change a parameter of the effect (3 floats)
////////////////////////////////////////////////////////////
void PostFX::SetParameter(const std::string& name, float x, float y, float z)
void Shader::SetParameter(const std::string& name, float x, float y, float z)
{
if (myShaderProgram)
{
@ -183,7 +159,7 @@ void PostFX::SetParameter(const std::string& name, float x, float y, float z)
if (location != -1)
GLCheck(glUniform3fARB(location, x, y, z));
else
std::cerr << "Parameter \"" << name << "\" not found in post-effect" << std::endl;
std::cerr << "Parameter \"" << name << "\" not found in shader" << std::endl;
// Disable program
GLCheck(glUseProgramObjectARB(0));
@ -192,9 +168,7 @@ void PostFX::SetParameter(const std::string& name, float x, float y, float z)
////////////////////////////////////////////////////////////
/// Change a parameter of the effect (4 floats)
////////////////////////////////////////////////////////////
void PostFX::SetParameter(const std::string& name, float x, float y, float z, float w)
void Shader::SetParameter(const std::string& name, float x, float y, float z, float w)
{
if (myShaderProgram)
{
@ -206,7 +180,7 @@ void PostFX::SetParameter(const std::string& name, float x, float y, float z, fl
if (location != -1)
GLCheck(glUniform4fARB(location, x, y, z, w));
else
std::cerr << "Parameter \"" << name << "\" not found in post-effect" << std::endl;
std::cerr << "Parameter \"" << name << "\" not found in shader" << std::endl;
// Disable program
GLCheck(glUseProgramObjectARB(0));
@ -215,16 +189,28 @@ void PostFX::SetParameter(const std::string& name, float x, float y, float z, fl
////////////////////////////////////////////////////////////
/// Set a texture parameter
////////////////////////////////////////////////////////////
void PostFX::SetTexture(const std::string& name, const Image* texture)
void Shader::SetParameter(const std::string& name, const Vector2f& v)
{
// Check that the current texture unit is available
SetParameter(name, v.x, v.y);
}
////////////////////////////////////////////////////////////
void Shader::SetParameter(const std::string& name, const Vector3f& v)
{
SetParameter(name, v.x, v.y, v.z);
}
////////////////////////////////////////////////////////////
void Shader::SetTexture(const std::string& name, const Image& texture)
{
// Check if there is a texture unit available
GLint maxUnits;
GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &maxUnits));
if (myTextures.size() >= static_cast<std::size_t>(maxUnits))
if (myTextures.size() + 1 >= static_cast<std::size_t>(maxUnits))
{
std::cerr << "Impossible to use texture \"" << name << "\" for post-effect : all available texture units are used" << std::endl;
std::cerr << "Impossible to use texture \"" << name << "\" for shader: all available texture units are used" << std::endl;
return;
}
@ -232,35 +218,93 @@ void PostFX::SetTexture(const std::string& name, const Image* texture)
int location = glGetUniformLocationARB(myShaderProgram, name.c_str());
if (location == -1)
{
std::cerr << "Texture \"" << name << "\" not found in post-effect" << std::endl;
std::cerr << "Texture \"" << name << "\" not found in Shader" << std::endl;
return;
}
// Store the texture for later use
myTextures[name] = texture ? texture : &myFrameBuffer;
if ((texture.GetWidth() > 0) && (texture.GetHeight() > 0))
{
myTextures[location] = &texture;
}
else
{
// An invalid size means that texture is Shader::CurrentTexture
myCurrentTexture = location;
}
}
////////////////////////////////////////////////////////////
/// Assignment operator
////////////////////////////////////////////////////////////
PostFX& PostFX::operator =(const PostFX& other)
void Shader::Bind() const
{
PostFX temp(other);
// Make sure that we have a valid program
if (!myShaderProgram)
return;
// Enable the program
GLCheck(glUseProgramObjectARB(myShaderProgram));
// Bind the textures
TextureTable::const_iterator it = myTextures.begin();
for (std::size_t i = 0; i < myTextures.size(); ++i)
{
GLint index = i + 1;
GLCheck(glUniform1iARB(it->first, index));
GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB + index));
it->second->Bind();
it++;
}
// Make sure that the texture unit which is left active is the number 0
GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB));
// Bind the current texture
if (myCurrentTexture != -1)
GLCheck(glUniform1iARB(myCurrentTexture, 0));
}
////////////////////////////////////////////////////////////
void Shader::Unbind() const
{
// First make sure that the program is currently bound
GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
if (!myShaderProgram || (myShaderProgram != program))
return;
// Unbind the program
GLCheck(glUseProgramObjectARB(0));
// Disable texture units
for (std::size_t i = 0; i < myTextures.size(); ++i)
{
GLint index = i + 1;
GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB + index));
GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
}
// Make sure that the texture unit which is left active is the number 0
GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB));
}
////////////////////////////////////////////////////////////
Shader& Shader::operator =(const Shader& right)
{
Shader temp(right);
std::swap(myShaderProgram, temp.myShaderProgram);
std::swap(myCurrentTexture, temp.myCurrentTexture);
std::swap(myTextures, temp.myTextures);
std::swap(myFragmentShader, temp.myFragmentShader);
std::swap(myFrameBuffer, temp.myFrameBuffer);
return *this;
}
////////////////////////////////////////////////////////////
/// Tell whether or not the system supports post-effects
////////////////////////////////////////////////////////////
bool PostFX::CanUsePostFX()
bool Shader::IsAvailable()
{
// Make sure that GLEW is initialized
priv::EnsureGlewInit();
@ -273,163 +317,25 @@ bool PostFX::CanUsePostFX()
////////////////////////////////////////////////////////////
/// /see Drawable::Render
////////////////////////////////////////////////////////////
void PostFX::Render(RenderTarget& target, RenderQueue&) const
bool Shader::CompileProgram()
{
// Check that we have a valid program
if (!myShaderProgram)
return;
// Copy the current framebuffer pixels to our frame buffer texture
// The ugly cast is temporary until PostFx are rewritten :)
RenderWindow& window = static_cast<RenderWindow&>(target);
myFrameBuffer.CopyScreen(window);
window.SetActive();
// Enable program
GLCheck(glUseProgramObjectARB(myShaderProgram));
// Bind textures
TextureTable::const_iterator it = myTextures.begin();
for (std::size_t i = 0; i < myTextures.size(); ++i)
// First make sure that we can use shaders!
if (!IsAvailable())
{
int location = glGetUniformLocationARB(myShaderProgram, it->first.c_str());
GLCheck(glUniform1iARB(location, static_cast<GLint>(i)));
GLCheck(glActiveTextureARB(static_cast<GLenum>(GL_TEXTURE0_ARB + i)));
it->second->Bind();
it++;
}
// Compute the texture coordinates (it may not be (0, 0, 1, 1) if the texture is padded or flipped)
IntRect frameBufferRect(0, 0, myFrameBuffer.GetWidth(), myFrameBuffer.GetHeight());
FloatRect texCoords = myFrameBuffer.GetTexCoords(frameBufferRect);
// Set the projection matrix to the identity so that the screen coordinates are in the range [-1, 1]
GLCheck(glMatrixMode(GL_PROJECTION));
GLCheck(glLoadIdentity());
// Render a fullscreen quad using the effect on our framebuffer
glBegin(GL_QUADS);
glTexCoord2f(texCoords.Left, texCoords.Top); glVertex2f(-1, 1);
glTexCoord2f(texCoords.Right, texCoords.Top); glVertex2f( 1, 1);
glTexCoord2f(texCoords.Right, texCoords.Bottom); glVertex2f( 1, -1);
glTexCoord2f(texCoords.Left, texCoords.Bottom); glVertex2f(-1, -1);
glEnd();
// Disable program
GLCheck(glUseProgramObjectARB(0));
// Disable texture units
for (std::size_t i = 0; i < myTextures.size(); ++i)
{
GLCheck(glActiveTextureARB(static_cast<GLenum>(GL_TEXTURE0_ARB + i)));
GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
}
GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB));
}
////////////////////////////////////////////////////////////
/// Preprocess a SFML effect file
/// to convert it to a valid GLSL fragment shader
////////////////////////////////////////////////////////////
std::string PostFX::PreprocessEffect(std::istream& file)
{
// Initialize output string
std::set<std::string> textures;
std::string out = "";
// Variable declarations
std::string line;
while (std::getline(file, line) && (line.substr(0, 6) != "effect"))
{
// Remove the ending '\r', if any
if (!line.empty() && (line[line.size() - 1] == '\r'))
line.erase(line.size() - 1);
// Skip empty lines
if (line == "")
continue;
// Extract variables type and name and convert them
std::string type, name;
std::istringstream iss(line);
if (!(iss >> type >> name))
{
std::cerr << "Post-effect error : invalid declaration (should be \"[type][name]\")" << std::endl
<< "> " << line << std::endl;
return "";
}
if (type == "texture")
{
// Textures need some checking and conversion
if (textures.find(name) != textures.end())
{
std::cerr << "Post-effect error : texture \"" << name << "\" already exists" << std::endl;
return "";
}
out += "uniform sampler2D " + name + ";\n";
textures.insert(name);
}
else
{
// Other types are just copied to output with "uniform" prefix
out += "uniform " + type + " " + name + ";\n";
}
}
// Effect code
out += "void main()\n";
while (std::getline(file, line))
{
// Replace any texture lookup "T(" by "texture2D(T, "
for (std::set<std::string>::const_iterator it = textures.begin(); it != textures.end(); ++it)
{
std::string::size_type pos = line.find(*it);
if (pos != std::string::npos)
line.replace(pos, it->size() + 1, "texture2D(" + *it + ", ");
}
// Replace "_in" by "gl_TexCoord[0].xy"
for (std::string::size_type pos = line.find("_in"); pos != std::string::npos; pos = line.find("_in"))
line.replace(pos, 3, "gl_TexCoord[0].xy");
// Replace "_out" by "gl_FragColor"
for (std::string::size_type pos = line.find("_out"); pos != std::string::npos; pos = line.find("_out"))
line.replace(pos, 4, "gl_FragColor");
// Write modified line to output string
out += line + "\n";
}
return out;
}
////////////////////////////////////////////////////////////
/// Create the program and attach the shaders
////////////////////////////////////////////////////////////
void PostFX::CreateProgram()
{
// Check that we can use post-FX !
if (!CanUsePostFX())
{
std::cerr << "Failed to create a PostFX : your system doesn't support effects" << std::endl;
return;
std::cerr << "Failed to create a shader: your system doesn't support shaders" << std::endl;
return false;
}
// Destroy effect program if it was already created
if (myShaderProgram)
GLCheck(glDeleteObjectARB(myShaderProgram));
// Define vertex shader source (we provide it directly as it doesn't have to change)
// Define the vertex shader source (we provide it directly as it doesn't have to change)
static const std::string vertexShaderSrc =
"void main()"
"{"
" gl_TexCoord[0] = gl_MultiTexCoord0;"
" gl_FrontColor = gl_Color;"
" gl_Position = ftransform();"
"}";
@ -455,26 +361,26 @@ void PostFX::CreateProgram()
{
char log[1024];
GLCheck(glGetInfoLogARB(vertexShader, sizeof(log), 0, log));
std::cerr << "Failed to compile post-effect :" << std::endl
std::cerr << "Failed to compile shader:" << std::endl
<< log << std::endl;
GLCheck(glDeleteObjectARB(vertexShader));
GLCheck(glDeleteObjectARB(fragmentShader));
GLCheck(glDeleteObjectARB(myShaderProgram));
myShaderProgram = 0;
return;
return false;
}
GLCheck(glGetObjectParameterivARB(fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
if (success == GL_FALSE)
{
char log[1024];
GLCheck(glGetInfoLogARB(fragmentShader, sizeof(log), 0, log));
std::cerr << "Failed to compile post-effect :" << std::endl
std::cerr << "Failed to compile shader:" << std::endl
<< log << std::endl;
GLCheck(glDeleteObjectARB(vertexShader));
GLCheck(glDeleteObjectARB(fragmentShader));
GLCheck(glDeleteObjectARB(myShaderProgram));
myShaderProgram = 0;
return;
return false;
}
// Attach the shaders to the program
@ -495,12 +401,14 @@ void PostFX::CreateProgram()
// Oops... link errors
char log[1024];
GLCheck(glGetInfoLogARB(myShaderProgram, sizeof(log), 0, log));
std::cerr << "Failed to link post-effect :" << std::endl
std::cerr << "Failed to link shader:" << std::endl
<< log << std::endl;
GLCheck(glDeleteObjectARB(myShaderProgram));
myShaderProgram = 0;
return;
return false;
}
return true;
}
} // namespace sf