|
@@ -0,0 +1,3141 @@
|
|
|
+'
|
|
|
+' BlitzMax port, 2015 Bruce A Henderson
|
|
|
+'
|
|
|
+' Copyright (c) 2015 Mark Sibly
|
|
|
+'
|
|
|
+' This software is provided 'as-is', without any express or implied
|
|
|
+' warranty. In no event will the authors be held liable for any damages
|
|
|
+' arising from the use of this software.
|
|
|
+'
|
|
|
+' Permission is granted to anyone to use this software for any purpose,
|
|
|
+' including commercial applications, and to alter it and redistribute it
|
|
|
+' freely, subject to the following restrictions:
|
|
|
+'
|
|
|
+' 1. The origin of this software must not be misrepresented; you must not
|
|
|
+' claim that you wrote the original software. If you use this software
|
|
|
+' in a product, an acknowledgement in the product documentation would be
|
|
|
+' appreciated but is not required.
|
|
|
+' 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
+' misrepresented as being the original software.
|
|
|
+' 3. This notice may not be removed or altered from any source distribution.
|
|
|
+'
|
|
|
+SuperStrict
|
|
|
+
|
|
|
+
|
|
|
+'Framework brl.standardio
|
|
|
+
|
|
|
+Import brl.bank
|
|
|
+Import brl.map
|
|
|
+Import brl.ramstream
|
|
|
+Import brl.pixmap
|
|
|
+Import brl.filesystem
|
|
|
+Import brl.system
|
|
|
+Import brl.Graphics
|
|
|
+Import "math3d.bmx"
|
|
|
+Import "glutil.bmx"
|
|
|
+Import "glslparser.bmx"
|
|
|
+Import "maps.bmx"
|
|
|
+
|
|
|
+
|
|
|
+Incbin "data/mojo2_font.png"
|
|
|
+Incbin "data/mojo2_program.glsl"
|
|
|
+Incbin "data/mojo2_fastshader.glsl"
|
|
|
+Incbin "data/mojo2_bumpshader.glsl"
|
|
|
+Incbin "data/mojo2_matteshader.glsl"
|
|
|
+Incbin "data/mojo2_shadowshader.glsl"
|
|
|
+Incbin "data/mojo2_lightmapshader.glsl"
|
|
|
+
|
|
|
+Private
|
|
|
+
|
|
|
+Global _inited:Int
|
|
|
+
|
|
|
+Global mainShader:String
|
|
|
+
|
|
|
+Global _fastShader:TShader
|
|
|
+Global _bumpShader:TShader
|
|
|
+Global _matteShader:TShader
|
|
|
+Global _shadowShader:TShader
|
|
|
+Global _lightMapShader:TShader
|
|
|
+
|
|
|
+Global defaultFont:TFont
|
|
|
+Global _defaultShader:TShader
|
|
|
+
|
|
|
+Global freeOps:TDrawOpStack=New TDrawOpStack
|
|
|
+Global nullOp:TDrawOp=New TDrawOp
|
|
|
+
|
|
|
+Global tmpi:Int[16]
|
|
|
+Global tmpf:Float[16]
|
|
|
+Global defaultFbo:Int
|
|
|
+
|
|
|
+Global tmpMat2d:Float[6]
|
|
|
+Global tmpMat3d:Float[16]
|
|
|
+Global tmpMat3d2:Float[16]
|
|
|
+
|
|
|
+Global flipYMatrix:Float[]=Mat4New()
|
|
|
+Global graphicsSeq:Int=1
|
|
|
+Global vbosSeq:Int
|
|
|
+
|
|
|
+'shader params
|
|
|
+Global rs_projMatrix:Float[]=Mat4New()
|
|
|
+Global rs_modelViewMatrix:Float[]=Mat4New()
|
|
|
+Global rs_modelViewProjMatrix:Float[]=Mat4New()
|
|
|
+Global rs_clipPosScale:Float[]=[1.0,1.0,1.0,1.0]
|
|
|
+Global rs_globalColor:Float[]=[1.0,1.0,1.0,1.0]
|
|
|
+Global rs_numLights:Int
|
|
|
+Global rs_fogColor:Float[]=[0.0,0.0,0.0,0.0]
|
|
|
+Global rs_ambientLight:Float[]=[0.0,0.0,0.0,1.0]
|
|
|
+Global rs_lightColors:Float[MAX_LIGHTS*4]
|
|
|
+Global rs_lightVectors:Float[MAX_LIGHTS*4]
|
|
|
+Global rs_shadowTexture:TTexture
|
|
|
+Global rs_program:TGLProgram
|
|
|
+Global rs_material:TMaterial
|
|
|
+Global rs_blend:Int=-1
|
|
|
+Global rs_vbo:Int
|
|
|
+Global rs_ibo:Int
|
|
|
+
|
|
|
+Const VBO_USAGE:Int=GL_STREAM_DRAW
|
|
|
+Const VBO_ORPHANING_ENABLED:Int=False
|
|
|
+
|
|
|
+Const MAX_LIGHTS:Int=4
|
|
|
+Const BYTES_PER_VERTEX:Int=28
|
|
|
+
|
|
|
+'can really be anything <64K (due to 16bit indices) but this keeps total VBO size<64K, and making it bigger doesn't seem to improve performance much.
|
|
|
+Const MAX_VERTICES:Int=65536/BYTES_PER_VERTEX
|
|
|
+
|
|
|
+Const MAX_QUADS:Int=MAX_VERTICES/4
|
|
|
+Const MAX_QUAD_INDICES:Int=MAX_QUADS*6
|
|
|
+Const PRIM_VBO_SIZE:Int=MAX_VERTICES*BYTES_PER_VERTEX
|
|
|
+
|
|
|
+Function IsPow2:Int( sz:Int )
|
|
|
+ Return (sz & (sz-1))=0
|
|
|
+End Function
|
|
|
+
|
|
|
+Public
|
|
|
+
|
|
|
+Type TLightData
|
|
|
+ Field kind:Int=0
|
|
|
+ Field color:Float[]=[1.0,1.0,1.0,1.0]
|
|
|
+ Field position:Float[]=[0.0,0.0,-10.0]
|
|
|
+ Field Range:Float=10
|
|
|
+ '
|
|
|
+ Field vector:Float[]=[0.0,0.0,-10.0,1.0]
|
|
|
+ Field tvector:Float[4]
|
|
|
+End Type
|
|
|
+
|
|
|
+Private
|
|
|
+
|
|
|
+Function InitVbos()
|
|
|
+ If vbosSeq=graphicsSeq Return
|
|
|
+ vbosSeq=graphicsSeq
|
|
|
+
|
|
|
+ glGenBuffers 1, Varptr rs_vbo
|
|
|
+ glBindBuffer GL_ARRAY_BUFFER,rs_vbo
|
|
|
+ glBufferData GL_ARRAY_BUFFER,PRIM_VBO_SIZE,Null,VBO_USAGE
|
|
|
+
|
|
|
+ glEnableVertexAttribArray 0
|
|
|
+ glVertexAttribPointer 0,2,GL_FLOAT,False,BYTES_PER_VERTEX,0
|
|
|
+
|
|
|
+ glEnableVertexAttribArray 1
|
|
|
+ glVertexAttribPointer 1,2,GL_FLOAT,False,BYTES_PER_VERTEX,8
|
|
|
+
|
|
|
+ glEnableVertexAttribArray 2
|
|
|
+ glVertexAttribPointer 2,2,GL_FLOAT,False,BYTES_PER_VERTEX,16
|
|
|
+
|
|
|
+ glEnableVertexAttribArray 3
|
|
|
+ glVertexAttribPointer 3,4,GL_UNSIGNED_BYTE,True,BYTES_PER_VERTEX,24
|
|
|
+
|
|
|
+ glGenBuffers(1, Varptr rs_ibo)
|
|
|
+ glBindBuffer GL_ELEMENT_ARRAY_BUFFER,rs_ibo
|
|
|
+ Local idxs:TBank=New TBank.Create( MAX_QUAD_INDICES*4*2 )
|
|
|
+ For Local j:Int = 0 Until 4
|
|
|
+ Local k:Int = j*MAX_QUAD_INDICES*2
|
|
|
+ For Local i:Int = 0 Until MAX_QUADS
|
|
|
+ idxs.PokeShort i*12+k+0,i*4+j+0
|
|
|
+ idxs.PokeShort i*12+k+2,i*4+j+1
|
|
|
+ idxs.PokeShort i*12+k+4,i*4+j+2
|
|
|
+ idxs.PokeShort i*12+k+6,i*4+j+0
|
|
|
+ idxs.PokeShort i*12+k+8,i*4+j+2
|
|
|
+ idxs.PokeShort i*12+k+10,i*4+j+3
|
|
|
+ Next
|
|
|
+ Next
|
|
|
+ glBufferData GL_ELEMENT_ARRAY_BUFFER,idxs.Size(),idxs._buf,GL_STATIC_DRAW
|
|
|
+ 'idxs.Discard
|
|
|
+End Function
|
|
|
+
|
|
|
+Global inited:Int
|
|
|
+
|
|
|
+Function InitMojo2()
|
|
|
+ If inited Return
|
|
|
+ inited=True
|
|
|
+
|
|
|
+?Not opengles
|
|
|
+ glewInit()
|
|
|
+?
|
|
|
+
|
|
|
+ InitVbos
|
|
|
+
|
|
|
+ glGetIntegerv GL_FRAMEBUFFER_BINDING,tmpi
|
|
|
+ defaultFbo=tmpi[0]
|
|
|
+
|
|
|
+ mainShader=LoadString( "incbin::data/mojo2_program.glsl" )
|
|
|
+
|
|
|
+ _fastShader=New TShader.Create( LoadString( "incbin::data/mojo2_fastshader.glsl" ) )
|
|
|
+ _bumpShader=New TBumpShader.Create( LoadString( "incbin::data/mojo2_bumpshader.glsl" ) )
|
|
|
+ _matteShader=New TMatteShader.Create( LoadString( "incbin::data/mojo2_matteshader.glsl" ) )
|
|
|
+ _shadowShader=New TShader.Create( LoadString( "incbin::data/mojo2_shadowshader.glsl" ) )
|
|
|
+ _lightMapShader=New TShader.Create( LoadString( "incbin::data/mojo2_lightmapshader.glsl" ) )
|
|
|
+ _defaultShader=_bumpShader
|
|
|
+
|
|
|
+ defaultFont=TFont.Load( "incbin::data/mojo2_font.png",32,96,True )'9,13,1,0,7,13,32,96 )
|
|
|
+ If Not defaultFont Throw "Can't load default font"
|
|
|
+
|
|
|
+ flipYMatrix[5]=-1
|
|
|
+End Function
|
|
|
+
|
|
|
+Public
|
|
|
+
|
|
|
+Type TRefCounted
|
|
|
+
|
|
|
+ Method Retain()
|
|
|
+ If _refs<=0 Throw "Internal error"
|
|
|
+ _refs:+1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Free()
|
|
|
+ If _refs<=0 Throw "Internal error"
|
|
|
+ _refs:-1
|
|
|
+ If _refs Return
|
|
|
+ _refs=-1
|
|
|
+ Destroy
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Destroy() Abstract
|
|
|
+
|
|
|
+ Field _refs:Int=1
|
|
|
+End Type
|
|
|
+
|
|
|
+'***** Texture *****
|
|
|
+
|
|
|
+rem
|
|
|
+bbdoc: Textures contains image data for use by shaders when rendering.
|
|
|
+about: For more information, please see the #TShader type.
|
|
|
+end rem
|
|
|
+Type TTexture Extends TRefCounted
|
|
|
+
|
|
|
+ 'flags
|
|
|
+ Const Filter:Int=1
|
|
|
+ Const Mipmap:Int=2
|
|
|
+ Const ClampS:Int=4
|
|
|
+ Const ClampT:Int=8
|
|
|
+ Const ClampST:Int=12
|
|
|
+ Const RenderTarget:Int=16
|
|
|
+ Const Managed:Int=256
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Creates a new texture.
|
|
|
+ about: The @width and @height are parameters are the size of the new texture.
|
|
|
+ The @format parameter must be 4.
|
|
|
+ The @flags parameter can be a bitwise combination of:
|
|
|
+ | @ Flags | @Description
|
|
|
+ | Texture.Filter | The texture is filtered when magnified
|
|
|
+ | Texture.Mipmap | The texture is mipmapped when minified
|
|
|
+ | Texture.ClampS | Texture S coordinate is clamped
|
|
|
+ | Texture.ClampT | Texture T coordinate is clamped
|
|
|
+ | Texture.ClampST | Texture S and T coordinates are clamped.
|
|
|
+ | Texture.RenderTarget | The texture can rendered to using a #Canvas.
|
|
|
+ | Texture.Managed | Texture contents are preserved when graphics are lost
|
|
|
+ End Rem
|
|
|
+ Method Create:TTexture( width:Int,height:Int,format:Int,flags:Int, data:TPixmap = Null )
|
|
|
+
|
|
|
+ If format<>PF_RGBA8888 Then
|
|
|
+ Throw "Invalid texture format: "+format
|
|
|
+ End If
|
|
|
+
|
|
|
+ 'can't mipmap NPOT textures on gles20
|
|
|
+ If Not IsPow2( width ) Or Not IsPow2( height ) flags:&~Mipmap
|
|
|
+
|
|
|
+ _width=width
|
|
|
+ _height=height
|
|
|
+ _format=format
|
|
|
+ _flags=flags
|
|
|
+ _data=data
|
|
|
+
|
|
|
+ If _flags & Managed
|
|
|
+ _managed=New TPixmap.Create( width,height,PF_RGBA8888 )
|
|
|
+ If _data
|
|
|
+ _managed.Paste( _data,0,0 )
|
|
|
+ _data=Null
|
|
|
+ Else
|
|
|
+ _managed.ClearPixels( $ffff00ff )
|
|
|
+ EndIf
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ Validate()
|
|
|
+
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Destroy()
|
|
|
+ If _seq=graphicsSeq glDeleteTextures 1, Varptr _glTexture
|
|
|
+ _glTexture=0
|
|
|
+ _glFramebuffer=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Gets texture width.
|
|
|
+ end rem
|
|
|
+ Method Width:Int()
|
|
|
+ Return _width
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Gets texture height.
|
|
|
+ end rem
|
|
|
+ Method Height:Int()
|
|
|
+ Return _height
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Gets texture format.
|
|
|
+ end rem
|
|
|
+ Method Format:Int()
|
|
|
+ Return _format
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Gets texture flags.
|
|
|
+ end rem
|
|
|
+ Method Flags:Int()
|
|
|
+ Return _flags
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Writes pixel data to texture.
|
|
|
+ about: Pixels should be in premultiplied alpha format.
|
|
|
+ end rem
|
|
|
+ Method WritePixels( x:Int,y:Int,width:Int,height:Int,data:TPixmap,dataOffset:Int=0,dataPitch:Int=0 )
|
|
|
+
|
|
|
+ glPushTexture2d GLTexture()
|
|
|
+
|
|
|
+ If Not dataPitch Or dataPitch=width*4
|
|
|
+
|
|
|
+ glTexSubImage2D GL_TEXTURE_2D,0,x,y,width,height,GL_RGBA,GL_UNSIGNED_BYTE,data.pixels + dataOffset
|
|
|
+
|
|
|
+ Else
|
|
|
+ For Local iy:Int=0 Until height
|
|
|
+ glTexSubImage2D GL_TEXTURE_2D,0,x,y+iy,width,1,GL_RGBA,GL_UNSIGNED_BYTE,data.pixels + dataOffset+iy*dataPitch
|
|
|
+ Next
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ glPopTexture2d
|
|
|
+
|
|
|
+ If _flags & Managed
|
|
|
+
|
|
|
+ Local texPitch:Int=_width*4
|
|
|
+ If Not dataPitch dataPitch=width*4
|
|
|
+
|
|
|
+ For Local iy:Int=0 Until height
|
|
|
+ MemCopy _data.pixels + (y+iy)*texPitch+x*4, data.pixels + dataOffset+iy*dataPitch, width*4
|
|
|
+ Next
|
|
|
+
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetData( x:Int,y:Int,pixmap:TPixmap )
|
|
|
+
|
|
|
+ If _managed
|
|
|
+ If pixmap<>_managed _managed.Paste( pixmap,x,y )
|
|
|
+ Else If _data
|
|
|
+ If pixmap<>_data Throw "Texture is read only"
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ glPushTexture2d( GLTexture() )
|
|
|
+
|
|
|
+ Local width:Int=pixmap.Width
|
|
|
+ Local height:Int=pixmap.Height
|
|
|
+
|
|
|
+ If pixmap.Pitch=_width*4
|
|
|
+
|
|
|
+ glTexSubImage2D( GL_TEXTURE_2D,0,x,y,width,height,GL_RGBA,GL_UNSIGNED_BYTE,pixmap.pixels )
|
|
|
+
|
|
|
+ Else
|
|
|
+
|
|
|
+ For Local iy:Int=0 Until height
|
|
|
+ glTexSubImage2D( GL_TEXTURE_2D,0,x,y+iy,width,1,GL_RGBA,GL_UNSIGNED_BYTE,pixmap.PixelPtr( 0,iy ) )
|
|
|
+ Next
|
|
|
+
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ glPopTexture2d
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method UpdateMipmaps()
|
|
|
+ If Not (_flags & Mipmap) Return
|
|
|
+
|
|
|
+ If _seq<>graphicsSeq
|
|
|
+ Validate()
|
|
|
+ Return
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ glPushTexture2d GLTexture()
|
|
|
+
|
|
|
+ glGenerateMipmap GL_TEXTURE_2D
|
|
|
+
|
|
|
+ glPopTexture2d
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Loading:Int()
|
|
|
+ Return False
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GLTexture:Int()
|
|
|
+ Validate
|
|
|
+ Return _glTexture
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GLFramebuffer:Int()
|
|
|
+ Validate
|
|
|
+ Return _glFramebuffer
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Function TexturesLoading:Int()
|
|
|
+ Return 0
|
|
|
+ End Function
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Loads a texture from a url.
|
|
|
+ end rem
|
|
|
+ Function Load:TTexture( url:Object,format:Int=PF_RGBA8888,flags:Int=Filter|Mipmap|ClampST )
|
|
|
+
|
|
|
+ Local info:Int[2]
|
|
|
+
|
|
|
+ Local data:TPixmap=LoadPixmap(url)
|
|
|
+ If Not data Return Null
|
|
|
+
|
|
|
+ ' convert to RGBA
|
|
|
+ If data.format <> format Then
|
|
|
+ data = data.Convert(format)
|
|
|
+ End If
|
|
|
+
|
|
|
+ PremultiplyAlpha(data)
|
|
|
+
|
|
|
+ Local tex:TTexture=New TTexture.Create( data.width,data.height,format,flags,data )
|
|
|
+
|
|
|
+ Return tex
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Function PremultiplyAlpha(pix:TPixmap)
|
|
|
+ For Local y:Int=0 Until pix.height
|
|
|
+ For Local x:Int=0 Until pix.width
|
|
|
+ Local pixel:Int=pix.ReadPixel( x,y )
|
|
|
+ Local a:Int=pixel Shr 24 & 255
|
|
|
+ Local b:Int=(pixel Shr 16 & 255)*a/255
|
|
|
+ Local g:Int=(pixel Shr 8 & 255)*a/255
|
|
|
+ Local r:Int=(pixel & 255)*a/255
|
|
|
+ pixel=a Shl 24 | b Shl 16 | g Shl 8 | r
|
|
|
+ pix.WritePixel( x,y,pixel )
|
|
|
+ Next
|
|
|
+ Next
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Function Color:TTexture( color:Int )
|
|
|
+ Local tex:TTexture=TTexture(_colors.ValueForKey( color ))
|
|
|
+ If tex Return tex
|
|
|
+
|
|
|
+ Local pixmap:TPixmap=New TPixmap.Create( 1,1,PF_RGBA8888 )
|
|
|
+ pixmap.ClearPixels( color )
|
|
|
+
|
|
|
+ tex=New TTexture.Create( 1,1,PF_RGBA8888,ClampST,pixmap )
|
|
|
+ _colors.Insert color,tex
|
|
|
+ Return tex
|
|
|
+ End Function
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Returns a stock single texel black texture.
|
|
|
+ end rem
|
|
|
+ Function Black:TTexture()
|
|
|
+ If Not _black _black=Color( $ff000000 )
|
|
|
+ Return _black
|
|
|
+ End Function
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Returns a stock single texel white texture.
|
|
|
+ end rem
|
|
|
+ Function White:TTexture()
|
|
|
+ If Not _white _white=Color( $ffffffff )
|
|
|
+ Return _white
|
|
|
+ End Function
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Returnss a stock single texel magenta texture.
|
|
|
+ end rem
|
|
|
+ Function Magenta:TTexture()
|
|
|
+ If Not _magenta _magenta=Color( $ffff00ff )
|
|
|
+ Return _magenta
|
|
|
+ End Function
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Returns a stock single texel 'flat' texture for normal mapping.
|
|
|
+ end rem
|
|
|
+ Function Flat:TTexture()
|
|
|
+ If Not _flat _flat=Color( $ff888888 )
|
|
|
+ Return _flat
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Private
|
|
|
+
|
|
|
+ Field _seq:Int
|
|
|
+ Field _width:Int
|
|
|
+ Field _height:Int
|
|
|
+ Field _format:Int
|
|
|
+ Field _flags:Int
|
|
|
+ Field _data:TPixmap
|
|
|
+ Field _managed:TPixmap
|
|
|
+
|
|
|
+ Field _glTexture:Int
|
|
|
+ Field _glFramebuffer:Int
|
|
|
+
|
|
|
+ Global _colors:TIntMap=New TIntMap'<TTexture>
|
|
|
+ Global _black:TTexture
|
|
|
+ Global _white:TTexture
|
|
|
+ Global _magenta:TTexture
|
|
|
+ Global _flat:TTexture
|
|
|
+
|
|
|
+ Method Validate()
|
|
|
+
|
|
|
+ If _seq=graphicsSeq Return
|
|
|
+
|
|
|
+ InitMojo2()
|
|
|
+
|
|
|
+ _seq=graphicsSeq
|
|
|
+
|
|
|
+ glGenTextures(1, Varptr _glTexture)
|
|
|
+
|
|
|
+ glPushTexture2d _glTexture
|
|
|
+
|
|
|
+ If _flags & Filter
|
|
|
+ glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
|
|
|
+ Else
|
|
|
+ glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
|
|
|
+ EndIf
|
|
|
+ If (_flags & Mipmap) And (_flags & Filter)
|
|
|
+ glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR
|
|
|
+ Else If _flags & Mipmap
|
|
|
+ glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST
|
|
|
+ Else If _flags & Filter
|
|
|
+ glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
|
|
|
+ Else
|
|
|
+ glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If _flags & ClampS glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
|
|
|
+ If _flags & ClampT glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
|
|
|
+
|
|
|
+ glTexImage2D GL_TEXTURE_2D,0,GL_RGBA,_width,_height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
|
|
|
+
|
|
|
+ glPopTexture2d
|
|
|
+
|
|
|
+ If _flags & RenderTarget
|
|
|
+
|
|
|
+ glGenFramebuffers(1, Varptr _glFramebuffer)
|
|
|
+
|
|
|
+ glPushFramebuffer _glFramebuffer
|
|
|
+
|
|
|
+ glBindFramebuffer GL_FRAMEBUFFER,_glFramebuffer
|
|
|
+ glFramebufferTexture2D GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,_glTexture,0
|
|
|
+
|
|
|
+ If glCheckFramebufferStatus( GL_FRAMEBUFFER )<>GL_FRAMEBUFFER_COMPLETE Throw "Incomplete framebuffer"
|
|
|
+
|
|
|
+ glPopFramebuffer
|
|
|
+
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If _managed Then
|
|
|
+
|
|
|
+ SetData( 0,0,_managed )
|
|
|
+ UpdateMipmaps()
|
|
|
+
|
|
|
+ Else If _data
|
|
|
+
|
|
|
+ SetData( 0,0,_data )
|
|
|
+ UpdateMipmaps()
|
|
|
+
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method LoadData( data:TPixmap )
|
|
|
+ glPushTexture2d GLTexture()
|
|
|
+
|
|
|
+ glTexImage2D GL_TEXTURE_2D,0,GL_RGBA,_width,_height,0,GL_RGBA,GL_UNSIGNED_BYTE,data.pixels
|
|
|
+
|
|
|
+ glPopTexture2d
|
|
|
+
|
|
|
+ UpdateMipmaps
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+'***** Shader ****
|
|
|
+
|
|
|
+Public
|
|
|
+
|
|
|
+Type TGLUniform
|
|
|
+ Field name:String
|
|
|
+ Field location:Int
|
|
|
+ Field size:Int
|
|
|
+ Field kind:Int
|
|
|
+
|
|
|
+ Method Create:TGLUniform( name:String,location:Int,size:Int,kind:Int )
|
|
|
+ Self.name=name
|
|
|
+ Self.location=location
|
|
|
+ Self.size=size
|
|
|
+ Self.kind=kind
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+Type TGLProgram
|
|
|
+ Field program:Int
|
|
|
+ 'material uniforms
|
|
|
+ Field matuniforms:TGLUniform[]
|
|
|
+ 'hard coded uniform locations
|
|
|
+ Field mvpMatrix:Int
|
|
|
+ Field mvMatrix:Int
|
|
|
+ Field clipPosScale:Int
|
|
|
+ Field globalColor:Int
|
|
|
+ Field AmbientLight:Int
|
|
|
+ Field fogColor:Int
|
|
|
+ Field lightColors:Int
|
|
|
+ Field lightVectors:Int
|
|
|
+ Field shadowTexture:Int
|
|
|
+
|
|
|
+ Method Create:TGLProgram( program:Int,matuniforms:TGLUniform[] )
|
|
|
+ Self.program=program
|
|
|
+ Self.matuniforms=matuniforms
|
|
|
+ mvpMatrix=glGetUniformLocation( program,"ModelViewProjectionMatrix" )
|
|
|
+ mvMatrix=glGetUniformLocation( program,"ModelViewMatrix" )
|
|
|
+ clipPosScale=glGetUniformLocation( program,"ClipPosScale" )
|
|
|
+ globalColor=glGetUniformLocation( program,"GlobalColor" )
|
|
|
+ fogColor=glGetUniformLocation( program,"FogColor" )
|
|
|
+ AmbientLight=glGetUniformLocation( program,"AmbientLight" )
|
|
|
+ lightColors=glGetUniformLocation( program,"LightColors" )
|
|
|
+ lightVectors=glGetUniformLocation( program,"LightVectors" )
|
|
|
+ shadowTexture=glGetUniformLocation( program,"ShadowTexture" )
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Bind()
|
|
|
+
|
|
|
+ glUseProgram program
|
|
|
+
|
|
|
+ If mvpMatrix<>-1 glUniformMatrix4fv mvpMatrix,1,False,rs_modelViewProjMatrix
|
|
|
+ If mvMatrix<>-1 glUniformMatrix4fv mvMatrix,1,False,rs_modelViewMatrix
|
|
|
+ If clipPosScale<>-1 glUniform4fv clipPosScale,1,rs_clipPosScale
|
|
|
+ If globalColor<>-1 glUniform4fv globalColor,1,rs_globalColor
|
|
|
+ If fogColor<>-1 glUniform4fv fogColor,1,rs_fogColor
|
|
|
+ If AmbientLight<>-1 glUniform4fv AmbientLight,1,rs_ambientLight
|
|
|
+ If lightColors<>-1 glUniform4fv lightColors,rs_numLights,rs_lightColors
|
|
|
+ If lightVectors<>-1 glUniform4fv lightVectors,rs_numLights,rs_lightVectors
|
|
|
+ glActiveTexture GL_TEXTURE0+7
|
|
|
+ If shadowTexture<>-1 And rs_shadowTexture
|
|
|
+ glBindTexture GL_TEXTURE_2D,rs_shadowTexture.GLTexture()
|
|
|
+ glUniform1i shadowTexture,7
|
|
|
+ Else
|
|
|
+ glBindTexture GL_TEXTURE_2D,TTexture.White().GLTexture()
|
|
|
+ End If
|
|
|
+ glActiveTexture GL_TEXTURE0
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+Public
|
|
|
+
|
|
|
+Type TShader
|
|
|
+
|
|
|
+ Method Create:TShader( source:String )
|
|
|
+ Build source
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method DefaultMaterial:TMaterial()
|
|
|
+ If Not _defaultMaterial _defaultMaterial=New TMaterial.Create( Self )
|
|
|
+ Return _defaultMaterial
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Function FastShader:TShader()
|
|
|
+ Return _fastShader
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Returns a stock bump shader for drawing lit sprites with specular and normal maps.
|
|
|
+ about:
|
|
|
+The following material properties are supported:
|
|
|
+
|
|
|
+| @Property | @Type | @Default
|
|
|
+| ColorTexture | Texture | White
|
|
|
+| SpecularTexture | Texture | Black
|
|
|
+| NormalTexture | Texture | Flat
|
|
|
+| AmbientColor | Float[4] | [0.0,0.0,0.0,1.0]
|
|
|
+| Roughness | Float | 0.5
|
|
|
+
|
|
|
+The shader b3d_Ambient value is computed by multiplying ColorTexture by AmbientColor.
|
|
|
+
|
|
|
+The shader b3d_Diffuse value is computed by multiplying ColorTexture by 1-AmbientColor.
|
|
|
+
|
|
|
+When loading materials that use the bump shader, diffuse, specular and normal maps can be given the following files names:
|
|
|
+
|
|
|
+| @Texture map | @Valid paths
|
|
|
+| Diffuse | (FILE).(EXT) ; (FILE)_d.(EXT) ; (FILE)_diff.(EXT) ; (FILE)_diffuse.(EXT)
|
|
|
+| Specular | (FILE)_s.(EXT) ; (FILE)_spec.(EXT) ; (FILE)_specular.(EXT) ;(FILE)_SPECUALR.(EXT)
|
|
|
+| Normal | (FILE)_n.(EXT) ; (FILE)_norm.(EXT) ; (FILE)_normal.(EXT) ; (FILE)_NORMALS.(EXT)
|
|
|
+
|
|
|
+Where (FILE) is the filename component of the path provided to Material.Load or Image.Load, and (EXT) is the file extension, eg: png, jpg.
|
|
|
+ end rem
|
|
|
+ Function BumpShader:TShader()
|
|
|
+ Return _bumpShader
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Returns a stock matte shader for drawing lit sprites with no specular or normal maps.
|
|
|
+ about:
|
|
|
+The following material properties are supported:
|
|
|
+
|
|
|
+| @Property | @Type | @Default
|
|
|
+| ColorTexture | Texture | White
|
|
|
+| AmbientColor | Float[4] | [0.0,0.0,0.0,1.0]
|
|
|
+| Roughness | Float | 0.5
|
|
|
+ end rem
|
|
|
+ Function MatteShader:TShader()
|
|
|
+ Return _matteShader
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Returns a stock shadow shader for drawing shadows.
|
|
|
+ about: This shader simply writes 'black' to b3d_FragColor.
|
|
|
+ end rem
|
|
|
+ Function ShadowShader:TShader()
|
|
|
+ Return _shadowShader
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Returns a stock shader for drawing light textures and light mask effects.
|
|
|
+ about:
|
|
|
+This shader performs a texture lookup, and writes the red component to b3d_FragColor.
|
|
|
+
|
|
|
+The following material properties are supported:
|
|
|
+
|
|
|
+| @Property | @Type | @Default
|
|
|
+| ColorTexture | Texture | White
|
|
|
+ end rem
|
|
|
+ Function LightMapShader:TShader()
|
|
|
+ Return _lightMapShader
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Returns the default shader used when a material is created with a 'Null' shader.
|
|
|
+ about: This is initially the #BumpShader, but can be modified using #SetDefaultShader.
|
|
|
+ end rem
|
|
|
+ Function DefaultShader:TShader()
|
|
|
+ Return _defaultShader
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Sets the default shader used when a material is created with a 'Null' shader.
|
|
|
+ end rem
|
|
|
+ Function SetDefaultShader( shader:TShader )
|
|
|
+ If Not shader shader=_bumpShader
|
|
|
+ _defaultShader=shader
|
|
|
+ End Function
|
|
|
+
|
|
|
+ 'Protected
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Compiles and links the shader.
|
|
|
+ about: Types that extend Shader must call this method at some point. This is usually done in the subclasses constructor.
|
|
|
+ end rem
|
|
|
+ Method Build( source:String )
|
|
|
+ _source=source
|
|
|
+ BuildInit
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Types that extend Shader must set defalut values for all valid shader parameters in this method.
|
|
|
+ end rem
|
|
|
+ Method OnInitMaterial( material:TMaterial )
|
|
|
+ material.SetTexture "ColorTexture",TTexture.White()
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Classes that extend Shader should load textures and other valid shader parameters from @path into @material in this method.
|
|
|
+ about: The interpretation of @path is completely up to the shader. The @texFlags parameter contains texture flag values that should be used for any textures loaded.
|
|
|
+ The @material parameter is an already initialized material.
|
|
|
+ This method should return @material if successful, or null on failure.
|
|
|
+ end rem
|
|
|
+ Method OnLoadMaterial:TMaterial( material:TMaterial,path:String,texFlags:Int )
|
|
|
+ Local texture:TTexture=TTexture.Load( path,4,texFlags )
|
|
|
+ If Not texture Return Null
|
|
|
+ material.SetTexture "ColorTexture",texture
|
|
|
+ If texture texture.Free
|
|
|
+ Return material
|
|
|
+ End Method
|
|
|
+
|
|
|
+ 'Private
|
|
|
+
|
|
|
+ Const MAX_FLAGS:Int=8
|
|
|
+
|
|
|
+ Field _seq:Int
|
|
|
+ Field _source:String
|
|
|
+
|
|
|
+ Field _vsource:String
|
|
|
+ Field _fsource:String
|
|
|
+ Field _uniforms:TStringMap=New TStringMap
|
|
|
+
|
|
|
+ Field _glPrograms:TGLProgram[MAX_LIGHTS+1]
|
|
|
+
|
|
|
+ Field _defaultMaterial:TMaterial
|
|
|
+
|
|
|
+ Method Bind()
|
|
|
+ Local program:TGLProgram=GLProgram()
|
|
|
+
|
|
|
+ If program=rs_program Return
|
|
|
+
|
|
|
+ rs_program=program
|
|
|
+ rs_material=Null
|
|
|
+
|
|
|
+ program.Bind
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GLProgram:TGLProgram()
|
|
|
+
|
|
|
+ If _seq<>graphicsSeq
|
|
|
+ _seq=graphicsSeq
|
|
|
+ rs_program=Null
|
|
|
+ BuildInit
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ Return _glPrograms[rs_numLights]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method BuildProgram:TGLProgram( numLights:Int )
|
|
|
+
|
|
|
+ Local defs:String=""
|
|
|
+ defs:+"#define NUM_LIGHTS "+numLights+"~n"
|
|
|
+
|
|
|
+ Local vshader:Int=glCompile( GL_VERTEX_SHADER,defs+_vsource )
|
|
|
+ Local fshader:Int=glCompile( GL_FRAGMENT_SHADER,defs+_fsource )
|
|
|
+
|
|
|
+ Local program:Int=glCreateProgram()
|
|
|
+ glAttachShader program,vshader
|
|
|
+ glAttachShader program,fshader
|
|
|
+ glDeleteShader vshader
|
|
|
+ glDeleteShader fshader
|
|
|
+
|
|
|
+ glBindAttribLocation program,0,"Position"
|
|
|
+ glBindAttribLocation program,1,"Texcoord0"
|
|
|
+ glBindAttribLocation program,2,"Tangent"
|
|
|
+ glBindAttribLocation program,3,"Color"
|
|
|
+
|
|
|
+ glLink program
|
|
|
+
|
|
|
+ 'enumerate program uniforms
|
|
|
+ Local matuniforms:TGLUniform[] = New TGLUniform[0]
|
|
|
+ Local size:Int
|
|
|
+ Local kind:Int
|
|
|
+ Local buf:Byte[1024]
|
|
|
+ Local l:Int
|
|
|
+ glGetProgramiv program,GL_ACTIVE_UNIFORMS,tmpi
|
|
|
+ For Local i:Int=0 Until tmpi[0]
|
|
|
+ glGetActiveUniform program,i,1024,Varptr l,Varptr size, Varptr kind, buf
|
|
|
+ Local name:String = String.FromBytes(buf, l)
|
|
|
+ If _uniforms.Contains( name )
|
|
|
+ Local location:Int=glGetUniformLocation( program,name )
|
|
|
+ If location=-1 Continue 'IE fix...
|
|
|
+ matuniforms :+ [New TGLUniform.Create( name,location,size,kind )]
|
|
|
+' Print name[0]+"->"+location
|
|
|
+ EndIf
|
|
|
+ Next
|
|
|
+
|
|
|
+ Return New TGLProgram.Create( program,matuniforms )
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method BuildInit()
|
|
|
+ InitMojo2
|
|
|
+
|
|
|
+ Local p:TGlslParser=TGlslParser(New TGlslParser.Create( _source ))
|
|
|
+
|
|
|
+ Local vars:TMap=New TMap
|
|
|
+
|
|
|
+ While p.Toke
|
|
|
+
|
|
|
+ If p.CParse( "uniform" )
|
|
|
+ 'uniform decl
|
|
|
+ Local ty:String=p.ParseType()
|
|
|
+ Local id:String=p.ParseIdent()
|
|
|
+ p.ParseToke ";"
|
|
|
+ _uniforms.Insert id, id
|
|
|
+' Print "uniform "+ty+" "+id+";"
|
|
|
+ Continue
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ Local id:String=p.CParseIdent()
|
|
|
+ If id
|
|
|
+ If id.StartsWith( "gl_" )
|
|
|
+ vars.Insert "B3D_"+id.ToUpper(), ""
|
|
|
+ Else If id.StartsWith( "b3d_" )
|
|
|
+ vars.Insert id.ToUpper(), ""
|
|
|
+ EndIf
|
|
|
+ Continue
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ p.Bump
|
|
|
+ Wend
|
|
|
+
|
|
|
+ Local vardefs:String=""
|
|
|
+ For Local v:String=EachIn vars.Keys()
|
|
|
+ vardefs:+"#define "+v+" 1~n"
|
|
|
+ Next
|
|
|
+
|
|
|
+' Print "Vardefs:";Print vardefs
|
|
|
+
|
|
|
+ Local source:String=mainShader
|
|
|
+ Local i0:Int=source.Find( "//@vertex" )
|
|
|
+ If i0=-1 Throw "Can't find //@vertex chunk"
|
|
|
+ Local i1:Int=source.Find( "//@fragment" )
|
|
|
+ If i1=-1 Throw "Can't find //@fragment chunk"
|
|
|
+
|
|
|
+ Local header:String=vardefs+source[..i0]
|
|
|
+ _vsource=header+source[i0..i1]
|
|
|
+ _fsource=header+source[i1..].Replace( "${SHADER}",_source )
|
|
|
+
|
|
|
+ For Local numLights:Int=0 To MAX_LIGHTS
|
|
|
+
|
|
|
+ _glPrograms[numLights]=BuildProgram( numLights )
|
|
|
+
|
|
|
+ If numLights Or vars.Contains( "B3D_DIFFUSE" ) Or vars.Contains( "B3D_SPECULAR" ) Continue
|
|
|
+
|
|
|
+ For Local i:Int=1 To MAX_LIGHTS
|
|
|
+ _glPrograms[i]=_glPrograms[0]
|
|
|
+ Next
|
|
|
+
|
|
|
+ Exit
|
|
|
+
|
|
|
+ Next
|
|
|
+
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+Type TBumpShader Extends TShader
|
|
|
+
|
|
|
+' Method New( source:String )
|
|
|
+' Super.New( source )
|
|
|
+' End
|
|
|
+
|
|
|
+ 'Protected
|
|
|
+
|
|
|
+ Method OnInitMaterial( material:TMaterial )
|
|
|
+ material.SetTexture "ColorTexture",TTexture.White()
|
|
|
+ material.SetTexture "SpecularTexture",TTexture.Black()
|
|
|
+ material.SetTexture "NormalTexture",TTexture.Flat()
|
|
|
+ material.SetVector "AmbientColor",[1.0,1.0,1.0,1.0]
|
|
|
+ material.SetScalar "Roughness",1.0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method OnLoadMaterial:TMaterial( material:TMaterial,path:String,texFlags:Int )
|
|
|
+
|
|
|
+ Local format:Int = PF_RGBA8888
|
|
|
+
|
|
|
+ Local ext:String = ExtractExt( path )
|
|
|
+ If ext path=StripExt( path ) Else ext="png"
|
|
|
+
|
|
|
+ Local colorTex:TTexture=TTexture.Load( path+"."+ext,format,texFlags )
|
|
|
+ If Not colorTex colorTex=TTexture.Load( path+"_d."+ext,format,texFlags )
|
|
|
+ If Not colorTex colorTex=TTexture.Load( path+"_diff."+ext,format,texFlags )
|
|
|
+ If Not colorTex colorTex=TTexture.Load( path+"_diffuse."+ext,format,texFlags )
|
|
|
+
|
|
|
+ Local specularTex:TTexture=TTexture.Load( path+"_s."+ext,format,texFlags )
|
|
|
+ If Not specularTex specularTex=TTexture.Load( path+"_spec."+ext,format,texFlags )
|
|
|
+ If Not specularTex specularTex=TTexture.Load( path+"_specular."+ext,format,texFlags )
|
|
|
+ If Not specularTex specularTex=TTexture.Load( path+"_SPECULAR."+ext,format,texFlags )
|
|
|
+
|
|
|
+ Local normalTex:TTexture=TTexture.Load( path+"_n."+ext,format,texFlags )
|
|
|
+ If Not normalTex normalTex=TTexture.Load( path+"_norm."+ext,format,texFlags )
|
|
|
+ If Not normalTex normalTex=TTexture.Load( path+"_normal."+ext,format,texFlags )
|
|
|
+ If Not normalTex normalTex=TTexture.Load( path+"_NORMALS."+ext,format,texFlags )
|
|
|
+
|
|
|
+ If Not colorTex And Not specularTex And Not normalTex Return Null
|
|
|
+
|
|
|
+ material.SetTexture "ColorTexture",colorTex
|
|
|
+ material.SetTexture "SpecularTexture",specularTex
|
|
|
+ material.SetTexture "NormalTexture",normalTex
|
|
|
+
|
|
|
+ If specularTex Or normalTex
|
|
|
+ material.SetVector "AmbientColor",[0.0,0.0,0.0,1.0]
|
|
|
+ material.SetScalar "Roughness",.5
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If colorTex colorTex.Free
|
|
|
+ If specularTex specularTex.Free
|
|
|
+ If normalTex normalTex.Free
|
|
|
+
|
|
|
+ Return material
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+Type TMatteShader Extends TShader
|
|
|
+
|
|
|
+' Method Create( source:String )
|
|
|
+' Super.New( source )
|
|
|
+' End
|
|
|
+
|
|
|
+' Protected
|
|
|
+
|
|
|
+ Method OnInitMaterial( material:TMaterial )
|
|
|
+ material.SetTexture "ColorTexture",TTexture.White()
|
|
|
+ material.SetVector "AmbientColor",[0.0,0.0,0.0,1.0]
|
|
|
+ material.SetScalar "Roughness",1.0
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+'***** Material *****
|
|
|
+
|
|
|
+Rem
|
|
|
+bbdoc: Materials contain shader parameters that map to shader uniforms variables when rendering.
|
|
|
+End Rem
|
|
|
+Type TMaterial Extends TRefCounted
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Creates a new material.
|
|
|
+ End Rem
|
|
|
+ Method Create:TMaterial( shader:TShader=Null )
|
|
|
+ InitMojo2
|
|
|
+
|
|
|
+ If Not shader shader=_defaultShader
|
|
|
+ _shader=shader
|
|
|
+ _shader.OnInitMaterial( Self )
|
|
|
+ _inited=True
|
|
|
+
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Destroy()
|
|
|
+ For Local tex:TTexture=EachIn _textures
|
|
|
+ tex.Free()
|
|
|
+ Next
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Gets material shader.
|
|
|
+ End Rem
|
|
|
+ Method Shader:TShader()
|
|
|
+ Return _shader
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ColorTexture:TTexture()
|
|
|
+ Return _colorTexture
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Width:Int()
|
|
|
+ If _colorTexture Return _colorTexture._width
|
|
|
+ Return 0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Height:Int()
|
|
|
+ If _colorTexture Return _colorTexture._height
|
|
|
+ Return 0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Sets float shader parameter.
|
|
|
+ End Rem
|
|
|
+ Method SetScalar( param:String,scalar:Float )
|
|
|
+ If _inited And Not _scalars.Contains( param ) Return
|
|
|
+ _scalars.Insert param,scalar
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Gets float shader parameter.
|
|
|
+ End Rem
|
|
|
+ Method GetScalar:Float( param:String,defValue:Float=1.0 )
|
|
|
+ If Not _scalars.Contains( param ) Return defValue
|
|
|
+ Return _scalars.ValueForKey( param )
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Sets vector shader parameter.
|
|
|
+ End Rem
|
|
|
+ Method SetVector( param:String,vector:Float[] )
|
|
|
+ If _inited And Not _vectors.Contains( param ) Return
|
|
|
+ _vectors.Insert param,vector
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Gets vector shader parameter.
|
|
|
+ End Rem
|
|
|
+ Method GetVector:Float[]( param:String,defValue:Float[]=[1.0,1.0,1.0,1.0] )
|
|
|
+ If Not _vectors.Contains( param ) Return defValue
|
|
|
+ Return _vectors.ValueForKey( param )
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Sets texture shader parameter.
|
|
|
+ End Rem
|
|
|
+ Method SetTexture( param:String,texture:TTexture )
|
|
|
+ If Not texture Return
|
|
|
+ If _inited And Not _textures.Contains( param ) Return
|
|
|
+
|
|
|
+ Local old:TTexture=TTexture(_textures.ValueForKey( param ))
|
|
|
+ texture.Retain
|
|
|
+ _textures.Insert param,texture
|
|
|
+ If old old.Free
|
|
|
+
|
|
|
+ If param="ColorTexture" _colorTexture=texture
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Gets texture shader parameter.
|
|
|
+ End Rem
|
|
|
+ Method GetTexture:TTexture( param:String,defValue:TTexture=Null )
|
|
|
+ If Not _textures.Contains( param ) Return defValue
|
|
|
+ Return TTexture(_textures.ValueForKey( param ))
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Loading:Int()
|
|
|
+ Return False
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Loads a material.
|
|
|
+ about: If @shader is null, the TShader.DefaultShader is used.
|
|
|
+ End Rem
|
|
|
+ Function Load:TMaterial( path:String,texFlags:Int,shader:TShader )
|
|
|
+
|
|
|
+ Local material:TMaterial=New TMaterial.Create( shader )
|
|
|
+
|
|
|
+ material=material.Shader.OnLoadMaterial( material,path,texFlags )
|
|
|
+
|
|
|
+ Return material
|
|
|
+ End Function
|
|
|
+
|
|
|
+ 'Private
|
|
|
+
|
|
|
+ Field _shader:TShader
|
|
|
+ Field _colorTexture:TTexture
|
|
|
+ Field _scalars:TStringFloatMap=New TStringFloatMap
|
|
|
+ Field _vectors:TStringMap=New TStringMap
|
|
|
+ Field _textures:TStringMap=New TStringMap
|
|
|
+ Field _inited:Int
|
|
|
+
|
|
|
+ Method Bind:Int()
|
|
|
+
|
|
|
+ _shader.Bind
|
|
|
+
|
|
|
+ If rs_material=Self Return True
|
|
|
+
|
|
|
+ rs_material=Self
|
|
|
+
|
|
|
+ Local texid:Int=0
|
|
|
+
|
|
|
+ For Local u:TGLUniform=EachIn rs_program.matuniforms
|
|
|
+ Select u.kind
|
|
|
+ Case GL_FLOAT
|
|
|
+ glUniform1f u.location,GetScalar( u.name )
|
|
|
+ Case GL_FLOAT_VEC4
|
|
|
+ glUniform4fv u.location,1,GetVector( u.name )
|
|
|
+ Case GL_SAMPLER_2D
|
|
|
+ Local tex:TTexture=GetTexture( u.name )
|
|
|
+' If tex.Loading
|
|
|
+' rs_material=Null
|
|
|
+' Exit
|
|
|
+' Endif
|
|
|
+ glActiveTexture GL_TEXTURE0+texid
|
|
|
+ glBindTexture GL_TEXTURE_2D,tex.GLTexture()
|
|
|
+ glUniform1i u.location,texid
|
|
|
+ texid:+1
|
|
|
+ Default
|
|
|
+ Throw "Unsupported uniform type:"+u.kind
|
|
|
+ End Select
|
|
|
+ Next
|
|
|
+
|
|
|
+ If texid glActiveTexture GL_TEXTURE0
|
|
|
+
|
|
|
+ Return rs_material=Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+'***** ShaderCaster *****
|
|
|
+
|
|
|
+Rem
|
|
|
+bbdoc: The ShadowCaster class provides support for simple 2d shadow rendering.
|
|
|
+about: Shadow casters are used by #Renderer objects when rendering layers. To render shadows, you will need to add
|
|
|
+shadow casters to the drawlists returned by ILayer.OnRenderLayer.
|
|
|
+A shadow caster can either be added to a drawlist using [[DrawList.AddShadowCaster]], or attached to images using [[Image.SetShadowCaster]]. Shadow casters attached to images are automatically added to drawlists when an image is drawn.
|
|
|
+A shadow caster contains a set of 2d vertices which describe the geometric shape of the object that casts a shadow. The vertices should describe a convex polygon.
|
|
|
+End Rem
|
|
|
+Type TShadowCaster
|
|
|
+
|
|
|
+ Method Create:TShadowCaster( verts:Float[] = Null,kind:Int = -1 )
|
|
|
+ If verts Then
|
|
|
+ _verts=verts
|
|
|
+ End If
|
|
|
+ If kind >= 0 Then
|
|
|
+ _kind=kind
|
|
|
+ End If
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Set shadow caster vertices.
|
|
|
+ end rem
|
|
|
+ Method SetVertices( vertices:Float[] )
|
|
|
+ _verts=vertices
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Get shadow caster vertices.
|
|
|
+ end rem
|
|
|
+ Method Vertices:Float[]()
|
|
|
+ Return _verts
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetKind( kind:Int )
|
|
|
+ _kind=kind
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Kind:Int()
|
|
|
+ Return _kind
|
|
|
+ End Method
|
|
|
+
|
|
|
+ 'Private
|
|
|
+
|
|
|
+ Field _verts:Float[]
|
|
|
+ Field _kind:Int
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+'***** Image *****
|
|
|
+
|
|
|
+Rem
|
|
|
+bbdoc: An image is a rectangular area of pixels within a material, that can be drawn using one of the [[DrawList.DrawImage]] methods.
|
|
|
+about: You can create a new image using one of the [[Image.Create]] methods, or load an image from file using [[Image.Load|Image.Load]].
|
|
|
+An image also has a handle, an offset within the image that represents it's origin whan it is drawn. Image handles are specified in fractional values, where 0,0 is the top-left of an image, 1,1 is the bottom-right and .5,.5 is the center.
|
|
|
+end rem
|
|
|
+Type TImage
|
|
|
+
|
|
|
+ Const Filter:Int=TTexture.Filter
|
|
|
+ Const Mipmap:Int=TTexture.Mipmap
|
|
|
+ Const Managed:Int=TTexture.Managed
|
|
|
+
|
|
|
+ Method Create:TImage( width:Int,height:Int,xhandle:Float=.5,yhandle:Float=.5,flags:Int=TImage.Filter )
|
|
|
+ flags:&_flagsMask
|
|
|
+ Local texture:TTexture=New TTexture.Create( width,height,PF_RGBA8888,flags|TTexture.ClampST|TTexture.RenderTarget )
|
|
|
+ _material=New TMaterial.Create( _fastShader )
|
|
|
+ _material.SetTexture "ColorTexture",texture
|
|
|
+ _width=width
|
|
|
+ _height=height
|
|
|
+ SetHandle xhandle,yhandle
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method CreateImage:TImage( image:TImage,x:Int,y:Int,width:Int,height:Int,xhandle:Float=.5,yhandle:Float=.5 )
|
|
|
+ _material=image._material
|
|
|
+ _material.Retain
|
|
|
+ _x=image._x+x
|
|
|
+ _y=image._y+y
|
|
|
+ _width=width
|
|
|
+ _height=height
|
|
|
+ SetHandle xhandle,yhandle
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method CreateMaterial:TImage( material:TMaterial,xhandle:Float=.5,yhandle:Float=.5 )
|
|
|
+ Local texture:TTexture=material.ColorTexture()
|
|
|
+ If Not texture Throw "Material has no ColorTexture"
|
|
|
+ _material=material
|
|
|
+ _material.Retain
|
|
|
+ _width=_material.Width
|
|
|
+ _height=_material.Height
|
|
|
+ SetHandle xhandle,yhandle
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method CreateMaterialSize:TImage( material:TMaterial,x:Int,y:Int,width:Int,height:Int,xhandle:Float=.5,yhandle:Float=.5 )
|
|
|
+ Local texture:TTexture=material.ColorTexture()
|
|
|
+ If Not texture Throw "Material has no ColorTexture"
|
|
|
+ _material=material
|
|
|
+ _material.Retain
|
|
|
+ _x=x
|
|
|
+ _y=y
|
|
|
+ _width=width
|
|
|
+ _height=height
|
|
|
+ SetHandle xhandle,yhandle
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Discard()
|
|
|
+ If _material _material.Free
|
|
|
+ _material=Null
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Material:TMaterial()
|
|
|
+ Return _material
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method X0:Float()
|
|
|
+ Return _x0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Y0:Float()
|
|
|
+ Return _y0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method X1:Float()
|
|
|
+ Return _x1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Y1:Float()
|
|
|
+ Return _y1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Width:Int()
|
|
|
+ Return _width
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Height:Int()
|
|
|
+ Return _height
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method HandleX:Float()
|
|
|
+ Return -_x0/(_x1-_x0)
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method HandleY:Float()
|
|
|
+ Return -_y0/(_y1-_y0)
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method WritePixels( x:Int,y:Int,width:Int,height:Int,data:TPixmap,dataOffset:Int=0,dataPitch:Int=0 )
|
|
|
+ _material.ColorTexture().WritePixels( x+_x,y+_y,width,height,data,dataOffset,dataPitch )
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetHandle( xhandle:Float,yhandle:Float )
|
|
|
+ _x0=Float(_width)*-xhandle
|
|
|
+ _x1=Float(_width)*(1-xhandle)
|
|
|
+ _y0=Float(_height)*-yhandle
|
|
|
+ _y1=Float(_height)*(1-yhandle)
|
|
|
+ _s0=Float(_x)/Float(_material.Width)
|
|
|
+ _t0=Float(_y)/Float(_material.Height)
|
|
|
+ _s1=Float(_x+_width)/Float(_material.Width)
|
|
|
+ _t1=Float(_y+_height)/Float(_material.Height)
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetShadowCaster( shadowCaster:TShadowCaster )
|
|
|
+ _caster=shadowCaster
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ShadowCaster:TShadowCaster()
|
|
|
+ Return _caster
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Loading:Int()
|
|
|
+ Return _material.Loading()
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Function ImagesLoading:Int()
|
|
|
+ Return TTexture.TexturesLoading>0
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Function SetFlagsMask( mask:Int )
|
|
|
+ _flagsMask=mask
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Function FlagsMask:Int()
|
|
|
+ Return _flagsMask
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Function Load:TImage( path:String,xhandle:Float=.5,yhandle:Float=.5,flags:Int=TImage.Filter|TImage.Mipmap,shader:TShader=Null )
|
|
|
+ flags:&_flagsMask
|
|
|
+
|
|
|
+ Local material:TMaterial=TMaterial.Load( path,flags|TTexture.ClampST,shader )
|
|
|
+ If Not material Return Null
|
|
|
+
|
|
|
+ Return New TImage.CreateMaterial( material,xhandle,yhandle )
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Function LoadFrames:TImage[]( path:String,numFrames:Int,padded:Int=False,xhandle:Float=.5,yhandle:Float=.5,flags:Int=TImage.Filter|TImage.Mipmap,shader:TShader=Null )
|
|
|
+ flags:&_flagsMask
|
|
|
+
|
|
|
+ Local material:TMaterial=TMaterial.Load( path,flags|TTexture.ClampST,shader )
|
|
|
+ If Not material Return Null
|
|
|
+
|
|
|
+ Local cellWidth:Int=material.Width/numFrames
|
|
|
+ Local cellHeight:Int=material.Height
|
|
|
+
|
|
|
+ Local x:Int=0
|
|
|
+ Local width:Int=cellWidth
|
|
|
+ If padded Then
|
|
|
+ x:+1
|
|
|
+ width:-2
|
|
|
+ End If
|
|
|
+
|
|
|
+ Local frames:TImage[]=New TImage[numFrames]
|
|
|
+
|
|
|
+ For Local i:Int=0 Until numFrames
|
|
|
+ frames[i]=New TImage.CreateMaterialSize( material,i*cellWidth+x,0,width,cellHeight,xhandle,yhandle )
|
|
|
+ Next
|
|
|
+
|
|
|
+ Return frames
|
|
|
+ End Function
|
|
|
+
|
|
|
+ 'Private
|
|
|
+
|
|
|
+ Global _flagsMask:Int=Filter|Mipmap|Managed
|
|
|
+
|
|
|
+ Field _material:TMaterial
|
|
|
+ Field _x:Int,_y:Int,_width:Int,_height:Int
|
|
|
+ Field _x0:Float=-1,_y0:Float=-1,_x1:Float=1,_y1:Float=1
|
|
|
+ Field _s0:Float=0 ,_t0:Float=0 ,_s1:Float=1,_t1:Float=1
|
|
|
+
|
|
|
+ Field _caster:TShadowCaster
|
|
|
+
|
|
|
+' Method SetFrame( x0:Float,y0:Float,x1:Float,y1:Float,s0:Float,t0:Float,s1:Float,t1:Float )
|
|
|
+' _x0=x0;_y0=y0;_x1=x1;_y1=y1
|
|
|
+' _s0=s0;_t0=t0;_s1=s1;_t1=t1
|
|
|
+' End
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+'***** Font *****
|
|
|
+
|
|
|
+Type TGlyph
|
|
|
+ Field image:TImage
|
|
|
+ Field char:Int
|
|
|
+ Field x:Int
|
|
|
+ Field y:Int
|
|
|
+ Field width:Int
|
|
|
+ Field height:Int
|
|
|
+ Field advance:Float
|
|
|
+
|
|
|
+ Method Create:TGlyph( image:TImage,char:Int,x:Int,y:Int,width:Int,height:Int,advance:Float )
|
|
|
+ Self.image=image
|
|
|
+ Self.char=char
|
|
|
+ Self.x=x
|
|
|
+ Self.y=y
|
|
|
+ Self.width=width
|
|
|
+ Self.height=height
|
|
|
+ Self.advance=advance
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+End Type
|
|
|
+
|
|
|
+Rem
|
|
|
+bbdoc: Provides support for simple fixed width bitmap fonts.
|
|
|
+End Rem
|
|
|
+Type TFont
|
|
|
+
|
|
|
+ Method Create:TFont( glyphs:TGlyph[],firstChar:Int,height:Float )
|
|
|
+ _glyphs=glyphs
|
|
|
+ _firstChar=firstChar
|
|
|
+ _height=height
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GetGlyph:TGlyph( char:Int )
|
|
|
+ Local i:Int=char-_firstChar
|
|
|
+ If i>=0 And i<_glyphs.Length Return _glyphs[i]
|
|
|
+ Return Null
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Gets width of @text drawn in this font.
|
|
|
+ End Rem
|
|
|
+ Method TextWidth:Float( Text:String )
|
|
|
+ Local w:Float=0.0
|
|
|
+ For Local char:Int=EachIn Text
|
|
|
+ Local glyph:TGlyph=GetGlyph( char )
|
|
|
+ If Not glyph Continue
|
|
|
+ w:+glyph.advance
|
|
|
+ Next
|
|
|
+ Return w
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Gets height of @text drawn in this font.
|
|
|
+ End Rem
|
|
|
+ Method TextHeight:Float( Text:String )
|
|
|
+ Return _height
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Loads a fixed width font from @path.
|
|
|
+ about: Glyphs should be laid out horizontally within the source image.
|
|
|
+ If @padded is true, then each glyph is assumed to have a transparent one pixel padding border around it.
|
|
|
+ End Rem
|
|
|
+ Function Load:TFont( path:String,firstChar:Int,numChars:Int,padded:Int )
|
|
|
+
|
|
|
+ Local image:TImage=TImage.Load( path )
|
|
|
+ If Not image Return Null
|
|
|
+
|
|
|
+ Local cellWidth:Int=image.Width/numChars
|
|
|
+ Local cellHeight:Int=image.Height
|
|
|
+ Local glyphX:Int=0,glyphY:Int=0,glyphWidth:Int=cellWidth,glyphHeight:Int=cellHeight
|
|
|
+ If padded glyphX:+1;glyphY:+1;glyphWidth:-2;glyphHeight:-2
|
|
|
+
|
|
|
+ Local w:Int=image.Width/cellWidth
|
|
|
+ Local h:Int=image.Height/cellHeight
|
|
|
+
|
|
|
+ Local glyphs:TGlyph[]=New TGlyph[numChars]
|
|
|
+
|
|
|
+ For Local i:Int=0 Until numChars
|
|
|
+ Local y:Int=i / w
|
|
|
+ Local x:Int=i Mod w
|
|
|
+ Local glyph:TGlyph=New TGlyph.Create( image,firstChar+i,x*cellWidth+glyphX,y*cellHeight+glyphY,glyphWidth,glyphHeight,glyphWidth )
|
|
|
+ glyphs[i]=glyph
|
|
|
+ Next
|
|
|
+
|
|
|
+ Return New TFont.Create( glyphs,firstChar,glyphHeight )
|
|
|
+
|
|
|
+ End Function
|
|
|
+
|
|
|
+ Function LoadSize:TFont( path:String,cellWidth:Int,cellHeight:Int,glyphX:Int,glyphY:Int,glyphWidth:Int,glyphHeight:Int,firstChar:Int,numChars:Int )
|
|
|
+
|
|
|
+ Local image:TImage=TImage.Load( path )
|
|
|
+ If Not image Return Null
|
|
|
+
|
|
|
+ Local w:Int=image.Width/cellWidth
|
|
|
+ Local h:Int=image.Height/cellHeight
|
|
|
+
|
|
|
+ Local glyphs:TGlyph[]=New TGlyph[numChars]
|
|
|
+
|
|
|
+ For Local i:Int=0 Until numChars
|
|
|
+ Local y:Int=i / w
|
|
|
+ Local x:Int=i Mod w
|
|
|
+ Local glyph:TGlyph=New TGlyph.Create( image,firstChar+i,x*cellWidth+glyphX,y*cellHeight+glyphY,glyphWidth,glyphHeight,glyphWidth )
|
|
|
+ glyphs[i]=glyph
|
|
|
+ Next
|
|
|
+
|
|
|
+ Return New TFont.Create( glyphs,firstChar,glyphHeight )
|
|
|
+ End Function
|
|
|
+
|
|
|
+ 'Private
|
|
|
+
|
|
|
+ Field _glyphs:TGlyph[]
|
|
|
+ Field _firstChar:Int
|
|
|
+ Field _height:Float
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+'***** DrawList *****
|
|
|
+
|
|
|
+Type TDrawOp
|
|
|
+' Field shader:Shader
|
|
|
+ Field material:TMaterial
|
|
|
+ Field blend:Int
|
|
|
+ Field order:Int
|
|
|
+ Field count:Int
|
|
|
+End Type
|
|
|
+
|
|
|
+Type TBlendMode
|
|
|
+ Const Opaque:Int=0
|
|
|
+ Const Alpha:Int=1
|
|
|
+ Const Additive:Int=2
|
|
|
+ Const Multiply:Int=3
|
|
|
+ Const Multiply2:Int=4
|
|
|
+End Type
|
|
|
+
|
|
|
+Rem
|
|
|
+bbdoc: A drawlist contains drawing state and a sequence of 2d drawing operations.
|
|
|
+about:
|
|
|
+You add drawing operations to a drawlist using any of the Draw methods. When a drawing operation is added, the current drawing state is captured by the drawing operation. Further changes to the drawing state will not affect drawing operations already in the drawlist.
|
|
|
+A [[Canvas]] extends [[DrawList]], and can be used to draw directly to the app window or an image. A drawlist can also be rendered to a canvas using [[Canvas.RenderDrawList]].
|
|
|
+A drawlist's drawing state consists of:
|
|
|
+| @Drawing state | @Description
|
|
|
+| Current color | [[SetColor]]
|
|
|
+| Current 2d matrix | [[Translate]], [[Rotate]], [[Scale]], [[PushMatrix]], [[PopMatrix]]
|
|
|
+| Current blend mode | [[SetBlendMode]]
|
|
|
+| Current font | [[DrawText]]
|
|
|
+End Rem
|
|
|
+Type TDrawList
|
|
|
+
|
|
|
+ Method New()
|
|
|
+ InitMojo2
|
|
|
+
|
|
|
+ _color = __colorArray
|
|
|
+
|
|
|
+ SetFont Null
|
|
|
+ SetDefaultMaterial _fastShader.DefaultMaterial
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetBlendMode( blend:Int )
|
|
|
+ _blend=blend
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method BlendMode:Int()
|
|
|
+ Return _blend
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetColor( r:Float,g:Float,b:Float,a:Float = -1 )
|
|
|
+ Local c:Float Ptr = _color
|
|
|
+ c[0]=r
|
|
|
+ c[1]=g
|
|
|
+ c[2]=b
|
|
|
+ If a >= 0
|
|
|
+ c[3]=a
|
|
|
+ _alpha=a*255
|
|
|
+ End If
|
|
|
+ _pmcolor=Int(_alpha) Shl 24 | Int(c[2]*_alpha) Shl 16 | Int(c[1]*_alpha) Shl 8 | Int(c[0]*_alpha)
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetAlpha( a:Float )
|
|
|
+ _color[3]=a
|
|
|
+ _alpha=a*255
|
|
|
+ _pmcolor=Int(_alpha) Shl 24 | Int(_color[2]*_alpha) Shl 16 | Int(_color[1]*_alpha) Shl 8 | Int(_color[0]*_alpha)
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Color:Float[]()
|
|
|
+ Return [_color[0],_color[1],_color[2],_color[3]]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GetColor( color:Float[] )
|
|
|
+ color[0]=_color[0]
|
|
|
+ color[1]=_color[1]
|
|
|
+ color[2]=_color[2]
|
|
|
+ If color.Length>3 color[3]=_color[3]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Alpha:Float()
|
|
|
+ Return _color[3]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Sets the current 2d matrix to the identity matrix.
|
|
|
+ about: Same as SetMatrix( 1,0,0,1,0,0 ).
|
|
|
+ end rem
|
|
|
+ Method ResetMatrix()
|
|
|
+ _ix=1;_iy=0
|
|
|
+ _jx=0;_jy=1
|
|
|
+ _tx=0;_ty=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Sets the current 2d matrix to the given matrix.
|
|
|
+ end rem
|
|
|
+ Method SetMatrix( ix:Float,iy:Float,jx:Float,jy:Float,tx:Float,ty:Float )
|
|
|
+ _ix=ix;_iy=iy
|
|
|
+ _jx=jx;_jy=jy
|
|
|
+ _tx=tx;_ty=ty
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Gets the current 2d matrix.
|
|
|
+ end rem
|
|
|
+ Method GetMatrix( matrix:Float[] )
|
|
|
+ matrix[0]=_ix
|
|
|
+ matrix[1]=_iy
|
|
|
+ matrix[2]=_jx
|
|
|
+ matrix[3]=_jy
|
|
|
+ matrix[4]=_tx
|
|
|
+ matrix[5]=_ty
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Multiplies the current 2d matrix by the given matrix.
|
|
|
+ end rem
|
|
|
+ Method Transform( ix:Float,iy:Float,jx:Float,jy:Float,tx:Float,ty:Float )
|
|
|
+ Local ix2:Float=ix*_ix+iy*_jx
|
|
|
+ Local iy2:Float=ix*_iy+iy*_jy
|
|
|
+ Local jx2:Float=jx*_ix+jy*_jx
|
|
|
+ Local jy2:Float=jx*_iy+jy*_jy
|
|
|
+ Local tx2:Float=tx*_ix+ty*_jx+_tx
|
|
|
+ Local ty2:Float=tx*_iy+ty*_jy+_ty
|
|
|
+ SetMatrix ix2,iy2,jx2,jy2,tx2,ty2
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Translates the current 2d matrix.
|
|
|
+ end rem
|
|
|
+ Method Translate( tx:Float,ty:Float )
|
|
|
+ Transform 1,0,0,1,tx,ty
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Rotates the current 2d matrix.
|
|
|
+ end rem
|
|
|
+ Method Rotate( rz:Float )
|
|
|
+ Transform Cos( rz ),-Sin( rz ),Sin( rz ),Cos( rz ),0,0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Scales the current 2d matrix.
|
|
|
+ end rem
|
|
|
+ Method Scale( sx:Float,sy:Float )
|
|
|
+ Transform sx,0,0,sy,0,0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Translates and rotates (in that order) the current 2d matrix.
|
|
|
+ end rem
|
|
|
+ Method TranslateRotate( tx:Float,ty:Float,rz:Float )
|
|
|
+ Translate tx,ty
|
|
|
+ Rotate rz
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Rotates and scales (in that order) the current 2d matrix.
|
|
|
+ end rem
|
|
|
+ Method RotateScale( rz:Float,sx:Float,sy:Float )
|
|
|
+ Rotate rz
|
|
|
+ Scale sx,sy
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method TranslateScale( tx:Float,ty:Float,sx:Float,sy:Float )
|
|
|
+ Translate tx,ty
|
|
|
+ Scale sx,sy
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Translates, rotates and scales (in that order) the current 2d matrix.
|
|
|
+ end rem
|
|
|
+ Method TranslateRotateScale( tx:Float,ty:Float,rz:Float,sx:Float,sy:Float )
|
|
|
+ Translate tx,ty
|
|
|
+ Rotate rz
|
|
|
+ Scale sx,sy
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Sets the maximum number of 2d matrices that can be pushed onto the matrix stack using @PushMatrix.
|
|
|
+ end rem
|
|
|
+ Method SetMatrixStackCapacity( capacity:Int )
|
|
|
+ '_matStack=_matStack.Resize( capacity*6 )
|
|
|
+ _matStack = _matStack[..capacity*6]
|
|
|
+ _matSp=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Gets the maximum number of 2d matrices that can be pushed onto the matrix stack using @PushMatrix.
|
|
|
+ end rem
|
|
|
+ Method MatrixStackCapacity:Int()
|
|
|
+ Return _matStack.Length/6
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Pushes the current 2d matrix on the 2d matrix stack.
|
|
|
+ end rem
|
|
|
+ Method PushMatrix()
|
|
|
+ _matStack[_matSp+0]=_ix;_matStack[_matSp+1]=_iy
|
|
|
+ _matStack[_matSp+2]=_jx;_matStack[_matSp+3]=_jy
|
|
|
+ _matStack[_matSp+4]=_tx;_matStack[_matSp+5]=_ty
|
|
|
+ _matSp:+6
|
|
|
+ If _matSp>=_matStack.Length _matSp:-_matStack.Length
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Pops the current 2d matrix from the 2d matrix stack.
|
|
|
+ end rem
|
|
|
+ Method PopMatrix()
|
|
|
+ _matSp:-6
|
|
|
+ If _matSp<0 _matSp:+_matStack.Length
|
|
|
+ _ix=_matStack[_matSp+0]
|
|
|
+ _iy=_matStack[_matSp+1]
|
|
|
+ _jx=_matStack[_matSp+2]
|
|
|
+ _jy=_matStack[_matSp+3]
|
|
|
+ _tx=_matStack[_matSp+4]
|
|
|
+ _ty=_matStack[_matSp+5]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Sets current font for use with #DrawText.
|
|
|
+ about: If @font is null, a default font is used.
|
|
|
+ end rem
|
|
|
+ Method SetFont( font:TFont )
|
|
|
+ If Not font font=defaultFont
|
|
|
+ _font=font
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Gets the current font.
|
|
|
+ end rem
|
|
|
+ Method Font:TFont()
|
|
|
+ Return _font
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Sets the default material used for drawing operations that use a null material.
|
|
|
+ end rem
|
|
|
+ Method SetDefaultMaterial( material:TMaterial )
|
|
|
+ _defaultMaterial=material
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Returns the current default material.
|
|
|
+ end rem
|
|
|
+ Method DefaultMaterial:TMaterial()
|
|
|
+ Return _defaultMaterial
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws a point at @x0,@y0.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawPoint( x0:Float,y0:Float,material:TMaterial=Null,s0:Float=0,t0:Float=0 )
|
|
|
+ BeginPrim material,1
|
|
|
+ PrimVert x0+.5,y0+.5,s0,t0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws a line from @x0,@y0 to @x1,@y1.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawLine( x0:Float,y0:Float,x1:Float,y1:Float,material:TMaterial=Null,s0:Float=0,t0:Float=0,s1:Float=1,t1:Float=0 )
|
|
|
+ BeginPrim material,2
|
|
|
+ PrimVert x0+.5,y0+.5,s0,t0
|
|
|
+ PrimVert x1+.5,y1+.5,s1,t1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw a triangle.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ End Rem
|
|
|
+ Method DrawTriangle( x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float,material:TMaterial=Null,s0:Float=.5,t0:Float=0,s1:Float=1,t1:Float=1,s2:Float=0,t2:Float=1 )
|
|
|
+ BeginPrim material,3
|
|
|
+ PrimVert x0,y0,s0,t0
|
|
|
+ PrimVert x1,y1,s1,t1
|
|
|
+ PrimVert x2,y2,s2,t2
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw a quad.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawQuad( x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float,x3:Float,y3:Float,material:TMaterial=Null,s0:Float=.5,t0:Float=0,s1:Float=1,t1:Float=1,s2:Float=0,t2:Float=1 )
|
|
|
+ BeginPrim material,4
|
|
|
+ PrimVert x0,y0,s0,t0
|
|
|
+ PrimVert x1,y1,s1,t1
|
|
|
+ PrimVert x2,y2,s2,t2
|
|
|
+ PrimVert x3,y3,s2,t2
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw an oval in the given rectangle.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawOval( x:Float,y:Float,width:Float,height:Float,material:TMaterial=Null )
|
|
|
+ Local xr:Float=width/2.0
|
|
|
+ Local yr:Float=height/2.0
|
|
|
+
|
|
|
+ Local dx_x:Float=xr*_ix
|
|
|
+ Local dx_y:Float=xr*_iy
|
|
|
+ Local dy_x:Float=yr*_jx
|
|
|
+ Local dy_y:Float=yr*_jy
|
|
|
+ Local dx:Float=Sqr( dx_x*dx_x+dx_y*dx_y )
|
|
|
+ Local dy:Float=Sqr( dy_x*dy_x+dy_y*dy_y )
|
|
|
+
|
|
|
+ Local n:Int=Int( dx+dy )
|
|
|
+ If n<12
|
|
|
+ n=12
|
|
|
+ Else If n>MAX_VERTICES
|
|
|
+ n=MAX_VERTICES
|
|
|
+ Else
|
|
|
+ n:&~3
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ Local x0:Float=x+xr
|
|
|
+ Local y0:Float=y+yr
|
|
|
+
|
|
|
+ BeginPrim material,n
|
|
|
+
|
|
|
+ For Local i:Int=0 Until n
|
|
|
+ Local th:Float=i*360.0/n
|
|
|
+ Local px:Float=x0+Cos( th ) * xr
|
|
|
+ Local py:Float=y0+Sin( th ) * yr
|
|
|
+ PrimVert px,py,0,0
|
|
|
+ Next
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw an ellipse at @x, @y with radii @xRadius, @yRadius.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawEllipse( x:Float,y:Float,xr:Float,yr:Float,material:TMaterial=Null )
|
|
|
+ DrawOval x-xr,y-yr,xr*2,yr*2,material
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw a circle at @x, @y with radius @radius.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawCircle( x:Float,y:Float,r:Float,material:TMaterial=Null )
|
|
|
+ DrawOval x-r,y-r,r*2,r*2,material
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method DrawPoly( vertices:Float[],material:TMaterial=Null )
|
|
|
+
|
|
|
+ Local n:Int=vertices.Length/2
|
|
|
+ If n<3 Or n>MAX_VERTICES Return
|
|
|
+
|
|
|
+ BeginPrim material,n
|
|
|
+
|
|
|
+ For Local i:Int=0 Until n
|
|
|
+ PrimVert vertices[i*2],vertices[i*2+1],0,0
|
|
|
+ Next
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw a batch of primtives.
|
|
|
+ about:
|
|
|
+ @order is the number of vertices for each primitive, eg: 1 for points, 2 for lines, 3 for triangles etc.
|
|
|
+ @count is the number of primitives to draw.
|
|
|
+ The @vertices array contains x,y vertex data, and must be at least @count \* @order \* 2 long.
|
|
|
+ If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawPrimitives( order:Int,count:Int,vertices:Float[],material:TMaterial=Null )
|
|
|
+
|
|
|
+ BeginPrims material,order,count
|
|
|
+ Local p:Int=0
|
|
|
+ For Local i:Int=0 Until count
|
|
|
+ For Local j:Int=0 Until order
|
|
|
+ PrimVert vertices[p],vertices[p+1],0,0
|
|
|
+ p:+2
|
|
|
+ Next
|
|
|
+ Next
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw a batch of primtives.
|
|
|
+ about:
|
|
|
+ @order is the number of vertices for each primitive, eg: 1 for points, 2 for lines, 3 for triangles etc.
|
|
|
+ @count is the number of primitives to draw.
|
|
|
+ The @vertices array contains x,y vertex data, and must be at least @count \* @order \* 2 long.
|
|
|
+ The @texcoords array contains s,t texture coordinate data, and must be at least @count \* @order \* 2 long.
|
|
|
+ If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawPrimitivesCoords( order:Int,count:Int,vertices:Float[],texcoords:Float[],material:TMaterial=Null )
|
|
|
+
|
|
|
+ BeginPrims material,order,count
|
|
|
+ Local p:Int=0
|
|
|
+ For Local i:Int=0 Until count
|
|
|
+ For Local j:Int=0 Until order
|
|
|
+ PrimVert vertices[p],vertices[p+1],texcoords[p],texcoords[p+1]
|
|
|
+ p:+2
|
|
|
+ Next
|
|
|
+ Next
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Rem
|
|
|
+ bbdoc: Draw a batch of indexed primtives.
|
|
|
+ about:
|
|
|
+ @order is the number of vertices for each primitive, eg: 1 for points, 2 for lines, 3 for triangles etc.
|
|
|
+ @count is the number of primitives to draw.
|
|
|
+ The @vertices array contains x,y vertex data.
|
|
|
+ The @indices array contains vertex indices, and must be at least @count \* @order long.
|
|
|
+ If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawIndexedPrimitives( order:Int,count:Int,vertices:Float[],indices:Int[],material:TMaterial=Null )
|
|
|
+
|
|
|
+ BeginPrims material,order,count
|
|
|
+ Local p:Int=0
|
|
|
+ For Local i:Int=0 Until count
|
|
|
+ For Local j:Int=0 Until order
|
|
|
+ Local k:Int=indices[p+j]*2
|
|
|
+ PrimVert vertices[k],vertices[k+1],0,0
|
|
|
+ Next
|
|
|
+ p:+order
|
|
|
+ Next
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method DrawIndexedPrimitivesCoords( order:Int,count:Int,vertices:Float[],texcoords:Float[],indices:Int[],material:TMaterial=Null )
|
|
|
+
|
|
|
+ BeginPrims material,order,count
|
|
|
+ Local p:Int=0
|
|
|
+ For Local i:Int=0 Until count
|
|
|
+ For Local j:Int=0 Until order
|
|
|
+ Local k:Int=indices[p+j]*2
|
|
|
+ PrimVert vertices[k],vertices[k+1],texcoords[k],texcoords[k+1]
|
|
|
+ Next
|
|
|
+ p:+order
|
|
|
+ Next
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws a rect from @x,@y to @x+@width,@y+@height.
|
|
|
+ about: If @material is null, the current default material is used.
|
|
|
+ end rem
|
|
|
+ Method DrawRect( x0:Float,y0:Float,width:Float,height:Float,material:TMaterial=Null,s0:Float=0,t0:Float=0,s1:Float=1,t1:Float=1 )
|
|
|
+ Local x1:Float=x0+width
|
|
|
+ Local y1:Float=y0+height
|
|
|
+ BeginPrim material,4
|
|
|
+ PrimVert x0,y0,s0,t0
|
|
|
+ PrimVert x1,y0,s1,t0
|
|
|
+ PrimVert x1,y1,s1,t1
|
|
|
+ PrimVert x0,y1,s0,t1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws a rect from @x,@y to @x+@width,@y+@height filled with @image.
|
|
|
+ about: The image's handle is ignored.
|
|
|
+ end rem
|
|
|
+ Method DrawRectImage( x0:Float,y0:Float,width:Float,height:Float,image:TImage )
|
|
|
+ DrawRect x0,y0,width,height,image._material,image._s0,image._t0,image._s1,image._t1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws a rect at @x,@y filled with the given subrect of @image.
|
|
|
+ about: The image's handle is ignored.
|
|
|
+ end rem
|
|
|
+ Method DrawRectImageSource( x:Float,y:Float,image:TImage,sourceX:Int,sourceY:Int,sourceWidth:Int,sourceHeight:Int )
|
|
|
+ DrawRectImageSourceSize( x,y,sourceWidth,sourceHeight,image,sourceX,sourceY,sourceWidth,sourceHeight )
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws a rect from @x,@y to @x+@width,@y+@height filled with the given subrect of @image.
|
|
|
+ about: The image's handle is ignored.
|
|
|
+ end rem
|
|
|
+ Method DrawRectImageSourceSize( x0:Float,y0:Float,width:Float,height:Float,image:TImage,sourceX:Int,sourceY:Int,sourceWidth:Int,sourceHeight:Int )
|
|
|
+ Local material:TMaterial=image._material
|
|
|
+ Local s0:Float=Float(image._x+sourceX)/Float(material.Width)
|
|
|
+ Local t0:Float=Float(image._y+sourceY)/Float(material.Height)
|
|
|
+ Local s1:Float=Float(image._x+sourceX+sourceWidth)/Float(material.Width)
|
|
|
+ Local t1:Float=Float(image._y+sourceY+sourceHeight)/Float(material.Height)
|
|
|
+ DrawRect x0,y0,width,height,material,s0,t0,s1,t1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ 'gradient rect - kinda hacky, but doesn't slow anything else down
|
|
|
+ Method DrawGradientRect( x0:Float,y0:Float,width:Float,height:Float,r0:Float,g0:Float,b0:Float,a0:Float,r1:Float,g1:Float,b1:Float,a1:Float,axis:Int )
|
|
|
+
|
|
|
+ r0:*_color[0];g0:*_color[1];b0:*_color[2];a0:*_alpha
|
|
|
+ r1:*_color[0];g1:*_color[1];b1:*_color[2];a1:*_alpha
|
|
|
+
|
|
|
+ Local pm0:Int=Int( a0 ) Shl 24 | Int( b0*a0 ) Shl 16 | Int( g0*a0 ) Shl 8 | Int( r0*a0 )
|
|
|
+ Local pm1:Int=Int( a1 ) Shl 24 | Int( b1*a0 ) Shl 16 | Int( g1*a0 ) Shl 8 | Int( r1*a0 )
|
|
|
+
|
|
|
+ Local x1:Float=x0+width
|
|
|
+ Local y1:Float=y0+height
|
|
|
+ Local s0:Float=0.0
|
|
|
+ Local t0:Float=0.0
|
|
|
+ Local s1:Float=1.0
|
|
|
+ Local t1:Float=1.0
|
|
|
+
|
|
|
+ BeginPrim Null,4
|
|
|
+
|
|
|
+ Local pmcolor:Int=_pmcolor
|
|
|
+
|
|
|
+ BeginPrim Null,4
|
|
|
+
|
|
|
+ Select axis
|
|
|
+ Case 0 'left->right
|
|
|
+ _pmcolor=pm0
|
|
|
+ PrimVert x0,y0,s0,t0
|
|
|
+ _pmcolor=pm1
|
|
|
+ PrimVert x1,y0,s1,t0
|
|
|
+ PrimVert x1,y1,s1,t1
|
|
|
+ _pmcolor=pm0
|
|
|
+ PrimVert x0,y1,s0,t1
|
|
|
+ Default 'top->bottom
|
|
|
+ _pmcolor=pm0
|
|
|
+ PrimVert x0,y0,s0,t0
|
|
|
+ PrimVert x1,y0,s1,t0
|
|
|
+ _pmcolor=pm1
|
|
|
+ PrimVert x1,y1,s1,t1
|
|
|
+ PrimVert x0,y1,s0,t1
|
|
|
+ End Select
|
|
|
+
|
|
|
+ _pmcolor=pmcolor
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method DrawImageImage( image:TImage )
|
|
|
+ BeginPrim image._material,4
|
|
|
+ PrimVert image._x0,image._y0,image._s0,image._t0
|
|
|
+ PrimVert image._x1,image._y0,image._s1,image._t0
|
|
|
+ PrimVert image._x1,image._y1,image._s1,image._t1
|
|
|
+ PrimVert image._x0,image._y1,image._s0,image._t1
|
|
|
+ If image._caster AddShadowCaster image._caster
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method DrawImage( image:TImage,tx:Float,ty:Float )
|
|
|
+ PushMatrix
|
|
|
+ Translate tx,ty
|
|
|
+ DrawImageImage image
|
|
|
+ PopMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method DrawImageXYZ( image:TImage,tx:Float,ty:Float,rz:Float )
|
|
|
+ PushMatrix
|
|
|
+ TranslateRotate tx,ty,rz
|
|
|
+ DrawImageImage image
|
|
|
+ PopMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method DrawImageXYZS( image:TImage,tx:Float,ty:Float,rz:Float,sx:Float,sy:Float )
|
|
|
+ PushMatrix
|
|
|
+ TranslateRotateScale tx,ty,rz,sx,sy
|
|
|
+ DrawImageImage image
|
|
|
+ PopMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws @text at @x,@y in the current font.
|
|
|
+ end rem
|
|
|
+ Method DrawText( Text:String,x:Float,y:Float,xhandle:Float=0,yhandle:Float=0 )
|
|
|
+ x:-_font.TextWidth( Text )*xhandle
|
|
|
+ y:-_font.TextHeight( Text )*yhandle
|
|
|
+ For Local char:Int=EachIn Text
|
|
|
+ Local glyph:TGlyph=_font.GetGlyph( char )
|
|
|
+ If Not glyph Continue
|
|
|
+ DrawRectImageSource x,y,glyph.image,glyph.x,glyph.y,glyph.width,glyph.height
|
|
|
+ x:+glyph.advance
|
|
|
+ Next
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws a shadow volume.
|
|
|
+ end rem
|
|
|
+ Method DrawShadow:Int( lx:Float,ly:Float,x0:Float,y0:Float,x1:Float,y1:Float )
|
|
|
+
|
|
|
+ Local ext:Int=1024
|
|
|
+
|
|
|
+ Local dx:Float=x1-x0
|
|
|
+ Local dy:Float=y1-y0
|
|
|
+ Local d0:Float=Sqr( dx*dx+dy*dy )
|
|
|
+ Local nx:Float=-dy/d0
|
|
|
+ Local ny:Float=dx/d0
|
|
|
+ Local pd:Float=-(x0*nx+y0*ny)
|
|
|
+
|
|
|
+ Local d:Float=lx*nx+ly*ny+pd
|
|
|
+ If d<0 Return False
|
|
|
+
|
|
|
+ Local x2:Float=x1-lx
|
|
|
+ Local y2:Float=y1-ly
|
|
|
+ 'Local d2:Float=ext/Sqr( x2*x2+y2*y2 )
|
|
|
+ x2=lx+x2*ext;y2=ly+y2*ext
|
|
|
+
|
|
|
+ Local x3:Float=x0-lx
|
|
|
+ Local y3:Float=y0-ly
|
|
|
+ 'Local d3:Float=ext/Sqr( x3*x3+y3*y3 )
|
|
|
+ x3=lx+x3*ext;y3=ly+y3*ext
|
|
|
+
|
|
|
+ Local x4:Float=(x2+x3)/2-lx
|
|
|
+ Local y4:Float=(y2+y3)/2-ly
|
|
|
+ 'Local d4:Float=ext/Sqr( x4*x4+y4*y4 )
|
|
|
+ x4=lx+x4*ext;y4=ly+y4*ext
|
|
|
+
|
|
|
+ DrawTriangle x0,y0,x4,y4,x3,y3
|
|
|
+ DrawTriangle x0,y0,x1,y1,x4,y4
|
|
|
+ DrawTriangle x1,y1,x2,y2,x4,y4
|
|
|
+
|
|
|
+ Return True
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Draws multiple shadow volumes.
|
|
|
+ end rem
|
|
|
+ Method DrawShadows( x0:Float,y0:Float,drawList:TDrawList )
|
|
|
+
|
|
|
+ Local lx:Float= x0 * _ix + y0 * _jx + _tx
|
|
|
+ Local ly:Float= x0 * _iy + y0 * _jy + _ty
|
|
|
+
|
|
|
+ Local verts:Float[]=drawList._casterVerts.Data
|
|
|
+ Local v0:Int=0
|
|
|
+
|
|
|
+ For Local i:Int=0 Until drawList._casters.Length
|
|
|
+
|
|
|
+ Local caster:TShadowCaster=drawList._casters.Get( i )
|
|
|
+ Local n:Int=caster._verts.Length
|
|
|
+
|
|
|
+ Select caster._kind
|
|
|
+ Case 0 'closed loop
|
|
|
+ Local x0:Float=verts[v0+n-2]
|
|
|
+ Local y0:Float=verts[v0+n-1]
|
|
|
+ For Local i:Int=0 Until n-1 Step 2
|
|
|
+ Local x1:Float=verts[v0+i]
|
|
|
+ Local y1:Float=verts[v0+i+1]
|
|
|
+ DrawShadow( lx,ly,x0,y0,x1,y1 )
|
|
|
+ x0=x1
|
|
|
+ y0=y1
|
|
|
+ Next
|
|
|
+ Case 1 'open loop
|
|
|
+ Case 2 'edge soup
|
|
|
+ End Select
|
|
|
+
|
|
|
+ v0:+n
|
|
|
+ Next
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Adds a shadow caster to the drawlist.
|
|
|
+ end rem
|
|
|
+ Method AddShadowCaster( caster:TShadowCaster )
|
|
|
+ _casters.Push caster
|
|
|
+ Local verts:Float[]=caster._verts
|
|
|
+ For Local i:Int=0 Until verts.Length-1 Step 2
|
|
|
+ Local x0:Float=verts[i]
|
|
|
+ Local y0:Float=verts[i+1]
|
|
|
+ _casterVerts.Push x0*_ix+y0*_jx+_tx
|
|
|
+ _casterVerts.Push x0*_iy+y0*_jy+_ty
|
|
|
+ Next
|
|
|
+ End Method
|
|
|
+
|
|
|
+ rem
|
|
|
+ bbdoc: Adds a shadow caster to the drawlist at @tx,@ty.
|
|
|
+ end rem
|
|
|
+ Method AddShadowCasterXY( caster:TShadowCaster,tx:Float,ty:Float )
|
|
|
+ PushMatrix
|
|
|
+ Translate tx,ty
|
|
|
+ AddShadowCaster caster
|
|
|
+ PopMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method AddShadowCasterXYZ( caster:TShadowCaster,tx:Float,ty:Float,rz:Float )
|
|
|
+ PushMatrix
|
|
|
+ TranslateRotate tx,ty,rz
|
|
|
+ AddShadowCaster caster
|
|
|
+ PopMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method AddShadowCasterXYZS( caster:TShadowCaster,tx:Float,ty:Float,rz:Float,sx:Float,sy:Float )
|
|
|
+ PushMatrix
|
|
|
+ TranslateRotateScale tx,ty,rz,sx,sy
|
|
|
+ AddShadowCaster caster
|
|
|
+ PopMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method IsEmpty:Int()
|
|
|
+ Return _next=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Compact()
|
|
|
+ If _data.Size()=_next Return
|
|
|
+ Local data:TBank=New TBank.Create( _next )
|
|
|
+ '_data.CopyBytes 0,data,0,_next
|
|
|
+ '_data.Discard
|
|
|
+ MemCopy(data._buf,_data._buf,_next)
|
|
|
+ _data=data
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method RenderOp( op:TDrawOp,index:Int,count:Int )
|
|
|
+
|
|
|
+ If Not op.material.Bind() Return
|
|
|
+
|
|
|
+ If op.blend<>rs_blend
|
|
|
+ rs_blend=op.blend
|
|
|
+ Select rs_blend
|
|
|
+ Case TBlendMode.Opaque
|
|
|
+ glDisable GL_BLEND
|
|
|
+ Case TBlendMode.Alpha
|
|
|
+ glEnable GL_BLEND
|
|
|
+ glBlendFunc GL_ONE,GL_ONE_MINUS_SRC_ALPHA
|
|
|
+ Case TBlendMode.Additive
|
|
|
+ glEnable GL_BLEND
|
|
|
+ glBlendFunc GL_ONE,GL_ONE
|
|
|
+ Case TBlendMode.Multiply
|
|
|
+ glEnable GL_BLEND
|
|
|
+ glBlendFunc GL_DST_COLOR,GL_ONE_MINUS_SRC_ALPHA
|
|
|
+ Case TBlendMode.Multiply2
|
|
|
+ glEnable GL_BLEND
|
|
|
+ glBlendFunc GL_DST_COLOR,GL_ZERO
|
|
|
+ End Select
|
|
|
+ End If
|
|
|
+
|
|
|
+ Select op.order
|
|
|
+ Case 1
|
|
|
+ glDrawArrays GL_POINTS,index,count
|
|
|
+ Case 2
|
|
|
+ glDrawArrays GL_LINES,index,count
|
|
|
+ Case 3
|
|
|
+ glDrawArrays GL_TRIANGLES,index,count
|
|
|
+ Case 4
|
|
|
+ glDrawElements GL_TRIANGLES,count/4*6,GL_UNSIGNED_SHORT,(index/4*6 + (index&3)*MAX_QUAD_INDICES)*2
|
|
|
+ Default
|
|
|
+ Local j:Int=0
|
|
|
+ While j<count
|
|
|
+ glDrawArrays GL_TRIANGLE_FAN,index+j,op.order
|
|
|
+ j:+op.order
|
|
|
+ Wend
|
|
|
+ End Select
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Render()
|
|
|
+ If Not _next Return
|
|
|
+
|
|
|
+ Local offset:Int=0
|
|
|
+ Local opid:Int=0
|
|
|
+ Local ops:Object[]=_ops.Data
|
|
|
+ Local length:Int=_ops.length
|
|
|
+
|
|
|
+ While offset<_next
|
|
|
+
|
|
|
+ Local size:Int=_next-offset
|
|
|
+ Local lastop:Int=length
|
|
|
+
|
|
|
+ If size>PRIM_VBO_SIZE
|
|
|
+
|
|
|
+ size=0
|
|
|
+ lastop=opid
|
|
|
+ While lastop<length
|
|
|
+ Local op:TDrawOp=TDrawOp(ops[lastop])
|
|
|
+ Local n:Int=op.count*BYTES_PER_VERTEX
|
|
|
+ If size+n>PRIM_VBO_SIZE Exit
|
|
|
+ size:+n
|
|
|
+ lastop:+1
|
|
|
+ Wend
|
|
|
+
|
|
|
+ If Not size
|
|
|
+ Local op:TDrawOp=TDrawOp(ops[opid])
|
|
|
+ Local count:Int=op.count
|
|
|
+ While count
|
|
|
+ Local n:Int=count
|
|
|
+ If n>MAX_VERTICES n=MAX_VERTICES/op.order*op.order
|
|
|
+ Local size:Int=n*BYTES_PER_VERTEX
|
|
|
+
|
|
|
+ If VBO_ORPHANING_ENABLED glBufferData GL_ARRAY_BUFFER,PRIM_VBO_SIZE,Null,VBO_USAGE
|
|
|
+ glBufferSubData GL_ARRAY_BUFFER,0,size,_data._buf + offset
|
|
|
+
|
|
|
+ RenderOp op,0,n
|
|
|
+
|
|
|
+ offset:+size
|
|
|
+ count:-n
|
|
|
+ Wend
|
|
|
+ opid:+1
|
|
|
+ Continue
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If VBO_ORPHANING_ENABLED glBufferData GL_ARRAY_BUFFER,PRIM_VBO_SIZE,Null,VBO_USAGE
|
|
|
+ glBufferSubData GL_ARRAY_BUFFER,0,size,_data._buf + offset
|
|
|
+
|
|
|
+ Local index:Int=0
|
|
|
+ While opid<lastop
|
|
|
+ Local op:TDrawOp=TDrawOp(ops[opid])
|
|
|
+ RenderOp op,index,op.count
|
|
|
+ index:+op.count
|
|
|
+ opid:+1
|
|
|
+ Wend
|
|
|
+ offset:+size
|
|
|
+
|
|
|
+ Wend
|
|
|
+
|
|
|
+ glGetError
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Reset()
|
|
|
+ _next=0
|
|
|
+
|
|
|
+ Local data:TDrawOp[]=_ops.Data
|
|
|
+ For Local i:Int=0 Until _ops.Length
|
|
|
+ data[i].material=Null
|
|
|
+ freeOps.Push data[i]
|
|
|
+ Next
|
|
|
+ _ops.Clear()
|
|
|
+ _op=nullOp
|
|
|
+
|
|
|
+ _casters.Clear
|
|
|
+ _casterVerts.Clear
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Flush()
|
|
|
+ Render
|
|
|
+ Reset
|
|
|
+ End Method
|
|
|
+
|
|
|
+' Protected
|
|
|
+
|
|
|
+ Field _blend:Float=1
|
|
|
+ Field _alpha:Float=255.0
|
|
|
+ Field _color:Float Ptr
|
|
|
+ Field __colorArray:Float[]=[1.0,1.0,1.0,1.0]
|
|
|
+ Field _pmcolor:Int=$ffffffff
|
|
|
+ Field _ix:Float=1,_iy:Float
|
|
|
+ Field _jx:Float,_jy:Float=1
|
|
|
+ Field _tx:Float,_ty:Float
|
|
|
+ Field _matStack:Float[64*6]
|
|
|
+ Field _matSp:Int
|
|
|
+ Field _font:TFont
|
|
|
+ Field _defaultMaterial:TMaterial
|
|
|
+
|
|
|
+' Private
|
|
|
+
|
|
|
+ Field _data:TBank=New TBank.Create( 4096 )
|
|
|
+ Field _next:Int=0
|
|
|
+
|
|
|
+ Field _op:TDrawOp=nullOp
|
|
|
+ Field _ops:TDrawOpStack=New TDrawOpStack'<DrawOp>
|
|
|
+ Field _casters:TShadowCasterStack=New TShadowCasterStack'<ShadowCaster>
|
|
|
+ Field _casterVerts:TFloatStack=New TFloatStack
|
|
|
+
|
|
|
+ Method BeginPrim( material:TMaterial,order:Int ) Final
|
|
|
+
|
|
|
+ If Not material material=_defaultMaterial
|
|
|
+
|
|
|
+ If _next+order*BYTES_PER_VERTEX>_data.Size()
|
|
|
+ Local newsize:Int=Max( _data.Size()+_data.Size()/2,_next+order*BYTES_PER_VERTEX )
|
|
|
+ Local data:TBank=New TBank.Create( newsize )
|
|
|
+ MemCopy(data._buf, _data._buf, _next)
|
|
|
+ '_data.CopyBytes 0,data,0,_next
|
|
|
+ '_data.Discard
|
|
|
+ _data=data
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If material=_op.material And _blend=_op.blend And order=_op.order
|
|
|
+ _op.count:+order
|
|
|
+ Return
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If freeOps.Length _op=freeOps.Pop() Else _op=New TDrawOp
|
|
|
+
|
|
|
+ _ops.Push _op
|
|
|
+ _op.material=material
|
|
|
+ _op.blend=_blend
|
|
|
+ _op.order=order
|
|
|
+ _op.count=order
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method BeginPrims( material:TMaterial,order:Int,count:Int ) Final
|
|
|
+
|
|
|
+ If Not material material=_defaultMaterial
|
|
|
+
|
|
|
+ count:*order
|
|
|
+
|
|
|
+ If _next+count*BYTES_PER_VERTEX>_data.Size()
|
|
|
+ Local newsize:Int=Max( _data.Size()+_data.Size()/2,_next+count*BYTES_PER_VERTEX )
|
|
|
+ Local data:TBank=New TBank.Create( newsize )
|
|
|
+ MemCopy data._buf, _data._buf, _next
|
|
|
+ _data=data
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If material=_op.material And _blend=_op.blend And order=_op.order
|
|
|
+ _op.count:+count
|
|
|
+ Return
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If freeOps.Length _op=freeOps.Pop() Else _op=New TDrawOp
|
|
|
+
|
|
|
+ _ops.Push _op
|
|
|
+ _op.material=material
|
|
|
+ _op.blend=_blend
|
|
|
+ _op.order=order
|
|
|
+ _op.count=count
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method PrimVert( x0:Float,y0:Float,s0:Float,t0:Float ) Final
|
|
|
+ Local df:Float Ptr = (_data._buf + _next)
|
|
|
+ Local di:Int Ptr = (_data._buf + _next)
|
|
|
+ df[0] = x0 * _ix + y0 * _jx + _tx
|
|
|
+ df[1] = x0 * _iy + y0 * _jy + _ty
|
|
|
+ df[2] = s0
|
|
|
+ df[3] = t0
|
|
|
+ df[4] = _ix
|
|
|
+ df[5] = _iy
|
|
|
+ di[6] = _pmcolor
|
|
|
+ _next:+BYTES_PER_VERTEX
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+
|
|
|
+'***** Canvas *****
|
|
|
+
|
|
|
+Type TCanvas Extends TDrawList
|
|
|
+
|
|
|
+ Const MaxLights:Int=MAX_LIGHTS
|
|
|
+
|
|
|
+ Method CreateCanvas:TCanvas( target:Object=Null )
|
|
|
+' Super.Create()
|
|
|
+ Init
|
|
|
+ SetRenderTarget target
|
|
|
+ SetViewport 0,0,_width,_height
|
|
|
+ SetProjection2d 0,_width,0,_height
|
|
|
+ Return Self
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Discard()
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetRenderTarget( target:Object )
|
|
|
+
|
|
|
+ FlushPrims
|
|
|
+
|
|
|
+ If Not target
|
|
|
+
|
|
|
+ _image=Null
|
|
|
+ _texture=Null
|
|
|
+ _width=GraphicsWidth()
|
|
|
+ _height=GraphicsHeight()
|
|
|
+ _twidth=_width
|
|
|
+ _theight=_height
|
|
|
+
|
|
|
+ Else If TImage( target )
|
|
|
+
|
|
|
+ _image=TImage( target )
|
|
|
+ _texture=_image.Material.ColorTexture
|
|
|
+ If Not (_texture.Flags & TTexture.RenderTarget) Throw "Texture is not a render target texture"
|
|
|
+ _width=_image.Width
|
|
|
+ _height=_image.Height
|
|
|
+ _twidth=_texture.Width
|
|
|
+ _theight=_texture.Height
|
|
|
+
|
|
|
+ Else If TTexture( target )
|
|
|
+
|
|
|
+ _image=Null
|
|
|
+ _texture=TTexture( target )
|
|
|
+
|
|
|
+ If Not (_texture.Flags & TTexture.RenderTarget) Throw "Texture is not a render target texture"
|
|
|
+ _width=_texture.Width
|
|
|
+ _height=_texture.Height
|
|
|
+ _twidth=_texture.Width
|
|
|
+ _theight=_texture.Height
|
|
|
+
|
|
|
+ Else
|
|
|
+
|
|
|
+ Throw "RenderTarget object must a TImage, a TTexture or Null"
|
|
|
+
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ _dirty=-1
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method RenderTarget:Object()
|
|
|
+ If _image Return _image Else Return _texture
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Width:Int()
|
|
|
+ Return _width
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Height:Int()
|
|
|
+ Return _height
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetColorMask( r:Int,g:Int,b:Int,a:Int )
|
|
|
+ FlushPrims
|
|
|
+ _colorMask[0]=r
|
|
|
+ _colorMask[1]=g
|
|
|
+ _colorMask[2]=b
|
|
|
+ _colorMask[3]=a
|
|
|
+ _dirty:|DIRTY_COLORMASK
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ColorMask:Int[]()
|
|
|
+ Return _colorMask
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetViewport( x:Int,y:Int,w:Int,h:Int )
|
|
|
+ FlushPrims
|
|
|
+ _viewport[0]=x
|
|
|
+ _viewport[1]=y
|
|
|
+ _viewport[2]=w
|
|
|
+ _viewport[3]=h
|
|
|
+ _dirty:|DIRTY_VIEWPORT
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Viewport:Int[]()
|
|
|
+ Return _viewport
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetScissor( x:Int,y:Int,w:Int,h:Int )
|
|
|
+ FlushPrims
|
|
|
+ _scissor[0]=x
|
|
|
+ _scissor[1]=y
|
|
|
+ _scissor[2]=w
|
|
|
+ _scissor[3]=h
|
|
|
+ _dirty:|DIRTY_VIEWPORT
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Scissor:Int[]()
|
|
|
+ Return _scissor
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetProjectionMatrix( projMatrix:Float[] )
|
|
|
+ FlushPrims
|
|
|
+ If projMatrix
|
|
|
+ Mat4Copy projMatrix,_projMatrix
|
|
|
+ Else
|
|
|
+ Mat4InitArray _projMatrix
|
|
|
+ EndIf
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetProjection2d( Left:Float,Right:Float,top:Float,bottom:Float,znear:Float=-1,zfar:Float=1 )
|
|
|
+ FlushPrims
|
|
|
+ Mat4Ortho Left,Right,top,bottom,znear,zfar,_projMatrix
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ProjectionMatrix:Float[]()
|
|
|
+ Return _projMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetViewMatrix( viewMatrix:Float[] )
|
|
|
+ FlushPrims
|
|
|
+ If viewMatrix
|
|
|
+ Mat4Copy viewMatrix,_viewMatrix
|
|
|
+ Else
|
|
|
+ Mat4InitArray _viewMatrix
|
|
|
+ End If
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ViewMatrix:Float[]()
|
|
|
+ Return _viewMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetModelMatrix( modelMatrix:Float[] )
|
|
|
+ FlushPrims
|
|
|
+ If modelMatrix
|
|
|
+ Mat4Copy modelMatrix,_modelMatrix
|
|
|
+ Else
|
|
|
+ Mat4InitArray _modelMatrix
|
|
|
+ EndIf
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ModelMatrix:Float[]()
|
|
|
+ Return _modelMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetAmbientLight( r:Float,g:Float,b:Float,a:Float=1 )
|
|
|
+ FlushPrims
|
|
|
+ _ambientLight[0]=r
|
|
|
+ _ambientLight[1]=g
|
|
|
+ _ambientLight[2]=b
|
|
|
+ _ambientLight[3]=a
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method AmbientLight:Float[]()
|
|
|
+ Return _ambientLight
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetFogColor( r:Float,g:Float,b:Float,a:Float )
|
|
|
+ FlushPrims
|
|
|
+ _fogColor[0]=r
|
|
|
+ _fogColor[1]=g
|
|
|
+ _fogColor[2]=b
|
|
|
+ _fogColor[3]=a
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method FogColor:Float[]()
|
|
|
+ Return _fogColor
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetLightType( index:Int,kind:Int )
|
|
|
+ FlushPrims
|
|
|
+ Local light:TLightData=_lights[index]
|
|
|
+ light.kind=kind
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GetLightType:Int( index:Int )
|
|
|
+ Return _lights[index].kind
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetLightColor( index:Int,r:Float,g:Float,b:Float,a:Float=1 )
|
|
|
+ FlushPrims
|
|
|
+ Local light:TLightData=_lights[index]
|
|
|
+ light.color[0]=r
|
|
|
+ light.color[1]=g
|
|
|
+ light.color[2]=b
|
|
|
+ light.color[3]=a
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GetLightColor:Float[]( index:Int )
|
|
|
+ Return _lights[index].color
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetLightPosition( index:Int,x:Float,y:Float,z:Float )
|
|
|
+ FlushPrims
|
|
|
+ Local light:TLightData=_lights[index]
|
|
|
+ light.position[0]=x
|
|
|
+ light.position[1]=y
|
|
|
+ light.position[2]=z
|
|
|
+ light.vector[0]=x
|
|
|
+ light.vector[1]=y
|
|
|
+ light.vector[2]=z
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GetLightPosition:Float[]( index:Int )
|
|
|
+ Return _lights[index].position
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetLightRange( index:Int,Range:Float )
|
|
|
+ FlushPrims
|
|
|
+ Local light:TLightData=_lights[index]
|
|
|
+ light.Range=Range
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method GetLightRange:Float( index:Int )
|
|
|
+ Return _lights[index].Range
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetShadowMap( image:TImage )
|
|
|
+ FlushPrims
|
|
|
+ _shadowMap=image
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ShadowMap:TImage()
|
|
|
+ Return _shadowMap
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method SetLineWidth( lineWidth:Float )
|
|
|
+ FlushPrims
|
|
|
+ _lineWidth=lineWidth
|
|
|
+ _dirty:|DIRTY_LINEWIDTH
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method LineWidth:Float()
|
|
|
+ Return _lineWidth
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Clear( r:Float=0,g:Float=0,b:Float=0,a:Float=1 )
|
|
|
+ FlushPrims
|
|
|
+ Validate
|
|
|
+ If _clsScissor
|
|
|
+ glEnable GL_SCISSOR_TEST
|
|
|
+ glScissor _vpx,_vpy,_vpw,_vph
|
|
|
+ EndIf
|
|
|
+ glClearColor r,g,b,a
|
|
|
+ glClear GL_COLOR_BUFFER_BIT
|
|
|
+ If _clsScissor glDisable GL_SCISSOR_TEST
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method ReadPixels( x:Int,y:Int,width:Int,height:Int,data:TBank,dataOffset:Int=0,dataPitch:Int=0 )
|
|
|
+
|
|
|
+ FlushPrims
|
|
|
+
|
|
|
+ If Not dataPitch Or dataPitch=width*4
|
|
|
+ glReadPixels x,y,width,height,GL_RGBA,GL_UNSIGNED_BYTE,data._buf + dataOffset
|
|
|
+ Else
|
|
|
+ For Local iy:Int=0 Until height
|
|
|
+ glReadPixels x,y+iy,width,1,GL_RGBA,GL_UNSIGNED_BYTE,data._buf + dataOffset+dataPitch*iy
|
|
|
+ Next
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method RenderDrawList( drawbuf:TDrawList )
|
|
|
+
|
|
|
+ Local fast:Int=_ix=1 And _iy=0 And _jx=0 And _jy=1 And _tx=0 And _ty=0 And _color[0]=1 And _color[1]=1 And _color[2]=1 And _color[3]=1
|
|
|
+
|
|
|
+ If fast
|
|
|
+ FlushPrims
|
|
|
+ Validate
|
|
|
+ drawbuf.Render
|
|
|
+ Return
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ tmpMat3d[0]=_ix
|
|
|
+ tmpMat3d[1]=_iy
|
|
|
+ tmpMat3d[4]=_jx
|
|
|
+ tmpMat3d[5]=_jy
|
|
|
+ tmpMat3d[12]=_tx
|
|
|
+ tmpMat3d[13]=_ty
|
|
|
+ tmpMat3d[10]=1
|
|
|
+ tmpMat3d[15]=1
|
|
|
+
|
|
|
+ Mat4Multiply _modelMatrix,tmpMat3d,tmpMat3d2
|
|
|
+
|
|
|
+ FlushPrims
|
|
|
+
|
|
|
+ Local tmp:Float[]=_modelMatrix
|
|
|
+ _modelMatrix=tmpMat3d2
|
|
|
+ rs_globalColor[0]=_color[0]*_color[3]
|
|
|
+ rs_globalColor[1]=_color[1]*_color[3]
|
|
|
+ rs_globalColor[2]=_color[2]*_color[3]
|
|
|
+ rs_globalColor[3]=_color[3]
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+
|
|
|
+ Validate
|
|
|
+ drawbuf.Render
|
|
|
+
|
|
|
+ _modelMatrix=tmp
|
|
|
+ rs_globalColor[0]=1
|
|
|
+ rs_globalColor[1]=1
|
|
|
+ rs_globalColor[2]=1
|
|
|
+ rs_globalColor[3]=1
|
|
|
+ _dirty:|DIRTY_SHADER
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method RenderDrawListXYZ( drawList:TDrawList,tx:Float,ty:Float,rz:Float=0,sx:Float=1,sy:Float=1 )
|
|
|
+ Super.PushMatrix
|
|
|
+ Super.TranslateRotateScale tx,ty,rz,sx,sy
|
|
|
+ RenderDrawList( drawList )
|
|
|
+ Super.PopMatrix
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Flush()
|
|
|
+ FlushPrims
|
|
|
+
|
|
|
+ If Not _texture Return
|
|
|
+
|
|
|
+ If _texture._flags & TTexture.Managed
|
|
|
+ Validate
|
|
|
+
|
|
|
+ glDisable GL_SCISSOR_TEST
|
|
|
+ glViewport 0,0,_twidth,_theight
|
|
|
+
|
|
|
+ If _width=_twidth And _height=_theight
|
|
|
+ glReadPixels 0,0,_twidth,_theight,GL_RGBA,GL_UNSIGNED_BYTE, _texture._data.pixels
|
|
|
+ Else
|
|
|
+ For Local y:Int=0 Until _height
|
|
|
+ glReadPixels _image._x,_image._y+y,_width,1,GL_RGBA,GL_UNSIGNED_BYTE,_texture._data.pixels + (_image._y+y) * (_twidth*4) + (_image._x*4)
|
|
|
+ Next
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ _dirty:|DIRTY_VIEWPORT
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ _texture.UpdateMipmaps
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Global _tformInvProj:Float[16]
|
|
|
+ Global _tformT:Float[]=[0.0,0.0,-1.0,1.0]
|
|
|
+ Global _tformP:Float[4]
|
|
|
+
|
|
|
+ Method TransformCoords( coords_in:Float[],coords_out:Float[],Mode:Int=0 )
|
|
|
+
|
|
|
+ Mat4Inverse _projMatrix,_tformInvProj
|
|
|
+
|
|
|
+ Select Mode
|
|
|
+ Case 0
|
|
|
+ _tformT[0]=(coords_in[0]-_viewport[0])/_viewport[2]*2-1
|
|
|
+ _tformT[1]=(coords_in[1]-_viewport[1])/_viewport[3]*2-1
|
|
|
+ Mat4Transform _tformInvProj,_tformT,_tformP
|
|
|
+ _tformP[0]:/_tformP[3]
|
|
|
+ _tformP[1]:/_tformP[3]
|
|
|
+ _tformP[2]:/_tformP[3]
|
|
|
+ _tformP[3]=1
|
|
|
+ coords_out[0]=_tformP[0]
|
|
|
+ coords_out[1]=_tformP[1]
|
|
|
+ If coords_out.Length>2 coords_out[2]=_tformP[2]
|
|
|
+ Default
|
|
|
+ Throw "Invalid TransformCoords mode"
|
|
|
+ End Select
|
|
|
+ End Method
|
|
|
+
|
|
|
+ 'Private
|
|
|
+
|
|
|
+ Const DIRTY_RENDERTARGET:Int=1
|
|
|
+ Const DIRTY_VIEWPORT:Int=2
|
|
|
+ Const DIRTY_SHADER:Int=4
|
|
|
+ Const DIRTY_LINEWIDTH:Int=8
|
|
|
+ Const DIRTY_COLORMASK:Int=16
|
|
|
+
|
|
|
+ Field _seq:Int
|
|
|
+ Field _dirty:Int=-1
|
|
|
+ Field _image:TImage
|
|
|
+ Field _texture:TTexture
|
|
|
+ Field _width:Int
|
|
|
+ Field _height:Int
|
|
|
+ Field _twidth:Int
|
|
|
+ Field _theight:Int
|
|
|
+ Field _shadowMap:TImage
|
|
|
+ Field _colorMask:Int[]=[True,True,True,True]
|
|
|
+ Field _viewport:Int[]=[0,0,640,480]
|
|
|
+ Field _scissor:Int[]=[0,0,100000,100000]
|
|
|
+ Field _vpx:Int,_vpy:Int,_vpw:Int,_vph:Int
|
|
|
+ Field _scx:Int,_scy:Int,_scw:Int,_sch:Int
|
|
|
+ Field _clsScissor:Int
|
|
|
+ Field _projMatrix:Float[]=Mat4New()
|
|
|
+ Field _invProjMatrix:Float[]=Mat4New()
|
|
|
+ Field _viewMatrix:Float[]=Mat4New()
|
|
|
+ Field _modelMatrix:Float[]=Mat4New()
|
|
|
+ Field _ambientLight:Float[]=[0.0,0.0,0.0,1.0]
|
|
|
+ Field _fogColor:Float[]=[0.0,0.0,0.0,0.0]
|
|
|
+ Field _lights:TLightData[4]
|
|
|
+ Field _lineWidth:Float=1
|
|
|
+
|
|
|
+ Global _active:TCanvas
|
|
|
+
|
|
|
+ Method Init()
|
|
|
+ For Local i:Int=0 Until 4
|
|
|
+ _lights[i]=New TLightData
|
|
|
+ Next
|
|
|
+ _dirty=-1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method FlushPrims()
|
|
|
+ If Super.IsEmpty Return
|
|
|
+ Validate
|
|
|
+ Super.Flush
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Validate()
|
|
|
+ If _seq<>graphicsSeq
|
|
|
+ _seq=graphicsSeq
|
|
|
+ InitVbos
|
|
|
+ _dirty=-1
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If _active=Self
|
|
|
+ If Not _dirty Return
|
|
|
+ Else
|
|
|
+ If _active _active.Flush
|
|
|
+ _active=Self
|
|
|
+ _dirty=-1
|
|
|
+ EndIf
|
|
|
+
|
|
|
+' _dirty=-1
|
|
|
+
|
|
|
+ If _dirty & DIRTY_RENDERTARGET
|
|
|
+
|
|
|
+ If _texture
|
|
|
+ glBindFramebuffer GL_FRAMEBUFFER,_texture.GLFramebuffer()
|
|
|
+ Else
|
|
|
+ glBindFramebuffer GL_FRAMEBUFFER,defaultFbo
|
|
|
+ EndIf
|
|
|
+ End If
|
|
|
+
|
|
|
+ If _dirty & DIRTY_VIEWPORT
|
|
|
+
|
|
|
+ _vpx=_viewport[0];_vpy=_viewport[1];_vpw=_viewport[2];_vph=_viewport[3]
|
|
|
+ If _image
|
|
|
+ _vpx:+_image._x
|
|
|
+ _vpy:+_image._y
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ _scx=_scissor[0];_scy=_scissor[1];_scw=_scissor[2];_sch=_scissor[3]
|
|
|
+
|
|
|
+ If _scx<0 _scx=0 Else If _scx>_vpw _scx=_vpw
|
|
|
+ If _scw<0 _scw=0 Else If _scx+_scw>_vpw _scw=_vpw-_scx
|
|
|
+
|
|
|
+ If _scy<0 _scy=0 Else If _scy>_vph _scy=_vph
|
|
|
+ If _sch<0 _sch=0 Else If _scy+_sch>_vph _sch=_vph-_scy
|
|
|
+
|
|
|
+ _scx:+_vpx;_scy:+_vpy
|
|
|
+
|
|
|
+ If Not _texture
|
|
|
+ _vpy=_theight-_vpy-_vph
|
|
|
+ _scy=_theight-_scy-_sch
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ glViewport _vpx,_vpy,_vpw,_vph
|
|
|
+
|
|
|
+ If _scx<>_vpx Or _scy<>_vpy Or _scw<>_vpw Or _sch<>_vph
|
|
|
+ glEnable GL_SCISSOR_TEST
|
|
|
+ glScissor _scx,_scy,_scw,_sch
|
|
|
+ _clsScissor=False
|
|
|
+ Else
|
|
|
+ glDisable GL_SCISSOR_TEST
|
|
|
+ _clsScissor=(_scx<>0 Or _scy<>0 Or _vpw<>_twidth Or _vph<>_theight)
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If _dirty & DIRTY_SHADER
|
|
|
+
|
|
|
+ rs_program=Null
|
|
|
+
|
|
|
+ If _texture
|
|
|
+ rs_clipPosScale[1]=1
|
|
|
+ Mat4Copy _projMatrix,rs_projMatrix
|
|
|
+ Else
|
|
|
+ rs_clipPosScale[1]=-1
|
|
|
+ Mat4Multiply flipYMatrix,_projMatrix,rs_projMatrix
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ Mat4Multiply _viewMatrix,_modelMatrix,rs_modelViewMatrix
|
|
|
+ Mat4Multiply rs_projMatrix,rs_modelViewMatrix,rs_modelViewProjMatrix
|
|
|
+ Vec4Copy _ambientLight,rs_ambientLight
|
|
|
+ Vec4Copy _fogColor,rs_fogColor
|
|
|
+
|
|
|
+ rs_numLights=0
|
|
|
+ For Local i:Int=0 Until MAX_LIGHTS
|
|
|
+
|
|
|
+ Local light:TLightData=_lights[i]
|
|
|
+ If Not light.kind Continue
|
|
|
+
|
|
|
+ Mat4Transform _viewMatrix,light.vector,light.tvector
|
|
|
+
|
|
|
+ rs_lightColors[rs_numLights*4+0]=light.color[0]
|
|
|
+ rs_lightColors[rs_numLights*4+1]=light.color[1]
|
|
|
+ rs_lightColors[rs_numLights*4+2]=light.color[2]
|
|
|
+ rs_lightColors[rs_numLights*4+3]=light.color[3]
|
|
|
+
|
|
|
+ rs_lightVectors[rs_numLights*4+0]=light.tvector[0]
|
|
|
+ rs_lightVectors[rs_numLights*4+1]=light.tvector[1]
|
|
|
+ rs_lightVectors[rs_numLights*4+2]=light.tvector[2]
|
|
|
+ rs_lightVectors[rs_numLights*4+3]=light.Range
|
|
|
+
|
|
|
+ rs_numLights:+1
|
|
|
+ Next
|
|
|
+
|
|
|
+ If _shadowMap
|
|
|
+ rs_shadowTexture=_shadowMap._material._colorTexture
|
|
|
+ Else
|
|
|
+ rs_shadowTexture=Null
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ rs_blend=-1
|
|
|
+
|
|
|
+ End If
|
|
|
+
|
|
|
+ If _dirty & DIRTY_LINEWIDTH
|
|
|
+ glLineWidth _lineWidth
|
|
|
+ EndIf
|
|
|
+
|
|
|
+ If _dirty & DIRTY_COLORMASK
|
|
|
+ glColorMask _colorMask[0],_colorMask[1],_colorMask[2],_colorMask[3]
|
|
|
+ End If
|
|
|
+
|
|
|
+ _dirty=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+' stacks
|
|
|
+
|
|
|
+Type TFloatStack
|
|
|
+ Field data:Float[]
|
|
|
+ Field length:Int
|
|
|
+
|
|
|
+ Method Push( value:Float )
|
|
|
+ If length=data.Length
|
|
|
+ data=data[..length*2+10]
|
|
|
+ EndIf
|
|
|
+ data[length]=value
|
|
|
+ length:+1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Pop:Float()
|
|
|
+ length:-1
|
|
|
+ Local v:Float=data[length]
|
|
|
+ data[length]=Null
|
|
|
+ Return v
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Top:Float()
|
|
|
+ Return data[length-1]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Clear()
|
|
|
+ For Local i:Int=0 Until length
|
|
|
+ data[i]=Null
|
|
|
+ Next
|
|
|
+ length=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+Type TDrawOpStack
|
|
|
+ Field data:TDrawOp[]
|
|
|
+ Field length:Int
|
|
|
+
|
|
|
+ Method Push( value:TDrawOp )
|
|
|
+ If length=data.Length
|
|
|
+ data=data[..length*2+10]
|
|
|
+ EndIf
|
|
|
+ data[length]=value
|
|
|
+ length:+1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Pop:TDrawOp()
|
|
|
+ length:-1
|
|
|
+ Local v:TDrawOp=data[length]
|
|
|
+ data[length]=Null
|
|
|
+ Return v
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Top:TDrawOp()
|
|
|
+ Return data[length-1]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Clear()
|
|
|
+ For Local i:Int=0 Until length
|
|
|
+ data[i]=Null
|
|
|
+ Next
|
|
|
+ length=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+
|
|
|
+Type TShadowCasterStack
|
|
|
+ Field data:TShadowCaster[]
|
|
|
+ Field length:Int
|
|
|
+
|
|
|
+ Method Push( value:TShadowCaster )
|
|
|
+ If length=data.Length
|
|
|
+ data=data[..length*2+10]
|
|
|
+ EndIf
|
|
|
+ data[length]=value
|
|
|
+ length:+1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Pop:TShadowCaster()
|
|
|
+ length:-1
|
|
|
+ Local v:TShadowCaster=data[length]
|
|
|
+ data[length]=Null
|
|
|
+ Return v
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Top:TShadowCaster()
|
|
|
+ Return data[length-1]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Get:TShadowCaster(index:Int)
|
|
|
+ Return data[index]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Clear()
|
|
|
+ For Local i:Int=0 Until length
|
|
|
+ data[i]=Null
|
|
|
+ Next
|
|
|
+ length=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|
|
|
+
|
|
|
+Type TDrawListStack
|
|
|
+ Field data:TDrawList[]
|
|
|
+ Field length:Int
|
|
|
+
|
|
|
+ Method Push( value:TDrawList )
|
|
|
+ If length=data.Length
|
|
|
+ data=data[..length*2+10]
|
|
|
+ EndIf
|
|
|
+ data[length]=value
|
|
|
+ length:+1
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Pop:TDrawList()
|
|
|
+ length:-1
|
|
|
+ Local v:TDrawList=data[length]
|
|
|
+ data[length]=Null
|
|
|
+ Return v
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Top:TDrawList()
|
|
|
+ Return data[length-1]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Get:TDrawList(index:Int)
|
|
|
+ Return data[index]
|
|
|
+ End Method
|
|
|
+
|
|
|
+ Method Clear()
|
|
|
+ For Local i:Int=0 Until length
|
|
|
+ data[i]=Null
|
|
|
+ Next
|
|
|
+ length=0
|
|
|
+ End Method
|
|
|
+
|
|
|
+End Type
|