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:
parent
63e07cec84
commit
d7bd00afc0
125 changed files with 1606 additions and 2348 deletions
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue