EGL环境
抽象工厂模式定义EGL环境接口
interface EGLComponentFactory {
fun createEGL ( ) : EGL10
fun createEGLDisplay ( egl: EGL10) : EGLDisplay
fun createEGLConfig ( egl: EGL10, display: EGLDisplay) : EGLConfig
fun createEGLContext ( egl: EGL10, display: EGLDisplay, config: EGLConfig) : EGLContext
fun createEGLSurface (
egl: EGL10,
display: EGLDisplay,
config: EGLConfig,
surface: Surface
) : EGLSurface
}
EGL环境接口的具体实现
class DefaultEGLFactory : EGLComponentFactory {
override fun createEGL ( ) : EGL10 = EGLContext. getEGL ( ) as EGL10
override fun createEGLDisplay ( egl: EGL10) : EGLDisplay {
val eglDisplay = egl. eglGetDisplay ( EGL10. EGL_DEFAULT_DISPLAY)
if ( eglDisplay == EGL10. EGL_NO_DISPLAY) {
throw RuntimeException ( "eglGetDisplay failed" )
}
val version = IntArray ( 2 )
if ( ! egl. eglInitialize ( eglDisplay, version) ) {
throw RuntimeException ( "eglInitialize failed" )
}
return eglDisplay
}
override fun createEGLConfig ( egl: EGL10, display: EGLDisplay) : EGLConfig {
val attributes = intArrayOf (
EGL_RED_SIZE, 8 ,
EGL_GREEN_SIZE, 8 ,
EGL_BLUE_SIZE, 8 ,
EGL_ALPHA_SIZE, 8 ,
EGL_DEPTH_SIZE, 8 ,
EGL_STENCIL_SIZE, 8 ,
EGL_NONE
)
val numConfigs = IntArray ( 1 )
egl. eglChooseConfig ( display, attributes, null , 0 , numConfigs)
if ( numConfigs[ 0 ] <= 0 ) {
throw RuntimeException ( "No matching EGL configs" )
}
val configs = arrayOfNulls< EGLConfig> ( numConfigs[ 0 ] )
egl. eglChooseConfig ( display, attributes, configs, numConfigs. size, numConfigs)
return configs[ 0 ] ?: throw RuntimeException ( "No suitable EGL config found" )
}
override fun createEGLContext ( egl: EGL10, display: EGLDisplay, config: EGLConfig) : EGLContext {
val contextAttrs = intArrayOf (
EGL_CONTEXT_CLIENT_VERSION, 3 ,
EGL_NONE
)
val eglContext = egl. eglCreateContext ( display, config, EGL10. EGL_NO_CONTEXT, contextAttrs)
if ( eglContext == EGL10. EGL_NO_CONTEXT) {
throw RuntimeException ( "eglCreateContext failed" )
}
return eglContext
}
override fun createEGLSurface (
egl: EGL10,
display: EGLDisplay,
config: EGLConfig,
surface: Surface
) : EGLSurface {
val eglSurface = egl. eglCreateWindowSurface ( display, config, surface, null )
if ( eglSurface == EGL10. EGL_NO_SURFACE) {
throw RuntimeException ( "eglCreateWindowSurface failed" )
}
return eglSurface
}
}
构造者实现EGL环境
class EGLEnvironmentBuilder ( private val factory: EGLComponentFactory = DefaultEGLFactory ( ) ) {
private lateinit var mEGL: EGL10
private lateinit var mEGLDisplay: EGLDisplay
private lateinit var mEGLConfig: EGLConfig
private lateinit var mEGLContext: EGLContext
private lateinit var mEGLSurface: EGLSurface
fun build ( surface: Surface) : EGLEnvironment {
mEGL = factory. createEGL ( )
mEGLDisplay = factory. createEGLDisplay ( mEGL)
mEGLConfig = factory. createEGLConfig ( mEGL, mEGLDisplay)
mEGLContext = factory. createEGLContext ( mEGL, mEGLDisplay, mEGLConfig)
mEGLSurface = factory. createEGLSurface ( mEGL, mEGLDisplay, mEGLConfig, surface)
if ( ! mEGL. eglMakeCurrent ( mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext) ) {
throw RuntimeException ( "eglMakeCurrent failed" )
}
return EGLEnvironment ( mEGL, mEGLDisplay, mEGLContext, mEGLSurface)
}
inner class EGLEnvironment (
val egl: EGL10,
val display: EGLDisplay,
val context: EGLContext,
val surface: EGLSurface
) {
fun swapBuffers ( ) {
if ( ! egl. eglSwapBuffers ( display, surface) ) {
throw RuntimeException ( "eglSwapBuffers failed" )
}
}
fun release ( ) {
egl. eglMakeCurrent (
display,
EGL10. EGL_NO_SURFACE,
EGL10. EGL_NO_SURFACE,
EGL10. EGL_NO_CONTEXT
)
egl. eglDestroySurface ( display, surface)
egl. eglDestroyContext ( display, context)
egl. eglTerminate ( display)
}
}
}
渲染数据
渲染数据接口定义
interface OpenGLData {
fun onSurfaceCreated ( )
fun onSurfaceChanged ( width: Int, height: Int)
fun onDrawFrame ( )
fun onSurfaceDestroyed ( )
}
渲染数据接口实现
class BaseOpenGLData ( private val context: Context) : OpenGLData {
private val NO_OFFSET = 0
private val VERTEX_POS_DATA_SIZE = 3
private val TEXTURE_POS_DATA_SIZE = 2
private val STRIDE = ( VERTEX_POS_DATA_SIZE + TEXTURE_POS_DATA_SIZE) * 4
private var mProgram: Int = - 1
val vertexData = floatArrayOf (
- 1.0f , 1.0f , 0.0f , 0.0f , 1.0f ,
- 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f ,
1.0f , 1.0f , 0.0f , 1.0f , 1.0f ,
1.0f , - 1.0f , 0.0f , 1.0f , 0.0f
)
val vertexDataBuffer = ByteBuffer. allocateDirect ( vertexData. size * 4 )
. order ( ByteOrder. nativeOrder ( ) )
. asFloatBuffer ( )
. put ( vertexData)
. position ( NO_OFFSET)
val index = shortArrayOf (
0 , 1 , 2 ,
1 , 3 , 2
)
val indexBuffer = ByteBuffer. allocateDirect ( index. size * 2 )
. order ( ByteOrder. nativeOrder ( ) )
. asShortBuffer ( )
. put ( index)
. position ( NO_OFFSET)
private var mVAO = IntArray ( 1 )
private var mVBO = IntArray ( 1 )
private var mIBO = IntArray ( 1 )
private var mTextureID = IntArray ( 1 )
private var mMVPMatrix = FloatArray ( 16 )
private val mProjectionMatrix = FloatArray ( 16 )
private val mViewMatrix = FloatArray ( 16 )
private val mModelMatrix = FloatArray ( 16 )
private var mWidth = 0
private var mHeight = 0
override fun onSurfaceCreated ( ) {
initTexture ( )
initShaderProgram ( )
initVertexBuffer ( )
resetMatrix ( )
}
override fun onSurfaceChanged ( width: Int, height: Int) {
GLES30. glViewport ( 0 , 0 , width, height)
mWidth = width
mHeight = height
computeMVPMatrix ( )
}
override fun onDrawFrame ( ) {
clearBuffers ( )
draw ( )
}
override fun onSurfaceDestroyed ( ) {
release ( )
}
private fun initShaderProgram ( ) {
val vertexShaderCode = "" "#version 300 es
uniform mat4 uMVPMatrix;
in vec4 aPosition;
in vec2 aTexCoord;
out vec2 vTexCoord;
void main ( ) {
gl_Position = uMVPMatrix * aPosition;
vTexCoord = aTexCoord;
} """.trimIndent()
val fragmentShaderCode = """ #version 300 es
precision mediump float;
uniform sampler2D uTexture_0;
in vec2 vTexCoord;
out vec4 fragColor;
void main ( ) {
fragColor = texture ( uTexture_0, vTexCoord) ;
} "" ". trimIndent ( )
val vertexShader = OpenGLUtils. loadShader ( GLES30. GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader = OpenGLUtils. loadShader ( GLES30. GL_FRAGMENT_SHADER, fragmentShaderCode)
mProgram = GLES30. glCreateProgram ( )
GLES30. glAttachShader ( mProgram, vertexShader)
GLES30. glAttachShader ( mProgram, fragmentShader)
GLES30. glLinkProgram ( mProgram)
GLES30. glDeleteShader ( vertexShader)
GLES30. glDeleteShader ( fragmentShader)
}
private fun initVertexBuffer ( ) {
GLES30. glGenVertexArrays ( mVAO. size, mVAO, NO_OFFSET)
GLES30. glBindVertexArray ( mVAO[ 0 ] )
GLES30. glGenBuffers ( mVBO. size, mVBO, NO_OFFSET)
GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, mVBO[ 0 ] )
GLES30. glBufferData (
GLES30. GL_ARRAY_BUFFER,
vertexData. size * 4 ,
vertexDataBuffer,
GLES30. GL_STATIC_DRAW
)
val positionHandle = GLES30. glGetAttribLocation ( mProgram, "aPosition" )
GLES30. glEnableVertexAttribArray ( positionHandle)
GLES30. glVertexAttribPointer (
positionHandle,
VERTEX_POS_DATA_SIZE,
GLES30. GL_FLOAT,
false ,
STRIDE,
NO_OFFSET
)
val textureHandle = GLES30. glGetAttribLocation ( mProgram, "aTexCoord" )
GLES30. glEnableVertexAttribArray ( textureHandle)
GLES30. glVertexAttribPointer (
textureHandle,
TEXTURE_POS_DATA_SIZE,
GLES30. GL_FLOAT,
false ,
STRIDE,
VERTEX_POS_DATA_SIZE * 4
)
GLES30. glGenBuffers ( mIBO. size, mIBO, NO_OFFSET)
GLES30. glBindBuffer ( GLES30. GL_ELEMENT_ARRAY_BUFFER, mIBO[ 0 ] )
GLES30. glBufferData (
GLES30. GL_ELEMENT_ARRAY_BUFFER,
index. size * 2 ,
indexBuffer,
GLES30. GL_STATIC_DRAW
)
GLES30. glBindVertexArray ( 0 )
GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, 0 )
GLES30. glBindBuffer ( GLES30. GL_ELEMENT_ARRAY_BUFFER, 0 )
}
private fun initTexture ( ) {
val textureId = IntArray ( 1 )
GLES30. glGenTextures ( 1 , textureId, 0 )
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, textureId[ 0 ] )
GLES30. glTexParameteri (
GLES30. GL_TEXTURE_2D,
GLES30. GL_TEXTURE_MIN_FILTER,
GLES30. GL_LINEAR
)
GLES30. glTexParameteri (
GLES30. GL_TEXTURE_2D,
GLES30. GL_TEXTURE_MAG_FILTER,
GLES30. GL_LINEAR
)
GLES30. glTexParameteri (
GLES30. GL_TEXTURE_2D,
GLES30. GL_TEXTURE_WRAP_S,
GLES30. GL_CLAMP_TO_EDGE
)
GLES30. glTexParameteri (
GLES30. GL_TEXTURE_2D,
GLES30. GL_TEXTURE_WRAP_T,
GLES30. GL_CLAMP_TO_EDGE
)
val options = BitmapFactory. Options ( ) . apply {
inScaled = false
}
val bitmap = BitmapFactory. decodeResource ( context. resources, R. drawable. picture, options)
GLUtils. texImage2D ( GLES30. GL_TEXTURE_2D, 0 , bitmap, 0 )
bitmap. recycle ( )
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
Log. e (
"yang" ,
"loadTexture: 纹理加载成功 bitmap.width:${ bitmap. width} bitmap.height:${ bitmap. height} "
)
mTextureID[ 0 ] = textureId[ 0 ]
}
private fun resetMatrix ( ) {
Matrix. setIdentityM ( mProjectionMatrix, NO_OFFSET)
Matrix. setIdentityM ( mViewMatrix, NO_OFFSET)
Matrix. setIdentityM ( mModelMatrix, NO_OFFSET)
Matrix. setIdentityM ( mMVPMatrix, NO_OFFSET)
}
private fun computeMVPMatrix ( ) {
val isLandscape = mWidth > mHeight
val viewPortRatio = if ( isLandscape) mWidth. toFloat ( ) / mHeight else mHeight. toFloat ( ) / mWidth
val radius = sqrt ( 1f + viewPortRatio * viewPortRatio)
val near = 0.1f
val far = near + 2 * radius
val distance = near / ( near + radius)
Matrix. setLookAtM (
mViewMatrix, NO_OFFSET,
0f , 0f , near + radius,
0f , 0f , 0f ,
0f , 1f , 0f
)
Matrix. frustumM (
mProjectionMatrix, NO_OFFSET,
if ( isLandscape) ( - viewPortRatio * distance) else ( - 1f * distance) ,
if ( isLandscape) ( viewPortRatio * distance) else ( 1f * distance) ,
if ( isLandscape) ( - 1f * distance) else ( - viewPortRatio * distance) ,
if ( isLandscape) ( 1f * distance) else ( viewPortRatio * distance) ,
near,
far
)
Matrix. multiplyMM (
mMVPMatrix,
NO_OFFSET,
mViewMatrix,
NO_OFFSET,
mModelMatrix,
NO_OFFSET
)
Matrix. multiplyMM (
mMVPMatrix,
NO_OFFSET,
mProjectionMatrix,
NO_OFFSET,
mMVPMatrix,
NO_OFFSET
)
Matrix. scaleM (
mMVPMatrix,
NO_OFFSET,
1f ,
- 1f ,
1f ,
)
}
private fun clearBuffers ( ) {
GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT)
}
private fun draw ( ) {
val state = saveGLState ( )
try {
GLES30. glUseProgram ( mProgram)
enableTexture0 ( mProgram, mTextureID[ 0 ] )
val matrixHandle = GLES30. glGetUniformLocation ( mProgram, "uMVPMatrix" )
GLES30. glUniformMatrix4fv ( matrixHandle, 1 , false , mMVPMatrix, NO_OFFSET)
GLES30. glBindVertexArray ( mVAO[ 0 ] )
GLES30. glDrawElements (
GLES30. GL_TRIANGLES,
index. size,
GLES30. GL_UNSIGNED_SHORT,
NO_OFFSET
)
GLES30. glBindVertexArray ( 0 )
disableTexture0 ( )
} finally {
restoreGLState ( state)
}
}
private fun release ( ) {
}
}
object OpenGLUtils {
data class GLState (
val viewport: IntArray,
val program: Int,
val framebuffer: Int
)
fun saveGLState ( ) : GLState {
val viewport = IntArray ( 4 )
val program = IntArray ( 1 )
val framebuffer = IntArray ( 1 )
GLES30. glGetIntegerv ( GLES30. GL_VIEWPORT, viewport, 0 )
GLES30. glGetIntegerv ( GLES30. GL_CURRENT_PROGRAM, program, 0 )
GLES30. glGetIntegerv ( GLES30. GL_FRAMEBUFFER_BINDING, framebuffer, 0 )
return GLState ( viewport, program[ 0 ] , framebuffer[ 0 ] )
}
fun restoreGLState ( state: GLState) {
GLES30. glViewport (
state. viewport[ 0 ] ,
state. viewport[ 1 ] ,
state. viewport[ 2 ] ,
state. viewport[ 3 ]
)
GLES30. glUseProgram ( state. program)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, state. framebuffer)
}
fun enableTexture0 ( program: Int, id: Int) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE0)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, id)
val textureSampleHandle = GLES30. glGetUniformLocation ( program, "uTexture_0" )
if ( textureSampleHandle != - 1 ) {
GLES30. glUniform1i ( textureSampleHandle, 0 )
}
}
fun disableTexture0 ( ) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE0)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
}
fun loadShader ( type: Int, source: String) : Int {
val shader = GLES30. glCreateShader ( type)
GLES30. glShaderSource ( shader, source)
GLES30. glCompileShader ( shader)
return shader
}
}
渲染引擎
渲染引擎接口
interface OpenGLEngine {
val callback: SurfaceHolder. Callback
fun requestRender ( mode : Int? = null )
}
渲染引擎接口实现
open class BaseOpenGLEngine ( private val renderData: OpenGLData) : OpenGLEngine {
private var mRenderThread: RenderThread? = null
override val callback: SurfaceHolder. Callback = object : SurfaceHolder. Callback {
override fun surfaceCreated ( holder: SurfaceHolder) {
mRenderThread = RenderThread ( holder. surface, renderData) ? . apply {
start ( )
}
}
override fun surfaceChanged ( holder: SurfaceHolder, format: Int, width: Int, height: Int) {
mRenderThread? . updateSize ( width, height)
}
override fun surfaceDestroyed ( holder: SurfaceHolder) {
mRenderThread? . shutdown ( )
mRenderThread = null
}
}
override fun requestRender ( mode: Int? ) {
mRenderThread? . requestRender ( mode)
}
}
渲染线程
class RenderThread ( private val surface: Surface, private val renderData: OpenGLData) : Thread ( ) {
private val TAG = "RenderThread"
private var mEGLEnvironment : EGLEnvironmentBuilder. EGLEnvironment ? = null
@Volatile
private var running = true
@Volatile
private var sizeChanged = false
@Volatile
private var renderMode = RENDERMODE_WHEN_DIRTY
@Volatile
private var requestRender = true
private var mCacheWidth = 0
private var mCacheHeight = 0
private val lock = Object ( )
fun updateSize ( width: Int, height: Int) {
synchronized ( lock) {
mCacheWidth = width
mCacheHeight = height
sizeChanged = true
requestRender = true
lock. notifyAll ( )
Log. d ( TAG, "updateSize width = $width , height = $height " )
}
}
fun requestRender ( mode: Int? = null ) {
synchronized ( lock) {
mode? . let { renderMode = it }
requestRender = true
lock. notifyAll ( )
Log. d ( TAG, "requestRender${mode?.let { " mode = $it" } ?: " "}" )
}
}
fun shutdown ( ) {
synchronized ( lock) {
running = false
lock. notifyAll ( )
Log. d ( TAG, "requestRender shutdown" )
}
join ( )
renderData. onSurfaceDestroyed ( )
mEGLEnvironment? . release ( )
}
override fun run ( ) {
mEGLEnvironment = EGLEnvironmentBuilder ( ) . build ( surface)
renderData. onSurfaceCreated ( )
renderLoop ( )
}
private fun renderLoop ( ) {
while ( running) {
synchronized ( lock) {
while ( running && ! requestRender && ! sizeChanged && renderMode != RENDERMODE_CONTINUOUSLY) {
lock. wait ( )
}
if ( ! running) return
if ( sizeChanged) {
renderData. onSurfaceChanged ( mCacheWidth, mCacheHeight)
sizeChanged = false
}
if ( requestRender || renderMode == RENDERMODE_CONTINUOUSLY) {
renderData. onDrawFrame ( )
mEGLEnvironment? . swapBuffers ( )
requestRender = false
}
}
}
}
}
activity_main的XML文件
<?xml version="1.0" encoding="utf-8"?>
< LinearLayout xmlns: android= " http://schemas.android.com/apk/res/android"
android: layout_width= " match_parent"
android: layout_height= " match_parent"
android: orientation= " vertical" >
< FrameLayout
android: id= " @id/preview_fragment_container"
android: layout_width= " match_parent"
android: layout_height= " 0dp"
android: layout_weight= " 1"
android: background= " #000000" >
< com.example.render.opengl.BaseSurfaceView
android: layout_width= " match_parent"
android: layout_height= " match_parent" />
</ FrameLayout>
< FrameLayout
android: id= " @+id/operate_fragment_container"
android: layout_width= " match_parent"
android: layout_height= " 230dp"
android: background= " #F5F5F5" />
</ LinearLayout>
Activity的代码
class MainActivity : AppCompatActivity ( ) { \
override fun onCreate ( savedInstanceState: Bundle? ) {
super . onCreate ( savedInstanceState)
setContentView ( R. layout. activity_main)
}
}
效果图