Mipmap generation must be done manually?!

I guess it’s not a scoop for most of the people here…

Anyway, I just found out that when running accelerated OpenGL on the Galaxy, glTexParameterx(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE) will simply not work (black textures…)

Same situation for older hardware like the G1

It seems that the official workaround is to use GLUtils.texImage2D(…)
I’m planning to test it with RGB, RBG+ALPHA and GRAYSCALE textures.

The thing is that the image data must be passed as a Bitmap. Not a big issue when loading images, but sometimes you need to use your own byte-based data (and then: having to pass through bitmap conversion can be overkill…)

Something in the lines GLU.gluBuild2DMipmaps(…) could be helpful.
What are you guys using?

this can be easily convert to using plain int[] (and then plain byte[])


   public static BufferedImage scaleHalfIntRGB(BufferedImage src)
   {
      if (src.getWidth() % 2 != 0)
         throw new IllegalStateException();
      if (src.getHeight() % 2 != 0)
         throw new IllegalStateException();

      int w = src.getWidth() / 2;
      int h = src.getHeight() / 2;

      BufferedImage dst = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

      int[] full = ((DataBufferInt) src.getRaster().getDataBuffer()).getData();
      int[] half = ((DataBufferInt) dst.getRaster().getDataBuffer()).getData();

      if (w * h * 4 != full.length)
         throw new IllegalStateException();
      if (w * h != half.length)
         throw new IllegalStateException();

      for (int y = 0; y < h; y++)
      {
         for (int x = 0; x < w; x++)
         {
            int rgb1 = full[((y << 1) + 0) * (w << 1) + ((x << 1) + 0)];
            int rgb2 = full[((y << 1) + 1) * (w << 1) + ((x << 1) + 0)];
            int rgb3 = full[((y << 1) + 0) * (w << 1) + ((x << 1) + 1)];
            int rgb4 = full[((y << 1) + 1) * (w << 1) + ((x << 1) + 1)];

            int r = (((rgb1 & 0x00FF0000) + (rgb2 & 0x00FF0000) + (rgb3 & 0x00FF0000) + (rgb4 & 0x00FF0000)) >> (16 + 2));
            int g = (((rgb1 & 0x0000FF00) + (rgb2 & 0x0000FF00) + (rgb3 & 0x0000FF00) + (rgb4 & 0x0000FF00)) >> (8 + 2));
            int b = (((rgb1 & 0x000000FF) + (rgb2 & 0x000000FF) + (rgb3 & 0x000000FF) + (rgb4 & 0x000000FF)) >> (0 + 2));

            half[y * w + x] = (r << 16) | (g << 8) | (b << 0);
         }
      }
      return dst;
   }

Thanks Riven,

It is definitely helpful. If I read well, it is a special case of standard bi-linear interpolation optimized for halving…

While we’re at it, what is the common way to solve the following in OpenGL land:

  1. Scaling down the subsequent mip-map levels based on the original image
  2. Or scaling down using the previously scaled pixels?

Quality wise, my common sense would vote for the first option, but I think that option 2 is the one mostly used.

If your just box filtering, then the previous level is what you want…otherwise it depends on your filter.

The quality is almost exactly the same. The early rounding isn’t really visible.

What do you mean by box filtering?
My main usage is the manipulation in 3d of photos and text (where each letter is a texture in alpha mode…)

For text, the two fields that matter are:
1- small text (i.e. tiny mipmap levels) should be crisp
2- the transition between levels (i.e. when zooming in/out) should be seamless

I don’t mind spending time on computation, as long as the mipmap generation is fine tuned for these needs…

This code is slow ( 1 sqrt per pixel ), but takes into account gamma correction:
http://www.java-gaming.org/index.php/topic,20947.0.html

Sounds (and looks) great!
I wonder if gamma correction is helpful for grayscale images?

In any case, I may execute this kind of computing off-line (with Android slow Java VM, “more data to load” should be faster than “more data to compute”…)

Gamma correction fixes brightness (see sourcecode) and therefore is useful for grayscale images too.

Cool!

So when you do
float e = x * x + y * y + z * z + w * w
it implies a gamma factor of 2.0?

I know that the gamma factor varies depending on the kind of screens (notable differences between Macs and PCs…)

In any case, I will definitely test all this on an AMOLED screen (Galaxy) and also on the iPhone, then post the results…

Just replace it with a sequence of Math.pow(n, e) then, and maybe (??) you have to change the Math.sqrt(n) into Math.pow(n, 1.0f / e).