Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Use an abstract sf::Texture class with sf::Shader (instead of current)  (Read 2928 times)

0 Members and 1 Guest are viewing this topic.

lamogui

  • Newbie
  • *
  • Posts: 13
    • View Profile
Hello

This topic comes from this fact:
sf::Shader (SFML 2.2) only allow the user to send sf::Texture as uniform sampler to the shader.
Concretely this restrict the textures passed as parameter to texture2D RGBA 8-bit.

To extend the possibility sf::Shader should allow the advanced user to pass other types of textures.

Here is my idea: propose an abstract class that represent the ID of the openGL texture which sf::Shader
can use. So the user who have other texture type to pass as parameter can simply inherit from the class and implement the constructor and proper bind fonction.

sf::Texture should inherit from this class.

the bind fonction should be a member specific (or not :) ) for the sf::Shader, it doesn't replace the static sf::Texture::bind.

Another possibility is change the attributes of sf::Shader as protected, the user can inherit and implement a specific member. But from my point of view it's ugly.

Exemples of textures other than texture2D RGBA:
 - Texture1D float luminance (eg audio spectrum) typically my case
 - Texture2D/3D float luminance (eg 2D 3D noise) very usefull for post-processing effects

I coded and tested a prototype available here:  https://github.com/lamogui/SFML (I also added missing bool and int setters of the sf::Shader) (classname : sf::GlTexture)
List of changes here : https://github.com/SFML/SFML/pull/788

Sorry for my bad english






« Last Edit: February 02, 2015, 08:53:46 pm by lamogui »

lamogui

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Use an abstract sf::Texture class with sf::Shader (instead of current)
« Reply #1 on: February 02, 2015, 08:55:18 pm »
No answer ? my english is too bad maybe  :-[ : here is the french http://fr.sfml-dev.org/forums/index.php?topic=17366.0

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10819
    • View Profile
    • development blog
    • Email
Re: Use an abstract sf::Texture class with sf::Shader (instead of current)
« Reply #2 on: February 03, 2015, 08:03:12 am »
I don't know enough about all of the things involved, but SFML only supports RGBA 8bit 2D textures. Adding an abstraction for the texture, which when used with SFML itself makes only sense as a 2D texture, doesn't make too much sense.

Do you have some example code that goes with the changes you had made?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

lamogui

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Use an abstract sf::Texture class with sf::Shader (instead of current)
« Reply #3 on: February 03, 2015, 11:58:46 pm »
I don't know enough about all of the things involved, but SFML only supports RGBA 8bit 2D textures. Adding an abstraction for the texture, which when used with SFML itself makes only sense as a 2D texture, doesn't make too much sense.

Do you have some example code that goes with the changes you had made?

It's not a sf::Texture abstraction for "texture" but a texture abstraction for Shaders. THIS IS NEEDED to enable all the GLSL uniform variables parameter compatibles with SFML.

To do a rendering with GLSL (even if it's 2D) you often need external uniform samplersXD variable (X is 1, 2 or 3): for instance rendering an audio spectrum (sampler1D), using time and a noise 3D texture (for post processing effects based on vec3 or vec2 input).

uniform sampler1D spectrum; //Impossible to pass 1D texture with SFML
 

uniform sampler3D noise3D; //Impossible to pass 3D texture with SFML
 

Example of inheriting (SFML style) class:
  class Sampler1D : public sf::GlTexture
  {
    public:
      Sampler1D();
      virtual ~Sampler1D();
      bool create(unsigned int size, const float*);
      void update(const float* );
      void update(const float* , unsigned int size, unsigned int x=0);
     
      virtual void bind() const;
     
      inline unsigned int getSize() const {
        return _size;
      }
     
      inline bool isSmooth() const {
        return _smooth;
      }
     
      inline bool isRepeated() const {
        return _isRepeated;
      }
     
      void setSmooth(bool);
      void setRepeated(bool);
     
    private:
      unsigned int _realSize;
      unsigned int _size;
     
      bool _smooth;
      bool _isRepeated;
     
  };
 

Sampler1D::Sampler1D() :
_realSize(0),
_size(0),
_smooth(false),
_isRepeated(false)
{
}

Sampler1D::~Sampler1D()
{
}


bool Sampler1D::create(unsigned int size, const float* data)
{
  unsigned int realSize = GlTexture::getValidSize(size);
  unsigned int maxSize = GlTexture::getMaximumSize();
  if (realSize > maxSize)
  {
    std::cerr << "Failed to create texture, its internal size is too high "
    << "maximum is " << maxSize << std::endl;
    return false;
  }
 
  _realSize=realSize;
  _size=size;
 
  ensureGlContext();
 
  if (!m_texture)
  {
   
    GLuint texture;
    glCheck(glGenTextures(1, &texture));
    m_texture = static_cast<unsigned int>(texture);
    glCheck(glEnable(GL_TEXTURE_1D));
  }
 
  glCheck(glBindTexture(GL_TEXTURE_1D, m_texture));
  glCheck(glTexImage1D( GL_TEXTURE_1D, 0, GL_LUMINANCE, _realSize, 0, GL_LUMINANCE, GL_FLOAT, (const GLvoid*) 0 ));
  glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, _isRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
  glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, _isRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
  glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, _smooth ? GL_LINEAR : GL_NEAREST));
  glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, _smooth ? GL_LINEAR : GL_NEAREST));
  glCheck(glBindTexture(GL_TEXTURE_1D, 0));
 
  update(data, size);
 
  return true;
}

void Sampler1D::update(const float* data){
  update(data, _size);
}

void Sampler1D::update(const float* data, unsigned int size, unsigned int x)
{
  if (data && m_texture)
  {
    ensureGlContext();

    // Copy pixels from the given array to the texture
    glCheck(glBindTexture(GL_TEXTURE_1D, m_texture));
    glCheck(glTexSubImage1D(GL_TEXTURE_1D, 0, x, size, GL_LUMINANCE, GL_FLOAT, (const GLvoid*) data));
    glCheck(glBindTexture(GL_TEXTURE_1D, 0));
  }
}

void Sampler1D::bind() const
{
  ensureGlContext();
  glCheck(glBindTexture(GL_TEXTURE_1D, m_texture));
  if (m_texture && _size != _realSize)
  {
    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};
    matrix[0] = (float) _size /(float)_realSize;
    // 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));
  }
}

void Sampler1D::setSmooth(bool smooth)
{
  if (smooth != _smooth)
  {
      _smooth = smooth;

      if (m_texture)
      {
          ensureGlContext();

          glCheck(glBindTexture(GL_TEXTURE_1D, m_texture));
          glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, _smooth ? GL_LINEAR : GL_NEAREST));
          glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, _smooth ? GL_LINEAR : GL_NEAREST));
      }
  }
}

void Sampler1D::setRepeated(bool repeated)
{
  if (repeated != _isRepeated)
  {
      _isRepeated = repeated;

      if (m_texture)
      {
          ensureGlContext();

          glCheck(glBindTexture(GL_TEXTURE_1D, m_texture));
          glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, _isRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
          glCheck(glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, _isRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
      }
  }
}
 
« Last Edit: February 04, 2015, 12:03:47 am by lamogui »