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 |
