Module::Colored sprites in GLSL

Share your advanced PureBasic knowledge/code with the community.
sq4
User
User
Posts: 98
Joined: Wed Feb 26, 2014 3:16 pm
Contact:

Module::Colored sprites in GLSL

Post by sq4 »

Code says it all :wink:
(Tested in Win10)

Code: Select all

; *****************************************************************************
; Implementation of Colored Sprites and other stuff with GLSL in a PB  Module
;
; www.raxntrax.com, 2021 by SQ4
; *****************************************************************************
CompilerIf #PB_Compiler_OS = #PB_OS_Windows And Subsystem("OpenGL") = #False
  CompilerError "OpenGL subsystem needs to be set in compiler options!"
CompilerEndIf
DeclareModule GLSL
  Enumeration
    #GLSLType_Sprite
    #GLSLType_Program ;Why not (needs just another fragment shader)
  EndEnumeration
  Declare Open(WindowID, x,y,w,h)
  Declare Close()
  Declare StartRender(color=$0)
  Declare StopRender()
  Declare.i LoadObject(Type, File.s)
  Declare.i CatchObject(Type, Buffer.i,w,h)
  Declare DrawObject(Object, x,y,w,h,angle.f,color=$ffffffff)
EndDeclareModule
Module GLSL

#GL_COLOR_BUFFER_BIT = $00004000
#GL_DEPTH_BUFFER_BIT = $00000100
#GL_ARRAY_BUFFER = $8892
#GL_ELEMENT_ARRAY_BUFFER = $8893
#GL_MODELVIEW = $1700
#GL_PROJECTION = $1701
#GL_SMOOTH = $1D01
#GL_DEPTH_TEST = $0B71
#GL_CULL_FACE = $0B44
#GL_STATIC_DRAW = $88E4
#GL_VERTEX_ARRAY = $8074
#GL_FLOAT = $1406
#GL_TRIANGLES = $0004
#GL_UNSIGNED_BYTE = $1401
#GL_UNSIGNED_SHORT = $1403
#GL_UNSIGNED_INT = $1405
#GL_ARRAY_BUFFER = $8892
#GL_STATIC_DRAW = $88E4
#GL_VERTEX_SHADER = $8B31
#GL_FRAGMENT_SHADER = $8B30
#GL_TEXTURE0 = $84C0
#GL_TEXTURE1 = $84C1
#GL_BGR = $80E0
#GL_BGRA = $80E1
#GL_RGB = $1907
#GL_RGBA = $1908

Prototype glGenBuffers( n.i, *buffers)
Prototype glBindBuffer( target.l, buffer.i)
Prototype glBufferData ( target.l, size.i, *Data_, usage.l)
Prototype glBufferSubData ( target.l, offset.i, size.i, *Data_)
Prototype glGenVertexArrays (n.i, *arrays)
Prototype glBindVertexArray(n.i)
Prototype glEnableVertexAttribArray ( index.i )
Prototype glVertexAttribPointer ( index.i, size.i, type.l, normalized.b, stride.i, *pointer )
Prototype glDrawArrays ( mode.l, first.i, count.i )
Prototype glIndexPointer ( enum.i, stride.i, *length )
Prototype glDeleteBuffers ( n.i, *buffers)
Prototype glDeleteVertexArrays ( n.i, *buffers)
Prototype glDisableVertexAttribArray(index.i)
Prototype glMapBuffer(Target.i, Access.i)
Prototype glUnmapBuffer(Target.i)
Prototype glActiveTexture(Texture.l)
Prototype glUniformMatrix4fv(location.i, count.i, transpose.b, *value)
Prototype glCreateShader(type.l)
Prototype glCreateProgram()
Prototype glCompileShader(shader.l)
Prototype glDeleteShader(ShaderObj.i)
Prototype glLinkProgram(shader.l)
Prototype glUseProgram(shader.l)
Prototype glAttachShader(Program.l, shader.l)
Prototype glShaderSource(shader.l, numOfStrings.l, *strings, *lenOfStrings) :
Prototype glGetUniformLocation(Program.i, name.p-ascii)
Prototype glUniform1i(location.i, v0.i)
Prototype glUniform2i(location.i, v0.i, v1.i)
Prototype glUniform1f(location.i, v0.f)
Prototype glUniform2f(location.i, v0.f, v1.f)
Prototype glUniform3f(location.i, v0.f, v1.f, v2.f)
Prototype glUniform4f(location.i, v0.f, v1.f, v2.f, v3.f)
Prototype glGetShaderInfoLog(shader.i, bufSize.l, *length_l, *infoLog)  

Structure _2DPoint
  x.f
  y.f
EndStructure
Structure _2DTex
  x.f
  y.f
EndStructure
Structure myTexVertex
  Pos._2DPoint
  Tex._2DTex
EndStructure
Structure Tindex
  a.l
  b.l
  c.l
  d.l
EndStructure

Structure Object
  Type.i
  Shader.i ;Object specific 
  Texture.i
  Array uModelScale.f(3,3)
  Array uRotate.f(3,3)
  Array uWorldScale.f(3,3)
  Array uTranslate.f(3,3)  
EndStructure
Structure GLSL
  W.i
  H.i
  Shader.i ;Default Shader
  Array Vertex.myTexVertex(3)
  List Objects.Object()
  glGenBuffers.glGenBuffers
  glBindBuffer.glBindBuffer
  glBufferData.glBufferData
  glBufferSubData.glBufferSubData
  glGenVertexArrays.glGenVertexArrays
  glBindVertexArray.glBindVertexArray
  glEnableVertexAttribArray.glEnableVertexAttribArray
  glVertexAttribPointer.glVertexAttribPointer
  glDrawArrays.glDrawArrays
  glIndexPointer.glIndexPointer
  glDeleteBuffers.glDeleteBuffers
  glDeleteVertexArrays.glDeleteVertexArrays
  glDisableVertexAttribArray.glDisableVertexAttribArray
  glMapBuffer.glMapBuffer
  glUnmapBuffer.glUnmapBuffer
  glActiveTexture.glActiveTexture
  glUniformMatrix4fv.glUniformMatrix4fv
  glCreateShader.glCreateShader
  glCreateProgram.glCreateProgram
  glCompileShader.glCompileShader
  glDeleteShader.glDeleteShader
  glLinkProgram.glLinkProgram
  glUseProgram.glUseProgram
  glAttachShader.glAttachShader
  glShaderSource.glShaderSource
  glGetUniformLocation.glGetUniformLocation
  glUniform1i.glUniform1i
  glUniform2i.glUniform2i
  glUniform1f.glUniform1f
  glUniform2f.glUniform2f
  glUniform3f.glUniform3f
  glUniform4f.glUniform4f
  glGetShaderInfoLog.glGetShaderInfoLog
EndStructure
  

UseJPEGImageDecoder()
UsePNGImageDecoder()
Global GLSL.GLSL

Procedure Open(WindowID, x,y,w,h)
If InitSprite() And OpenWindowedScreen(WindowID,x,y,w,h)

;InitSprite is not necessary, but you have to disable debugger
;DisableDebugger
;If OpenWindowedScreen(WindowID,x,y,w,h)

  GLSL\W=w
  GLSL\H=h
  GLSL\glGenBuffers = wglGetProcAddress_("glGenBuffers")
  GLSL\glBindBuffer = wglGetProcAddress_("glBindBuffer")
  GLSL\glBufferData = wglGetProcAddress_("glBufferData")
  GLSL\glBufferSubData = wglGetProcAddress_("glBufferSubData")
  GLSL\glGenVertexArrays = wglGetProcAddress_("glGenVertexArrays")
  GLSL\glBindVertexArray = wglGetProcAddress_("glBindVertexArray")
  GLSL\glEnableVertexAttribArray = wglGetProcAddress_("glEnableVertexAttribArray")
  GLSL\glVertexAttribPointer = wglGetProcAddress_("glVertexAttribPointer")
  GLSL\glDrawArrays = wglGetProcAddress_("glDrawArrays")
  GLSL\glIndexPointer = wglGetProcAddress_("glIndexPointer")
  GLSL\glDeleteBuffers = wglGetProcAddress_("glDeleteBuffers")
  GLSL\glDeleteVertexArrays = wglGetProcAddress_("glDeleteVertexArrays")
  GLSL\glDisableVertexAttribArray = wglGetProcAddress_("glDisableVertexAttribArray")
  GLSL\glMapBuffer = wglGetProcAddress_("glMapBuffer")
  GLSL\glUnmapBuffer = wglGetProcAddress_("glUnmapBuffer")
  GLSL\glActiveTexture = wglGetProcAddress_("glActiveTexture")
  GLSL\glUniformMatrix4fv=wglGetProcAddress_("glUniformMatrix4fv")
  GLSL\glCreateShader = wglGetProcAddress_("glCreateShader")
  GLSL\glCreateProgram = wglGetProcAddress_("glCreateProgram")
  GLSL\glCompileShader = wglGetProcAddress_("glCompileShader")
  GLSL\glDeleteShader = wglGetProcAddress_("glDeleteShader")
  GLSL\glLinkProgram = wglGetProcAddress_("glLinkProgram")
  GLSL\glUseProgram = wglGetProcAddress_("glUseProgram")
  GLSL\glAttachShader = wglGetProcAddress_("glAttachShader")
  GLSL\glShaderSource = wglGetProcAddress_("glShaderSource")
  GLSL\glGetUniformLocation = wglGetProcAddress_("glGetUniformLocation")
  GLSL\glUniform1i = wglGetProcAddress_("glUniform1i")
  GLSL\glUniform2i = wglGetProcAddress_("glUniform2i")
  GLSL\glUniform1f = wglGetProcAddress_("glUniform1f")
  GLSL\glUniform2f = wglGetProcAddress_("glUniform2f")
  GLSL\glUniform3f = wglGetProcAddress_("glUniform3f")
  GLSL\glUniform4f = wglGetProcAddress_("glUniform4f")
  GLSL\glGetShaderInfoLog = wglGetProcAddress_("glGetShaderInfoLog") 
  
  ; Vertexes in WorldSpace
  ; top left
  GLSL\Vertex(3)\Pos\x = -1    : GLSL\Vertex(3)\Pos\y = 1
  GLSL\Vertex(3)\Tex\x = 0.0   : GLSL\Vertex(3)\Tex\y = 1.0  
  ; top right
  GLSL\Vertex(2)\Pos\x = 1     : GLSL\Vertex(2)\Pos\y = 1
  GLSL\Vertex(2)\Tex\x = 1.0   : GLSL\Vertex(2)\Tex\y = 1.0  
  ; bottom left
  GLSL\Vertex(0)\Pos\x = -1    : GLSL\Vertex(0)\Pos\y = -1
  GLSL\Vertex(0)\Tex\x = 0.0   : GLSL\Vertex(0)\Tex\y = 0.0  
  ; bottom right
  GLSL\Vertex(1)\Pos\x = 1     : GLSL\Vertex(1)\Pos\y = -1
  GLSL\Vertex(1)\Tex\x = 1.0   : GLSL\Vertex(1)\Tex\y = 0.0
  
  ;Clockwise processing of vertexes
  Dim Index.Tindex(0)
  Index(0)\a = 0  : Index(0)\b = 1  : Index(0)\c = 2  : Index(0)\d = 3
  
  GLSL\glGenVertexArrays(1, @vao)   
  GLSL\glGenBuffers(1, @vbo)  
  GLSL\glGenBuffers(1, @ebo)       
  
  GLSL\glBindVertexArray(vao)
  GLSL\glBindBuffer(#GL_ARRAY_BUFFER, vbo)
  GLSL\glBufferData(#GL_ARRAY_BUFFER,SizeOf(myTexVertex) * (ArraySize(GLSL\Vertex())+1),@GLSL\Vertex(), #GL_STATIC_DRAW)   
  
  GLSL\glVertexAttribPointer(0, SizeOf(_2DPoint)/SizeOf(float), #GL_FLOAT, #GL_FALSE, SizeOf(myTexVertex), 0)
  GLSL\glEnableVertexAttribArray(0)     
  
  GLSL\glVertexAttribPointer(1, SizeOf(_2DTex)/SizeOf(float), #GL_FLOAT, #GL_FALSE, SizeOf(myTexVertex), OffsetOf(myTexVertex\Tex))
  GLSL\glEnableVertexAttribArray(1);
  
  GLSL\glBindBuffer(#GL_ELEMENT_ARRAY_BUFFER, ebo)
  GLSL\glBufferData(#GL_ELEMENT_ARRAY_BUFFER, 16*(ArraySize(Index())+1), @Index(0), #GL_STATIC_DRAW)
  
  VS$ = "#version 330 core"+#CRLF$
  VS$ + "layout(location = 0) in vec2 aPos;"+#CRLF$             ; the position variable has attribute position 0
  VS$ + "layout(location = 1) in vec2 aTexCoord;"+#CRLF$        ; the color variable has attribute position 1
  VS$ + "out vec2 TexCoord;"+#CRLF$
  VS$ + "uniform mat4 uModelScale;"+#CRLF$
  VS$ + "uniform mat4 uRotate;"+#CRLF$
  VS$ + "uniform mat4 uWorldScale;"+#CRLF$
  VS$ + "uniform mat4 uTranslate;"+#CRLF$
  VS$ + "void main() {"+#CRLF$
  VS$ + "vec4 Position = vec4(aPos, 1.0, 1.0);"+#CRLF$
  
  VS$ + "Position = uModelScale*Position;"+#CRLF$
  VS$ + "Position = uRotate*Position;"+#CRLF$  
  VS$ + "Position = uWorldScale*Position;"+#CRLF$  
  VS$ + "Position = uTranslate*Position;"+#CRLF$
  
  VS$ + "gl_Position = Position;"+#CRLF$
  VS$ + "TexCoord = aTexCoord;"+#CRLF$
  VS$ + "}"

  FS$ = "#version 330 core"+#CRLF$
  FS$ + "out vec4 FragColor;"+#CRLF$
  FS$ + "in vec2 TexCoord;"+#CRLF$
  FS$ + "uniform vec4 uColor;"+#CRLF$
  FS$ + "uniform sampler2D uImage;"+#CRLF$
  
  FS$ + "void main()"+#CRLF$
  FS$ + "{"+#CRLF$
  FS$ + "   FragColor = texture(uImage, TexCoord)*uColor;"+#CRLF$
  FS$ + "}"+#CRLF$
  
  *vbuff = Ascii(VS$)
  *fbuff = Ascii(FS$)

  vs = GLSL\glCreateShader(#GL_VERTEX_SHADER);
  GLSL\glShaderSource(vs, 1, @*vbuff, #Null) ;
  GLSL\glCompileShader(vs)

  buffer = AllocateMemory(512)
  GLSL\glGetShaderInfoLog(vs,512,#Null,buffer)
  Log$=PeekS(buffer,512,#PB_Ascii)
  If Log$:Debug Log$:EndIf
  FreeMemory(buffer)

  fs = GLSL\glCreateShader(#GL_FRAGMENT_SHADER);
  GLSL\glShaderSource(fs, 1, @*fbuff, #Null);
  GLSL\glCompileShader(fs) 

  buffer = AllocateMemory(512)
  GLSL\glGetShaderInfoLog(vs,512,#Null,buffer)
  Log$=PeekS(buffer,512,#PB_Ascii)
  If Log$:Debug Log$:EndIf
  FreeMemory(buffer)

  GLSL\Shader = GLSL\glCreateProgram();
  GLSL\glAttachShader(GLSL\Shader, vs)
  GLSL\glAttachShader(GLSL\Shader, fs)
  GLSL\glLinkProgram(GLSL\Shader)     
  
  GLSL\glDeleteShader(vs)
  GLSL\glDeleteShader(fs)
  
EndIf
EndProcedure
Procedure Close()
EndProcedure
Procedure StartRender(rgba=$0)
  glClearColor_(Red(rgba)/255, Green(rgba)/255, Blue(rgba)/255, Alpha(rgba)/255)
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
EndProcedure
Procedure StopRender()
  ;Use disabledebugger when not using InitSprite()
  FlipBuffers()
EndProcedure
Procedure.i LoadObject(Type, File.s)
  If FileSize(File)>0
    Select Type
    Case #GLSLType_Sprite
      Img=LoadImage(#PB_Any,File)
      If IsImage(Img)   
        ImgDepth=ImageDepth(Img)
        If ImgDepth<>32
          Img2=CreateImage(#PB_Any,ImageWidth(Img), ImageHeight(Img),32)
          StartDrawing(ImageOutput(Img2))
          DrawImage(ImageID(Img),0,0)
          StopDrawing()
          FreeImage(Img)
          Img=Img2
        EndIf

        StartDrawing(ImageOutput(Img))
          mem=DrawingBuffer()
          size=DrawingBufferPitch()* ImageHeight(Img)
          *Buffer=AllocateMemory(size)
          CopyMemory(mem, *Buffer, size)
        StopDrawing()
        RetVal=CatchObject(Type, *Buffer, ImageWidth(Img), ImageHeight(Img))
        FreeMemory(*Buffer)
          
      EndIf
    EndSelect
  EndIf
  ProcedureReturn RetVal
EndProcedure
Procedure.i CatchObject(Type, *Buffer, w, h)
  Select Type
  Case #GLSLType_Sprite
    glGenTextures_(1, @texture)
    glBindTexture_(#GL_TEXTURE_2D, texture)
    glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_WRAP_S, #GL_CLAMP_TO_EDGE)
    glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_WRAP_T, #GL_CLAMP_TO_EDGE)
    glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_LINEAR)
    glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_LINEAR)
    glTexImage2D_(#GL_TEXTURE_2D, 0, 4, w, h, 0, #GL_BGRA_EXT, #GL_UNSIGNED_BYTE, *Buffer)
  
    AddElement(GLSL\Objects())
    GLSL\Objects()\Texture=Texture
        
    RetVal=ListIndex(GLSL\Objects())
  EndSelect
  ProcedureReturn RetVal
EndProcedure
Procedure DrawObject(Nr,x,y,w,h,Angle.f,rgba=$ffffffff)

  If SelectElement(GLSL\Objects(), Nr)
  
    glEnable_(#GL_BLEND)
    glBlendFunc_(#GL_SRC_ALPHA, #GL_ONE_MINUS_SRC_ALPHA)
  
    GLSL\glUseProgram(GLSL\Shader)

    GLSL\glActiveTexture(#GL_TEXTURE0);
    glBindTexture_(#GL_TEXTURE_2D, GLSL\Objects()\Texture)

    myCos.f=Cos(Radian(360-Angle))
    mySin.f=Sin(Radian(360-Angle))
    
    Aspect_X.f=(w/h)
    Scale.f=h/GLSL\H
    
    Sprite_X.f=x+(w/2)
    Sprite_Y.f=y+(h/2)
  
    fLeft.f=((Sprite_X/GLSL\W)-0.5)*2
    fTop.f=((Sprite_Y/GLSL\H)-0.5)*-2
        
    With GLSL\Objects()
      \uModelScale(0,0)=Aspect_X*Scale : \uModelScale(1,0)=0 : \uModelScale(2,0)=0 : \uModelScale(3,0)=0
      \uModelScale(0,1)=0 : \uModelScale(1,1)=Scale : \uModelScale(2,1)=0 : \uModelScale(3,1)=0
      \uModelScale(0,2)=0 : \uModelScale(1,2)=0 : \uModelScale(2,2)=1 : \uModelScale(3,2)=0
      \uModelScale(0,3)=0 : \uModelScale(1,3)=0 : \uModelScale(2,3)=0 : \uModelScale(3,3)=1
    
      \uRotate(0,0)=myCos : \uRotate(1,0)=-mySin : \uRotate(2,0)=0 : \uRotate(3,0)=0
      \uRotate(0,1)=mySin : \uRotate(1,1)=myCos : \uRotate(2,1)=0 : \uRotate(3,1)=0
      \uRotate(0,2)=0 : \uRotate(1,2)=0 : \uRotate(2,2)=1 : \uRotate(3,2)=0
      \uRotate(0,3)=0 : \uRotate(1,3)=0 : \uRotate(2,3)=0 : \uRotate(3,3)=1
    
      \uWorldScale(0,0)=GLSL\H/GLSL\W : \uWorldScale(1,0)=0 : \uWorldScale(2,0)=0 : \uWorldScale(3,0)=0
      \uWorldScale(0,1)=0 : \uWorldScale(1,1)=1 : \uWorldScale(2,1)=0 : \uWorldScale(3,1)=0
      \uWorldScale(0,2)=0 : \uWorldScale(1,2)=0 : \uWorldScale(2,2)=1 : \uWorldScale(3,2)=0
      \uWorldScale(0,3)=0 : \uWorldScale(1,3)=0 : \uWorldScale(2,3)=0 : \uWorldScale(3,3)=1
    
      \uTranslate(0,0)=1 : \uTranslate(1,0)=0 : \uTranslate(2,0)=0 : \uTranslate(3,0)=fLeft
      \uTranslate(0,1)=0 : \uTranslate(1,1)=1 : \uTranslate(2,1)=0 : \uTranslate(3,1)=fTop
      \uTranslate(0,2)=0 : \uTranslate(1,2)=0 : \uTranslate(2,2)=1 : \uTranslate(3,2)=0
      \uTranslate(0,3)=0 : \uTranslate(1,3)=0 : \uTranslate(2,3)=0 : \uTranslate(3,3)=1
    EndWith
  
    GLSL\glUniformMatrix4fv(GLSL\glGetUniformLocation(GLSL\Shader, "uModelScale"), 1, #GL_FALSE, @GLSL\Objects()\uModelScale());
    GLSL\glUniformMatrix4fv(GLSL\glGetUniformLocation(GLSL\Shader, "uRotate"), 1, #GL_FALSE, @GLSL\Objects()\uRotate());
    GLSL\glUniformMatrix4fv(GLSL\glGetUniformLocation(GLSL\Shader, "uWorldScale"), 1, #GL_FALSE, @GLSL\Objects()\uWorldScale());
    GLSL\glUniformMatrix4fv(GLSL\glGetUniformLocation(GLSL\Shader, "uTranslate"), 1, #GL_FALSE, @GLSL\Objects()\uTranslate());
    GLSL\glUniform4f(GLSL\glGetUniformLocation(GLSL\Shader, "uColor"), Red(rgba)/255, Green(rgba)/255, Blue(rgba)/255, Alpha(rgba)/255)
    glDrawElements_(#GL_QUADS, 4, #GL_UNSIGNED_INT, 0 )  
  
    glDisable_(#GL_BLEND)
    GLSL\glUseProgram(0)
          
  EndIf
EndProcedure
EndModule
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
OpenWindow(0, 0, 0, 800, 600, "GLSL sprites in WindowedScreen")

GLSL::Open(WindowID(0),100,50,600,500)

#ImagePath = #PB_Compiler_Home + "examples/3d/Data/Textures/"

Object1=GLSL::LoadObject(GLSL::#GLSLType_Sprite, #ImagePath+"ValetCoeur.jpg")
Object2=GLSL::LoadObject(GLSL::#GLSLType_Sprite, #ImagePath+"ValetCoeur.jpg")

Repeat
 Event = WindowEvent()
  
  GLSL::StartRender(RGBA(40,0,0,255))        

  GLSL::DrawObject(Object1, 0,50,300,400,Angle)
  GLSL::DrawObject(Object2, 300,50,300,400,-Angle, RGBA(255,128,0,128))
  
  Angle+1
  Angle%360
  
  GLSL::StopRender()

Until Event = #PB_Event_CloseWindow

GLSL::Close()
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: Module::Colored sprites in GLSL

Post by Kwai chang caine »

Very nice, works great here :D
Thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
Post Reply