package com.homelinux.holtrop.opengltest; import android.opengl.GLSurfaceView; import android.opengl.GLES20; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.egl.EGLConfig; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.ByteOrder; import android.util.Log; import android.content.res.AssetManager; import android.content.res.Resources; import java.io.InputStream; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.IOException; import android.opengl.Matrix; import android.os.SystemClock; import android.view.MotionEvent; import android.graphics.BitmapFactory; import android.graphics.Bitmap; import android.opengl.GLUtils; public class MyRenderer implements GLSurfaceView.Renderer { private int m_program; private final String DBGTAG = "JoshsOpenGL"; private FloatBuffer m_quad_attrib_buffer; private AssetManager m_asset_manager; private Resources m_resources; private float m_proj_matrix[] = new float[16]; private float m_modelview[] = new float[16]; private int m_width; private int m_height; private float m_aspect = 1.0f; private float m_x = 0.0f; private float m_y = 0.0f; public MyRenderer(AssetManager am, Resources resources) { m_asset_manager = am; m_resources = resources; } public void checkGLError(String glOperation) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e(DBGTAG, glOperation + ": glError " + error); } } private String read_asset(String fname) { String result = ""; try { InputStream is = m_asset_manager.open(fname); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; while ((line = br.readLine()) != null) { result += line + "\n"; } } catch (IOException ioe) { } return result; } private int load_shader(int type, String source) { int shader = GLES20.glCreateShader(type); GLES20.glShaderSource(shader, source); GLES20.glCompileShader(shader); IntBuffer ib = IntBuffer.allocate(1); GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, ib); if (ib.get(0) != 1) { String info_log = GLES20.glGetShaderInfoLog(shader); Log.e(DBGTAG, "Error compiling shader: " + info_log); } return shader; } public void onSurfaceCreated(GL10 unused, EGLConfig config) { final float attribs[] = { 1, 1, 0, 1, 1, -1, 1, 0, 0, 1, -1, -1, 0, 0, 0, 1, -1, 0, 1, 0, }; checkGLError("onSurfaceCreated"); ByteBuffer bb = ByteBuffer.allocateDirect(attribs.length * 4); bb.order(ByteOrder.nativeOrder()); m_quad_attrib_buffer = bb.asFloatBuffer(); m_quad_attrib_buffer.put(attribs); m_quad_attrib_buffer.position(0); final String v_shader_src = read_asset("shaders/vertex.glsl"); final String f_shader_src = read_asset("shaders/fragment.glsl"); int v_shader = load_shader(GLES20.GL_VERTEX_SHADER, v_shader_src); int f_shader = load_shader(GLES20.GL_FRAGMENT_SHADER, f_shader_src); m_program = GLES20.glCreateProgram(); GLES20.glAttachShader(m_program, v_shader); GLES20.glAttachShader(m_program, f_shader); GLES20.glLinkProgram(m_program); checkGLError("glLinkProgram"); IntBuffer ib = IntBuffer.allocate(1); GLES20.glGetProgramiv(m_program, GLES20.GL_LINK_STATUS, ib); if (ib.get(0) != 1) { String info_log = GLES20.glGetProgramInfoLog(m_program); Log.e(DBGTAG, "Program log: " + info_log); } Bitmap texture = BitmapFactory.decodeResource(m_resources, R.drawable.texture); int[] textures = new int[1]; GLES20.glGenTextures(1, textures, 0); checkGLError("glGenTextures"); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); checkGLError("glBindTexture"); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); checkGLError("glTexParameterf"); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, texture, 0); checkGLError("GLUtils.texImage2D"); GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D); checkGLError("glGenerateMipmap"); texture.recycle(); GLES20.glClearColor(1.0f, 0.6f, 0.1f, 1.0f); } public void onDrawFrame(GL10 unused) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); long time = SystemClock.uptimeMillis() % 4000L; float angle = 0.090f * ((int) time); Matrix.setIdentityM(m_modelview, 0); Matrix.translateM(m_modelview, 0, m_x, m_y, 0); Matrix.rotateM(m_modelview, 0, angle, 0, 0, 1); Matrix.scaleM(m_modelview, 0, 0.2f, 0.2f, 0.2f); GLES20.glUniformMatrix4fv( GLES20.glGetUniformLocation(m_program, "modelview"), 1, false, m_modelview, 0); int attr_pos = GLES20.glGetAttribLocation(m_program, "pos"); int attr_tex_coord = GLES20.glGetAttribLocation(m_program, "tex_coord"); checkGLError("glGetAttribLocation"); GLES20.glEnableVertexAttribArray(attr_pos); GLES20.glEnableVertexAttribArray(attr_tex_coord); checkGLError("glEnableVertexAttribArray"); m_quad_attrib_buffer.position(0); GLES20.glVertexAttribPointer(attr_pos, 3, GLES20.GL_FLOAT, false, 5 * 4, m_quad_attrib_buffer); m_quad_attrib_buffer.position(3); GLES20.glVertexAttribPointer(attr_tex_coord, 2, GLES20.GL_FLOAT, false, 5 * 4, m_quad_attrib_buffer); checkGLError("glVertexAttribPointer"); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4); checkGLError("glDrawArrays"); GLES20.glDisableVertexAttribArray(attr_pos); GLES20.glDisableVertexAttribArray(attr_tex_coord); checkGLError("glDisableVertexAttribArray"); } public void onSurfaceChanged(GL10 unused, int width, int height) { m_width = width; m_height = height; m_aspect = width / (float) height; GLES20.glViewport(0, 0, width, height); Matrix.orthoM(m_proj_matrix, 0, -m_aspect, m_aspect, -1, 1, 1, -1); GLES20.glUseProgram(m_program); GLES20.glUniformMatrix4fv( GLES20.glGetUniformLocation(m_program, "projection"), 1, false, m_proj_matrix, 0); } public boolean onTouchEvent(MotionEvent e) { if (e.getAction() == MotionEvent.ACTION_DOWN) { float x = m_aspect * ((e.getX() / (float) m_width) * 2.0f - 1.0f); float y = -((e.getY() / (float) m_height) * 2.0f - 1.0f); m_x = x; m_y = y; } return false; } }