I'm working on an android application which augment 3D model when image target is detected using vuforia SDK. Nine 3D model are augmented at a same time. I have loaded texture using GLES20.glGenTextures(1, textureHandle, 0) method. So I've called below method for nine times and store the integer value of texture id in integer array.
public static int loadTexture(Bitmap bitmap)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
isaugmented1 = false;
android.graphics.Matrix matrix = new android.graphics.Matrix();
bitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),matrix,true);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap = null;
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
Now I want to delete that all nine texture, so I've called
GLES20.glDeleteTextures(1, temphandler, 0)
method in a loop as mentioned in below code. but as a result only last texture is deleted. I want to delete all texture which are stored.
public void deleteTexture()
{
if(mosaicHandler!=null){
if(mosaicHandler.length>0)
{
Log.e("deleting", "texture");
for(int i = 0; i<mosaicHandler.length;i++)
{
Log.e("deletingTexture", i+"");
int [] temphandler = new int[1];
temphandler[0] = mosaicHandler[i];
GLES20.glDeleteTextures(1, temphandler, 0);
}
}
}
}
Is there any other way to delete texture whose Id is stored in integer array?
To delete multiple textures at once, just follow the opengl api
https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteTextures.xml
Related
I'm trying to change the texture image displayed on an object in my opengl view in response to a button click. Currently, when the user presses a button I set a flag to true in my OpenGL Renderer thread. My cross-thread communication seems fine: I am able to successfully toggle flag variables in the Renderer thread at will. My problem seems to be with the Open GL onDraw() workflow, I can't figure out how to systematically change a texture on an object after a texture has already been set during the Renderer's initial onSurfaceCreated() execution.
It seems that fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.dark_wood); never works outside of onSurfaceCreated(), why?
Below is the code i've tried. Am I missing a sequence of GLES20() method invocations somewhere?
OpenGL Renderer Class
private int chosenWoodColor = 1;
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
...
loadFretBoardTexture(); //this call works: it succeeds in changing texture
}
public void onDrawFrame(GL10 glUnused) {
if (flag){
loadFretBoardTexture(); //this call fails: it never changes the texture
}
...
//***Fretboard OpenGL_TextureData Binding***
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fretBoard._textureID);
//Draw Background
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -1.0f);
drawFretBoard(); //draw the fretboard
...
}
public void loadFretBoardTexture(){
switch (chosenWoodColor){
case 1:
fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.dark_wood);
break;
case 2:
fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.medium_wood);
break;
case 3:
fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.light_wood);
break;
}
setFretboardTextureRefresh(false);
return;
}
Texture Data Helper Class
public class OpenGL_TextureData {
public int textureID;
public float imageWidth, imageHeight;
public OpenGL_TextureData(Context context, int resourceId) { //constructor
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
//fetch texture image width & height
imageWidth = options.outWidth;
imageHeight = options.outHeight;
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0) {
throw new RuntimeException("Error loading texture.");
}
textureID = textureHandle[0];
}
}
Solved.
The problem was that I was creating a new texture object and loading a bitmap to it, but since the texture object was already created in my onSurfaceCreated() method this was undesired: I really just needed to load a bitmap onto the already existing texture object.
I added the following method to my Texture data helper class:
public void updateTexture(Context context, int resourceId) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); //Read in the resource
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
Inspiration drawn from here
I will like to load textures during run time ( so I dont need to load all of the texture)
If I try to load a texture during run time with this function, I get the RunTimeException ( I think that is because the context is already created)
Is any way to do this without having 2 OpenlGL context(I read that this may cause error if the drivers are bad implemented)?
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
I haven't touched OpenGL ES in Java, only C++ but I would have thought this would be perfectly OK - are you trying to create this texture on a different thread to the thread you created the OpenGL context on? Did your OpenGL context creation code succeed?
I'm trying to optimize my app by having compressed textures. Since a lot of my textures require alpha I can't use ETC1.
I've successfully compressed textures to other formats using hints from this post. Android OpenGL Texture Compression
Problem is I can't seem to adapt my code, to read this textures. The only thing I get with this code is black (colour, instead of texture).
Here is the method, that loads textures:
public static int loadCompressedTexture(Context context, int resourceId){
final int[] textureObjectIds = new int[1];
glGenTextures(1, textureObjectIds, 0);
if(textureObjectIds[0] == 0){
logTextureHelper(Log.WARN, "Could not generate a new OpenGL texture object");
return 0;
}
final InputStream bitmap = context.getResources().openRawResource(resourceId);
byte[] buffer;
ByteBuffer bf;
try {
buffer = new byte[bitmap.available()];
bitmap.read(buffer);
bf = ByteBuffer.wrap(buffer);
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);//binds texture to texture object
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//minimization filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);//send texture data to OpenGL to the CURRENTLY BOUND object
GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D, 0, GL10.GL_PALETTE4_RGBA8_OES, 512, 512, 0, bf.capacity(), bf);
//glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0); //unbind texture
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return textureObjectIds[0];
}
I currently trying to load resource that is 512x512px, compressed with PvrTexTool, using PVRTC 4bpp RGBA encoding.
Can anyone see what the problem is? Or better yet, point me to an example that works? From what I found I could only find examples for ETC1, who use some ETCUtil to load textures.
EDIT2: Ok I've solved it.
There were 2 problems. First you need to use these texture filters.
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
Secondly I was not aware that pvrtc had a seperate header. The correct offset is thus 67 bytes.
PVRTC format specification
This code now works correctly:
buffer = new byte[bitmap.available()];
bitmap.read(buffer);
int offset = 67; // 52 bit = header, 15 bit = metadata
bf = ByteBuffer.wrap(buffer, offset, buffer.length-offset);
bf.order(ByteOrder.LITTLE_ENDIAN);
long version = bf.getInt(0) & 0xFFFFFFFFL;
long flags = bf.getInt(4);
long pixelFormat = bf.getLong(8);
long colorF = bf.getInt(16);
long chanel = bf.getInt(20);
int height = bf.getInt(24);
int width = bf.getInt(28);
long depth = bf.getInt(32);
long nsurf = bf.getInt(36);
long nface = bf.getInt(40);
long mipC = bf.getInt(44);
long mSize = bf.getInt(48);
long fourCC = bf.getInt(52)& 0xFFFFFFFFL;
long key = bf.getInt(56)& 0xFFFFFFFFL;
long dataSize = bf.getInt(60)& 0xFFFFFFFFL;
// Log.d("TextureHelper","Buffer size: "+version+" "+flags+" "+pixelFormat+" "+colorF+" "+chanel+" "+height+" w: "+width+" h: "+height+" "+depth+" "+nsurf+" "+nface+" "+mipC+" "+mSize);
// Log.d("TextureHelper","Buffer size: "+fourCC+" "+key+" "+dataSize);
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glCompressedTexImage2D(GL_TEXTURE_2D, 0,GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, width, height, 0, bf.capacity()-offset, bf);
Log.d("TextureHelper","Buffer size: "+bf.capacity()+" : "+buffer.length+" error:"+GLES20.glGetError());
glBindTexture(GL_TEXTURE_2D, 0); //unbind texture
You want to load PVRTC 4bpp RGBA texture via glCompressedTexImage2D? You should use COMPRESSED_RGBA_PVRTC_4BPPV1_IMG instead of GL10.GL_PALETTE4_RGBA8_OES.
IMG_texture_compression_pvrtc
https://www.khronos.org/registry/gles/extensions/IMG/IMG_texture_compression_pvrtc.txt
I'm not sure but it seems Android GLES20 doesn't have those constants, so you need to define it.
// PowerVR Texture compression constants
public static final int GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
public static final int GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
public static final int GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
public static final int GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
And you should check glGetError after glCompressedTexImage2D calling. The value of glGetError should be GL_NO_ERROR.
I'm trying to load multiple textures in my Applikation. The Problem is that the second texture isnt displayed right.
This is how i get the Handels:
mTextureDataHandle = TextureHelper.loadTexture(mActivityContext, R.drawable.full_texture);
mTextureDataHandleError = TextureHelper.loadTexture(mActivityContext, R.drawable.full_texture_error);
using this Method:
public static int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0 )
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
during the onDrawFrame method I use this to switch between Textures:
if (LessonFourActivity.error) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandleError);
GLES20.glUniform1i(mTextureUniformHandle, 1);
} else {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
GLES20.glUniform1i(mTextureUniformHandle, 0);
}
The texture without the error works fine but when i switch to the error texture it's just black.
Does anyone know an answer to this?
I already found a few answers regarding GL10 but they didnt help me.
I am building an android opengl es 2.0 application. I am drawing squares in a circle, and with the user's movements left and right I am moving the squares. I am applying textures on the squares and keep getting this error:
2-19 16:08:25.666: E/Adreno200-EGL(8183): eglLockWindowSurface: failed to map the memory
for fd=42 offs=6352896
I think that it has something to do with the textures. For loading the textures I use:
public static int loadTexture(final Context context, Bitmap bmp)
{
final int[] textureHandle = new int[1];
// GLES20.glDeleteTextures(1, textureHandle, 0);
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = bmp;
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
// bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
Note: with bitmap.recycle() the app does not work.
Also I must say that the onDraw() method is always working and the renderer is NOT set to RENDER_WHEN_DIRTY. I assume that I am loading too many textures and not doing anything to the old ones, but I can't solve this problem for several days now. If someone has a solution, please let me know. I will deeply appreciate any advice or feedback. Thank u in advance!!!