mirror of
https://github.com/SFML/SFML.git
synced 2024-11-24 20:31:05 +08:00
Implemented initial support for modular rendering backends. Currently only the existing GL1 renderer implementation is available.
This commit is contained in:
parent
80c3bdc23c
commit
fcd52afb5c
@ -41,6 +41,7 @@
|
||||
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||
#include <SFML/Graphics/Rect.hpp>
|
||||
#include <SFML/Graphics/RectangleShape.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderStates.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/RenderTexture.hpp>
|
||||
|
@ -30,13 +30,8 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/Color.hpp>
|
||||
#include <SFML/Graphics/Rect.hpp>
|
||||
#include <SFML/Graphics/View.hpp>
|
||||
#include <SFML/Graphics/Transform.hpp>
|
||||
#include <SFML/Graphics/BlendMode.hpp>
|
||||
#include <SFML/Graphics/RenderStates.hpp>
|
||||
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||
#include <SFML/Graphics/Vertex.hpp>
|
||||
#include <SFML/System/NonCopyable.hpp>
|
||||
|
||||
|
||||
@ -44,6 +39,13 @@ namespace sf
|
||||
{
|
||||
class Drawable;
|
||||
class VertexBuffer;
|
||||
class View;
|
||||
class Vertex;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
class RenderTargetImpl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Base class for all render targets (window, texture, ...)
|
||||
@ -385,96 +387,10 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply the current view
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyCurrentView();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new blending mode
|
||||
///
|
||||
/// \param mode Blending mode to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyBlendMode(const BlendMode& mode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new transform
|
||||
///
|
||||
/// \param transform Transform to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyTransform(const Transform& transform);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new texture
|
||||
///
|
||||
/// \param texture Texture to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyTexture(const Texture* texture);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new shader
|
||||
///
|
||||
/// \param shader Shader to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyShader(const Shader* shader);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Setup environment for drawing
|
||||
///
|
||||
/// \param useVertexCache Are we going to use the vertex cache?
|
||||
/// \param states Render states to use for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setupDraw(bool useVertexCache, const RenderStates& states);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Draw the primitives
|
||||
///
|
||||
/// \param type Type of primitives to draw
|
||||
/// \param firstVertex Index of the first vertex to use when drawing
|
||||
/// \param vertexCount Number of vertices to use when drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Clean up environment after drawing
|
||||
///
|
||||
/// \param states Render states used for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void cleanupDraw(const RenderStates& states);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Render states cache
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct StatesCache
|
||||
{
|
||||
enum {VertexCacheSize = 4};
|
||||
|
||||
bool enable; ///< Is the cache enabled?
|
||||
bool glStatesSet; ///< Are our internal GL states set yet?
|
||||
bool viewChanged; ///< Has the current view changed since last draw?
|
||||
BlendMode lastBlendMode; ///< Cached blending mode
|
||||
Uint64 lastTextureId; ///< Cached texture
|
||||
bool texCoordsArrayEnabled; ///< Is GL_TEXTURE_COORD_ARRAY client state enabled?
|
||||
bool useVertexCache; ///< Did we previously use the vertex cache?
|
||||
Vertex vertexCache[VertexCacheSize]; ///< Pre-transformed vertices cache
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
View m_defaultView; ///< Default view
|
||||
View m_view; ///< Current view
|
||||
StatesCache m_cache; ///< Render states cache
|
||||
Uint64 m_id; ///< Unique number that identifies the RenderTarget
|
||||
priv::RenderTargetImpl* m_impl; ///< Platform/hardware specific implementation
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
|
117
include/SFML/Graphics/Renderer.hpp
Normal file
117
include/SFML/Graphics/Renderer.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_RENDERER_HPP
|
||||
#define SFML_RENDERER_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace Renderer
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \ingroup graphics
|
||||
/// \brief Enumeration of the renderer types
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
enum
|
||||
{
|
||||
Legacy = 0, ///< Let SFML choose the renderer for best compatibility
|
||||
OpenGL1 = 1 << 0, ///< OpenGL 1.x renderer
|
||||
|
||||
Default = Legacy ///< Default renderer
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \ingroup graphics
|
||||
/// \brief Get the available renderers
|
||||
///
|
||||
/// SFML determines at runtime the renderers that are supported
|
||||
/// on the target system. These are returned by this function.
|
||||
/// When calling setRenderers(), only renderers returned by this
|
||||
/// function are allowed to be specified.
|
||||
///
|
||||
/// \return Renderers supported on the current system
|
||||
///
|
||||
/// \see setRenderers, getRenderer
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Uint32 SFML_GRAPHICS_API getAvailableRenderers();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \ingroup graphics
|
||||
/// \brief Set the renderers SFML is allowed to pick from
|
||||
///
|
||||
/// Before anything graphics related is performed, it is possible
|
||||
/// to specify via this function the renderers that SFML is allowed
|
||||
/// to choose from to perform any future rendering operations.
|
||||
///
|
||||
/// The renderers available on the target system can be retrieved
|
||||
/// via getAvailableRenderers().
|
||||
///
|
||||
/// Once SFML has chosen a renderer, it is final until the next time
|
||||
/// the application is run. As such, this function must be called as
|
||||
/// soon as possible if the user decides they want influence the
|
||||
/// selection process in any way.
|
||||
///
|
||||
/// If the applicable renderers are not explicitly set by calling this
|
||||
/// function, SFML will automatically choose from everything that is
|
||||
/// supported on the target system.
|
||||
///
|
||||
/// \param renderers Bit-wise OR of renderers SFML is allowed to pick from
|
||||
///
|
||||
/// \see getAvailableRenderers, getRenderer
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void SFML_GRAPHICS_API setRenderers(Uint32 renderers);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \ingroup graphics
|
||||
/// \brief Get the renderer SFML has selected to use
|
||||
///
|
||||
/// Calling this function will force SFML to finalize its decision
|
||||
/// on which renderer it wants to make use of if it has not already
|
||||
/// done so. The selected renderer is then returned by this function.
|
||||
///
|
||||
/// After this function has been called either from user code or
|
||||
/// internally within SFML itself, calling setRenderers() will no
|
||||
/// longer have any effect until the next time the application is run.
|
||||
///
|
||||
/// \return The renderer SFML has selected to use
|
||||
///
|
||||
/// \see setRenderers
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
Uint32 SFML_GRAPHICS_API getRenderer();
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_RENDERER_HPP
|
@ -45,11 +45,16 @@ class InputStream;
|
||||
class Texture;
|
||||
class Transform;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
class ShaderImpl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Shader class (vertex, geometry and fragment)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SFML_GRAPHICS_API Shader : GlResource, NonCopyable
|
||||
class SFML_GRAPHICS_API Shader : NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
@ -693,62 +698,10 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Compile the shader(s) and create the program
|
||||
///
|
||||
/// If one of the arguments is NULL, the corresponding shader
|
||||
/// is not created.
|
||||
///
|
||||
/// \param vertexShaderCode Source code of the vertex shader
|
||||
/// \param geometryShaderCode Source code of the geometry shader
|
||||
/// \param fragmentShaderCode Source code of the fragment shader
|
||||
///
|
||||
/// \return True on success, false if any error happened
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
bool compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Bind all the textures used by the shader
|
||||
///
|
||||
/// This function each texture to a different unit, and
|
||||
/// updates the corresponding variables in the shader accordingly.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void bindTextures() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the location ID of a shader uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable to search
|
||||
///
|
||||
/// \return Location ID of the uniform, or -1 if not found
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
int getUniformLocation(const std::string& name);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief RAII object to save and restore the program
|
||||
/// binding while uniforms are being set
|
||||
///
|
||||
/// Implementation is private in the .cpp file.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct UniformBinder;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Types
|
||||
////////////////////////////////////////////////////////////
|
||||
typedef std::map<int, const Texture*> TextureTable;
|
||||
typedef std::map<std::string, int> UniformTable;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int m_shaderProgram; ///< OpenGL identifier for the program
|
||||
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
|
||||
priv::ShaderImpl* m_impl; ///< Platform/hardware specific implementation
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
|
@ -29,23 +29,30 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Window/GlResource.hpp>
|
||||
#include <SFML/Graphics/Rect.hpp>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class InputStream;
|
||||
class RenderTarget;
|
||||
class RenderTexture;
|
||||
class Text;
|
||||
class Image;
|
||||
class Window;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
class TextureImpl;
|
||||
class RenderTargetImpl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Image living on the graphics card that can be used for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SFML_GRAPHICS_API Texture : GlResource
|
||||
class SFML_GRAPHICS_API Texture
|
||||
{
|
||||
public:
|
||||
|
||||
@ -587,45 +594,12 @@ private:
|
||||
|
||||
friend class Text;
|
||||
friend class RenderTexture;
|
||||
friend class RenderTarget;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get a valid image size according to hardware support
|
||||
///
|
||||
/// This function checks whether the graphics driver supports
|
||||
/// non power of two sizes or not, and adjusts the size
|
||||
/// accordingly.
|
||||
/// The returned size is greater than or equal to the original size.
|
||||
///
|
||||
/// \param size size to convert
|
||||
///
|
||||
/// \return Valid nearest size (greater than or equal to specified size)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static unsigned int getValidSize(unsigned int size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Invalidate the mipmap if one exists
|
||||
///
|
||||
/// This also resets the texture's minifying function.
|
||||
/// This function is mainly for internal use by RenderTexture.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void invalidateMipmap();
|
||||
friend class priv::RenderTargetImpl;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2u m_size; ///< Public texture size
|
||||
Vector2u m_actualSize; ///< Actual texture size (can be greater than public size because of padding)
|
||||
unsigned int m_texture; ///< Internal texture identifier
|
||||
bool m_isSmooth; ///< Status of the smooth filter
|
||||
bool m_sRgb; ///< Should the texture source be converted from sRGB?
|
||||
bool m_isRepeated; ///< Is the texture in repeat mode?
|
||||
mutable bool m_pixelsFlipped; ///< To work around the inconsistency in Y orientation
|
||||
bool m_fboAttachment; ///< Is this texture owned by a framebuffer object?
|
||||
bool m_hasMipmap; ///< Has the mipmap been generated?
|
||||
Uint64 m_cacheId; ///< Unique number that identifies the texture to the render target's cache
|
||||
priv::TextureImpl* m_impl; ///< Platform/hardware specific implementation
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||
#include <SFML/Graphics/Drawable.hpp>
|
||||
#include <SFML/Window/GlResource.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -39,11 +38,16 @@ namespace sf
|
||||
class RenderTarget;
|
||||
class Vertex;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
class VertexBufferImpl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Vertex buffer storage for one or more 2D primitives
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class SFML_GRAPHICS_API VertexBuffer : public Drawable, private GlResource
|
||||
class SFML_GRAPHICS_API VertexBuffer : public Drawable
|
||||
{
|
||||
public:
|
||||
|
||||
@ -334,10 +338,8 @@ private:
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int m_buffer; ///< Internal buffer identifier
|
||||
std::size_t m_size; ///< Size in Vertexes of the currently allocated buffer
|
||||
PrimitiveType m_primitiveType; ///< Type of primitives to draw
|
||||
Usage m_usage; ///< How this vertex buffer is to be used
|
||||
priv::VertexBufferImpl* m_impl; ///< Platform/hardware specific implementation
|
||||
PrimitiveType m_primitiveType; ///< Type of primitives to draw
|
||||
};
|
||||
|
||||
} // namespace sf
|
||||
|
@ -15,10 +15,6 @@ set(SRC
|
||||
${INCROOT}/Glsl.hpp
|
||||
${INCROOT}/Glsl.inl
|
||||
${INCROOT}/Glyph.hpp
|
||||
${SRCROOT}/GLCheck.cpp
|
||||
${SRCROOT}/GLCheck.hpp
|
||||
${SRCROOT}/GLExtensions.hpp
|
||||
${SRCROOT}/GLExtensions.cpp
|
||||
${SRCROOT}/Image.cpp
|
||||
${INCROOT}/Image.hpp
|
||||
${SRCROOT}/ImageLoader.cpp
|
||||
@ -26,20 +22,30 @@ set(SRC
|
||||
${INCROOT}/PrimitiveType.hpp
|
||||
${INCROOT}/Rect.hpp
|
||||
${INCROOT}/Rect.inl
|
||||
${SRCROOT}/Renderer.cpp
|
||||
${INCROOT}/Renderer.hpp
|
||||
${SRCROOT}/RenderStates.cpp
|
||||
${INCROOT}/RenderStates.hpp
|
||||
${SRCROOT}/RenderTargetImpl.cpp
|
||||
${SRCROOT}/RenderTargetImpl.hpp
|
||||
${SRCROOT}/RenderTexture.cpp
|
||||
${INCROOT}/RenderTexture.hpp
|
||||
${SRCROOT}/RenderTextureImpl.cpp
|
||||
${SRCROOT}/RenderTextureImpl.hpp
|
||||
${SRCROOT}/RenderTarget.cpp
|
||||
${INCROOT}/RenderTarget.hpp
|
||||
${SRCROOT}/RenderWindow.cpp
|
||||
${INCROOT}/RenderWindow.hpp
|
||||
${SRCROOT}/Shader.cpp
|
||||
${INCROOT}/Shader.hpp
|
||||
${SRCROOT}/ShaderImpl.cpp
|
||||
${SRCROOT}/ShaderImpl.hpp
|
||||
${SRCROOT}/ShaderImplNull.cpp
|
||||
${SRCROOT}/ShaderImplNull.hpp
|
||||
${SRCROOT}/Texture.cpp
|
||||
${INCROOT}/Texture.hpp
|
||||
${SRCROOT}/TextureSaver.cpp
|
||||
${SRCROOT}/TextureSaver.hpp
|
||||
${SRCROOT}/TextureImpl.cpp
|
||||
${SRCROOT}/TextureImpl.hpp
|
||||
${SRCROOT}/Transform.cpp
|
||||
${INCROOT}/Transform.hpp
|
||||
${SRCROOT}/Transformable.cpp
|
||||
@ -70,24 +76,43 @@ set(DRAWABLES_SRC
|
||||
${INCROOT}/VertexArray.hpp
|
||||
${SRCROOT}/VertexBuffer.cpp
|
||||
${INCROOT}/VertexBuffer.hpp
|
||||
${SRCROOT}/VertexBufferImpl.cpp
|
||||
${SRCROOT}/VertexBufferImpl.hpp
|
||||
)
|
||||
source_group("drawables" FILES ${DRAWABLES_SRC})
|
||||
|
||||
# render-texture sources
|
||||
set(RENDER_TEXTURE_SRC
|
||||
${SRCROOT}/RenderTextureImpl.cpp
|
||||
${SRCROOT}/RenderTextureImpl.hpp
|
||||
${SRCROOT}/RenderTextureImplFBO.cpp
|
||||
${SRCROOT}/RenderTextureImplFBO.hpp
|
||||
${SRCROOT}/RenderTextureImplDefault.cpp
|
||||
${SRCROOT}/RenderTextureImplDefault.hpp
|
||||
# OpenGL 1.x sources
|
||||
set(OPENGL_SRC
|
||||
${SRCROOT}/OpenGL/GLCheck.cpp
|
||||
${SRCROOT}/OpenGL/GLCheck.hpp
|
||||
${SRCROOT}/OpenGL/GLExtensions.hpp
|
||||
${SRCROOT}/OpenGL/GLExtensions.cpp
|
||||
)
|
||||
source_group("render texture" FILES ${RENDER_TEXTURE_SRC})
|
||||
source_group("opengl implementation" FILES ${OPENGL_SRC})
|
||||
|
||||
# OpenGL 1.x sources
|
||||
set(OPENGL_1_SRC
|
||||
${SRCROOT}/OpenGL/GL1/RenderTargetImplDefault.cpp
|
||||
${SRCROOT}/OpenGL/GL1/RenderTargetImplDefault.hpp
|
||||
${SRCROOT}/OpenGL/GL1/RenderTextureImplFBO.cpp
|
||||
${SRCROOT}/OpenGL/GL1/RenderTextureImplFBO.hpp
|
||||
${SRCROOT}/OpenGL/GL1/RenderTextureImplDefault.cpp
|
||||
${SRCROOT}/OpenGL/GL1/RenderTextureImplDefault.hpp
|
||||
${SRCROOT}/OpenGL/GL1/TextureImplDefault.cpp
|
||||
${SRCROOT}/OpenGL/GL1/TextureImplDefault.hpp
|
||||
${SRCROOT}/OpenGL/GL1/VertexBufferImplDefault.cpp
|
||||
${SRCROOT}/OpenGL/GL1/VertexBufferImplDefault.hpp
|
||||
)
|
||||
if(NOT SFML_OPENGL_ES)
|
||||
list(APPEND OPENGL_1_SRC ${SRCROOT}/OpenGL/GL1/ShaderImplDefault.cpp)
|
||||
list(APPEND OPENGL_1_SRC ${SRCROOT}/OpenGL/GL1/ShaderImplDefault.hpp)
|
||||
endif()
|
||||
source_group("opengl 1.x implementation" FILES ${OPENGL_1_SRC})
|
||||
|
||||
|
||||
# define the sfml-graphics target
|
||||
sfml_add_library(sfml-graphics
|
||||
SOURCES ${SRC} ${DRAWABLES_SRC} ${RENDER_TEXTURE_SRC} ${STB_SRC})
|
||||
SOURCES ${SRC} ${DRAWABLES_SRC} ${OPENGL_1_SRC} ${OPENGL_SRC} ${STB_SRC})
|
||||
|
||||
# setup dependencies
|
||||
target_link_libraries(sfml-graphics PUBLIC sfml-window)
|
||||
|
@ -26,7 +26,8 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Font.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#ifdef SFML_SYSTEM_ANDROID
|
||||
#include <SFML/System/Android/ResourceStream.hpp>
|
||||
#endif
|
||||
|
704
src/SFML/Graphics/OpenGL/GL1/RenderTargetImplDefault.cpp
Normal file
704
src/SFML/Graphics/OpenGL/GL1/RenderTargetImplDefault.cpp
Normal file
@ -0,0 +1,704 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/OpenGL/GL1/RenderTargetImplDefault.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Drawable.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/TextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/VertexArray.hpp>
|
||||
#include <SFML/Graphics/VertexBuffer.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
|
||||
// GL_QUADS is unavailable on OpenGL ES, thus we need to define GL_QUADS ourselves
|
||||
#ifdef SFML_OPENGL_ES
|
||||
|
||||
#define GL_QUADS 0
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Mutex to protect ID generation and our context-RenderTarget-map
|
||||
sf::Mutex mutex;
|
||||
|
||||
// Unique identifier, used for identifying RenderTargets when
|
||||
// tracking the currently active RenderTarget within a given context
|
||||
sf::Uint64 getUniqueId()
|
||||
{
|
||||
sf::Lock lock(mutex);
|
||||
|
||||
static sf::Uint64 id = 1; // start at 1, zero is "no RenderTarget"
|
||||
|
||||
return id++;
|
||||
}
|
||||
|
||||
// Map to help us detect whether a different RenderTarget
|
||||
// has been activated within a single context
|
||||
typedef std::map<sf::Uint64, sf::Uint64> ContextRenderTargetMap;
|
||||
ContextRenderTargetMap contextRenderTargetMap;
|
||||
|
||||
// Check if a RenderTarget with the given ID is active in the current context
|
||||
bool isActive(sf::Uint64 id)
|
||||
{
|
||||
ContextRenderTargetMap::iterator iter = contextRenderTargetMap.find(sf::Context::getActiveContextId());
|
||||
|
||||
if ((iter == contextRenderTargetMap.end()) || (iter->second != id))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert an sf::BlendMode::Factor constant to the corresponding OpenGL constant.
|
||||
sf::Uint32 factorToGlConstant(sf::BlendMode::Factor blendFactor)
|
||||
{
|
||||
switch (blendFactor)
|
||||
{
|
||||
case sf::BlendMode::Zero: return GL_ZERO;
|
||||
case sf::BlendMode::One: return GL_ONE;
|
||||
case sf::BlendMode::SrcColor: return GL_SRC_COLOR;
|
||||
case sf::BlendMode::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR;
|
||||
case sf::BlendMode::DstColor: return GL_DST_COLOR;
|
||||
case sf::BlendMode::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR;
|
||||
case sf::BlendMode::SrcAlpha: return GL_SRC_ALPHA;
|
||||
case sf::BlendMode::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA;
|
||||
case sf::BlendMode::DstAlpha: return GL_DST_ALPHA;
|
||||
case sf::BlendMode::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA;
|
||||
}
|
||||
|
||||
sf::err() << "Invalid value for sf::BlendMode::Factor! Fallback to sf::BlendMode::Zero." << std::endl;
|
||||
assert(false);
|
||||
return GL_ZERO;
|
||||
}
|
||||
|
||||
|
||||
// Convert an sf::BlendMode::BlendEquation constant to the corresponding OpenGL constant.
|
||||
sf::Uint32 equationToGlConstant(sf::BlendMode::Equation blendEquation)
|
||||
{
|
||||
switch (blendEquation)
|
||||
{
|
||||
case sf::BlendMode::Add: return GLEXT_GL_FUNC_ADD;
|
||||
case sf::BlendMode::Subtract: return GLEXT_GL_FUNC_SUBTRACT;
|
||||
case sf::BlendMode::ReverseSubtract: return GLEXT_GL_FUNC_REVERSE_SUBTRACT;
|
||||
}
|
||||
|
||||
sf::err() << "Invalid value for sf::BlendMode::Equation! Fallback to sf::BlendMode::Add." << std::endl;
|
||||
assert(false);
|
||||
return GLEXT_GL_FUNC_ADD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTargetImplDefault::RenderTargetImplDefault(RenderTarget* parent) :
|
||||
RenderTargetImpl(parent),
|
||||
m_defaultView (),
|
||||
m_view (),
|
||||
m_cache (),
|
||||
m_id (0)
|
||||
{
|
||||
m_cache.glStatesSet = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTargetImplDefault::~RenderTargetImplDefault()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::clear(const Color& color)
|
||||
{
|
||||
if (isActive(m_id) || getParent()->setActive(true))
|
||||
{
|
||||
// Unbind texture to fix RenderTexture preventing clear
|
||||
applyTexture(NULL);
|
||||
|
||||
glCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f));
|
||||
glCheck(glClear(GL_COLOR_BUFFER_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::setView(const View& view)
|
||||
{
|
||||
m_view = view;
|
||||
m_cache.viewChanged = true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const View& RenderTargetImplDefault::getView() const
|
||||
{
|
||||
return m_view;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const View& RenderTargetImplDefault::getDefaultView() const
|
||||
{
|
||||
return m_defaultView;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::draw(const Vertex* vertices, std::size_t vertexCount,
|
||||
PrimitiveType type, const RenderStates& states)
|
||||
{
|
||||
// Nothing to draw?
|
||||
if (!vertices || (vertexCount == 0))
|
||||
return;
|
||||
|
||||
// GL_QUADS is unavailable on OpenGL ES
|
||||
#ifdef SFML_OPENGL_ES
|
||||
if (type == Quads)
|
||||
{
|
||||
err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isActive(m_id) || getParent()->setActive(true))
|
||||
{
|
||||
// Check if the vertex count is low enough so that we can pre-transform them
|
||||
bool useVertexCache = (vertexCount <= StatesCache::VertexCacheSize);
|
||||
|
||||
if (useVertexCache)
|
||||
{
|
||||
// Pre-transform the vertices and store them into the vertex cache
|
||||
for (std::size_t i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
Vertex& vertex = m_cache.vertexCache[i];
|
||||
vertex.position = states.transform * vertices[i].position;
|
||||
vertex.color = vertices[i].color;
|
||||
vertex.texCoords = vertices[i].texCoords;
|
||||
}
|
||||
}
|
||||
|
||||
setupDraw(useVertexCache, states);
|
||||
|
||||
// Check if texture coordinates array is needed, and update client state accordingly
|
||||
bool enableTexCoordsArray = (states.texture || states.shader);
|
||||
if (!m_cache.enable || (enableTexCoordsArray != m_cache.texCoordsArrayEnabled))
|
||||
{
|
||||
if (enableTexCoordsArray)
|
||||
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
else
|
||||
glCheck(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
}
|
||||
|
||||
// If we switch between non-cache and cache mode or enable texture
|
||||
// coordinates we need to set up the pointers to the vertices' components
|
||||
if (!m_cache.enable || !useVertexCache || !m_cache.useVertexCache)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(vertices);
|
||||
|
||||
// If we pre-transform the vertices, we must use our internal vertex cache
|
||||
if (useVertexCache)
|
||||
data = reinterpret_cast<const char*>(m_cache.vertexCache);
|
||||
|
||||
glCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), data + 0));
|
||||
glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8));
|
||||
if (enableTexCoordsArray)
|
||||
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
|
||||
}
|
||||
else if (enableTexCoordsArray && !m_cache.texCoordsArrayEnabled)
|
||||
{
|
||||
// If we enter this block, we are already using our internal vertex cache
|
||||
const char* data = reinterpret_cast<const char*>(m_cache.vertexCache);
|
||||
|
||||
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
|
||||
}
|
||||
|
||||
drawPrimitives(type, 0, vertexCount);
|
||||
cleanupDraw(states);
|
||||
|
||||
// Update the cache
|
||||
m_cache.useVertexCache = useVertexCache;
|
||||
m_cache.texCoordsArrayEnabled = enableTexCoordsArray;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex,
|
||||
std::size_t vertexCount, const RenderStates& states)
|
||||
{
|
||||
// VertexBuffer not supported?
|
||||
if (!VertexBuffer::isAvailable())
|
||||
{
|
||||
err() << "sf::VertexBuffer is not available, drawing skipped" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (firstVertex > vertexBuffer.getVertexCount())
|
||||
return;
|
||||
|
||||
// Clamp vertexCount to something that makes sense
|
||||
vertexCount = std::min(vertexCount, vertexBuffer.getVertexCount() - firstVertex);
|
||||
|
||||
// Nothing to draw?
|
||||
if (!vertexCount || !vertexBuffer.getNativeHandle())
|
||||
return;
|
||||
|
||||
// GL_QUADS is unavailable on OpenGL ES
|
||||
#ifdef SFML_OPENGL_ES
|
||||
if (vertexBuffer.getPrimitiveType() == Quads)
|
||||
{
|
||||
err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isActive(m_id) || getParent()->setActive(true))
|
||||
{
|
||||
setupDraw(false, states);
|
||||
|
||||
// Bind vertex buffer
|
||||
VertexBuffer::bind(&vertexBuffer);
|
||||
|
||||
// Always enable texture coordinates
|
||||
if (!m_cache.enable || !m_cache.texCoordsArrayEnabled)
|
||||
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
|
||||
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)));
|
||||
|
||||
drawPrimitives(vertexBuffer.getPrimitiveType(), firstVertex, vertexCount);
|
||||
|
||||
// Unbind vertex buffer
|
||||
VertexBuffer::bind(NULL);
|
||||
|
||||
cleanupDraw(states);
|
||||
|
||||
// Update the cache
|
||||
m_cache.useVertexCache = false;
|
||||
m_cache.texCoordsArrayEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderTargetImplDefault::setActive(bool active)
|
||||
{
|
||||
// Mark this RenderTarget as active or no longer active in the tracking map
|
||||
{
|
||||
sf::Lock lock(mutex);
|
||||
|
||||
Uint64 contextId = Context::getActiveContextId();
|
||||
|
||||
ContextRenderTargetMap::iterator iter = contextRenderTargetMap.find(contextId);
|
||||
|
||||
if (active)
|
||||
{
|
||||
if (iter == contextRenderTargetMap.end())
|
||||
{
|
||||
contextRenderTargetMap[contextId] = m_id;
|
||||
|
||||
m_cache.enable = false;
|
||||
}
|
||||
else if (iter->second != m_id)
|
||||
{
|
||||
iter->second = m_id;
|
||||
|
||||
m_cache.enable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iter != contextRenderTargetMap.end())
|
||||
contextRenderTargetMap.erase(iter);
|
||||
|
||||
m_cache.enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::pushGLStates()
|
||||
{
|
||||
if (isActive(m_id) || getParent()->setActive(true))
|
||||
{
|
||||
#ifdef SFML_DEBUG
|
||||
// make sure that the user didn't leave an unchecked OpenGL error
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
err() << "OpenGL error (" << error << ") detected in user code, "
|
||||
<< "you should check for errors with glGetError()"
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SFML_OPENGL_ES
|
||||
glCheck(glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS));
|
||||
glCheck(glPushAttrib(GL_ALL_ATTRIB_BITS));
|
||||
#endif
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
glCheck(glPushMatrix());
|
||||
glCheck(glMatrixMode(GL_PROJECTION));
|
||||
glCheck(glPushMatrix());
|
||||
glCheck(glMatrixMode(GL_TEXTURE));
|
||||
glCheck(glPushMatrix());
|
||||
}
|
||||
|
||||
resetGLStates();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::popGLStates()
|
||||
{
|
||||
if (isActive(m_id) || getParent()->setActive(true))
|
||||
{
|
||||
glCheck(glMatrixMode(GL_PROJECTION));
|
||||
glCheck(glPopMatrix());
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
glCheck(glPopMatrix());
|
||||
glCheck(glMatrixMode(GL_TEXTURE));
|
||||
glCheck(glPopMatrix());
|
||||
#ifndef SFML_OPENGL_ES
|
||||
glCheck(glPopClientAttrib());
|
||||
glCheck(glPopAttrib());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::resetGLStates()
|
||||
{
|
||||
// Check here to make sure a context change does not happen after activate(true)
|
||||
bool shaderAvailable = Shader::isAvailable();
|
||||
bool vertexBufferAvailable = VertexBuffer::isAvailable();
|
||||
|
||||
// Workaround for states not being properly reset on
|
||||
// macOS unless a context switch really takes place
|
||||
#if defined(SFML_SYSTEM_MACOS)
|
||||
getParent()->setActive(false);
|
||||
#endif
|
||||
|
||||
if (isActive(m_id) || getParent()->setActive(true))
|
||||
{
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
|
||||
// Make sure that the texture unit which is active is the number 0
|
||||
if (GLEXT_multitexture)
|
||||
{
|
||||
glCheck(GLEXT_glClientActiveTexture(GLEXT_GL_TEXTURE0));
|
||||
glCheck(GLEXT_glActiveTexture(GLEXT_GL_TEXTURE0));
|
||||
}
|
||||
|
||||
// Define the default OpenGL states
|
||||
glCheck(glDisable(GL_CULL_FACE));
|
||||
glCheck(glDisable(GL_LIGHTING));
|
||||
glCheck(glDisable(GL_DEPTH_TEST));
|
||||
glCheck(glDisable(GL_ALPHA_TEST));
|
||||
glCheck(glEnable(GL_TEXTURE_2D));
|
||||
glCheck(glEnable(GL_BLEND));
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
glCheck(glLoadIdentity());
|
||||
glCheck(glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glCheck(glEnableClientState(GL_COLOR_ARRAY));
|
||||
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
m_cache.glStatesSet = true;
|
||||
|
||||
// Apply the default SFML states
|
||||
applyBlendMode(BlendAlpha);
|
||||
applyTexture(NULL);
|
||||
if (shaderAvailable)
|
||||
applyShader(NULL);
|
||||
|
||||
if (vertexBufferAvailable)
|
||||
glCheck(VertexBuffer::bind(NULL));
|
||||
|
||||
m_cache.texCoordsArrayEnabled = true;
|
||||
|
||||
m_cache.useVertexCache = false;
|
||||
|
||||
// Set the default view
|
||||
setView(getView());
|
||||
|
||||
m_cache.enable = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::initialize(const Vector2u& newSize)
|
||||
{
|
||||
// Setup the default and current views
|
||||
m_defaultView.reset(FloatRect(0, 0, static_cast<float>(newSize.x), static_cast<float>(newSize.y)));
|
||||
m_view = m_defaultView;
|
||||
|
||||
// Set GL states only on first draw, so that we don't pollute user's states
|
||||
m_cache.glStatesSet = false;
|
||||
|
||||
// Generate a unique ID for this RenderTarget to track
|
||||
// whether it is active within a specific context
|
||||
m_id = getUniqueId();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::applyCurrentView()
|
||||
{
|
||||
// Set the viewport
|
||||
IntRect viewport = getParent()->getViewport(m_view);
|
||||
int top = getParent()->getSize().y - (viewport.top + viewport.height);
|
||||
glCheck(glViewport(viewport.left, top, viewport.width, viewport.height));
|
||||
|
||||
// Set the projection matrix
|
||||
glCheck(glMatrixMode(GL_PROJECTION));
|
||||
glCheck(glLoadMatrixf(m_view.getTransform().getMatrix()));
|
||||
|
||||
// Go back to model-view mode
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
|
||||
m_cache.viewChanged = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::applyBlendMode(const BlendMode& mode)
|
||||
{
|
||||
// Apply the blend mode, falling back to the non-separate versions if necessary
|
||||
if (GLEXT_blend_func_separate)
|
||||
{
|
||||
glCheck(GLEXT_glBlendFuncSeparate(
|
||||
factorToGlConstant(mode.colorSrcFactor), factorToGlConstant(mode.colorDstFactor),
|
||||
factorToGlConstant(mode.alphaSrcFactor), factorToGlConstant(mode.alphaDstFactor)));
|
||||
}
|
||||
else
|
||||
{
|
||||
glCheck(glBlendFunc(
|
||||
factorToGlConstant(mode.colorSrcFactor),
|
||||
factorToGlConstant(mode.colorDstFactor)));
|
||||
}
|
||||
|
||||
if (GLEXT_blend_minmax && GLEXT_blend_subtract)
|
||||
{
|
||||
if (GLEXT_blend_equation_separate)
|
||||
{
|
||||
glCheck(GLEXT_glBlendEquationSeparate(
|
||||
equationToGlConstant(mode.colorEquation),
|
||||
equationToGlConstant(mode.alphaEquation)));
|
||||
}
|
||||
else
|
||||
{
|
||||
glCheck(GLEXT_glBlendEquation(equationToGlConstant(mode.colorEquation)));
|
||||
}
|
||||
}
|
||||
else if ((mode.colorEquation != BlendMode::Add) || (mode.alphaEquation != BlendMode::Add))
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
err() << "OpenGL extension EXT_blend_minmax and/or EXT_blend_subtract unavailable" << std::endl;
|
||||
err() << "Selecting a blend equation not possible" << std::endl;
|
||||
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_cache.lastBlendMode = mode;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::applyTransform(const Transform& 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()));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::applyTexture(const Texture* texture)
|
||||
{
|
||||
Texture::bind(texture, Texture::Pixels);
|
||||
|
||||
m_cache.lastTextureId = texture ? static_cast<const priv::TextureImplDefault*>(getTextureImpl(*texture))->m_cacheId : 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::applyShader(const Shader* shader)
|
||||
{
|
||||
Shader::bind(shader);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::setupDraw(bool useVertexCache, const RenderStates& states)
|
||||
{
|
||||
// First set the persistent OpenGL states if it's the very first call
|
||||
if (!m_cache.glStatesSet)
|
||||
resetGLStates();
|
||||
|
||||
if (useVertexCache)
|
||||
{
|
||||
// Since vertices are transformed, we must use an identity transform to render them
|
||||
if (!m_cache.enable || !m_cache.useVertexCache)
|
||||
glCheck(glLoadIdentity());
|
||||
}
|
||||
else
|
||||
{
|
||||
applyTransform(states.transform);
|
||||
}
|
||||
|
||||
// Apply the view
|
||||
if (!m_cache.enable || m_cache.viewChanged)
|
||||
applyCurrentView();
|
||||
|
||||
// Apply the blend mode
|
||||
if (!m_cache.enable || (states.blendMode != m_cache.lastBlendMode))
|
||||
applyBlendMode(states.blendMode);
|
||||
|
||||
// Apply the texture
|
||||
if (!m_cache.enable || (states.texture && static_cast<const priv::TextureImplDefault*>(getTextureImpl(*states.texture))->m_fboAttachment))
|
||||
{
|
||||
// If the texture is an FBO attachment, always rebind it
|
||||
// in order to inform the OpenGL driver that we want changes
|
||||
// made to it in other contexts to be visible here as well
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
Uint64 textureId = states.texture ? static_cast<const priv::TextureImplDefault*>(getTextureImpl(*states.texture))->m_cacheId : 0;
|
||||
if (textureId != m_cache.lastTextureId)
|
||||
applyTexture(states.texture);
|
||||
}
|
||||
|
||||
// Apply the shader
|
||||
if (states.shader)
|
||||
applyShader(states.shader);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount)
|
||||
{
|
||||
// Find the OpenGL primitive type
|
||||
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
|
||||
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
|
||||
GLenum mode = modes[type];
|
||||
|
||||
// Draw the primitives
|
||||
glCheck(glDrawArrays(mode, static_cast<GLint>(firstVertex), static_cast<GLsizei>(vertexCount)));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImplDefault::cleanupDraw(const RenderStates& states)
|
||||
{
|
||||
// Unbind the shader, if any
|
||||
if (states.shader)
|
||||
applyShader(NULL);
|
||||
|
||||
// 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 && static_cast<const priv::TextureImplDefault*>(getTextureImpl(*states.texture))->m_fboAttachment)
|
||||
applyTexture(NULL);
|
||||
|
||||
// Re-enable the cache at the end of the draw if it was disabled
|
||||
m_cache.enable = true;
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Render states caching strategies
|
||||
//
|
||||
// * View
|
||||
// If SetView was called since last draw, the projection
|
||||
// matrix is updated. We don't need more, the view doesn't
|
||||
// change frequently.
|
||||
//
|
||||
// * Transform
|
||||
// The transform matrix is usually expensive because each
|
||||
// entity will most likely use a different transform. This can
|
||||
// lead, in worst case, to changing it every 4 vertices.
|
||||
// To avoid that, when the vertex count is low enough, we
|
||||
// pre-transform them and therefore use an identity transform
|
||||
// to render them.
|
||||
//
|
||||
// * Blending mode
|
||||
// Since it overloads the == operator, we can easily check
|
||||
// whether any of the 6 blending components changed and,
|
||||
// thus, whether we need to update the blend mode.
|
||||
//
|
||||
// * Texture
|
||||
// Storing the pointer or OpenGL ID of the last used texture
|
||||
// is not enough; if the sf::Texture instance is destroyed,
|
||||
// both the pointer and the OpenGL ID might be recycled in
|
||||
// a new texture instance. We need to use our own unique
|
||||
// identifier system to ensure consistent caching.
|
||||
//
|
||||
// * Shader
|
||||
// Shaders are very hard to optimize, because they have
|
||||
// parameters that can be hard (if not impossible) to track,
|
||||
// like matrices or textures. The only optimization that we
|
||||
// do is that we avoid setting a null shader if there was
|
||||
// already none for the previous draw.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
271
src/SFML/Graphics/OpenGL/GL1/RenderTargetImplDefault.hpp
Normal file
271
src/SFML/Graphics/OpenGL/GL1/RenderTargetImplDefault.hpp
Normal file
@ -0,0 +1,271 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_RENDERTARGET_IMPL_DEFAULT_HPP
|
||||
#define SFML_RENDERTARGET_IMPL_DEFAULT_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderTargetImpl.hpp>
|
||||
#include <SFML/Graphics/Color.hpp>
|
||||
#include <SFML/Graphics/Rect.hpp>
|
||||
#include <SFML/Graphics/View.hpp>
|
||||
#include <SFML/Graphics/Transform.hpp>
|
||||
#include <SFML/Graphics/BlendMode.hpp>
|
||||
#include <SFML/Graphics/RenderStates.hpp>
|
||||
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||
#include <SFML/Graphics/Vertex.hpp>
|
||||
#include <SFML/System/NonCopyable.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Drawable;
|
||||
class VertexBuffer;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Base class for all render targets (window, texture, ...)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class RenderTargetImplDefault : public RenderTargetImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTargetImplDefault(RenderTarget* parent);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual ~RenderTargetImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Clear the entire target with a single color
|
||||
///
|
||||
/// \param color Fill color to use to clear the render target
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void clear(const Color& color);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the current active view
|
||||
///
|
||||
/// \param view New view to use
|
||||
///
|
||||
/// \see getView, getDefaultView
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setView(const View& view);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the view currently in use in the render target
|
||||
///
|
||||
/// \return The view object that is currently used
|
||||
///
|
||||
/// \see setView, getDefaultView
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual const View& getView() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the default view of the render target
|
||||
///
|
||||
/// \return The default view of the render target
|
||||
///
|
||||
/// \see setView, getView
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual const View& getDefaultView() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Draw primitives defined by an array of vertices
|
||||
///
|
||||
/// \param vertices Pointer to the vertices
|
||||
/// \param vertexCount Number of vertices in the array
|
||||
/// \param type Type of primitives to draw
|
||||
/// \param states Render states to use for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void draw(const Vertex* vertices, std::size_t vertexCount,
|
||||
PrimitiveType type, const RenderStates& states);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Draw primitives defined by a vertex buffer
|
||||
///
|
||||
/// \param vertexBuffer Vertex buffer
|
||||
/// \param firstVertex Index of the first vertex to render
|
||||
/// \param vertexCount Number of vertices to render
|
||||
/// \param states Render states to use for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex,
|
||||
std::size_t vertexCount, const RenderStates& states);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Activate or deactivate the render target for rendering
|
||||
///
|
||||
/// \param active True to activate, false to deactivate
|
||||
///
|
||||
/// \return True if operation was successful, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool setActive(bool active);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Save the current OpenGL render states and matrices
|
||||
///
|
||||
/// \see popGLStates
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void pushGLStates();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Restore the previously saved OpenGL render states and matrices
|
||||
///
|
||||
/// \see pushGLStates
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void popGLStates();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Reset the internal OpenGL states so that the target is ready for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void resetGLStates();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Performs the common initialization step after creation
|
||||
///
|
||||
/// \param newSize New size of the RenderTarget
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void initialize(const Vector2u& newSize);
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply the current view
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyCurrentView();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new blending mode
|
||||
///
|
||||
/// \param mode Blending mode to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyBlendMode(const BlendMode& mode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new transform
|
||||
///
|
||||
/// \param transform Transform to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyTransform(const Transform& transform);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new texture
|
||||
///
|
||||
/// \param texture Texture to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyTexture(const Texture* texture);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Apply a new shader
|
||||
///
|
||||
/// \param shader Shader to apply
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void applyShader(const Shader* shader);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Setup environment for drawing
|
||||
///
|
||||
/// \param useVertexCache Are we going to use the vertex cache?
|
||||
/// \param states Render states to use for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void setupDraw(bool useVertexCache, const RenderStates& states);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Draw the primitives
|
||||
///
|
||||
/// \param type Type of primitives to draw
|
||||
/// \param firstVertex Index of the first vertex to use when drawing
|
||||
/// \param vertexCount Number of vertices to use when drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Clean up environment after drawing
|
||||
///
|
||||
/// \param states Render states used for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void cleanupDraw(const RenderStates& states);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Render states cache
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct StatesCache
|
||||
{
|
||||
enum {VertexCacheSize = 4};
|
||||
|
||||
bool enable; ///< Is the cache enabled?
|
||||
bool glStatesSet; ///< Are our internal GL states set yet?
|
||||
bool viewChanged; ///< Has the current view changed since last draw?
|
||||
BlendMode lastBlendMode; ///< Cached blending mode
|
||||
Uint64 lastTextureId; ///< Cached texture
|
||||
bool texCoordsArrayEnabled; ///< Is GL_TEXTURE_COORD_ARRAY client state enabled?
|
||||
bool useVertexCache; ///< Did we previously use the vertex cache?
|
||||
Vertex vertexCache[VertexCacheSize]; ///< Pre-transformed vertices cache
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
View m_defaultView; ///< Default view
|
||||
View m_view; ///< Current view
|
||||
StatesCache m_cache; ///< Render states cache
|
||||
Uint64 m_id; ///< Unique number that identifies the RenderTarget
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_RENDERTARGET_IMPL_DEFAULT_HPP
|
@ -25,13 +25,32 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderTextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/TextureSaver.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/RenderTextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Automatic wrapper for saving and restoring the current texture binding
|
||||
struct TextureSaver
|
||||
{
|
||||
TextureSaver()
|
||||
{
|
||||
glCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding));
|
||||
}
|
||||
|
||||
~TextureSaver()
|
||||
{
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, textureBinding));
|
||||
}
|
||||
|
||||
GLint textureBinding;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
@ -89,7 +108,7 @@ bool RenderTextureImplDefault::activate(bool active)
|
||||
void RenderTextureImplDefault::updateTexture(unsigned int textureId)
|
||||
{
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
TextureSaver save;
|
||||
|
||||
// Copy the rendered pixels to the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, textureId));
|
@ -25,9 +25,9 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
@ -208,6 +208,22 @@ void RenderTextureImplFBO::unbind()
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, 0));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int RenderTextureImplFBO::getFramebuffer()
|
||||
{
|
||||
unsigned int frameBuffer = 0;
|
||||
|
||||
glCheck(glGetIntegerv(GLEXT_GL_FRAMEBUFFER_BINDING, reinterpret_cast<GLint*>(&frameBuffer)));
|
||||
|
||||
return frameBuffer;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTextureImplFBO::bindFramebuffer(unsigned int frameBuffer)
|
||||
{
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, frameBuffer));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderTextureImplFBO::create(unsigned int width, unsigned int height, unsigned int textureId, const ContextSettings& settings)
|
@ -81,6 +81,18 @@ public:
|
||||
////////////////////////////////////////////////////////////
|
||||
static void unbind();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the currently bound frame buffer object
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static unsigned int getFramebuffer();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Bind a frame buffer object
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void bindFramebuffer(unsigned int frameBuffer);
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
687
src/SFML/Graphics/OpenGL/GL1/ShaderImplDefault.cpp
Normal file
687
src/SFML/Graphics/OpenGL/GL1/ShaderImplDefault.cpp
Normal file
@ -0,0 +1,687 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/OpenGL/GL1/ShaderImplDefault.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <SFML/System/NonCopyable.hpp>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#if defined(SFML_SYSTEM_MACOS) || defined(SFML_SYSTEM_IOS)
|
||||
|
||||
#define castToGlHandle(x) reinterpret_cast<GLEXT_GLhandle>(static_cast<ptrdiff_t>(x))
|
||||
#define castFromGlHandle(x) static_cast<unsigned int>(reinterpret_cast<ptrdiff_t>(x))
|
||||
|
||||
#else
|
||||
|
||||
#define castToGlHandle(x) (x)
|
||||
#define castFromGlHandle(x) (x)
|
||||
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::Mutex maxTextureUnitsMutex;
|
||||
sf::Mutex isAvailableMutex;
|
||||
|
||||
GLint checkMaxTextureUnits()
|
||||
{
|
||||
GLint maxUnits = 0;
|
||||
glCheck(glGetIntegerv(GLEXT_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxUnits));
|
||||
|
||||
return maxUnits;
|
||||
}
|
||||
|
||||
// Retrieve the maximum number of texture units available
|
||||
GLint getMaxTextureUnits()
|
||||
{
|
||||
// TODO: Remove this lock when it becomes unnecessary in C++11
|
||||
sf::Lock lock(maxTextureUnitsMutex);
|
||||
|
||||
static GLint maxUnits = checkMaxTextureUnits();
|
||||
|
||||
return maxUnits;
|
||||
}
|
||||
|
||||
// Transforms an array of 2D vectors into a contiguous array of scalars
|
||||
template <typename T>
|
||||
std::vector<T> flatten(const sf::Vector2<T>* vectorArray, std::size_t length)
|
||||
{
|
||||
const std::size_t vectorSize = 2;
|
||||
|
||||
std::vector<T> contiguous(vectorSize * length);
|
||||
for (std::size_t i = 0; i < length; ++i)
|
||||
{
|
||||
contiguous[vectorSize * i] = vectorArray[i].x;
|
||||
contiguous[vectorSize * i + 1] = vectorArray[i].y;
|
||||
}
|
||||
|
||||
return contiguous;
|
||||
}
|
||||
|
||||
// Transforms an array of 3D vectors into a contiguous array of scalars
|
||||
template <typename T>
|
||||
std::vector<T> flatten(const sf::Vector3<T>* vectorArray, std::size_t length)
|
||||
{
|
||||
const std::size_t vectorSize = 3;
|
||||
|
||||
std::vector<T> contiguous(vectorSize * length);
|
||||
for (std::size_t i = 0; i < length; ++i)
|
||||
{
|
||||
contiguous[vectorSize * i] = vectorArray[i].x;
|
||||
contiguous[vectorSize * i + 1] = vectorArray[i].y;
|
||||
contiguous[vectorSize * i + 2] = vectorArray[i].z;
|
||||
}
|
||||
|
||||
return contiguous;
|
||||
}
|
||||
|
||||
// Transforms an array of 4D vectors into a contiguous array of scalars
|
||||
template <typename T>
|
||||
std::vector<T> flatten(const sf::priv::Vector4<T>* vectorArray, std::size_t length)
|
||||
{
|
||||
const std::size_t vectorSize = 4;
|
||||
|
||||
std::vector<T> contiguous(vectorSize * length);
|
||||
for (std::size_t i = 0; i < length; ++i)
|
||||
{
|
||||
contiguous[vectorSize * i] = vectorArray[i].x;
|
||||
contiguous[vectorSize * i + 1] = vectorArray[i].y;
|
||||
contiguous[vectorSize * i + 2] = vectorArray[i].z;
|
||||
contiguous[vectorSize * i + 3] = vectorArray[i].w;
|
||||
}
|
||||
|
||||
return contiguous;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
struct ShaderImplDefault::UniformBinder : private sf::NonCopyable
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Constructor: set up state before uniform is set
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
UniformBinder(ShaderImplDefault& shader, const std::string& name) :
|
||||
savedProgram(0),
|
||||
currentProgram(castToGlHandle(shader.m_shaderProgram)),
|
||||
location(-1)
|
||||
{
|
||||
if (currentProgram)
|
||||
{
|
||||
// Enable program object
|
||||
glCheck(savedProgram = GLEXT_glGetHandle(GLEXT_GL_PROGRAM_OBJECT));
|
||||
if (currentProgram != savedProgram)
|
||||
glCheck(GLEXT_glUseProgramObject(currentProgram));
|
||||
|
||||
// Store uniform location for further use outside constructor
|
||||
location = shader.getUniformLocation(name);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor: restore state after uniform is set
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~UniformBinder()
|
||||
{
|
||||
// Disable program object
|
||||
if (currentProgram && (currentProgram != savedProgram))
|
||||
glCheck(GLEXT_glUseProgramObject(savedProgram));
|
||||
}
|
||||
|
||||
TransientContextLock lock; ///< Lock to keep context active while uniform is bound
|
||||
GLEXT_GLhandle savedProgram; ///< Handle to the previously active program object
|
||||
GLEXT_GLhandle currentProgram; ///< Handle to the program object of the modified sf::Shader instance
|
||||
GLint location; ///< Uniform location, used by the surrounding sf::Shader code
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
ShaderImplDefault::ShaderImplDefault() :
|
||||
m_shaderProgram (0),
|
||||
m_currentTexture(-1),
|
||||
m_textures (),
|
||||
m_uniforms ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
ShaderImplDefault::~ShaderImplDefault()
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Destroy effect program
|
||||
if (m_shaderProgram)
|
||||
glCheck(GLEXT_glDeleteObject(castToGlHandle(m_shaderProgram)));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, float x)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform1f(binder.location, x));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Vec2& v)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform2f(binder.location, v.x, v.y));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Vec3& v)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform3f(binder.location, v.x, v.y, v.z));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Vec4& v)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform4f(binder.location, v.x, v.y, v.z, v.w));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, int x)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform1i(binder.location, x));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Ivec2& v)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform2i(binder.location, v.x, v.y));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Ivec3& v)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform3i(binder.location, v.x, v.y, v.z));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Ivec4& v)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform4i(binder.location, v.x, v.y, v.z, v.w));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Mat3& matrix)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniformMatrix3fv(binder.location, 1, GL_FALSE, matrix.array));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Glsl::Mat4& matrix)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniformMatrix4fv(binder.location, 1, GL_FALSE, matrix.array));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, const Texture& texture)
|
||||
{
|
||||
if (m_shaderProgram)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Find the location of the variable in the shader
|
||||
int location = getUniformLocation(name);
|
||||
if (location != -1)
|
||||
{
|
||||
// Store the location -> texture mapping
|
||||
TextureTable::iterator it = m_textures.find(location);
|
||||
if (it == m_textures.end())
|
||||
{
|
||||
// New entry, make sure there are enough texture units
|
||||
GLint maxUnits = getMaxTextureUnits();
|
||||
if (m_textures.size() + 1 >= static_cast<std::size_t>(maxUnits))
|
||||
{
|
||||
err() << "Impossible to use texture \"" << name << "\" for shader: all available texture units are used" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_textures[location] = &texture;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Location already used, just replace the texture
|
||||
it->second = &texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniform(const std::string& name, Shader::CurrentTextureType)
|
||||
{
|
||||
if (m_shaderProgram)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Find the location of the variable in the shader
|
||||
m_currentTexture = getUniformLocation(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniformArray(const std::string& name, const float* scalarArray, std::size_t length)
|
||||
{
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform1fv(binder.location, static_cast<GLsizei>(length), scalarArray));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length)
|
||||
{
|
||||
std::vector<float> contiguous = flatten(vectorArray, length);
|
||||
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform2fv(binder.location, static_cast<GLsizei>(length), &contiguous[0]));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length)
|
||||
{
|
||||
std::vector<float> contiguous = flatten(vectorArray, length);
|
||||
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform3fv(binder.location, static_cast<GLsizei>(length), &contiguous[0]));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length)
|
||||
{
|
||||
std::vector<float> contiguous = flatten(vectorArray, length);
|
||||
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniform4fv(binder.location, static_cast<GLsizei>(length), &contiguous[0]));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length)
|
||||
{
|
||||
const std::size_t matrixSize = 3 * 3;
|
||||
|
||||
std::vector<float> contiguous(matrixSize * length);
|
||||
for (std::size_t i = 0; i < length; ++i)
|
||||
priv::copyMatrix(matrixArray[i].array, matrixSize, &contiguous[matrixSize * i]);
|
||||
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniformMatrix3fv(binder.location, static_cast<GLsizei>(length), GL_FALSE, &contiguous[0]));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length)
|
||||
{
|
||||
const std::size_t matrixSize = 4 * 4;
|
||||
|
||||
std::vector<float> contiguous(matrixSize * length);
|
||||
for (std::size_t i = 0; i < length; ++i)
|
||||
priv::copyMatrix(matrixArray[i].array, matrixSize, &contiguous[matrixSize * i]);
|
||||
|
||||
UniformBinder binder(*this, name);
|
||||
if (binder.location != -1)
|
||||
glCheck(GLEXT_glUniformMatrix4fv(binder.location, static_cast<GLsizei>(length), GL_FALSE, &contiguous[0]));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int ShaderImplDefault::getNativeHandle() const
|
||||
{
|
||||
return m_shaderProgram;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::bind(const ShaderImplDefault* shader)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that we can use shaders
|
||||
if (!isAvailable())
|
||||
{
|
||||
err() << "Failed to bind or unbind shader: your system doesn't support shaders "
|
||||
<< "(you should test ShaderImplDefault::isAvailable() before trying to use the Shader class)" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (shader && shader->m_shaderProgram)
|
||||
{
|
||||
// Enable the program
|
||||
glCheck(GLEXT_glUseProgramObject(castToGlHandle(shader->m_shaderProgram)));
|
||||
|
||||
// Bind the textures
|
||||
shader->bindTextures();
|
||||
|
||||
// Bind the current texture
|
||||
if (shader->m_currentTexture != -1)
|
||||
glCheck(GLEXT_glUniform1i(shader->m_currentTexture, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Bind no shader
|
||||
glCheck(GLEXT_glUseProgramObject(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ShaderImplDefault::isAvailable()
|
||||
{
|
||||
Lock lock(isAvailableMutex);
|
||||
|
||||
static bool checked = false;
|
||||
static bool available = false;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
checked = true;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
sf::priv::ensureExtensionsInit();
|
||||
|
||||
available = GLEXT_multitexture &&
|
||||
GLEXT_shading_language_100 &&
|
||||
GLEXT_shader_objects &&
|
||||
GLEXT_vertex_shader &&
|
||||
GLEXT_fragment_shader;
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ShaderImplDefault::isGeometryAvailable()
|
||||
{
|
||||
Lock lock(isAvailableMutex);
|
||||
|
||||
static bool checked = false;
|
||||
static bool available = false;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
checked = true;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
sf::priv::ensureExtensionsInit();
|
||||
|
||||
available = isAvailable() && GLEXT_geometry_shader4;
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ShaderImplDefault::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// First make sure that we can use shaders
|
||||
if (!isAvailable())
|
||||
{
|
||||
err() << "Failed to create a shader: your system doesn't support shaders "
|
||||
<< "(you should test ShaderImplDefault::isAvailable() before trying to use the Shader class)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure we can use geometry shaders
|
||||
if (geometryShaderCode && !isGeometryAvailable())
|
||||
{
|
||||
err() << "Failed to create a shader: your system doesn't support geometry shaders "
|
||||
<< "(you should test ShaderImplDefault::isGeometryAvailable() before trying to use geometry shaders)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Destroy the shader if it was already created
|
||||
if (m_shaderProgram)
|
||||
{
|
||||
glCheck(GLEXT_glDeleteObject(castToGlHandle(m_shaderProgram)));
|
||||
m_shaderProgram = 0;
|
||||
}
|
||||
|
||||
// Reset the internal state
|
||||
m_currentTexture = -1;
|
||||
m_textures.clear();
|
||||
m_uniforms.clear();
|
||||
|
||||
// Create the program
|
||||
GLEXT_GLhandle shaderProgram;
|
||||
glCheck(shaderProgram = GLEXT_glCreateProgramObject());
|
||||
|
||||
// Create the vertex shader if needed
|
||||
if (vertexShaderCode)
|
||||
{
|
||||
// Create and compile the shader
|
||||
GLEXT_GLhandle vertexShader;
|
||||
glCheck(vertexShader = GLEXT_glCreateShaderObject(GLEXT_GL_VERTEX_SHADER));
|
||||
glCheck(GLEXT_glShaderSource(vertexShader, 1, &vertexShaderCode, NULL));
|
||||
glCheck(GLEXT_glCompileShader(vertexShader));
|
||||
|
||||
// Check the compile log
|
||||
GLint success;
|
||||
glCheck(GLEXT_glGetObjectParameteriv(vertexShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
char log[1024];
|
||||
glCheck(GLEXT_glGetInfoLog(vertexShader, sizeof(log), 0, log));
|
||||
err() << "Failed to compile vertex shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
glCheck(GLEXT_glDeleteObject(vertexShader));
|
||||
glCheck(GLEXT_glDeleteObject(shaderProgram));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach the shader to the program, and delete it (not needed anymore)
|
||||
glCheck(GLEXT_glAttachObject(shaderProgram, vertexShader));
|
||||
glCheck(GLEXT_glDeleteObject(vertexShader));
|
||||
}
|
||||
|
||||
// Create the geometry shader if needed
|
||||
if (geometryShaderCode)
|
||||
{
|
||||
// Create and compile the shader
|
||||
GLEXT_GLhandle geometryShader = GLEXT_glCreateShaderObject(GLEXT_GL_GEOMETRY_SHADER);
|
||||
glCheck(GLEXT_glShaderSource(geometryShader, 1, &geometryShaderCode, NULL));
|
||||
glCheck(GLEXT_glCompileShader(geometryShader));
|
||||
|
||||
// Check the compile log
|
||||
GLint success;
|
||||
glCheck(GLEXT_glGetObjectParameteriv(geometryShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
char log[1024];
|
||||
glCheck(GLEXT_glGetInfoLog(geometryShader, sizeof(log), 0, log));
|
||||
err() << "Failed to compile geometry shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
glCheck(GLEXT_glDeleteObject(geometryShader));
|
||||
glCheck(GLEXT_glDeleteObject(shaderProgram));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach the shader to the program, and delete it (not needed anymore)
|
||||
glCheck(GLEXT_glAttachObject(shaderProgram, geometryShader));
|
||||
glCheck(GLEXT_glDeleteObject(geometryShader));
|
||||
}
|
||||
|
||||
// Create the fragment shader if needed
|
||||
if (fragmentShaderCode)
|
||||
{
|
||||
// Create and compile the shader
|
||||
GLEXT_GLhandle fragmentShader;
|
||||
glCheck(fragmentShader = GLEXT_glCreateShaderObject(GLEXT_GL_FRAGMENT_SHADER));
|
||||
glCheck(GLEXT_glShaderSource(fragmentShader, 1, &fragmentShaderCode, NULL));
|
||||
glCheck(GLEXT_glCompileShader(fragmentShader));
|
||||
|
||||
// Check the compile log
|
||||
GLint success;
|
||||
glCheck(GLEXT_glGetObjectParameteriv(fragmentShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
char log[1024];
|
||||
glCheck(GLEXT_glGetInfoLog(fragmentShader, sizeof(log), 0, log));
|
||||
err() << "Failed to compile fragment shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
glCheck(GLEXT_glDeleteObject(fragmentShader));
|
||||
glCheck(GLEXT_glDeleteObject(shaderProgram));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach the shader to the program, and delete it (not needed anymore)
|
||||
glCheck(GLEXT_glAttachObject(shaderProgram, fragmentShader));
|
||||
glCheck(GLEXT_glDeleteObject(fragmentShader));
|
||||
}
|
||||
|
||||
// Link the program
|
||||
glCheck(GLEXT_glLinkProgram(shaderProgram));
|
||||
|
||||
// Check the link log
|
||||
GLint success;
|
||||
glCheck(GLEXT_glGetObjectParameteriv(shaderProgram, GLEXT_GL_OBJECT_LINK_STATUS, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
char log[1024];
|
||||
glCheck(GLEXT_glGetInfoLog(shaderProgram, sizeof(log), 0, log));
|
||||
err() << "Failed to link shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
glCheck(GLEXT_glDeleteObject(shaderProgram));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_shaderProgram = castFromGlHandle(shaderProgram);
|
||||
|
||||
// Force an OpenGL flush, so that the shader will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplDefault::bindTextures() const
|
||||
{
|
||||
TextureTable::const_iterator it = m_textures.begin();
|
||||
for (std::size_t i = 0; i < m_textures.size(); ++i)
|
||||
{
|
||||
GLint index = static_cast<GLsizei>(i + 1);
|
||||
glCheck(GLEXT_glUniform1i(it->first, index));
|
||||
glCheck(GLEXT_glActiveTexture(GLEXT_GL_TEXTURE0 + index));
|
||||
Texture::bind(it->second);
|
||||
++it;
|
||||
}
|
||||
|
||||
// Make sure that the texture unit which is left active is the number 0
|
||||
glCheck(GLEXT_glActiveTexture(GLEXT_GL_TEXTURE0));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
int ShaderImplDefault::getUniformLocation(const std::string& name)
|
||||
{
|
||||
// Check the cache
|
||||
UniformTable::const_iterator it = m_uniforms.find(name);
|
||||
if (it != m_uniforms.end())
|
||||
{
|
||||
// Already in cache, return it
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not in cache, request the location from OpenGL
|
||||
int location = GLEXT_glGetUniformLocation(castToGlHandle(m_shaderProgram), name.c_str());
|
||||
m_uniforms.insert(std::make_pair(name, location));
|
||||
|
||||
if (location == -1)
|
||||
err() << "Uniform \"" << name << "\" not found in shader" << std::endl;
|
||||
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
327
src/SFML/Graphics/OpenGL/GL1/ShaderImplDefault.hpp
Normal file
327
src/SFML/Graphics/OpenGL/GL1/ShaderImplDefault.hpp
Normal file
@ -0,0 +1,327 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_SHADER_IMPL_DEFAULT_HPP
|
||||
#define SFML_SHADER_IMPL_DEFAULT_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/ShaderImpl.hpp>
|
||||
#include <SFML/Graphics/Glsl.hpp>
|
||||
#include <SFML/Window/GlResource.hpp>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Texture;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default specialization of ShaderImpl
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class ShaderImplDefault : public ShaderImpl, GlResource
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
ShaderImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~ShaderImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Bind a shader for rendering
|
||||
///
|
||||
/// \param shader Shader to bind, can be null to use no shader
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void bind(const ShaderImplDefault* shader);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether or not the system supports shaders
|
||||
///
|
||||
/// \return True if shaders are supported, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isAvailable();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether or not the system supports geometry shaders
|
||||
///
|
||||
/// \return True if geometry shaders are supported, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isGeometryAvailable();
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p float uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param x Value of the float scalar
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, float x);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec2 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec2 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec2& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec3 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec3 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec3& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec4 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec4 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec4& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p int uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param x Value of the int scalar
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, int x);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec2 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec2 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec2& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec3 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec3 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec3& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec4 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec4 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec4& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p mat3 matrix
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrix Value of the mat3 matrix
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Mat3& matrix);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p mat4 matrix
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrix Value of the mat4 matrix
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Mat4& matrix);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify a texture as \p sampler2D uniform
|
||||
///
|
||||
/// \param name Name of the texture in the shader
|
||||
/// \param texture Texture to assign
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Texture& texture);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify current texture as \p sampler2D uniform
|
||||
///
|
||||
/// \param name Name of the texture in the shader
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, Shader::CurrentTextureType);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p float[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param scalarArray pointer to array of \p float values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const float* scalarArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec2[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec2 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec3[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec3 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec4[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec4 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p mat3[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrixArray pointer to array of \p mat3 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p mat4[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrixArray pointer to array of \p mat4 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the underlying OpenGL handle of the shader.
|
||||
///
|
||||
/// \return OpenGL handle of the shader or 0 if not yet loaded
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual unsigned int getNativeHandle() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Compile the shader(s) and create the program
|
||||
///
|
||||
/// \param vertexShaderCode Source code of the vertex shader
|
||||
/// \param geometryShaderCode Source code of the geometry shader
|
||||
/// \param fragmentShaderCode Source code of the fragment shader
|
||||
///
|
||||
/// \return True on success, false if any error happened
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Bind all the textures used by the shader
|
||||
///
|
||||
/// This function each texture to a different unit, and
|
||||
/// updates the corresponding variables in the shader accordingly.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void bindTextures() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the location ID of a shader uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable to search
|
||||
///
|
||||
/// \return Location ID of the uniform, or -1 if not found
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
int getUniformLocation(const std::string& name);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief RAII object to save and restore the program
|
||||
/// binding while uniforms are being set
|
||||
///
|
||||
/// Implementation is private in the .cpp file.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
struct UniformBinder;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Types
|
||||
////////////////////////////////////////////////////////////
|
||||
typedef std::map<int, const Texture*> TextureTable;
|
||||
typedef std::map<std::string, int> UniformTable;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int m_shaderProgram; ///< OpenGL identifier for the program
|
||||
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
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SHADER_IMPL_DEFAULT_HPP
|
796
src/SFML/Graphics/OpenGL/GL1/TextureImplDefault.cpp
Normal file
796
src/SFML/Graphics/OpenGL/GL1/TextureImplDefault.cpp
Normal file
@ -0,0 +1,796 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/OpenGL/GL1/TextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/Window/Window.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::Mutex idMutex;
|
||||
sf::Mutex maximumSizeMutex;
|
||||
|
||||
// Thread-safe unique identifier generator,
|
||||
// is used for states cache (see RenderTarget)
|
||||
sf::Uint64 getUniqueId()
|
||||
{
|
||||
sf::Lock lock(idMutex);
|
||||
|
||||
static sf::Uint64 id = 1; // start at 1, zero is "no texture"
|
||||
|
||||
return id++;
|
||||
}
|
||||
|
||||
// Automatic wrapper for saving and restoring the current texture binding
|
||||
struct TextureSaver
|
||||
{
|
||||
TextureSaver()
|
||||
{
|
||||
glCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBinding));
|
||||
}
|
||||
|
||||
~TextureSaver()
|
||||
{
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, textureBinding));
|
||||
}
|
||||
|
||||
GLint textureBinding;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureImplDefault::TextureImplDefault() :
|
||||
m_size (0, 0),
|
||||
m_actualSize (0, 0),
|
||||
m_texture (0),
|
||||
m_isSmooth (false),
|
||||
m_sRgb (false),
|
||||
m_isRepeated (false),
|
||||
m_pixelsFlipped(false),
|
||||
m_fboAttachment(false),
|
||||
m_hasMipmap (false),
|
||||
m_cacheId (getUniqueId())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureImplDefault::TextureImplDefault(const TextureImplDefault& copy) :
|
||||
m_size (0, 0),
|
||||
m_actualSize (0, 0),
|
||||
m_texture (0),
|
||||
m_isSmooth (copy.m_isSmooth),
|
||||
m_sRgb (copy.m_sRgb),
|
||||
m_isRepeated (copy.m_isRepeated),
|
||||
m_pixelsFlipped(false),
|
||||
m_fboAttachment(false),
|
||||
m_hasMipmap (false),
|
||||
m_cacheId (getUniqueId())
|
||||
{
|
||||
if (copy.m_texture)
|
||||
{
|
||||
if (create(copy.getSize().x, copy.getSize().y))
|
||||
{
|
||||
update(copy, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to copy texture, failed to create new texture" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureImplDefault::~TextureImplDefault()
|
||||
{
|
||||
// Destroy the OpenGL texture
|
||||
if (m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
GLuint texture = static_cast<GLuint>(m_texture);
|
||||
glCheck(glDeleteTextures(1, &texture));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool TextureImplDefault::create(unsigned int width, unsigned int height)
|
||||
{
|
||||
// Check if texture parameters are valid before creating it
|
||||
if ((width == 0) || (height == 0))
|
||||
{
|
||||
err() << "Failed to create texture, invalid size (" << width << "x" << height << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
|
||||
// Compute the internal texture dimensions depending on NPOT textures support
|
||||
Vector2u actualSize(getValidSize(width), getValidSize(height));
|
||||
|
||||
// Check the maximum texture size
|
||||
unsigned int maxSize = getMaximumSize();
|
||||
if ((actualSize.x > maxSize) || (actualSize.y > maxSize))
|
||||
{
|
||||
err() << "Failed to create texture, its internal size is too high "
|
||||
<< "(" << actualSize.x << "x" << actualSize.y << ", "
|
||||
<< "maximum is " << maxSize << "x" << maxSize << ")"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// All the validity checks passed, we can store the new texture settings
|
||||
m_size.x = width;
|
||||
m_size.y = height;
|
||||
m_actualSize = actualSize;
|
||||
m_pixelsFlipped = false;
|
||||
m_fboAttachment = false;
|
||||
|
||||
// Create the OpenGL texture if it doesn't exist yet
|
||||
if (!m_texture)
|
||||
{
|
||||
GLuint texture;
|
||||
glCheck(glGenTextures(1, &texture));
|
||||
m_texture = static_cast<unsigned int>(texture);
|
||||
}
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
static bool textureEdgeClamp = GLEXT_texture_edge_clamp;
|
||||
|
||||
if (!m_isRepeated && !textureEdgeClamp)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
err() << "OpenGL extension SGIS_texture_edge_clamp unavailable" << std::endl;
|
||||
err() << "Artifacts may occur along texture edges" << std::endl;
|
||||
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool textureSrgb = GLEXT_texture_sRGB;
|
||||
|
||||
if (m_sRgb && !textureSrgb)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
#ifndef SFML_OPENGL_ES
|
||||
err() << "OpenGL extension EXT_texture_sRGB unavailable" << std::endl;
|
||||
#else
|
||||
err() << "OpenGL ES extension EXT_sRGB unavailable" << std::endl;
|
||||
#endif
|
||||
err() << "Automatic sRGB to linear conversion disabled" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
|
||||
m_sRgb = false;
|
||||
}
|
||||
|
||||
// Initialize the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexImage2D(GL_TEXTURE_2D, 0, (m_sRgb ? GLEXT_GL_SRGB8_ALPHA8 : GL_RGBA), m_actualSize.x, m_actualSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
m_hasMipmap = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool TextureImplDefault::loadFromImage(const Image& image, const IntRect& area)
|
||||
{
|
||||
// Retrieve the image size
|
||||
int width = static_cast<int>(image.getSize().x);
|
||||
int height = static_cast<int>(image.getSize().y);
|
||||
|
||||
// Load the entire image if the source area is either empty or contains the whole image
|
||||
if (area.width == 0 || (area.height == 0) ||
|
||||
((area.left <= 0) && (area.top <= 0) && (area.width >= width) && (area.height >= height)))
|
||||
{
|
||||
// Load the entire image
|
||||
if (create(image.getSize().x, image.getSize().y))
|
||||
{
|
||||
update(image.getPixelsPtr(), image.getSize().x, image.getSize().y, 0, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load a sub-area of the image
|
||||
|
||||
// Adjust the rectangle to the size of the image
|
||||
IntRect rectangle = area;
|
||||
if (rectangle.left < 0) rectangle.left = 0;
|
||||
if (rectangle.top < 0) rectangle.top = 0;
|
||||
if (rectangle.left + rectangle.width > width) rectangle.width = width - rectangle.left;
|
||||
if (rectangle.top + rectangle.height > height) rectangle.height = height - rectangle.top;
|
||||
|
||||
// Create the texture and upload the pixels
|
||||
if (create(rectangle.width, rectangle.height))
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
// Copy the pixels to the texture, row by row
|
||||
const Uint8* pixels = image.getPixelsPtr() + 4 * (rectangle.left + (width * rectangle.top));
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
for (int i = 0; i < rectangle.height; ++i)
|
||||
{
|
||||
glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, rectangle.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
pixels += 4 * width;
|
||||
}
|
||||
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
|
||||
// Force an OpenGL flush, so that the texture will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2u TextureImplDefault::getSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Image TextureImplDefault::copyToImage() const
|
||||
{
|
||||
// Easy case: empty texture
|
||||
if (!m_texture)
|
||||
return Image();
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
// Create an array of pixels
|
||||
std::vector<Uint8> pixels(m_size.x * m_size.y * 4);
|
||||
|
||||
#ifdef SFML_OPENGL_ES
|
||||
|
||||
// OpenGL ES doesn't have the glGetTexImage function, the only way to read
|
||||
// from a texture is to bind it to a FBO and use glReadPixels
|
||||
GLuint frameBuffer = 0;
|
||||
glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer));
|
||||
if (frameBuffer)
|
||||
{
|
||||
GLint previousFrameBuffer;
|
||||
glCheck(glGetIntegerv(GLEXT_GL_FRAMEBUFFER_BINDING, &previousFrameBuffer));
|
||||
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, frameBuffer));
|
||||
glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
|
||||
glCheck(glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]));
|
||||
glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer));
|
||||
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, previousFrameBuffer));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if ((m_size == m_actualSize) && !m_pixelsFlipped)
|
||||
{
|
||||
// Texture is not padded nor flipped, we can use a direct copy
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Texture is either padded or flipped, we have to use a slower algorithm
|
||||
|
||||
// All the pixels will first be copied to a temporary array
|
||||
std::vector<Uint8> allPixels(m_actualSize.x * m_actualSize.y * 4);
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &allPixels[0]));
|
||||
|
||||
// Then we copy the useful pixels from the temporary array to the final one
|
||||
const Uint8* src = &allPixels[0];
|
||||
Uint8* dst = &pixels[0];
|
||||
int srcPitch = m_actualSize.x * 4;
|
||||
int dstPitch = m_size.x * 4;
|
||||
|
||||
// Handle the case where source pixels are flipped vertically
|
||||
if (m_pixelsFlipped)
|
||||
{
|
||||
src += srcPitch * (m_size.y - 1);
|
||||
srcPitch = -srcPitch;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_size.y; ++i)
|
||||
{
|
||||
std::memcpy(dst, src, dstPitch);
|
||||
src += srcPitch;
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
|
||||
// Create the image
|
||||
Image image;
|
||||
image.create(m_size.x, m_size.y, &pixels[0]);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y)
|
||||
{
|
||||
assert(x + width <= m_size.x);
|
||||
assert(y + height <= m_size.y);
|
||||
|
||||
if (pixels && m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
// Copy pixels from the given array to the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
m_pixelsFlipped = false;
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
// Force an OpenGL flush, so that the texture data will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::update(const TextureImpl& texture, unsigned int x, unsigned int y)
|
||||
{
|
||||
const TextureImplDefault& texture_ = static_cast<const TextureImplDefault&>(texture);
|
||||
|
||||
assert(x + texture_.m_size.x <= m_size.x);
|
||||
assert(y + texture_.m_size.y <= m_size.y);
|
||||
|
||||
if (!m_texture || !texture_.m_texture)
|
||||
return;
|
||||
|
||||
#ifndef SFML_OPENGL_ES
|
||||
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
}
|
||||
|
||||
if (GLEXT_framebuffer_object && GLEXT_framebuffer_blit)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Save the current bindings so we can restore them after we are done
|
||||
GLint readFramebuffer = 0;
|
||||
GLint drawFramebuffer = 0;
|
||||
|
||||
glCheck(glGetIntegerv(GLEXT_GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer));
|
||||
glCheck(glGetIntegerv(GLEXT_GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer));
|
||||
|
||||
// Create the framebuffers
|
||||
GLuint sourceFrameBuffer = 0;
|
||||
GLuint destFrameBuffer = 0;
|
||||
glCheck(GLEXT_glGenFramebuffers(1, &sourceFrameBuffer));
|
||||
glCheck(GLEXT_glGenFramebuffers(1, &destFrameBuffer));
|
||||
|
||||
if (!sourceFrameBuffer || !destFrameBuffer)
|
||||
{
|
||||
err() << "Cannot copy texture, failed to create a frame buffer object" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Link the source texture to the source frame buffer
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, sourceFrameBuffer));
|
||||
glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_READ_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_.m_texture, 0));
|
||||
|
||||
// Link the destination texture to the destination frame buffer
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, destFrameBuffer));
|
||||
glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_DRAW_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
|
||||
|
||||
// A final check, just to be sure...
|
||||
GLenum sourceStatus;
|
||||
glCheck(sourceStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_READ_FRAMEBUFFER));
|
||||
|
||||
GLenum destStatus;
|
||||
glCheck(destStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_DRAW_FRAMEBUFFER));
|
||||
|
||||
if ((sourceStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE) && (destStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE))
|
||||
{
|
||||
// Blit the texture contents from the source to the destination texture
|
||||
glCheck(GLEXT_glBlitFramebuffer(
|
||||
0, texture_.m_pixelsFlipped ? texture_.m_size.y : 0, texture_.m_size.x, texture_.m_pixelsFlipped ? 0 : texture_.m_size.y, // Source rectangle, flip y if source is flipped
|
||||
x, y, x + texture_.m_size.x, y + texture_.m_size.y, // Destination rectangle
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Cannot copy texture, failed to link texture to frame buffer" << std::endl;
|
||||
}
|
||||
|
||||
// Restore previously bound framebuffers
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, readFramebuffer));
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, drawFramebuffer));
|
||||
|
||||
// Delete the framebuffers
|
||||
glCheck(GLEXT_glDeleteFramebuffers(1, &sourceFrameBuffer));
|
||||
glCheck(GLEXT_glDeleteFramebuffers(1, &destFrameBuffer));
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
// Set the parameters of this texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
m_pixelsFlipped = false;
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
// Force an OpenGL flush, so that the texture data will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
|
||||
update(texture_.copyToImage().getPixelsPtr(), x, y, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::update(const Window& window, unsigned int x, unsigned int y)
|
||||
{
|
||||
assert(x + window.getSize().x <= m_size.x);
|
||||
assert(y + window.getSize().y <= m_size.y);
|
||||
|
||||
if (m_texture && window.setActive(true))
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
// Copy pixels from the back-buffer to the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 0, 0, window.getSize().x, window.getSize().y));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
m_pixelsFlipped = true;
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
// Force an OpenGL flush, so that the texture will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::setSmooth(bool smooth)
|
||||
{
|
||||
if (smooth != m_isSmooth)
|
||||
{
|
||||
m_isSmooth = smooth;
|
||||
|
||||
if (m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
|
||||
if (m_hasMipmap)
|
||||
{
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR));
|
||||
}
|
||||
else
|
||||
{
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool TextureImplDefault::isSmooth() const
|
||||
{
|
||||
return m_isSmooth;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::setSrgb(bool sRgb)
|
||||
{
|
||||
m_sRgb = sRgb;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool TextureImplDefault::isSrgb() const
|
||||
{
|
||||
return m_sRgb;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::setRepeated(bool repeated)
|
||||
{
|
||||
if (repeated != m_isRepeated)
|
||||
{
|
||||
m_isRepeated = repeated;
|
||||
|
||||
if (m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
static bool textureEdgeClamp = GLEXT_texture_edge_clamp;
|
||||
|
||||
if (!m_isRepeated && !textureEdgeClamp)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
err() << "OpenGL extension SGIS_texture_edge_clamp unavailable" << std::endl;
|
||||
err() << "Artifacts may occur along texture edges" << std::endl;
|
||||
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool TextureImplDefault::isRepeated() const
|
||||
{
|
||||
return m_isRepeated;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool TextureImplDefault::generateMipmap()
|
||||
{
|
||||
if (!m_texture)
|
||||
return false;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
|
||||
if (!GLEXT_framebuffer_object)
|
||||
return false;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(GLEXT_glGenerateMipmap(GL_TEXTURE_2D));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR));
|
||||
|
||||
m_hasMipmap = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::invalidateMipmap()
|
||||
{
|
||||
if (!m_hasMipmap)
|
||||
return;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
TextureSaver save;
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
|
||||
m_hasMipmap = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void TextureImplDefault::bind(const TextureImplDefault* texture, Texture::CoordinateType coordinateType)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
if (texture && texture->m_texture)
|
||||
{
|
||||
// Bind the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, texture->m_texture));
|
||||
|
||||
// Check if we need to define a special texture matrix
|
||||
if ((coordinateType == Texture::Pixels) || texture->m_pixelsFlipped)
|
||||
{
|
||||
GLfloat matrix[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};
|
||||
|
||||
// If non-normalized coordinates (= pixels) are requested, we need to
|
||||
// setup scale factors that convert the range [0 .. size] to [0 .. 1]
|
||||
if (coordinateType == Texture::Pixels)
|
||||
{
|
||||
matrix[0] = 1.f / texture->m_actualSize.x;
|
||||
matrix[5] = 1.f / texture->m_actualSize.y;
|
||||
}
|
||||
|
||||
// If pixels are flipped we must invert the Y axis
|
||||
if (texture->m_pixelsFlipped)
|
||||
{
|
||||
matrix[5] = -matrix[5];
|
||||
matrix[13] = static_cast<float>(texture->m_size.y) / texture->m_actualSize.y;
|
||||
}
|
||||
|
||||
// Load the matrix
|
||||
glCheck(glMatrixMode(GL_TEXTURE));
|
||||
glCheck(glLoadMatrixf(matrix));
|
||||
|
||||
// Go back to model-view mode (sf::RenderTarget relies on it)
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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 (sf::RenderTarget relies on it)
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int TextureImplDefault::getMaximumSize()
|
||||
{
|
||||
Lock lock(maximumSizeMutex);
|
||||
|
||||
static bool checked = false;
|
||||
static GLint size = 0;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
checked = true;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
|
||||
}
|
||||
|
||||
return static_cast<unsigned int>(size);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int TextureImplDefault::getNativeHandle() const
|
||||
{
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int TextureImplDefault::getValidSize(unsigned int size)
|
||||
{
|
||||
if (GLEXT_texture_non_power_of_two)
|
||||
{
|
||||
// If hardware supports NPOT textures, then just return the unmodified size
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If hardware doesn't support NPOT textures, we calculate the nearest power of two
|
||||
unsigned int powerOfTwo = 1;
|
||||
while (powerOfTwo < size)
|
||||
powerOfTwo *= 2;
|
||||
|
||||
return powerOfTwo;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
297
src/SFML/Graphics/OpenGL/GL1/TextureImplDefault.hpp
Normal file
297
src/SFML/Graphics/OpenGL/GL1/TextureImplDefault.hpp
Normal file
@ -0,0 +1,297 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_TEXTURE_IMPL_DEFAULT_HPP
|
||||
#define SFML_TEXTURE_IMPL_DEFAULT_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/TextureImpl.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Window/GlResource.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class InputStream;
|
||||
class RenderTarget;
|
||||
class RenderTexture;
|
||||
class Text;
|
||||
class Window;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
class RenderTargetImplDefault;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Image living on the graphics card that can be used for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class TextureImplDefault : public TextureImpl, private GlResource
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
/// Creates an empty texture.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Copy constructor
|
||||
///
|
||||
/// \param copy instance to copy
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureImplDefault(const TextureImplDefault& copy);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~TextureImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Bind a texture for rendering
|
||||
///
|
||||
/// \param texture Pointer to the texture to bind, can be null to use no texture
|
||||
/// \param coordinateType Type of texture coordinates to use
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void bind(const TextureImplDefault* texture, Texture::CoordinateType coordinateType = Texture::Normalized);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the maximum texture size allowed
|
||||
///
|
||||
/// \return Maximum size allowed for textures, in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static unsigned int getMaximumSize();
|
||||
|
||||
private:
|
||||
|
||||
friend class sf::Text;
|
||||
friend class sf::RenderTexture;
|
||||
friend class RenderTargetImplDefault;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the texture
|
||||
///
|
||||
/// \param width Width of the texture
|
||||
/// \param height Height of the texture
|
||||
///
|
||||
/// \return True if creation was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool create(unsigned int width, unsigned int height);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the texture from an image
|
||||
///
|
||||
/// \param image Image to load into the texture
|
||||
/// \param area Area of the image to load
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
/// \see loadFromFile, loadFromMemory
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool loadFromImage(const Image& image, const IntRect& area);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the size of the texture
|
||||
///
|
||||
/// \return Size in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Vector2u getSize() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Copy the texture pixels to an image
|
||||
///
|
||||
/// \return Image containing the texture's pixels
|
||||
///
|
||||
/// \see loadFromImage
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Image copyToImage() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of the texture from an array of pixels
|
||||
///
|
||||
/// \param pixels Array of pixels to copy to the texture
|
||||
/// \param width Width of the pixel region contained in \a pixels
|
||||
/// \param height Height of the pixel region contained in \a pixels
|
||||
/// \param x X offset in the texture where to copy the source pixels
|
||||
/// \param y Y offset in the texture where to copy the source pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of this texture from another texture
|
||||
///
|
||||
/// \param texture Source texture to copy to this texture
|
||||
/// \param x X offset in this texture where to copy the source texture
|
||||
/// \param y Y offset in this texture where to copy the source texture
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void update(const TextureImpl& texture, unsigned int x, unsigned int y);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of the texture from the contents of a window
|
||||
///
|
||||
/// \param window Window to copy to the texture
|
||||
/// \param x X offset in the texture where to copy the source window
|
||||
/// \param y Y offset in the texture where to copy the source window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void update(const Window& window, unsigned int x, unsigned int y);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable the smooth filter
|
||||
///
|
||||
/// \param smooth True to enable smoothing, false to disable it
|
||||
///
|
||||
/// \see isSmooth
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setSmooth(bool smooth);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether the smooth filter is enabled or not
|
||||
///
|
||||
/// \return True if smoothing is enabled, false if it is disabled
|
||||
///
|
||||
/// \see setSmooth
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool isSmooth() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable conversion from sRGB
|
||||
///
|
||||
/// \param sRgb True to enable sRGB conversion, false to disable it
|
||||
///
|
||||
/// \see isSrgb
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setSrgb(bool sRgb);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether the texture source is converted from sRGB or not
|
||||
///
|
||||
/// \return True if the texture source is converted from sRGB, false if not
|
||||
///
|
||||
/// \see setSrgb
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool isSrgb() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable repeating
|
||||
///
|
||||
/// \param repeated True to repeat the texture, false to disable repeating
|
||||
///
|
||||
/// \see isRepeated
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setRepeated(bool repeated);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether the texture is repeated or not
|
||||
///
|
||||
/// \return True if repeat mode is enabled, false if it is disabled
|
||||
///
|
||||
/// \see setRepeated
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool isRepeated() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Generate a mipmap using the current texture data
|
||||
///
|
||||
/// \return True if mipmap generation was successful, false if unsuccessful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool generateMipmap();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the underlying OpenGL handle of the texture.
|
||||
///
|
||||
/// \return OpenGL handle of the texture or 0 if not yet created
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual unsigned int getNativeHandle() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get a valid image size according to hardware support
|
||||
///
|
||||
/// This function checks whether the graphics driver supports
|
||||
/// non power of two sizes or not, and adjusts the size
|
||||
/// accordingly.
|
||||
/// The returned size is greater than or equal to the original size.
|
||||
///
|
||||
/// \param size size to convert
|
||||
///
|
||||
/// \return Valid nearest size (greater than or equal to specified size)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static unsigned int getValidSize(unsigned int size);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Invalidate the mipmap if one exists
|
||||
///
|
||||
/// This also resets the texture's minifying function.
|
||||
/// This function is mainly for internal use by RenderTexture.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void invalidateMipmap();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2u m_size; ///< Public texture size
|
||||
Vector2u m_actualSize; ///< Actual texture size (can be greater than public size because of padding)
|
||||
unsigned int m_texture; ///< Internal texture identifier
|
||||
bool m_isSmooth; ///< Status of the smooth filter
|
||||
bool m_sRgb; ///< Should the texture source be converted from sRGB?
|
||||
bool m_isRepeated; ///< Is the texture in repeat mode?
|
||||
mutable bool m_pixelsFlipped; ///< To work around the inconsistency in Y orientation
|
||||
bool m_fboAttachment; ///< Is this texture owned by a framebuffer object?
|
||||
bool m_hasMipmap; ///< Has the mipmap been generated?
|
||||
Uint64 m_cacheId; ///< Unique number that identifies the texture to the render target's cache
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_TEXTURE_IMPL_DEFAULT_HPP
|
276
src/SFML/Graphics/OpenGL/GL1/VertexBufferImplDefault.cpp
Normal file
276
src/SFML/Graphics/OpenGL/GL1/VertexBufferImplDefault.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/OpenGL/GL1/VertexBufferImplDefault.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Vertex.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::Mutex isAvailableMutex;
|
||||
|
||||
GLenum usageToGlEnum(sf::VertexBuffer::Usage usage)
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case sf::VertexBuffer::Static: return GLEXT_GL_STATIC_DRAW;
|
||||
case sf::VertexBuffer::Dynamic: return GLEXT_GL_DYNAMIC_DRAW;
|
||||
default: return GLEXT_GL_STREAM_DRAW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBufferImplDefault::VertexBufferImplDefault() :
|
||||
m_buffer(0),
|
||||
m_size (0),
|
||||
m_usage (VertexBuffer::Stream)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBufferImplDefault::VertexBufferImplDefault(VertexBuffer::Usage usage) :
|
||||
m_buffer(0),
|
||||
m_size (0),
|
||||
m_usage (usage)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBufferImplDefault::~VertexBufferImplDefault()
|
||||
{
|
||||
if (m_buffer)
|
||||
{
|
||||
TransientContextLock contextLock;
|
||||
|
||||
glCheck(GLEXT_glDeleteBuffers(1, &m_buffer));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBufferImplDefault::create(std::size_t vertexCount)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return false;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
if (!m_buffer)
|
||||
glCheck(GLEXT_glGenBuffers(1, &m_buffer));
|
||||
|
||||
if (!m_buffer)
|
||||
{
|
||||
err() << "Could not create vertex buffer, generation failed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
|
||||
|
||||
m_size = vertexCount;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
std::size_t VertexBufferImplDefault::getVertexCount() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBufferImplDefault::update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset)
|
||||
{
|
||||
// Sanity checks
|
||||
if (!m_buffer)
|
||||
return false;
|
||||
|
||||
if (!vertices)
|
||||
return false;
|
||||
|
||||
if (offset && (offset + vertexCount > m_size))
|
||||
return false;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
|
||||
// Check if we need to resize or orphan the buffer
|
||||
if (vertexCount >= m_size)
|
||||
{
|
||||
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
|
||||
|
||||
m_size = vertexCount;
|
||||
}
|
||||
|
||||
glCheck(GLEXT_glBufferSubData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * offset, sizeof(Vertex) * vertexCount, vertices));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBufferImplDefault::update(const VertexBufferImpl& vertexBuffer)
|
||||
{
|
||||
#ifdef SFML_OPENGL_ES
|
||||
|
||||
return false;
|
||||
|
||||
#else
|
||||
|
||||
const VertexBufferImplDefault& other = static_cast<const VertexBufferImplDefault&>(vertexBuffer);
|
||||
|
||||
if (!m_buffer || !other.m_buffer)
|
||||
return false;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
sf::priv::ensureExtensionsInit();
|
||||
|
||||
if (GLEXT_copy_buffer)
|
||||
{
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, other.m_buffer));
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, m_buffer));
|
||||
|
||||
glCheck(GLEXT_glCopyBufferSubData(GLEXT_GL_COPY_READ_BUFFER, GLEXT_GL_COPY_WRITE_BUFFER, 0, 0, sizeof(Vertex) * other.m_size));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, 0));
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * other.m_size, 0, usageToGlEnum(m_usage)));
|
||||
|
||||
void* destination = 0;
|
||||
glCheck(destination = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_WRITE_ONLY));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, other.m_buffer));
|
||||
|
||||
void* source = 0;
|
||||
glCheck(source = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_READ_ONLY));
|
||||
|
||||
std::memcpy(destination, source, sizeof(Vertex) * other.m_size);
|
||||
|
||||
GLboolean sourceResult = GL_FALSE;
|
||||
glCheck(sourceResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
|
||||
GLboolean destinationResult = GL_FALSE;
|
||||
glCheck(destinationResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
|
||||
|
||||
if ((sourceResult == GL_FALSE) || (destinationResult == GL_FALSE))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int VertexBufferImplDefault::getNativeHandle() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexBufferImplDefault::bind(const VertexBufferImplDefault* vertexBuffer)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, vertexBuffer ? vertexBuffer->m_buffer : 0));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexBufferImplDefault::setUsage(VertexBuffer::Usage usage)
|
||||
{
|
||||
m_usage = usage;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::Usage VertexBufferImplDefault::getUsage() const
|
||||
{
|
||||
return m_usage;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBufferImplDefault::isAvailable()
|
||||
{
|
||||
Lock lock(isAvailableMutex);
|
||||
|
||||
static bool checked = false;
|
||||
static bool available = false;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
checked = true;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
sf::priv::ensureExtensionsInit();
|
||||
|
||||
available = GLEXT_vertex_buffer_object;
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
170
src/SFML/Graphics/OpenGL/GL1/VertexBufferImplDefault.hpp
Normal file
170
src/SFML/Graphics/OpenGL/GL1/VertexBufferImplDefault.hpp
Normal file
@ -0,0 +1,170 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_VERTEXBUFFER_IMPL_DEFAULT_HPP
|
||||
#define SFML_VERTEXBUFFER_IMPL_DEFAULT_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/VertexBufferImpl.hpp>
|
||||
#include <SFML/Window/GlResource.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class RenderTarget;
|
||||
class Vertex;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default specialization of VertexBufferImpl,
|
||||
/// using OpenGL VBOs
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class VertexBufferImplDefault : public VertexBufferImpl, GlResource
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
/// Creates an empty vertex buffer.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBufferImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Construct a VertexBuffer with a specific usage specifier
|
||||
///
|
||||
/// Creates an empty vertex buffer and sets its usage to \p usage.
|
||||
///
|
||||
/// \param usage Usage specifier
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
explicit VertexBufferImplDefault(VertexBuffer::Usage usage);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~VertexBufferImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Bind a vertex buffer for rendering
|
||||
///
|
||||
/// \param vertexBuffer Pointer to the vertex buffer to bind, can be null to use no vertex buffer
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void bind(const VertexBufferImplDefault* vertexBuffer);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether or not the system supports vertex buffers
|
||||
///
|
||||
/// \return True if vertex buffers are supported, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isAvailable();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the vertex buffer
|
||||
///
|
||||
/// \param vertexCount Number of vertices worth of memory to allocate
|
||||
///
|
||||
/// \return True if creation was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool create(std::size_t vertexCount);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the vertex count
|
||||
///
|
||||
/// \return Number of vertices in the vertex buffer
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual std::size_t getVertexCount() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of the buffer from an array of vertices
|
||||
///
|
||||
/// \param vertices Array of vertices to copy to the buffer
|
||||
/// \param vertexCount Number of vertices to copy
|
||||
/// \param offset Offset in the buffer to copy to
|
||||
///
|
||||
/// \return True if the update was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Copy the contents of another buffer into this buffer
|
||||
///
|
||||
/// \param vertexBuffer Vertex buffer whose contents to copy into this vertex buffer
|
||||
///
|
||||
/// \return True if the copy was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool update(const VertexBufferImpl& vertexBuffer);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the underlying OpenGL handle of the vertex buffer.
|
||||
///
|
||||
/// \return OpenGL handle of the vertex buffer or 0 if not yet created
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual unsigned int getNativeHandle() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the usage specifier of this vertex buffer
|
||||
///
|
||||
/// \param usage Usage specifier
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUsage(VertexBuffer::Usage usage);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the usage specifier of this vertex buffer
|
||||
///
|
||||
/// \return Usage specifier
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual VertexBuffer::Usage getUsage() const;
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int m_buffer; ///< Internal buffer identifier
|
||||
std::size_t m_size; ///< Size in Vertexes of the currently allocated buffer
|
||||
VertexBuffer::Usage m_usage; ///< How this vertex buffer is to be used
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_VERTEXBUFFER_IMPL_DEFAULT_HPP
|
@ -25,7 +25,7 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <string>
|
||||
|
@ -29,7 +29,7 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Config.hpp>
|
||||
#include <SFML/Graphics/GLExtensions.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLExtensions.hpp>
|
||||
|
||||
|
||||
namespace sf
|
@ -26,7 +26,7 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#define SF_GLAD_GL_IMPLEMENTATION
|
||||
#include <SFML/Graphics/GLExtensions.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLExtensions.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
@ -26,154 +26,54 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Drawable.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/VertexArray.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/RenderTargetImplDefault.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/VertexBuffer.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
|
||||
// GL_QUADS is unavailable on OpenGL ES, thus we need to define GL_QUADS ourselves
|
||||
#ifndef GL_QUADS
|
||||
|
||||
#define GL_QUADS 0
|
||||
|
||||
#endif // GL_QUADS
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Mutex to protect ID generation and our context-RenderTarget-map
|
||||
sf::Mutex mutex;
|
||||
|
||||
// Unique identifier, used for identifying RenderTargets when
|
||||
// tracking the currently active RenderTarget within a given context
|
||||
sf::Uint64 getUniqueId()
|
||||
{
|
||||
sf::Lock lock(mutex);
|
||||
|
||||
static sf::Uint64 id = 1; // start at 1, zero is "no RenderTarget"
|
||||
|
||||
return id++;
|
||||
}
|
||||
|
||||
// Map to help us detect whether a different RenderTarget
|
||||
// has been activated within a single context
|
||||
typedef std::map<sf::Uint64, sf::Uint64> ContextRenderTargetMap;
|
||||
ContextRenderTargetMap contextRenderTargetMap;
|
||||
|
||||
// Check if a RenderTarget with the given ID is active in the current context
|
||||
bool isActive(sf::Uint64 id)
|
||||
{
|
||||
ContextRenderTargetMap::iterator iter = contextRenderTargetMap.find(sf::Context::getActiveContextId());
|
||||
|
||||
if ((iter == contextRenderTargetMap.end()) || (iter->second != id))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert an sf::BlendMode::Factor constant to the corresponding OpenGL constant.
|
||||
sf::Uint32 factorToGlConstant(sf::BlendMode::Factor blendFactor)
|
||||
{
|
||||
switch (blendFactor)
|
||||
{
|
||||
case sf::BlendMode::Zero: return GL_ZERO;
|
||||
case sf::BlendMode::One: return GL_ONE;
|
||||
case sf::BlendMode::SrcColor: return GL_SRC_COLOR;
|
||||
case sf::BlendMode::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR;
|
||||
case sf::BlendMode::DstColor: return GL_DST_COLOR;
|
||||
case sf::BlendMode::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR;
|
||||
case sf::BlendMode::SrcAlpha: return GL_SRC_ALPHA;
|
||||
case sf::BlendMode::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA;
|
||||
case sf::BlendMode::DstAlpha: return GL_DST_ALPHA;
|
||||
case sf::BlendMode::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA;
|
||||
}
|
||||
|
||||
sf::err() << "Invalid value for sf::BlendMode::Factor! Fallback to sf::BlendMode::Zero." << std::endl;
|
||||
assert(false);
|
||||
return GL_ZERO;
|
||||
}
|
||||
|
||||
|
||||
// Convert an sf::BlendMode::BlendEquation constant to the corresponding OpenGL constant.
|
||||
sf::Uint32 equationToGlConstant(sf::BlendMode::Equation blendEquation)
|
||||
{
|
||||
switch (blendEquation)
|
||||
{
|
||||
case sf::BlendMode::Add: return GLEXT_GL_FUNC_ADD;
|
||||
case sf::BlendMode::Subtract: return GLEXT_GL_FUNC_SUBTRACT;
|
||||
case sf::BlendMode::ReverseSubtract: return GLEXT_GL_FUNC_REVERSE_SUBTRACT;
|
||||
}
|
||||
|
||||
sf::err() << "Invalid value for sf::BlendMode::Equation! Fallback to sf::BlendMode::Add." << std::endl;
|
||||
assert(false);
|
||||
return GLEXT_GL_FUNC_ADD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTarget::RenderTarget() :
|
||||
m_defaultView(),
|
||||
m_view (),
|
||||
m_cache (),
|
||||
m_id (0)
|
||||
m_impl(NULL)
|
||||
{
|
||||
m_cache.glStatesSet = false;
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::RenderTargetImplDefault(this);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTarget::~RenderTarget()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::clear(const Color& color)
|
||||
{
|
||||
if (isActive(m_id) || setActive(true))
|
||||
{
|
||||
// Unbind texture to fix RenderTexture preventing clear
|
||||
applyTexture(NULL);
|
||||
|
||||
glCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f));
|
||||
glCheck(glClear(GL_COLOR_BUFFER_BIT));
|
||||
}
|
||||
m_impl->clear(color);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::setView(const View& view)
|
||||
{
|
||||
m_view = view;
|
||||
m_cache.viewChanged = true;
|
||||
m_impl->setView(view);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const View& RenderTarget::getView() const
|
||||
{
|
||||
return m_view;
|
||||
return m_impl->getView();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const View& RenderTarget::getDefaultView() const
|
||||
{
|
||||
return m_defaultView;
|
||||
return m_impl->getDefaultView();
|
||||
}
|
||||
|
||||
|
||||
@ -246,78 +146,7 @@ void RenderTarget::draw(const Drawable& drawable, const RenderStates& states)
|
||||
void RenderTarget::draw(const Vertex* vertices, std::size_t vertexCount,
|
||||
PrimitiveType type, const RenderStates& states)
|
||||
{
|
||||
// Nothing to draw?
|
||||
if (!vertices || (vertexCount == 0))
|
||||
return;
|
||||
|
||||
// GL_QUADS is unavailable on OpenGL ES
|
||||
#ifdef SFML_OPENGL_ES
|
||||
if (type == Quads)
|
||||
{
|
||||
err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isActive(m_id) || setActive(true))
|
||||
{
|
||||
// Check if the vertex count is low enough so that we can pre-transform them
|
||||
bool useVertexCache = (vertexCount <= StatesCache::VertexCacheSize);
|
||||
|
||||
if (useVertexCache)
|
||||
{
|
||||
// Pre-transform the vertices and store them into the vertex cache
|
||||
for (std::size_t i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
Vertex& vertex = m_cache.vertexCache[i];
|
||||
vertex.position = states.transform * vertices[i].position;
|
||||
vertex.color = vertices[i].color;
|
||||
vertex.texCoords = vertices[i].texCoords;
|
||||
}
|
||||
}
|
||||
|
||||
setupDraw(useVertexCache, states);
|
||||
|
||||
// Check if texture coordinates array is needed, and update client state accordingly
|
||||
bool enableTexCoordsArray = (states.texture || states.shader);
|
||||
if (!m_cache.enable || (enableTexCoordsArray != m_cache.texCoordsArrayEnabled))
|
||||
{
|
||||
if (enableTexCoordsArray)
|
||||
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
else
|
||||
glCheck(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
}
|
||||
|
||||
// If we switch between non-cache and cache mode or enable texture
|
||||
// coordinates we need to set up the pointers to the vertices' components
|
||||
if (!m_cache.enable || !useVertexCache || !m_cache.useVertexCache)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(vertices);
|
||||
|
||||
// If we pre-transform the vertices, we must use our internal vertex cache
|
||||
if (useVertexCache)
|
||||
data = reinterpret_cast<const char*>(m_cache.vertexCache);
|
||||
|
||||
glCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), data + 0));
|
||||
glCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8));
|
||||
if (enableTexCoordsArray)
|
||||
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
|
||||
}
|
||||
else if (enableTexCoordsArray && !m_cache.texCoordsArrayEnabled)
|
||||
{
|
||||
// If we enter this block, we are already using our internal vertex cache
|
||||
const char* data = reinterpret_cast<const char*>(m_cache.vertexCache);
|
||||
|
||||
glCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
|
||||
}
|
||||
|
||||
drawPrimitives(type, 0, vertexCount);
|
||||
cleanupDraw(states);
|
||||
|
||||
// Update the cache
|
||||
m_cache.useVertexCache = useVertexCache;
|
||||
m_cache.texCoordsArrayEnabled = enableTexCoordsArray;
|
||||
}
|
||||
m_impl->draw(vertices, vertexCount, type, states);
|
||||
}
|
||||
|
||||
|
||||
@ -332,438 +161,42 @@ void RenderTarget::draw(const VertexBuffer& vertexBuffer, const RenderStates& st
|
||||
void RenderTarget::draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex,
|
||||
std::size_t vertexCount, const RenderStates& states)
|
||||
{
|
||||
// VertexBuffer not supported?
|
||||
if (!VertexBuffer::isAvailable())
|
||||
{
|
||||
err() << "sf::VertexBuffer is not available, drawing skipped" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity check
|
||||
if (firstVertex > vertexBuffer.getVertexCount())
|
||||
return;
|
||||
|
||||
// Clamp vertexCount to something that makes sense
|
||||
vertexCount = std::min(vertexCount, vertexBuffer.getVertexCount() - firstVertex);
|
||||
|
||||
// Nothing to draw?
|
||||
if (!vertexCount || !vertexBuffer.getNativeHandle())
|
||||
return;
|
||||
|
||||
// GL_QUADS is unavailable on OpenGL ES
|
||||
#ifdef SFML_OPENGL_ES
|
||||
if (vertexBuffer.getPrimitiveType() == Quads)
|
||||
{
|
||||
err() << "sf::Quads primitive type is not supported on OpenGL ES platforms, drawing skipped" << std::endl;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isActive(m_id) || setActive(true))
|
||||
{
|
||||
setupDraw(false, states);
|
||||
|
||||
// Bind vertex buffer
|
||||
VertexBuffer::bind(&vertexBuffer);
|
||||
|
||||
// Always enable texture coordinates
|
||||
if (!m_cache.enable || !m_cache.texCoordsArrayEnabled)
|
||||
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
|
||||
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)));
|
||||
|
||||
drawPrimitives(vertexBuffer.getPrimitiveType(), firstVertex, vertexCount);
|
||||
|
||||
// Unbind vertex buffer
|
||||
VertexBuffer::bind(NULL);
|
||||
|
||||
cleanupDraw(states);
|
||||
|
||||
// Update the cache
|
||||
m_cache.useVertexCache = false;
|
||||
m_cache.texCoordsArrayEnabled = true;
|
||||
}
|
||||
m_impl->draw(vertexBuffer, firstVertex, vertexCount, states);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderTarget::setActive(bool active)
|
||||
{
|
||||
// Mark this RenderTarget as active or no longer active in the tracking map
|
||||
{
|
||||
sf::Lock lock(mutex);
|
||||
|
||||
Uint64 contextId = Context::getActiveContextId();
|
||||
|
||||
ContextRenderTargetMap::iterator iter = contextRenderTargetMap.find(contextId);
|
||||
|
||||
if (active)
|
||||
{
|
||||
if (iter == contextRenderTargetMap.end())
|
||||
{
|
||||
contextRenderTargetMap[contextId] = m_id;
|
||||
|
||||
m_cache.enable = false;
|
||||
}
|
||||
else if (iter->second != m_id)
|
||||
{
|
||||
iter->second = m_id;
|
||||
|
||||
m_cache.enable = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iter != contextRenderTargetMap.end())
|
||||
contextRenderTargetMap.erase(iter);
|
||||
|
||||
m_cache.enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return m_impl->setActive(active);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::pushGLStates()
|
||||
{
|
||||
if (isActive(m_id) || setActive(true))
|
||||
{
|
||||
#ifdef SFML_DEBUG
|
||||
// make sure that the user didn't leave an unchecked OpenGL error
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR)
|
||||
{
|
||||
err() << "OpenGL error (" << error << ") detected in user code, "
|
||||
<< "you should check for errors with glGetError()"
|
||||
<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SFML_OPENGL_ES
|
||||
glCheck(glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS));
|
||||
glCheck(glPushAttrib(GL_ALL_ATTRIB_BITS));
|
||||
#endif
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
glCheck(glPushMatrix());
|
||||
glCheck(glMatrixMode(GL_PROJECTION));
|
||||
glCheck(glPushMatrix());
|
||||
glCheck(glMatrixMode(GL_TEXTURE));
|
||||
glCheck(glPushMatrix());
|
||||
}
|
||||
|
||||
resetGLStates();
|
||||
m_impl->pushGLStates();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::popGLStates()
|
||||
{
|
||||
if (isActive(m_id) || setActive(true))
|
||||
{
|
||||
glCheck(glMatrixMode(GL_PROJECTION));
|
||||
glCheck(glPopMatrix());
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
glCheck(glPopMatrix());
|
||||
glCheck(glMatrixMode(GL_TEXTURE));
|
||||
glCheck(glPopMatrix());
|
||||
#ifndef SFML_OPENGL_ES
|
||||
glCheck(glPopClientAttrib());
|
||||
glCheck(glPopAttrib());
|
||||
#endif
|
||||
}
|
||||
m_impl->popGLStates();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::resetGLStates()
|
||||
{
|
||||
// Check here to make sure a context change does not happen after activate(true)
|
||||
bool shaderAvailable = Shader::isAvailable();
|
||||
bool vertexBufferAvailable = VertexBuffer::isAvailable();
|
||||
|
||||
// Workaround for states not being properly reset on
|
||||
// macOS unless a context switch really takes place
|
||||
#if defined(SFML_SYSTEM_MACOS)
|
||||
setActive(false);
|
||||
#endif
|
||||
|
||||
if (isActive(m_id) || setActive(true))
|
||||
{
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
|
||||
// Make sure that the texture unit which is active is the number 0
|
||||
if (GLEXT_multitexture)
|
||||
{
|
||||
glCheck(GLEXT_glClientActiveTexture(GLEXT_GL_TEXTURE0));
|
||||
glCheck(GLEXT_glActiveTexture(GLEXT_GL_TEXTURE0));
|
||||
}
|
||||
|
||||
// Define the default OpenGL states
|
||||
glCheck(glDisable(GL_CULL_FACE));
|
||||
glCheck(glDisable(GL_LIGHTING));
|
||||
glCheck(glDisable(GL_DEPTH_TEST));
|
||||
glCheck(glDisable(GL_ALPHA_TEST));
|
||||
glCheck(glEnable(GL_TEXTURE_2D));
|
||||
glCheck(glEnable(GL_BLEND));
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
glCheck(glLoadIdentity());
|
||||
glCheck(glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glCheck(glEnableClientState(GL_COLOR_ARRAY));
|
||||
glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||
m_cache.glStatesSet = true;
|
||||
|
||||
// Apply the default SFML states
|
||||
applyBlendMode(BlendAlpha);
|
||||
applyTexture(NULL);
|
||||
if (shaderAvailable)
|
||||
applyShader(NULL);
|
||||
|
||||
if (vertexBufferAvailable)
|
||||
glCheck(VertexBuffer::bind(NULL));
|
||||
|
||||
m_cache.texCoordsArrayEnabled = true;
|
||||
|
||||
m_cache.useVertexCache = false;
|
||||
|
||||
// Set the default view
|
||||
setView(getView());
|
||||
|
||||
m_cache.enable = true;
|
||||
}
|
||||
m_impl->resetGLStates();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::initialize()
|
||||
{
|
||||
// Setup the default and current views
|
||||
m_defaultView.reset(FloatRect(0, 0, static_cast<float>(getSize().x), static_cast<float>(getSize().y)));
|
||||
m_view = m_defaultView;
|
||||
|
||||
// Set GL states only on first draw, so that we don't pollute user's states
|
||||
m_cache.glStatesSet = false;
|
||||
|
||||
// Generate a unique ID for this RenderTarget to track
|
||||
// whether it is active within a specific context
|
||||
m_id = getUniqueId();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::applyCurrentView()
|
||||
{
|
||||
// Set the viewport
|
||||
IntRect viewport = getViewport(m_view);
|
||||
int top = getSize().y - (viewport.top + viewport.height);
|
||||
glCheck(glViewport(viewport.left, top, viewport.width, viewport.height));
|
||||
|
||||
// Set the projection matrix
|
||||
glCheck(glMatrixMode(GL_PROJECTION));
|
||||
glCheck(glLoadMatrixf(m_view.getTransform().getMatrix()));
|
||||
|
||||
// Go back to model-view mode
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
|
||||
m_cache.viewChanged = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::applyBlendMode(const BlendMode& mode)
|
||||
{
|
||||
// Apply the blend mode, falling back to the non-separate versions if necessary
|
||||
if (GLEXT_blend_func_separate)
|
||||
{
|
||||
glCheck(GLEXT_glBlendFuncSeparate(
|
||||
factorToGlConstant(mode.colorSrcFactor), factorToGlConstant(mode.colorDstFactor),
|
||||
factorToGlConstant(mode.alphaSrcFactor), factorToGlConstant(mode.alphaDstFactor)));
|
||||
}
|
||||
else
|
||||
{
|
||||
glCheck(glBlendFunc(
|
||||
factorToGlConstant(mode.colorSrcFactor),
|
||||
factorToGlConstant(mode.colorDstFactor)));
|
||||
}
|
||||
|
||||
if (GLEXT_blend_minmax && GLEXT_blend_subtract)
|
||||
{
|
||||
if (GLEXT_blend_equation_separate)
|
||||
{
|
||||
glCheck(GLEXT_glBlendEquationSeparate(
|
||||
equationToGlConstant(mode.colorEquation),
|
||||
equationToGlConstant(mode.alphaEquation)));
|
||||
}
|
||||
else
|
||||
{
|
||||
glCheck(GLEXT_glBlendEquation(equationToGlConstant(mode.colorEquation)));
|
||||
}
|
||||
}
|
||||
else if ((mode.colorEquation != BlendMode::Add) || (mode.alphaEquation != BlendMode::Add))
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
err() << "OpenGL extension EXT_blend_minmax and/or EXT_blend_subtract unavailable" << std::endl;
|
||||
err() << "Selecting a blend equation not possible" << std::endl;
|
||||
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_cache.lastBlendMode = mode;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::applyTransform(const Transform& 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()));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::applyTexture(const Texture* texture)
|
||||
{
|
||||
Texture::bind(texture, Texture::Pixels);
|
||||
|
||||
m_cache.lastTextureId = texture ? texture->m_cacheId : 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::applyShader(const Shader* shader)
|
||||
{
|
||||
Shader::bind(shader);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::setupDraw(bool useVertexCache, const RenderStates& states)
|
||||
{
|
||||
// First set the persistent OpenGL states if it's the very first call
|
||||
if (!m_cache.glStatesSet)
|
||||
resetGLStates();
|
||||
|
||||
if (useVertexCache)
|
||||
{
|
||||
// Since vertices are transformed, we must use an identity transform to render them
|
||||
if (!m_cache.enable || !m_cache.useVertexCache)
|
||||
glCheck(glLoadIdentity());
|
||||
}
|
||||
else
|
||||
{
|
||||
applyTransform(states.transform);
|
||||
}
|
||||
|
||||
// Apply the view
|
||||
if (!m_cache.enable || m_cache.viewChanged)
|
||||
applyCurrentView();
|
||||
|
||||
// Apply the blend mode
|
||||
if (!m_cache.enable || (states.blendMode != m_cache.lastBlendMode))
|
||||
applyBlendMode(states.blendMode);
|
||||
|
||||
// Apply the texture
|
||||
if (!m_cache.enable || (states.texture && states.texture->m_fboAttachment))
|
||||
{
|
||||
// If the texture is an FBO attachment, always rebind it
|
||||
// in order to inform the OpenGL driver that we want changes
|
||||
// made to it in other contexts to be visible here as well
|
||||
// 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);
|
||||
}
|
||||
else
|
||||
{
|
||||
Uint64 textureId = states.texture ? states.texture->m_cacheId : 0;
|
||||
if (textureId != m_cache.lastTextureId)
|
||||
applyTexture(states.texture);
|
||||
}
|
||||
|
||||
// Apply the shader
|
||||
if (states.shader)
|
||||
applyShader(states.shader);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::drawPrimitives(PrimitiveType type, std::size_t firstVertex, std::size_t vertexCount)
|
||||
{
|
||||
// Find the OpenGL primitive type
|
||||
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
|
||||
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
|
||||
GLenum mode = modes[type];
|
||||
|
||||
// Draw the primitives
|
||||
glCheck(glDrawArrays(mode, static_cast<GLint>(firstVertex), static_cast<GLsizei>(vertexCount)));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::cleanupDraw(const RenderStates& states)
|
||||
{
|
||||
// Unbind the shader, if any
|
||||
if (states.shader)
|
||||
applyShader(NULL);
|
||||
|
||||
// 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);
|
||||
|
||||
// Re-enable the cache at the end of the draw if it was disabled
|
||||
m_cache.enable = true;
|
||||
m_impl->initialize(getSize());
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Render states caching strategies
|
||||
//
|
||||
// * View
|
||||
// If SetView was called since last draw, the projection
|
||||
// matrix is updated. We don't need more, the view doesn't
|
||||
// change frequently.
|
||||
//
|
||||
// * Transform
|
||||
// The transform matrix is usually expensive because each
|
||||
// entity will most likely use a different transform. This can
|
||||
// lead, in worst case, to changing it every 4 vertices.
|
||||
// To avoid that, when the vertex count is low enough, we
|
||||
// pre-transform them and therefore use an identity transform
|
||||
// to render them.
|
||||
//
|
||||
// * Blending mode
|
||||
// Since it overloads the == operator, we can easily check
|
||||
// whether any of the 6 blending components changed and,
|
||||
// thus, whether we need to update the blend mode.
|
||||
//
|
||||
// * Texture
|
||||
// Storing the pointer or OpenGL ID of the last used texture
|
||||
// is not enough; if the sf::Texture instance is destroyed,
|
||||
// both the pointer and the OpenGL ID might be recycled in
|
||||
// a new texture instance. We need to use our own unique
|
||||
// identifier system to ensure consistent caching.
|
||||
//
|
||||
// * Shader
|
||||
// Shaders are very hard to optimize, because they have
|
||||
// parameters that can be hard (if not impossible) to track,
|
||||
// like matrices or textures. The only optimization that we
|
||||
// do is that we avoid setting a null shader if there was
|
||||
// already none for the previous draw.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -22,13 +22,11 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_TEXTURESAVER_HPP
|
||||
#define SFML_TEXTURESAVER_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/RenderTargetImpl.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -36,40 +34,54 @@ namespace sf
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Automatic wrapper for saving and restoring the current texture binding
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class TextureSaver
|
||||
RenderTargetImpl::RenderTargetImpl(RenderTarget* parent) :
|
||||
m_parent(parent)
|
||||
{
|
||||
public:
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default constructor
|
||||
///
|
||||
/// The current texture binding is saved.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureSaver();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
/// The previous texture binding is restored.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~TextureSaver();
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTargetImpl::~RenderTargetImpl()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
GLint m_textureBinding; ///< Texture binding to restore
|
||||
};
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImpl::pushGLStates()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImpl::popGLStates()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTargetImpl::resetGLStates()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTarget* RenderTargetImpl::getParent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const TextureImpl* RenderTargetImpl::getTextureImpl(const Texture& texture)
|
||||
{
|
||||
return texture.m_impl;
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_TEXTURESAVER_HPP
|
207
src/SFML/Graphics/RenderTargetImpl.hpp
Normal file
207
src/SFML/Graphics/RenderTargetImpl.hpp
Normal file
@ -0,0 +1,207 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_RENDERTARGET_IMPL_HPP
|
||||
#define SFML_RENDERTARGET_IMPL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Drawable;
|
||||
class VertexBuffer;
|
||||
class Vertex;
|
||||
class View;
|
||||
class RenderStates;
|
||||
class Color;
|
||||
class RenderTarget;
|
||||
class Texture;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
class TextureImpl;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Base class for all render targets (window, texture, ...)
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class RenderTargetImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTargetImpl(RenderTarget* parent);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual ~RenderTargetImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Clear the entire target with a single color
|
||||
///
|
||||
/// \param color Fill color to use to clear the render target
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void clear(const Color& color) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Change the current active view
|
||||
///
|
||||
/// \param view New view to use
|
||||
///
|
||||
/// \see getView, getDefaultView
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setView(const View& view) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the view currently in use in the render target
|
||||
///
|
||||
/// \return The view object that is currently used
|
||||
///
|
||||
/// \see setView, getDefaultView
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual const View& getView() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the default view of the render target
|
||||
///
|
||||
/// \return The default view of the render target
|
||||
///
|
||||
/// \see setView, getView
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual const View& getDefaultView() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Draw primitives defined by an array of vertices
|
||||
///
|
||||
/// \param vertices Pointer to the vertices
|
||||
/// \param vertexCount Number of vertices in the array
|
||||
/// \param type Type of primitives to draw
|
||||
/// \param states Render states to use for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void draw(const Vertex* vertices, std::size_t vertexCount,
|
||||
PrimitiveType type, const RenderStates& states) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Draw primitives defined by a vertex buffer
|
||||
///
|
||||
/// \param vertexBuffer Vertex buffer
|
||||
/// \param firstVertex Index of the first vertex to render
|
||||
/// \param vertexCount Number of vertices to render
|
||||
/// \param states Render states to use for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void draw(const VertexBuffer& vertexBuffer, std::size_t firstVertex,
|
||||
std::size_t vertexCount, const RenderStates& states) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Activate or deactivate the render target for rendering
|
||||
///
|
||||
/// \param active True to activate, false to deactivate
|
||||
///
|
||||
/// \return True if operation was successful, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool setActive(bool active) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Save the current OpenGL render states and matrices
|
||||
///
|
||||
/// \see popGLStates
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void pushGLStates();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Restore the previously saved OpenGL render states and matrices
|
||||
///
|
||||
/// \see pushGLStates
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void popGLStates();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Reset the internal OpenGL states so that the target is ready for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void resetGLStates();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Performs the common initialization step after creation
|
||||
///
|
||||
/// \param newSize New size of the RenderTarget
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void initialize(const Vector2u& newSize) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the parent RenderTarget
|
||||
///
|
||||
/// \return The parent RenderTarget
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTarget* getParent();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the concrete implementation of a texture
|
||||
///
|
||||
/// \param The texture
|
||||
///
|
||||
/// \return The concrete implementation of a texture
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static const TextureImpl* getTextureImpl(const Texture& texture);
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTarget* m_parent;
|
||||
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_RENDERTARGET_IMPL_HPP
|
@ -26,8 +26,10 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderTexture.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/RenderTextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/TextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
|
||||
@ -65,28 +67,33 @@ bool RenderTexture::create(unsigned int width, unsigned int height, const Contex
|
||||
return false;
|
||||
}
|
||||
|
||||
// We disable smoothing by default for render textures
|
||||
setSmooth(false);
|
||||
|
||||
// Create the implementation
|
||||
delete m_impl;
|
||||
if (priv::RenderTextureImplFBO::isAvailable())
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
{
|
||||
// Use frame-buffer object (FBO)
|
||||
m_impl = new priv::RenderTextureImplFBO;
|
||||
priv::TextureImplDefault& texture = *static_cast<priv::TextureImplDefault*>(m_texture.m_impl);
|
||||
|
||||
// Mark the texture as being a framebuffer object attachment
|
||||
m_texture.m_fboAttachment = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default implementation
|
||||
m_impl = new priv::RenderTextureImplDefault;
|
||||
}
|
||||
// We disable smoothing by default for render textures
|
||||
setSmooth(false);
|
||||
|
||||
// Initialize the render texture
|
||||
if (!m_impl->create(width, height, m_texture.m_texture, settings))
|
||||
return false;
|
||||
// Create the implementation
|
||||
delete m_impl;
|
||||
if (priv::RenderTextureImplFBO::isAvailable())
|
||||
{
|
||||
// Use frame-buffer object (FBO)
|
||||
m_impl = new priv::RenderTextureImplFBO;
|
||||
|
||||
// Mark the texture as being a framebuffer object attachment
|
||||
texture.m_fboAttachment = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default implementation
|
||||
m_impl = new priv::RenderTextureImplDefault;
|
||||
}
|
||||
|
||||
// Initialize the render texture
|
||||
if (!m_impl->create(width, height, texture.m_texture, settings))
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can now initialize the render target part
|
||||
RenderTarget::initialize();
|
||||
@ -161,11 +168,16 @@ bool RenderTexture::setActive(bool active)
|
||||
void RenderTexture::display()
|
||||
{
|
||||
// Update the target texture
|
||||
if (m_impl && (priv::RenderTextureImplFBO::isAvailable() || setActive(true)))
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
{
|
||||
m_impl->updateTexture(m_texture.m_texture);
|
||||
m_texture.m_pixelsFlipped = true;
|
||||
m_texture.invalidateMipmap();
|
||||
if (m_impl && (priv::RenderTextureImplFBO::isAvailable() || setActive(true)))
|
||||
{
|
||||
priv::TextureImplDefault& texture = *static_cast<priv::TextureImplDefault*>(m_texture.m_impl);
|
||||
|
||||
m_impl->updateTexture(texture.m_texture);
|
||||
texture.m_pixelsFlipped = true;
|
||||
texture.invalidateMipmap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,9 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GLCheck.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -82,13 +83,16 @@ bool RenderWindow::setActive(bool active)
|
||||
if (result)
|
||||
RenderTarget::setActive(active);
|
||||
|
||||
// If FBOs are available, make sure none are bound when we
|
||||
// try to draw to the default framebuffer of the RenderWindow
|
||||
if (active && result && priv::RenderTextureImplFBO::isAvailable())
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
{
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, m_defaultFrameBuffer));
|
||||
// If FBOs are available, make sure none are bound when we
|
||||
// try to draw to the default framebuffer of the RenderWindow
|
||||
if (active && result && priv::RenderTextureImplFBO::isAvailable())
|
||||
{
|
||||
priv::RenderTextureImplFBO::bindFramebuffer(m_defaultFrameBuffer);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -111,11 +115,14 @@ Image RenderWindow::capture() const
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderWindow::onCreate()
|
||||
{
|
||||
if (priv::RenderTextureImplFBO::isAvailable())
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
{
|
||||
// Retrieve the framebuffer ID we have to bind when targeting the window for rendering
|
||||
// We assume that this window's context is still active at this point
|
||||
glCheck(glGetIntegerv(GLEXT_GL_FRAMEBUFFER_BINDING, reinterpret_cast<GLint*>(&m_defaultFrameBuffer)));
|
||||
if (priv::RenderTextureImplFBO::isAvailable())
|
||||
{
|
||||
// Retrieve the framebuffer ID we have to bind when targeting the window for rendering
|
||||
// We assume that this window's context is still active at this point
|
||||
m_defaultFrameBuffer = priv::RenderTextureImplFBO::getFramebuffer();
|
||||
}
|
||||
}
|
||||
|
||||
// Just initialize the render target part
|
||||
|
59
src/SFML/Graphics/Renderer.cpp
Normal file
59
src/SFML/Graphics/Renderer.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::Uint32 renderer = sf::Renderer::Default;
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Uint32 getAvailableRenderers()
|
||||
{
|
||||
return Renderer::OpenGL1;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void setRenderers(Uint32 renderers)
|
||||
{
|
||||
// TODO: Select a renderer based on the user's preferences
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Uint32 getRenderer()
|
||||
{
|
||||
return renderer;
|
||||
}
|
||||
|
||||
} // namespace sf
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/TextureSaver.hpp>
|
||||
#include <SFML/Graphics/ShaderImpl.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
@ -33,16 +33,9 @@ namespace sf
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureSaver::TextureSaver()
|
||||
ShaderImpl::~ShaderImpl()
|
||||
{
|
||||
glCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &m_textureBinding));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureSaver::~TextureSaver()
|
||||
{
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_textureBinding));
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
} // namespace priv
|
251
src/SFML/Graphics/ShaderImpl.hpp
Normal file
251
src/SFML/Graphics/ShaderImpl.hpp
Normal file
@ -0,0 +1,251 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_SHADER_IMPL_HPP
|
||||
#define SFML_SHADER_IMPL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/Glsl.hpp>
|
||||
#include <SFML/System/NonCopyable.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Texture;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Abstract base class for shader implementations
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class ShaderImpl : NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual ~ShaderImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p float uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param x Value of the float scalar
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, float x) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec2 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec2 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec2& vector) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec3 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec3 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec3& vector) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec4 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec4 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec4& vector) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p int uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param x Value of the int scalar
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, int x) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec2 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec2 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec2& vector) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec3 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec3 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec3& vector) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec4 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec4 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec4& vector) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p mat3 matrix
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrix Value of the mat3 matrix
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Mat3& matrix) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p mat4 matrix
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrix Value of the mat4 matrix
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Mat4& matrix) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify a texture as \p sampler2D uniform
|
||||
///
|
||||
/// \param name Name of the texture in the shader
|
||||
/// \param texture Texture to assign
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Texture& texture) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify current texture as \p sampler2D uniform
|
||||
///
|
||||
/// \param name Name of the texture in the shader
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, Shader::CurrentTextureType) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p float[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param scalarArray pointer to array of \p float values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const float* scalarArray, std::size_t length) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec2[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec2 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec3[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec3 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec4[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec4 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p mat3[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrixArray pointer to array of \p mat3 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p mat4[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrixArray pointer to array of \p mat4 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the underlying OpenGL handle of the shader.
|
||||
///
|
||||
/// \return OpenGL handle of the shader or 0 if not yet loaded
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual unsigned int getNativeHandle() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Compile the shader(s) and create the program
|
||||
///
|
||||
/// \param vertexShaderCode Source code of the vertex shader
|
||||
/// \param geometryShaderCode Source code of the geometry shader
|
||||
/// \param fragmentShaderCode Source code of the fragment shader
|
||||
///
|
||||
/// \return True on success, false if any error happened
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode) = 0;
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SHADER_IMPL_HPP
|
179
src/SFML/Graphics/ShaderImplNull.cpp
Normal file
179
src/SFML/Graphics/ShaderImplNull.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/ShaderImplNull.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, float x)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Vec2& v)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Vec3& v)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Vec4& v)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, int x)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Ivec2& v)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Ivec3& v)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Ivec4& v)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Mat3& matrix)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Glsl::Mat4& matrix)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, const Texture& texture)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniform(const std::string& name, Shader::CurrentTextureType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniformArray(const std::string& name, const float* scalarArray, std::size_t length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int ShaderImplNull::getNativeHandle() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ShaderImplNull::bind(const ShaderImplNull* shader)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ShaderImplNull::isAvailable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ShaderImplNull::isGeometryAvailable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool ShaderImplNull::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
272
src/SFML/Graphics/ShaderImplNull.hpp
Normal file
272
src/SFML/Graphics/ShaderImplNull.hpp
Normal file
@ -0,0 +1,272 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_SHADER_IMPL_NULL_HPP
|
||||
#define SFML_SHADER_IMPL_NULL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/ShaderImpl.hpp>
|
||||
#include <SFML/Graphics/Glsl.hpp>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Texture;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Null specialization of ShaderImpl,
|
||||
/// for platforms without shader support
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class ShaderImplNull : public ShaderImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Bind a shader for rendering
|
||||
///
|
||||
/// \param shader Shader to bind, can be null to use no shader
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static void bind(const ShaderImplNull* shader);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether or not the system supports shaders
|
||||
///
|
||||
/// \return True if shaders are supported, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isAvailable();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether or not the system supports geometry shaders
|
||||
///
|
||||
/// \return True if geometry shaders are supported, false otherwise
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool isGeometryAvailable();
|
||||
|
||||
private:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p float uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param x Value of the float scalar
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, float x);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec2 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec2 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec2& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec3 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec3 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec3& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p vec4 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the vec4 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Vec4& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p int uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param x Value of the int scalar
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, int x);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec2 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec2 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec2& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec3 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec3 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec3& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p ivec4 uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vector Value of the ivec4 vector
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Ivec4& vector);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p mat3 matrix
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrix Value of the mat3 matrix
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Mat3& matrix);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify value for \p mat4 matrix
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrix Value of the mat4 matrix
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Glsl::Mat4& matrix);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify a texture as \p sampler2D uniform
|
||||
///
|
||||
/// \param name Name of the texture in the shader
|
||||
/// \param texture Texture to assign
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, const Texture& texture);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify current texture as \p sampler2D uniform
|
||||
///
|
||||
/// \param name Name of the texture in the shader
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniform(const std::string& name, Shader::CurrentTextureType);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p float[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param scalarArray pointer to array of \p float values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const float* scalarArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec2[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec2 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec2* vectorArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec3[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec3 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec3* vectorArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p vec4[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param vectorArray pointer to array of \p vec4 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Vec4* vectorArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p mat3[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrixArray pointer to array of \p mat3 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Mat3* matrixArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specify values for \p mat4[] array uniform
|
||||
///
|
||||
/// \param name Name of the uniform variable in GLSL
|
||||
/// \param matrixArray pointer to array of \p mat4 values
|
||||
/// \param length Number of elements in the array
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUniformArray(const std::string& name, const Glsl::Mat4* matrixArray, std::size_t length);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the underlying OpenGL handle of the shader.
|
||||
///
|
||||
/// \return OpenGL handle of the shader or 0 if not yet loaded
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual unsigned int getNativeHandle() const;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Compile the shader(s) and create the program
|
||||
///
|
||||
/// \param vertexShaderCode Source code of the vertex shader
|
||||
/// \param geometryShaderCode Source code of the geometry shader
|
||||
/// \param fragmentShaderCode Source code of the fragment shader
|
||||
///
|
||||
/// \return True on success, false if any error happened
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode);
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_SHADER_IMPL_NULL_HPP
|
@ -27,6 +27,8 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Text.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/TextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@ -395,12 +397,19 @@ void Text::ensureGeometryUpdate() const
|
||||
if (!m_font)
|
||||
return;
|
||||
|
||||
// Do nothing, if geometry has not changed and the font texture has not changed
|
||||
if (!m_geometryNeedUpdate && m_font->getTexture(m_characterSize).m_cacheId == m_fontTextureId)
|
||||
return;
|
||||
Uint64 cacheId = 0;
|
||||
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
{
|
||||
cacheId = static_cast<const priv::TextureImplDefault*>(m_font->getTexture(m_characterSize).m_impl)->m_cacheId;
|
||||
|
||||
// Do nothing, if geometry has not changed and the font texture has not changed
|
||||
if (!m_geometryNeedUpdate && (cacheId == m_fontTextureId))
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the current fonts texture id
|
||||
m_fontTextureId = m_font->getTexture(m_characterSize).m_cacheId;
|
||||
m_fontTextureId = cacheId;
|
||||
|
||||
// Mark geometry as updated
|
||||
m_geometryNeedUpdate = false;
|
||||
|
@ -26,191 +26,42 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/TextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/TextureSaver.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/Window/Window.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::Mutex idMutex;
|
||||
sf::Mutex maximumSizeMutex;
|
||||
|
||||
// Thread-safe unique identifier generator,
|
||||
// is used for states cache (see RenderTarget)
|
||||
sf::Uint64 getUniqueId()
|
||||
{
|
||||
sf::Lock lock(idMutex);
|
||||
|
||||
static sf::Uint64 id = 1; // start at 1, zero is "no texture"
|
||||
|
||||
return id++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Texture::Texture() :
|
||||
m_size (0, 0),
|
||||
m_actualSize (0, 0),
|
||||
m_texture (0),
|
||||
m_isSmooth (false),
|
||||
m_sRgb (false),
|
||||
m_isRepeated (false),
|
||||
m_pixelsFlipped(false),
|
||||
m_fboAttachment(false),
|
||||
m_hasMipmap (false),
|
||||
m_cacheId (getUniqueId())
|
||||
m_impl(NULL)
|
||||
{
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::TextureImplDefault;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Texture::Texture(const Texture& copy) :
|
||||
m_size (0, 0),
|
||||
m_actualSize (0, 0),
|
||||
m_texture (0),
|
||||
m_isSmooth (copy.m_isSmooth),
|
||||
m_sRgb (copy.m_sRgb),
|
||||
m_isRepeated (copy.m_isRepeated),
|
||||
m_pixelsFlipped(false),
|
||||
m_fboAttachment(false),
|
||||
m_hasMipmap (false),
|
||||
m_cacheId (getUniqueId())
|
||||
m_impl(NULL)
|
||||
{
|
||||
if (copy.m_texture)
|
||||
{
|
||||
if (create(copy.getSize().x, copy.getSize().y))
|
||||
{
|
||||
update(copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Failed to copy texture, failed to create new texture" << std::endl;
|
||||
}
|
||||
}
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::TextureImplDefault(*static_cast<const priv::TextureImplDefault*>(copy.m_impl));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Texture::~Texture()
|
||||
{
|
||||
// Destroy the OpenGL texture
|
||||
if (m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
GLuint texture = static_cast<GLuint>(m_texture);
|
||||
glCheck(glDeleteTextures(1, &texture));
|
||||
}
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::create(unsigned int width, unsigned int height)
|
||||
{
|
||||
// Check if texture parameters are valid before creating it
|
||||
if ((width == 0) || (height == 0))
|
||||
{
|
||||
err() << "Failed to create texture, invalid size (" << width << "x" << height << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
|
||||
// Compute the internal texture dimensions depending on NPOT textures support
|
||||
Vector2u actualSize(getValidSize(width), getValidSize(height));
|
||||
|
||||
// Check the maximum texture size
|
||||
unsigned int maxSize = getMaximumSize();
|
||||
if ((actualSize.x > maxSize) || (actualSize.y > maxSize))
|
||||
{
|
||||
err() << "Failed to create texture, its internal size is too high "
|
||||
<< "(" << actualSize.x << "x" << actualSize.y << ", "
|
||||
<< "maximum is " << maxSize << "x" << maxSize << ")"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// All the validity checks passed, we can store the new texture settings
|
||||
m_size.x = width;
|
||||
m_size.y = height;
|
||||
m_actualSize = actualSize;
|
||||
m_pixelsFlipped = false;
|
||||
m_fboAttachment = false;
|
||||
|
||||
// Create the OpenGL texture if it doesn't exist yet
|
||||
if (!m_texture)
|
||||
{
|
||||
GLuint texture;
|
||||
glCheck(glGenTextures(1, &texture));
|
||||
m_texture = static_cast<unsigned int>(texture);
|
||||
}
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
static bool textureEdgeClamp = GLEXT_texture_edge_clamp;
|
||||
|
||||
if (!m_isRepeated && !textureEdgeClamp)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
err() << "OpenGL extension SGIS_texture_edge_clamp unavailable" << std::endl;
|
||||
err() << "Artifacts may occur along texture edges" << std::endl;
|
||||
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool textureSrgb = GLEXT_texture_sRGB;
|
||||
|
||||
if (m_sRgb && !textureSrgb)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
#ifndef SFML_OPENGL_ES
|
||||
err() << "OpenGL extension EXT_texture_sRGB unavailable" << std::endl;
|
||||
#else
|
||||
err() << "OpenGL ES extension EXT_sRGB unavailable" << std::endl;
|
||||
#endif
|
||||
err() << "Automatic sRGB to linear conversion disabled" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
|
||||
m_sRgb = false;
|
||||
}
|
||||
|
||||
// Initialize the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexImage2D(GL_TEXTURE_2D, 0, (m_sRgb ? GLEXT_GL_SRGB8_ALPHA8 : GL_RGBA), m_actualSize.x, m_actualSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
m_hasMipmap = false;
|
||||
|
||||
return true;
|
||||
return m_impl->create(width, height);
|
||||
}
|
||||
|
||||
|
||||
@ -241,157 +92,21 @@ bool Texture::loadFromStream(InputStream& stream, const IntRect& area)
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::loadFromImage(const Image& image, const IntRect& area)
|
||||
{
|
||||
// Retrieve the image size
|
||||
int width = static_cast<int>(image.getSize().x);
|
||||
int height = static_cast<int>(image.getSize().y);
|
||||
|
||||
// Load the entire image if the source area is either empty or contains the whole image
|
||||
if (area.width == 0 || (area.height == 0) ||
|
||||
((area.left <= 0) && (area.top <= 0) && (area.width >= width) && (area.height >= height)))
|
||||
{
|
||||
// Load the entire image
|
||||
if (create(image.getSize().x, image.getSize().y))
|
||||
{
|
||||
update(image);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load a sub-area of the image
|
||||
|
||||
// Adjust the rectangle to the size of the image
|
||||
IntRect rectangle = area;
|
||||
if (rectangle.left < 0) rectangle.left = 0;
|
||||
if (rectangle.top < 0) rectangle.top = 0;
|
||||
if (rectangle.left + rectangle.width > width) rectangle.width = width - rectangle.left;
|
||||
if (rectangle.top + rectangle.height > height) rectangle.height = height - rectangle.top;
|
||||
|
||||
// Create the texture and upload the pixels
|
||||
if (create(rectangle.width, rectangle.height))
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Copy the pixels to the texture, row by row
|
||||
const Uint8* pixels = image.getPixelsPtr() + 4 * (rectangle.left + (width * rectangle.top));
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
for (int i = 0; i < rectangle.height; ++i)
|
||||
{
|
||||
glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, rectangle.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
pixels += 4 * width;
|
||||
}
|
||||
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
|
||||
// Force an OpenGL flush, so that the texture will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return m_impl->loadFromImage(image, area);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2u Texture::getSize() const
|
||||
{
|
||||
return m_size;
|
||||
return m_impl->getSize();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Image Texture::copyToImage() const
|
||||
{
|
||||
// Easy case: empty texture
|
||||
if (!m_texture)
|
||||
return Image();
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Create an array of pixels
|
||||
std::vector<Uint8> pixels(m_size.x * m_size.y * 4);
|
||||
|
||||
#ifdef SFML_OPENGL_ES
|
||||
|
||||
// OpenGL ES doesn't have the glGetTexImage function, the only way to read
|
||||
// from a texture is to bind it to a FBO and use glReadPixels
|
||||
GLuint frameBuffer = 0;
|
||||
glCheck(GLEXT_glGenFramebuffers(1, &frameBuffer));
|
||||
if (frameBuffer)
|
||||
{
|
||||
GLint previousFrameBuffer;
|
||||
glCheck(glGetIntegerv(GLEXT_GL_FRAMEBUFFER_BINDING, &previousFrameBuffer));
|
||||
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, frameBuffer));
|
||||
glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
|
||||
glCheck(glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]));
|
||||
glCheck(GLEXT_glDeleteFramebuffers(1, &frameBuffer));
|
||||
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_FRAMEBUFFER, previousFrameBuffer));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if ((m_size == m_actualSize) && !m_pixelsFlipped)
|
||||
{
|
||||
// Texture is not padded nor flipped, we can use a direct copy
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Texture is either padded or flipped, we have to use a slower algorithm
|
||||
|
||||
// All the pixels will first be copied to a temporary array
|
||||
std::vector<Uint8> allPixels(m_actualSize.x * m_actualSize.y * 4);
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &allPixels[0]));
|
||||
|
||||
// Then we copy the useful pixels from the temporary array to the final one
|
||||
const Uint8* src = &allPixels[0];
|
||||
Uint8* dst = &pixels[0];
|
||||
int srcPitch = m_actualSize.x * 4;
|
||||
int dstPitch = m_size.x * 4;
|
||||
|
||||
// Handle the case where source pixels are flipped vertically
|
||||
if (m_pixelsFlipped)
|
||||
{
|
||||
src += srcPitch * (m_size.y - 1);
|
||||
srcPitch = -srcPitch;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_size.y; ++i)
|
||||
{
|
||||
std::memcpy(dst, src, dstPitch);
|
||||
src += srcPitch;
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
|
||||
// Create the image
|
||||
Image image;
|
||||
image.create(m_size.x, m_size.y, &pixels[0]);
|
||||
|
||||
return image;
|
||||
return m_impl->copyToImage();
|
||||
}
|
||||
|
||||
|
||||
@ -399,35 +114,14 @@ Image Texture::copyToImage() const
|
||||
void Texture::update(const Uint8* pixels)
|
||||
{
|
||||
// Update the whole texture
|
||||
update(pixels, m_size.x, m_size.y, 0, 0);
|
||||
update(pixels, m_impl->getSize().x, m_impl->getSize().y, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y)
|
||||
{
|
||||
assert(x + width <= m_size.x);
|
||||
assert(y + height <= m_size.y);
|
||||
|
||||
if (pixels && m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Copy pixels from the given array to the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
m_pixelsFlipped = false;
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
// Force an OpenGL flush, so that the texture data will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
}
|
||||
m_impl->update(pixels, width, height, x, y);
|
||||
}
|
||||
|
||||
|
||||
@ -442,101 +136,7 @@ void Texture::update(const Texture& texture)
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::update(const Texture& texture, unsigned int x, unsigned int y)
|
||||
{
|
||||
assert(x + texture.m_size.x <= m_size.x);
|
||||
assert(y + texture.m_size.y <= m_size.y);
|
||||
|
||||
if (!m_texture || !texture.m_texture)
|
||||
return;
|
||||
|
||||
#ifndef SFML_OPENGL_ES
|
||||
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
}
|
||||
|
||||
if (GLEXT_framebuffer_object && GLEXT_framebuffer_blit)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Save the current bindings so we can restore them after we are done
|
||||
GLint readFramebuffer = 0;
|
||||
GLint drawFramebuffer = 0;
|
||||
|
||||
glCheck(glGetIntegerv(GLEXT_GL_READ_FRAMEBUFFER_BINDING, &readFramebuffer));
|
||||
glCheck(glGetIntegerv(GLEXT_GL_DRAW_FRAMEBUFFER_BINDING, &drawFramebuffer));
|
||||
|
||||
// Create the framebuffers
|
||||
GLuint sourceFrameBuffer = 0;
|
||||
GLuint destFrameBuffer = 0;
|
||||
glCheck(GLEXT_glGenFramebuffers(1, &sourceFrameBuffer));
|
||||
glCheck(GLEXT_glGenFramebuffers(1, &destFrameBuffer));
|
||||
|
||||
if (!sourceFrameBuffer || !destFrameBuffer)
|
||||
{
|
||||
err() << "Cannot copy texture, failed to create a frame buffer object" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Link the source texture to the source frame buffer
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, sourceFrameBuffer));
|
||||
glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_READ_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.m_texture, 0));
|
||||
|
||||
// Link the destination texture to the destination frame buffer
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, destFrameBuffer));
|
||||
glCheck(GLEXT_glFramebufferTexture2D(GLEXT_GL_DRAW_FRAMEBUFFER, GLEXT_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0));
|
||||
|
||||
// A final check, just to be sure...
|
||||
GLenum sourceStatus;
|
||||
glCheck(sourceStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_READ_FRAMEBUFFER));
|
||||
|
||||
GLenum destStatus;
|
||||
glCheck(destStatus = GLEXT_glCheckFramebufferStatus(GLEXT_GL_DRAW_FRAMEBUFFER));
|
||||
|
||||
if ((sourceStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE) && (destStatus == GLEXT_GL_FRAMEBUFFER_COMPLETE))
|
||||
{
|
||||
// Blit the texture contents from the source to the destination texture
|
||||
glCheck(GLEXT_glBlitFramebuffer(
|
||||
0, texture.m_pixelsFlipped ? texture.m_size.y : 0, texture.m_size.x, texture.m_pixelsFlipped ? 0 : texture.m_size.y, // Source rectangle, flip y if source is flipped
|
||||
x, y, x + texture.m_size.x, y + texture.m_size.y, // Destination rectangle
|
||||
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
err() << "Cannot copy texture, failed to link texture to frame buffer" << std::endl;
|
||||
}
|
||||
|
||||
// Restore previously bound framebuffers
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_READ_FRAMEBUFFER, readFramebuffer));
|
||||
glCheck(GLEXT_glBindFramebuffer(GLEXT_GL_DRAW_FRAMEBUFFER, drawFramebuffer));
|
||||
|
||||
// Delete the framebuffers
|
||||
glCheck(GLEXT_glDeleteFramebuffers(1, &sourceFrameBuffer));
|
||||
glCheck(GLEXT_glDeleteFramebuffers(1, &destFrameBuffer));
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Set the parameters of this texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
m_pixelsFlipped = false;
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
// Force an OpenGL flush, so that the texture data will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
|
||||
update(texture.copyToImage(), x, y);
|
||||
m_impl->update(*texture.m_impl, x, y);
|
||||
}
|
||||
|
||||
|
||||
@ -565,246 +165,71 @@ void Texture::update(const Window& window)
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::update(const Window& window, unsigned int x, unsigned int y)
|
||||
{
|
||||
assert(x + window.getSize().x <= m_size.x);
|
||||
assert(y + window.getSize().y <= m_size.y);
|
||||
|
||||
if (m_texture && window.setActive(true))
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Copy pixels from the back-buffer to the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 0, 0, window.getSize().x, window.getSize().y));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
m_hasMipmap = false;
|
||||
m_pixelsFlipped = true;
|
||||
m_cacheId = getUniqueId();
|
||||
|
||||
// Force an OpenGL flush, so that the texture will appear updated
|
||||
// in all contexts immediately (solves problems in multi-threaded apps)
|
||||
glCheck(glFlush());
|
||||
}
|
||||
m_impl->update(window, x, y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::setSmooth(bool smooth)
|
||||
{
|
||||
if (smooth != m_isSmooth)
|
||||
{
|
||||
m_isSmooth = smooth;
|
||||
|
||||
if (m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
|
||||
if (m_hasMipmap)
|
||||
{
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR));
|
||||
}
|
||||
else
|
||||
{
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
}
|
||||
}
|
||||
}
|
||||
m_impl->setSmooth(smooth);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::isSmooth() const
|
||||
{
|
||||
return m_isSmooth;
|
||||
return m_impl->isSmooth();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::setSrgb(bool sRgb)
|
||||
{
|
||||
m_sRgb = sRgb;
|
||||
m_impl->setSrgb(sRgb);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::isSrgb() const
|
||||
{
|
||||
return m_sRgb;
|
||||
return m_impl->isSrgb();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::setRepeated(bool repeated)
|
||||
{
|
||||
if (repeated != m_isRepeated)
|
||||
{
|
||||
m_isRepeated = repeated;
|
||||
|
||||
if (m_texture)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
static bool textureEdgeClamp = GLEXT_texture_edge_clamp;
|
||||
|
||||
if (!m_isRepeated && !textureEdgeClamp)
|
||||
{
|
||||
static bool warned = false;
|
||||
|
||||
if (!warned)
|
||||
{
|
||||
err() << "OpenGL extension SGIS_texture_edge_clamp unavailable" << std::endl;
|
||||
err() << "Artifacts may occur along texture edges" << std::endl;
|
||||
err() << "Ensure that hardware acceleration is enabled if available" << std::endl;
|
||||
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP)));
|
||||
}
|
||||
}
|
||||
m_impl->setRepeated(repeated);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::isRepeated() const
|
||||
{
|
||||
return m_isRepeated;
|
||||
return m_impl->isRepeated();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::generateMipmap()
|
||||
{
|
||||
if (!m_texture)
|
||||
return false;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
priv::ensureExtensionsInit();
|
||||
|
||||
if (!GLEXT_framebuffer_object)
|
||||
return false;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(GLEXT_glGenerateMipmap(GL_TEXTURE_2D));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_LINEAR));
|
||||
|
||||
m_hasMipmap = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::invalidateMipmap()
|
||||
{
|
||||
if (!m_hasMipmap)
|
||||
return;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
|
||||
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
|
||||
m_hasMipmap = false;
|
||||
return m_impl->generateMipmap();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::bind(const Texture* texture, CoordinateType coordinateType)
|
||||
{
|
||||
TransientContextLock lock;
|
||||
|
||||
if (texture && texture->m_texture)
|
||||
{
|
||||
// Bind the texture
|
||||
glCheck(glBindTexture(GL_TEXTURE_2D, texture->m_texture));
|
||||
|
||||
// Check if we need to define a special texture matrix
|
||||
if ((coordinateType == Pixels) || texture->m_pixelsFlipped)
|
||||
{
|
||||
GLfloat matrix[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};
|
||||
|
||||
// If non-normalized coordinates (= pixels) are requested, we need to
|
||||
// setup scale factors that convert the range [0 .. size] to [0 .. 1]
|
||||
if (coordinateType == Pixels)
|
||||
{
|
||||
matrix[0] = 1.f / texture->m_actualSize.x;
|
||||
matrix[5] = 1.f / texture->m_actualSize.y;
|
||||
}
|
||||
|
||||
// If pixels are flipped we must invert the Y axis
|
||||
if (texture->m_pixelsFlipped)
|
||||
{
|
||||
matrix[5] = -matrix[5];
|
||||
matrix[13] = static_cast<float>(texture->m_size.y) / texture->m_actualSize.y;
|
||||
}
|
||||
|
||||
// Load the matrix
|
||||
glCheck(glMatrixMode(GL_TEXTURE));
|
||||
glCheck(glLoadMatrixf(matrix));
|
||||
|
||||
// Go back to model-view mode (sf::RenderTarget relies on it)
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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 (sf::RenderTarget relies on it)
|
||||
glCheck(glMatrixMode(GL_MODELVIEW));
|
||||
}
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
priv::TextureImplDefault::bind(texture ? static_cast<const priv::TextureImplDefault*>(texture->m_impl) : 0, coordinateType);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Texture::getMaximumSize()
|
||||
{
|
||||
Lock lock(maximumSizeMutex);
|
||||
|
||||
static bool checked = false;
|
||||
static GLint size = 0;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
checked = true;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
glCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
|
||||
}
|
||||
|
||||
return static_cast<unsigned int>(size);
|
||||
return priv::TextureImplDefault::getMaximumSize();
|
||||
}
|
||||
|
||||
|
||||
@ -822,45 +247,14 @@ Texture& Texture::operator =(const Texture& right)
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::swap(Texture& right)
|
||||
{
|
||||
std::swap(m_size, right.m_size);
|
||||
std::swap(m_actualSize, right.m_actualSize);
|
||||
std::swap(m_texture, right.m_texture);
|
||||
std::swap(m_isSmooth, right.m_isSmooth);
|
||||
std::swap(m_sRgb, right.m_sRgb);
|
||||
std::swap(m_isRepeated, right.m_isRepeated);
|
||||
std::swap(m_pixelsFlipped, right.m_pixelsFlipped);
|
||||
std::swap(m_fboAttachment, right.m_fboAttachment);
|
||||
std::swap(m_hasMipmap, right.m_hasMipmap);
|
||||
|
||||
m_cacheId = getUniqueId();
|
||||
right.m_cacheId = getUniqueId();
|
||||
std::swap(m_impl, right.m_impl);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Texture::getNativeHandle() const
|
||||
{
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Texture::getValidSize(unsigned int size)
|
||||
{
|
||||
if (GLEXT_texture_non_power_of_two)
|
||||
{
|
||||
// If hardware supports NPOT textures, then just return the unmodified size
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If hardware doesn't support NPOT textures, we calculate the nearest power of two
|
||||
unsigned int powerOfTwo = 1;
|
||||
while (powerOfTwo < size)
|
||||
powerOfTwo *= 2;
|
||||
|
||||
return powerOfTwo;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
43
src/SFML/Graphics/TextureImpl.cpp
Normal file
43
src/SFML/Graphics/TextureImpl.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/TextureImpl.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
TextureImpl::~TextureImpl()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
213
src/SFML/Graphics/TextureImpl.hpp
Normal file
213
src/SFML/Graphics/TextureImpl.hpp
Normal file
@ -0,0 +1,213 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_TEXTURE_IMPL_HPP
|
||||
#define SFML_TEXTURE_IMPL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Export.hpp>
|
||||
#include <SFML/Graphics/Rect.hpp>
|
||||
#include <SFML/System/Vector2.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Image;
|
||||
class Window;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Image living on the graphics card that can be used for drawing
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class TextureImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual ~TextureImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the texture implementation
|
||||
///
|
||||
/// \param width Width of the texture
|
||||
/// \param height Height of the texture
|
||||
///
|
||||
/// \return True if creation was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool create(unsigned int width, unsigned int height) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Load the texture from an image
|
||||
///
|
||||
/// \param image Image to load into the texture
|
||||
/// \param area Area of the image to load
|
||||
///
|
||||
/// \return True if loading was successful
|
||||
///
|
||||
/// \see loadFromFile, loadFromMemory
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool loadFromImage(const Image& image, const IntRect& area) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the size of the texture
|
||||
///
|
||||
/// \return Size in pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Vector2u getSize() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Copy the texture pixels to an image
|
||||
///
|
||||
/// \return Image containing the texture's pixels
|
||||
///
|
||||
/// \see loadFromImage
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual Image copyToImage() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of the texture from an array of pixels
|
||||
///
|
||||
/// \param pixels Array of pixels to copy to the texture
|
||||
/// \param width Width of the pixel region contained in \a pixels
|
||||
/// \param height Height of the pixel region contained in \a pixels
|
||||
/// \param x X offset in the texture where to copy the source pixels
|
||||
/// \param y Y offset in the texture where to copy the source pixels
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of this texture from another texture
|
||||
///
|
||||
/// \param texture Source texture to copy to this texture
|
||||
/// \param x X offset in this texture where to copy the source texture
|
||||
/// \param y Y offset in this texture where to copy the source texture
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void update(const TextureImpl& texture, unsigned int x, unsigned int y) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of the texture from the contents of a window
|
||||
///
|
||||
/// \param window Window to copy to the texture
|
||||
/// \param x X offset in the texture where to copy the source window
|
||||
/// \param y Y offset in the texture where to copy the source window
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void update(const Window& window, unsigned int x, unsigned int y) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable the smooth filter
|
||||
///
|
||||
/// \param smooth True to enable smoothing, false to disable it
|
||||
///
|
||||
/// \see isSmooth
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setSmooth(bool smooth) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether the smooth filter is enabled or not
|
||||
///
|
||||
/// \return True if smoothing is enabled, false if it is disabled
|
||||
///
|
||||
/// \see setSmooth
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool isSmooth() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable conversion from sRGB
|
||||
///
|
||||
/// \param sRgb True to enable sRGB conversion, false to disable it
|
||||
///
|
||||
/// \see isSrgb
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setSrgb(bool sRgb) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether the texture source is converted from sRGB or not
|
||||
///
|
||||
/// \return True if the texture source is converted from sRGB, false if not
|
||||
///
|
||||
/// \see setSrgb
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool isSrgb() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Enable or disable repeating
|
||||
///
|
||||
/// \param repeated True to repeat the texture, false to disable repeating
|
||||
///
|
||||
/// \see isRepeated
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setRepeated(bool repeated) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Tell whether the texture is repeated or not
|
||||
///
|
||||
/// \return True if repeat mode is enabled, false if it is disabled
|
||||
///
|
||||
/// \see setRepeated
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool isRepeated() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Generate a mipmap using the current texture data
|
||||
///
|
||||
/// \return True if mipmap generation was successful, false if unsuccessful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool generateMipmap() = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the underlying OpenGL handle of the texture.
|
||||
///
|
||||
/// \return OpenGL handle of the texture or 0 if not yet created
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual unsigned int getNativeHandle() const = 0;
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_TEXTURE_IMPL_HPP
|
@ -26,82 +26,60 @@
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/VertexBuffer.hpp>
|
||||
#include <SFML/Graphics/OpenGL/GL1/VertexBufferImplDefault.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Vertex.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
sf::Mutex isAvailableMutex;
|
||||
|
||||
GLenum usageToGlEnum(sf::VertexBuffer::Usage usage)
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case sf::VertexBuffer::Static: return GLEXT_GL_STATIC_DRAW;
|
||||
case sf::VertexBuffer::Dynamic: return GLEXT_GL_DYNAMIC_DRAW;
|
||||
default: return GLEXT_GL_STREAM_DRAW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::VertexBuffer() :
|
||||
m_buffer (0),
|
||||
m_size (0),
|
||||
m_primitiveType(Points),
|
||||
m_usage (Stream)
|
||||
m_primitiveType(Points)
|
||||
{
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::VertexBufferImplDefault;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::VertexBuffer(PrimitiveType type) :
|
||||
m_buffer (0),
|
||||
m_size (0),
|
||||
m_primitiveType(type),
|
||||
m_usage (Stream)
|
||||
m_primitiveType(type)
|
||||
{
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::VertexBufferImplDefault;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::VertexBuffer(VertexBuffer::Usage usage) :
|
||||
m_buffer (0),
|
||||
m_size (0),
|
||||
m_primitiveType(Points),
|
||||
m_usage (usage)
|
||||
m_primitiveType(Points)
|
||||
{
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::VertexBufferImplDefault(usage);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::VertexBuffer(PrimitiveType type, VertexBuffer::Usage usage) :
|
||||
m_buffer (0),
|
||||
m_size (0),
|
||||
m_primitiveType(type),
|
||||
m_usage (usage)
|
||||
m_primitiveType(type)
|
||||
{
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::VertexBufferImplDefault(usage);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::VertexBuffer(const VertexBuffer& copy) :
|
||||
m_buffer (0),
|
||||
m_size (0),
|
||||
m_primitiveType(copy.m_primitiveType),
|
||||
m_usage (copy.m_usage)
|
||||
m_primitiveType(copy.m_primitiveType)
|
||||
{
|
||||
if (copy.m_buffer && copy.m_size)
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
m_impl = new priv::VertexBufferImplDefault(copy.m_impl->getUsage());
|
||||
|
||||
if (copy.getNativeHandle() && copy.getVertexCount())
|
||||
{
|
||||
if (!create(copy.m_size))
|
||||
if (!create(copy.getVertexCount()))
|
||||
{
|
||||
err() << "Could not create vertex buffer for copying" << std::endl;
|
||||
return;
|
||||
@ -116,148 +94,42 @@ m_usage (copy.m_usage)
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::~VertexBuffer()
|
||||
{
|
||||
if (m_buffer)
|
||||
{
|
||||
TransientContextLock contextLock;
|
||||
|
||||
glCheck(GLEXT_glDeleteBuffers(1, &m_buffer));
|
||||
}
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBuffer::create(std::size_t vertexCount)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return false;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
if (!m_buffer)
|
||||
glCheck(GLEXT_glGenBuffers(1, &m_buffer));
|
||||
|
||||
if (!m_buffer)
|
||||
{
|
||||
err() << "Could not create vertex buffer, generation failed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
|
||||
|
||||
m_size = vertexCount;
|
||||
|
||||
return true;
|
||||
return m_impl->create(vertexCount);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
std::size_t VertexBuffer::getVertexCount() const
|
||||
{
|
||||
return m_size;
|
||||
return m_impl->getVertexCount();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBuffer::update(const Vertex* vertices)
|
||||
{
|
||||
return update(vertices, m_size, 0);
|
||||
return update(vertices, m_impl->getVertexCount(), 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBuffer::update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset)
|
||||
{
|
||||
// Sanity checks
|
||||
if (!m_buffer)
|
||||
return false;
|
||||
|
||||
if (!vertices)
|
||||
return false;
|
||||
|
||||
if (offset && (offset + vertexCount > m_size))
|
||||
return false;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
|
||||
// Check if we need to resize or orphan the buffer
|
||||
if (vertexCount >= m_size)
|
||||
{
|
||||
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexCount, 0, usageToGlEnum(m_usage)));
|
||||
|
||||
m_size = vertexCount;
|
||||
}
|
||||
|
||||
glCheck(GLEXT_glBufferSubData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * offset, sizeof(Vertex) * vertexCount, vertices));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
|
||||
|
||||
return true;
|
||||
return m_impl->update(vertices, vertexCount, offset);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBuffer::update(const VertexBuffer& vertexBuffer)
|
||||
{
|
||||
#ifdef SFML_OPENGL_ES
|
||||
|
||||
return false;
|
||||
|
||||
#else
|
||||
|
||||
if (!m_buffer || !vertexBuffer.m_buffer)
|
||||
return false;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
sf::priv::ensureExtensionsInit();
|
||||
|
||||
if (GLEXT_copy_buffer)
|
||||
{
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, vertexBuffer.m_buffer));
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, m_buffer));
|
||||
|
||||
glCheck(GLEXT_glCopyBufferSubData(GLEXT_GL_COPY_READ_BUFFER, GLEXT_GL_COPY_WRITE_BUFFER, 0, 0, sizeof(Vertex) * vertexBuffer.m_size));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_WRITE_BUFFER, 0));
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_COPY_READ_BUFFER, 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
glCheck(GLEXT_glBufferData(GLEXT_GL_ARRAY_BUFFER, sizeof(Vertex) * vertexBuffer.m_size, 0, usageToGlEnum(m_usage)));
|
||||
|
||||
void* destination = 0;
|
||||
glCheck(destination = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_WRITE_ONLY));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, vertexBuffer.m_buffer));
|
||||
|
||||
void* source = 0;
|
||||
glCheck(source = GLEXT_glMapBuffer(GLEXT_GL_ARRAY_BUFFER, GLEXT_GL_READ_ONLY));
|
||||
|
||||
std::memcpy(destination, source, sizeof(Vertex) * vertexBuffer.m_size);
|
||||
|
||||
GLboolean sourceResult = GL_FALSE;
|
||||
glCheck(sourceResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, m_buffer));
|
||||
|
||||
GLboolean destinationResult = GL_FALSE;
|
||||
glCheck(destinationResult = GLEXT_glUnmapBuffer(GLEXT_GL_ARRAY_BUFFER));
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, 0));
|
||||
|
||||
if ((sourceResult == GL_FALSE) || (destinationResult == GL_FALSE))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
#endif // SFML_OPENGL_ES
|
||||
return m_impl->update(*vertexBuffer.m_impl);
|
||||
}
|
||||
|
||||
|
||||
@ -275,29 +147,23 @@ VertexBuffer& VertexBuffer::operator =(const VertexBuffer& right)
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexBuffer::swap(VertexBuffer& right)
|
||||
{
|
||||
std::swap(m_size, right.m_size);
|
||||
std::swap(m_buffer, right.m_buffer);
|
||||
std::swap(m_impl, right.m_impl);
|
||||
std::swap(m_primitiveType, right.m_primitiveType);
|
||||
std::swap(m_usage, right.m_usage);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int VertexBuffer::getNativeHandle() const
|
||||
{
|
||||
return m_buffer;
|
||||
return m_impl->getNativeHandle();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexBuffer::bind(const VertexBuffer* vertexBuffer)
|
||||
{
|
||||
if (!isAvailable())
|
||||
return;
|
||||
|
||||
TransientContextLock lock;
|
||||
|
||||
glCheck(GLEXT_glBindBuffer(GLEXT_GL_ARRAY_BUFFER, vertexBuffer ? vertexBuffer->m_buffer : 0));
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
priv::VertexBufferImplDefault::bind(vertexBuffer ? static_cast<const priv::VertexBufferImplDefault*>(vertexBuffer->m_impl) : 0);
|
||||
}
|
||||
|
||||
|
||||
@ -318,46 +184,32 @@ PrimitiveType VertexBuffer::getPrimitiveType() const
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexBuffer::setUsage(VertexBuffer::Usage usage)
|
||||
{
|
||||
m_usage = usage;
|
||||
m_impl->setUsage(usage);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBuffer::Usage VertexBuffer::getUsage() const
|
||||
{
|
||||
return m_usage;
|
||||
return m_impl->getUsage();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool VertexBuffer::isAvailable()
|
||||
{
|
||||
Lock lock(isAvailableMutex);
|
||||
if ((sf::getRenderer() == sf::Renderer::Default) || (sf::getRenderer() == sf::Renderer::OpenGL1))
|
||||
return priv::VertexBufferImplDefault::isAvailable();
|
||||
|
||||
static bool checked = false;
|
||||
static bool available = false;
|
||||
|
||||
if (!checked)
|
||||
{
|
||||
checked = true;
|
||||
|
||||
TransientContextLock contextLock;
|
||||
|
||||
// Make sure that extensions are initialized
|
||||
sf::priv::ensureExtensionsInit();
|
||||
|
||||
available = GLEXT_vertex_buffer_object;
|
||||
}
|
||||
|
||||
return available;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexBuffer::draw(RenderTarget& target, RenderStates states) const
|
||||
{
|
||||
if (m_buffer && m_size)
|
||||
target.draw(*this, 0, m_size, states);
|
||||
if (getNativeHandle() && getVertexCount())
|
||||
target.draw(*this, 0, getVertexCount(), states);
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
43
src/SFML/Graphics/VertexBufferImpl.cpp
Normal file
43
src/SFML/Graphics/VertexBufferImpl.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/VertexBufferImpl.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexBufferImpl::~VertexBufferImpl()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
124
src/SFML/Graphics/VertexBufferImpl.hpp
Normal file
124
src/SFML/Graphics/VertexBufferImpl.hpp
Normal file
@ -0,0 +1,124 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SFML - Simple and Fast Multimedia Library
|
||||
// Copyright (C) 2007-2019 Laurent Gomila (laurent@sfml-dev.org)
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied warranty.
|
||||
// In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it freely,
|
||||
// subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented;
|
||||
// you must not claim that you wrote the original software.
|
||||
// If you use this software in a product, an acknowledgment
|
||||
// in the product documentation would be appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such,
|
||||
// and must not be misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_VERTEXBUFFER_IMPL_HPP
|
||||
#define SFML_VERTEXBUFFER_IMPL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/VertexBuffer.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
class Vertex;
|
||||
|
||||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Abstract base class for vertex buffer implementations
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class VertexBufferImpl
|
||||
{
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual ~VertexBufferImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the vertex buffer
|
||||
///
|
||||
/// \param vertexCount Number of vertices worth of memory to allocate
|
||||
///
|
||||
/// \return True if creation was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool create(std::size_t vertexCount) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Return the vertex count
|
||||
///
|
||||
/// \return Number of vertices in the vertex buffer
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual std::size_t getVertexCount() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Update a part of the buffer from an array of vertices
|
||||
///
|
||||
/// \param vertices Array of vertices to copy to the buffer
|
||||
/// \param vertexCount Number of vertices to copy
|
||||
/// \param offset Offset in the buffer to copy to
|
||||
///
|
||||
/// \return True if the update was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool update(const Vertex* vertices, std::size_t vertexCount, unsigned int offset) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Copy the contents of another buffer into this buffer
|
||||
///
|
||||
/// \param vertexBuffer Vertex buffer whose contents to copy into this vertex buffer
|
||||
///
|
||||
/// \return True if the copy was successful
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual bool update(const VertexBufferImpl& vertexBuffer) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the underlying OpenGL handle of the vertex buffer.
|
||||
///
|
||||
/// \return OpenGL handle of the vertex buffer or 0 if not yet created
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual unsigned int getNativeHandle() const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Set the usage specifier of this vertex buffer
|
||||
///
|
||||
/// \param usage Usage specifier
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual void setUsage(VertexBuffer::Usage usage) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Get the usage specifier of this vertex buffer
|
||||
///
|
||||
/// \return Usage specifier
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual VertexBuffer::Usage getUsage() const = 0;
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
||||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_VERTEXBUFFER_IMPL_HPP
|
Loading…
Reference in New Issue
Block a user