Wednesday, December 28, 2011

(The hard way) OpenGL, Bypass the power of two (POT) restriction

Assuming you have decided to use OpenGL ES for your game and your designer drew all the backgrounds as 324×226 images like the one on the picture 1.





picture 1


During the development you load these backgrounds as textures in the OpenGL and you are happy watching nice graphic results on the emulator.

At some point of the timeline of your project you transfer the application on a real device and suddenly you realize than instead of a nice artwork you see a white square 324×226 (scaled at whatever scale-factor you have calculated according to the physical screen resolution)

What happened actually????

OpenGL ES binds only images where the width and the height are both power of 2 (POT).

This means, only 32×16, 128×64, 8×256 etc images are supported. It does not sound flexible, huh?. It is a certain restriction for your designer (I guess it is you!).

Newer GPUs that support OpenGL version 2.0 or above can load any arbitrary dimension but why to take such a huge risk?

In this tutorial I am showing to you a solution to this issue so to leave your talent free and wake up the hidden Van Gong who lives inside you and forget about any such kind of restrictions.

The main idea is very simple: You feed the engine with images of whatever dimension you want and the procedure that I am going to describe right now will split this image to the minimum amount of images with all their dimensions to be of POT.

In the example above, a background will be split in 12 images:

4 × 2
4 × 32
4 × 64
4 × 128
64 × 2
64 × 32
64 × 64
64 × 128
256 × 2
256 × 32
256 × 64
256 × 128

Like you can see on the picture 2




picture 2

Seeing this picture it is clear what steps has to be executed by an automated procedure:

  1. Express the width and the height of the image as a sum of numbers of only powers of two.

  2. Combine these numbers that sums the width with the numbers that sums the height and we have the dimensions of the new images.

  3. Crop the initial image using these dimensions and get all the part-images as also the coordinates of them in relation of the (0,0) corner of the initial image.

Expressing any natural number k∈N as a sum of powers of two is the same as to represent this number into the binary numeral system. In fact this is the definition of the binary numeral system.

Apply this step in our example:

324 = (101000100)2
= 1×28 + 0×27 + 1×26 + 0×25 +0×24 +0×23 + 1×22 + 0×21 +0×20
= 256 + 64 + 4
= 4 + 64 + 256

similar for the height
226 = (11100010)2
= 27 + 26 + 25 + 21
= 128 + 64 + 32 + 2
= 2 + 32 + 64 + 128

It would be handy for the second step if we had an array for the width and another for the height to store these constants. For example it could be:

for 324, int w[] = {4, 64, 256 }
for 226, int h[] = {2, 32, 64, 128 }

And since the speech is about arrays it raises automatically the need to allocate memory for them before making any operation on them. What we exactly seek is the appearances of ‘1’s in the binary representation of the number. Let’s introduce our first function

int bitCount ( int number)
{
     int ones = 0;
     for ( int i = 0; i < 16; i++ )
     {
          if ( (number&1) == 1 )
               ones++;
      number >>= 1;
     }
     return ones;
}


Nothing special has been used than just a few boring bitwise operations.
(...or you can simply use the Integer.bitCount(int i) static method of Java!!!!)

Now we can allocate memory for our arrays and play safely with them. According to your IDE environment you can use malloc (Ansi C) , NSMutableArray (iPhone) or the “new” operator (Android/Java/C++)

Using the same pattern we can fill the array with values.

void getPowersOfTwo ( int number, int[] array )
{
     int pos = 0;
     for ( int i = 0; i < 16; i++ )
     {
          if ( (number&1) == 1)
          {
               array[pos++] = (int) Math.pow((double) 2, (double) i);
          }
          number >>= 1;
     }
}


Be very careful about the precedence of the operators since pos++ here doesn't have the same effect as ++pos. (Why?)

After we have called this function on both w[] and h[] arrays we loop through their elements to build all pairs we need for the cropping.

There are (w.length)×(h.length) combinations. That means that for our example there will be 3×4=12 images.

For this purpose we introduce two nested “for” loops :

int fromX = 0;
int fromY = 0;
for ( int i = 0; i < w.length; i++ )
{
     for ( int j = 0; j < h.length; j++ )
     {
          System.out.printf("Crop %d x %d from (%d,%d\n", w[i],h[j],fromX,fromY);
          fromY += h[j];
     }
     fromY = 0;
     fromX += w[i];
} 


Inside the body of the second “for” it is where you have to call a special function of the standard graphics library (not the OpenGL) and get the part of the image that you can bind right after as an OpenGL-texture. The printf has everything we need: Where to crop from (and where in the OpenGL mesh to put) and what size to crop.

Of course you have to save also the values of fromX and fromY to a data structure and don't blast them into oblivion after this print-out.

Here are these functions for the main platforms that rule the galaxy nowadays:

Android:
Bitmap android.graphics.Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height) 


iPhone:
CGImageRef image = CGImageCreateWithImageInRect(CGImage source, rect);
UIImage*   uiimage = [UIImage imageWithCGImage:image];


And here is the output of this function on the console.

Crop 4 × 2 from (0,0)
Crop 4 × 32 from (0,2)
Crop 4 × 64 from (0,34)
Crop 4 × 128 from (0,98)
Crop 64 × 2 from (4,0)
Crop 64 × 32 from (4,2)
Crop 64 × 64 from (4,34)
Crop 64 × 128 from (4,98)
Crop 256 × 2 from (68,0)
Crop 256 × 32 from (68,2)
Crop 256 × 64 from (68,34)
Crop 256 × 128 from (68,98)

Is this all what you need? No, but it is the 90%.

I leave the remaining ...90% as an excercise.

Good luck

Saturday, December 17, 2011

How to draw your own buttons

In this tutorial I am presenting a way for the case where you don’t want to use the high level library to add buttons in a game (or whatever else application) and want to draw your own instead.

Suppose you are making a game for the iPhone using the OpenGL ES. Of course you can use UIKit buttons and simply lay them over your OpenGL view. Using UIKit buttons works fine and is probably the easiest way to add buttons to your game. However, if you are trying to achieve the best performance possible, you should avoid putting a UIView on top of your OpenGL view. This is especially true if you want to use the controls in the game, unless your game is a “Find The Differences”-like game.

And since everything in my engine is texture everything that you can imagine can be considered as a button. From graphics and single alphanumeric characters (this is very useful for the “write your name” menu) to words and entire phrases.

Three types of buttons are fully supported:

  • Buttons that fire a single signal of the touch event even when the button is kept pressed

  • Continuous sending of signals to the core mechanism of the game as long as the button is kept pressed

  • One signle signal only if the button is released after it has been pressed.



We do need a procedure for this because the operating system (iOS or Dalvik) triggers one single event when we click on the screen, no matter if we keep our finger on the screen.

As a first step we have to introduce a new structure (or class, in java) where we are going to store whatever is needed for a clickable object or Option, to speak more general.


public class Option
{
int x;
int y;
int width;
int height;
int type;
int prevState;
}


Where x,y are the (x,y) coordinates of the upper left corner of the option in actual screen coordinates, calculated in the initialization procedure of the clickable object that is bound with this option.
‘width’ and’ height’ is the width and the height of the object , again in screen coordinates.

The field ‘type’ stores the information of the type (what else?) of the option according to the three different cases as I described above. I have defined them as follow:


final static int OPTION_TYPE_INSTANT = 0;
final static int OPTION_TYPE_CONTINUOUS = 1;
final static int OPTION_TYPE_PRESSED = 2;


The ‘type’ property of the option can be changed on runtime to achieve other effect for the same button in different game situations.
In the field ‘prevState’ is stored the previous state of the clickable object. You don’t have to deal with it since it is calculated automatically from the procedure that I am going to attach here. This state is defined as 0 for previously not pressed and 1 for previously pressed.


final static int PREVIOUSLY_NOT_PRESSED = 0;
final static int PREVIOUSLY_PRESSED = 1;


So,I am ready to reveal how our function will look like


boolean hasTouchedOnOption ( Option option )


The function returns a ‘boolean’ (BOOL for iOS). This means that in the current iteration of the game loop an option is either active or not active.

Do we need anything else? As you can guess we need a ‘touch_x’ and a ‘touch_y’ variable that represent the coordinates of the point where the click has taken place. We need also a ‘pointerStates’ variable that will do exactly what it says.

In my engine there are two states for the pointer. A finger is either on the screen or it is not on the screen.


final static int POINTER_RELEASED = 0;
final static int POINTER_PRESSED = 1;

int pointerStates = POINTER_RELEASED;


I chose to declare all these three variables as global variables. They are initialized in the function that catches the touch events directly from the underlying hardware.

iPhone: touchesBegan, touchesMoved, touchesEnded
Android: public boolean onTouchEvent

I am pasting here my implementation for Android


@Override
public boolean onTouchEvent(MotionEvent event)
{
int action = event.getAction();
if ( action == MotionEvent.ACTION_OUTSIDE ||
action == MotionEvent.ACTION_UP )
{
touch_x = -1;
touch_y = -1;
pointerStates = POINTER_RELEASED;
}
else if ( action == MotionEvent.ACTION_DOWN ||
action == MotionEvent.ACTION_MOVE )
{
touch_x = (int) event.getX();
touch_y = (int) event.getY();
pointerStates = POINTER_PRESSED;
}
return super.onTouchEvent(event);
}


Now it is time to open the curtain and reveal the body of the hasTouchedOnOption function

protected static boolean hasTouchedOnOption ( Option option )
{
if (pointerStates == POINTER_RELEASED )
{
if ( option.type == OPTION_TYPE_PRESSED )
{
if ( option.prevState == PREVIOUSLY_PRESSED)
{
option.prevState = PREVIOUSLY_NOT_PRESSED;
return true;
}
}
option.prevState = PREVIOUSLY_NOT_PRESSED;
return false;
}

if ( option.type == OPTION_TYPE_INSTANT )
{
if ( option.prevState == PREVIOUSLY_PRESSED )
{
return false;
}
}

// [OPTION] [TOUCH]
if ( touch_x > option.x + option.width )
{
option.prevState = PREVIOUSLY_NOT_PRESSED;
return false;
}

// [TOUCH] [OPTION]
if ( touch_x < option.x )
{
option.prevState = PREVIOUSLY_NOT_PRESSED;
return false;
}

// [ OPTION]
//
// [TOUCH]
if ( touch_y > option.y + option.height )
{
option.prevState = PREVIOUSLY_NOT_PRESSED;
return false;
}

// [TOUCH]
//
// [OPTION]
if ( touch_y < option.y )
{
option.prevState = PREVIOUSLY_NOT_PRESSED;
return false;
}

option.prevState = PREVIOUSLY_PRESSED;
if ( option.type != OPTION_TYPE_PRESSED )
return true;

return false;
}


I think there is not a lot of stuff that needs detailed explanation. [OPTION] and [TOUCH] is the relative position of the touch and the option. The function is extremely quick and it needs from 2 to 10(in the worst case) operations to return a result.

But where is the best place to call this function?

It depends on the nature of your application. Either directly inside the functions that transfer the touches from the OS(see above) or inside the main game loop.