XML
文件
<?xml version="1.0" encoding="utf-8"?>
< com.example.myapplication.EGLSurfaceView xmlns: android= " http://schemas.android.com/apk/res/android"
android: layout_width= " match_parent"
android: layout_height= " match_parent" >
</ com.example.myapplication.EGLSurfaceView>
Activity
代码
class MainActivity7 : AppCompatActivity ( ) {
override fun onCreate ( savedInstanceState: Bundle? ) {
super . onCreate ( savedInstanceState)
setContentView ( R. layout. activity_main7)
}
}
SurfaceView
代码,外观+依赖注入模式
class EGLSurfaceView ( context: Context, attrs: AttributeSet? = null ) : SurfaceView ( context, attrs) {
private val renderer = EGLRenderer ( context)
init {
holder. addCallback ( renderer. surfaceCallback)
}
fun setRenderStrategy ( strategy: RenderStrategy) {
renderer. setRenderStrategy ( strategy)
}
}
渲染器代码,外观+策略+适配器+依赖注入模式
class EGLRenderer ( context: Context) {
private val strategy: RenderStrategy = MyRenderStrategy ( context)
private val engine: EGLRenderEngine = EGLRenderEngine ( strategy)
fun setRenderStrategy ( strategy: RenderStrategy) {
}
val surfaceCallback = object : SurfaceHolder. Callback {
override fun surfaceCreated ( holder: SurfaceHolder) {
engine. onSurfaceCreated ( holder. surface)
}
override fun surfaceChanged ( holder: SurfaceHolder, format: Int, width: Int, height: Int) {
engine. onSurfaceChanged ( width, height)
}
override fun surfaceDestroyed ( holder: SurfaceHolder) {
engine. onSurfaceDestroyed ( )
}
}
}
渲染引擎代码,外观+策略+依赖注入模式
class EGLRenderEngine ( private val strategy: RenderStrategy) {
private var mEGLEnvironment: EGLEnvironment? = null
private var mRenderThread: RenderThread? = null
fun onSurfaceCreated ( surface: Surface) {
mRenderThread = RenderThread ( surface, strategy) . apply {
start ( )
}
}
fun onSurfaceChanged ( width: Int, height: Int) {
mRenderThread? . updateSize ( width, height)
}
fun onSurfaceDestroyed ( ) {
mRenderThread? . shutdown ( )
mRenderThread = null
}
private inner class RenderThread (
private val surface: Surface,
private val strategy: RenderStrategy
) : Thread ( ) {
@Volatile private var running = true
@Volatile private var sizeChanged = false
private var width = 0
private var height = 0
fun updateSize ( width: Int, height: Int) {
this . width = width
this . height = height
sizeChanged = true
}
fun shutdown ( ) {
running = false
interrupt ( )
strategy. onSurfaceDestroyed ( )
mEGLEnvironment? . release ( )
}
override fun run ( ) {
try {
mEGLEnvironment = EGLEnvironmentBuilder ( ) . build ( surface)
strategy. onSurfaceCreated ( )
while ( running) {
if ( sizeChanged) {
strategy. onSurfaceChanged ( width, height)
sizeChanged = false
}
strategy. onDrawFrame ( )
mEGLEnvironment? . swapBuffers ( )
}
} catch ( e: Exception) {
Log. e ( "RenderEngine" , "Render thread error: ${ e. message} " )
}
}
}
}
自定义渲染策略代码,策略模式
interface RenderStrategy {
fun onSurfaceCreated ( )
fun onSurfaceChanged ( width: Int, height: Int)
fun onDrawFrame ( )
fun onSurfaceDestroyed ( )
}
class MyRenderStrategy ( private val context: Context) : RenderStrategy {
var mDrawData: MyDrawData2? = null
override fun onSurfaceCreated ( ) {
GLES30. glClearColor ( 0.0f , 0.5f , 0.5f , 1.0f )
mDrawData = MyDrawData2 ( ) . apply {
initTexture0 ( context, R. drawable. picture)
initShaderProgram ( )
initVertexBuffer ( )
}
}
override fun onSurfaceChanged ( width: Int, height: Int) {
GLES30. glViewport ( 0 , 0 , width, height)
mDrawData? . setSurfaceSize ( width, height)
}
override fun onDrawFrame ( ) {
GLES30. glEnable ( GLES30. GL_DEPTH_TEST)
GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT or GLES30. GL_DEPTH_BUFFER_BIT)
mDrawData? . drawCurrentOutput ( )
}
override fun onSurfaceDestroyed ( ) {
mDrawData? . release ( )
}
}
搭建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)
}
}
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 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
}
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, 4 ,
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[ 0 ] , 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
}
}
渲染数据代码
data class CubeInfo (
var x: Float,
var y: Float,
var angle: Float,
var rotationSpeed: Float,
var scale : Float
)
private val cubes = arrayOf (
CubeInfo ( x = - 1.0f , y = 1.0f , angle = 0f , rotationSpeed = 0.3f , scale = 0.3f ) ,
CubeInfo ( x = 1.0f , y = 1.0f , angle = 45f , rotationSpeed = 0.5f , scale = 0.4f ) ,
CubeInfo ( x = 0f , y = 0f , angle = 90f , rotationSpeed = 0.7f , scale = 0.2f ) ,
CubeInfo ( x = - 1.0f , y = - 1.0f , angle = 135f , rotationSpeed = 0.4f , scale = 0.5f ) ,
CubeInfo ( x = 1.0f , y = - 1.0f , angle = 180f , rotationSpeed = 0.2f , scale = 0.7f )
)
class MyDrawData2 {
private var mProgram: Int = - 1
private var 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 mVAO = IntArray ( 1 )
private var mVBO = 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 mViewPortRatio = 1f
private var mSurfaceWidth = 0
private var mSurfaceHeight = 0
val vertexData = floatArrayOf (
- 0.5f , - 0.5f , - 0.5f , 0.0f , 0.0f ,
0.5f , - 0.5f , - 0.5f , 1.0f , 0.0f ,
0.5f , 0.5f , - 0.5f , 1.0f , 1.0f ,
0.5f , 0.5f , - 0.5f , 1.0f , 1.0f ,
- 0.5f , 0.5f , - 0.5f , 0.0f , 1.0f ,
- 0.5f , - 0.5f , - 0.5f , 0.0f , 0.0f ,
- 0.5f , - 0.5f , 0.5f , 0.0f , 0.0f ,
0.5f , - 0.5f , 0.5f , 1.0f , 0.0f ,
0.5f , 0.5f , 0.5f , 1.0f , 1.0f ,
0.5f , 0.5f , 0.5f , 1.0f , 1.0f ,
- 0.5f , 0.5f , 0.5f , 0.0f , 1.0f ,
- 0.5f , - 0.5f , 0.5f , 0.0f , 0.0f ,
- 0.5f , 0.5f , 0.5f , 1.0f , 0.0f ,
- 0.5f , 0.5f , - 0.5f , 1.0f , 1.0f ,
- 0.5f , - 0.5f , - 0.5f , 0.0f , 1.0f ,
- 0.5f , - 0.5f , - 0.5f , 0.0f , 1.0f ,
- 0.5f , - 0.5f , 0.5f , 0.0f , 0.0f ,
- 0.5f , 0.5f , 0.5f , 1.0f , 0.0f ,
0.5f , 0.5f , 0.5f , 1.0f , 0.0f ,
0.5f , 0.5f , - 0.5f , 1.0f , 1.0f ,
0.5f , - 0.5f , - 0.5f , 0.0f , 1.0f ,
0.5f , - 0.5f , - 0.5f , 0.0f , 1.0f ,
0.5f , - 0.5f , 0.5f , 0.0f , 0.0f ,
0.5f , 0.5f , 0.5f , 1.0f , 0.0f ,
- 0.5f , - 0.5f , - 0.5f , 0.0f , 1.0f ,
0.5f , - 0.5f , - 0.5f , 1.0f , 1.0f ,
0.5f , - 0.5f , 0.5f , 1.0f , 0.0f ,
0.5f , - 0.5f , 0.5f , 1.0f , 0.0f ,
- 0.5f , - 0.5f , 0.5f , 0.0f , 0.0f ,
- 0.5f , - 0.5f , - 0.5f , 0.0f , 1.0f ,
- 0.5f , 0.5f , - 0.5f , 0.0f , 1.0f ,
0.5f , 0.5f , - 0.5f , 1.0f , 1.0f ,
0.5f , 0.5f , 0.5f , 1.0f , 0.0f ,
0.5f , 0.5f , 0.5f , 1.0f , 0.0f ,
- 0.5f , 0.5f , 0.5f , 0.0f , 0.0f ,
- 0.5f , 0.5f , - 0.5f , 0.0f , 1.0f
)
val vertexDataBuffer = ByteBuffer. allocateDirect ( vertexData. size * 4 )
. order ( ByteOrder. nativeOrder ( ) )
. asFloatBuffer ( )
. put ( vertexData)
. position ( NO_OFFSET)
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 = LoadShaderUtil. loadShader ( GLES30. GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader = LoadShaderUtil. 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)
}
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. glBindVertexArray ( 0 )
GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, 0 )
}
fun drawSomething ( program: Int, mvpMatrix: FloatArray) {
val matrixHandle = GLES30. glGetUniformLocation ( program, "uMVPMatrix" )
GLES30. glUniformMatrix4fv ( matrixHandle, 1 , false , mvpMatrix, NO_OFFSET)
GLES30. glBindVertexArray ( mVAO[ 0 ] )
GLES30. glDrawArrays ( GLES30. GL_TRIANGLES, NO_OFFSET, vertexData. size / ( VERTEX_POS_DATA_SIZE + TEXTURE_POS_DATA_SIZE) )
GLES30. glBindVertexArray ( 0 )
}
fun setSurfaceSize ( width: Int, height: Int) {
mSurfaceWidth = width
mSurfaceHeight = height
}
fun resetMatrix ( ) {
Matrix. setIdentityM ( mModelMatrix, NO_OFFSET)
Matrix. setIdentityM ( mViewMatrix, NO_OFFSET)
Matrix. setIdentityM ( mProjectionMatrix, NO_OFFSET)
Matrix. setIdentityM ( mMVPMatrix, NO_OFFSET)
}
fun computeMVPMatrix ( width: Int, height: Int, cube: CubeInfo) {
mSurfaceWidth = width
mSurfaceHeight = height
cube. angle += cube. rotationSpeed
cube. angle %= 360
Matrix. scaleM ( mModelMatrix, NO_OFFSET, cube. scale, cube. scale, cube. scale)
Matrix. translateM ( mModelMatrix, NO_OFFSET, cube. x, cube. y, 0f )
Matrix. rotateM ( mModelMatrix, NO_OFFSET, cube. angle, 0.5f , 0.5f , 0f )
val isLandscape = width > height
mViewPortRatio = if ( isLandscape) width. toFloat ( ) / height else height. toFloat ( ) / width
val radius = sqrt ( 1f + mViewPortRatio * mViewPortRatio)
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) ( - mViewPortRatio * distance) else ( - 1f * distance) ,
if ( isLandscape) ( mViewPortRatio * distance) else ( 1f * distance) ,
if ( isLandscape) ( - 1f * distance) else ( - mViewPortRatio * distance) ,
if ( isLandscape) ( 1f * distance) else ( mViewPortRatio * 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 ,
)
}
fun loadTexture ( context: Context, resourceId: Int) : Int {
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, resourceId, 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} "
)
return textureId[ 0 ]
}
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 initTexture0 ( context: Context, resourceId: Int) {
mTextureID[ 0 ] = loadTexture ( context, resourceId)
}
fun drawCurrentOutput ( ) {
val state = saveGLState ( )
try {
GLES30. glUseProgram ( mProgram)
enableTexture0 ( mProgram, mTextureID[ 0 ] )
for ( cube in cubes) {
resetMatrix ( )
computeMVPMatrix ( mSurfaceWidth, mSurfaceHeight, cube)
drawSomething ( mProgram, mMVPMatrix)
}
disableTexture0 ( )
} finally {
restoreGLState ( state)
}
}
private 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 ] )
}
private 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 release ( ) {
if ( mVAO[ 0 ] != 0 ) {
GLES30. glDeleteVertexArrays ( 1 , mVAO, 0 )
mVAO[ 0 ] = 0
}
if ( mVBO[ 0 ] != 0 ) {
GLES30. glDeleteBuffers ( 1 , mVBO, 0 )
mVBO[ 0 ] = 0
}
if ( mTextureID[ 0 ] != 0 ) {
GLES30. glDeleteTextures ( 1 , mTextureID, 0 )
mTextureID[ 0 ] = 0
}
if ( mProgram != - 1 ) {
GLES30. glDeleteProgram ( mProgram)
mProgram = - 1
}
vertexDataBuffer. clear ( )
}
data class GLState (
val viewport: IntArray,
val program: Int,
val framebuffer: Int
)
object LoadShaderUtil {
fun loadShader ( type: Int, source: String) : Int {
val shader = GLES30. glCreateShader ( type)
GLES30. glShaderSource ( shader, source)
GLES30. glCompileShader ( shader)
return shader
}
}
}
效果图