using mipmaps with ETC1 textures - android

Ive modified my code to use ETC1 textures to help lower memory usage and while the texture loads, its not automatically generating mipmaps anymore. Is this not supported for ETC1 images? Heres my code:
//Generate three texture pointers...
gl.glGenTextures(3, textures, 0);
//...and bind it to our array
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
// gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST); //problem child
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
//gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE); problem child.
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
//Get the texture from the Android resource directory
Log.e("Sys", "ETC1 texture support: " + ETC1Util.isETC1Supported());
InputStream input = context.getResources().openRawResource(R.drawable.testtile);
try {
ETC1Util.loadTexture(GLES10.GL_TEXTURE_2D, 0, 0,
GLES10.GL_RGB, GLES10.GL_UNSIGNED_SHORT_5_6_5, input);
Log.w("sys", "loaded!");
} catch (IOException e) {
Log.w("sys", "Could not load texture: " + e);
} finally {
try {
input.close();
} catch (IOException e) {
// ignore exception thrown from close.
}
}

An easy way to solve this is to generate the mipmap levels with the tool you use to create your ETC1 texture (all the levels will end up in the file (eg .pvr)) and to upload each level individually.

Use this tool : http://www.malideveloper.com/developer-resources/tools/texture-compression-tool.php
The one from the Android SDK ( etc1tool ) will not generate mipmaps automatically. The mali tool can even batch convert textures to etc1/etc2 .

Related

how to use compressed texture in opengl?

I want to use .PVR image for texture purpose.
For this, I used PVRtextool and loaded my pvr image in drawables-mdpi.
Now, when i use this in my project the app just crashes.
Am I missing some step?
Please guide.
Here is the load texture code where I'm getting problem. resource contains the image in .pvr format.
static void loadTexture(GL10 gl, Context context, int[] resource)
{
gl.glGenTextures(n, textureIDs, 0);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inScaled = false;
for (int face = 0; face < n; face++)
{
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[face]);
bitmap[face] = BitmapFactory.decodeResource(
context.getResources(), resource[face],opts);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[face], 0);
bitmap[face].recycle();
}
]
You can't use BitmapFactory.decodeResource() with that format. You have to use the openRawResource() function and pass the InputStream it returns to the ETC1Util.loadTexture() function.
A sample implementation should be at /sdk/platforms/<version>/samples/CompressedTextureActivity.java, or an online version is here.

Android OpenGL textures: creating and deleting them on the fly

I am currently implementing a 3D viewer which basically renders a subset of all the images the user has on his SD Card. The closest matching product I would think of would be CoolIris:
It simply show a scrolling board of N tiles on screen, each showing different images, with new tiles entering the screen and showing new images.
Now for my problem: I have the program working and rendering nicely the quads. When a quad goes out of the screen, it gets recycled/released. And new quads keep on being added to the tile board before they enter the screen.
Because there can be hundreds of images, the textures need to be created and deleted on the fly (so that we don't run out of memory). The problem I have is that after I delete textures, newly created textures seem to get some IDs of other textures currently in use.
My rendering loop looks like this:
void render(GL10 gl) {
0. Move the camera
// Tile board maintenance
1. Remove tiles out of screen
2. Add new tiles which are about to enter screen
// Texture handling
3. glDeleteTextures on all unused textures followed by glFlush
4. For newly used images
- Create corresponding Bitmap
- Create the OpenGL texture, followed by glFlush
- Release the Bitmap
// Rendering
5. Render the tile (using a textured quad)
}
To give a better idea of how the data is organised, here is an overview of the classes:
TileBoard {
Image[] allImages;
Tile[] board;
}
Tile {
Image image;
}
Image {
String path;
int textureId;
int referenceCount;
}
Texture creation code:
protected void loadSingleTexture(GL10 gl, long objectId, Bitmap bmp) {
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
gl.glFlush();
if (bmp != null) bmp.recycle();
if (listener != null) listener.onTextureLoaded(gl, objectId, textures[0]);
}
Texture deletion code:
// pendingTextureUnloads is a Set<Integer>
if (pendingTextureUnloads.size() > 0) {
int[] textureIds = new int[pendingTextureUnloads.size()];
int i = 0;
Iterator<Integer> it = pendingTextureUnloads.iterator();
while (it.hasNext()) {
textureIds[i] = it.next();
}
gl.glDeleteTextures(textureIds.length, textureIds, 0);
gl.glFlush();
}
I have solved the problem: the issue was that you have to keep the texture array passed to glGenTextures and reuse it.
Here is the modified overview for the ones who will have the same problem:
Image {
String path;
int[] textureIds;
int referenceCount;
}
Texture creation code:
// Notice that I don't allocate the int[] at the beginning but use the one of the image
protected void loadSingleTexture(GL10 gl, Image img, Bitmap bmp) {
gl.glGenTextures(1, img.textureIds, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, img.textureIds[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
gl.glFlush();
if (bmp != null) bmp.recycle();
}
Texture deletion code:
foreach Image img {
gl.glDeleteTextures(img.textureIds.length, img.textureIds, 0);
}
gl.glFlush();
I know you said that you solved your issue, but I think I noticed your error in the first bit of code. Look at the while loop in your texture deletion code, you are not increasing the index i for your array, so you will continuously assign the first index until you reach the last entry in pendingTextureUnloads, the rest of the indices will be 0 (null). That might be problematic.
And by the way, I have got texture generation working by not reusing the array, just returning the index that was generated by glGenTextures. My code is to the line equal to yours, except from creating a new int array in the beginning of the method and returning the int at the first index at the end. Your code for texture generation should work, the error was just in the texture deletion.

Android OpenGL ES texture colors show up correctly on emulator but not on phone

I have a problem where the colors of any textures that I use are bleached, if that's a good word to use to describe it, on two different phones but the textures show up just fine on the emulator.
Here are the images.
The first image is the texture that I'm using.
The second image is how the texture shows up on the emulator and the way it is supposed to show up on the phones.
The third image is how the texture actually shows up on the phone.
Should I include the code where I draw the rectangle? The rectangle is just a vertex buffer and texcoord buffer. Anything that actually is done with the texture is gl.glBindTexture and gl.glBlendFunction(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA). gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f) is also called.
The following code is where I believe my error could exist. I hope someone can help me out here. Thanks!
This is in my GLSurfaceView.Renderer implementation
#Override
public void onSurfaceCreated(final GL10 gl, final EGLConfig config) {
DebugLog.d("onSurfaceCreated");
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glShadeModel(GL10.GL_FLAT);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glDisable(GL10.GL_DITHER);
gl.glDisable(GL10.GL_LIGHTING);
gl.glDisable(GL10.GL_MULTISAMPLE);
gl.glEnable(GL10.GL_BLEND);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glFrontFace(GL10.GL_CW);
gl.glCullFace(GL10.GL_BACK);
}
This is in my BitmapTexture class.
#Override
public void loadBitmapToHardware(final GL10 gl) throws IOException {
final Bitmap bitmap = loadBitmap();
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, bitmap, GL10.GL_UNSIGNED_BYTE, 0);
bitmap.recycle();
}
#Override
public Bitmap loadBitmap() {
InputStream is = null;
try {
is = mContext.getAssets().open(mBitmapPath);
return BitmapFactory.decodeStream(is);
} catch (final IOException e) {
DebugLog.e("Failed to load Bitmap in " + this.getClass().getSimpleName() + " from path: " + mBitmapPath, e);
return null;
} finally {
try {
is.close();
} catch (final IOException e) {
e.printStackTrace();
}
}
}
#Override
public void loadTexture() throws IOException {
gl.glGenTextures(1, TEXTURE_CONTAINER, 0);
mTextureId = TEXTURE_CONTAINER[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureId);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
loadBitmapToHardware();
}
It looks like an overexposure issue to me. It is likely that the screen settings for the emulator and your phone handles this problem differently, especially since dither is disabled in your code.
You should try to:
1: Remove the glColor4f() call, and see if that works (from what I know of GL10, it sets the color to white in your case, which might cause problems with blending).
or
2: Turn of blending and turn on depth-test to see if your blending give this result.

Drawing translucent textures in Android using OpenGL

I've been struggling with this issue for a few weeks now, with no results. I'm sure I'm just missing something silly, so I thought I'd get an outside opinion on it.
I'm drawing a bunch of different textures in an app, and for some reason, some of them aren't showing up. I tried to figure out why only certain textures wouldn't display, and I think I've narrowed it down to textures with translucent pixels (textures that contain pixels with an alpha value that is not 0 or 255). Fully opaque textures display just fine, and textures that have either fully on or fully off pixels do as well. The problem textures display as a white square. Also, I figure I should add that everything displays fine in the emulator, it's only on my testing device (Samsung Captivate) that the textures don't display.
Here are some snippets of my code showing the important parts, as always, let me know if you need more information.
View setup (I've tried both of these, but having these lines there or not seems to make no difference):
gameView.setEGLConfigChooser(8,8,8,8,16,0);
gameView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
Renderer's onSurfaceCreated method (I've also tried enabling depth test to no avail, the lines I used are commented here, and when I tried depth testing, I did clear the depth buffer on every draw):
gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
gl.glShadeModel(GL10.GL_FLAT);
gl.glDisable(GL10.GL_DEPTH_TEST);
//gl.glEnable(GL10.GL_DEPTH_TEST);
//gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
Texture loading method (could it have something to do with GLUtils.texImage2D?):
int texId;
gl.glGenTextures(1, mTextureNameWorkspace, 0);
texId = mTextureNameWorkspace[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, texId);
if (gl instanceof GL11) {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
}
else {
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
}
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
InputStream is = res.openRawResource(resourceId);
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(is, null, bitmapOptions);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
if (gl instanceof GL11) {
mCropWorkspace[0] = 0;
mCropWorkspace[1] = bitmap.getHeight();
mCropWorkspace[2] = bitmap.getWidth();
mCropWorkspace[3] = -bitmap.getHeight();
((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace, 0);
}
//Don't poke fun at my archaic error handler
int error;
String errorCodes = "";
while ((error = gl.glGetError()) != GL10.GL_NO_ERROR) {
errorCodes += error + " ";
}
if (errorCodes.length() != 0)
throw new Exception("OpenGL error while loading texture. Error codes: " + errorCodes.substring(0,errorCodes.length()-1));
textureWidth = bitmap.getWidth();
textureHeight = bitmap.getHeight();
textureId = texId;
return texId;
}
finally {
try { is.close(); } catch (IOException e) { }
try { bitmap.recycle(); } catch (Exception e) { }
}
Just to close the question in case anyone stumbles upon it:
This error was occurring because the images were saved in res/drawable. When loaded from there, the Android can do some behind-the-scenes processing, causing the resulting images to not be sized to a power of two. Store the images in res/raw to avoid this processing.

texture mapping

I'm trying to apply texture to a sprite using opengl as follows:
int[] textures=new int[1];
gl.glEnableClientState(GL10.GL_TEXTURE_2D);
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
Bitmap bitmap=null;
try {
bitmap= BitmapFactory.decodeStream(contxt.getAssets().open("gfx/garf.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
GLUtils.texImage2D(GL10.GL_VERTEX_ARRAY, 0, bitmap, 0);
bitmap.recycle();
.....
I'm using andEngine framework in android and using onManagedDraw method of Sprite to do this.
Can anyone help in this direction?
I think you need texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
I'm just guessing that your problem is that the texture doesn't show up :)
This is wrong:
GLUtils.texImage2D(GL10.GL_VERTEX_ARRAY, 0, bitmap, 0);
Should be:
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

Categories

Resources