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">
<com.example.myapplication.FilterSurfaceView
android:id="@+id/glSurfaceView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/filterRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:layout_weight="1" />
<TextView
android:id="@+id/intensityTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="强度: 100%"
android:textSize="20sp" />
<SeekBar
android:id="@+id/intensitySeekBar"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:layout_weight="1"
android:max="100"
android:progress="100" />
</LinearLayout>
Activity
代码
class MainActivity4 : AppCompatActivity() {
private lateinit var glSurfaceView: FilterSurfaceView
private lateinit var intensityTextView: TextView
private lateinit var intensitySeekBar: SeekBar
private lateinit var filterRecyclerView: RecyclerView
private var mCurrentFilterType = FilterType.ORIGINAL
private val filters = listOf(
FilterItem(FilterType.ORIGINAL, "原图"),
FilterItem(FilterType.COLOR, "颜色变换"),
FilterItem(FilterType.PIXEL, "像素化"),
FilterItem(FilterType.EDGE, "边缘检测")
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main4)
initView()
initFilterSeekBar()
}
private fun initView() {
glSurfaceView = findViewById(R.id.glSurfaceView)
intensityTextView = findViewById(R.id.intensityTextView)
intensitySeekBar = findViewById(R.id.intensitySeekBar)
filterRecyclerView = findViewById(R.id.filterRecyclerView)
intensityTextView.visibility = View.GONE
intensitySeekBar.visibility = View.GONE
}
private fun initFilterSeekBar() {
intensitySeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
val drawData = glSurfaceView?.getDrawData() ?: return
drawData.currentFilterStrength = progress.toFloat()
intensityTextView.text = " ${mCurrentFilterType} -> 强度: $progress%"
glSurfaceView?.requestRender()
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
}
fun initFilterRecyclerView() {
filters?.forEach { filter ->
when (filter.type) {
FilterType.ORIGINAL -> {
filter.thumbnailBitmap = glSurfaceView?.getDrawData()?.mOriginBitmap
}
FilterType.EDGE -> {
filter.thumbnailBitmap = glSurfaceView?.getDrawData()?.mEdgeFilterBitmap
}
FilterType.PIXEL -> {
filter.thumbnailBitmap = glSurfaceView?.getDrawData()?.mPixelFilterBitmap
}
FilterType.COLOR -> {
filter.thumbnailBitmap = glSurfaceView?.getDrawData()?.mColorFilterBitmap
}
}
}
filterRecyclerView.apply {
adapter = FilterAdapter(filters, object : FilterItemClickListener {
override fun onFilterItemClick(filterItem: FilterItem) {
val drawData = glSurfaceView?.getDrawData() ?: return
val currentFilterType = drawData.currentFilterType
drawData.filterConfigs[currentFilterType]?.strength = drawData.currentFilterStrength
mCurrentFilterType = filterItem.type
drawData.currentFilterType = mCurrentFilterType
val savedStrength = drawData.filterConfigs[mCurrentFilterType]?.strength ?: 100f
drawData.currentFilterStrength = savedStrength
if (mCurrentFilterType != FilterType.ORIGINAL) {
intensityTextView.visibility = View.VISIBLE
intensitySeekBar.visibility = View.VISIBLE
val strengthInt = savedStrength.toInt()
intensitySeekBar.progress = strengthInt
intensityTextView.text = "${filterItem.type} -> 强度: $strengthInt%"
} else {
intensityTextView.visibility = View.GONE
intensitySeekBar.visibility = View.GONE
}
glSurfaceView?.requestRender()
}
})
layoutManager = LinearLayoutManager(this@MainActivity4, LinearLayoutManager.HORIZONTAL, false)
}
}
override fun onResume() {
super.onResume()
glSurfaceView.onResume()
}
override fun onPause() {
super.onPause()
glSurfaceView.onPause()
}
}
滤镜数据类
enum class FilterType {
ORIGINAL, EDGE, PIXEL, COLOR
}
data class FilterItem(
val type: FilterType,
val name: String,
var thumbnailBitmap: Bitmap? = null
)
RecyclerView
的Adapter
和ViewHolder
interface FilterItemClickListener {
fun onFilterItemClick(filterItem: FilterItem)
}
class FilterAdapter(private val filters: List<FilterItem>, private val itemClickListener: FilterItemClickListener) : RecyclerView.Adapter<FilterAdapter.FilterViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilterViewHolder {
return FilterViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.filter_item, parent, false)
)
}
override fun onBindViewHolder(holder: FilterViewHolder, position: Int) {
val filterItem = filters[position]
holder.bind(filterItem)
holder.itemView.setOnClickListener {
itemClickListener.onFilterItemClick(filterItem)
}
}
override fun getItemCount(): Int = filters.size
class FilterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val ivThumbnail: ImageView = itemView.findViewById(R.id.ivThumbnail)
private val tvFilterName: TextView = itemView.findViewById(R.id.tvFilterName)
fun bind(item: FilterItem) {
item.thumbnailBitmap?.let {
ivThumbnail.setImageBitmap(it)
}
tvFilterName.text = item.name
}
}
}
GLSurfaceView
代码
class FilterSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {
private var mRenderer = FilterRenderer(context)
init {
setEGLContextClientVersion(3)
setRenderer(mRenderer)
renderMode = RENDERMODE_WHEN_DIRTY
}
fun getDrawData(): FilterDrawData? {
return mRenderer?.getDrawData()
}
}
GLSurfaceView.Renderer
代码
class FilterRenderer(private val mContext: Context) : GLSurfaceView.Renderer {
private var mDrawData: FilterDrawData? = null
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
GLES30.glClearColor(0.0f, 0.5f, 0.5f, 1.0f)
mDrawData = FilterDrawData().apply {
initTexture0(mContext, R.drawable.picture)
initShader()
initVertexBuffer()
initEdgeFilterShader()
initPixelFilterShader()
initColorFilterShader()
initOriginFrameBuffer()
initColorFilterBuffer()
initEdgeFilterBuffer()
initPixelFilterBuffer()
initTempFrameBuffer()
initOutputFrameBuffer()
}
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES30.glViewport(0, 0, width, height)
mDrawData?.computeMVPMatrix(width, height)
}
override fun onDrawFrame(gl: GL10?) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
mDrawData?.drawFilter()
takeIf { mDrawData?.filterBitmapIsNull() == true }?.apply {
mDrawData?.drawOriginBitmap()
mDrawData?.drawPixelFilterBitmap()
mDrawData?.drawColorFilterBitmap()
mDrawData?.drawEdgeFilterBitmap()
Handler(Looper.getMainLooper()).post {
(mContext as MainActivity4)?.initFilterRecyclerView()
}
}
}
fun getDrawData(): FilterDrawData? {
return mDrawData
}
}
GLSurfaceView.Renderer
需要的绘制数据
class FilterDrawData {
private var NO_OFFSET = 0
private val VERTEX_POS_DATA_SIZE = 3
private val TEXTURE_POS_DATA_SIZE = 2
private var mProgram: Int = -1
private var mEdgeProgram: Int = -1
private var mPixelProgram: Int = -1
private var mColorProgram: Int = -1
private var mOriginFBO = IntArray(1)
private var mColorFBO = IntArray(1)
private var mEdgeFBO = IntArray(1)
private var mPixelFBO = IntArray(1)
private var mOutputFBO = IntArray(1)
private val mTempFBO = IntArray(1)
private var mOriginTextureID = IntArray(1)
private var mColorTextureID = IntArray(1)
private var mEdgeTextureID = IntArray(1)
private var mPixelTextureID = IntArray(1)
private var mOutputTextureID = IntArray(1)
private val mTempTextureID = IntArray(1)
private var mVAO = IntArray(1)
private var mVBO = IntArray(2)
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 var mViewPortRatio = 1f
private var mFrameBufferWidth = 0
private var mFrameBufferHeight = 0
private val mFrameBufferMVPMatrix = FloatArray(16)
private var mSurfaceWidth = 0
private var mSurfaceHeight = 0
val vertex = floatArrayOf(
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
)
val vertexBuffer = ByteBuffer.allocateDirect(vertex.size * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(vertex)
.position(NO_OFFSET)
val textureCoords = floatArrayOf(
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f,
)
val textureBuffer = ByteBuffer.allocateDirect(textureCoords.size * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer()
.put(textureCoords)
.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)
var mOriginBitmap: Bitmap? = null
var mEdgeFilterBitmap: Bitmap? = null
var mPixelFilterBitmap: Bitmap? = null
var mColorFilterBitmap: Bitmap? = null
data class FilterConfig(
val type: FilterType,
var strength: Float = 100f,
var isActive: Boolean = false,
var lastAppliedStrength: Float = 100f
)
val filterConfigs = mutableMapOf<FilterType, FilterConfig>().apply {
put(FilterType.ORIGINAL, FilterConfig(FilterType.ORIGINAL))
put(FilterType.EDGE, FilterConfig(FilterType.EDGE))
put(FilterType.PIXEL, FilterConfig(FilterType.PIXEL))
put(FilterType.COLOR, FilterConfig(FilterType.COLOR))
}
private val activeFilters = mutableListOf<FilterType>()
var currentFilterType = FilterType.ORIGINAL
var currentFilterStrength: Float
get() = filterConfigs[currentFilterType]?.strength ?: 0f
set(value) {
filterConfigs[currentFilterType]?.strength = value
}
fun initShader() {
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.glUseProgram(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,
vertex.size * 4,
vertexBuffer,
GLES30.GL_STATIC_DRAW
)
val positionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")
GLES30.glEnableVertexAttribArray(positionHandle)
GLES30.glVertexAttribPointer(
positionHandle,
VERTEX_POS_DATA_SIZE,
GLES30.GL_FLOAT,
false,
0,
NO_OFFSET
)
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVBO[1])
GLES30.glBufferData(
GLES30.GL_ARRAY_BUFFER,
textureCoords.size * 4,
textureBuffer,
GLES30.GL_STATIC_DRAW
)
val textureHandle = GLES30.glGetAttribLocation(mProgram, "aTexCoord")
GLES30.glEnableVertexAttribArray(textureHandle)
GLES30.glVertexAttribPointer(
textureHandle,
TEXTURE_POS_DATA_SIZE,
GLES30.GL_FLOAT,
false,
0,
NO_OFFSET
)
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)
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_ELEMENT_ARRAY_BUFFER, 0)
}
fun initOriginFrameBuffer() {
GLES30.glGenFramebuffers(mOriginFBO.size, mOriginFBO, NO_OFFSET)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mOriginFBO[0])
GLES30.glGenTextures(mOriginTextureID.size, mOriginTextureID, NO_OFFSET)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mOriginTextureID[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
)
GLES30.glTexImage2D(
GLES30.GL_TEXTURE_2D,
NO_OFFSET,
GLES30.GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30.GL_RGBA,
GLES30.GL_UNSIGNED_BYTE,
null
)
GLES30.glFramebufferTexture2D(
GLES30.GL_FRAMEBUFFER,
GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D,
mOriginTextureID[0],
0
)
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
Log.e("yang", "init FrameBuffer failed")
}
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
}
fun initTempFrameBuffer() {
GLES30.glGenFramebuffers(mTempFBO.size, mTempFBO, NO_OFFSET)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mTempFBO[0])
GLES30.glGenTextures(mTempTextureID.size, mTempTextureID, NO_OFFSET)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTempTextureID[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
)
GLES30.glTexImage2D(
GLES30.GL_TEXTURE_2D,
0,
GLES30.GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
0,
GLES30.GL_RGBA,
GLES30.GL_UNSIGNED_BYTE,
null
)
GLES30.glFramebufferTexture2D(
GLES30.GL_FRAMEBUFFER,
GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D,
mTempTextureID[0],
0
)
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
Log.e("yang", "init FrameBuffer failed")
}
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
}
fun drawOriginBitmap() {
val state = saveGLState()
try {
GLES30.glViewport(0, 0, mFrameBufferWidth, mFrameBufferHeight)
enableTexture0(mProgram, mTextureID[0])
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mOriginFBO[0])
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
computeFrameBufferMVPMatrix()
drawSomething(mProgram, mFrameBufferMVPMatrix)
mOriginBitmap = savePixelBufferBitmap()
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
disableTexture0()
} finally {
restoreGLState(state)
}
}
fun drawEdgeFilterBitmap() {
takeIf { mEdgeFilterBitmap == null }?.let {
val state = saveGLState()
try {
GLES30.glUseProgram(mEdgeProgram)
GLES30.glViewport(0, 0, mFrameBufferWidth, mFrameBufferHeight)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mEdgeFBO[0])
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
enableTexture0(mEdgeProgram, mOriginTextureID[0])
val textureSizeHandle = GLES30.glGetUniformLocation(mEdgeProgram, "uTextureSize")
if (textureSizeHandle != -1) {
GLES30.glUniform2f(
textureSizeHandle,
mFrameBufferWidth.toFloat(),
mFrameBufferHeight.toFloat()
)
}
val intensityLocation = GLES30.glGetUniformLocation(mEdgeProgram, "uIntensity")
if (intensityLocation != -1) {
GLES30.glUniform1f(intensityLocation, 1f)
}
drawSomething(mEdgeProgram, mFrameBufferMVPMatrix)
mEdgeFilterBitmap = savePixelBufferBitmap()
disableTexture0()
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
} finally {
restoreGLState(state)
}
}
}
fun drawPixelFilterBitmap() {
takeIf { mPixelFilterBitmap == null }?.let {
val state = saveGLState()
try {
GLES30.glUseProgram(mPixelProgram)
GLES30.glViewport(0, 0, mFrameBufferWidth, mFrameBufferHeight)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mPixelFBO[0])
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
enableTexture0(mPixelProgram, mOriginTextureID[0])
val textureSizeHandle = GLES30.glGetUniformLocation(mPixelProgram, "uTextureSize")
if (textureSizeHandle != -1) {
GLES30.glUniform2f(
textureSizeHandle,
mFrameBufferWidth.toFloat(),
mFrameBufferWidth.toFloat()
)
}
val pixelSizeHandle = GLES30.glGetUniformLocation(mPixelProgram, "uPixelSize")
if (pixelSizeHandle != -1) {
GLES30.glUniform1f(pixelSizeHandle, 15.0f)
}
val intensityLocation = GLES30.glGetUniformLocation(mPixelProgram, "uIntensity")
if (intensityLocation != -1) {
GLES30.glUniform1f(intensityLocation, 1f)
}
drawSomething(mPixelProgram, mFrameBufferMVPMatrix)
mPixelFilterBitmap = savePixelBufferBitmap()
disableTexture0()
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
} finally {
restoreGLState(state)
}
}
}
fun drawColorFilterBitmap() {
takeIf { mColorFilterBitmap == null }?.let {
val state = saveGLState()
try {
GLES30.glUseProgram(mColorProgram)
GLES30.glViewport(0, 0, mFrameBufferWidth, mFrameBufferHeight)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mColorFBO[0])
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
enableTexture0(mColorProgram, mOriginTextureID[0])
val timeHandle = GLES30.glGetUniformLocation(mColorProgram, "uTime")
if (timeHandle != -1) {
GLES30.glUniform1f(timeHandle, (System.currentTimeMillis() % 10000) / 10000.0f)
}
val twistIntensityHandle =
GLES30.glGetUniformLocation(mColorProgram, "uTwistIntensity")
if (twistIntensityHandle != -1) {
GLES30.glUniform1f(twistIntensityHandle, 0.15f)
}
val intensityLocation = GLES30.glGetUniformLocation(mColorProgram, "uIntensity")
if (intensityLocation != -1) {
GLES30.glUniform1f(intensityLocation, 1f)
}
drawSomething(mColorProgram, mFrameBufferMVPMatrix)
mColorFilterBitmap = savePixelBufferBitmap()
disableTexture0()
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
} finally {
restoreGLState(state)
}
}
}
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.glDrawElements(
GLES30.GL_TRIANGLES,
index.size,
GLES30.GL_UNSIGNED_SHORT,
NO_OFFSET
)
GLES30.glBindVertexArray(0)
}
fun initEdgeFilterShader() {
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;
uniform vec2 uTextureSize;
uniform float uIntensity;
in vec2 vTexCoord;
out vec4 fragColor;
void main() {
vec4 originalColor = texture(uTexture_0, vTexCoord);
float dx = 1.0 / uTextureSize.x;
float dy = 1.0 / uTextureSize.y;
vec4 left = texture(uTexture_0, vTexCoord - vec2(dx, 0.0));
vec4 right = texture(uTexture_0, vTexCoord + vec2(dx, 0.0));
vec4 top = texture(uTexture_0, vTexCoord - vec2(0.0, dy));
vec4 bottom = texture(uTexture_0, vTexCoord + vec2(0.0, dy));
vec4 horizontal = abs(right - left);
vec4 vertical = abs(bottom - top);
float edge = (horizontal.r + horizontal.g + horizontal.b +
vertical.r + vertical.g + vertical.b) / 6.0;
vec4 edgeColor = vec4(vec3(1.0 - edge * 3.0), 1.0);
fragColor = mix(originalColor, edgeColor, uIntensity);
}
""".trimIndent()
val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader =
LoadShaderUtil.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)
mEdgeProgram = GLES30.glCreateProgram()
GLES30.glAttachShader(mEdgeProgram, vertexShader)
GLES30.glAttachShader(mEdgeProgram, fragmentShader)
GLES30.glLinkProgram(mEdgeProgram)
GLES30.glDeleteShader(vertexShader)
GLES30.glDeleteShader(fragmentShader)
}
fun initPixelFilterShader() {
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;
uniform vec2 uTextureSize;
uniform float uIntensity;
in vec2 vTexCoord;
out vec4 fragColor;
void main() {
vec4 originalColor = texture(uTexture_0, vTexCoord);
float pixelSize = 2.0 + 23.0 * uIntensity;
float dx = pixelSize / uTextureSize.x;
float dy = pixelSize / uTextureSize.y;
vec2 pixelatedCoord;
pixelatedCoord.x = dx * floor(vTexCoord.x / dx) + dx * 0.5;
pixelatedCoord.y = dy * floor(vTexCoord.y / dy) + dy * 0.5;
vec4 pixelColor = texture(uTexture_0, pixelatedCoord);
float colorLevels = mix(16.0, 5.0, uIntensity);
pixelColor = floor(pixelColor * colorLevels) / colorLevels;
vec2 pixelPos = fract(vTexCoord / vec2(dx, dy));
float borderThreshold = mix(0.95, 0.80, uIntensity);
float borderFactor = step(borderThreshold, max(pixelPos.x, pixelPos.y));
float borderDarkness = mix(0.95, 0.7, uIntensity);
pixelColor.rgb *= mix(1.0, borderDarkness, borderFactor);
fragColor = mix(originalColor, pixelColor, uIntensity);
}""".trimIndent()
val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader =
LoadShaderUtil.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)
mPixelProgram = GLES30.glCreateProgram()
GLES30.glAttachShader(mPixelProgram, vertexShader)
GLES30.glAttachShader(mPixelProgram, fragmentShader)
GLES30.glLinkProgram(mPixelProgram)
GLES30.glDeleteShader(vertexShader)
GLES30.glDeleteShader(fragmentShader)
}
fun initColorFilterShader() {
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;
uniform float uIntensity;
in vec2 vTexCoord;
out vec4 fragColor;
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
vec4 originalColor = texture(uTexture_0, vTexCoord);
vec2 center = vec2(0.5, 0.5);
vec2 texCoordFromCenter = vTexCoord - center;
float distance = length(texCoordFromCenter);
float angle = atan(texCoordFromCenter.y, texCoordFromCenter.x);
float twistFactor = 0.25 * uIntensity;
angle += twistFactor * (1.0 - distance);
vec2 newCoord;
newCoord.x = center.x + distance * cos(angle);
newCoord.y = center.y + distance * sin(angle);
vec4 distortedColor = texture(uTexture_0, newCoord);
vec3 hsv = rgb2hsv(distortedColor.rgb);
hsv.y = hsv.y * (1.0 + 0.3 * uIntensity);
hsv.z = mix(hsv.z, hsv.z * 0.95 + 0.05, uIntensity);
hsv.x = hsv.x + distance * 0.4 * uIntensity;
vec4 colorizedColor = vec4(hsv2rgb(hsv), distortedColor.a);
fragColor = mix(originalColor, colorizedColor, uIntensity);
}
""".trimIndent()
val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader =
LoadShaderUtil.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)
mColorProgram = GLES30.glCreateProgram()
GLES30.glAttachShader(mColorProgram, vertexShader)
GLES30.glAttachShader(mColorProgram, fragmentShader)
GLES30.glLinkProgram(mColorProgram)
GLES30.glDeleteShader(vertexShader)
GLES30.glDeleteShader(fragmentShader)
}
fun initColorFilterBuffer() {
GLES30.glGenFramebuffers(mColorFBO.size, mColorFBO, NO_OFFSET)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mColorFBO[0])
GLES30.glGenTextures(mColorTextureID.size, mColorTextureID, NO_OFFSET)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorTextureID[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
)
GLES30.glTexImage2D(
GLES30.GL_TEXTURE_2D,
NO_OFFSET,
GLES30.GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30.GL_RGBA,
GLES30.GL_UNSIGNED_BYTE,
null
)
GLES30.glFramebufferTexture2D(
GLES30.GL_FRAMEBUFFER,
GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D,
mColorTextureID[0],
0
)
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
Log.e("yang", "init FrameBuffer failed")
}
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
}
fun initEdgeFilterBuffer() {
GLES30.glGenFramebuffers(mEdgeFBO.size, mEdgeFBO, NO_OFFSET)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mEdgeFBO[0])
GLES30.glGenTextures(mEdgeTextureID.size, mEdgeTextureID, NO_OFFSET)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mEdgeTextureID[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
)
GLES30.glTexImage2D(
GLES30.GL_TEXTURE_2D,
NO_OFFSET,
GLES30.GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30.GL_RGBA,
GLES30.GL_UNSIGNED_BYTE,
null
)
GLES30.glFramebufferTexture2D(
GLES30.GL_FRAMEBUFFER,
GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D,
mEdgeTextureID[0],
0
)
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
Log.e("yang", "init FrameBuffer failed")
}
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
}
fun initPixelFilterBuffer() {
GLES30.glGenFramebuffers(mPixelFBO.size, mPixelFBO, NO_OFFSET)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mPixelFBO[0])
GLES30.glGenTextures(mPixelTextureID.size, mPixelTextureID, NO_OFFSET)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mPixelTextureID[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
)
GLES30.glTexImage2D(
GLES30.GL_TEXTURE_2D,
NO_OFFSET,
GLES30.GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30.GL_RGBA,
GLES30.GL_UNSIGNED_BYTE,
null
)
GLES30.glFramebufferTexture2D(
GLES30.GL_FRAMEBUFFER,
GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D,
mPixelTextureID[0],
0
)
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
Log.e("yang", "init FrameBuffer failed")
}
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
}
fun initOutputFrameBuffer() {
GLES30.glGenFramebuffers(mOutputFBO.size, mOutputFBO, NO_OFFSET)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mOutputFBO[0])
GLES30.glGenTextures(mOutputTextureID.size, mOutputTextureID, NO_OFFSET)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mOutputTextureID[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
)
GLES30.glTexImage2D(
GLES30.GL_TEXTURE_2D,
NO_OFFSET,
GLES30.GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30.GL_RGBA,
GLES30.GL_UNSIGNED_BYTE,
null
)
GLES30.glFramebufferTexture2D(
GLES30.GL_FRAMEBUFFER,
GLES30.GL_COLOR_ATTACHMENT0,
GLES30.GL_TEXTURE_2D,
mOutputTextureID[0],
0
)
if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
Log.e("yang", "init FrameBuffer failed")
}
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
}
fun savePixelBufferBitmap(): Bitmap? {
val pixelBuffer =
ByteBuffer.allocateDirect(mFrameBufferWidth * mFrameBufferHeight * 4)
.order(ByteOrder.LITTLE_ENDIAN)
GLES30.glReadPixels(
0, 0, mFrameBufferWidth, mFrameBufferHeight,
GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE,
pixelBuffer
)
val bitmap = Bitmap.createBitmap(
mFrameBufferWidth,
mFrameBufferHeight,
Bitmap.Config.ARGB_8888
)
pixelBuffer.rewind()
bitmap.copyPixelsFromBuffer(pixelBuffer)
return bitmap
}
fun computeMVPMatrix(width: Int, height: Int) {
mSurfaceWidth = width
mSurfaceHeight = height
Matrix.setIdentityM(mProjectionMatrix, NO_OFFSET)
Matrix.setIdentityM(mViewMatrix, NO_OFFSET)
Matrix.setIdentityM(mMVPMatrix, NO_OFFSET)
takeIf { width > height }?.let {
mViewPortRatio = (width * 1f) / height
Matrix.orthoM(
mProjectionMatrix,
NO_OFFSET,
-mViewPortRatio,
mViewPortRatio,
-1f,
1f,
-1f,
1f
)
} ?: run {
mViewPortRatio = (height * 1f) / width
Matrix.orthoM(
mProjectionMatrix,
NO_OFFSET,
-1f,
1f,
-mViewPortRatio,
mViewPortRatio,
-1f,
1f
)
}
Matrix.setLookAtM(
mViewMatrix,
NO_OFFSET,
0f,
0f,
1f,
0f,
0f,
0f,
0f,
1f,
0f
)
Matrix.multiplyMM(
mMVPMatrix,
NO_OFFSET,
mProjectionMatrix,
NO_OFFSET,
mViewMatrix,
NO_OFFSET
)
Matrix.scaleM(
mMVPMatrix,
NO_OFFSET,
1f,
-1f,
1f,
)
}
fun computeFrameBufferMVPMatrix() {
Matrix.setIdentityM(mProjectionMatrix, NO_OFFSET)
Matrix.setIdentityM(mViewMatrix, NO_OFFSET)
Matrix.setIdentityM(mFrameBufferMVPMatrix, NO_OFFSET)
takeIf { mFrameBufferWidth > mFrameBufferHeight }?.let {
mViewPortRatio = (mFrameBufferWidth * 1f) / mFrameBufferHeight
Matrix.orthoM(
mProjectionMatrix,
NO_OFFSET,
-mViewPortRatio,
mViewPortRatio,
-1f,
1f,
0f,
1f
)
} ?: run {
mViewPortRatio = (mFrameBufferHeight * 1f) / mFrameBufferWidth
Matrix.orthoM(
mProjectionMatrix,
NO_OFFSET,
-1f,
1f,
-mViewPortRatio,
mViewPortRatio,
0f,
1f
)
}
Matrix.setLookAtM(
mViewMatrix,
NO_OFFSET,
0f,
0f,
1f,
0f,
0f,
0f,
0f,
1f,
0f
)
Matrix.multiplyMM(
mFrameBufferMVPMatrix,
NO_OFFSET,
mProjectionMatrix,
NO_OFFSET,
mViewMatrix,
NO_OFFSET
)
}
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)
mFrameBufferWidth = max(mFrameBufferWidth, bitmap.width)
mFrameBufferHeight = max(mFrameBufferHeight, bitmap.height)
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 filterBitmapIsNull(): Boolean {
return mOriginBitmap == null && mEdgeFilterBitmap == null && mPixelFilterBitmap == null && mColorFilterBitmap == null
}
fun drawFilter() {
when (currentFilterType) {
FilterType.ORIGINAL -> {
activeFilters.clear()
drawCurrentOutput(mTextureID[0])
}
else -> {
val config = filterConfigs.getOrPut(currentFilterType) {
FilterConfig(currentFilterType)
}
if (config.strength < 1f) {
activeFilters.remove(currentFilterType)
renderFilterChain()
return
}
if (!activeFilters.contains(currentFilterType)) {
activeFilters.add(currentFilterType)
}
renderFilterChain()
}
}
}
private fun renderFilterChain() {
if (activeFilters.isEmpty()) {
drawCurrentOutput(mOriginTextureID[0])
return
}
var sourceFBO = 0
var sourceTexture = mOriginTextureID[0]
activeFilters.forEachIndexed { index, filterType ->
val isLastFilter = index == activeFilters.size - 1
val targetFBO = if (isLastFilter) mOutputFBO[0] else mTempFBO[0]
val targetTexture = if (isLastFilter) mOutputTextureID[0] else mTempTextureID[0]
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, targetFBO)
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
val config = filterConfigs[filterType] ?: return
val program = getFilterProgram(filterType)
drawFilter(program, sourceTexture, config)
sourceTexture = targetTexture
sourceFBO = targetFBO
}
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
drawCurrentOutput(mOutputTextureID[0])
}
private fun drawCurrentOutput(id: Int) {
val state = saveGLState()
try {
GLES30.glUseProgram(mProgram)
enableTexture0(mProgram, id)
drawSomething(mProgram, mMVPMatrix)
disableTexture0()
} finally {
restoreGLState(state)
}
}
private fun getFilterProgram(filterType: FilterType): Int {
return when (filterType) {
FilterType.EDGE -> mEdgeProgram
FilterType.PIXEL -> mPixelProgram
FilterType.COLOR -> mColorProgram
FilterType.ORIGINAL -> mProgram
}
}
private fun drawFilter(program: Int, inputTexture: Int, config: FilterConfig) {
val state = saveGLState()
try {
GLES30.glUseProgram(program)
GLES30.glViewport(0, 0, mFrameBufferWidth, mFrameBufferHeight)
enableTexture0(program, inputTexture)
val intensityLocation = GLES30.glGetUniformLocation(program, "uIntensity")
if (intensityLocation != -1) {
GLES30.glUniform1f(intensityLocation, config.strength / 100f)
}
drawSomething(program, mFrameBufferMVPMatrix)
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)
}
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
}
}
}
效果图
