GRABSPRITE on transparent color problem with ZOOMSPRITE/STRETCHSPRITE

Previous topic - Next topic

AndyH

I've some code that

* draws a rectangle using the transparent color -RGB(255,0,128)
* draws a sprite into that area
* does a grab sprite
* THEN draws this grabbed sprite using ZOOMSPRITE

I get a purple halo around the image where transparent and non-transparent colours meet, included the outer border of the sprite.  I reported this problem as part of another post which was buried and I forgot about it until coming across it again now.

Code (glbasic) Select
// sprite loaded in Id=1
DRAWRECT 0,0, 32, 32, RGB(255,0,128) // transparent colour
DRAWSPRITE 1,0,0
GRABSPRITE 1,0,0,32,32

ZOOMSPRITE 1, 100,100, 2,2
Here's a examples:





It doesn't do it if you only do LOADSPRITE, the problem occurs after doing a drawsprite then grabsprite.  Can this please be fixed.

AndyH

Ah, should add that ROTOSPRITE and ROTOZOOMSPRITE does it as well.  Only vanilla DRAWSPRITE will draw the grabbed sprite without putting the purple outline around everything.

Kitty Hello

Oh dear. Could you set RGB(0,0,0) as transparent color, maybe :D (duck+run)

The problem is, that OpenGL slighty blends the neighbour pixels (pink) into your grabbed image. I might improve it, but it could slow down things horribly, since I'd have to check pixel by pixel for transparent color.

AndyH

OK, I'll check that.  There's a command to change what is the transparent colour - does this change globally for DRAWSPRITE or does it affect GRABSPRITE only?  (I haven't got GLB here at work to check)

Kitty Hello


AndyH


AndyH

Hi Gernot,  I've tried using SETTRANSPARENT and it does improve things a tiny bit but I think there must be a problem.

Take a look at this (i've made this screenshot 300% the size it normally is):



All of these sprites have been grabbed using GRABSPRITE apart from one of the 'v's and then I've used either DRAWSPRITE, ZOOMSPRITE or ROTOZOOMSPRITE to display them at different sizes.

Notice the Boxed 'O' has no transparency and looks as I expect it to (yes it's blurred a bit due to scaling it up).

Now look at the N and the bottom larger V.  I;ve GRABSPRITE'd these from a black background now, with black as the transparent colour.  They have a black outline much like the purple one I had before with the default transparent colour.

Now take a look at the top V that is scaled up.  This is my original image of the V where I have just used LOADSPRITE and nothing else (no GRABSPRITE on this one).  The non-transparent areas are blurred as expected, but the transparent regions remain transparent, right up the the edges of the V.

Look at the bottom V, this has been GRABSPRITE'd and displayed in exactly the same way as the top V, only it suffers from a black border.

What I don't understand is when I do a GRABSPRITE the image of the V is identical to the LOADSPRITE original.  It is identical on screen - there is no blurring or anti-aliasing around the edges, so I would expect GRABSPRITE to get an exact copy of the V and be no different to the LOADSPRITE original - so why is it not?

For comparison I have drawn the V from the LOADSPRITE version and the GRABSPRITE version at normal scale to the upper right of that screenshot.  Can you tell which one is which?  I can't.  I've checked in photoshop too, and there is no difference.

Why can't / doesn't GRABSPRITE work the same as LOADSPRITE in this case?  The image I load has no alpha information, it's just got a transparent colour.  I've linked to the images used below.

This screenshot is from my larger project, so I'll put together a small example later just to make sure I haven't done something wrong in my code.  But it does appear to be a bug in GRABSPRITE...


Images used to generate that screenshot:



AndyH

Here's the code:

Code (glbasic) Select
SETSCREEN 320,240,0
LIMITFPS 60

// normal sprite in 0
LOADSPRITE "v.png",0


// Grab sprite on purple trans in 1
SETTRANSPARENCY RGB(255,0,128)
DRAWRECT 0,0, 32,32, RGB(255,0,128)
DRAWSPRITE 0,0,0
GRABSPRITE 1,0,0,32,32


// Grab sprite on black trans in 2
SETTRANSPARENCY RGB(0,0,0)
DRAWRECT 0,0, 32,32, RGB(0,0,0)
DRAWSPRITE 0,0,0
GRABSPRITE 2,0,0,32,32


BLACKSCREEN

DRAWRECT 10,10,20,230, RGB(120,0,0)
DRAWRECT 50,10,20,230, RGB(120,0,0)

// sprite 0 normal and large
PRINT "Normal sprite 0",0,0
DRAWSPRITE 0,0,5
PRINT "Zoom sprite 0",50,7
ZOOMSPRITE 0,50,20,2,2

// sprite 1 normal and large
PRINT "Purple sprite 1",0,50
DRAWSPRITE 1,0,55
PRINT "Zoom sprite 1",50,57
ZOOMSPRITE 1,50,70,2,2

// sprite 2 normal and large
PRINT "Black sprite 2",0,100
DRAWSPRITE 2,0,105
PRINT "Zoom sprite 2",50,107
ZOOMSPRITE 2,50,120,2,2


SHOWSCREEN
MOUSEWAIT
You need that v.png image in the previous post.

Run on PocketPC (no OpenGL intervention I guess) and all six 'V's look the same.

Run on Windows and the first two look as I'd expect, next two with the purple halo and final two with black halo.  The halo parts of the image are part transparent pixels and part actual sprite pixels - so it is destroying the image at these edges, not just putting a halo around it.

Can this be fixed?  Grabsprite is not very useful in it's current state.  I'm using GRABSPRITE because the ANIM functions for ZOOM, STRETCH, ROTATE, ROTOZOOM etc are not available yet.  I can't use tilesets and then GRABSPRITE them into separate sprites so I can use the SPRITE ZOOM/STRETCH/ROTATE etc if the images are altered in this way.

Kitty Hello

OK, there's 2 fixes for you.
I'll implement ROTOZOOMANIM, that's the easiest solution.
If you want to scale grabbed gfx, then OpenGL also uses pixels at the border and mixes their color in (take 25% from border pixel + 50% from best pixel + some from the neighbours).
If you want to disable this, you can set it to linear mode:
Code (glbasic) Select
}
extern "C" void __stdcall ::glTexParameteri(int, int, int);
glTexParameteri(0x0de1, 0x2800, 0x2600); // GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(0x0de1, 0x2801, 0x2600); // GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
namespace __GLBASIC__{
Then your scaled images also look blocky as on GP2X/PocketPC.
Note, this is just for informaton - don't do it.

So for now, stay with it until I finished zoomani, or save each piece as a different sprite.

AndyH

Thank Gernot

RotoZoomAnim will atleast allow me to keep all my anims together :)  What's the deal with GRABSPRITE though?

On my PC the loaded sprite when scaled up does not 'take 25% from border pixel + 50% from best pixel + some from the neighbours', only the grabbed sprite versions do that.  Meaning Loaded sprites do look blobky on the edges, not smoothed.  Does this not happen on your OpenGL card?

Thanks for looking into this.

Kitty Hello

Yes. OpenGL does smooth texture texel interpolation, resulting in smoothed images, when scaling bigger than factor 1.0.
In PocketPC (my own library) I use "take the closes pixel" approach, which results in blocky scalings, but offer more speed. (would be unusable on small devices otherwise).

AndyH

QuoteYes. OpenGL does smooth texture texel interpolation, resulting in smoothed images, when scaling bigger than factor 1.0.
This doesn't happen on my PC in Windows (Vista) with a LOADSPRITE'd version though... that's the bit I don't understand:

Code (glbasic) Select
LOADSPRITE "v.png",0
DRAWSPRITE 0,0,5   // sprite at normal size
ZOOMSPRITE 0,50,20,2,2 // sprite at double size - transparent edges are not blurred
This scales up, there is no alteration of the border of visible pixels with the pixels that are transparent.

This code however ...

Code (glbasic) Select
SETTRANSPARENCY RGB(255,0,128)
DRAWRECT 0,0, 32,32, RGB(255,0,128)
DRAWSPRITE 0,0,0
GRABSPRITE 1,0,0,32,32
... draws the sprite at normal scale on the purple background.  I've taken a snapshot of this and compared it to the original image in photoshop and all pixels are exactly the same colour values.  I then GRABSPRITE into sprite 1 and draw this with ZOOMSPRITE and it looks different:

Code (glbasic) Select
ZOOMSPRITE 0,50,20,2,2
ZOOMSPRITE 1,150,20,2,2
Sprite 0 and sprite 1 are displayed differently.  Sprite 0 has no blurring or color distortion on edges with transparent colours, but sprite 1 does.

BTW - there's no alpha channel on the original LOADSPRITE'd image, so I'd expect sprite 0 and sprite 1 to look the same.

I want sprite 1 to look like sprite 0.   That's the bit I don't get.

This is how it looks in Windows (compare the two enlarged V letters):


AndyH

QuoteThen your scaled images also look blocky as on GP2X/PocketPC.
Note, this is just for informaton - don't do it.
BTW - having a command to choose blocky or smoothed for Win/Mac/Linux would be nice to have - sometimes in 2D games you might not want OpenGL to render the image smoothed, but in textures for 3D of course you probaly always do.

Could this be toggled at runtime to affect drawing operations at will such as ALPHAMODE does or is it a property that can only be set when the texture is loaded?

Kitty Hello

You can change that at runtime. Well, might be an idea.

AndyH

Sounds like a good option to have, for when it's needed (epsecially when doing retro - or when scaling up the 320x240 screen to 640x480 when your monitor doesn't support the lower full screen resolution and you want to scale up without the blurring).  Please could you add that command?

So are you able to fix the issue seen here, it's quite important to be able to grab and display consistent to the original image:

Code (glbasic) Select
LOADSPRITE "v.png",0
SETTRANSPARENCY RGB(255,0,128)
DRAWRECT 0,0, 32,32, RGB(255,0,128)
DRAWSPRITE 0,0,0
GRABSPRITE 1,0,0,32,32

ZOOMSPRITE 0,50,20,2,2  // original - no edge blurring
ZOOMSPRITE 1,150,20,2,2 // GRABSPRITE version - bluring on edges