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
Related
I am using Google VR SDK to show an image on the screen.
I am encountering a strange bug when displaying the objects without distortion although it happens only on large screens (namely 5.5 inch or larger).
To disable distortion I am using gvrView.setDistortionCorrectionEnabled(false)
The result looks like this:
You can see that there is a cut part at the top of the screen that shows some of the objects again.
When I use distortion the problem seems to disappear.
I will give the relevant code here for reference:
public class MainActivity extends GvrActivity {
private GLSurfaceView mGLSurfaceView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fpv_activity_layout);
initGvrView();
}
private void initGvrView() {
GvrView gvrView = (GvrView) findViewById(R.id.gvr_view);
gvrView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
// Associate a GvrView.StereoRenderer with gvrView.
gvrView.setRenderer(new FpvRenderer(this));
AndroidCompat.setSustainedPerformanceMode(this, true);
gvrView.setDistortionCorrectionEnabled(false);
setGvrView(gvrView);
}
}
The XML file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.vr.sdk.base.GvrView
android:id="#+id/gvr_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" />
</RelativeLayout>
I am using this function to load the textures:
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);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
// 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];
}
Has anyone encountered this, have any idea why this is happening and how to resolve it ?
I appreciate the help.
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 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
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!!!