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