Author Topic: Loading texture in a more efficent way  (Read 1717 times)

Offline ginopeloso

  • byte
  • *
  • Posts: 13
    • View Profile
Loading texture in a more efficent way
« on: August 02, 2015, 06:57:13 pm »
I need to load a texture starting from a non-squared image. The final image must be squared (with both height and width power of 2), than I am forced to load the bitmap in memory, complete it with a useless part (in order to obtain a squared bitmap) and then create a texture with it. The whole process consumes too much memory (I have very big textures, 1024x1024, 2048x2048 or also 4096x4096). Is there a smarter way for creating textures?

Code: [Select]
        int maxTextureSize = calcMaxTextureSize(); // the max size in pixels that GLSurfaceView can render on this device (tipically 2048, or 4096 for newer devices, however a power of 2)

        // do not load bitmap, just decode its bounds
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inSampleSize = 1;
        BitmapFactory.decodeFile(filepath, options);

        int width = options.outWidth;
        int height = options.outHeight;

        // scale down the image if it is bigger than the maxTextureSize
        while (width / (float) options.inSampleSize > maxTextureSize || height / (float) options.inSampleSize > maxTextureSize) {
            options.inSampleSize *= 2; // inSampleSize must be a power of 2 (1, 2, 4, 8, etc... that's why this line)
        }

        // now load the bitmap
        options.inJustDecodeBounds = false;

        Bitmap bitmap = BitmapFactory.decodeFile(filepath, options); // decode the real bitmap, ONE
        int dim = Math.max(bitmap.getWidth(), bitmap.getHeight());

        // now put it in a squared bitmap (it will be used as a texture, then it must be square (dim x dim))
        Bitmap textureBitmap = Bitmap.createBitmap(dim, dim, Bitmap.Config.RGB_565); // TWO bitmaps
        Canvas canvas = new Canvas(textureBitmap);
        canvas.drawBitmap(bitmap, 0, 0, null);
        bitmap.recycle();

        // The texture must be a power-of-2 bitmap, then resize it... THREE bitmaps
        Bitmap scaledTexture = Bitmap.createScaledBitmap(textureBitmap, maxTextureSize, maxTextureSize, false);
        textureBitmap.recycle();

        Texture texture = new Texture(scaledTexture, false);
        TextureManager.getInstance().addTexture(textureName, texture); // ANOTHER bitmap in memory
        scaledTexture.recycle();

As you can see there are too many passes, and too many bitmaps allocated in memory before I can have the final texture:
1. Decode the original bitmap, not the whole one but the maximum size supported by the device
2. Put it on a square (with a useless part)
3. Resize it, in order to have a power-of-2 texture
4. Create a Texture object with that bitmap
« Last Edit: August 03, 2015, 09:48:30 am by ginopeloso »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Loading texture in a more efficent way
« Reply #1 on: August 04, 2015, 12:05:15 pm »
Can't you simply process them instead of doing this at runtime? If not, maybe doing all the operations in your own code on an int-array might help...but I'm not sure if it really would. Another option is to use NPOTTexture instead, but that has other drawbacks like no mip-mapping support.