My Android Game Developed By OpenGL ES 2.0 Shows Textures In Low Quality

239 views Asked by At

I'm new to developing Android games using OpenGL ES 2.0.
I recently made a simple game where players must touch hidden numbers respectively that appeared within 3 seconds to win a level.
Each level contains numbers as many as two more than level amounts (For example, level 5 has 5 + 2 numbers).
The game works fine but not enough fine as I expected in two issues:
1 - The textures shown in my game, compared with the image shown in my Image Viewer application, are low in quality.
This is the screenshot of my game: image
And this is the screenshot of my Image Viewer application: image
This is my Texture Class:

package com.theNumbers.openGLES;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLUtils;

public class OpenGLESTexture {
    
    private final Context mActivityContext;
    private final FloatBuffer mCubeTextureCoordinates;
    private int mTextureUniformHandle;
    private int mTextureCoordinateHandle;
    private final int mTextureCoordinateDataSize = 2;
    private int mTextureDataHandle;
    private final String vertexShaderCode =
            "attribute vec2 a_TexCoordinate;" +
            "varying vec2 v_TexCoordinate;" +
            "uniform mat4 uMVPMatrix;" +
            "attribute vec4 vPosition;" +
            "void main() {" +
            "   gl_Position = uMVPMatrix * vPosition;" +
            "   v_TexCoordinate = a_TexCoordinate;" +
            "}";
    private final String fragmentShaderCode =
            "precision mediump float;" +
            "uniform sampler2D u_Texture;" +
            "varying vec2 v_TexCoordinate;" +
            "void main() {" +
            "   gl_FragColor = texture2D(u_Texture, v_TexCoordinate);" +
            "}";
    private final int shaderProgram;    
    private final FloatBuffer vertexBuffer;
    private final ShortBuffer drawListBuffer;
    private int mPositionHandle;
    private int mMVPMatrixHandle;
    static final int COORDS_PER_VERTEX = 2;
    private float[] spriteCoords = new float[8];
    private short drawOrder[] = { 0, 1, 2, 0, 2, 3 };
    private final int vertexStride = COORDS_PER_VERTEX * 4;
    private final float[] mTextureSize = new float[2];
    
    public OpenGLESTexture(final Context activityContext, final int resourceId, final short width, final short height) {
        mActivityContext = activityContext;
        mTextureSize[0] = width;
        mTextureSize[1] = height;
        spriteCoords[0] = width / 2f;
        spriteCoords[1] = height / 2f;
        spriteCoords[2] = -width / 2f;
        spriteCoords[3] = height / 2f;
        spriteCoords[4] = -width / 2f;
        spriteCoords[5] = -height / 2f;
        spriteCoords[6] = width / 2f;
        spriteCoords[7] = -height / 2f;
        ByteBuffer bb = ByteBuffer.allocateDirect(spriteCoords.length * 4); 
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(spriteCoords);
        vertexBuffer.position(0);
        final float[] cubeTextureCoordinateData =
        {        
                 0.0f,  0.0f,
                 1.0f,  0.0f,
                 1.0f,  1.0f,
                 0.0f,  1.0f
        };
        mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
        mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);
        ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(drawOrder);
        drawListBuffer.position(0);
        int vertexShader = OpenGLESRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
        int fragmentShader = OpenGLESRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
        shaderProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(shaderProgram, vertexShader);
        GLES20.glAttachShader(shaderProgram, fragmentShader);
        GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");
        GLES20.glLinkProgram(shaderProgram);
        mTextureDataHandle = loadTexture(mActivityContext, resourceId);
    }
    
    public void draw(float[] mvpMatrix)
    {
        GLES20.glUseProgram(shaderProgram);
        mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
        mTextureUniformHandle = GLES20.glGetAttribLocation(shaderProgram, "u_Texture");
        mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate");
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
        GLES20.glUniform1i(mTextureUniformHandle, 0);
        GLES20.glUniform2fv(GLES20.glGetUniformLocation(shaderProgram, "u_TextureSize"), 1, mTextureSize, 0);//
        mCubeTextureCoordinates.position(0);
        GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
        mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
    
    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;
            final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
            bitmap.recycle();
            GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        }
        if (textureHandle[0] == 0)
        {
            throw new RuntimeException("Error loading texture.");
        }
        return textureHandle[0];
    }

}

And this is my Renderer Class:

package com.theNumbers.openGLES;

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

import com.theNumbers.game.AssetsManager;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

public class OpenGLESRenderer implements GLSurfaceView.Renderer {
    
    private final Context mActivityContext;
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjMatrix = new float[16];
    private final float[] mVMatrix = new float[16];
    private float[] mRotationMatrix = new float[16];
    private boolean onCreate = true;
    public static float[] mStaticMVPMatrix = new float[16];
    public volatile float mAngle;
    
    public OpenGLESRenderer(final Context context) {
        mActivityContext = context;
    }

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
        AssetsManager.loadAssets(mActivityContext);
    }

    public void onDrawFrame(GL10 unused) {
        GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
        Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
        Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
        AssetsManager.equalizeMatrices(mMVPMatrix);
        if (onCreate) {
            onCreate = false;
            AssetsManager.load(mActivityContext);
            AssetsManager.save(mActivityContext);
            AssetsManager.createGUI();
            AssetsManager.updateLines();
            AssetsManager.mDoesFileExist = false;
        }
        AssetsManager.updateTime();
        AssetsManager.drawGUI();
        AssetsManager.drawRooms(mActivityContext);
        AssetsManager.mIsTouched = false;
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        float aspectRatio = (float) width / height;
        GLES20.glViewport(0, 0, width, height);
        Matrix.frustumM(mProjMatrix, 0, -aspectRatio * 960, aspectRatio * 960, -960, 960, 3, 7);
        AssetsManager.updateLines();
    }

    public static int loadShader(int type, String shaderCode) {
        int shader = GLES20.glCreateShader(type);
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);
        return shader;
    }
    
}

You can get the complete source code and the APK file here.
2 - Others can easily copy the textures I used in my game.
Just change the APK suffix to the ZIP suffix and open it to see all of my textures.

How can I solve these two issues that I explained above?

0

There are 0 answers