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

Author Topic: subpixel accuracy of sprite of image  (Read 14912 times)

0 Members and 1 Guest are viewing this topic.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
subpixel accuracy of sprite of image
« Reply #15 on: March 11, 2008, 02:31:29 am »
Quote
the default value for the parameter Adjust is true.

But now, if the image is not smooth it won't apply. Isn't it what you suggested previously ?

Quote
In addition I'd like to get back an API to set the "repetition" of images or at least to have the default value GL_REPEAT instead of GL_CLAMP for the setting GL_TEXTURE_WRAP of images.

The quote was about GL_REPEAT, not GL_CLAMP. I can't put it back, because it wouldn't be consistent. Imagine the texture is padded because its dimensions are not power of two : you would never get the result you expect with GL_REPEAT.
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
subpixel accuracy of sprite of image
« Reply #16 on: March 12, 2008, 09:55:08 pm »
Quote from: "Laurent"
I can't put it back, because it wouldn't be consistent. Imagine the texture is padded because its dimensions are not power of two : you would never get the result you expect with GL_REPEAT.

Hmm, good point.

Quote from: "Laurent"
But now, if the image is not smooth it won't apply. Isn't it what you suggested previously?

No. I do need Smoothing. Actually I do not care at all about un-smoothed images.


Okay, again, as precise as I am able to describe it:

When image smoothing is off there is no need for the half-pixel-trick because OpenGL does not take any pixel outside your source area of the sprite into account.

When image smoothing is on there might be need for the half-pixel-trick:

There is need for the half-pixel-trick when you do not want OpenGL taking any pixel outside the source area into account but you can live with some distortion of the source area (-0.5 pixel on each side of the source area).

There must not be any half-pixel-trick in case there must not be any distortion, e.x. when you try to make 100% seamless tiles e.x. for a terrain where a distortion would be visible as some kind of "edge" between the (smoothed) images of the adjacent tiles (look closely here). In that same case the user himself has to remember that OpenGL will take pixel outside the source area into account (+0.5 pixel on each side of the source area) and so the user has to make his own preparations therefore, e.x. putting 3x3 the very same tile into one image and picking only the center tile as source area for the sprite.


Thinking of my upcoming birthday next Saturday and hypothetically assuming that I have a wish free I'd wish for the following API in SFML regarding my personal needs of my own application:
Code: [Select]

void Image::SetSmooth(bool Smooth, bool Adjust)
{
    myIsSmooth = Smooth;
    myIsAdjust = Adjust;

    if (myGLTexture)
    {
        // Change OpenGL texture filter
        GLint PreviousTexture;
        GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &PreviousTexture));
        GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
        GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Smooth ? GL_LINEAR : GL_NEAREST));
        GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Smooth ? GL_LINEAR : GL_NEAREST));
        GLCheck(glBindTexture(GL_TEXTURE_2D, PreviousTexture));
    }
}

FloatRect Image::GetTexCoords(const IntRect& Rect) const
{
    float Width  = static_cast<float>(myTextureWidth);
    float Height = static_cast<float>(myTextureHeight);

    if (myIsSmooth && myIsAdjust)
    {
        return FloatRect((Rect.Left   + 0.5f) / Width,
                         (Rect.Top    + 0.5f) / Height,
                         (Rect.Right  - 0.5f) / Width,
                         (Rect.Bottom - 0.5f) / Height);
    }
    else
    {
        return FloatRect(Rect.Left   / Width,
                         Rect.Top    / Height,
                         Rect.Right  / Width,
                         Rect.Bottom / Height);
    }
}

Basically Adjust is no more function parameter "decided" by sf::Sprite (and other SFML classes) when calling sf::Image::GetTexCoords but it is a member variable of sf::Image itself, accessible by the user. In that way it's 1) coupled directly with the Smooth setting to which it refers anyway and 2) it can be controlled by the user (me) depending on the requirements of the user's application.

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
subpixel accuracy of sprite of image
« Reply #17 on: November 26, 2008, 11:02:17 pm »
I am digging up this old thread because this issue still is a problem for me and because I want to present a solution how I "fixed" it for myself. The change is made in SFML directly as it's not possible to fix within my own application but the change is pretty small, pretty simple and -in my opinion- pretty helpful for people like me who desire/demand pixel-preciseness even during antialiased/smoothed rendering. So without further ado I will now post a patch against r936 of SFML. Just copy&paste the following text into a file called "subpixelaccuracy.patch" and apply it to SFML - under Windows simply with TortoiseSVN and "Apply patch..." or under Linux with the diff command (if I remember correctly).

Laurent, I'd really like to see this implemented in SFML and I tried to make it as small and as easy and as reasonable for you as possible. In case you are not convinced of its necessity yet I can give you an example application clearly demonstrating the whole issue.

Code: [Select]
Index: include/SFML/Graphics/Image.hpp
===================================================================
--- include/SFML/Graphics/Image.hpp (revision 936)
+++ include/SFML/Graphics/Image.hpp (working copy)
@@ -224,6 +224,16 @@
     void SetSmooth(bool Smooth);
 
     ////////////////////////////////////////////////////////////
+    /// Enable or disable half-texel adjustment.
+    /// This parameter is enabled by default
+    /// and only relevant if Smooth is enabled, too
+    ///
+    /// \param Adjust : True to enable half-texel adjustment, false to disable it
+    ///
+    ////////////////////////////////////////////////////////////
+    void SetAdjust(bool Adjust);
+
+    ////////////////////////////////////////////////////////////
     /// Return the width of the image
     ///
     /// \return Width in pixels
@@ -248,6 +258,14 @@
     bool IsSmooth() const;
 
     ////////////////////////////////////////////////////////////
+    /// Tells whether the half-texel adjustment is enabled or not
+    ///
+    /// \return True if half-texel adjustment is enabled
+    ///
+    ////////////////////////////////////////////////////////////
+    bool IsAdjust() const;
+
+    ////////////////////////////////////////////////////////////
     /// Convert a subrect expressed in pixels, into float
     /// texture coordinates
     ///
@@ -324,6 +342,7 @@
     unsigned int               myTextureHeight;     ///< Actual texture height (can be greater than image height because of padding)
     unsigned int               myTexture;           ///< Internal texture identifier
     bool                       myIsSmooth;          ///< Status of the smooth filter
+    bool                       myIsAdjust;          ///< Status of the texel adjustment
     mutable std::vector<Color> myPixels;            ///< Pixels of the image
     mutable bool               myNeedTextureUpdate; ///< Status of synchronization between pixels in central memory and the internal texture un video memory
     mutable bool               myNeedArrayUpdate;   ///< Status of synchronization between pixels in central memory and the internal texture un video memory
Index: src/SFML/Graphics/Image.cpp
===================================================================
--- src/SFML/Graphics/Image.cpp (revision 936)
+++ src/SFML/Graphics/Image.cpp (working copy)
@@ -47,6 +47,7 @@
 myTextureHeight    (0),
 myTexture          (0),
 myIsSmooth         (true),
+myIsAdjust         (true),
 myNeedTextureUpdate(false),
 myNeedArrayUpdate  (false)
 {
@@ -65,6 +66,7 @@
 myTextureHeight    (Copy.myTextureHeight),
 myTexture          (0),
 myIsSmooth         (Copy.myIsSmooth),
+myIsAdjust         (Copy.myIsAdjust),
 myPixels           (Copy.myPixels),
 myNeedTextureUpdate(false),
 myNeedArrayUpdate  (false)
@@ -83,6 +85,7 @@
 myTextureHeight    (0),
 myTexture          (0),
 myIsSmooth         (true),
+myIsAdjust         (true),
 myNeedTextureUpdate(false),
 myNeedArrayUpdate  (false)
 {
@@ -100,6 +103,7 @@
 myTextureHeight    (0),
 myTexture          (0),
 myIsSmooth         (true),
+myIsAdjust         (true),
 myNeedTextureUpdate(false),
 myNeedArrayUpdate  (false)
 {
@@ -483,6 +487,15 @@
 
 
 ////////////////////////////////////////////////////////////
+/// Enable or disable half-texel adjustment
+////////////////////////////////////////////////////////////
+void Image::SetAdjust(bool Adjust)
+{
+    myIsAdjust = Adjust;
+}
+
+
+////////////////////////////////////////////////////////////
 /// Return the width of the image
 ////////////////////////////////////////////////////////////
 unsigned int Image::GetWidth() const
@@ -510,6 +523,14 @@
 
 
 ////////////////////////////////////////////////////////////
+/// Tells whether the half-texel adjustment is enabled or not
+////////////////////////////////////////////////////////////
+bool Image::IsAdjust() const
+{
+    return myIsAdjust;
+}
+
+////////////////////////////////////////////////////////////
 /// Convert a subrect expressed in pixels, into float
 /// texture coordinates
 ////////////////////////////////////////////////////////////
@@ -518,7 +539,7 @@
     float Width  = static_cast<float>(myTextureWidth);
     float Height = static_cast<float>(myTextureHeight);
 
-    if (Adjust && myIsSmooth)
+    if (Adjust && myIsAdjust && myIsSmooth)
     {
         return FloatRect((Rect.Left   + 0.5f) / Width,
                          (Rect.Top    + 0.5f) / Height,
@@ -573,6 +594,7 @@
     std::swap(myTextureHeight,     Temp.myTextureHeight);
     std::swap(myTexture,           Temp.myTexture);
     std::swap(myIsSmooth,          Temp.myIsSmooth);
+    std::swap(myIsAdjust,          Temp.myIsAdjust);
     std::swap(myNeedArrayUpdate,   Temp.myNeedArrayUpdate);
     std::swap(myNeedTextureUpdate, Temp.myNeedTextureUpdate);
     myPixels.swap(Temp.myPixels);
@@ -729,6 +751,7 @@
     myTextureHeight     = 0;
     myTexture           = 0;
     myIsSmooth          = true;
+    myIsAdjust          = true;
     myNeedTextureUpdate = false;
     myNeedArrayUpdate   = false;
     myPixels.clear();

Wizzard

  • Full Member
  • ***
  • Posts: 213
    • View Profile
subpixel accuracy of sprite of image
« Reply #18 on: November 27, 2008, 01:01:34 am »
This is a nice patch, thanks! I'd recommend that you make it static though.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
subpixel accuracy of sprite of image
« Reply #19 on: November 27, 2008, 08:13:03 am »
Well, this half-texel adjustment is not really a feature that should be available as an option in the public interface, it's a "bug" fix actually. Without it, pixels are (sometimes) not rendered exactly as they should, this is due to the way texels are mapped by OpenGL. I thought the current code was able to make it look ok in all situations, but apparently not ;)

Can you show me your examples? This will help me understand when this fix is necessary, and when it should not be applied.

Thanks for your feedback :)
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
subpixel accuracy of sprite of image
« Reply #20 on: November 27, 2008, 06:58:43 pm »
This is my proof-of-concept example (1.8 MB zipped VC++2005 Express project plus some images). You need to have my above mentioned patch applied to SFML to make it work.

Type 's' to toggle texture smoothing and type 'a' to toggle half-texel adjusment (note: half-texel adjustment is only meaningful in combination with texture smooting turned on).

 

anything