We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpOpenGL and 3D Libraries › Gift #2: Fast 2D openGL Font
Pages: 1 2 
Gift #2: Fast 2D openGL Font (Read 8658 times)
Gift #2: Fast 2D openGL Font
Jun 15th, 2008, 9:57pm
 
Update 2: Fixed a font width problem.
UPDATE: I've changed the code so that it works with any character (ASCII or Extended Characters) that the respective PFont can display.

Alright, so i decided to make a class that will convert any font you could normally create using "createFont" into an ultra efficient object.
Each character is rendered as a point sprite display lists. _Added bonus_: It works in ortho projection mode!

Note: this works on my macbook pro which has an Nvidia card. Point Sprites are sort of fickle and may not be supported on your machine.

to use it:
Code:

//set everything up as usual
PGraphicsOpenGL pgl = ((PGraphicsOpenGL)g);
GL gl = pgl.beginGL();

// GLFont (opengl Context, font name, size (in pixels), smooth)
GLFont gltext = new GLFont(gl, "Monaco",26, true);
gltext.setcolor( 1.0, 0.0, 0.0, 1.0);
pgl.endGL();

....
//somewhere in your render
gl = pgl.bignGL();
gltext.write(gl, "Joey Joe-Joe Junior Shabadoo" ,  20, 20);
pgl.endGL();

....
//when you dont need text any longer
gltext.deallocate(gl);



Ok here's the class:
Code:

class GLFont{
 int _texsize, _tex[], _list[];
 float _size, _charwidth[], _color[];
 String _name;
 Hashtable _charmap;
 
 GLFont(GL gl, String fontName, float fontSize, boolean smoothFont){
   PFont font = createFont(fontName, fontSize, smoothFont);
   textFont(font);
   textMode(MODEL);

   _name = fontName;
   _size = fontSize;
   _texsize = font.images[0].width;
   _tex = new int[280];
   _list = new int[280];
   _charwidth = new float[280];
   _charmap = new Hashtable();
   setcolor(1,1,1,1);

   ByteBuffer tempBuf;
   boolean noImage;
_charwidth[32] = textWidth( " " );
   for(int index=0; index<280; index++){
     _charmap.put( new Character( char(font.value[index]) ), new Integer(index) );
     _charwidth[index]= textWidth(char(font.value[index]));

     noImage = true;
     tempBuf = ByteBuffer.allocate( 4 * font.images[index].pixels.length );
     for(int t=0; t< font.images[index].pixels.length; t++){
       tempBuf.putInt(  t*4, (255<<24)+(255<<16)+(255<<8)+(font.images[index].pixels[t]) );
       if( font.images[index].pixels[t] >0 ) noImage = false;
     }
     tempBuf.rewind();
     if( noImage ) continue;

     _tex[index] = glNewTex(gl, GL.GL_TEXTURE_2D, _texsize, _texsize, GL.GL_RGBA, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE,  GL.GL_NEAREST, GL.GL_NEAREST,  tempBuf);    

     //generate and build the display list
     _list[index] = gl.glGenLists(1);
     gl.glNewList( _list[index] ,GL.GL_COMPILE);
       gl.glActiveTexture( GL.GL_TEXTURE0);
       gl.glEnable( GL.GL_TEXTURE_2D );
       gl.glBindTexture( GL.GL_TEXTURE_2D, _tex[index] );

       gl.glPushMatrix();
       gl.glBegin(GL.GL_POINTS);
         //i shift the pixel to the char's correct distance from the baseline
         gl.glVertex2f( _texsize/2 +font.leftExtent[index] , _size + _texsize/2 -font.topExtent[index] );
       gl.glEnd();
       gl.glPopMatrix();
     gl.glEndList();
   }
   gl.glActiveTexture( GL.GL_TEXTURE0);
   gl.glEnable( GL.GL_TEXTURE_2D );
   gl.glBindTexture( GL.GL_TEXTURE_2D, 0 );
 }

 void deallocate(GL gl){
   gl.glDeleteTextures(128, _tex, 0);
   gl.glDeleteLists(128, _list[0] );
 }

 void setcolor(float r, float g, float b, float a){
   _color = new float[]{r,g,b,a};
 }
 
 void write(GL gl, String l_text, float x, float y){
   gl.glPushAttrib( GL.GL_ALL_ATTRIB_BITS );
   gl.glPushMatrix();
   gl.glColor4f( _color[0], _color[1], _color[2], _color[3] );
   gl.glTranslatef(x,y,0);
   gl.glDepthMask(false);
   gl.glDisable(GL.GL_DEPTH_TEST);
   gl.glEnable(GL.GL_BLEND);  //blending is important for alpha

   //set up point sprites
   gl.glEnable(GL.GL_POINT_SPRITE);
   gl.glPointSize(_texsize);
   gl.glTexEnvi(GL.GL_POINT_SPRITE, GL.GL_COORD_REPLACE, GL.GL_TRUE);
   int len = l_text.length();
   int t;
   for(int i=0; i<len; i++){
     if( _charmap.containsKey( new Character( l_text.charAt(i) ) ) ){
       t = ( (Integer)_charmap.get( new Character( l_text.charAt(i) ) ) ).intValue();
       gl.glCallList( _list[t] );
       gl.glTranslatef( _charwidth[t], 0, 0 );
     }else if( l_text.charAt(i) == char(32) )
gl.glTranslatef( _charwidth[32], 0, 0 );
   }
   gl.glPopMatrix();
   gl.glPopAttrib();
 }
}

//Create a new texture of any type and pass back it's ID
int glNewTex(GL gl, int texType, int w, int h,  int internalFormat, int l_format, int dataType, int minFilter, int magFilter, Buffer data){
 gl.glActiveTexture( GL.GL_TEXTURE0 );
 gl.glEnable(texType);
 int[] temp = new int[1];
 gl.glGenTextures( 1, temp, 0 );

 gl.glBindTexture( texType, temp[0] );
 gl.glTexParameteri( texType, GL.GL_TEXTURE_MIN_FILTER, minFilter );
 gl.glTexParameteri( texType, GL.GL_TEXTURE_MAG_FILTER, magFilter );
 gl.glTexParameteri( texType, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE );
 gl.glTexParameteri( texType, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE );
 gl.glTexImage2D( texType, 0, internalFormat, w, h, 0, l_format, dataType, data );    
 gl.glActiveTexture( GL.GL_TEXTURE0);
 gl.glEnable( GL.GL_TEXTURE_2D );
 gl.glBindTexture( GL.GL_TEXTURE_2D, 0 );
 return temp[0];
}
Re: Gift #2: Fast 2D openGL Font
Reply #1 - Jun 16th, 2008, 3:17pm
 
nice, you want to add this to the hacks section?
Re: Gift #2: Fast 2D openGL Font
Reply #2 - Jun 16th, 2008, 4:45pm
 
UPDATE: I updated the code (see above) and will add this to the hacks section when i get a bit of time. I have another much larger sketch to demonstrate that i must finish

You know I just realized that it only works for ASCII charcters right now. It should be a quick fix but i want to extend it to character codes 127 and up before i add it to the hacks section.

Re: Gift #2: Fast 2D openGL Font
Reply #3 - Jun 18th, 2008, 8:45am
 
Would you like to collaborate and build a lib out of this with me? Vertext was doing something very similar.
Re: Gift #2: Fast 2D openGL Font
Reply #4 - Jul 2nd, 2008, 4:35pm
 
This doesn't work. . I tried adding Code:
import processing.opengl.*; 

but it still wouldn't compile.

Re: Gift #2: Fast 2D openGL Font
Reply #5 - Jul 2nd, 2008, 4:49pm
 
you probably need "import javax.media.opengl.*;" as well
Re: Gift #2: Fast 2D openGL Font
Reply #6 - Aug 8th, 2008, 8:40pm
 
Your class works fine on my MBP15 CoreDuo, thanks for sharing! I couldn't manage to use JOGL with Processing's OpenGL, though: I first did 3D stuff with Processing within pushMatrix and popMatrix, then started a 3D session using JOGL to do 2D text drawings. After that I couldn't continue with 3D stuff. Porting to JOGL solved this issue.

When do you call deallocate (glDeleteTextures, glDeleteLists) to free ressources? I always get a BAD MEMORY ACCESS in opengl.dylib, I think the GL canvas is already destroyed on stop(), close(), destroy() and finalize()? Does JOGL free OpenGL resources automatically, I am worried about memory leaks.
Re: Gift #2: Fast 2D openGL Font
Reply #7 - Nov 20th, 2008, 11:25pm
 
I have a question -- I think I am missing a step somewhere.

I set everything up and I just get gray boxes.  Is this the point sprite finicky-ness?  Or is it something I missed?
Re: Gift #2: Fast 2D openGL Font
Reply #8 - Nov 21st, 2008, 3:01am
 
I can't be sure what your setup is like but this sounds like GL_TEXTURE_2D is not enabled before you go to write the text. If that is the case try this:

Try changing the begining of the write() method to this:

Code:

void write(GL gl, String l_text, float x, float y){
gl.glPushAttrib( GL.GL_ALL_ATTRIB_BITS );
gl.glPushMatrix();
gl.glColor4f( _color[0], _color[1], _color[2], _color[3] );
gl.glTranslatef(x,y,0);
gl.glDepthMask(false);
gl.glDisable(GL.GL_DEPTH_TEST);
gl.glEnable(GL.GL_BLEND); //blending is important for alpha
gl.glEnable( GL.GL_TEXTURE_2D ); //Enable 2D Textures!
Re: Gift #2: Fast 2D openGL Font
Reply #9 - Feb 9th, 2009, 12:13am
 
Thanks for writing this code and posting the results; it works just as advertised.

I have one problem, however, that I hope will be easy to solve for someone who know more about OpenGL than I do (which must include most people reading this thread.)

When I use the GLFont class to draw a string, it always appears "behind" all the other 3D objects that I'm drawing. It's as if the text is drawn on a wall, and the 3D objects are floating in front of the wall, partially obscuring the text.

I'd like to have the text floating in a visual plane that will always render in front of my 3D objects, rather than behind them. Is there a way for me to modify the code to make this happen?

Thanks for any tips.
Re: Gift #2: Fast 2D openGL Font
Reply #10 - Feb 9th, 2009, 10:47am
 
here's another textwriter in opengl for 2d/3d mode.


how to use:

VTextRenderer textRender;

void setup()
{
 textRender = new VTextRenderer( "Arial", 32 );
}

void draw()
{
textRender.print( "singing in the rain", 0, 10, 0, 0.2 );
}


-------------------------------------------------------

import java.text.*;
import com.sun.opengl.util.*;
import com.sun.opengl.util.j2d.*;

class VTextRenderer
{
 VTextRenderer( String fontName, int size )
 {
   _fontName = fontName;
   _fontSize = size;
   _textRender = new TextRenderer( new Font(fontName, Font.TRUETYPE_FONT, size), true, true, null, true );
   _textRender.setColor( 1.0f, 1.0, 1.0, 1.0 );
   //_textRender.setUseVertexArrays( true );
 }

 VTextRenderer( String fontName, int size, boolean antialiased, boolean mipmap )
 {
   _fontName = fontName;
   _fontSize = size;
   _textRender = new TextRenderer( new Font(fontName, Font.TRUETYPE_FONT, size), antialiased, true, null, mipmap );
   _textRender.setColor( 1.0f, 1.0, 1.0, 1.0 );
   //_textRender.setUseVertexArrays( true );
 }
 
 
 void print( String str, int x, int y )
 {
   _textRender.beginRendering( width, height, true );
   _textRender.draw( str, x, y );
   _textRender.endRendering();  
   _textRender.flush();
 }

 void print( String str, float x, float y, float z )
 {
   print( str, x, y, z, 1.0f );
 }

 void print( String str, float x, float y, float z, float s )
 {
   _textRender.begin3DRendering();
   _textRender.draw3D( str, x, y, z, s );
   _textRender.end3DRendering();  
   _textRender.flush();
 }

 void setColor( float c )
 {
   setColor( c, c, c, 1 );
 }

 void setColor( float c, float a )
 {
   setColor( c, c, c, a );
 }

 void setColor( float r, float g, float b )
 {
   setColor( r, g, b, 1 );
 }
 
 void setColor( float r, float g, float b, float a )
 {
   _textRender.setColor( r, g, b, a );
 }
 
 void setSmoothing( boolean flag )
 {
   _textRender.setSmoothing( flag );
 }


 /// ____________________________________________________
 /// Members
 int _w, _h;
 
 String _fontName;
 int _fontSize;
 TextRenderer _textRender;
 Font font;
 
}

Re: Gift #2: Fast 2D openGL Font
Reply #11 - Feb 9th, 2009, 9:39pm
 
I like this VTextRenderer class. Since my sketch is already married to JOGL, it makes sense to build on the existing JOGL TextRenderer class. I wasn't even aware that the TextRenderer class existed.

But my problem using VTextRenderer is the same as before. When I call VTextRenderer in 2D mode, using only x and y location parameters, I still end up with the text "behind" my 3D objects, as I explained/complained in my first post.

If I try calling VTextRenderer with x, y, and z parameters, I don't see text rendered at all. I don't need to use 3D text, and in fact I think I don't want text in 3D space, but I'm afraid that not seeing the text is another indication of my limited understanding of OpenGL.

When mixing 2D and 3D OpenGL objects, how do you position the 2D plane relative to the 3D objects and the screen view's z depth?
Re: Gift #2: Fast 2D openGL Font
Reply #12 - Feb 9th, 2009, 10:50pm
 
i dont see what the problem is. i just tried a simple processing test and it works just fine.

you might be having problem with your matrix states. you will need to reset your modelview to ortho mode to draw over the screen. or then disable DEPTH_TEST to reset on top.


Code:

VTextRenderer textRender;

void setup()
{
size( 800, 600, OPENGL );

textRender = new VTextRenderer( "Arial", 32 );

rectMode( CENTER );
}

void draw()
{
float time = millis() * 0.001;

background( 0 );
perspective( PI*0.25, 1.33333, 1, 1000 );
camera( 0, 0, 100, 0, 0, 0, 0, 1, 0 );

rotateY( time*.60 );
rotateZ( time*.60 );
rotateX( time*.60 );
rect( 0, 0, 80, 80 );

textRender.setColor( 0.3, 0.3, 0.3, 1 );
textRender.print( "testing.1.2.3", (int)(200+sin(time)*200), 400 );
}
Re: Gift #2: Fast 2D openGL Font
Reply #13 - Feb 10th, 2009, 1:40am
 
You're right that your example works fine, and your right that I almost certainly have a matrix state problem. It's amazing that I've gotten as far as I have (and almost as far as I need to go) with so little understanding of how to setup and use OpenGL matrices.

My code does lots of matrix pushing and popping. Most of my view manipulation is done using modified versions of other's examples. The curse of borrowed code is that I never really know why it works, and more to the point, why it doesn't.

However, I've found that if I rearrange the order in which I draw my 3D objects and my 2D text, I can get the text to "float" on top as I want it, and as you've done in your example.

Once I have the rest of my features in place, I'll try and go back to figure out what's actually going on in my code. For now, I'm happy to have just gotten past this obstacle.

Your VTextRenderer looks to me like a superior solution to the original "Gift #2." I'd call it Gift 3.0. Thanks to your guidance, I'm ready and able to move on.
Re: Gift #2: Fast 2D openGL Font
Reply #14 - Mar 6th, 2009, 8:57pm
 
I can't get the 3d (x,y,z position) in VTextRenderer to work.  It just doesn't display anything.  Works with 2d (x,y).
Pages: 1 2