I've attached a small proggy with sourcecode. All it does is use Polyvector to draw tiles side by side, then scales them in and out.
At 1:1 ratio tiles are seemless. However, when not at 1:1 there are often clear divisions between the tiles. How can this be prevented?
(http://i904.photobucket.com/albums/ac242/wheeethefibble/webpics/example-division.jpg)
[attachment deleted by admin]
Replace that inner loop with this one.
I turned into a triangle strip, put the start and end outisde the loop and added POLYNEWSTRIP. This should be faster in general. But the fix turned out to be simple, add 1 to your X start of texture and subtract 1 from your Y end of texture.
STARTPOLY 1,2
WHILE sprtemp > 0
POLYNEWSTRIP
POLYVECTOR xstep, ystep+(ydim*zoomsize), 1, ydim-1, RGB (255, 255, 255)
POLYVECTOR xstep+(xdim*zoomsize), ystep+(ydim*zoomsize), xdim, ydim-1, RGB(255, 255, 255)
POLYVECTOR xstep+(xdim*zoomsize), ystep, xdim, 0, RGB(255, 255, 255)
POLYVECTOR xstep, ystep, 1, 0, RGB(255, 255, 255)
POLYVECTOR xstep, ystep+(ydim*zoomsize), 1, ydim-1, RGB (255, 255, 255)
DEC sprtemp
INC xstep, (zoomsize * xdim)
INC xc
IF xc = horsprites
xstep = xmid-(gridxmid * zoomsize)
xc = 0
INC ystep, (zoomsize * ydim)
INC yc
IF yc = 11
xstep = xmid-(gridxmid * zoomsize)-1
ystep = ymid-(gridymid * zoomsize)-1
xc = 0
yx = 0
ENDIF
ENDIF
WEND
ENDPOLY
Scott_AQ you have saved me much head scratching yet again! :happy: Your programming skills obviously far exceed mine but if there is anything I can ever do to help you out I'd only be too happy.
I have absolutely no idea why adding one and subtracting one from the x start and y end should work like this but the result is perfect. Polyvector is awesome but stuff like that confuses me. Until recently I hadn't even looked at Polyvector or the 3D functions of GLBasic. Anyway, I'm very slowly emerging from the darkened cave of the 16-bit era - the last time I tried games programming.
Thanks for suggesting Polynewstrip. I guess it would be faster if the same texture was used for each tile. Ultimately I'm aiming to create a map display routine that will scale and scroll in the classic iPhone manner so unless checking which tiles are identical and drawing all of them as a bunch is worth it to save CPU I'll probably be using standard FAN mode.
Actually I had to figure it out with good old 'trial and error'. Hasn't failed, just frustrated.
Another tricky thing with polyvector is how your order your vectors.
However if you have a large image as a tile map, you can position your texture points according to the tile's position.
For example, lets say you have a tilemap of 32x32 tiles. To grab a new tile you'll just have to adjust the start and end of your texture points.
startx = 1+tile * 32
endx = -1+tile * 32
With the offset of course, this way one image for one map, much faster then many sprites and individual polyvector calls.
Well my 'trial and error' was leading me to create tiles that over-ran their borders. Terrible idea! So I'm glad you found that fix.
Its a simple thing to design a tilemap drawing routine to check the display area for identical tiles rather than sequentially draw each tile individually from left to right & top to bottom. I'll be doing that from now on since Polyvector is essential for ultra-smooth scrolling involving fractions of pixels. I've experimented with forcing to absolute pixels and it looks untidy by comparison.
The only drawback I found if that if you use them and the computer is a POS with out-of-date opengl drivers and it's forced to do software, then its runs horribly slow.
I should mention that, through writing a testing app specifically for the purpose of testing Polyvector to draw tiles under many varied conditions on a 3rd generation iDevice, I've found out quite a lot about it. Summary: -
- This is hard to explain. I'll try anyway because its quite important in some circumstances. To have completely smooth tiled scaling with Polyvector, the borders of the texture being used have to be extended by one pixel each. For instance, a 160 x 160 tile should be 162 x 162 pixels with the border of 1 pixel being filled by what you'd expect the next line of pixels to be. The area of texture copied would then be 1,1 to 161, 161.
- The most efficient draw method is the STRIP method, with the TRIANGLES method almost as fast - all from the same texture of course. FAN method is much slower when displaying multiple tiles because it has to switch textures for every new fan polygon.
- Alphamode -1.0 and 1.0 are fastest with Polyvector. Alphamode 0 is much slower - it is approximately twice as slow as -1.0 or 1.0. So, transparency on by default is a good idea! Not sure why this is the case (OpenGL, GLBasic or iPhone GPU) but it just is.
- The larger the tile dimensions the faster the screen can be covered in them, i.e. the more screen real-estate can be claimed for less cost. For example, my testing routine completely covers an area of the full screen at least 10 times with tiles of 160 x 160 (scaled to various dimensions) without ever dipping below 60 FPS. When using 20 x 20 tiles the area covered can only reach approximately at least 5 times the entire screen area without dipping below 60 FPS.
- Polyvector was always faster than Drawsprite in my test program. Always. That goes for the Nvidia GPU on my PC as well as the iDevice stuff.
- Not exactly related - using the simulator that comes with the iPhone Dev kit is useless. :glare:
I will never use the various DRAWSPRITE commands again for anything where speed is critical!
Using the 'STRIP' method, how often did you lift your pen using the 'POLYNEWSTRIP' command?
Each sprite?
Each row?
Never (drew all sprites with one connecting series of 'POLYVECTORS')?
If you did it per sprite, I wonder if your texture alignment problem could be fixed by never using 'POLYNEWSTRIP'?
Although, the code to draw one connecting series of polygons could be tricky!
Just curious.
Good idea about trying without using POLYNEWSTRIP.
Previously I was lifting the pen for every sprite. So, I changed it so that POLYNEWSTRIP was called every row instead to see what would happen. It didn't make any difference so I tried not using POLYNEWSTRIP at all. Unfortunately vertical and horizontal seams were still showing between each sprite.
The original problem stems from (necessarily for some purposes) using x,y screen co-ords that are often in fractions of a pixel instead of just integers. I don't mind using sprites with an extra pixel border if I want to do that. It seems an ok price to pay and I could write a little routine to automate the process of adding those borders for me.
Interesting to hear about the alphamode, I'll have to test that out.
NEWPOLYSTRIP would be better for something like particle systems, or handling a bunch of objects in that share the same graphics.
I found out that the 'seams showing' problem is quite widespread.
Here is one of several threads from Cocos-2d iPhone forums about it: http://www.cocos2d-iphone.org/forum/topic/3290 (http://www.cocos2d-iphone.org/forum/topic/3290)
Using many sprites on TextureAtlas sheets requires that they all have 1 pixel of padding. With sprites that don't connect with other sprites this padding should be totally transparent. With sprites that connect with other sprites, i.e. tile-like sprites, the edges that connect to other sprites should be filled.
I'm going to partially convert my PowFish game so it uses a single TextureAtlas and Polyvector for the main sprites, background and some other bits & pieces. I'm guessing I should see quite an improvement in performance since it was previously using variations of the Drawsprite methods.
I wonder if the problem comes from when GLBasic converts the tx, ty values (sometimes called 'UV') to be between 0 and 1 for OpenGL. (I think that conversion takes place!)
If your source coordinates divided by your texture dimensions doesn't result in only a few decimal places, rounding may occur.
Example:
A 32x32 sprite extracted from a 256x256 texture map results in:
32 / 256 = 0.125 (a fairly simple number)
But a 32x32 sprite extracted from a 600x600 texture map results in:
32 / 600 = 0.05333333333333333... (infinite decimal places, so rounding occurs)
But if your sizes are already fairly divisible, then I'm out of ideas.
BTW:
QuoteWith sprites that connect with other sprites, i.e. tile-like sprites, the edges that connect to other sprites should be filled.
What's best for the 'filled' pixels, just a repeat of its neighbor?
Still get the same seams problem taking a 128x128 sprite from a 256x256 texture map (aka texture atlas) unless I use borders.
Oddly, a 128x128 sprite from a 128x128 texture map doesn't cause any problems without a border. It looks smooth with no seams. (this doesn't work with 160 x 160. Seems it has to be a power-of-2 size)
I find the same as the above with a 64x64 sprite. Taking it from a 256x256 or 128x128 texture map I get seams. Taking it from a 64x64 texture map I get no seams - perfect scaling.
Anyway, the best thing for the filled pixels is to use the next expected pixel. So, if you have a repeating tile of a ground texture then the rightmost border should be filled with pixels from the left of the sprite and so forth and so on. Example: -
(http://i904.photobucket.com/albums/ac242/wheeethefibble/webpics/example-tile.jpg)
This issue has just hit me on my own project. It seems that when scaling up GLBasic is blurring the pixels with pixels to the left and above (so you probably don't need the right or bottom border) but of course at the very top and left edges there ARE no pixels above or to the left, so GLBasic (or OpenGL or whatever) guesses what colour to blend with (I guess it assumes a default).
A border to top and left won't work for my situation, but I THINK you may be able to omit the border to the bottom and right of tiles.
a "PROPER" fix has been found by matchy :
Quote from: matchy on 2010-Sep-24
Try:
SMOOTHSHADING FALSE
::)
This should result in very sharp edges. Note though that as a reuls scaling up by a lot may look jagged.
D'oh - just posted exactly this in the other thread about this.
Hi,
The reason for the border is that the end texels don't know what is adjacent to them to calculates a decent anti-aliased pixel, as its on a separate tile . What I have done here is to wrap to texture. I am not changing the UV coords or UV scale so the texture is not repeating but at the very edge, it uses the information at the opposite border to calculate a new smoother border.
This is done by IMPORTing the OPENGL "glTexParameteri" command and the required GL flags.
The result is no borders, yet retaining the smooth anti-aliased texture at any zoom level, for your tile maps.
Not sure if this is the standard way to do it but it seems to work.
Cheers,
Ian
P.S. I changed the demo to use a couple of textures to show how it works, a little more clearly too. Please see attached code.
Whoops... here's the correct zip...
[attachment deleted by admin]
Quote from: Cliff3D on 2010-Sep-24
Try:
SMOOTHSHADING FALSE
::)
This should result in very sharp edges. Note though that as a reuls scaling up by a lot may look jagged.
Thanks for pointing that out. In most situations I would probably go with smoothness on with scaling but this is good to know.
Quote from: bigsofty on 2010-Sep-24
Hi,
The reason for the border is that the end texels don't know what is adjacent to them to calculates a decent anti-aliased pixel, as its on a separate tile . What I have done here is to wrap to texture. I am not changing the UV coords or UV scale so the texture is not repeating but at the very edge, it uses the information at the opposite border to calculate a new smoother border.
This is done by IMPORTing the OPENGL "glTexParameteri" command and the required GL flags.
The result is no borders, yet retaining the smooth anti-aliased texture at any zoom level, for your tile maps.
Not sure if this is the standard way to do it but it seems to work.
Cheers,
That's great Ian. Very interesting. I played around a bit and the only thing I will say is that the extra-pixel border method looks a wee bit smoother on my PC. For some reason there is a slight yellow tinge at the edges the tiles using your routine. Its barely noticeable and can only really be seen when enlarging with the lighter tiles. I'll attach a modification of your routine to demonstrate. Press space to change between border method and glTexParameteri method. The method currently being used is displayed at the top left of the screen.
[attachment deleted by admin]
I can't quite see it, it looks OK to me but I am viewing on a very small netbook screen here?
Cheers,
Ian
Quote from: bigsofty on 2010-Sep-29
I can't quite see it, it looks OK to me but I am viewing on a very small netbook screen here?
That's good because no one is going to be seeing it on a tiny iPhone or iPod screen. =D
Ha, that logical I suppose! : :good: