Page 1 of 1

DrawGLSprite

Posted: Thu Dec 13, 2018 10:40 pm
by ultimzeus
This is my first post.
After searching the forum and tested many GL codes, i have discovered how Sprites are handled in purebasic in Opengl sub.
So i wrote my own LoadGLSprite and DrawGLSprite procedures to handle more efficiently sprites.
The trick is that sprites are just textures witch are stored in GL mode by handles. these hundles can be binded by calling SpriteID(Spritenumber) :wink:

Features :
-Now we can display sprites with tint , transparency , rotation , scale , all and parts = in one procedure
-Notice that the same handle returned by load procedure can be used in default DisplaySprite procedure
-Works fine with Engine3D initialized

Works fine in PB 5.30 Windows 8, OpenGL subsysem
Please test other versions if you have time, and feedback

Code: Select all

Procedure.l LoadGLSprite(spname.s,mode.l)
  Protected sp1.l=LoadSprite(#PB_Any,spname,mode)
  glEnable_(#GL_TEXTURE_2D)
  StartDrawing(SpriteOutput(sp1))
  glBindTexture_(#GL_TEXTURE_2D, SpriteID(sp1))
If SpriteDepth(sp1)=32
  glTexImage2D_(#GL_TEXTURE_2D, 0, 4, SpriteWidth(sp1), SpriteHeight(sp1), 0, #GL_BGRA_EXT, #GL_UNSIGNED_BYTE, DrawingBuffer())
Else
  glTexImage2D_(#GL_TEXTURE_2D, 0, 3, SpriteWidth(sp1), SpriteHeight(sp1), 0, #GL_BGRA_EXT, #GL_UNSIGNED_BYTE, DrawingBuffer())
EndIf 
  glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_NEAREST)
  glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_NEAREST)
  glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_WRAP_S, #GL_CLAMP)
  glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_WRAP_T, #GL_CLAMP)
  StopDrawing()
ProcedureReturn sp1
EndProcedure

; a procedure to test dimensions
Procedure.l Cadrer(x.l,min.l,max.l)
  If x>=max:ProcedureReturn max:EndIf
  If x=<min:ProcedureReturn min:EndIf
  ProcedureReturn x 
EndProcedure

; x,y coordinates where to put sprite 
; xp,yp coordinates where to begin sprite part ; 
; wp,hp : width and height of sprite part ; 
; if part coordinates are set to 0,0,0,0 then all the sprite will be drawn
; sc is the scale of the sprite or its part
; rot is the rotation of the sprite or its part
; col is the tint (you can have RGB values)
; alp is the transparency (0=invisible ; 255 is full opaque) , it is practicle for fading effect

Procedure DrawGlSprite(tex.l,x.l,y.l,xp.l=0,yp.l=0,wp.l=0,hp.l=0,sc.f=1,rot.f=0,col.l=#White,alp.l=255)
  ;here we bind the preloaded sprite texture by calling spriteid(tex)
  glEnable_(#GL_TEXTURE_2D) :  glBindTexture_(#GL_TEXTURE_2D,SpriteID(tex))
  ; we get the width and height
  glGetTexLevelParameteriv_(#GL_TEXTURE_2D, 0, #GL_TEXTURE_WIDTH, @w)
  glGetTexLevelParameteriv_(#GL_TEXTURE_2D, 0, #GL_TEXTURE_HEIGHT, @h)
  
  xp=Cadrer(xp,0,w)
  yp=Cadrer(yp,0,h)
  wp=Cadrer(wp,0,w)
  hp=Cadrer(hp,0,h)
    
  If xp=0 And wp=0:wp=w:EndIf
  If yp=0 And hp=0:hp=h:EndIf
    
  sh.l=WindowHeight(0)
  sw.l=WindowWidth(0)
  ;setting envirenment 
  glEnable_(#GL_BLEND)
  glDepthFunc_(#GL_LEQUAL)                      
  glBlendFunc_(#GL_SRC_ALPHA, #GL_ONE_MINUS_SRC_ALPHA)
  
  glPopMatrix_()
  glMatrixMode_(#GL_PROJECTION) 
  glDisable_(#GL_DEPTH)
  glLoadIdentity_()
  gluPerspective_(58.1, WindowWidth(0)/WindowHeight(0)*0.75, 0, 60.0) 
  glPushMatrix_()
  
  ; apply the rotation and scale 
  glRotatef_(rot,0,0,1)
  glScalef_(sc,sc,1)
  glTranslatef_(CameraX(cam)-0.5,CameraY(cam)-0.5,CameraZ(cam)-0.9)
  Protected x1.f=x/sW
  Protected x2.f=(x+wp)/sW
  ;drawing the sprite or the part of it
  glBegin_(#GL_QUADS)
  glColor4f_(Red(col)/255,Green(col)/255,Blue(col)/255,alp/255)
  glTexCoord2f_(xp/w,(h-yp)/h) : glVertex2f_(x1, (sh-y)/sh)
  glTexCoord2f_((xp+wp)/w,(h-yp)/h) : glVertex2f_(x2,(sh-y)/sh)
  glTexCoord2f_((xp+wp)/w,(h-yp-hp)/h) : glVertex2f_(x2, (sh-y-hp)/sh)
  glTexCoord2f_(xp/w,(h-hp-yp)/h) : glVertex2f_(x1, (sh-y-hp)/sh)
  glEnd_()
  glPopMatrix_()
  glDisable_(#GL_TEXTURE_2D)
EndProcedure


exemple using it

Code: Select all

InitEngine3D()
OpenWindow(0, 270, 100, 800, 600, "Sprite OpenGL demo")
Add3DArchive(#PB_Compiler_Home + "", #PB_3DArchive_FileSystem)
Parse3DScripts()
InitSprite()
OpenWindowedScreen(WindowID(0), 0, 0, WindowWidth(0) , WindowHeight(0))

UsePNGImageDecoder(); use PNG images to hundle alphachannel and avoid transparent color handling
Global sp.l
sp=LoadGLSprite("SomeFile.png",#PB_Sprite_AlphaBlending) ; replace SomeFile.png by your own png file
cam.l=CreateCamera(#PB_Any,0,0,100,100)

repeat
  CameraBackColor(Cam,RGB(0,255,55))
  RenderWorld()
  DrawGlSprite(sp,450,60,0,0,150,150,1.1,0,RGB(255,0,0),150);draws a part of a sprite scaled , red tinted and semi transparent 
  FlipBuffers()
Until WaitWindowEvent() = #PB_Event_CloseWindow


Re: DrawGLSprite

Posted: Fri Dec 14, 2018 6:39 pm
by Fig
What are the advantages versus Purebasic native's sprites ? :?:

Re: DrawGLSprite

Posted: Fri Dec 14, 2018 10:25 pm
by ultimzeus
As i said the feastures:
- One procedure makes all
- The Tint feature now works better with opengl. native Purebasic procedure DisplayTransparentSprite does not work at all when mixing tinting and transparency.
- You can mix this procedure with my veryfast DrawRect procedure witch replaces the box procedure (wicth uses the very slow 2Ddrawing mode)

Try this

Code: Select all

Procedure DrawRect(x.l,y.l,w.l,h.l,Col.l)
  glEnable_(#GL_BLEND)
  glDepthFunc_(#GL_LEQUAL)                      
  glBlendFunc_(#GL_SRC_ALPHA, #GL_ONE_MINUS_SRC_ALPHA)
  glMatrixMode_(#GL_PROJECTION) 
  glLoadIdentity_() 
  gluPerspective_(58.1, WindowWidth(0)/WindowHeight(0)*0.75, 0, 60.0) 
  ;glMatrixMode_(#GL_MODELVIEW) 
  glPushMatrix_() 
  glTranslatef_(CameraX(cam)-0.5,CameraY(cam)-0.5,CameraZ(cam)-0.9)
  ;glRotatef_(30.0, 0.0, 0.0, 1.0); uncomment if you want rotation
  glBegin_(#GL_POLYGON)
  glColor4f_(Red(col)/255,Green(col)/255,Blue(col)/255,Alpha(col)/255)
    Protected x1.f=x/WindowWidth(0)
    Protected x2.f=(x+w)/WindowWidth(0)
    glVertex2f_(x1, (WindowHeight(0)-y)/WindowHeight(0))
    glVertex2f_(x2,(WindowHeight(0)-y)/WindowHeight(0))
    glVertex2f_(x2, (WindowHeight(0)-y-h)/WindowHeight(0))
    glVertex2f_(x1, (WindowHeight(0)-y-h)/WindowHeight(0))
 glEnd_() 
 glPopMatrix_() 
 glDisable_(#GL_TEXTURE_2D) 
 
EndProcedure

Re: DrawGLSprite

Posted: Thu Jan 10, 2019 2:09 pm
by Env
Tested as working on Linux...

I just want to extend a huge thanks for this as it allows us to finally tint sprites, which is a very underestimated feature, and it's beyond me why it hasn't been implemented natively yet.

Re: DrawGLSprite

Posted: Thu Jan 17, 2019 9:20 pm
by Olliv
@Env

Thank you for the feedback.

@UltimZeus

You are using native sprite functions to store texturing datas onto the graphic card. Could you compare executable file size if you use native image functions ?

Re: DrawGLSprite

Posted: Thu Jan 17, 2019 10:35 pm
by Bitblazer
Win7x64 - PureBasic 5.70 x86 LTS final - OpenGL subsystem

[ERROR] The specified #Camera is not initialised at

Code: Select all

  glTranslatef_(CameraX(cam)-0.5,CameraY(cam)-0.5,CameraZ(cam)-0.9)
Though this line

Code: Select all

cam.l=CreateCamera(#PB_Any,0,0,100,100)
returns a value.

Re: DrawGLSprite

Posted: Mon Jan 21, 2019 9:59 pm
by Olliv
Just insert Global on the start of the line cam.l = CreateCamera(...

Code: Select all

Global Cam.L = CreateCamera(... 

Re: DrawGLSprite

Posted: Tue Jan 22, 2019 3:17 am
by Bitblazer
Olliv wrote:Just insert Global on the start of the line cam.l = CreateCamera(...

Code: Select all

Global Cam.L = CreateCamera(... 
Thanks. Thats why i always use "enableexplicit()" in my own software :?