The last thing we added to the app was multilingual support. We did not plan to add it so soon, the problem was that people were starting to login using facebook, and boom the username name all became ?????. That’s no good especially when we are targeting so many international users. For us support other language is easy on iOS because we did not use opengl on the iOS version (only reason we did not was because we did not have to, that would be the answers to a lot of the decisions we made, “because we can!!”) , so as long as we have the right settings on mysql, storing unicode username etc. is easy. However showing weird characters on android is much more difficult and we learned a lot of useful info that i will be sharing here.
If you are doing openGL and you are having problem with printing text on the screen, just take some time and read Nehe Productions’ tutorials. .. . .. . .. Ok, i believe you have all spent time to read the tutorials and now understand how to print text on screen. But just to refresh your memory, here is the general idea if you are dealing with the English language only. You first create a bitmap that includes each letter and symbol that you are going to use.and whenever you need to write something, you use the letters’ texture regions to show the letters one by one. Sounds easy right? this site
has the complete code on how to do that.
The “load()” method is where you should be paying attention.
// load the font and setup paint instance for drawing
Typeface tf = Typeface.createFromAsset( assets, file ); // Create the Typeface from Font File
Paint paint = new Paint(); // Create Android Paint Instance
paint.setAntiAlias( true ); // Enable Anti Alias
paint.setTextSize( size ); // Set Text Size
paint.setColor( 0xffffffff ); // Set ARGB (White, Opaque)
paint.setTypeface( tf ); // Set Typeface
this is where you set the font and size of the letters you want. You can also decide what resolution to use depending on the screen.
// create an empty bitmap (alpha only)
Bitmap bitmap = Bitmap.createBitmap( textureSize, textureSize, Bitmap.Config.ALPHA_8 );
Canvas canvas = new Canvas( bitmap ); // Create Canvas for Rendering to Bitmap
bitmap.eraseColor( 0×00000000 ); // Set Transparent Background (ARGB)
now we create a bitmap and at the end we draw the characters one by one into the canvas using the paint (style) we created.
canvas.drawText( s, 0, 1, x, y, paint ); // Draw Character
after we have drawn all the characters to the bitmap, we create a texture from it
glGraphics.getGL().glBindTexture( GL10.GL_TEXTURE_2D, textureId ); // Bind Texture GLUtils.texImage2D( GL10.GL_TEXTURE_2D, 0, bitmap, 0 ); // Load Bitmap to Texture
(of course there are more things to take care of like filter and wrapping and width and height etc., but this is the basic idea). From this point on, we can use the texture to write whatever character we want. And at this point we are very happy except that if a character is not in the texture, we won’t be able to draw it. To support multilingual characters, we will have to have an extremely big texture file…. I don’t know how many different characters there are, but with Chinese characters alone, we are pretty much screwed with this method. (which btw is the most memory efficient way if you are only dealing with limited number of different characters, comparing to the method i am introducing next.)
Clearly we cannot write all the characters into the texture, what’s the next best thing to do? well we can use sprite text, which means for each sentence or a set of words, we create a sprite for it and use the sprite to the word/sentence instead of writing it character by character. Google actually provided an example on how to do that. It is inside Android example ApiDemos -> com.exmaple.android.apis.graphics.spritetext
Within it there are two files i want to talk about.
1. NumericSprite.java -> this is basically what we had before, there are only so many numeric characters, we can easily get them all into one texture.
2. LabelMaker.java -> this is the most important part, label means a sprite here, this is where you create the different sprites you need. You start creating by calling beginAdding(gl) which creates a bitmap
mBitmap = Bitmap.createBitmap(mStrikeWidth, mStrikeHeight, config);
mCanvas = new Canvas(mBitmap);
this bitmap will hold all the labels and later you will create a texture using this. (i hope this sounds familiar). And then you just write each text you want to create a label for into the texture. The text can be in whatever language you want, and by this little change we already have multilingual support. (make sure you have a variable(s) to keep track of where you put each text)
mCanvas.drawText(text, x, y, textPaint);
and we create the texture just like above :
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0);
It’s exactly the same as before!! the only difference is what to put into the texture. In the first method, we put in the letters one by one so when we need a word we pick the letters and combine them to create a word. However in the second method we can an image of the whole sequence and when we need to show the sequence we just put the whole thing in. In the example from GOOGLE, they paste the whole sprite without any modification by using
((GL11)gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, label.mCrop, 0);
((GL11Ext)gl).glDrawTexiOES((int) x, (int) y, 0, (int) label.width, (int) label.height);
this is fine as is, but if you want to have different colors or different alpha, you can roll out your own draw method, which is just like any other draw method because you have your own texture already, so do whatever you want to do with it. There is one for thing to keep in mind, if you are using the second method (sprite text), you need to update the texture whenever there are new text you want to show. I hope this helps.