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?