Lib Screen (Sprite) (PB 6.10)
Posted: Sun May 05, 2024 3:07 pm
[EDIT 05/17/2024] some shader corrections
[EDIT 05/18/2024] x86 corrections
[EDIT 05/23/2024] Linux corrections
hi coders,
I've made a small lib to replace the sprite lib
- shader management (with integrated editor, real-time modifications)
- light management
- camera management (modifies position, zoom and rotation of the entire scene)
- ability to define sprite origin point (zoom and rotation are centered on this point)
- ability to define sprite UV coordinates
- text display (fast), brush capability
(no collision management at present)
use is a little different, notably sprite creation from images (cf demo)
examples of use are at the end of the program (from line 725).
concerning shaders:
the “new” shader (comobox at the top right of the editor) contains the list of “varying” parameters sent by the vertex shader and the list of global (uniform) parameters.)
to create a new shader:
in the editor, choose a shader as a model (combobox), click on “save clipboard” and copy it into your code :
SHnew=shaderCreate(-1,"#version 130 ....
to use it:
mysprite=S_CreateSprite(-1,SHnew,image)
(replace shader name as you want)
you'll find a bit of documentation in the code, the smart ones should be able to work it out, for all the others
, I'm waiting for your questions
if anyone's interested, I'm thinking of making a version that's more faithful to what sprites really are
in PB, sprites are more or less an image that you redraw with each frame
I'm thinking of doing something equivalent to “entities” in 3D (no more DisplaySprite)
this will enable more consistent collision management, with the possibility of sorting by depth (for isometric 3d games in particular)
[EDIT 05/18/2024] x86 corrections
[EDIT 05/23/2024] Linux corrections
hi coders,
I've made a small lib to replace the sprite lib
- shader management (with integrated editor, real-time modifications)
- light management
- camera management (modifies position, zoom and rotation of the entire scene)
- ability to define sprite origin point (zoom and rotation are centered on this point)
- ability to define sprite UV coordinates
- text display (fast), brush capability
(no collision management at present)
use is a little different, notably sprite creation from images (cf demo)
examples of use are at the end of the program (from line 725).
concerning shaders:
the “new” shader (comobox at the top right of the editor) contains the list of “varying” parameters sent by the vertex shader and the list of global (uniform) parameters.)
to create a new shader:
in the editor, choose a shader as a model (combobox), click on “save clipboard” and copy it into your code :
SHnew=shaderCreate(-1,"#version 130 ....
to use it:
mysprite=S_CreateSprite(-1,SHnew,image)
(replace shader name as you want)
you'll find a bit of documentation in the code, the smart ones should be able to work it out, for all the others

if anyone's interested, I'm thinking of making a version that's more faithful to what sprites really are
in PB, sprites are more or less an image that you redraw with each frame
I'm thinking of doing something equivalent to “entities” in 3D (no more DisplaySprite)
this will enable more consistent collision management, with the possibility of sorting by depth (for isometric 3d games in particular)
Code: Select all
;=======================================================
; Lib screen (Sprite) - pf Shadoko -2024
;=======================================================
EnableExplicit
InitSprite():OpenWindow(0,0,0,10,10,""):OpenWindowedScreen(WindowID(0),0,0,10,10):CloseWindow(0);init opengl to add functions
#PB_Shader_Vector2=2
#PB_Shader_color=10
#GL_TEXTURE0=$84c0
#GL_VERTEX_SHADER = $8B31
#GL_FRAGMENT_SHADER = $8B30
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
ImportC "-framework OpenGL"
glActiveTexture(type.l) As "_glActiveTexture"
glCreateShader(type.l) As "_glCreateShader"
glCreateProgram() As "_glCreateProgram"
glDeleteProgram(Program.l) As "_glDeleteProgram"
glDeleteShader(shader.l) As "_glDeleteShader"
glCompileShader(shader.l) As "_glCompileShader"
glLinkProgram(shader.l) As "_glLinkProgram"
glUseProgram(shader.l) As "_glUseProgram"
glAttachShader(Program.l, shader.l) As "_glAttachShader"
glShaderSource(shader.l, numOfStrings.l, *strings, *lenOfStrings) As "_glShaderSource"
glGetUniformLocation(Program, name.p-ascii) As "_glGetUniformLocation"
glUniform1i(location, v0) As "_glUniform1i"
glUniform2i(location, v0, v1) As "_glUniform2i"
glUniform1f(location, v0.f) As "_glUniform1f"
glUniform1d(location, v0.d) As "_glUniform1d"
glUniform2d(location, v0.d, v1.d) As "_glUniform2d"
glUniform2f(location, v0.f, v1.f) As "_glUniform2f"
glUniform3f(location, v0.f, v1.f, v2.f) As "_glUniform3f"
glUniform4f(location, v0.f, v1.f, v2.f, v3.f) As "_glUniform4f"
glGetShaderInfoLog(shader, bufSize.l, *length_l, *infoLog) As "_glGetShaderInfoLog"
EndImport
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
; =================== Please choose your libGL.so folder ===================
;ImportC "/usr/lib/x86_64-linux-gnu/libGL.so"
;ImportC "/usr/lib/libGL.so"
ImportC "/usr/lib64/libGL.so"
glActiveTexture(type.l)
glCreateShader(type.l)
glCreateProgram()
glDeleteProgram(Program.l)
glDeleteShader(shader.l)
glCompileShader(shader.l)
glLinkProgram(shader.l)
glUseProgram(shader.l)
glAttachShader(Program.l, shader.l)
glShaderSource(shader.l, numOfStrings.l, *strings, *lenOfStrings) :
glGetUniformLocation(Program, name.p-ascii)
glUniform1i(location, v0)
glUniform2i(location, v0, v1)
glUniform1d(location, v0.d)
glUniform2d(location, v0.d, v1.d)
glUniform1f(location, v0.f)
glUniform2f(location, v0.f, v1.f)
glUniform3f(location, v0.f, v1.f, v2.f)
glUniform4f(location, v0.f, v1.f, v2.f, v3.f)
glGetShaderInfoLog(shader, bufSize.l, *length_l, *infoLog)
EndImport
CompilerElseIf #PB_Compiler_OS = #PB_OS_Windows
Macro QUOTE:"
EndMacro
Macro _ :,:EndMacro
Macro mPrototype (nom,params=)
Prototype nom(params)
Global nom.nom=wglGetProcAddress_(QUOTE#nom#QUOTE)
EndMacro
mPrototype (glActiveTexture,type.l)
mPrototype (glCreateShader,type.l)
mPrototype (glCreateProgram)
mPrototype (glDeleteProgram,Program.l)
mPrototype (glDeleteShader,shader.l)
mPrototype (glCompileShader,shader.l)
mPrototype (glLinkProgram,shader.l)
mPrototype (glUseProgram,shader.l)
mPrototype (glAttachShader,Program.l _ shader.l)
mPrototype (glShaderSource,shader.l _ numOfStrings.l _ *strings _ *lenOfStrings)
mPrototype (glGetUniformLocation,Program _ name.p-ascii)
mPrototype (glUniform1i,location _ v0)
mPrototype (glUniform2i,location _ v0 _ v1)
mPrototype (glUniform1d,location _ v0.d)
mPrototype (glUniform2d,location _ v0.d _ v1.d)
mPrototype (glUniform1f,location _ v0.f)
mPrototype (glUniform2f,location _ v0.f _ v1.f)
mPrototype (glUniform3f,location _ v0.f _ v1.f _ v2.f)
mPrototype (glUniform4f,location _ v0.f _ v1.f _ v2.f _ v3.f)
mPrototype (glGetShaderInfoLog,shader _ bufSize.l _ *lengthl _ *infoLog)
CompilerEndIf
;============================================================================================ Sprite internal
Structure f2
x.f
y.f
EndStructure
Structure sShaderinfo
num.i ;shader num
name.s
pg.i ;shader program
vcode.s
fcode.s
Map uloc.i() ;uniform location
EndStructure
Structure sparam
nom.s
type.b
v0.d
v1.f
v2.f
v3.f
EndStructure
Structure sSpriteinfo
num.i ;sprite num
sh.sShaderinfo ;shader program
List tx.i() ;texture num
Map param.sparam()
Tdx.w:Tdy.w
dx.w:dy.w
x1.f:y1.f:u1.f:v1.f
x2.f:y2.f:u2.f:v2.f
x3.f:y3.f:u3.f:v3.f
x4.f:y4.f:u4.f:v4.f
zx.f:zy.f
ag.f
xo.f:yo.f
EndStructure
Global s_screendx,s_screendy,s_screendx2,s_screendy2
Global Shadermessage.s,codevertex.s, SHvertex
Global.f glcamx,glcamy,glcamzoom=1,glcamrot,glcami=1,glcamj
Global.f glligthx,glligthy,glligthz,glligthdist,glligthcolor.l=0,glambiantcolor.l=$ffffffff
Global NewMap SpriteInfo.sSpriteinfo()
Global NewMap ShaderInfo.sShaderinfo()
Procedure ImageToGLTextures(image,free=0)
Protected TextureID,w,h,rgb,rgba
If #PB_Compiler_OS = #PB_OS_Windows:rgb=#GL_BGR_EXT:rgba=#GL_BGRA_EXT:Else:rgb=#GL_RGB:rgba=#GL_RGBA:EndIf
StartDrawing(ImageOutput(image))
glGenTextures_(1, @TextureID)
glBindTexture_(#GL_TEXTURE_2D, TextureID)
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_LINEAR)
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_LINEAR)
W = OutputWidth() : H = OutputHeight()
;glPixelStorei_(#GL_PACK_ROW_LENGTH,DrawingBufferPitch())
Select OutputDepth()
Case 24:glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGB, W, H, 0, rgb, #GL_UNSIGNED_BYTE, DrawingBuffer());
Case 32:glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGBA, W, H, 0, rgba, #GL_UNSIGNED_BYTE, DrawingBuffer());
EndSelect
StopDrawing()
If free:FreeImage(image):EndIf
ProcedureReturn TextureID
EndProcedure
Procedure Spriteverif(num)
If FindMapElement(SpriteInfo(),""+num)=0:MessageRequester("S_ Erreur","Sprite "+num+" does not exist"):CallDebugger:EndIf
EndProcedure
Procedure spritecoord(num)
Protected.f co,si,xs,ys,xx,yy,zxo,zyo
Macro rot(x,y,xs,ys)
xx=x-zxo
yy=y-zyo
xs= xx*co+yy*si
ys=-xx*si+yy*co
EndMacro
With SpriteInfo(""+num)
co=Cos(\ag):si=Sin(\ag)
zxo=\xo*\zx
zyo=\yo*\zy
rot(0 ,0 ,\x1,\y1)
rot(\dx,0 ,\x2,\y2)
rot(\dx,\dy,\x3,\y3)
rot(0 ,\dy,\x4,\y4)
EndWith
EndProcedure
Procedure screenpos(*sx.float,*sy.float)
Protected.f xx,yy
xx=*sx\f-glcamx-s_screendx2
yy=*sy\f-glcamy-s_screendy2
*sx\f= (xx*glcami+yy*glcamj+s_screendx2)
*sy\f=(-xx*glcamj+yy*glcami+s_screendy2)
EndProcedure
Procedure shaderuniform(*sh.sShaderinfo,nom.s,type,v0.d,v1.f=0,v2.f=0,v3.f=0)
If FindMapElement(*sh\uloc(),nom)
Select type
Case #PB_Shader_Integer :glUniform1i(*sh\uloc(),v0)
Case #PB_Shader_Float :glUniform1f(*sh\uloc(),v0)
Case #PB_Shader_Vector2 :glUniform2f(*sh\uloc(),v0,v1)
Case #PB_Shader_Vector3 :glUniform3f(*sh\uloc(),v0,v1,v2)
Case #PB_Shader_Vector4 :glUniform4f(*sh\uloc(),v0,v1,v2,v3)
Case #PB_Shader_color :Protected c.q=v0:glUniform4f(*sh\uloc(),Red(c)/255,Green(c)/255,Blue(c)/255,Alpha(c)/255)
EndSelect
EndIf
EndProcedure
;============================================================================================ Sprite public
Enumeration S_unit
#s_unit_Pixel=0
#s_unit_UV=1
EndEnumeration
Enumeration s_BlendingMode
#s_BlendingMode_alphablend
#s_BlendingMode_add
#s_BlendingMode_custom
EndEnumeration
Enumeration s_shader2D
#SHoverlay=1000
#SHdefault
#SHblend
#SHlight
#SHbump
#SHflame
#SHwater
#SHplasma
#SHnew
EndEnumeration
Procedure.s supspace(l.s)
Protected i
Protected.s ll,ac,c
l=ReplaceString(l,#TAB$," ")
l=ReplaceString(l,#LF$," ")
l=ReplaceString(l,#CR$," ")
i=0:While i<Len(l)
Repeat
i+1
ac=c:c=Mid(l,i,1)
Until c<>" " Or ac<>" "
ll+c
Wend
ProcedureReturn Trim(ll)
EndProcedure
Procedure ShaderCompile(shadercode.s,type=#PB_Shader_Fragment,dbg=1)
Protected shader,gltype, *TxtPointer,Program, Textlength, message.s = Space(1024)
If type=#PB_Shader_Vertex:gltype=#GL_VERTEX_SHADER:Else:gltype=#GL_FRAGMENT_SHADER:EndIf
shadercode=ReplaceString(shadercode,"%",#CRLF$)
shader = glCreateShader(gltype)
*TxtPointer = Ascii(shadercode)
glShaderSource(shader, 1, @*TxtPointer, #Null)
glCompileShader(shader)
glGetShaderInfoLog(shader,1023,@Textlength,@message)
Shadermessage=PeekS(@message,1023,#PB_Ascii)
If Shadermessage
If dbg:Debug "error shader "+shader+#CRLF$+Shadermessage:EndIf
ProcedureReturn
EndIf
ProcedureReturn shader
EndProcedure
Procedure shaderCreate(num,fshadercode.s,vshadercode.s="",name.s="",dbg=1)
Static numauto=1000000
Protected vshader,fshader,Program,vfcode.s,ul,txu
If num=-1:num=numauto:numauto+1:EndIf
If fshadercode="":fshader=#SHdefault:Else:fshader=ShaderCompile(fshadercode,#PB_Shader_Fragment,dbg):EndIf:If fshader=0 :ProcedureReturn :EndIf
If vshadercode="":vshadercode=codevertex:vshader=SHvertex :Else:vshader=ShaderCompile(vshadercode,#PB_Shader_Vertex,dbg):EndIf:If vshader=0 :ProcedureReturn :EndIf
Program = glCreateProgram()
glAttachShader(Program,vshader)
glAttachShader(Program,fshader)
glLinkProgram(Program)
glUseProgram(Program)
If FindMapElement(ShaderInfo(),""+num):DeleteMapElement(ShaderInfo(),""+num):EndIf
With ShaderInfo(""+num)
\num=num
\name=name
\pg=Program
\vcode=vshadercode
\fcode=fshadercode
Protected p,pf,l.s,n.s,t.s
vfcode=supspace(vshadercode+fshadercode)
Repeat
p=FindString(vfcode,"uniform",p+1)
pf=FindString(vfcode,";",p)
If p
l=Mid(vfcode,p,pf-p)
n=StringField(l,3," ")
t=StringField(l,2," ")
ul=glGetUniformLocation(Program,n)
If FindString(t,"sampler"):glUniform1i(ul,txu):txu+1:Else:\uloc(n)=ul:EndIf
EndIf
Until p=0
EndWith
ProcedureReturn num
EndProcedure
Procedure S_Camera(x.f,y.f,zoom.f=0,rotation.f=1e10)
glcamx=x
glcamy=y
If zoom<>0:glcamzoom=zoom:EndIf
If rotation<>1e10
glcamrot=Radian(rotation)
glcami=Cos(glcamrot)*glcamzoom
glcamj=Sin(glcamrot)*glcamzoom
EndIf
EndProcedure
Procedure S_light(x.f,y.f,z.f,dist.f,color.l,ambiantcolor.l,world=1)
If world:screenpos(@x,@y):EndIf
glligthx=x
glligthy=y
glligthz=z
glligthdist=dist
glligthcolor=$ff<<24 | color
glambiantcolor=$ff<<24 | ambiantcolor
EndProcedure
Procedure S_SpriteParameter(num,parameter.s,type,v0.d,v1.f=0,v2.f=0,v3.f=0); parameter: #PB_Shader_Integer/float/vector2/vector3/vector4/color
Protected *sh.sShaderinfo,*p.sparam
If num=-1
;S_SpriteParameter(-1,"screenratio",#PB_Shader_Float,glratio)
EndIf
Spriteverif(num)
With SpriteInfo(""+num)
*p=\param(parameter)
*p\nom=parameter
*p\type=type
*p\v0=v0
*p\v1=v1
*p\v2=v2
*p\v3=v3
EndWith
EndProcedure
Procedure S_SpriteUV(num, u1.f, v1.f, u2.f, v2.f, u3.f, v3.f, u4.f, v4.f)
Spriteverif(num)
With SpriteInfo(""+num)
\u1=u1:\v1=v1
\u2=u2:\v2=v2
\u3=u3:\v3=v3
\u4=u4:\v4=v4
EndWith
EndProcedure
Procedure S_ClipSprite(num, x.f, y.f, dx.f, dy.f,mode=0)
Spriteverif(num)
With SpriteInfo(""+num)
\u1=x/\Tdx:\v1=y/\Tdy
\u2=(x+dx)/\Tdx:\v2=y/\Tdy
\u3=(x+dx)/\Tdx:\v3=(y+dy)/\Tdy
\u4=x/\Tdx:\v4=(y+dy)/\Tdy
\dx=dx
\dy=dy
EndWith
spritecoord(num)
EndProcedure
Procedure S_CreateSprite(num,shaderNum,image1,image2=-1,image3=-1,image4=-1); shaderNum:Enumeration S_shader2D
If shaderNum=0:MessageRequester("Erreur S_CreateSprite","Shader invalid"):CallDebugger:EndIf
Static numauto=1000000
Protected u.s,txu
If num=-1:num=numauto:numauto+1:EndIf
AddMapElement(SpriteInfo(),""+num)
SpriteInfo()\sh = ShaderInfo(""+shaderNum)
Macro addtx(image)
If image>=0
If IsImage(image)=0:MessageRequester("Erreur S_CreateSprite","image"+Str(txu+1)+" isn't loaded"):CallDebugger:EndIf
AddElement(SpriteInfo()\tx())
SpriteInfo()\tx()= ImageToGLTextures(image)
EndIf
EndMacro
addtx(image1)
addtx(image2)
addtx(image3)
addtx(image4)
With SpriteInfo()
\Tdx=ImageWidth(image1):\dx=\Tdx
\Tdy=ImageHeight(image1):\dy=\Tdy
\u2=1:\u3=1:\v3=1:\v4=1
\x2=\Tdx:\x3=\Tdx:\y3=\Tdy:\y4=\Tdy
\zx=1:\zy=1
EndWith
ProcedureReturn num
EndProcedure
Procedure S_DisplaySprite(num,x.f,y.f,Alpha=$ff,color.l=$ffffff,z.f=0)
Spriteverif(num)
Protected.f a=alpha/255, r=Red(color)/255, g=Green(color)/255, b=Blue(color)/255,sx,sy
Protected txu, *sp.sSpriteinfo
*sp=SpriteInfo(""+num)
glUseProgram(*sp\sh\pg)
ForEach *sp\tx()
glActiveTexture(#GL_TEXTURE0+txu):glBindTexture_(#GL_TEXTURE_2D,*sp\tx()):txu+1
Next
ForEach *sp\param()
With *sp\param()
shaderuniform(*sp\sh,\nom,\type,\v0,\v1,\v2,\v3)
EndWith
Next
With *sp
Macro glv(x,y):sx=x:sy=y:If *sp\sh\num<>#SHoverlay:screenpos(@sx,@sy):EndIf:glVertex3f_(sx, sy,z):EndMacro
glBegin_(#GL_QUADS)
glColor4f_(r,g,b,a)
glNormal3f_(Cos(*sp\ag+glcamrot),Sin(*sp\ag+glcamrot),0); for tangent !
glTexCoord2f_(\u1,\v1):glv(x+\x1,y+\y1)
glTexCoord2f_(\u2,\v2):glv(x+\x2,y+\y2)
glTexCoord2f_(\u3,\v3):glv(x+\x3,y+\y3)
glTexCoord2f_(\u4,\v4):glv(x+\x4,y+\y4)
glEnd_()
EndWith
EndProcedure
Procedure S_FreeSprite(num)
Spriteverif(num)
glDeleteProgram(SpriteInfo(""+num)\sh\pg)
DeleteMapElement(SpriteInfo(),""+num)
EndProcedure
Procedure S_IsSprite(num)
If FindMapElement(SpriteInfo(),""+num):ProcedureReturn 1:EndIf
EndProcedure
Procedure S_RotateSprite(num,angle.f,mode=0)
Spriteverif(num)
With SpriteInfo(""+num)
angle=Radian(angle)
If mode:\ag+angle:Else:\ag=angle:EndIf
EndWith
spritecoord(num)
EndProcedure
Procedure S_SpriteOrigine(num,x.f,y.f,unit=#s_unit_UV) ; unit:Enumeration S_unit
Spriteverif(num)
With SpriteInfo(""+num)
If unit=#s_unit_UV
\xo=x*\Tdx
\yo=y*\Tdy
Else
\xo=x
\yo=y
EndIf
EndWith
spritecoord(num)
EndProcedure
Procedure S_BlendingMode(mode, modesource=#PB_Sprite_BlendSourceAlpha, modedestination=#PB_Sprite_BlendInvertSourceAlpha); mode:Enumeration S_BlendingMode, mosesource/modedestination: cf:SpriteBlendingMode
Protected glsrc,gldst
Macro cvmode(pbmode,glmode)
Select pbmode
Case #PB_Sprite_BlendZero:glmode=#GL_ZERO
Case #PB_Sprite_BlendOne:glmode=#GL_ONE
Case #PB_Sprite_BlendSourceColor:glmode=#GL_SRC_COLOR
Case #PB_Sprite_BlendInvertSourceColor:glmode=#GL_ONE_MINUS_SRC_COLOR
Case #PB_Sprite_BlendDestinationColor:glmode=#GL_DST_COLOR
Case #PB_Sprite_BlendInvertDestinationColor:glmode=#GL_ONE_MINUS_DST_COLOR
Case #PB_Sprite_BlendSourceAlpha:glmode=#GL_SRC_ALPHA
Case #PB_Sprite_BlendInvertSourceAlpha:glmode=#GL_ONE_MINUS_SRC_ALPHA
Case #PB_Sprite_BlendDestinationAlpha:glmode=#GL_DST_ALPHA
Case #PB_Sprite_BlendInvertDestinationAlpha:glmode=#GL_ONE_MINUS_DST_ALPHA
EndSelect
EndMacro
Select mode
Case #s_BlendingMode_alphablend: glBlendFunc_(#GL_SRC_ALPHA, #GL_ONE_MINUS_SRC_ALPHA)
Case #s_BlendingMode_add : glBlendFunc_(#GL_ONE, #GL_ONE)
Case #s_BlendingMode_custom :cvmode(modesource,glsrc):cvmode(modedestination,gldst):glBlendFunc_(glsrc, gldst)
EndSelect
EndProcedure
Procedure S_Spritecollision(num1, X1, Y1, num2, X2, Y2); !!! todo
Spriteverif(num1)
Spriteverif(num2)
EndProcedure
Procedure S_TransformSprite(num, X1.f, Y1.f, X2.f, Y2.f, X3.f, Y3.f, X4.f, Y4.f)
Spriteverif(num)
With SpriteInfo(""+num)
\x1=x1:\y1=y1
\x2=x2:\y2=y2
\x3=x3:\y3=y3
\x4=x4:\y4=y4
\zx=1:\zy=1
\ag=0
EndWith
EndProcedure
Procedure S_ZoomSprite(num, Width.f, Height.f,unit=#s_unit_UV); unit:Enumeration S_unit
Spriteverif(num)
With SpriteInfo(""+num)
If unit=#s_unit_UV
\dx=Width*\Tdx
\dy=Height*\Tdy
Else
\dx=Width
\dy=Height
EndIf
\zx=\dx/\tdx
\zy=\dy/\tdy
EndWith
spritecoord(num)
EndProcedure
Procedure s_FlipBuffers()
FlipBuffers()
ForEach ShaderInfo()
glUseProgram(ShaderInfo()\pg)
shaderuniform(ShaderInfo(),"screen",#PB_Shader_Vector2,s_screendx,s_screendy)
shaderuniform(ShaderInfo(),"campos",#PB_Shader_Vector3,s_screendx2,s_screendy2,s_screendy2)
shaderuniform(ShaderInfo(),"ambiantcolor",#PB_Shader_color,glambiantcolor)
shaderuniform(ShaderInfo(),"lightcolor",#PB_Shader_color,glligthcolor)
shaderuniform(ShaderInfo(),"lightinfo",#PB_Shader_Vector4,glligthx,glligthy,glligthz,glligthdist)
shaderuniform(ShaderInfo(),"time",#PB_Shader_Float,ElapsedMilliseconds()/1000)
Next
glEnable_(#GL_BLEND)
EndProcedure
Procedure S_init()
s_screendx=ScreenWidth():s_screendx2=s_screendx/2
s_screendy=ScreenHeight():s_screendy2=s_screendy/2
codevertex="#version 120 %%uniform vec2 screen;% varying vec3 vpos;% varying vec4 vcolor;% varying vec2 vuv;% varying vec2 vtan;% void main() {% vtan = gl_Normal.xy;% gl_Position = vec4( gl_Vertex.xy/screen*2-1,gl_Vertex.z, 1 );gl_Position.y*=-1;% vcolor=gl_Color;% vuv=gl_MultiTexCoord0.xy;//invertv% vpos=gl_Vertex.xyz;%}"
If #PB_Compiler_OS = #PB_OS_Windows:codevertex=ReplaceString(codevertex,"//invertv","vuv.y=1-vuv.y;"):EndIf
SHvertex=ShaderCompile(codevertex,#PB_Shader_Vertex)
;Debug ReplaceString(codevertex,"%",#LF$)
shaderCreate(#SHoverlay,"#version 130 %%uniform sampler2D txt0;%%in vec4 vcolor;%in vec2 vuv;%%out vec4 fcolor;%%void main( void ) {% vec4 tcolor=texture(txt0,vuv);% fcolor =tcolor*vcolor;%}","","overlay")
shaderCreate(#SHdefault,"#version 130 %%uniform sampler2D txt0;%%in vec4 vcolor;%in vec2 vuv;%%out vec4 fcolor;%%void main( void ) {% vec4 tcolor=texture(txt0,vuv);% fcolor =tcolor*vcolor;%}","","default")
shaderCreate(#SHblend,"#version 130 %%uniform sampler2D tx0;%uniform sampler2D tx1;%uniform vec4 lightinfo;%uniform vec4 lightcolor;%uniform vec4 ambiantcolor;%uniform float blend;%%in vec4 vcolor;%in vec2 vuv;%in vec3 vpos;%%out vec4 fcolor;%%void main( void ) {% vec4 tcolor=mix(texture(tx0,vuv),texture(tx1,vuv),blend);% float lum=max(1-distance(lightinfo.xyz,vpos)/lightinfo.w,0);% fcolor =tcolor*vcolor*(ambiantcolor+lightcolor*lum);%}","","blend")
shaderCreate(#SHlight,"#version 130 %%uniform sampler2D txt0;%uniform vec4 lightinfo;%uniform vec4 lightcolor;%uniform vec4 ambiantcolor;%%in vec4 vcolor;%in vec2 vuv;%in vec3 vpos;%%out vec4 fcolor;%%void main( void ) {% vec4 tcolor=texture(txt0,vuv);% float lum=max(1-distance(lightinfo.xyz,vpos)/lightinfo.w,0);% fcolor =tcolor*vcolor*(ambiantcolor+lum*lightcolor);%}","","light")
shaderCreate(#SHbump,"#version 130 %%uniform sampler2D tx0;%uniform sampler2D tx1;%%uniform vec3 campos;%uniform vec4 lightinfo;%uniform vec4 lightcolor;%uniform vec4 ambiantcolor;%%in vec4 vcolor;%in vec2 vuv;%in vec3 vpos;%in vec2 vtan;%%out vec4 fcolor;%%void main( void ) {% vec4 tcol=texture(tx0,vuv)*vcolor;% vec3 tnor=texture(tx1,vuv).xyz-0.5;tnor.xy*=1;% tnor.xy=vec2(vtan.x*tnor.x+vtan.y*-tnor.y, -vtan.y*tnor.x+vtan.x*-tnor.y);% tnor=normalize(tnor);% vec3 ldir=normalize(lightinfo.xyz-vpos);% vec3 cdir=normalize(campos-vpos);% float att=max(1-distance(lightinfo.xyz,vpos)/lightinfo.w,0);% float dif=max(dot(ldir,tnor),0)*att;% float spe=pow(max(dot(normalize(ldir+cdir),tnor),0),50);% fcolor =tcol*(ambiantcolor+lightcolor*(dif+spe));%}","","bump")
shaderCreate(#SHflame,"#version 130 %%uniform sampler2D tx;%uniform float time;%%in vec2 vuv;%in vec4 vcolor;%%out vec4 fcolor;%void main()%{%float odec=1;%vec2 uv=vuv;uv.y=pow(uv.y,0.5);%vec2 pc=uv*2-1;%float h=1-dot(pc,pc);%if(h<0)discard;%float vx=time*0.08;%float vy=time*-0.2;%float lum=0.8*h*(texture(tx,uv+vec2(vx,vy+odec)).a+texture(tx,uv+vec2(-vx,vy+0.5+odec)).a);%fcolor=(lum*lum)*vcolor;%}","","flame")
shaderCreate(#SHwater,"#version 130 %%uniform sampler2D tx;%%uniform float time;%uniform vec3 campos;%uniform vec4 lightinfo;%uniform vec4 lightcolor;%uniform vec4 skycolor;%%in vec4 vcolor;%in vec2 vuv;%in vec3 vpos;%in vec2 vtan;%%out vec4 fcolor;%%void main( void ) {% vec2 duv=vec2(time*0.02,0);% vec3 tnor=(texture(tx,vuv+duv).xyz+texture(tx,vuv+0.5-duv).xyz-1).xyz;tnor.xy*=1;% tnor.xy=vec2(vtan.x*tnor.x+vtan.y*-tnor.y, -vtan.y*tnor.x+vtan.x*-tnor.y);% tnor=normalize(tnor);% vec3 ldir=normalize(lightinfo.xyz-vpos);% vec3 cdir=normalize(campos-vpos);% float spe=pow(max(dot(normalize(ldir+cdir),tnor),0),50);% float cfresnel = 1-abs(dot(cdir, tnor));% fcolor =mix(vcolor,skycolor,cfresnel*cfresnel)+lightcolor*spe;%}","","water")
shaderCreate(#SHplasma,"#version 130 %%uniform sampler2D tx;%uniform float time;%uniform vec4 color1;%uniform vec4 color2;%%in vec2 vuv;%in vec4 vcolor;%%out vec4 fcolor;%void main()%{%vec2 duv=vec2(time*0.02,0);%float lum=(texture(tx,vuv+duv).a+texture(tx,vuv-duv+0.5).a);%fcolor=mix(color1,color2,mod(lum*2,1))*vcolor;%//fcolor=mix(color1,color2,(1+cos(lum*3.14*4))/2)*vcolor;%}","","plasma")
shaderCreate(#SHnew,"#version 130 %%uniform sampler2D tx;%%// global parameters%uniform vec3 campos; // camera position%uniform vec4 ambiantcolor;%uniform vec4 lightcolor;%uniform vec4 lightinfo; // x,y,z:position, w:range%uniform float time; // in seconds%%// keep only if you use it%in vec3 vpos; // vertex position%in vec4 vcolor; // vertex color%in vec2 vuv; // vertex uv%in vec2 tan; // tangent (for normal mapping)%%out vec4 fcolor;%%void main()%{%vec4 tcolor=texture(tx,vuv);%fcolor=tcolor*vcolor;%}","","new")
EndProcedure
;========================================================================== shader editor
Global GSE_editor,GSE_message,GSE_list,GSE_run,GSE_savecb, SE_window, shaderedit
Procedure shaderEditorcallback()
Protected event,code.s
Macro updateshader
shaderCreate(shaderedit,code,"",ShaderInfo(""+shaderedit)\name,0)
SetGadgetText(GSE_message,Shadermessage)
If Shadermessage=""
ForEach SpriteInfo()
If SpriteInfo()\sh\num=shaderedit:SpriteInfo()\sh=ShaderInfo(""+shaderedit):EndIf
Next
EndIf
EndMacro
Select Event()
Case #PB_Event_CloseWindow:CloseWindow(EventWindow()):SE_window=0:ReleaseMouse(0)
Case #PB_Event_Menu
Select EventMenu()
Case 1111:code = GetGadgetText(GSE_editor):updateshader
Case 1112:CloseWindow(EventWindow()):SE_window=0:ReleaseMouse(0)
EndSelect
Case #PB_Event_Gadget
Select EventGadget()
Case GSE_list:shaderedit=GetGadgetItemData(GSE_list,GetGadgetState(GSE_list)):SetGadgetText(GSE_editor,ReplaceString(ShaderInfo(""+shaderedit)\fcode,"%",#CRLF$))
Case GSE_run:code = GetGadgetText(GSE_editor):updateshader
Case GSE_savecb:code=GetGadgetText(GSE_editor):code=ReplaceString(code,#CRLF$,"%"):SetClipboardText(~"SHnew=shaderCreate(-1,\""+code+~"\",\"\",\""+ShaderInfo(""+shaderedit)\name+~"\")\n")
EndSelect
EndSelect
EndProcedure
Procedure shaderEditor(shader)
Protected wdx=700,xdy=600,nf,it,ls
If SE_window:ReleaseMouse(1):SetActiveWindow(SE_window): ProcedureReturn :EndIf
shaderedit=shader
SE_window=OpenWindow(-1,0,0,wdx,xdy,"Shader Editor")
BindEvent(#PB_Event_Gadget,@shaderEditorcallback(),SE_window)
BindEvent(#PB_Event_Menu,@shaderEditorcallback(),SE_window)
BindEvent(#PB_Event_CloseWindow,@shaderEditorcallback(),SE_window)
GSE_editor=EditorGadget(-1,8,30,wdx-16,xdy-30-150)
SetGadgetText(GSE_editor,ReplaceString(ShaderInfo(""+shaderedit)\fcode,"%",#CRLF$))
GSE_message=EditorGadget(-1,8,xdy+8-150,wdx-16,150-16,#PB_Editor_ReadOnly)
nf=LoadFont(-1,"consolas",10)
SetGadgetFont(GSE_editor,FontID(nf))
SetGadgetFont(GSE_message,FontID(nf))
GSE_list=ComboBoxGadget(-1,8,0,90,24):ForEach ShaderInfo():AddGadgetItem(GSE_list,-1,ShaderInfo()\name):SetGadgetItemData(GSE_list,it,ShaderInfo()\num):If ShaderInfo()\num=shader:ls=it:EndIf:it+1:Next
SetGadgetState(GSE_list,ls)
GSE_run=ButtonGadget(-1,108 ,0,90,24,"run [F5]")
GSE_savecb=ButtonGadget(-1,208 ,0,90,24,"save clipboard")
AddKeyboardShortcut(SE_window, #PB_Shortcut_F5, 1111)
AddKeyboardShortcut(SE_window, #PB_Shortcut_Escape, 1112)
EndProcedure
;============================================================================================ brush
Procedure initIF(image,cx.w=-1,cy.w=-1)
;image : numero de l'image
;centerx/y : definit le centre de l'image
Structure sImageFont
x.b
y.b
col.l
EndStructure
Protected i,j,d,k,n,c,idx,idy,x,y
idx=ImageWidth (image):If cx=-1:cx=idx/2:EndIf
idy=ImageHeight(image):If cy=-1:cy=idy/2:EndIf
Global Dim IFdata.sImageFont(idx * idy-1)
n=-1
StartDrawing(ImageOutput(image))
DrawingMode(#PB_2DDrawing_AllChannels)
Macro gplot(i,j):x=cx+i:y=cy+j:If x>=0 And x<idx And y>=0 And y<idy:c=Point(x,y):If c<>0:n+1:IFdata(n)\x=x:IFdata(n)\y=y:IFdata(n)\col=c:EndIf:EndIf:EndMacro
gplot(0,0)
For d=1 To 30
For k=0 To d-1
gplot(-d+k,-k)
gplot(k,-d+k)
gplot(d-k, k)
gplot(-k,d-k)
Next
Next
ReDim IFdata(n)
StopDrawing()
EndProcedure
Procedure DrawVectorTextBrush(text.s)
Protected x.f,y.f,j,n
x=PathCursorX()
y=PathBoundsY()
n=ArraySize(IFdata())
For j=n To 0 Step -1
MovePathCursor(x+IFdata(j)\x,y+IFdata(j)\y):VectorSourceColor(IFdata(j)\col):DrawVectorText(text)
Next
EndProcedure
;============================================================================================ fastfont
Procedure S_InitFont(num,name.s, height.f,style=0,brush=-1,chars.s="")
Structure ssc
sx.l
sl.l
cl.l
co.l
EndStructure
Structure sscfont
ns.i
height.f
Array c.ssc(255)
EndStructure
Global ScrennFont.sscfont
Protected i,h,l,c.s,ca,im,bx,by,cx,co,cv,cl:Global nf
If chars="":For i=32 To 128:chars+Chr(i):Next:EndIf
nf=LoadFont(-1,name,height,style)
If brush>=0:initIF(brush):bx=ImageWidth(brush):by=ImageHeight((brush)):EndIf
IM=CreateImage(-1,1,1)
StartDrawing(ImageOutput(im)):DrawingFont(FontID(nf))
h=TextHeight(" ")+by
l=TextWidth(chars)*1.3+Len(chars)*bx:cx=0
StopDrawing()
FreeImage(im)
IM=CreateImage(-1,l,h,32,#PB_Image_Transparent):StartDrawing(ImageOutput(im)):DrawingMode(#PB_2DDrawing_AllChannels):Box(0,0,l,h,$00ffffff):StopDrawing()
StartVectorDrawing(ImageVectorOutput(im)):VectorFont(FontID(nf))
For i=1 To Len(chars)
c=Mid(chars,i,1):ca=Asc(c)
With ScrennFont\c(ca)
co=VectorTextWidth(c,#PB_VectorText_Visible|#PB_VectorText_Offset):If ca=126:co=0:EndIf
cv=VectorTextWidth(c,#PB_VectorText_Visible)
cl=VectorTextWidth(c)
\sx=cx
\sl=cv+bx+2
\cl=cl+bx/2
\co=co
;AddPathBox(\sx,0,\sl,h):VectorSourceColor($8800ff00):FillPath()
MovePathCursor(cx-co+1,0)
If brush<0:VectorSourceColor($ffffffff):DrawVectorText(c):Else:DrawVectorTextBrush(c):EndIf
cx+\sl+1
EndWith
Next
StopVectorDrawing()
ScrennFont\ns=S_CreateSprite(-1,#SHoverlay,im)
ScrennFont\height=h
EndProcedure
Procedure S_DrawText(x,y,t.s,size=-1,color=$ffffffff)
Protected i,ca,cx,c.ssc,zoom.f
With ScrennFont
If size=-1:size=\height:EndIf
zoom=size/\height
For i=1 To Len(t)
c=\c(Asc(Mid(t,i,1)))
S_ClipSprite(\ns,c\sx,0,c\sl,\height)
S_ZoomSprite(\ns,c\sl*zoom,\height*zoom,#s_unit_Pixel)
S_DisplaySprite(\ns,x+c\co*zoom,y,255,color)
x+c\cl*zoom
Next
EndWith
EndProcedure
;====================================================================================================================================================
;====================================================================================================================================================
;====================================================================================================================================================
ExamineDesktops()
Define swidth=DesktopWidth(0)*0.8
Define sheight=DesktopHeight(0)*0.8
OpenWindow(0,0,0,swidth,sheight,"Lib 2D v1.0",#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0),0,0,swidth,sheight)
S_init()
InitKeyboard()
InitMouse()
;----------------------------- init screen font
CreateImage(100,8,8,32,#PB_Image_Transparent)
StartVectorDrawing(ImageVectorOutput(100))
VectorSourceCircularGradient(3,3,5)
VectorSourceGradientColor($ffffffff, 0.0)
VectorSourceGradientColor($ff0000ff, 0.5)
VectorSourceGradientColor($00000000, 1.0)
AddPathCircle(4,4,4):FillPath()
StopVectorDrawing()
S_InitFont(0,"ink free",30,#PB_Font_Italic,100)
Define i,sblend,sbump,sflare,sflame, swater,scloud, splasma, SHwobble,swobble
;----------------------------- load images
UseJPEGImageDecoder()
UsePNGImageDecoder()
LoadImage(1,#PB_Compiler_Home+"examples/3D/Data/Textures/water.png")
LoadImage(2,#PB_Compiler_Home+"examples/3D/Data/Textures/smoke2.png")
LoadImage(3,#PB_Compiler_Home+"examples/3D/Data/Textures/flare.png")
LoadImage(4,#PB_Compiler_Home+"examples/3D/Data/Textures/sky.png")
LoadImage(5,#PB_Compiler_Home+"examples/3D/Data/Textures/nvidia/dirt_grayrocky_diffusespecular.jpg")
LoadImage(6,#PB_Compiler_Home+"examples/3D/Data/Textures/nvidia/dirt_grayrocky_normalheight.jpg")
LoadImage(7,#PB_Compiler_Home+"examples/3D/Data/Textures/waternormal.png")
CreateImage(10,512,512,32,#PB_Image_Transparent):StartDrawing(ImageOutput(10)):DrawingMode(#PB_2DDrawing_AlphaBlend):For i=0 To 800:Circle(Random(512-64)+32,Random(512-64)+32,32,Random($44ffffff)):Next:StopDrawing()
;----------------------------- init demo1
sbump=S_CreateSprite(-1,#SHbump,5,6):S_SpriteOrigine(sbump,0.5,0.5):S_ZoomSprite(sbump,swidth*2,sheight*2,0):S_SpriteUV(sbump,0,0, 2,0, 2,2, 0,2)
sblend=S_CreateSprite(-1,#shblend,1,2):S_SpriteOrigine(sblend,0.5,0.5):S_ZoomSprite(sblend,2,2)
sflare=S_CreateSprite(-1,#SHoverlay,3):S_SpriteOrigine(sflare,0.5,0.5):S_ZoomSprite(sflare,2,2)
sflame=S_CreateSprite(-1,#SHflame,7):S_SpriteOrigine(sflame,0.5,0.5):S_ZoomSprite(sflame,1,1.5)
;----------------------------- init demo2
swater=S_CreateSprite(-1,#SHwater,7):S_SpriteParameter(swater,"skycolor",#PB_Shader_color,$ffffbb88):S_SpriteOrigine(swater,0.5,0.5):S_ZoomSprite(swater,swidth*2,swidth*2,#s_unit_Pixel)
scloud=S_CreateSprite(-1,#SHdefault,4):S_ZoomSprite(scloud,swidth*2,swidth*2,#s_unit_Pixel):S_SpriteOrigine(scloud,0.5,0.5)
;----------------------------- init demo3
splasma=S_CreateSprite(-1,#SHplasma,7):S_SpriteParameter(splasma,"color1",#PB_Shader_color,$ffff0000):S_SpriteParameter(splasma,"color2",#PB_Shader_color,$ff00ffff):S_SpriteOrigine(splasma,0.5,0.5):S_ZoomSprite(splasma,sheight*2,sheight*2,#s_unit_Pixel)
;---------------------------- init test shader
SHwobble=shaderCreate(-1,"#version 130 %%uniform sampler2D txt0;%uniform vec4 lightinfo;%uniform vec4 lightcolor;%uniform vec4 ambiantcolor;%uniform float time;%%in vec4 vcolor;%in vec2 vuv;%in vec3 vpos;%%out vec4 fcolor;%%void main( void ) {% float fq=8,amp=0.04,ti=time*4;% vec2 uv=vuv*(1+2*amp)-amp;% uv=uv+vec2(sin(vuv.y*fq+ti)*amp,sin(vuv.x*fq+ti)*amp);% if (uv.x<0 || uv.x>1 || uv.y<0 || uv.y>1) discard; % vec4 tcolor=texture(txt0,uv);% float lum=max(1-distance(lightinfo.xyz,vpos)/lightinfo.w,0);% fcolor =tcolor*vcolor*(ambiantcolor+lum*lightcolor);%}","","wobble")
swobble=S_CreateSprite(-1,SHwobble,10):S_SpriteOrigine(swobble,0.5,0.5):S_ZoomSprite(swobble,sheight,sheight,#s_unit_Pixel);:S_SpriteParameter(swobble,"amp",#PB_Shader_Float,1)
Define.f sy,a,ai,py,dy,t, rot,zw=0.5*8,zc=0.25, example.b=0
MouseLocate(swidth/2,sheight/2)
Repeat
While WindowEvent():Wend
ExamineKeyboard()
ExamineMouse()
t=ElapsedMilliseconds()/1000
a=t*2
sy=-t/10
ClearScreen(0)
S_BlendingMode(#s_BlendingMode_alphablend)
Select example
Case 0
S_Camera(Sin(sy*5)*200,Sin(sy*7)*200,1,0)
S_light(MouseX(),MouseY(),sheight/2,sheight*4,$ffffff,$0,0)
S_DisplaySprite(sbump,swidth/2,sheight/2)
S_SpriteParameter(sblend,"blend",#PB_Shader_Float,0.5+0.5*Cos(a)):S_DisplaySprite(sblend,swidth*0.25,sheight*0.25,$ff,$ffff00)
S_SpriteParameter(sblend,"blend",#PB_Shader_Float,0.5+0.5*Sin(a)):S_DisplaySprite(sblend,swidth*0.25,sheight*0.75,$ff,$ff00ff)
S_BlendingMode(#s_BlendingMode_add)
S_DisplaySprite(sflame,swidth*0.75,sheight/2,128,$88ff)
S_RotateSprite(sflare,2,#PB_Relative):S_DisplaySprite(sflare,MouseX(),MouseY())
S_BlendingMode(#s_BlendingMode_alphablend)
Case 1
rot+MouseDeltaX()*0.05
S_Camera(0,0,1+Sin(sy*4)/3,rot)
S_light(10000,-10000,10000,0,$ffffff,$222222*4)
S_SpriteUV(swater, 0,sy, zw,sy, zw,zw+sy, 0,zw+sy):S_DisplaySprite(swater,swidth/2,sheight/2,255,$443300)
S_SpriteUV(scloud, 0,sy, zc*2,sy, zc*2,zc*2+sy, 0,zc*2+sy)
S_DisplaySprite(scloud,swidth/2,sheight/2)
S_SpriteUV(scloud, 0,sy, zc,sy, zc,zc+sy, 0,zc+sy)
S_DisplaySprite(scloud,swidth/2,sheight/2)
Case 2
S_Camera(0,0,1,0)
S_DisplaySprite(splasma,swidth/2,sheight/2)
Case 3
S_Camera(0,0,1,0)
S_light(0,0,0,0,0,$ffffff,0)
S_DisplaySprite(sbump,swidth/2,sheight/2,$ff,$888888)
S_DisplaySprite(swobble,swidth/2,sheight/2)
EndSelect
S_DrawText(8,0,"[F1] Edit shader")
S_DrawText(8,60,"[Space] Change example")
S_DrawText(8,120,"[Esc] Quit")
S_DrawText(8,180,"Use mouse",40)
s_FlipBuffers()
If KeyboardReleased(#PB_Key_F1):shaderEditor(#SHnew) :EndIf
If KeyboardReleased(#PB_Key_Space):example=(example+1)%4:EndIf
Until KeyboardReleased(#PB_Key_Escape) Or MouseButton(3)