diff --git a/README.md b/README.md index 320bd56..187c79d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ShaderView -[![](https://jitpack.io/v/appspell/ShaderView.svg)](https://jitpack.io/#appspell/ShaderView) +[![](https://jitpack.io/v/oxters168/ShaderView.svg)](https://jitpack.io/#oxters168/ShaderView) This library is the easiest way to use **OpenGL shaders** as an **[Android View](https://developer.android.com/reference/android/view/View)**. You just simply need to add **ShaderView** in your layout and set up shaders. The advantage of this library that you can use ShaderView in your hierarchy as a regular View. @@ -81,9 +81,13 @@ with(shaderView) { ## The full list of ShaderView properties: -`fragmentShaderRawResId` - reference to the vertex shader file in RAW resource solder [example] +`fragmentShaderRawResId` - reference to the vertex shader file in RAW resource solder [example] +OR +`fragmentShader` - a string of the fragment shader code -`vertexShaderRawResId` - reference to the fragment shader file in RAW resource solder [example] +`vertexShaderRawResId` - reference to the fragment shader file in RAW resource solder [example] +OR +`vertexShader` - a string of the vertex shader code `shaderParams` - custom parameters that we're going to send to the shader (uniform) @@ -93,6 +97,8 @@ with(shaderView) { `updateContinuously` - should we render the view each frame (default is "false") +`framerate` - how many frames the shader should be drawn per second when update mode is set to continuously (<=0 means every frame) + `debugMode` - enable or disable debug logs @@ -105,7 +111,7 @@ shaderView.shaderParams = ShaderParamsBuilder() .addTexture2D( "uNormalTexture", // name of `sampler2D` in the fragment shader R.drawable.normal_button, // drawable that we use for such texture - GLES30.GL_TEXTURE0 // texture slot + GLES32.GL_TEXTURE0 // texture slot ) .addColor("uColor", R.color.grey, resources) // send color as `uniform vec4` .addVec4f("uColor2", floatArrayOf(0.5f, 0.5f, 0.5f, 1f)) diff --git a/demo/src/main/java/com/appspell/shaderview/demo/list/ShaderListAdapter.kt b/demo/src/main/java/com/appspell/shaderview/demo/list/ShaderListAdapter.kt index 6dab4d4..897ef3f 100644 --- a/demo/src/main/java/com/appspell/shaderview/demo/list/ShaderListAdapter.kt +++ b/demo/src/main/java/com/appspell/shaderview/demo/list/ShaderListAdapter.kt @@ -1,6 +1,6 @@ package com.appspell.shaderview.demo.list -import android.opengl.GLES30 +import android.opengl.GLES32 import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -74,17 +74,17 @@ class ShaderListAdapter : RecyclerView.Adapter .addTexture2D( "uTextureSampler1", R.drawable.bokeh, - GLES30.GL_TEXTURE0 + GLES32.GL_TEXTURE0 ) .addTexture2D( "uTextureSampler2", R.drawable.normal_button, - GLES30.GL_TEXTURE1 + GLES32.GL_TEXTURE1 ) .addTexture2D( "uTextureSampler3", R.drawable.test_texture, - GLES30.GL_TEXTURE2 + GLES32.GL_TEXTURE2 ) .build() } @@ -102,7 +102,7 @@ class ShaderListAdapter : RecyclerView.Adapter .addTexture2D( "uNormalTexture", R.drawable.normal_button, - GLES30.GL_TEXTURE0 + GLES32.GL_TEXTURE0 ) .addColor("uColor", R.color.grey, resources) .addVec3f("uVaryingColor", floatArrayOf(0.5f, 0.5f, 0.5f)) @@ -128,7 +128,7 @@ class ShaderListAdapter : RecyclerView.Adapter .addTexture2D( "uNormalTexture", R.drawable.normal_sphere, - GLES30.GL_TEXTURE0 + GLES32.GL_TEXTURE0 ) .addVec4f("uColor", floatArrayOf(0.5f, 0.5f, 0.5f, 1f)) .addVec3f("uVaryingColor", floatArrayOf(0.4f, 0.4f, 0.5f)) @@ -199,7 +199,7 @@ class ShaderListAdapter : RecyclerView.Adapter .addTexture2D( "uTexture", R.drawable.android, - GLES30.GL_TEXTURE0 + GLES32.GL_TEXTURE0 ) .addVec2f("uOffset") .build() @@ -223,7 +223,7 @@ class ShaderListAdapter : RecyclerView.Adapter .addTexture2D( "uTexture", R.drawable.test_texture, - GLES30.GL_TEXTURE0 + GLES32.GL_TEXTURE0 ) .addVec2f("uScale", floatArrayOf(0f, 0f)) .addInt("uBlurSize", 3) diff --git a/lib/publish.gradle b/lib/publish.gradle index 9785e8d..06be77c 100644 --- a/lib/publish.gradle +++ b/lib/publish.gradle @@ -1,6 +1,6 @@ apply plugin: 'maven-publish' -version '0.8.8' +version '0.8.12' task sourceJar(type: Jar) { from android.sourceSets.main.java.srcDirs diff --git a/lib/src/main/java/com/appspell/shaderview/ShaderView.kt b/lib/src/main/java/com/appspell/shaderview/ShaderView.kt index 56669f3..76112dc 100644 --- a/lib/src/main/java/com/appspell/shaderview/ShaderView.kt +++ b/lib/src/main/java/com/appspell/shaderview/ShaderView.kt @@ -45,6 +45,17 @@ class ShaderView @JvmOverloads constructor( field = value } + var vertexShader: String? = null + set(value) { + needToRecreateShaders = true + field = value + } + var fragmentShader: String? = null + set(value) { + needToRecreateShaders = true + field = value + } + var shaderParams: ShaderParams? = null set(value) { field = value @@ -87,6 +98,17 @@ class ShaderView @JvmOverloads constructor( } } + /** + * how many frames the shader should be drawn per second + */ + var framerate: Int + set(value) { + setFPS(value) + } + get(): Int { + return getFPS() + } + private val rendererListener = object : GLQuadRender.ShaderViewListener { override fun onSurfaceCreated() { initShaders() @@ -158,21 +180,39 @@ class ShaderView @JvmOverloads constructor( // delete existing shader if we have some renderer.shader.release() - // create a new shader - renderer.shader = renderer.shader.newBuilder() - .create( - context = context, - vertexShaderRawResId = vertexShaderRawResId ?: DEFAULT_VERTEX_SHADER_RESOURCE, - fragmentShaderRawResId = fragmentShader - ) - .apply { - // if we have some ShaderParams to set - shaderParams?.apply { params(this) } - } - .build() - .also { - needToRecreateShaders = true - } + vertexShader?.let { + // create a new shader from text + renderer.shader = renderer.shader.newBuilder() + .create( + vertexShader = this.vertexShader!!, + fragmentShader = this.fragmentShader!! + ) + .apply { + // if we have some ShaderParams to set + shaderParams?.apply { params(this) } + } + .build() + .also { + needToRecreateShaders = true + } + } ?: run { + // create a new shader from resources + renderer.shader = renderer.shader.newBuilder() + .create( + context = context, + vertexShaderRawResId = vertexShaderRawResId + ?: DEFAULT_VERTEX_SHADER_RESOURCE, + fragmentShaderRawResId = fragmentShader + ) + .apply { + // if we have some ShaderParams to set + shaderParams?.apply { params(this) } + } + .build() + .also { + needToRecreateShaders = true + } + } } } diff --git a/lib/src/main/java/com/appspell/shaderview/annotations/ShaderExperimentalApi.kt b/lib/src/main/java/com/appspell/shaderview/annotations/ShaderExperimentalApi.kt index 0cb646d..806600c 100644 --- a/lib/src/main/java/com/appspell/shaderview/annotations/ShaderExperimentalApi.kt +++ b/lib/src/main/java/com/appspell/shaderview/annotations/ShaderExperimentalApi.kt @@ -1,6 +1,6 @@ package com.appspell.shaderview.annotations @Suppress("DEPRECATION") -@Experimental(level = Experimental.Level.WARNING) +//@Experimental(level = Experimental.Level.WARNING) @RequiresOptIn(level = RequiresOptIn.Level.WARNING) public annotation class ShaderExperimentalApi \ No newline at end of file diff --git a/lib/src/main/java/com/appspell/shaderview/ext/Texture.kt b/lib/src/main/java/com/appspell/shaderview/ext/Texture.kt index 6a4d9dc..d1b7d0d 100644 --- a/lib/src/main/java/com/appspell/shaderview/ext/Texture.kt +++ b/lib/src/main/java/com/appspell/shaderview/ext/Texture.kt @@ -4,8 +4,7 @@ import android.content.res.Resources import android.graphics.Bitmap import android.graphics.BitmapFactory import android.opengl.GLES11Ext -import android.opengl.GLES20 -import android.opengl.GLES30 +import android.opengl.GLES32 import android.opengl.GLUtils import androidx.annotation.DrawableRes import java.nio.IntBuffer @@ -21,16 +20,16 @@ import java.nio.IntBuffer */ fun createExternalTexture(): Int { val textureIds = IntArray(1) - GLES30.glGenTextures(1, IntBuffer.wrap(textureIds)) + GLES32.glGenTextures(1, IntBuffer.wrap(textureIds)) if (textureIds[0] == 0) { throw java.lang.RuntimeException("It's not possible to generate ID for texture") } - GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureIds[0]) - GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR) - GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR) + GLES32.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureIds[0]) + GLES32.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES32.GL_TEXTURE_MIN_FILTER, GLES32.GL_LINEAR) + GLES32.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES32.GL_TEXTURE_MAG_FILTER, GLES32.GL_LINEAR) - GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE) - GLES30.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE) + GLES32.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES32.GL_TEXTURE_WRAP_S, GLES32.GL_CLAMP_TO_EDGE) + GLES32.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES32.GL_TEXTURE_WRAP_T, GLES32.GL_CLAMP_TO_EDGE) return textureIds[0] } @@ -47,30 +46,30 @@ fun Resources.loadBitmapForTexture(@DrawableRes drawableRes: Int): Bitmap { * @needToRecycle - do we need to recycle current Bitmap when we write it GPI? */ @Throws(RuntimeException::class) -fun Bitmap.toGlTexture(needToRecycle: Boolean = true, textureSlot: Int = GLES30.GL_TEXTURE0): Int { +fun Bitmap.toGlTexture(needToRecycle: Boolean = true, textureSlot: Int = GLES32.GL_TEXTURE0): Int { // init textures val textureIds = IntArray(1) - GLES30.glGenTextures(1, textureIds, 0) // generate ID for texture + GLES32.glGenTextures(1, textureIds, 0) // generate ID for texture if (textureIds[0] == 0) { throw java.lang.RuntimeException("It's not possible to generate ID for texture") } - GLES30.glActiveTexture(textureSlot) // activate slot #0 for texture - GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0]) // bind texture by ID with active slot + GLES32.glActiveTexture(textureSlot) // activate slot #0 for texture + GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, textureIds[0]) // bind texture by ID with active slot // texture filters - 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) + GLES32.glTexParameteri(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_MIN_FILTER, GLES32.GL_LINEAR) + GLES32.glTexParameteri(GLES32.GL_TEXTURE_2D, GLES32.GL_TEXTURE_MAG_FILTER, GLES32.GL_LINEAR) // write bitmap to GPU - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, this, 0) + GLUtils.texImage2D(GLES32.GL_TEXTURE_2D, 0, this, 0) // we don't need this bitmap anymore if (needToRecycle) { this.recycle() } // unbind texture from slot - GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0) + GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, 0) return textureIds[0] } \ No newline at end of file diff --git a/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsBuilder.kt b/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsBuilder.kt index 9a08012..f18afa7 100644 --- a/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsBuilder.kt +++ b/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsBuilder.kt @@ -3,7 +3,7 @@ package com.appspell.shaderview.gl.params import android.content.res.Resources import android.graphics.Bitmap import android.graphics.Color -import android.opengl.GLES30 +import android.opengl.GLES32 import androidx.annotation.ColorInt import androidx.annotation.ColorRes import androidx.annotation.DrawableRes @@ -125,7 +125,7 @@ class ShaderParamsBuilder { fun addTexture2D( paramName: String, bitmap: Bitmap? = null, - textureSlot: Int = GLES30.GL_TEXTURE0 + textureSlot: Int = GLES32.GL_TEXTURE0 ): ShaderParamsBuilder { val param = Param( valeType = Param.ValueType.SAMPLER_2D, @@ -146,7 +146,7 @@ class ShaderParamsBuilder { fun addTexture2D( paramName: String, @DrawableRes textureResourceId: Int, - textureSlot: Int = GLES30.GL_TEXTURE0 + textureSlot: Int = GLES32.GL_TEXTURE0 ): ShaderParamsBuilder { val param = Param( valeType = Param.ValueType.SAMPLER_2D, diff --git a/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsImpl.kt b/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsImpl.kt index 6efa8b9..4f1828f 100644 --- a/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsImpl.kt +++ b/lib/src/main/java/com/appspell/shaderview/gl/params/ShaderParamsImpl.kt @@ -3,7 +3,7 @@ package com.appspell.shaderview.gl.params import android.content.res.Resources import android.graphics.Bitmap import android.graphics.SurfaceTexture -import android.opengl.GLES30 +import android.opengl.GLES32 import android.view.Surface import com.appspell.shaderview.annotations.ShaderExperimentalApi import com.appspell.shaderview.ext.createExternalTexture @@ -64,7 +64,7 @@ class ShaderParamsImpl : ShaderParams { private fun updateUniformLocation(paramName: String, shaderProgram: Int) { map[paramName]?.apply { - location = GLES30.glGetUniformLocation(shaderProgram, paramName) + location = GLES32.glGetUniformLocation(shaderProgram, paramName) } } @@ -105,30 +105,30 @@ class ShaderParamsImpl : ShaderParams { continue } when (param.valeType) { - Param.ValueType.FLOAT -> GLES30.glUniform1f(param.location, param.value as Float) - Param.ValueType.INT -> GLES30.glUniform1i(param.location, param.value as Int) - Param.ValueType.BOOL -> GLES30.glUniform1i(param.location, if (param.value as Boolean) 1 else 0) - Param.ValueType.FLOAT_VEC2 -> GLES30.glUniform2fv(param.location, 1, (param.value as FloatArray), 0) - Param.ValueType.FLOAT_VEC3 -> GLES30.glUniform3fv(param.location, 1, (param.value as FloatArray), 0) - Param.ValueType.FLOAT_VEC4 -> GLES30.glUniform4fv(param.location, 1, (param.value as FloatArray), 0) - Param.ValueType.INT_VEC2 -> GLES30.glUniform2iv(param.location, 1, (param.value as IntArray), 0) - Param.ValueType.INT_VEC3 -> GLES30.glUniform3iv(param.location, 1, (param.value as IntArray), 0) - Param.ValueType.INT_VEC4 -> GLES30.glUniform4iv(param.location, 1, (param.value as IntArray), 0) - Param.ValueType.MAT3 -> GLES30.glUniformMatrix3fv( + Param.ValueType.FLOAT -> GLES32.glUniform1f(param.location, param.value as Float) + Param.ValueType.INT -> GLES32.glUniform1i(param.location, param.value as Int) + Param.ValueType.BOOL -> GLES32.glUniform1i(param.location, if (param.value as Boolean) 1 else 0) + Param.ValueType.FLOAT_VEC2 -> GLES32.glUniform2fv(param.location, 1, (param.value as FloatArray), 0) + Param.ValueType.FLOAT_VEC3 -> GLES32.glUniform3fv(param.location, 1, (param.value as FloatArray), 0) + Param.ValueType.FLOAT_VEC4 -> GLES32.glUniform4fv(param.location, 1, (param.value as FloatArray), 0) + Param.ValueType.INT_VEC2 -> GLES32.glUniform2iv(param.location, 1, (param.value as IntArray), 0) + Param.ValueType.INT_VEC3 -> GLES32.glUniform3iv(param.location, 1, (param.value as IntArray), 0) + Param.ValueType.INT_VEC4 -> GLES32.glUniform4iv(param.location, 1, (param.value as IntArray), 0) + Param.ValueType.MAT3 -> GLES32.glUniformMatrix3fv( param.location, 1, false, (param.value as FloatArray), 0 ) - Param.ValueType.MAT4 -> GLES30.glUniformMatrix4fv( + Param.ValueType.MAT4 -> GLES32.glUniformMatrix4fv( param.location, 1, false, (param.value as FloatArray), 0 ) - Param.ValueType.MAT3x4 -> GLES30.glUniformMatrix3x4fv( + Param.ValueType.MAT3x4 -> GLES32.glUniformMatrix3x4fv( param.location, 1, false, @@ -137,9 +137,9 @@ class ShaderParamsImpl : ShaderParams { ) Param.ValueType.SAMPLER_2D -> { (param.value as? TextureParam)?.apply { - GLES30.glUniform1i(param.location, textureSlot.convertTextureSlotToIndex()) - GLES30.glActiveTexture(textureSlot) - textureId?.also { GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, it) } + GLES32.glUniform1i(param.location, textureSlot.convertTextureSlotToIndex()) + GLES32.glActiveTexture(textureSlot) + textureId?.also { GLES32.glBindTexture(GLES32.GL_TEXTURE_2D, it) } } } Param.ValueType.SAMPLER_OES -> { @@ -208,38 +208,38 @@ class ShaderParamsImpl : ShaderParams { private fun Int.convertTextureSlotToIndex(): Int = when (this) { - GLES30.GL_TEXTURE0 -> 0 - GLES30.GL_TEXTURE1 -> 1 - GLES30.GL_TEXTURE2 -> 2 - GLES30.GL_TEXTURE3 -> 3 - GLES30.GL_TEXTURE4 -> 4 - GLES30.GL_TEXTURE5 -> 5 - GLES30.GL_TEXTURE6 -> 6 - GLES30.GL_TEXTURE7 -> 7 - GLES30.GL_TEXTURE8 -> 8 - GLES30.GL_TEXTURE9 -> 9 - GLES30.GL_TEXTURE10 -> 10 - GLES30.GL_TEXTURE11 -> 11 - GLES30.GL_TEXTURE12 -> 12 - GLES30.GL_TEXTURE13 -> 13 - GLES30.GL_TEXTURE14 -> 14 - GLES30.GL_TEXTURE15 -> 15 - GLES30.GL_TEXTURE16 -> 16 - GLES30.GL_TEXTURE17 -> 17 - GLES30.GL_TEXTURE18 -> 18 - GLES30.GL_TEXTURE19 -> 19 - GLES30.GL_TEXTURE20 -> 20 - GLES30.GL_TEXTURE21 -> 21 - GLES30.GL_TEXTURE22 -> 22 - GLES30.GL_TEXTURE23 -> 23 - GLES30.GL_TEXTURE24 -> 24 - GLES30.GL_TEXTURE25 -> 25 - GLES30.GL_TEXTURE26 -> 26 - GLES30.GL_TEXTURE27 -> 27 - GLES30.GL_TEXTURE28 -> 28 - GLES30.GL_TEXTURE29 -> 29 - GLES30.GL_TEXTURE30 -> 30 - GLES30.GL_TEXTURE31 -> 31 + GLES32.GL_TEXTURE0 -> 0 + GLES32.GL_TEXTURE1 -> 1 + GLES32.GL_TEXTURE2 -> 2 + GLES32.GL_TEXTURE3 -> 3 + GLES32.GL_TEXTURE4 -> 4 + GLES32.GL_TEXTURE5 -> 5 + GLES32.GL_TEXTURE6 -> 6 + GLES32.GL_TEXTURE7 -> 7 + GLES32.GL_TEXTURE8 -> 8 + GLES32.GL_TEXTURE9 -> 9 + GLES32.GL_TEXTURE10 -> 10 + GLES32.GL_TEXTURE11 -> 11 + GLES32.GL_TEXTURE12 -> 12 + GLES32.GL_TEXTURE13 -> 13 + GLES32.GL_TEXTURE14 -> 14 + GLES32.GL_TEXTURE15 -> 15 + GLES32.GL_TEXTURE16 -> 16 + GLES32.GL_TEXTURE17 -> 17 + GLES32.GL_TEXTURE18 -> 18 + GLES32.GL_TEXTURE19 -> 19 + GLES32.GL_TEXTURE20 -> 20 + GLES32.GL_TEXTURE21 -> 21 + GLES32.GL_TEXTURE22 -> 22 + GLES32.GL_TEXTURE23 -> 23 + GLES32.GL_TEXTURE24 -> 24 + GLES32.GL_TEXTURE25 -> 25 + GLES32.GL_TEXTURE26 -> 26 + GLES32.GL_TEXTURE27 -> 27 + GLES32.GL_TEXTURE28 -> 28 + GLES32.GL_TEXTURE29 -> 29 + GLES32.GL_TEXTURE30 -> 30 + GLES32.GL_TEXTURE31 -> 31 else -> 0 } } \ No newline at end of file diff --git a/lib/src/main/java/com/appspell/shaderview/gl/params/SpecialParam.kt b/lib/src/main/java/com/appspell/shaderview/gl/params/SpecialParam.kt index a72f749..2b2b5b8 100644 --- a/lib/src/main/java/com/appspell/shaderview/gl/params/SpecialParam.kt +++ b/lib/src/main/java/com/appspell/shaderview/gl/params/SpecialParam.kt @@ -2,7 +2,7 @@ package com.appspell.shaderview.gl.params import android.graphics.Bitmap import android.graphics.SurfaceTexture -import android.opengl.GLES30 +import android.opengl.GLES32 import android.view.Surface import androidx.annotation.DrawableRes import java.util.concurrent.atomic.AtomicBoolean @@ -20,5 +20,5 @@ data class TextureParam( val bitmap: Bitmap? = null, var textureId: Int? = null, val needToRecycleWhenUploaded: Boolean = true, - val textureSlot: Int = GLES30.GL_TEXTURE0 + val textureSlot: Int = GLES32.GL_TEXTURE0 ) \ No newline at end of file diff --git a/lib/src/main/java/com/appspell/shaderview/gl/render/GLQuadRender.kt b/lib/src/main/java/com/appspell/shaderview/gl/render/GLQuadRender.kt index a003404..802b672 100644 --- a/lib/src/main/java/com/appspell/shaderview/gl/render/GLQuadRender.kt +++ b/lib/src/main/java/com/appspell/shaderview/gl/render/GLQuadRender.kt @@ -1,7 +1,6 @@ package com.appspell.shaderview.gl.render -import android.opengl.GLES20 -import android.opengl.GLES30 +import android.opengl.GLES32 import android.opengl.Matrix import com.appspell.shaderview.gl.params.ShaderParams import com.appspell.shaderview.gl.shader.GLShader @@ -83,7 +82,7 @@ internal class GLQuadRenderImpl( } override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) { - GLES30.glViewport(0, 0, width, height) + GLES32.glViewport(0, 0, width, height) } override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) { @@ -112,10 +111,10 @@ internal class GLQuadRenderImpl( return } - GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f) - GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT or GLES30.GL_COLOR_BUFFER_BIT) + GLES32.glClearColor(0.0f, 0.0f, 0.0f, 0.0f) + GLES32.glClear(GLES32.GL_DEPTH_BUFFER_BIT or GLES32.GL_COLOR_BUFFER_BIT) - GLES30.glUseProgram(shader.program) + GLES32.glUseProgram(shader.program) checkGlError("glUseProgram") // shader input (built-in attributes) @@ -134,21 +133,21 @@ internal class GLQuadRenderImpl( shader.onDrawFrame() // activate blending for textures - GLES30.glBlendFunc(GLES30.GL_SRC_ALPHA, GLES30.GL_ONE_MINUS_SRC_ALPHA) - GLES30.glEnable(GLES20.GL_BLEND) + GLES32.glBlendFunc(GLES32.GL_SRC_ALPHA, GLES32.GL_ONE_MINUS_SRC_ALPHA) + GLES32.glEnable(GLES32.GL_BLEND) // draw scene - GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4) + GLES32.glDrawArrays(GLES32.GL_TRIANGLE_STRIP, 0, 4) checkGlError("glDrawArrays") - GLES30.glFinish() + GLES32.glFinish() } /** * get location of some input attribute for shader */ private fun glGetAttribLocation(attrName: String): Int { - val attrLocation = GLES30.glGetAttribLocation(shader.program, attrName) + val attrLocation = GLES32.glGetAttribLocation(shader.program, attrName) checkGlError("glGetAttribLocation $attrName") return attrLocation } @@ -162,24 +161,25 @@ internal class GLQuadRenderImpl( return } quadVertices.position(offset) - GLES30.glVertexAttribPointer( + GLES32.glVertexAttribPointer( attrLocation, size, - GLES30.GL_FLOAT, + GLES32.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, quadVertices ) checkGlError("glVertexAttribPointer $attrName") - GLES30.glEnableVertexAttribArray(attrLocation) + GLES32.glEnableVertexAttribArray(attrLocation) checkGlError("glEnableVertexAttribArray $attrName") } private fun checkGlError(op: String) { var error: Int - while (GLES30.glGetError().also { error = it } != GLES30.GL_NO_ERROR) { + while (GLES32.glGetError().also { error = it } != GLES32.GL_NO_ERROR) { LibLog.e(TAG, "$op: glError $error") - throw RuntimeException("$op: glError $error") + // don't throw an exception since it cannot be caught outside of ShaderView + //throw RuntimeException("$op: glError $error") } } } \ No newline at end of file diff --git a/lib/src/main/java/com/appspell/shaderview/gl/shader/GLShaderImpl.kt b/lib/src/main/java/com/appspell/shaderview/gl/shader/GLShaderImpl.kt index a1881a3..a899990 100644 --- a/lib/src/main/java/com/appspell/shaderview/gl/shader/GLShaderImpl.kt +++ b/lib/src/main/java/com/appspell/shaderview/gl/shader/GLShaderImpl.kt @@ -1,7 +1,7 @@ package com.appspell.shaderview.gl.shader import android.content.res.Resources -import android.opengl.GLES30 +import android.opengl.GLES32 import com.appspell.shaderview.gl.params.ShaderParams import com.appspell.shaderview.log.LibLog @@ -18,19 +18,19 @@ class GLShaderImpl constructor( if (program != UNKNOWN_PROGRAM) { release() } - val vertexShader = loadShader(GLES30.GL_VERTEX_SHADER, vertexSource) + val vertexShader = loadShader(GLES32.GL_VERTEX_SHADER, vertexSource) if (vertexShader == UNKNOWN_PROGRAM) { return false } - val pixelShader = loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentSource) + val pixelShader = loadShader(GLES32.GL_FRAGMENT_SHADER, fragmentSource) if (pixelShader == UNKNOWN_PROGRAM) { return false } - program = GLES30.glCreateProgram() + program = GLES32.glCreateProgram() if (program != UNKNOWN_PROGRAM) { - GLES30.glAttachShader(program, vertexShader) + GLES32.glAttachShader(program, vertexShader) checkGlError("glAttachShader: vertex") - GLES30.glAttachShader(program, pixelShader) + GLES32.glAttachShader(program, pixelShader) checkGlError("glAttachShader: pixel") return linkProgram() } @@ -41,13 +41,13 @@ class GLShaderImpl constructor( if (program == UNKNOWN_PROGRAM) { return false } - GLES30.glLinkProgram(program) + GLES32.glLinkProgram(program) val linkStatus = IntArray(1) - GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0) - if (linkStatus[0] != GLES30.GL_TRUE) { + GLES32.glGetProgramiv(program, GLES32.GL_LINK_STATUS, linkStatus, 0) + if (linkStatus[0] != GLES32.GL_TRUE) { LibLog.e(TAG, "Could not link program: ") - LibLog.e(TAG, GLES30.glGetProgramInfoLog(program)) - GLES30.glDeleteProgram(program) + LibLog.e(TAG, GLES32.glGetProgramInfoLog(program)) + GLES32.glDeleteProgram(program) program = UNKNOWN_PROGRAM return false } @@ -63,7 +63,7 @@ class GLShaderImpl constructor( override fun release() { if (program != UNKNOWN_PROGRAM) { - GLES30.glDeleteProgram(program) + GLES32.glDeleteProgram(program) program = UNKNOWN_PROGRAM } params.release() @@ -97,16 +97,16 @@ class GLShaderImpl constructor( } private fun loadShader(shaderType: Int, source: String): Int { - var shader = GLES30.glCreateShader(shaderType) + var shader = GLES32.glCreateShader(shaderType) if (shader != UNKNOWN_PROGRAM) { - GLES30.glShaderSource(shader, source) - GLES30.glCompileShader(shader) + GLES32.glShaderSource(shader, source) + GLES32.glCompileShader(shader) val compiled = IntArray(1) - GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compiled, 0) + GLES32.glGetShaderiv(shader, GLES32.GL_COMPILE_STATUS, compiled, 0) if (compiled[0] == UNKNOWN_PROGRAM) { LibLog.e(TAG, "Could not compile shader $shaderType:") - LibLog.e(TAG, GLES30.glGetShaderInfoLog(shader)) - GLES30.glDeleteShader(shader) + LibLog.e(TAG, GLES32.glGetShaderInfoLog(shader)) + GLES32.glDeleteShader(shader) shader = UNKNOWN_PROGRAM } } @@ -115,7 +115,7 @@ class GLShaderImpl constructor( private fun checkGlError(op: String) { var error: Int - while (GLES30.glGetError().also { error = it } != GLES30.GL_NO_ERROR) { + while (GLES32.glGetError().also { error = it } != GLES32.GL_NO_ERROR) { LibLog.e(TAG, "$op: glError $error") throw RuntimeException("$op: glError $error") } diff --git a/lib/src/main/java/com/appspell/shaderview/gl/shader/ShaderBuilder.kt b/lib/src/main/java/com/appspell/shaderview/gl/shader/ShaderBuilder.kt index 34bd487..287c7fd 100644 --- a/lib/src/main/java/com/appspell/shaderview/gl/shader/ShaderBuilder.kt +++ b/lib/src/main/java/com/appspell/shaderview/gl/shader/ShaderBuilder.kt @@ -43,6 +43,15 @@ class ShaderBuilder { } return this } + fun create( + vertexShader: String, + fragmentShader: String + ): ShaderBuilder { + if (!shader.createProgram(vertexShader, fragmentShader)) { + LibLog.e(TAG, "shader program wasn't created") + } + return this + } fun params(shaderParams: ShaderParams): ShaderBuilder { shader.params = shaderParams diff --git a/lib/src/main/java/com/appspell/shaderview/gl/view/GLTextureView.kt b/lib/src/main/java/com/appspell/shaderview/gl/view/GLTextureView.kt index b14f58d..13439c8 100644 --- a/lib/src/main/java/com/appspell/shaderview/gl/view/GLTextureView.kt +++ b/lib/src/main/java/com/appspell/shaderview/gl/view/GLTextureView.kt @@ -12,6 +12,7 @@ import androidx.annotation.CallSuper import com.appspell.shaderview.log.LibLog import java.io.Writer import java.lang.ref.WeakReference +import java.util.concurrent.TimeUnit import java.util.concurrent.locks.ReentrantLock import javax.microedition.khronos.egl.* import javax.microedition.khronos.opengles.GL @@ -421,6 +422,20 @@ open class GLTextureView @JvmOverloads constructor( return mGLThread!!.renderMode } + /** + * Set how often RENDERMODE_CONTINUOUSLY draws the shader + */ + fun setFPS(fps: Int) { + mGLThread!!.fps = fps + } + + /** + * Get the current framerate of RENDERMODE_CONTINUOUSLY + */ + fun getFPS(): Int { + return mGLThread!!.fps + } + /** * Request that the renderer render a frame. * This method is typically used when the render mode has been set to @@ -1465,6 +1480,7 @@ open class GLTextureView @JvmOverloads constructor( + " mRenderMode: " + mRenderMode) ) } + threadLockCondition.await() } } // end of synchronized(sGLThreadManager) @@ -1529,6 +1545,7 @@ open class GLTextureView @JvmOverloads constructor( if (enableLogRendererDrawFrame) { LibLog.w("GLThread", "onDrawFrame tid=$id") } + run { val view = mGLTextureViewWeakRef.get() if (view != null) { @@ -1537,6 +1554,7 @@ open class GLTextureView @JvmOverloads constructor( Trace.TRACE_TAG_VIEW, "onDrawFrame" ) + view.mRenderer?.onDrawFrame(gl) if (finishDrawingRunnable != null) { finishDrawingRunnable!!.run() @@ -1547,6 +1565,7 @@ open class GLTextureView @JvmOverloads constructor( } } } + val swapError = mEglHelper!!.swap() when (swapError) { EGL10.EGL_SUCCESS -> { @@ -1562,7 +1581,11 @@ open class GLTextureView @JvmOverloads constructor( // probably because the SurfaceView surface has been destroyed, // but we haven't been notified yet. // Log the error to help developers understand why rendering stopped. - LogHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError) + LogHelper.logEglErrorAsWarning( + "GLThread", + "eglSwapBuffers", + swapError + ) threadLock.withLock { mSurfaceIsBad = true threadLockCondition.signalAll() @@ -1573,6 +1596,11 @@ open class GLTextureView @JvmOverloads constructor( doRenderNotification = true wantRenderNotification = false } + + if (mFPS > 0) { + val millisPerFrame = (1000f / mFPS).toLong() + sleep(millisPerFrame); + } } } finally { /* @@ -1607,6 +1635,16 @@ open class GLTextureView @JvmOverloads constructor( } } + var fps: Int + get() { + threadLock.withLock { return mFPS } + } + set(fps) { + threadLock.withLock { + mFPS = fps + } + } + fun requestRender() { threadLock.withLock { mRequestRender = true @@ -1797,6 +1835,7 @@ open class GLTextureView @JvmOverloads constructor( private var mShouldReleaseEglContext = false private var mWidth = 0 private var mHeight = 0 + private var mFPS = 0 private var mRenderMode: Int private var mRequestRender = true private var mWantRenderNotification: Boolean diff --git a/local.properties b/local.properties deleted file mode 100644 index d235f30..0000000 --- a/local.properties +++ /dev/null @@ -1,8 +0,0 @@ -## This file must *NOT* be checked into Version Control Systems, -# as it contains information specific to your local configuration. -# -# Location of the SDK. This is only used by Gradle. -# For customization when using a Version Control System, please read the -# header note. -#Thu Dec 24 14:06:27 MSK 2020 -sdk.dir=/Users/alexey/Library/Android/sdk