Open GL ES ->GLSurfaceView+离屏渲染滤镜作用的Bitmap+动态顺序叠加滤镜作用链的RecyclerView

OpenGL ES离屏渲染滤镜及动态滤镜链应用

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">

    <!-- GLSurfaceView 用于显示滤镜效果 -->
    <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)
        // 初始化UI
        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

                    // 更新UI
                    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
)

RecyclerViewAdapterViewHolder

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 {
   
   
        // 设置 OpenGL ES 3.0 版本
        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?) {
   
   
        // 当 Surface 创建时调用, 进行 OpenGL ES 环境的初始化操作, 设置清屏颜色为青蓝色 (Red=0, Green=0.5, Blue=0.5, Alpha=1)
        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) {
   
   
        // 当 Surface 尺寸发生变化时调用,例如设备的屏幕方向发生改变, 设置视口为新的尺寸,视口是指渲染区域的大小
        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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值