Android GLSurfaceView glTexImage2D glDrawTexiOES

Cinar picture Cinar · May 3, 2010 · Viewed 11.8k times · Source

I'm trying to render a 640x480 RGB565 image using OpenGL ES on Android using GLSurfaceView and Native C code.

Initially I had a 0x0501 error with glTexImage2D, which I was able to resolve by changing the image dimensions.

But now, in the "drawFrame" call, when I do glDrawTexiOES to resnder the texture, I'm getting the following error on the Logs:

drawtex.c:89: DrawTexture: No textures enabled

I'm already doing glEnable(GL_TEXTURE_2D), is there anything else I should do?

Is there a complete example showing GLSurfaceView with native code using textures?

Thanks in advance!

Answer

user504779 picture user504779 · Nov 11, 2010

I have had the same problem,you can either make a custom renderer like this: or (a do it little bit complicated by subclassing SurfaceView directly)


import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.util.Log;

import com.TIEmulator.JNI.NLib;

class EmulatorRenderer implements GLSurfaceView.Renderer, NLib.EventsInterface {

    public static interface RenderCb {
        public boolean dismissStartupDialog();

        public void updateStartupDialog(String msg);
    }

    private static int mViewHeight;
    private static int mViewWidth;
    private static BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();

    private static int TEX_BUF_HEIGHT = 128;
    private static int TEX_BUF_WIDTH = 256;

    private final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4
            * EmulatorRenderer.TEX_BUF_HEIGHT * EmulatorRenderer.TEX_BUF_WIDTH);
    private boolean emulation_running = false;

    private Context mContext = null;
    private final int[] mCropWorkspace;
    private final GLSurfaceView mGLView;
    protected int mTex = -1;

    protected int[] mtexBuf = new int[1];
    private final int[] mTextureNameWorkspace;

    public EmulatorRenderer(final Context ctx, final GLSurfaceView v) {
        // Pre-allocate and store these objects so we can use them at runtime
        // without allocating memory mid-frame.
        mTextureNameWorkspace = new int[1];
        mCropWorkspace = new int[4];

        byteBuffer.order(ByteOrder.BIG_ENDIAN);

        // Set our bitmaps to 16-bit, 565 format.
        EmulatorRenderer.sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
        mGLView = v;
        mContext = ctx;

        try {
            NLib.setListener(this);
        } catch (final RuntimeException exc) {
            exc.printStackTrace();
            callFinishOnce();
            return;
        }
        if (!NLib.TryLoadLib()) {
            callFinishOnce();
            return;
        }
        Log.v(this.getClass().toString(),">>>>>>>>>>>>>>>>>>>>>>> init successfull! <<<<<<<<<<<<<<<<<<<<<<");
    }

    private void callFinishOnce() {
        if (mContext != null) {
            ((Activity) mContext).finish();
            mContext = null;
        }
    }

    @Override
    protected void finalize() throws Throwable {
        NLib.stopEmu();
        super.finalize();
    }

    protected int loadBB(final GL10 gl) {
        int textureName = -1;
        if (mContext != null && gl != null) {
            gl.glGenTextures(1, mTextureNameWorkspace, 0);

            textureName = mTextureNameWorkspace[0];
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);

            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_NEAREST);// 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_REPLACE);

            mCropWorkspace[0] = 0; // u
            // mCropWorkspace[1] = EMU_HEIGHT; // v
            mCropWorkspace[1] = 0; // v

            mCropWorkspace[2] = NLib.getWidth(); // w
            // mCropWorkspace[3] = -EMU_HEIGHT; // h -EMU_HEIGHT;
            mCropWorkspace[3] = NLib.getHeight(); // h -EMU_HEIGHT;
            byteBuffer.order(ByteOrder.BIG_ENDIAN);

            final int error = gl.glGetError();
            if (error != GL10.GL_NO_ERROR) {
                Log.e("SpriteMethodTest", "Texture Load GLError: " + error);
            }
        }
        return textureName;
    }

    public void onDrawFrame(final GL10 gl) {
        // Log.v(this.toString(),"onDrawFrame called");
        gl.glActiveTexture(mTex);
        gl.glClientActiveTexture(mTex);

        byteBuffer.position(0);

        // this two lines bind and create the texture!
        gl.glBindTexture(GL10.GL_TEXTURE_2D, mTex);
        ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D,
                GL11Ext.GL_TEXTURE_CROP_RECT_OES, mCropWorkspace, 0);

        gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA,
                EmulatorRenderer.TEX_BUF_WIDTH,
                EmulatorRenderer.TEX_BUF_HEIGHT, 0, GL10.GL_RGBA,
                GL10.GL_UNSIGNED_BYTE, byteBuffer);

        ((GL11Ext) gl).glDrawTexiOES(0, 0, 0, EmulatorRenderer.mViewWidth,
                EmulatorRenderer.mViewHeight);

        /** gl.glEnable(GL10.GL_DEPTH_TEST); gl.glDepthFunc(GL10.GL_LEQUAL);
         */
    }

    public void OnFatalError(final String text) {
        Log.d(toString(), "FATAL ERROR CALLBACK raised: " + text
                + " ===> Activity calls finish()");
    }

    public void onFinish() {
        onPause();
    }
/*
* JNI interface
*
*/
    @Override
    public void OnBufferUpdate() {
        mGLView.requestRender();
    }
    // TODO Auto-generated method stub

    @Override
    public void OnWarning(String msg) {
        // TODO Auto-generated method stub

    }
    public void onPause() {
        mGLView.onPause();
        // Log.v("onPause", "NILib.stopEmulate()");
        emulation_running = false;
        //startupDialogDismiss = false;
        NLib.stopEmu();
    }

    public void onResume() {
        // Log.v(this.toString(),"EmulatorRenderer:onResume called");
        NLib.startEmu(byteBuffer);

        mGLView.onResume();
        //callFinishOnce();
        emulation_running = true;
    }

    public void onSurfaceChanged(final GL10 gl, final int w, final int h) {
        EmulatorRenderer.mViewWidth = w;
        EmulatorRenderer.mViewHeight = h;
        Log.v(toString(), "onSurfaceChanged: ==> New View Size: [" + w + ","
                + h + "]");
    }

    public void onSurfaceCreated(final GL10 gl, final EGLConfig config) {

        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);

        gl.glClearColor(0.5f, 0.5f, 0.5f, 1);
        gl.glShadeModel(GL10.GL_FLAT);
        gl.glDisable(GL10.GL_DEPTH_TEST);
        gl.glEnable(GL10.GL_TEXTURE_2D);

        /*
         * By default, OpenGL enables features that improve quality but reduce
         * performance. One might want to tweak that especially on software
         * renderer.
         */
        gl.glDisable(GL10.GL_DITHER);
        gl.glDisable(GL10.GL_LIGHTING);
        gl.glDisable(GL10.GL_BLEND);
        gl.glDisable(GL10.GL_DEPTH_TEST);
        gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST); // Set Line
        // Antialiasing
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        // create the one and only texture here...
        mTex = loadBB(gl);
    }

    public void OnTIEmuStopped() {
        System.out.println("OnTIEmuStopped callback called! ");
        callFinishOnce();
    }

    /* Called when the size of the window changes. */
    public void sizeChanged(final GL10 gl, final int w, final int h) {
        // Log.v(this.toString(),"sizeChanged: ==> new Viewport: ["+w+","+h+"]");

        gl.glViewport(0, 0, w, h);
        /*
         * Set our projection matrix. This doesn't have to be done each time we
         * draw, but usually a new projection needs to be set when the viewport
         * is resized.
         */
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();

        // Set up the orthographic projection
        // gl.glOrthof(0.0f, w, 0.0f, h, 0.0f, 1.0f);
        gl.glOrthof(0.0f, w, 0.0f, 0.0f, h, 1.0f);

        gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
        gl.glColor4x(0x10000, 0x10000, 0x10000, 0x10000);
        gl.glEnable(GL10.GL_TEXTURE_2D);

        gl.glMatrixMode(GL10.GL_MODELVIEW);
    }
}