Multilingual characters in Android opengl ES

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

http://fractiousg.blogspot.hk/2012/04/rendering-text-in-opengl-on-android.html

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);
mBitmap.eraseColor(0);

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 :

gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
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.

New Version of Big2 Online released

Finally… After some productive off days during the holidays, we managed to release new versions on both iOS and Android platoform.

iOS : http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=375750079&pageNumber=0&%20sortOrdering=1&type=Purple+Software&mt=8

Android  : https://play.google.com/store/apps/details?id=hk.com.smapp.big2online&feature=search_result#?t=W251bGwsMSwxLDEsImhrLmNvbS5zbWFwcC5iaWcyb25saW5lIl0.

We put in so many stuff i don’t even know where to begin. So i will take a short break and come back with a post about the last thing we added – Multilingual support in OpenGL ES.

The JDBC Timestamp Timezone problem!!!

Well our development of the Android version of Big2Online is getting towards the end. We are now updating the server so we can push to both iOS and Android. We will be using GCM to do the push for android, but that’s a topic for another time. We just spent the last few hours trying to improve our design a little. One thing we want to know is when did a user last login. That sounded very simple. All we have to do is the set the last login field to the current timestamp whenever there is an update. You can do that easily through mysql.

Well if it were that simple i wouldn’t be writing this. The problem was that we already had a field that keeps track of the registered time, so that field used the current_timestamp function, that is not allowed in mysql. Now what? well we will just update the last login field through jdbc when we are logging in through java. sounded simple enough right? we just create a date object in java and update the resultset we got from jdbc.

Date now = new Date();

resultset.updateTimestamp(“lastlogin”, new java.sql.Timestamp(now.getTime());

that would actually do the job. Except for one thing, if you use an update statement, using the now() function within mysql, the field will be updated to the current time on the db server, in our case a GMT timezone. However the jdbc driver doesn’t know that, it thinks the db server is in the same timezone as the java server. For example, since we are in Hong Kong, 8am here means 0am on the db server, so if i login 8am in hong kong, the db should have a value of 0am in the “lastlogin” field, but it’s actually not the case!! but since jdbc got the timezone wrong, the value is 8am instead!! Regardless of what timezone you set on a Date object in java, it still represents the same point in time, there will only be a difference in display. so the fix cannot lie in modifying the date object in java. It took us a while to realize that the problem probably lies with jdbc having the wrong assumption about the db timezone, once we have realized that, we found this :

http://stackoverflow.com/questions/7605953/how-to-change-mysql-timezone-in-java-connection

All we need was to add useLegacyDatetimeCode=false to the jdbc url and BAM!!, everything is working now.

 

 

 

Android Big 2 Part II.Text Input on OpenGLES

If you read our post on September 21st, you would know that we got stuck because of the 24MB memory limit on android application. The day after writing that post we decided to rewrite the app in OpenGL ES.

Since this is a simple 2D card game, we have decided to make the game is GL 1.x so even older devices can run it. There are a million tutorials on openGL so i won’t be spending much time discussing it. After 10 days of learning and rewriting and what not, we have finished the single player end of the game and now working on the online part of the game. The one problem we ran into when adding the online functionality is somewhat weird. It has nothing to do with socket programming or buffer size or connection speed, (all of which we have dealt with on the iOS version and the server side). The problem was we have to ask the users to login and thus requires them to input text on their android devices.

When we were writing apps in simple android views, it’s just a matter of adding an EditText view. But with GLSurfaceView that is not as easy. So we tried few approaches

1. Wrap a onkeylistener, get the key pressed and then show it on the screen ourselves.

Problem : normally this approach would work, but on an android phone, the soft keyboard does not necessarily fire an event to the onkeyListener. A simple google search tells us that getting alphabets from the soft keyboard is easier said than done. We can show the keyboard but we just can’t recognize the alphabet keys….

2. Use addContentView on top of the GLSurfaceView. http://gamedev.stackexchange.com/questions/11143/is-it-possible-to-overlay-edittext-box-on-a-glsurfaceview-on-android

This sounded like a promising approach but I just couldn’t get it to work. Maybe if we show the text field from the very beginning it would work. However we are trying to show and hide the text field based on some other events, so the renderer will have to tell the context when to show the text field. I cannot think of a good way to present that text field on top of the GL screen, but i didn’t even get to that. I was stopped by a mainthread exception or something like that. I did all the runOnUiThread stuffs but yet it still does not work, plus even if it did work i couldn’t think of a good way of presenting this, I gave up after a little while.

3. AlertDialog with text input.

One thing i love about android is how easy you can manipulate the alertdialog. It has just a normal view and you can put any elements you want in it.Best of all you can just use it with GLES, With a dialog you don’t really need to fit the elements with your GL screen, which makes life much easier. within minutes we already have something that is workable and looks reasonable. Once we tested the login function, we called it a day and i get to share this experience with everyone. The game should be ready in a couple of weeks, stay tuned :>

Ting

Android Version of Multiplayer Big 2

These blogs are not in chronological orders, but this post is about something we are doing today.

We used simple sprites instead of OpenGL for the iOS version of the game, we thought we could do the same for the Android version. In iOS development, you can do a lot with sprites because of the way UIView and UIImageView work. It has a very complete set of listeners and you can easily move each view around. This is of course partly due to the fixed screen size nature of the iPhone, if i say something should be at point (x,y), it will look right on all iPhone (until iPhone 5!! GRRR….). On the other hand, android developer needs to take care of hundreds of different devices, so a lot of the apps interfaces are designed using xml layout files and depending on the device they will be arranged differently. That is fine for utility apps but when it comes to games it’s a different story. Without an equivalent of UIImageView, we simply use a canvas to draw the bitmaps of images. To deal with different screen size, we just used a bit of scaling code to make sure every device can get a stretched version of the game. It’s nothing fancy but it should get the job done.

We were going down this road but today we realized there was something we didn’t think about…. The memory limit for each process on Android is 24MB!!!!! Well, on a old android phone that seems quite reasonable but on  something like a S3 if you are looking to make a reasonably good looking game with sprites you probably need high quality images. On the iOS i read all 52 cards from files and store them in memory, but in the android emulator it just ran into an Out Of Memory exception….. I am aware of some work arounds like :

http://blog.javia.org/how-to-work-around-androids-24-mb-memory-limit/

but it just seems quite silly to have a 24MB limit considering how powerful the new phones are.

Two lessons we learned here. Lesson 1. OpenGL from now on. Once we are done with this game, we will be using Unity to develop all our future games. If the memory is allocated from OpenGL, it does not count towards the 24MB limit. Lesson 2, even though i like google as a company more than i like apple, the way Android keeps trying to accommodate all devices is really annoying to me. We want to create or at least try to create apps that looks good on the latest devices. With apple, you can always target the latest generation of iPhone. Apple themselves create iOS that is practically impossible to run on older iPhones anyway, so no one will blame us. With Android, it feels like you are creating a website that has to be compatible with IE6….. it’s not fun.

 

 

The Road to Multiplayer big 2

For the past couple of months we have been working hard on a 2 years old game we developed for iOS. It is our favorite card game and one of the first apps we developed. (You can find the app here.) The plan was always to make it a cross-platform multiplayer game but for various reasons (mainly because we need to eat) we have put it off.

Finally in July this year we managed to release a new version that has online capability. It was in itself not anything special, there are many multiplayer games out there. We are still happy because we wrote everything from ground up. We didn’t use any of the multiplayer framework out there, we just used java.nio and sockets to get everything done. We know we were reinventing the wheel but it was a fun process. We are blogging to share the continuing experience with whoever is interested. Hope we can all learn something.

 

Our development blog is finally up!

We have been thinking about putting up a blog talking about problems we run into when we are developing. We are not sure whether this blog will attract any traffic but at the least this blog will be a record of our progress in dealing with different problems :>

We have some experience in development but no one is perfect, so if you find any errors in our posts please kindly let us know so we can learn.