SFML community forums
Help => Graphics => Topic started by: T.T.H. on January 30, 2008, 10:57:17 pm
-
Hi there
Since I am a nitpicker regarding pixel moving I stumbled upon a problem: when I create a sprite from an image and draw that sprite on the screen, the border pixel of the image are only half as big as the inner pixel of the image.
...and now with pictures:
Source image, 32 x 32 pixel, with colorful 1 pixel wide border and checkerboard within:
(http://www.teeteehaa.de/SFML/image_1x1.png)
Screenshot, rendered with SFML, sprite scaled quite large and rendered four times around the center of the screen:
(http://www.teeteehaa.de/SFML/sprite_subpixel_accuracy.png)
As you can see the colorful border pixel are only half as big as the black and white checkerboard pixel.
Relevant piece of code:
// render window
sf::RenderWindow MyRenderWindow(sf::VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT), "SFML", sf::Style::Close);
MyRenderWindow.OptimizeForNonOpenGL(true);
MyRenderWindow.SetBackgroundColor(sf::Color(255, 0, 255));
// image
sf::Image MyImage;
MyImage.LoadFromFile(IMAGE_FILE);
MyImage.SetSmooth(false);
// sprite
sf::Sprite MySprite(MyImage);
MySprite.Scale(20.f, 20.f);
// center of screen
float CenterX = (float) MyRenderWindow.GetWidth() / 2.0f;
float CenterY = (float) MyRenderWindow.GetHeight() / 2.0f;
// big loop
while (Looping)
{
// draw top left sprite
MySprite.SetPosition(CenterX - MySprite.GetWidth(), CenterY - MySprite.GetHeight());
MyRenderWindow.Draw(MySprite);
// draw top right sprite
MySprite.SetPosition(CenterX , CenterY - MySprite.GetHeight());
MyRenderWindow.Draw(MySprite);
// draw bottom left sprite
MySprite.SetPosition(CenterX - MySprite.GetWidth(), CenterY );
MyRenderWindow.Draw(MySprite);
// draw bottom right sprite
MySprite.SetPosition(CenterX , CenterY );
MyRenderWindow.Draw(MySprite);
// display screen
MyRenderWindow.Display();
I don't like that and I would like to change that. Unfortunately I'm not sure whether it's due to SFML or due to OpenGL or due to the fact that I am totally missing something. Please somebody enlighten me :D
-
Weird, that's not supposed to happen. Which version of SMFL are you using ?
-
I was using revision 408. I now updated to revision 442 but the result is exactly the same.
Any other info I could provide? Do you want the whole VC2005 project of my test application?
-
Do you want the whole VC2005 project of my test application?
Yep, I'll try it at home.
-
The problem seems to come from the high scale. Using a bigger image and applying no scale works just fine. I guess it has to do with the OpenGL filtering / rasterization algorithm, combined with my texture coordinate trick (subtracting a half-texel to make the OpenGL coordinates match the screen ones).
-
So whenever I "zoom in" on a sprite by giving it any scale over 1.0 the border of the sprite looses its "pixel preciseness"? Sorry to say, but I'd consider that a bummer :shock:
For something I am tinkering on I do have a seamless grass texture being 256 x 256 pixel in size. My application "tiles" that texture to create a grass landscape and can zoom in and out from it. I stumbled about that pixel un-precision because I noticed "edges" between my perfectly fine seamless textures when I zoomed in on my terrain, not only at "zoom deep in" but at any kind of "zoom in".
-
So whenever I "zoom in" on a sprite by giving it any scale over 1.0 the border of the sprite looses its "pixel preciseness"? Sorry to say, but I'd consider that a bummer
I wouldn't say that, I think it will produce this kind of issue only with high scales.
Anyway, I don't think we can avoid this when using scale or zoom, as the scene units become different from screen pixels ; you just can't get a perfect mapping.
-
I wouldn't say that, I think it will produce this kind of issue only with high scales.
No. It happens with any scale larger than 1.0.
Anyway, I don't think we can avoid this when using scale or zoom
:cry:
While trying that again out I even stumbled about the next problem (sooorry), this time related to image smoothing.
Original image - 32x32 pixel, drawn 4 times around center of screen, image smoothing is enabled:
(http://www.teeteehaa.de/SFML/checkerboard_1x1.png)
Scale factor 1.0 - please note those nasty "circles", where do those come from?!?
Might they come from the "high contrast" checkerboard plus some fancy Moire patterns?
But at a scale factor of 1.0 everything should be copied exactly, shouldn't it?
(sidenote: image is reduced to 256 colors, but even in full color mode those circles are clearly visible)
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_1_0.png)
Scale factor 1.1 - please note the "circles" and please even note the "half size border pixel":
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_1_1.png)
Scale factor 1.5 - including "half size border pixel":
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_1_5.png)
Scale factor 2.0 - including "circles" (even while not that visible) and "half size border pixel":
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_2_0.png)
Scale factor 0.9 - "circles":
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_0_9.png)
Scale factor 0.5 - total bogus?!
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_0_5.png)
SFML revision 449. Help.
// --- includes ---
// windows
#include <windows.h>
// SFML
#include "SFML/Graphics.hpp"
// STL
#include <iostream>
// --- defines ---
#define IMAGE_FILE "checkerboard_1x1.bmp"
// #define IMAGE_FILE "image_1x1.bmp"
const int SCREEN_WIDTH = 200;
const int SCREEN_HEIGHT = 200;
const float SCALE_FACTOR = 1.0f;
const bool IMAGE_SMOOTHING = true;
// --- signal handler ---
BOOL WINAPI MyHandlerRoutine(DWORD dwCtrlType)
{
std::cout << "exiting the hard way" << std::endl;
exit(0);
return TRUE;
}
// --- run ---
bool runSFML()
{
// variables
bool Looping(true);
sf::Event MyEvent;
// render window
sf::RenderWindow MyRenderWindow(sf::VideoMode(SCREEN_WIDTH, SCREEN_HEIGHT), "SFML", sf::Style::Close);
MyRenderWindow.OptimizeForNonOpenGL(true);
MyRenderWindow.SetBackgroundColor(sf::Color(255, 0, 255));
// image
sf::Image MyImage;
if (!MyImage.LoadFromFile(IMAGE_FILE))
{
std::cout << "failed to load image '" << IMAGE_FILE << "'" << std::endl;
return false;
}
MyImage.SetRepeat(true);
MyImage.SetSmooth(IMAGE_SMOOTHING);
// sprite
sf::Sprite MySprite(MyImage);
MySprite.Scale(SCALE_FACTOR, SCALE_FACTOR);
// center of screen
float CenterX = (float) MyRenderWindow.GetWidth() / 2.0f;
float CenterY = (float) MyRenderWindow.GetHeight() / 2.0f;
// big loop
while (Looping)
{
// draw top left sprite
MySprite.SetPosition(CenterX - MySprite.GetWidth(), CenterY - MySprite.GetHeight());
MyRenderWindow.Draw(MySprite);
// draw top right sprite
MySprite.SetPosition(CenterX , CenterY - MySprite.GetHeight());
MyRenderWindow.Draw(MySprite);
// draw bottom left sprite
MySprite.SetPosition(CenterX - MySprite.GetWidth(), CenterY );
MyRenderWindow.Draw(MySprite);
// draw bottom right sprite
MySprite.SetPosition(CenterX , CenterY );
MyRenderWindow.Draw(MySprite);
// display screen
MyRenderWindow.Display();
// poll events
while (MyRenderWindow.GetEvent(MyEvent))
{
// check whether window was closed
if (MyEvent.Type == sf::Event::Closed)
{
Looping = false;
}
// check whether escape was pressed
if ((MyEvent.Type == sf::Event::KeyReleased) && (MyEvent.Key.Code == sf::Key::Escape))
{
Looping = false;
}
}
}
return true;
}
// --- main ---
int main(int argc, char *argv[])
{
// add signal handler routine
if (!SetConsoleCtrlHandler(MyHandlerRoutine, TRUE))
{
std::cout << "failed to add signal handler routine" << std::endl;
exit(1);
}
// start
std::cout << "started" << std::endl;
// run SFML
runSFML();
// stopped
std::cout << "stopped" << std::endl;
return 0;
}
-
...and another post that I am not just nitpicking in checkerboard stress tests but actually do notice that effects on "real life data" alias "I want to draw a landscape made of grass tiles":
Original image - which tiles wonderfully seamless (http://www.teeteehaa.de/SFML/grass.html):
(http://www.teeteehaa.de/SFML/grass_256x256.png)
Scale factor 1.0 - when looking close I can see an "edge":
(http://www.teeteehaa.de/SFML/resize_grass_smooth_1_0.png)
Scale factor 2.0 - I obviously do see an "edge":
(http://www.teeteehaa.de/SFML/resize_grass_smooth_2_0.png)
Those "edges" get even more visible when I scroll around over a landscape made of those tiles.
-
Good demonstration of the problem ;)
I'll see what I can do.
-
Ha! After tinkering around in Sprite.cpp and changing line 184 in Sprite::Render from...
// Calculate the texture coordinates
FloatRect TexCoords = myImage->GetTexCoords(mySubRect);
...into...
// Calculate the texture coordinates
FloatRect TexCoords = myImage->GetTexCoords(mySubRect, false);
...and by so basically disabling your "half texel texture coordinate trick" I now get the following results:
Checkerboard 1.0:
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_unadjusted_1_0.png)
Checkerboard 1.5:
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_unadjusted_1_5.png)
Checkerboard 2.0:
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_unadjusted_2_0.png)
Checkerboard 0.5:
(http://www.teeteehaa.de/SFML/resize_checkerboard_smooth_unadjusted_0_5.png)
Grass 2.0:
(http://www.teeteehaa.de/SFML/resize_grass_smooth_unadjusted_2_0.png)
:D :D :D
This leads me to the following conclusions:
My original "half border pixel" problem is caused (or at least affected) by your "texture coordinate trick" and by disabling that "trick" I exactly totally 100% get what I want (pixel perfect seamless landscapes). On the other hand I do not know why you initially put that "trick" into the code. But maybe you give that reason a second thought (please).
My following "strangle circles appearing" problem seems to be caused by some Moire patterns on my "extreme contrast checkerboard" image in combination with the "not pixel precise" usage of the image. When the pixel precision is done correctly the circles simply disappear.
-
P.S.: are the values in the following code snippet casting in a correct way so that no precision is lost? Personally I'd put several (float) in front of the Rect.Left, Rect.Top, Rect.Right and Rect.Bottom because int + float = int in my opinion and I'd prefer to have (float) int + float = float.
FloatRect Image::GetTexCoords(const IntRect& Rect, bool Adjust) const
{
float Offset = Adjust ? 0.5f : 0.f;
return FloatRect((Rect.Left + Offset) / myTextureWidth,
(Rect.Top + Offset) / myTextureHeight,
(Rect.Right - Offset) / myTextureWidth,
(Rect.Bottom - Offset) / myTextureHeight);
}
-
On the other hand I do not know why you initially put that "trick" into the code. But maybe you give that reason a second thought (please).
OpenGL texels doesn't map exactly to the screen pixels, they are offseted by half a pixel. If I don't use this trick, I get unwanted pixels on the borders of images with smoothing activated. But I think I could just use the trick when smoothing is enabled.
P.S.: are the values in the following code snippet casting in a correct way so that no precision is lost? Personally I'd put several (float) in front of the Rect.Left, Rect.Top, Rect.Right and Rect.Bottom because int + float = int in my opinion and I'd prefer to have (float) int + float = float.
int + float = float.
If there's at least one float as an operand, the result of any operator will be a float.
-
If I don't use this trick, I get unwanted pixels on the borders of images with smoothing activated.
Isn't that what GL_REPEAT and GL_CLAMP are for? (assuming the sprite is made of the whole image).
In case you have one image and make several sprites out of it, yes, not using the trick will include unwanted pixel of the neighbor sprite. To be honest that even is my full intention: I put my grass tile 25 times into an image (5x5) and make a sprite out of the center tile to achieve a correct smoothing "to the neighbor" and so a perfectly seamless landscape. If it would be that single sprite only I could use GL_REPEAT, too, but in those 24 tiles around the center are several "borders" to create "round borders of grass". And for those "half grass, half empty" tiles I indeed don't want any neighbor pixel included on an "empty" edge - so my source image is GL_CLAMP.
Finally a suggestion:
////////////////////////////////////////////////////////////
/// Enable or disable several image options:
/// Repeat: how to define pixels outside the texture range
/// Smooth: image smoothing filter
/// AdjustTexel: prevent pixel outside the sprite range being
/// used when smoothing filter is enabled
////////////////////////////////////////////////////////////
void Image::SetOptions(bool Repeat, bool Smooth, bool AdjustTexel)
{
// Remember options
myRepeat = Repeat;
mySmooth = Smooth;
myAdjustTexel = AdjustTexel;
if (myGLTexture)
{
// Change OpenGL texture wrap mode
GLint PreviousTexture;
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &PreviousTexture));
GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, Repeat ? GL_REPEAT : GL_CLAMP));
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Repeat ? GL_REPEAT : GL_CLAMP));
GLCheck(glBindTexture(GL_TEXTURE_2D, PreviousTexture));
// 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));
}
}
////////////////////////////////////////////////////////////
/// Convert a subrect expressed in pixels, into float
/// texture coordinates
////////////////////////////////////////////////////////////
FloatRect Image::GetTexCoords(const IntRect& Rect) const
{
float Offset = mySmooth && myAdjustTexel ? 0.5f : 0.f;
return FloatRect((Rect.Left + Offset) / myTextureWidth,
(Rect.Top + Offset) / myTextureHeight,
(Rect.Right - Offset) / myTextureWidth,
(Rect.Bottom - Offset) / myTextureHeight);
}
////////////////////////////////////////////////////////////
/// Create the OpenGL texture
////////////////////////////////////////////////////////////
bool Image::CreateTexture()
{
// [...snip...]
// Create the OpenGL texture
GLCheck(glGenTextures(1, (GLuint*)&myGLTexture));
GLCheck(glBindTexture(GL_TEXTURE_2D, myGLTexture));
GLCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, myTextureWidth, myTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
// Set texture options
SetOptions(bool myRepeat, bool mySmooth, bool myAdjustTexel)
// Copy the pixel buffer to the OpenGL texture
Update();
// Put back the previous texture
GLCheck(glBindTexture(GL_TEXTURE_2D, PreviousTexture));
return true;
}
-
(note: late answer because I was in holidays)
Updating to 492 I've seen you changed something in 474:
Removed Image::SetRepeat (useless and even incorrect when texture was padded with extra pixels)
Removed the "half-pixel trick" on texture coordinates when an image is not smooth
Unfortunately my problem still exists: there is a visible edge between my seamless tiles.
To solve my problem (and doing so without hacking around inside SFML itself) I need a way to control the "half-pixel trick" myself (via some SFML API). Currently this is not possible because Sprite::Render calls...
// Calculate the texture coordinates
// FloatRect TexCoords = myImage->GetTexCoords(mySubRect);
...and in Image.hpp...
FloatRect GetTexCoords(const IntRect& Rect, bool Adjust = true) const;
...the default value for the parameter Adjust is true.
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. You are even saying yourself about GL_CLAMP...
...(useless and even incorrect when texture was padded with extra pixels)
Yes, I could make both those changes locally in my very own version of SFML, but a) I'd prefer to have an API for it and b) I'm probably not the only person wishing pixel preciseness.
-
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 ?
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.
-
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.
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 (http://www.teeteehaa.de/SFML/resize_grass_smooth_2_0.png)). 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:
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.
-
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.
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();
-
This is a nice patch, thanks! I'd recommend that you make it static though.
-
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 :)
-
This (http://www.teeteehaa.de/SFML/TestSFMLSeamless.zip) 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).