123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610 |
- Strict
- Rem
- bbdoc: Graphics/OpenGL Max2D
- about:
- The OpenGL Max2D module provides an OpenGL driver for #Max2D.
- End Rem
- Module BRL.GLMax2D
- ModuleInfo "Version: 1.13"
- ModuleInfo "Author: Mark Sibly"
- ModuleInfo "License: zlib/libpng"
- ModuleInfo "Copyright: Blitz Research Ltd"
- ModuleInfo "Modserver: BRL"
- ModuleInfo "History: 1.13 Release"
- ModuleInfo "History: Cleaned up SetGraphics"
- ModuleInfo "History: 1.12 Release"
- ModuleInfo "History: Fixed filtered image min filters"
- ModuleInfo "History: 1.11 Release"
- ModuleInfo "History: Fixed texture delete logic"
- ModuleInfo "History: 1.10 Release"
- ModuleInfo "History: Add SetColor/SetClsColor clamping"
- ModuleInfo "History: 1.09 Release"
- ModuleInfo "History: Fixed DrawPixmap using current blend mode - now always uses SOLIDBLEND"
- ModuleInfo "History: 1.08 Release"
- ModuleInfo "History: Added MIPMAPPEDIMAGE support"
- ModuleInfo "History: 1.07 Release"
- ModuleInfo "History: Now default driver for MacOS/Linux only (D3D7 for windows)"
- ModuleInfo "History: 1.06 Release"
- ModuleInfo "History: Ripped out a bunch of dead code"
- ModuleInfo "History: 1.05 Release"
- ModuleInfo "History: Added checks to prevent invalid textures deletes"
- ?Not opengles And Not nx And Not raspberrypi And Not haiku
- Import BRL.Max2D
- Import BRL.GLGraphics
- Import BRL.Threads
- Private
- Global _driver:TGLMax2DDriver
- 'Naughty!
- Const GL_BGR=$80E0
- Const GL_BGRA=$80E1
- Const GL_CLAMP_TO_EDGE=$812F
- Const GL_CLAMP_TO_BORDER=$812D
- Global ix#,iy#,jx#,jy#
- Global color4ub:Byte[4]
- Global state_blend
- Global state_boundtex
- Global state_texenabled
- Function BindTex( name )
- If name=state_boundtex Return
- glBindTexture GL_TEXTURE_2D,name
- state_boundtex=name
- End Function
- Function EnableTex( name )
- BindTex name
- If state_texenabled Return
- glEnable GL_TEXTURE_2D
- state_texenabled=True
- End Function
- Function DisableTex()
- If Not state_texenabled Return
- glDisable GL_TEXTURE_2D
- state_texenabled=False
- End Function
- Function Pow2Size( n )
- Local t=1
- While t<n
- t:*2
- Wend
- Return t
- End Function
- Global dead_texs:TDynamicArray = New TDynamicArray(32),dead_tex_seq
- Extern
- Function bbAtomicAdd:Int( target:Int Ptr,value:Int )="int bbAtomicAdd( int *,int )!"
- End Extern
- 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
- Function DeleteTex( name,seq )
- If seq<>dead_tex_seq Return
- dead_texs.AddLast(name)
- End Function
- Function CreateTex( width,height,flags,pixmap:TPixmap )
- If pixmap.dds_fmt<>0 Return pixmap.tex_name ' if dds texture already exists
-
- 'alloc new tex
- Local name
- glGenTextures 1,Varptr name
-
- 'flush dead texs
- If dead_tex_seq=GraphicsSeq
- Local n:Int = dead_texs.RemoveLast()
- While n <> $FFFFFFFF
- glDeleteTextures 1, Varptr n
- n = dead_texs.RemoveLast()
- Wend
- EndIf
- dead_tex_seq=GraphicsSeq
- 'bind new tex
- BindTex name
-
- 'set texture parameters
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
-
- If flags & FILTEREDIMAGE
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
- If flags & MIPMAPPEDIMAGE
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR
- Else
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
- EndIf
- Else
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
- If flags & MIPMAPPEDIMAGE
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST
- Else
- glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
- EndIf
- EndIf
- Local mip_level
- Repeat
- glTexImage2D GL_TEXTURE_2D,mip_level,GL_RGBA8,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
- If Not (flags & MIPMAPPEDIMAGE) Exit
- If width=1 And height=1 Exit
- If width>1 width:/2
- If height>1 height:/2
- mip_level:+1
- Forever
- Return name
- End Function
- Function UploadTex( pixmap:TPixmap,flags )
- Local mip_level
- If pixmap.dds_fmt<>0 Return ' if dds texture already exists
- Repeat
- glPixelStorei GL_UNPACK_ROW_LENGTH,pixmap.pitch/BytesPerPixel[pixmap.format]
- glTexSubImage2D GL_TEXTURE_2D,mip_level,0,0,pixmap.width,pixmap.height,GL_RGBA,GL_UNSIGNED_BYTE,pixmap.pixels
- If Not (flags & MIPMAPPEDIMAGE) Exit
- If pixmap.width>1 And pixmap.height>1
- pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height/2 )
- Else If pixmap.width>1
- pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height )
- Else If pixmap.height>1
- pixmap=ResizePixmap( pixmap,pixmap.width,pixmap.height/2 )
- Else
- Exit
- EndIf
- mip_level:+1
- Forever
- glPixelStorei GL_UNPACK_ROW_LENGTH,0
- End Function
- Function AdjustTexSize( width Var,height Var )
- 'calc texture size
- width=Pow2Size( width )
- height=Pow2Size( height )
- Repeat
- Local t
- glTexImage2D GL_PROXY_TEXTURE_2D,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
- glGetTexLevelParameteriv GL_PROXY_TEXTURE_2D,0,GL_TEXTURE_WIDTH,Varptr t
- If t Return
- If width=1 And height=1 RuntimeError "Unable to calculate tex size"
- If width>1 width:/2
- If height>1 height:/2
- Forever
- End Function
- Type TDynamicArray
- Private
-
- Field data:Int Ptr
- Field size:Size_T
- Field capacity:Size_T
-
- Field guard:TMutex
-
- Public
-
- Method New(initialCapacity:Int = 8)
- capacity = initialCapacity
- data = malloc_(Size_T(initialCapacity * 4))
- guard = CreateMutex()
- End Method
- Method AddLast(value:Int)
- guard.Lock()
- If size = capacity Then
- capacity :* 2
- Local d:Byte Ptr = realloc_(data, capacity * 4)
- If Not d Then
- Throw "Failed to allocate more memory"
- End If
- data = d
- End If
-
- data[size] = value
- size :+ 1
- guard.Unlock()
- End Method
-
- Method RemoveLast:Int()
- guard.Lock()
- Local v:Int
-
- If size > 0 Then
- size :- 1
- v = data[size]
- Else
- v = $FFFFFFFF
- End If
-
- guard.Unlock()
-
- Return v
- End Method
- Method Delete()
- free_(data)
- CloseMutex(guard)
- End Method
-
- End Type
- Public
- Type TGLImageFrame Extends TImageFrame
- Field u0#,v0#,u1#,v1#,uscale#,vscale#
- Field name,seq
-
- Method New()
- seq=GraphicsSeq
- End Method
-
- Method Delete()
- If Not seq Return
- DeleteTex name,seq
- seq=0
- End Method
-
- Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
- Assert seq=GraphicsSeq Else "Image does not exist"
- Local u0#=sx * uscale
- Local v0#=sy * vscale
- Local u1#=(sx+sw) * uscale
- Local v1#=(sy+sh) * vscale
-
- EnableTex name
- glBegin GL_QUADS
- glTexCoord2f u0,v0
- glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
- glTexCoord2f u1,v0
- glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
- glTexCoord2f u1,v1
- glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
- glTexCoord2f u0,v1
- glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
- glEnd
- End Method
-
- Function CreateFromPixmap:TGLImageFrame( src:TPixmap,flags )
- 'determine tex size
- Local tex_w=src.width
- Local tex_h=src.height
- AdjustTexSize tex_w,tex_h
-
- 'make sure pixmap fits texture
- Local width=Min( src.width,tex_w )
- Local height=Min( src.height,tex_h )
- If src.width<>width Or src.height<>height src=ResizePixmap( src,width,height )
- 'create texture pixmap
- Local tex:TPixmap=src
-
- '"smear" right/bottom edges if necessary
- If width<tex_w Or height<tex_h
- tex=TPixmap.Create( tex_w,tex_h,PF_RGBA8888 )
- tex.Paste src,0,0
- If width<tex_w
- tex.Paste src.Window( width-1,0,1,height ),width,0
- EndIf
- If height<tex_h
- tex.Paste src.Window( 0,height-1,width,1 ),0,height
- If width<tex_w
- tex.Paste src.Window( width-1,height-1,1,1 ),width,height
- EndIf
- EndIf
- Else
- If tex.dds_fmt=0 ' not dds
- If tex.format<>PF_RGBA8888 tex=tex.Convert( PF_RGBA8888 )
- EndIf
- EndIf
-
- 'create tex
- Local name=CreateTex( tex_w,tex_h,flags,tex )
-
- 'upload it
- UploadTex tex,flags
- 'done!
- Local frame:TGLImageFrame=New TGLImageFrame
- frame.name=name
- frame.uscale=1.0/tex_w
- frame.vscale=1.0/tex_h
- frame.u1=width * frame.uscale
- frame.v1=height * frame.vscale
- Return frame
- End Function
- End Type
- Type TGLMax2DDriver Extends TMax2DDriver
- Method Create:TGLMax2DDriver()
- If Not GLGraphicsDriver() Return Null
-
- Return Self
- End Method
- 'graphics driver overrides
- Method GraphicsModes:TGraphicsMode[]() Override
- Return GLGraphicsDriver().GraphicsModes()
- End Method
-
- Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr,flags ) Override
- Local g:TGLGraphics=GLGraphicsDriver().AttachGraphics( widget,flags )
- If g Return TMax2DGraphics.Create( g,Self )
- End Method
-
- Method CreateGraphics:TMax2DGraphics( width,height,depth,hertz,flags,x,y ) Override
- Local g:TGLGraphics=GLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
- If g Return TMax2DGraphics.Create( g,Self )
- End Method
-
- Method SetGraphics( g:TGraphics ) Override
- If Not g
- TMax2DGraphics.ClearCurrent
- GLGraphicsDriver().SetGraphics Null
- Return
- EndIf
-
- Local t:TMax2DGraphics=TMax2DGraphics(g)
- Assert t And TGLGraphics( t._graphics )
- GLGraphicsDriver().SetGraphics t._graphics
- ResetGLContext t
-
- t.MakeCurrent
- End Method
-
- Method ResetGLContext( g:TGraphics )
- Local gw,gh,gd,gr,gf,gx,gy
- g.GetSettings gw,gh,gd,gr,gf,gx,gy
-
- state_blend=0
- state_boundtex=0
- state_texenabled=0
- glDisable GL_TEXTURE_2D
- glMatrixMode GL_PROJECTION
- glLoadIdentity
- glOrtho 0,gw,gh,0,-1,1
- glMatrixMode GL_MODELVIEW
- glLoadIdentity
- glViewport 0,0,gw,gh
- End Method
-
- Method Flip( sync ) Override
- GLGraphicsDriver().Flip sync
- End Method
-
- Method ToString$() Override
- Return "OpenGL"
- End Method
- Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags ) Override
- Local frame:TGLImageFrame
- frame=TGLImageFrame.CreateFromPixmap( pixmap,flags )
- Return frame
- End Method
- Method SetBlend( blend ) Override
- If blend=state_blend Return
- state_blend=blend
- Select blend
- Case MASKBLEND
- glDisable GL_BLEND
- glEnable GL_ALPHA_TEST
- glAlphaFunc GL_GEQUAL,.5
- Case SOLIDBLEND
- glDisable GL_BLEND
- glDisable GL_ALPHA_TEST
- Case ALPHABLEND
- glEnable GL_BLEND
- glBlendFunc GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA
- glDisable GL_ALPHA_TEST
- Case LIGHTBLEND
- glEnable GL_BLEND
- glBlendFunc GL_SRC_ALPHA,GL_ONE
- glDisable GL_ALPHA_TEST
- Case SHADEBLEND
- glEnable GL_BLEND
- glBlendFunc GL_DST_COLOR,GL_ZERO
- glDisable GL_ALPHA_TEST
- Default
- glDisable GL_BLEND
- glDisable GL_ALPHA_TEST
- End Select
- End Method
- Method SetAlpha( alpha# ) Override
- If alpha>1.0 alpha=1.0
- If alpha<0.0 alpha=0.0
- color4ub[3]=alpha*255
- glColor4ubv color4ub
- End Method
- Method SetLineWidth( width# ) Override
- glLineWidth width
- End Method
-
- Method SetColor( red,green,blue ) Override
- color4ub[0]=Min(Max(red,0),255)
- color4ub[1]=Min(Max(green,0),255)
- color4ub[2]=Min(Max(blue,0),255)
- glColor4ubv color4ub
- End Method
- Method SetColor( color:SColor8 ) Override
- color4ub[0]=color.r
- color4ub[1]=color.g
- color4ub[2]=color.b
- glColor4ubv color4ub
- End Method
- Method SetClsColor( red,green,blue ) Override
- red=Min(Max(red,0),255)
- green=Min(Max(green,0),255)
- blue=Min(Max(blue,0),255)
- glClearColor red/255.0,green/255.0,blue/255.0,1.0
- End Method
- Method SetClsColor( color:SColor8 ) Override
- glClearColor color.r/255.0,color.g/255.0,color.b/255.0,1.0
- End Method
-
- Method SetViewport( x,y,w,h ) Override
- If x=0 And y=0 And w=GraphicsWidth() And h=GraphicsHeight()
- glDisable GL_SCISSOR_TEST
- Else
- glEnable GL_SCISSOR_TEST
- glScissor x,GraphicsHeight()-y-h,w,h
- EndIf
- End Method
- Method SetTransform( xx#,xy#,yx#,yy# ) Override
- ix=xx
- iy=xy
- jx=yx
- jy=yy
- End Method
- Method Cls() Override
- glClear GL_COLOR_BUFFER_BIT
- End Method
- Method Plot( x#,y# ) Override
- DisableTex
- glBegin GL_POINTS
- glVertex2f x+.5,y+.5
- glEnd
- End Method
- Method DrawLine( x0#,y0#,x1#,y1#,tx#,ty# ) Override
- DisableTex
- glBegin GL_LINES
- glVertex2f x0*ix+y0*iy+tx+.5,x0*jx+y0*jy+ty+.5
- glVertex2f x1*ix+y1*iy+tx+.5,x1*jx+y1*jy+ty+.5
- glEnd
- End Method
- Method DrawRect( x0#,y0#,x1#,y1#,tx#,ty# ) Override
- DisableTex
- glBegin GL_QUADS
- glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
- glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
- glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
- glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
- glEnd
- End Method
-
- Method DrawOval( x0#,y0#,x1#,y1#,tx#,ty# ) Override
-
- Local xr#=(x1-x0)*.5
- Local yr#=(y1-y0)*.5
- Local segs=Abs(xr)+Abs(yr)
-
- segs=Max(segs,12)&~3
- x0:+xr
- y0:+yr
-
- DisableTex
- glBegin GL_POLYGON
- For Local i=0 Until segs
- Local th#=i*360#/segs
- Local x#=x0+Cos(th)*xr
- Local y#=y0-Sin(th)*yr
- glVertex2f x*ix+y*iy+tx,x*jx+y*jy+ty
- Next
- glEnd
-
- End Method
-
- Method DrawPoly( xy#[],handle_x#,handle_y#,origin_x#,origin_y# ) Override
- If xy.length<6 Or (xy.length&1) Return
-
- DisableTex
- glBegin GL_POLYGON
- For Local i=0 Until Len xy Step 2
- Local x#=xy[i+0]+handle_x
- Local y#=xy[i+1]+handle_y
- glVertex2f x*ix+y*iy+origin_x,x*jx+y*jy+origin_y
- Next
- glEnd
- End Method
-
- Method DrawPixmap( p:TPixmap,x,y ) Override
- Local blend=state_blend
- DisableTex
- SetBlend SOLIDBLEND
-
- Local t:TPixmap=p
- If t.format<>PF_RGBA8888 t=ConvertPixmap( t,PF_RGBA8888 )
- glPixelZoom 1,-1
- glRasterPos2i 0,0
- glBitmap 0,0,0,0,x,-y,Null
- glPixelStorei GL_UNPACK_ROW_LENGTH, t.pitch Shr 2
- glDrawPixels t.width,t.height,GL_RGBA,GL_UNSIGNED_BYTE,t.pixels
- glPixelStorei GL_UNPACK_ROW_LENGTH,0
- glPixelZoom 1,1
-
- SetBlend blend
- End Method
- Method GrabPixmap:TPixmap( x,y,w,h ) Override
- Local blend=state_blend
- SetBlend SOLIDBLEND
- Local p:TPixmap=CreatePixmap( w,h,PF_RGBA8888 )
- glReadPixels x,GraphicsHeight()-h-y,w,h,GL_RGBA,GL_UNSIGNED_BYTE,p.pixels
- p=YFlipPixmap( p )
- SetBlend blend
- Return p
- End Method
-
- Method SetResolution( width#,height# ) Override
- glMatrixMode GL_PROJECTION
- glLoadIdentity
- glOrtho 0,width,height,0,-1,1
- glMatrixMode GL_MODELVIEW
- End Method
-
- End Type
- Rem
- bbdoc: Get OpenGL Max2D Driver
- about:
- The returned driver can be used with #SetGraphicsDriver to enable OpenGL Max2D
- rendering.
- End Rem
- Function GLMax2DDriver:TGLMax2DDriver()
- Global _done
- If Not _done
- _driver=New TGLMax2DDriver.Create()
- _done=True
- EndIf
- Return _driver
- End Function
- Local driver:TGLMax2DDriver=GLMax2DDriver()
- If driver SetGraphicsDriver driver
- ?
|