A.A. Grapsas
A.A. Grapsas

Reputation: 782

Texture & Quad Drawing Wrong, Android OpenGL ES

I, for the life of me, am unable to get a simple sprite drawing to screen using OpenGL ES and Java. Graphics programming is definitely my weak spot, and my rustiness with OpenGL isn't helping, what so ever.

What I'm trying to do

Use a quad class to render a textured quad to the screen

What I've tried

I was using glDrawTexfOES and everything was dandy. But, upon some inspection, I realized that I wouldn't be able to use the translations and rotations I would require to build a more robust system; so, I decided to go for a textured quad, as, a long time ago, I'd done just that in college.

The Issue

My texture ends up taking the entire screen and not being mapped correctly, it makes me somewhat grumpy. I was hoping I could get some eyes on my code and some professional opinions.

The Result

Should be this:

Correct Image

But is this:

Incorrect Image

Thank you so much, in advance!

My Quad class:

public class Quad
{
    private float _Vertices[] = 
        {
            -1.0f, 1.0f, 0.0f,  // Top left
            -1.0f, -1.0f, 0.0f, // Bottom left
            1.0f, -1.0f, 0.0f,  // Bottom right
            1.0f, 1.0f, 0.0f,   // Top right
        };

    private float _TextureCoords[] = 
        { 
            0.0f, 1.0f,
            1.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 0.0f
        };

    private FloatBuffer _VertexBuffer;
    private ShortBuffer _IndexBuffer;
    private FloatBuffer _TextureBuffer;

    private short[] _Indices = { 0, 1, 2, 0, 2, 3 };

    public Quad()
    {
        Setup();
    }

    public void Setup()
    {
        ByteBuffer vbb = ByteBuffer.allocateDirect( _Vertices.length * 4 );
        vbb.order( ByteOrder.nativeOrder() );

        _VertexBuffer = vbb.asFloatBuffer();
        _VertexBuffer.put( _Vertices );
        _VertexBuffer.position( 0 );

        ByteBuffer ibb = ByteBuffer.allocateDirect( _Indices.length * 2 );
        ibb.order( ByteOrder.nativeOrder() );

        _IndexBuffer = ibb.asShortBuffer();

        _IndexBuffer.put( _Indices );
        _IndexBuffer.position( 0 );

        ByteBuffer tbb = ByteBuffer.allocateDirect( _TextureCoords.length * 4 );
        tbb.order( ByteOrder.nativeOrder() );

        _TextureBuffer = tbb.asFloatBuffer();
        _TextureBuffer.put( _TextureCoords );
        _TextureBuffer.position( 0 );
    }

    public void Draw( GL10 gl, Texture texture )
    {               
        gl.glBindTexture( GL10.GL_TEXTURE_2D, texture.getID() );
        gl.glTexCoordPointer( 2, GL10.GL_FLOAT, 0, _TextureBuffer );

        gl.glVertexPointer( 3, GL10.GL_FLOAT, 0, _VertexBuffer );
        gl.glDrawElements( GL10.GL_TRIANGLES, _Indices.length,
                GL10.GL_UNSIGNED_SHORT, _IndexBuffer );
    }
}

My renderer:

public class FoxRenderer implements Renderer
{
private Context _Context;
private Quad _Quad;

private int _Width;
private int _Height;

public FoxRenderer( Context context, Game game )
{
    // Assignment
    _Context = context;
    _Game = game;

    _Quad = new Quad();
}

@Override
public void onDrawFrame(GL10 gl)
{
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    gl.glLoadIdentity();

    _Quad.Draw( gl, _Game.getGameData().TextureSystem.GetTexture( "buddha") );
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height)
{
    _Width = width;
    _Height = height;

    gl.glViewport(0, 0, width, height);

    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    gl.glOrthof(0.0f, width, 0.0f, height, 0.0f, 1.0f);
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{
    // Initialize various OpenGL elements
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);

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

    // Disabling certain elements for performance
    gl.glDisable(GL10.GL_DITHER);
    gl.glDisable(GL10.GL_LIGHTING);

    // Stuff for rendering quads
    gl.glFrontFace( GL10.GL_CCW );
    gl.glEnable( GL10.GL_CULL_FACE );
    gl.glCullFace( GL10.GL_BACK );

    gl.glShadeModel(GL10.GL_FLAT);
    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

    gl.glEnableClientState( GL10.GL_VERTEX_ARRAY );
gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY );
}
}

And, just in case, my texture loading:

public void LoadTexture( String name, int resource )
{
    Texture texture = new Texture();

    // LOADING TEXTURE CODE
    int[] temp = new int[ 1 ];

    _GL10.glGenTextures( 1, temp, 0 );

    // Get newly generated OpenGL texture ID and bind it and store in our texture class
    int id = temp[ 0 ];
    _GL10.glBindTexture( GL10.GL_TEXTURE_2D, id );
    texture.setID( id );

    _GL10.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST );
    _GL10.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST );
    _GL10.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT );
    _GL10.glTexParameterf( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT );
    _GL10.glTexEnvf( GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE );

    // Load actual resource into bitmap
    Bitmap bitmap = BitmapFactory.decodeResource( _Context.getResources(), resource );

    // Not 100% sure what this does
    GLUtils.texImage2D( GL10.GL_TEXTURE_2D, 0, bitmap, 0 );

    texture.setWidth( bitmap.getWidth() );
    texture.setHeight( bitmap.getHeight() );

    _Map.put( name, texture );

    bitmap.recycle();
}

Upvotes: 1

Views: 2925

Answers (1)

A.A. Grapsas
A.A. Grapsas

Reputation: 782

I ended up solving the problem with the help of a graphics engineer I work with. Just needed to change my onSurfaceChanged:

public void onSurfaceChanged(GL10 gl, int width, int height)
{
    _Width = width;
    _Height = height;

    gl.glViewport(0, 0, width, height);

        gl.glMatrixMode(GL10.GL_PROJECTION);
            gl.glLoadIdentity();
        gl.glOrthof(0.0f, width, height, 0.0f, 0.0f, 1.0f);

    gl.glMatrixMode(GL10.GL_MODELVIEW);
}

Also changed to clock-wise winding:

gl.glFrontFace( GL10.GL_CW );

And changed my vertices:

private static float _Vertices[] = 
{
    -0.5f, -0.5f, 0.0f, 
    0.5f, -0.5f, 0.0f,  
    0.5f, 0.5f, 0.0f,   
    -0.5f, 0.5f, 0.0f,  
};

And now everything works the way I want, including having it act like screen-space in most engines (positive Y down).

Upvotes: 2

Related Questions