WordMix Pro is now also available on Amazon Underground. This is identical to WordMix Pro, which is sold on the Amazon App Store or is available as an In-App Purchase to WordMix, but apps on Amazon Underground are “actually free” while fully featured. Get it now!
A recent WordMix update brings much improved support for Android tablets as well as experimental support for Japanese dictionary.
Improvements to the layout for 7″ and 10″ Android tablets were long overdue, fixing some issues where activities and controls looked out of place because they were initially created and optimised for mobile phones.
Further I based the App’s theme on Holo for Android 4 and on Material for Android 5, ditching the DeviceDefault as a recommendation. In my experience, vendors quite often ship a DeviceDefault implementation, that is inconsistent, incomplete and quite often breaks visual appearance. In order to work around inconsistent presentation on some Android devices, I have decided to pin the theme to a set of known appearance with some custom styling, bringing a consistent look across all Android 4 and Android 5 devices (Android 2 and 3 support has been removed).
Only new feature is the experimental support for Japanese as a language, including a Japanese dictionary (needs to be downloaded after installing the App). Japanese is particularly difficult to implement in this game due to the high number of different letters and combinations. Similar sound combinations have been combined as single letters, allowing to choose the specific sound by tapping on the dice. Feedback is appreciated!
As always, get it in Google Play Store, while it’s hot!
android.opengl.GLException: out of memory at android.opengl.GLErrorWrapper.checkError(GLErrorWrapper.java:62) at android.opengl.GLErrorWrapper.glGenTextures(GLErrorWrapper.java:350) at [...]
From the very limited information the Google Play Developer Console gives me about crash reports, I assumed it only affects devices running Android version 3. Modifying the code only caused the out of memory exception to be thrown at random other places, even at GL10.glClear(…)!
I also found out, the crash only happens when the user finishes a subactivity that would leave to the activity containing the GLSurfaceView. Users were complaining about the crash happening before starting a second game, which puzzled me, because all my rendering code seemed to be working fine on all devices running Android 4. Everything worked fine without the GLSurfaceView as well.
Looking that the source code for GLSurfaceView, nothing interesting was changed between Android 3.2 to Android 4, so the GLSurfaceView was hardly to blame, but more the hardware, drivers or specific OpenGL implementation.
The actual problem was very hard to track down and took me several hours and was particularly hard because I did not have an Android 3 tablet for debugging:
Up to Android 2.3, views were drawn in software and later composited using the hardware. Android 3 introduced an alternative hardware accelerated drawing engine for everything that uses Canvas classes. This alternative render path is disabled by default in Android 3 and supposedly enabled by default in Android 4 (previous blog post).
When I found out, that the Samsung Galaxy S2 does not enable hardware acceleration by default, I did set
<application android:hardwareAccelerated="true" ...>
in the AndroidManifest.xml for all activities that should support hardware acceleration. Using hardware acceleration for the activity with the anyway hardware accelerated GLSurfaceView did not make much of a difference. But accelerating the results or preferences activity, for example, gave a nice performance boost on my SGS2.
It turns out that the crash happens in Android, when an activity, that contains a GLSurfaceView, is paused for a fullscreen activity, that is hardware accelerated. When that hardware accelerated activity is finished, the underlying GLSurfaceView is screwed up, throwing out of memory exceptions, even though the GL context is completely reinitialized correctly.
Yes, I should have tested more the effects of hardwareAccelerated=”true”.
Leaving that attribute entirely unset is recommended for Android 3, especially when you use a GLSurfaceView, and should not hurt Android 4 devices as well. Setting a reasonable default value is then up to the manufacturers.
- If you use a GLSurfaceView in an activity
- and suspend that activity by starting another fullscreen activity
- and that activity is hardwareAccelerated by setting so in the AndroidManifest.xml
- and you target Android 3 devices
- expect weird behaviour like out-of-memory exceptions
Welcome to fragmentation. Just let hardwareAccelerated be unset.
So far only the paid Pro version is available, the free version, which comes without the nice 3D interface, might follow soon.
The review process took only about 4 work days.
Because the tiles are simple rectangles with round corners, I created a texture with gimp and rendered a quad in OpenGL. The texture had no mipmaps and was filtered linear for both, minimizing and magnifying. When rotating that quad, I got the typical “staircase” lines, because I did not use anti-aliasing / multisampling. The result looks rather horrible:
You can see two effects, one if it being the clear staircase borders, where the texture is not linear filtered, and you see the round corners of the texture with a grayish border, I’ll explain in the next paragraphs.
Multisampling emulation to remove “staircase”
So how to achieve multisampling in OpenGL ES 1.1? The answer I found is quite simple and easy on the hardware: use a texture with a transparent border and linear texture interpolation will do the rest. So I modified the texture to include a transparent border and rendered the quads slightly bigger to fill the same amount of pixels.
The result looked better but I was not satisfied with the borders. I saw the interpolations but there is still a very visible “staircase”. Plus it seems, that the borders are blended with a black color, which can be seen on the overlapping tiles:
This is in fact due to my texture, which had the transparent pixels assigned the color black. The OpenGL interpolation would just average two neighbour pixels, which would calculate like
(argb(1, 1, 1, 1) + argb(0, 0, 0, 0)) / 2 = argb(0.5, 0.5, 0.5, 0.5)
which is a semi transparent gray color tone.
Monkeying with gimp for transparent pixel
So how to create a texture, where the transparent pixels have the color white? Gimp seemed to screw up the color of transparent pixels even though when exporting my work as png file, it offers to keep the color of transparent pixels.
The trick: combine all visible planes, create an alpha channel and change the color layer. If you have uncombined planes, the result is unpredictable and the colors are screwed up.
So now I had a texture with a white but fully transparent border (value 0x00FFFFFF) and I’d expect the calculation to be
(argb(1, 1, 1, 1) + argb(0, 1, 1, 1)) / 2 = argb(0.5, 1, 1, 1)
But I still got the same result:
Bitmaps with transparent pixels in Android
So why is my border still black, while the texture has white transparent regions? I checked the loaded Bitmap with this code after loading the png resource:
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.stone); Log.d("texture", bmp.getPixel(0, 0)); /* result: 0 */
Why is the result 0?? I’d expect a 0x00FFFFFF, but either Androids Bitmap loader premultiplies the alpha or recompresses the image file on compile, although I did place the image in the res/drawable-nodpi folder.
But apparently Bitmap and Canvas throw away all color information, when drawing with an alpha value of 0. This results in a fully transparent, but black canvas:
canvas.drawColor(Color.argb(0, 255, 255, 255), Mode.SRC); Log.d("texture", bmp.getPixel(0, 0)); /* result: 0 */
while the following results in a white canvas, which is almost transparent (1/256):
canvas.drawColor(Color.argb(1, 255, 255, 255), Mode.SRC); Log.d("texture", bmp.getPixel(0, 0)); /* result: 0x01FFFFFF */
Good to know, so now I create my texture with a border that is almost transparent, but not completely (alpha value 1/256) and the color white, which should be hardly visible, calculating like:
(argb(1, 1, 1, 1) + argb(0.01, 1, 1, 1)) / 2 = argb(0.505, 1, 1, 1)
I checked with above Log code and indeed got the value 0x01FFFFFF. So at least the Bitmap was loaded correctly now. But I still get a black border and the result looks the same. Why?
Creating OpenGL textures with unmultiplied alpha
I found a post and bug report that apparently the GLUtils.glTexImage2D() screws with the alpha and colors too, creating texture values of 0x01010101, which gets blended with the nearby white pixels on linear filtering. What the…?
The post suggests a workaround to not use GLUtils to load the Bitmap into an OpenGL texture but use the original GL10.glTexImage2D(). While the code in that post is not very efficient, it does result in nice and smooth blended borders. Of course the use of mipmaps helps too to make the texture smooth when minified:
Several culprits were found to make antialiasing work with an Android App using OpenGL ES 1.1:
- Create textures that have transparent borders, so linear filtering emulated oversampling at polygon borders
- Make sure the transparent border of your texture contains color values, which will “bleed” into the border pixels of the texture.
- If you use mipmaps, make sure you have enough transparent border pixels or set GL_TEXTURE_WRAP to GL_CLAMP.
- Double check result, because gimp does screw up when having multiple layers, that are merged when exporting as png image.
- Androids Bitmap loader and Canvas code seems to zero out the color values when alpha is 0. The workaround to keep the color values on load: Use colored pixels with alpha value of 1 (of 255).
- The GLUtils.glTexImage2D implementation premultiplies alpha values with color values, resulting in very dark color, instead of the white I wanted. Use the GL10.glTexImage2D directly (example in this post).
Using mipmaps and adding a nice shadow texture results in a screen, that looks very similar to the original, but which is much faster:
The next WordMix and WordMix Pro release will include support for Russian, Portuguese and Dutch as dictionary languages. I had a lot of fun with the Cyrillic encoding of characters and especially the database for the words as I learned that a lot of Linux tools are still not ready for handling multi byte character sequences correctly.
Mostly the tool tr kept me busy, when I tried to convert lower case letters to upper case. The normal approach of
tr [:lower:] [:upper:]
only seems to work for the ASCII character set. If manually used on UTF-8 data, it screws everything up even more, like in the command:
tr \ абвгдеёжзийклмнопрстуфхцчшщъыьэюя \ AБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ
The trick was to use tr on the original KOI8-R encoded data (which is 8 bit), for which I also had to pass KOI8-R encoded parameters to the tool, which was a pain inside an otherwise UTF-8 encoded shell script. So I tried to read the KOI8-R encoded parameters from a file before passing it as arguments so I don’t screw up my shell script.
It took me several hours and attempts to find that out and to get all the encodings right, so now a working Russian dictionary is available. 🙂 It won’t be shipped by default though, so it needs to be fetched from the Internet once by the game, on first use.
Of course the global ranklist is prepared for the new languages as well.
I tried using the Blender modelling software to create a new featured image for WordMix in Google Play, but I just can’t wrap my head around it. The software has such a horrible UI, that after several hours of trying, I still was unable to create a dice looking object. The learning curve is very flat, I wish I had more time.
This is the result with 3dsmax instead:
The previous image was created with Gimp, based on a screenshot of the game, which I took in a tabet android emulator. It sure did look poorly modified and, compared to the screenshots in Google Play, it did not add anything more:
WordMix Pro arrived in the Google Play Store. While WordMix will stay free of charge, selling a pro-version will support the developing of the game and helpkeeping the free version adfree. So far the Pro version does not have much to offer but some more background images for the game. I do not intend to make the gameplay differ between the free and the payed version.
A 3D OpenGL interface for the game is under development and will be available in the pro-version soon.
Check out the first screenshot:
My first Android game is ready to be released in the Google Play Store (former Android Market).
The game is pretty simple and very similar to Toss Words, Spill and Spell, Perquackey or the German games Letra-Mix and Wörter Würfeln.
In the game you get a set of random letters and you have to arrange them in a limited time to valid words. The words are checked against a database of valid words using available spell checkers. After the first update, the game comes with support for English, German, Romanian, Spanish and French, both the dictionary and the localization of the user interface.
Get the game fresh from the Store, while it’s still hot: 🙂