If you ever wanted to be able to rotate X_SPRITEs or you want them to be faster (so you can create plenty of them, e.g. for a particle engine), than here is a solution for you:
My TSprite can get scaled, rotated and positioned anywhere in the 3D-scene, it will always turn to the camera (like X_SPRITE does), even if you use X_CAMERAUP (for a 6DOF camera). Its all encapsulated into one Type, for easy transfer to your projects.
Comparison with X_SPRITE:
differences:
- its midhandled (centered)
- need to get textured manually
- scale=1 has alwasy the same size (1 unit in 3D environment), no matter what size the texture got
advantages:
- rotation is possible
- faster at least +5-400% on my machine (without texture ordering)
- gives you the ability for texture ordering (+700-3200% more speed on my machine!
)
disadvantages:
- you need to call more than one function
- gl.gbas (or at least a part of it) and QSIN is needed in your project
- maybe do not run on mobile devices (with OpenGL ES), i dont know, someone need to test this
How to use it:
At game start, define and initialise it:
LOCAL sprite AS TSprite
sprite.Init()
In your gameloop render all your GLB 3D stuff, than make sprite.start(), draw your sprites and texture them, try to use as few X_SETTEXTURE as possible if some sprites use the same texture, just make only one X_SETTEXTURE and draw all sprites that use it (texture ordering). End your sprite drawing with sprite.stop(). Just use one start() and stop() pair each loop and draw all sprites between them. Do not use any GLB OpenGL calls between start() and stop()!
sprite.Start()
X_SETTEXTURE 0
sprite.Draw()
sprite.Draw()
sprite.Draw()
sprite.Draw()
X_SETTEXTURE 1
sprite.Draw()
X_SETTEXTURE 2
sprite.Draw()
sprite.Draw()
sprite.Stop()
Ok, here is the code and a test program that show you how to use it (again^^) and let you compare the sprite techniques on your machine:
Code:
// ------------------------------------------ //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: December 01, 2012
// For a newer Version go to: http://www.kanonet.de/downloads/libsprite
// ------------------------------------------ //
//?DEFINE gl_gbas 1 // define this, if you use gl.gbas; set it to zero or dont define it, if you do NOT use gl.gbas
TYPE TSprite
// vertex coords
m0#; m1#; m2#
m4#; m5#
m8#; m9#; m10#
// normal coords
nx#; ny#; nz#
// texture coords
t0x#=0; t0y#=1
t1x#=1; t1y#=1
t2x#=0; t2y#=0
t3x#=1; t3y#=0
// last drawn normal
lastnormal AS char
?IF DEFINED( gl_gbas )
?ELSE
INLINE
typedef unsigned int GLenum;
typedef float GLfloat;
#define GL_TRIANGLE_STRIP 0x0005
} extern "C" {
void __stdcall glBegin( GLenum mode );
void __stdcall glEnd( void );
void __stdcall glVertex3f( GLfloat x , GLfloat y , GLfloat z );
void __stdcall glNormal3f( GLfloat nx , GLfloat ny , GLfloat nz );
void __stdcall glTexCoord2f( GLfloat s , GLfloat t );
} namespace __GLBASIC__ {
ENDINLINE
?ENDIF
// start drawing of sprites, call it one time each loop: after X_CAMERA... and before you draw your sprites
FUNCTION Init%:
STATIC mat#[]
X_GETCAMERAMATRIX mat[]
ALIAS n2 AS mat[2]; ALIAS n10 AS mat[10]
self.m0 = -mat[0]
self.m4 = -mat[4]
self.m8 = -mat[8]
self.m1 = mat[1]
self.m5 = mat[5]
self.m9 = mat[9]
self.m10=qInvSQR(n2*n2 + n10*n10)
self.m2=n2*self.m10
self.m10=n10*self.m10
self.nx = n2
self.ny = mat[6]
self.nz = n10
self.lastnormal = 0
ENDFUNCTION
// draw a spherical sprite (same like X_SPRITE)
// needs to be after Start()
// sprite will be midhandled (unlike X_SPRITE)
FUNCTION Draw%: x#,y#,z#, Scale#=1.0, Rotation#=0.0
STATIC xn#,xp#, yn#,yp#, zn#,zp#
Scale# = Scale# * 0.5
zn = qSIN( Rotation# + 90 ) * Scale#
zp = qSIN( Rotation# ) * Scale#
Rotation# = self.m1 * zp + self.m0 * zn
xn = self.m1 * zn - self.m0 * zp
xp = Rotation#+xn; xn = Rotation#-xn
Rotation# = self.m5 * zp + self.m4 * zn
yn = self.m5 * zn - self.m4 * zp
yp = Rotation#+yn; yn = Rotation#-yn
Rotation# = self.m9 * zp + self.m8 * zn
zn = self.m9 * zn - self.m8 * zp
zp = Rotation#+zn; zn = Rotation#-zn
?IF DEFINED( gl_gbas )
glBegin( GL_TRIANGLE_STRIP )
IF self.lastnormal <> 1
glNormal3f( self.nx, self.ny, self.nz )
self.lastnormal = 1
ENDIF
glTexCoord2f( self.t0x, self.t0y )
glVertex3f( x# + xp, y# + yp, z# + zp )
glTexCoord2f( self.t1x, self.t1y )
glVertex3f( x# - xn, y# - yn, z# - zn )
glTexCoord2f( self.t2x, self.t2y )
glVertex3f( x# + xn, y# + yn, z# + zn )
glTexCoord2f( self.t3x, self.t3y )
glVertex3f( x# - xp, y# - yp, z# - zp )
glEnd()
?ELSE
INLINE
glBegin( GL_TRIANGLE_STRIP );
if (this->lastnormal != 1) {
glNormal3f( this->nx, this->ny, this->nz );
this->lastnormal = 1;
};
glTexCoord2f( this->t0x, this->t0y );
glVertex3f( x + xp, y + yp, z + zp );
glTexCoord2f( this->t1x, this->t1y );
glVertex3f( x - xn, y - yn, z - zn );
glTexCoord2f( this->t2x, this->t2y );
glVertex3f( x + xn, y + yn, z + zn );
glTexCoord2f( this->t3x, this->t3y );
glVertex3f( x - xp, y - yp, z - zp );
glEnd();
ENDINLINE
?ENDIF
ENDFUNCTION
// draw a cylindrical sprite (same like X_SPRITE)
// needs to be after Start()
// sprite will be midhandled (unlike X_SPRITE)
FUNCTION Draw2%: x#,y#,z#, Scale#=1.0, Rotation#=0.0
STATIC xn#,xp#, yn#,yp#, zn#,zp#
Scale# = Scale# * 0.5
zn = qSIN( Rotation# + 90 )*Scale#
zp = qSIN( Rotation# )*Scale#
Rotation# = self.m10 * zn
xn = self.m10 * zp
xp = Rotation#-xn; xn = Rotation#+xn
yp = zp + zn; yn = zp - zn
Rotation# = self.m2 * zn
zn = self.m2 * zp
zp = Rotation#-zn; zn = Rotation#+zn
?IF DEFINED( gl_gbas )
glBegin( GL_TRIANGLE_STRIP )
IF self.lastnormal <> 2
glNormal3f( self.m2, 0, self.m10 )
self.lastnormal = 2
ENDIF
glTexCoord2f( self.t0x, self.t0y )
glVertex3f( x# - xp, y# + yp, z# + zp )
glTexCoord2f( self.t1x, self.t1y )
glVertex3f( x# + xn, y# - yn, z# - zn )
glTexCoord2f( self.t2x, self.t2y )
glVertex3f( x# - xn, y# + yn, z# + zn )
glTexCoord2f( self.t3x, self.t3y )
glVertex3f( x# + xp, y# - yp, z# - zp )
glEnd()
?ELSE
INLINE
glBegin( GL_TRIANGLE_STRIP );
if (this->lastnormal != 2) {
glNormal3f( this->m2, 0, this->m10 );
this->lastnormal = 2;
};
glTexCoord2f( this->t0x, this->t0y );
glVertex3f( x - xp, y + yp, z + zp );
glTexCoord2f( this->t1x, this->t1y );
glVertex3f( x + xn, y - yn, z - zn );
glTexCoord2f( this->t2x, this->t2y );
glVertex3f( x - xn, y + yn, z + zn );
glTexCoord2f( this->t3x, this->t3y );
glVertex3f( x + xp, y - yp, z - zp );
glEnd();
ENDINLINE
?ENDIF
ENDFUNCTION
// use this if you want to change texture coords
// its way faster to change texture coords instead of changing texture with X_SETTEXTURE
// it will affect all following draw()/draw2() calls, in all following loops!
FUNCTION SetTextureCoords: t0x#, t0y#, t1x#, t1y#, t2x#, t2y#, t3x#, t3y#
self.t0x = t0x; self.t0y = t0y
self.t1x = t1x; self.t1y = t1y
self.t2x = t2x; self.t2y = t2y
self.t3x = t3x; self.t3y = t3y
ENDFUNCTION
ENDTYPE
Test Program:
// --------------------------------- //
// Project: TSprite
// Start: Sunday, July 24, 2011
// Autor: Kanonet
// Last Update: April 20, 2012
SETSCREEN 800,600,0
SYSTEMPOINTER TRUE
ALLOWESCAPE FALSE
AUTOPAUSE FALSE
LIMITFPS -1
// number of sprites to draw:
LOCAL count%=1000
LOCAL root%=SQR(count)/2, line%, row%, fps, timer, mx, my=15, mz=-4, selected%=1
// texture
DRAWRECT 0,0, 16, 16, RGB(0,0,255)
DRAWRECT 12,0, 4,8, RGB(255,127,0)
DRAWRECT 0,12, 4,4, RGB(255,0,63)
DRAWLINE 0,0, 16,16, 0xffffff
DRAWLINE 0,16, 16,0, 0xffffff
GRABSPRITE 0, 0,0, 16,16
// sprite
LOCAL sprite AS TSprite
sprite.Init()
// mainloop
REPEAT
line=-root; row=-root
// mouse for camera control:
mx = mx + MOUSEAXIS(0)
my = my + MOUSEAXIS(1)
mz = mz + MOUSEAXIS(2)
IF KEY(27) // + more sprites
INC count
root=SQR(count)/2
ENDIF
IF KEY(53) AND count>1 // - less sprites
DEC count
root=SQR(count)/2
ENDIF
IF KEY(2) THEN selected=1
IF KEY(3) THEN selected=2
IF KEY(4) THEN selected=3
X_MAKE3D 0.1, 1000, 45
X_CAMERA my*COS(mx)*root*0.2,mz*2,my*SIN(mx)*root*0.2, 0,0,0
IF selected=1
FOR i=1 TO count
X_SPRITE 0, 0, line, row, 0.06
INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
ELSEIF selected=2
sprite.Start()
FOR i=1 TO count
X_SETTEXTURE 0, -1
sprite.Draw(0, line, row, 0.5)
INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ELSE
sprite.Start()
X_SETTEXTURE 0, -1
FOR i=1 TO count
sprite.Draw(0, line, row, 0.5)
INC row
IF row>root
row=-root
INC line
ENDIF
NEXT
sprite.Stop()
ENDIF
X_MAKE2D
ALPHAMODE 0.9
DRAWRECT 0,0,800,60,RGB(70,70,70)
PRINT "CAMERA CONTROL: MOVE MOUSE / MOUSE WHEEL | FPS: "+INTEGER(1000/(timer-fps)), 0,0
PRINT "SPRITES CURRENTLY: "+count+" | PRESS (+) FOR MORE SPRITES AND (-) FOR LESS", 0,15
PRINT "SELECT: (1) X_SPRITE | (2) TSPRITE | (3) TSPRITE WITH TEXTURE ORDERING", 0, 30
PRINT "SELECTED: "+selected, 0, 45
SHOWSCREEN
fps=timer
timer=GETTIMERALL()
UNTIL KEY(1)
END
Finally some test results (FPS), done on my T410s (see signature), which have to graphiccards (i can select one to use):
Intel HD Graphics - 1000 Sprites: 46 / 48 / 393
Intel HD Graphics - 2000 Sprites: 24 / 25 / 253
Intel HD Graphics - 3000 Sprites: 16 / 17 / 196
Intel HD Graphics - 4000 Sprites: 12 / 13 / 152
Intel HD Graphics - 5000 Sprites: 10 / 10 / 125
Intel HD Graphics - 7500 Sprites: 7 / 7 / 88
Intel HD Graphics - 10000 Sprites: 5 / 6 / 68
NVidia NVS 3100M - 1000 Sprites: 85 / 459 / 500 (cant do more)
NVidia NVS 3100M - 2000 Sprites: 50 / 256 / 500 (cant do more)
NVidia NVS 3100M - 3000 Sprites: 35 / 175 / 500 (cant do more)
NVidia NVS 3100M - 4000 Sprites: 27 / 134 / 500 (cant do more)
NVidia NVS 3100M - 5000 Sprites: 22 / 110 / 500 (cant do more)
NVidia NVS 3100M - 7500 Sprites: 15 / 74 / 480
NVidia NVS 3100M - 10000 Sprites: 11 / 56 / 370
I think here is the newes gl.gbas:
http://www.glbasic.com/forum/index.php?topic=7801.msg66675#msg66675 it can run without this, but if you want to use it, you need to uncomment "//?DEFINE gl_gbas 1"
You can find newest QSIN (QQSIN) here:
http://www.glbasic.com/forum/index.php?topic=6446.msg65027#msg65027 but i included it in this testprogram.

Would be really good, if someone could test it on mobile devices.
Now i want someone to create a decent particle engine with this.

Im pretty new to (directly) using OpenGL, which is hard cuz i dont know C.

So maybe there are better/faster ways to do this, so please point me at them. Any tips/ suggestions/ feedback are really welcome.

You always find the latest version on my website:
http://www.kanonet.de/downloads/libsprite