Sprites or PolyVectors - Mixed Opinions

Previous topic - Next topic


I've tried to look at the varied posts regarding which is best to use and some people seem to say there's no difference, others are saying Sprites are slower. Is there a definitive answer here, and if indeed the answer is different can anyone give an example of when to use each for optimum speed usage. One thing also concerns me is that if PolyVectors are the way to go then we have no collision commands for them do we?

Thanks for your enlightenment =)
http://www.spicypixel.net | http://www.facebook.com/SpicyPixel.NET

Comps Owned - ZX.81, ZX.48K, ZX.128K+2, Vic20, C64, Atari-ST, A500.600.1200, PC, Apple Mini-Mac.

Ian Price

You can still use POLYVECTOR sprites with collision - it's their position (and image number) that's important, not how they are displayed. In fact you can have a collision with no images on screen - just don't draw them!

Different machines mean different specs - what might be faster in one area for that user may not be the same for another. Also consider that handheld devices will have varying results too, depending on their GFX hardware.

All you can be definitive about is the machine YOU are using.

If you need millions of sprites on screen, then take some time to try sprites and polyvectors. It'll be time well spent. With POLYVECTORs it's best to use POLYNEWSTRIP when drawing loads of images rather than using a loop to draw them.
I came. I saw. I played.


I'd wait for another opinion, but here's my take on this issue.
Polyvectors are DEFINATELY faster than sprites IF used properly.

  • For maximum speed, keep all your graphics in one (or as few as possible) sprite sheet, and use the tx/ty to specify where the desired image is located
  • Have a common DrawPoly() routine that DOESN'T include the command 'STARTPOLY' or 'ENDPOLY'.
    (Manually use START/ENDPOLY before/after all your polyvector drawing, this keeps the draw calls do a minimum.)

And correct, polyvectors don't have any collision commands. 
However there's nothing stopping you from using polyvectors for the fast drawing, and then use ANIMCOLL() for the collision detection.  It would make things easier if your entire sprite sheet was grid based for ANIMCOLL(), then treat each animation frame like a normal sprite sheet item.

Just for reference, or to compare, here's (mostly) my polyvector code:
(I added a tex_start and tex_end to handle the STARTPOLY/ENDPOLY automatically)
The 'scale' option hasn't been tested.

Code (glbasic) Select


TYPE TSpriteUv
uv AS TXyXy

FUNCTION New%: sprite_id%, tx%, ty%, tw%=1, th%=1, colour%=0, grid_size%=32
self.sprite_id = sprite_id
self.colour = colour
IF grid_size > 1
self.uv.x1 = tx * grid_size // Texture Left
self.uv.y1 = ty * grid_size // Texture Top
self.uv.x2 = tw * grid_size + self.uv.x1 // Texture Right
self.uv.y2 = th * grid_size + self.uv.y1 // Texture Bottom
self.uv.x1 = tx // Texture Left
self.uv.y1 = ty // Texture Top
self.uv.x2 = tx + tw // Texture Right
self.uv.y2 = ty + th // Texture Bottom

FUNCTION Draw: x%, y%, colour%=-1, tex_start%=FALSE, tex_end%=FALSE, scale#=1.0
xy.x1 = x
xy.y1 = y
xy.x2 = x + ((self.uv.x2 - self.uv.x1) * scale)
xy.y2 = y + ((self.uv.y2 - self.uv.y1) * scale)
IF colour = -1 THEN colour = self.colour
IF tex_start THEN STARTPOLY self.sprite_id, POLYMODE_STRIP
Poly_Draw(xy, self.uv, colour)


// (uv1) 0___2
//       |  /|
//       | / |
//       |/__|
//       1   3 (uv2)
// xy_px :: Top-Left and Bottom-Right screen location
// xy_uv :: Top-Left and Bottom-Right texture location
FUNCTION Poly_Draw: xy AS TXyXy, uv AS TXyXy, colour%
POLYVECTOR xy.x1, xy.y1, uv.x1, uv.y1, colour // TL
POLYVECTOR xy.x1, xy.y2, uv.x1, uv.y2, colour // BL
POLYVECTOR xy.x2, xy.y1, uv.x2, uv.y1, colour // TR
POLYVECTOR xy.x2, xy.y2, uv.x2, uv.y2, colour // BR

// Usage:
LOCAL tile AS TSpriteUv
tile.New(1, 4, 3, 1, 1, RGB(255,0,0)) // Tile is in sprite 1, five over and four down in sprite sheet (and is only 1x1 grid units in size), the sheet is arranged with a 32 pixel grid
LOCAL is_first%=FALSE, is_last%=FALSE
FOR x = 1 to 100000
  is_first = FALSE; is_last = FALSE
  if x=1 then is_first = TRUE
  if x=100000 then is_last = TRUE
  tile.Draw(100, 100, -1, is_first, is_last)  // Draw 'tile' at 100,100, keep original colour

[Edit] - Simplified the 'Draw()' function somewhat by removing the tex_start and tex_end, and simplified the main drawing loop:
Code (glbasic) Select
FUNCTION Draw: x%, y%, colour%=-1, scale#=1.0
xy.x1 = x
xy.y1 = y
xy.x2 = x + ((self.uv.x2 - self.uv.x1) * scale)
xy.y2 = y + ((self.uv.y2 - self.uv.y1) * scale)
IF colour = -1 THEN colour = self.colour
Poly_Draw(xy, self.uv, colour)

// Start drawing polygons from 'tile.sprite_id'

FOR x = 1 to 100000
  tile.Draw(100, 100)  // Draw 'tile' at 100,100

ENDPOLY  // Done drawing all polygons from this sheet
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]


Thank you for the replies I will endeavour to do some tests and see what works best for me. Thank you for the code snippet it will indeed help me get going in the right direction. Again thank you both.
http://www.spicypixel.net | http://www.facebook.com/SpicyPixel.NET

Comps Owned - ZX.81, ZX.48K, ZX.128K+2, Vic20, C64, Atari-ST, A500.600.1200, PC, Apple Mini-Mac.


@slydog Interesting findings.

Is there any reason why using gfx on a sprite sheet is faster performance than using gfx that you have loaded into memory initially??
Or do you mean that it is quicker overall including the loading time.

I am not trying to be argumentative, just curious that I might have missed something


When using a sprite sheet (or more importantly, only using STARTPOLY and ENDPOLY once total) you don't keep changing the material.
GLBasic converts your code to use OpenGL calls, and the STARTPOLY command instructs OpenGL to start using a new material.  (correct me if I'm wrong)
Each new material creates a new Draw Call (OpenGL term?).
Each draw call change takes time, so the more draw calls, the slower your game.  (Draw calls are more important that the actual quantity of polygons, within reason).

For example, on the Unity forums they say for iPhones to keep your total draw calls to 30 or below (may have been for the older iPhones).
Each 'item' on the screen generally uses a draw call, unless you can group them together using sprite sheets, then they can share a draw call.

Same as for 3D mode and 3D models, if each model uses its own material / texture file, then each model uses a new draw call.
If you can design your models with one texture file to share amongst them and 'paint' them with the proper UV coordinates, then those models share one draw call.
The 'X_SETTEXTURE()' command changes the material, so only use that once before drawing the models.

I'm not really an expert as I've never programmed in OpenGL, this info was just from prior researching.
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]


I understand thanks.
i didnt realise that each material triggered a new draw call so that is very useful to know.

Learn something new every day  :good:


I am surprised that my lattest app, GLOWING SKY, draw so many sprites so fast. I am using a single sheet 16x12 sprites, and I draw on iphone4 around 4000 sprites withput noticing any lag... I didnt implement any fps counter.

I use just drawsprite.

Also I have noted also that Palm Pre2 is as fast as a iphone 4.


Earlier I thought that polyvector significantly improves rendering speed, but now I do not know ..
Check it yourself, I uploaded code here:
maybe I'm doing something wrong..

Yesterday I saw some old post about slow 3d on iPad with Glb, so today I was searching for some OpenGl speed-up improvements that could be adapted into Glb. I found that:
I don't know how exactly StartPoly, Polyvector works, but would be faster to draw for example map tiles with glDrawArrays? My c++ and raw OpenGl skills are low, so I only managed to rewrite some code from that video:

Code (glbasic) Select

TYPE sb_vertex

GLOBAL SB_maxverts%, sb_currvert%
GLOBAL SB_vertices[] AS sb_vertex, sb_typesize%

FUNCTION SB_init: ver_count%
DIM SB_vertices[ver_count%]
sb_currvert% = 0
SB_maxverts% = ver_count%
sb_typesize = sizeof(sb_vertex);

FUNCTION SB_clear: something%
DIM SB_vertices[0]

FUNCTION SB_addvertex: posx#, posy#, uvx#, uvy#, vcolor%
SB_vertices[sb_currvert%].v#[0] = posx#
SB_vertices[sb_currvert%].v#[1] = posy#
SB_vertices[sb_currvert%].uv#[0] = uvx#
SB_vertices[sb_currvert%].uv#[1] = uvy#
//SB_vertices[sb_currvert%].color% = vcolor%
SB_vertices[sb_currvert%].color%[0] = 255
SB_vertices[sb_currvert%].color%[1] = 255
SB_vertices[sb_currvert%].color%[2] = 255
SB_vertices[sb_currvert%].color%[3] = 255
INC sb_currvert%

SUB SB_draw:
IF (sb_currvert = 0); RETURN; ENDIF

//glBlendFunc(GL_SRC_ALPHA, GL_ONE)

glVertexPointer(2, GL_SHORT, sb_typesize, SB_vertices[0].v#[])
glTexCoordPointer(2, GL_FLOAT, sb_typesize, SB_vertices[0].uv#[])
//glColorPointer(4, GL_UNSIGNED_BYTE, sb_typesize, SB_vertices[0].color%[])
glDrawArrays(GL_TRIANGLES, sb_typesize, sb_currvert%)
sb_currvert% = 0


and to add a rectangular sprite to batch I do this: (assuming that sprite width=height=128)
Code (glbasic) Select
SB_addvertex(spr.x, spr.y, 0, 0, white_color%)
SB_addvertex(spr.x+128, spr.y, 1, 0, white_color%)
SB_addvertex(spr.x, spr.y+128, 0, 1, white_color%)

SB_addvertex(spr.x+128, spr.y, 1, 0, white_color%)
SB_addvertex(spr.x, spr.y+128, 0, 1, white_color%)
SB_addvertex(spr.x+128, spr.y+128, 1, 1, white_color%)

You need to attach 'GLBasic\Samples\Common\gl.bas' or just download my file..
I'm getting strange results -> misplaced sprites and other crazy things.. Whats wrong in this code, and how get this working correctly? ;]
of course before drawing I set X_Make3d, X_Settexture texnumber%, -1 and X_Make2d after drawing.

[attachment deleted by admin]
Check my source code editor for GLBasic - link Update: 20.04.2020