Dynamicly drawing to a texture
BlitzMax Forums/OpenGL Module/Dynamicly drawing to a texture
| ||
hello peeps. Im having a bit of trouble when drawing to a texture during runtime. I figured out I need to draw my stuff to the backbuffer first, then copy it to an existing OpenGL texture. This is no problem in itself, but the problem arises during the drawing to the backbuffer. There is no actual Flip()/swapbuffer command issued during the texture drawing, and the actual drawing of the scene in the main loop occurs later on in the code, so there is a glCear()/Cls() issued later in the code. But for some reason, the stuff I draw still apears on the screen, but just for a split second it's visible before being replaced by the actual scene. Why is this happening? here is the routine I use for drawing to the texture. Method UpdateTexture() If( Lines.Length = 0 ) Then Return; End If '// are we in Render or Select mode? '// (Select mode is used by Entity.__getPicked() routine) Local rm:Int; glGetIntegerv( GL_RENDER_MODE, Varptr rm ); If( rm <> GL_RENDER ) Then Return; '// If( AsciiTables = Null ) Then '// GenerateAsciiTables(); '// End If If( (Texture[0] = Null) Or ((Texture[0].Width <> (Size.x * 2)) Or (Texture[0].Height <> (Size.y * 2))) ) Then Local img:TImage = CreateImage( Size.x * 2, Size.y * 2 ); Texture[0] = GLTexture.FromImage( img ); End If SetAlpha( 1 ); TileImage( Texture[1].Image ); Local x:Float = 2.0; Local y:Float = 2.0; Local maxlines:Int = Texture[0].Height / TextHeight( "M" ); Local startline:Int = 0; If( maxlines < Lines.Length - 1 ) Then startline = (Lines.Length - 1) - maxlines; End If For Local l:TBLine = EachIn Lines If( l.Position >= startline ) Then For Local w:TBWord = EachIn l.Words For Local t:TBToken = EachIn w.Tokens t.Draw( x, y ); x :+ TextWidth( Chr(t.Value) ); Next x :+ TextWidth(" "); Next y :+ TextHeight( " " ); x = 2.0; End If Next glCopyTexSubImage2D ( .. Texture[0].Texture.ID, .. '// target 0, .. '// level 0, 0, .. '// xoffset, yoffset 0, Stage.Instance.StageHeight - Texture[0].Height, .. '// x , y Texture[0].Width, Texture[0].Height.. '// width, height ); oldText = Text; End Method the t.Draw( x, y ); routine is simple: Method Draw( lx:Float = -1, ly:Float = -1 ) If( lx = -1 ) Then lx = x; If( ly = -1 ) Then ly = y; If( IsSelected ) Then SetColor( 255-Word.Textbox.ForeColor[0], 255-Word.Textbox.ForeColor[1], 255-Word.Textbox.ForeColor[2] ); Else SetColor( Word.Textbox.ForeColor[0], Word.Textbox.ForeColor[1], Word.Textbox.ForeColor[2] ); End If DrawText( Chr(Value), lx, ly ); End Method This is not the only instance where I can actually see the backbuffer contents on my screen without it having been 'flipped'. Other parts of the code where I attempted drawing to a texture had a similar result. Note that I have tried various different things to make it go away. Like insert a CLS() at the end of the drawing routine. This does stop the drawn contents from showing on my screen, but instead it shows a completely black background for a split second. Either a backbuffer does not exist and everything is just drawn to the frontbuffer directly, or for some reason, either Max2D or OpenGL insists on swapping the front/back buffer without issuing an explicit Flip/SwapBuffer |
| ||
OpenGl will not flip the screen if you do not tell it to. If you can see stuff being drawn you do not have a backbuffer. Or you can put glDrawBuffer(GL_BACK) just to be sure. Having said that, on some systems it's idea of which is back and which is front is all screwed up. It should default to the backbuffer if there is one. I suggest testing to be sure that it may be drawing to the front buffer. Also call: Local a:Int glGetIntegerv(GL_DOUBLEBUFFER,Varptr(a)) print a (it might not be doublebuffer, maybe DOUBLE_BUFFERED. .. but it should tell you if there is one. |
| ||
thanks for the info. Unfortunatly it seems I am using a doublebuffer and drawing to the backbuffer so that rules out this possibility. :| ah well. time to dig further i guess |
| ||
As i'm researching this stuff, isn't there an aux buffers to render to and extract form? |
| ||
There are a number of extra buffers, but the they don't make any difference in my case. I found out that, eventhough not intended to, my draw-to-texture code was running during the main render loop in some cases. this caused the flickering of the screen. It's solved now. Now all I need is to find a proper way to render Text to a texture and still have it look OK. Atm either the texture turns out to be to small for the object im putting it on, or it looks really horrible. New drawing code Method Invalidate( r:Rectangle = Null ) Super.Invalidate( r ); If( (Text = oldText) Or (Tokens.Length = 0) ) Then Return; End If '// are we in Render or Select mode? '// (Select mode is used by Entity.__getPicked() routine) Local rm:Int; glGetIntegerv( GL_RENDER_MODE, Varptr rm ); If( rm <> GL_RENDER ) Then Return; If( (Texture[0] = Null) Or ((Texture[0].Width <> (Size.x * 2)) Or (Texture[0].Height <> (Size.y * 2))) ) Then Local img:TImage = CreateImage( (Size.x * 2), (Size.y * 2) ); Texture[0] = GLTexture.FromImage( img ); End If Local tw:Int = Texture[0].Width, th:Int = Texture[0].Height; GLTexture.AdjustTexSize( tw, th ); glViewPort( 0, 0, tw, th ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); SetAlpha( 1 ); SetBlend( ALPHABLEND ); TileImage( Texture[1].Image ); If( MultiLine ) Then Local x:Float = 2.0, y:Float = th; Local ncw:Int = tw / TextWidth( "M" ); Local nch:Int = th / TextHeight( "M" ); Local nx:Int = 0, ny:Int = 0, count:Int = 0; Local startline:Int = 0; If( ActiveControl = Self ) Then If( MouseZ() <> 0 ) Then If( OldMouseZ < MouseZ() ) Then ScrollOffset :- 1; Else If( OldMouseZ > MouseZ() ) Then ScrollOffset :+ 1; End If End If End If If( Linecount > nch ) Then startline = (Linecount - nch); startline :+ ScrollOffset; If( startline < 0 ) Then startline = 0; ScrollOffset :+ 1; End If If( startline > Linecount - nch ) Then startline = Linecount - nch; ScrollOffset :- 1; End If End If For Local t:TBToken = EachIn Tokens If( count >= startline + nch ) Then Exit; End If If( count >= startline ) Then Select( Chr(t.Value) ) Case "~n", "~r", "~r~n"; Default; t.Draw( x, y ); x :+ t.Rect.w; nx :+ 1; If( nx >= ncw ) Then x = 0; nx = 0; y :- t.Rect.h; ny :+ 1; End If End Select End If Select( Chr(t.Value) ) Case "~n", "~r", "~r~n"; If( count >= startline And count <= (startline + nch) ) Then x = 0; nx = 0; y :- TextHeight("M"); ny :+ 1; End If count :+ 1; End Select Next Else Local x:Float = 2.0, y:Float = 2.0; For Local t:TBToken = EachIn Tokens Select( Chr(t.Value) ) Case "~n", "~r", "~r~n"; Default; t.Draw( x, y ); x :+ t.Rect.w; End Select Next End If glBindTexture( GL_TEXTURE_2D, Texture[0].Texture.ID ); glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, tw, th, 0); glViewport( 0, 0, Stage.Instance.Width, Stage.Instance.Height ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glBindTexture( GL_TEXTURE_2D, 0 ); oldText = Text; End Method The resulting texture is not of the proper size to fit over the entire control (sprite) though. I have to adjust the texure size oin the above code to fit a Power of 2 Size, otherwise the glCopyTexImage2D() function fails. this causes some problems when Im trying to render the characters to it in the proper location. To make the texture and characters allign properly, I am resetting the viewport to the texture's size before the drawing starts. This method is taken from NeHe's Blur tutorial (#36). It doesnt work quite as intended though. The characters are very blurry. and the texture does not scale properly with the quad. the lines should stretch from the top of the screen, to the blue bar in the center. and from the left to the very right of the screen. This is what the texture looks like just after it has been drawn to the screen and before it is copied to the actual OpenGL texture. It is still somewhat blurry, but the direction of the characters, the horizontal size and the scaling of the lines is correct. |
| ||
What it looks like here is you are losing horizontal lines when the texture is squashed onto the area its supposed to go into, have you tried doubling the height of the font if thats possible before placing the texture. |
| ||
Hi, There is an OpenGL extension WGL_ARB_PBUFFER that does render to texture without using the backbuffer. Here's a link to a sample in C++ that does this: http://www.paulsprojects.net/opengl/rtotex/rtotex.html |
| ||
cool thanks :) edit: well that was shortlived :p My card doesn't support any of the extensions required for Pbuffer's :p Seems my GF FX 5700 is getting old :D |