Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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)

Expand All @@ -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


Expand All @@ -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))
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -74,17 +74,17 @@ class ShaderListAdapter : RecyclerView.Adapter<ShaderListAdapter.BaseShaderView>
.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()
}
Expand All @@ -102,7 +102,7 @@ class ShaderListAdapter : RecyclerView.Adapter<ShaderListAdapter.BaseShaderView>
.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))
Expand All @@ -128,7 +128,7 @@ class ShaderListAdapter : RecyclerView.Adapter<ShaderListAdapter.BaseShaderView>
.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))
Expand Down Expand Up @@ -199,7 +199,7 @@ class ShaderListAdapter : RecyclerView.Adapter<ShaderListAdapter.BaseShaderView>
.addTexture2D(
"uTexture",
R.drawable.android,
GLES30.GL_TEXTURE0
GLES32.GL_TEXTURE0
)
.addVec2f("uOffset")
.build()
Expand All @@ -223,7 +223,7 @@ class ShaderListAdapter : RecyclerView.Adapter<ShaderListAdapter.BaseShaderView>
.addTexture2D(
"uTexture",
R.drawable.test_texture,
GLES30.GL_TEXTURE0
GLES32.GL_TEXTURE0
)
.addVec2f("uScale", floatArrayOf(0f, 0f))
.addInt("uBlurSize", 3)
Expand Down
2 changes: 1 addition & 1 deletion lib/publish.gradle
Original file line number Diff line number Diff line change
@@ -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
Expand Down
70 changes: 55 additions & 15 deletions lib/src/main/java/com/appspell/shaderview/ShaderView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
31 changes: 15 additions & 16 deletions lib/src/main/java/com/appspell/shaderview/ext/Texture.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]
}

Expand All @@ -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]
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
Loading