Tiled/Polyvectors/Math Errors...

Previous topic - Next topic

bigtunacan

So I created a loader for Tiled; that part is working fine.  I loaded all of my tiles into sprites and run through bunch of calls to ZOOMSPRITE.  Holy smokes it was slow!  I'm using 16x16 tiles and targeting iPhone 3G.  So max of 600 sprites per layer; current maps are using 3 layers, I would say somewhere around 1000 sprites being drawn per frame.  It was unbelievably slow...

So I tried to switch direct over to polyvectors, but somehow I'm getting my math all wrong...

Code (glbasic) Select

FOREACH lyr IN lyr_arr[]
FOR i%=0 TO LEN(lyr.tiles$[])-1
tile = lyr.tiles$[i]
IF bAND(FLIPPED_VERT, tile) = FLIPPED_VERT
yflip = -1
ELSE
yflip = 1
ENDIF

ret=0
INLINE

int a,b;
a = (int) FLIPPED_HORZ;
b = (int) tile;
ret = a & b;
ENDINLINE
IF ABS(ret) = FLIPPED_HORZ
xflip = -1
ELSE
xflip=1
ENDIF

tile = ASL(tile,2)
tile = ASR(tile,2)

IF NOT tile=0
//ZOOMSPRITE (tile+TILE_SPRITE_INDEX_OFFSET-1), MOD(i,lyr.width)*tilewidth, (i%/lyr.width%)*tileheight%, xflip, yflip
LOCAL x%,y%
x%=MOD(i,lyr.width)*tilewidth
y%=(i%/lyr.width%)*tileheight%

STARTPOLY 0,0
  POLYVECTOR  MOD(i,lyr.width)*tilewidth,    (i%/lyr.width%)*tileheight%,  MOD(tile,32)*tilewidth,  tile%/2, RGB(255, 255, 255)
  POLYVECTOR  MOD(i,lyr.width)*tilewidth, ((i%/lyr.width%)*tileheight%)+tileheight, MOD(tile,32)*tilewidth, (tile%/2)+16, RGB(255, 255, 255)
  POLYVECTOR  (MOD(i,lyr.width)*tilewidth)+tilewidth, ((i%/lyr.width%)*tileheight%)+tileheight, (MOD(tile,32)*tilewidth)+16, (tile%/2)+16, RGB(255, 255, 255)
  POLYVECTOR  (MOD(i,lyr.width)*tilewidth)+tilewidth, (i%/lyr.width%)*tileheight%, (MOD(tile,32)*tilewidth)+16, tile%/2, RGB(255, 255, 255)
ENDPOLY
ENDIF
NEXT
NEXT


If I comment out the POLYVECTOR section and uncomment the ZOOMSPRITE line it works correctly but the frame rate is too low...

The polyvector section renders tiles to the screen but they are off.  I've played with them a little bit and got them working for some simple stuff, but still a little confused how they work.

monono

I don´t know exactly what you are doing, but it seems pretty complicated to me (No complete code. I can´t test it =D). What is that MOD() function about?
But one mistake I can help. You don´t have to call STARTPOLY/ENDPOLY instead of DRAWSPRITE, you can do it with one drawing call. Using POLYNEWSTRIP is where the increase of speed should come from.
Code (glbasic) Select

STARTPOLY
FOR y = 0 to 10
   FOR x = 0 to 15
      POLYVECTOR x*tilewidth,y*tilewidth
      POLYVECTOR ....
      POLYVECTOR ...
      POLYVECTOR ...
      POLYNEWSTRIP //!!!!!!!!!
   NEXT
NEXT
ENDPOLY


To do that you have to put all tile-graphics into one texture and change the texture coordinates in the loop.

Ian Price

Don't use MOD on handheld devices if you can help it - it can be incredibly slow, especially if you are calling it upto 1000 times per loop for the map!

Rather than calling MOD(i,lyr.width)*tilewidth mulitple times every frame, why not set up a global/local variable that acts as that value?

And use monono's POLYNEWSTRIP code - you should see a massive improvement in your map drawing speed.
I came. I saw. I played.

bigtunacan

I typically run on the PC to get everything working properly before moving to iPhone to do performance checks; and even on the PC I notice the slow down.  It makes sense about MOD being slow on iPhone, but I wouldn't expect that on the PC, so I think my biggest problem is related to the number of zoomsprites.

Also, this is being called in a big loop as it goes through all of the tiles so the value is changing each pass through; if it's needed I could pre-calculate and store the value in an array and use that.

I'll check out the POLYNEWSTRIP code and see if that will work better for what I'm doing; I haven't seen it before.

Ian Price

ZOOMSPRITE is indeed processor intensive, but I guarantee you that using MOD is having a big impact too. If you are so sure it's just the ZOOMSPRITE then why not just increase the size of your sprites to the ZOOMSPRITE size value? Seems like you are trying to do a lot of CPU intensive stuff that is totally unnecessary (from what we've read).

As stated, getting rid of MOD and using POLYVECTORs and POLYNEWSTRIP should cure this problem.
I came. I saw. I played.

bigtunacan

I'm not re-sizing the sprites in a true sense.  I'm using ZOOMSPRITE because some tiles are flipped vert/horz.  So ZOOMSPRITE is used so x/y scales can be passed as -1 when they are flipped.

Also, just looked at the doc on the POLYNEWSTRIP.  I understand how that will speed things up.  I'm having 2 issues here.

1) Performance
2) Polyvector drawing is off

Problem 1 was due to the ZOOMSPRITE plus MOD.  So I can remove MOD with an array lookup; that's not too big a deal.

Problem 2 was due to something in my POLYVECTOR.  At this stage I'm only trying to address this issue of the POLYVECTOR drawing.  After I get it working I will add in POLYNEWSTRIP to speed things up.

I have a single PNG file that stores my tiles as a 512x512 image.  The individual tiles are 16x16. 
My map layers are 30 wide x 20 high tiles
I believe that in my POLYVECTOR code my texture mappings are incorrect.


Code (glbasic) Select

STARTPOLY 0,0
POLYVECTOR  MOD(i,lyr.width)*tilewidth,    (i%/lyr.width%)*tileheight%,  MOD(tile,32)*tilewidth,  tile%/2, RGB(255, 255, 255)
POLYVECTOR  MOD(i,lyr.width)*tilewidth, ((i%/lyr.width%)*tileheight%)+tileheight, MOD(tile,32)*tilewidth, (tile%/2)+16, RGB(255, 255, 255)
POLYVECTOR  (MOD(i,lyr.width)*tilewidth)+tilewidth, ((i%/lyr.width%)*tileheight%)+tileheight, (MOD(tile,32)*tilewidth)+16, (tile%/2)+16, RGB(255, 255, 255)
POLYVECTOR  (MOD(i,lyr.width)*tilewidth)+tilewidth, (i%/lyr.width%)*tileheight%, (MOD(tile,32)*tilewidth)+16, tile%/2, RGB(255, 255, 255)
ENDPOLY

Ian Price

Without seeing how you want the sprites/polyvectors to appear and how they are actually appearing it's not easy to see what the problem is. Can you provide us with screenies of both.
Quote2) Polyvector drawing is off
doesn't mean a great deal - are all your polys being drawn slightly left/right/up/down or completely in the wrong positions?
I came. I saw. I played.

Slydog

#7
Since you calculate x%, and y%, your code can be simplified:
Code (glbasic) Select
STARTPOLY 0,0
  POLYVECTOR  x, y,                      MOD(tile,32)*tilewidth,  tile%/2, RGB(255, 255, 255) // Top Left
  POLYVECTOR  x, y+tileheight,           MOD(tile,32)*tilewidth, tile%/2+16, RGB(255, 255, 255) // Bottom Left
  POLYVECTOR  x+tilewidth, y+tileheight, MOD(tile,32)*tilewidth+16, tile%/2+16, RGB(255, 255, 255) // Bottom Right
  POLYVECTOR  x+tilewidth, y,            MOD(tile,32)*tilewidth+16, tile%/2, RGB(255, 255, 255) // Top Right
ENDPOLY


I think one of your problems is drawing the polyvector corners in the wrong order.
Try switching the last two POLYVECTOR lines, so it doesn't draw in a square, but diagonal.

[Edit] I see you're in 'fan' mode (STARTPOLY 0,0).  My diagonal comment assumed you were in 'strip' mode (STARTPOLY 0,2).  Not sure how fan mode behaves as I always use strip.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

bigtunacan

I've attached here a copy of a good versus bad image.  The good image shows what the screen should look like; in that case I created a bunch of sprites up front by breaking up my tile image using polyvectors then drawing with zoomsprite.  In the bad image I'm using my polyvector code that is attempting to map to the texture sprite on the fly.

[attachment deleted by admin]

Ian Price

Just looking at the yellow band in the "bad.png" image It would appear that your texture/display co-ords are not correct for the polyvector. I would therefore presume that all of your co-ords are incorrect, causing the unexpected image results.

Ensure that you are following Gernot's diagram for drawing the polygon correctly. The texture should be drawn in exactly the same way.
I came. I saw. I played.

Slydog

#10
The following:
Code (glbasic) Select
tile = ASL(tile,2)
tile = ASR(tile,2)

Multiplies by 4, then divides by 4, basically just removing the left two bits?

Could that be written:
Code (glbasic) Select
tile = tile bAND 0x3FFFFFFF
[Edit] That should be:
Code (glbasic) Select
tile = bAND(tile, 0x3FFFFFFF)

I would add this somewhere in that loop to be sure 'tile' is what you think it is:
Code (glbasic) Select
DEBUG tile + "\n"

Oh, and the 'tile%/2' in the POLYVECTOR command, why divide by 2? 
It looks like you're starting to draw your poly's from the middle of the sprite texture, and that command suggests that too.

I would recommend rewriting the tile TYPE to include the x, y coordinates in the sprite texture (plus width and height for future expansion). 

To keep the code cleaner and less bug prone, create a generic 'DrawPoly()' command such as:
Code (glbasic) Select

// Default 'colour' to white if omitted
FUNCTION DrawPoly: x1%, y1%, x2%, y2%, u1%, v1%, u2%, v2%, colour%=0xFFFFFFFF
  STARTPOLY 0, 2
    POLYVECTOR  x1, y1, u1, v1, colour // Top Left
    POLYVECTOR  x1, y2, u1, v2, colour // Bottom Left
    POLYVECTOR  x2, y1, u2, v1, colour // Top Right
    POLYVECTOR  x2, y2, u2, v2, colour // Bottom Right
  ENDPOLY
ENDFUNCTION


[Edit] For speed, I wouldn't put the STARTPOLY / ENDPOLY inside the function, but for testing it is fine.  Do like what was suggested by monono.

Good luck!
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

bigtunacan

Quote from: Slydog on 2011-Nov-16
The following:
Code (glbasic) Select
tile = ASL(tile,2)
tile = ASR(tile,2)

Multiplies by 4, then divides by 4, basically just removing the left two bits?

Could that be written:
Code (glbasic) Select
tile = tile bAND 0x3FFFFFFF

I've done Debug with the tile value out and it show the correct value after the shift; I'm just doing that to remove the flip data that is embedded with the tile data.  I removed the debug statements when posting here to make it easier to read.

Quote
Oh, and the 'tile%/2' in the POLYVECTOR command, why divide by 2? 
It looks like you're starting to draw your poly's from the middle of the sprite texture, and that command suggests that too.

My image is 512px wide and the tiles are 16px wide, so it is 32 tiles wide.  So what I was trying to do there was Divide by 32 for map width then multiply by 16 for tile width offset; so I reduced to 2 since that is less calculations.

Quote
I would recommend rewriting the tile TYPE to include the x, y coordinates in the sprite texture (plus width and height for future expansion). 

I like this idea a lot; it didn't cross my mind, but may very well work and save me the calculations here.  Thanks much for this wonderful suggestion.

Quote
To keep the code cleaner and less bug prone, create a generic 'DrawPoly()' command such as:
Code (glbasic) Select

// Default 'colour' to white if omitted
FUNCTION DrawPoly: x1%, y1%, x2%, y2%, u1%, v1%, u2%, v2%, colour%=0xFFFFFFFF
  STARTPOLY 0, 2
    POLYVECTOR  x1, y1, u1, v1, colour // Top Left
    POLYVECTOR  x1, y2, u1, v2, colour // Bottom Left
    POLYVECTOR  x2, y1, u2, v1, colour // Top Right
    POLYVECTOR  x2, y2, u2, v2, colour // Bottom Right
  ENDPOLY
ENDFUNCTION



[Edit] For speed, I wouldn't put the STARTPOLY / ENDPOLY inside the function, but for testing it is fine.  Do like what was suggested by monono.[/Edit]


I have a generic function like you suggest for my characters sprites, but since my tiles are being handled quite differently I have just plopped it into my function for now.  My plan is to switch it over to use the POLYNEWSTRIP as suggested earlier to speed things up; but for simplicity I wanted to start with just getting it working this way first; then I will refactor it.

Slydog

Does 'tile%' represent a tile index?
Such as the map consists of say 32 unique tile graphics, and the map stores a tile index of say 6 meaning to draw the 6th tile image for that location? (and therefore tile=6?)

If so, then the 'tile% / 2' seems like your problem.
You are saying that the tile graphic's y start location is 'tile / 2' which doesn't make sense.
(Unless tile doesn't mean tile index.)
I have a hunch you want to use 'tile / 32' for the y instead (the x portion looks right).
May have to adjust for rounding, maybe using the INTEGER() command.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

bigtunacan

#13
Ok... so I figured out what my first problem was.

I've post the updated section of the code here.  I had an off by 1 issue in the x texture position; the tile numbers start at one, but the pixels start at 0... this was causing some of the tiles to index into the wrong area of the image and hit transparent issues.  Similarly on the y texture position it was off due to me trying to short cut a divide by 32 and multiply by 16 into a divide by 2; this was causing some of the tile indices to shift off by a tile; it is so hard for me to get into the mindset of integer math rather than floating math and so I make these kinds of stupid mistakes  :doubt:

Code (glbasic) Select

LOCAL x%,y%
x%=MOD(i,lyr.width)*tilewidth
y%=(i%/lyr.width%)*tileheight%

LOCAL xtex = MOD(tile-1,32)*tilewidth
LOCAL ytex = ((tile%-1)/32)*16

STARTPOLY 0,2 // Bitmap = No.0
IF xflip=1 AND yflip=1
POLYVECTOR  x,    y%,  xtex,  ytex, RGB(255, 255, 255)
POLYVECTOR  x, y%+tileheight, xtex, ytex+16, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%, xtex+16, ytex, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%+tileheight, xtex+16, ytex+16, RGB(255, 255, 255)
ELSEIF xflip = -1 AND yflip =1
POLYVECTOR  x,    y%,  xtex+16,  ytex, RGB(255, 255, 255)
POLYVECTOR  x, y%+tileheight, xtex+16, ytex+16, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%, xtex, ytex, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%+tileheight, xtex, ytex+16, RGB(255, 255, 255)
ELSEIF xflip = 1 AND yflip = -1
POLYVECTOR  x,    y%,  xtex,  ytex+16, RGB(255, 255, 255)
POLYVECTOR  x, y%+tileheight, xtex, ytex, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%, xtex+16, ytex+16, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%+tileheight, xtex+16, ytex, RGB(255, 255, 255)
ELSEIF xflip = -1 AND yflip = -1
POLYVECTOR  x,    y%,  xtex+16,  ytex+16, RGB(255, 255, 255)
POLYVECTOR  x, y%+tileheight, xtex+16, ytex, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%, xtex, ytex+16, RGB(255, 255, 255)
POLYVECTOR  x+tilewidth, y%+tileheight, xtex, ytex, RGB(255, 255, 255)
ENDIF
ENDPOLY


So after I got that working I tried to reduce the number of calls to STARTPOLY by switching to STRIP mode; which you can see above.  STRIP mode worked ok when I was still drawing a single block at a time, but when I added in POLYNEWSTRIP I ended up with the wacky image I have attached here.

It is fixed now and using STRIP mode with POLYNEWSTRIP.  The image attached here was caused by a PRINT statement I head inside my tile rendering function that I had been using for debugging.  Everything is running way faster.  Thanks for all of the help!

[attachment deleted by admin]