From 5f85e2a5005de48f146ffb8e52012f555c1f8b3e Mon Sep 17 00:00:00 2001
From: xiaodi86 <1287548549@qq.com>
Date: Sat, 18 Feb 2023 14:17:14 +0800
Subject: [PATCH 01/10] Brightness table special effects try

---
 .../java/org/wysaid/cgeDemo/MainActivity.java |   3 +-
 library/src/main/jni/Android.mk               |   1 +
 .../jni/cge/filters/cgeAdvancedEffects.cpp    |   5 +
 .../main/jni/cge/filters/cgeAdvancedEffects.h |   2 +
 .../jni/cge/filters/cgeDataParsingEngine.cpp  |  18 ++++
 .../jni/cge/filters/cgeHistogramFilter.cpp    | 101 ++++++++++++++++++
 .../main/jni/cge/filters/cgeHistogramFilter.h |  41 +++++++
 7 files changed, 170 insertions(+), 1 deletion(-)
 create mode 100644 library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
 create mode 100644 library/src/main/jni/cge/filters/cgeHistogramFilter.h

diff --git a/cgeDemo/src/main/java/org/wysaid/cgeDemo/MainActivity.java b/cgeDemo/src/main/java/org/wysaid/cgeDemo/MainActivity.java
index 9ab17665..00d12207 100644
--- a/cgeDemo/src/main/java/org/wysaid/cgeDemo/MainActivity.java
+++ b/cgeDemo/src/main/java/org/wysaid/cgeDemo/MainActivity.java
@@ -31,8 +31,9 @@ public class MainActivity extends AppCompatActivity {
 
     public static final String EFFECT_CONFIGS[] = {
             "",
-            "@curve RGB(0,255)(255,0) @style cm mapping0.jpg 80 80 8 3", // ASCII art (字符画效果)
+            "@style hist 0.01 0.01 0.4 0.4 0.0 0.0 0.0 0.9",
             "@style waveform 0.01 0.01 0.4 0.4",
+            "@curve RGB(0,255)(255,0) @style cm mapping0.jpg 80 80 8 3", // ASCII art (字符画效果)
             "@beautify face 1 480 640", //Beautify
             "@adjust lut edgy_amber.png",
             "@adjust lut filmstock.png",
diff --git a/library/src/main/jni/Android.mk b/library/src/main/jni/Android.mk
index b8e8c6fb..6459ed47 100644
--- a/library/src/main/jni/Android.mk
+++ b/library/src/main/jni/Android.mk
@@ -75,6 +75,7 @@ LOCAL_SRC_FILES :=  \
 			$(CGE_SOURCE)/filters/cgeEmbossFilter.cpp \
 			\
 			$(CGE_SOURCE)/filters/cgeWaveformFilter.cpp \
+			$(CGE_SOURCE)/filters/cgeHistogramFilter.cpp \
 			\
 			$(CGE_SOURCE)/filters/cgeCrosshatchFilter.cpp \
 			$(CGE_SOURCE)/filters/cgeLiquifyFilter.cpp \
diff --git a/library/src/main/jni/cge/filters/cgeAdvancedEffects.cpp b/library/src/main/jni/cge/filters/cgeAdvancedEffects.cpp
index 8ba92182..bf161dc2 100644
--- a/library/src/main/jni/cge/filters/cgeAdvancedEffects.cpp
+++ b/library/src/main/jni/cge/filters/cgeAdvancedEffects.cpp
@@ -137,6 +137,11 @@ CGEBeautifyFilter* createBeautifyFilter()
     COMMON_FUNC(CGEBeautifyFilter);
 }
 
+CGEHistogramFilter* createHistogramFilter()
+{
+    COMMON_FUNC(CGEHistogramFilter);
+}
+
 CGEWaveformFilter* createWaveformFilter()
 {
     COMMON_FUNC(CGEWaveformFilter);
diff --git a/library/src/main/jni/cge/filters/cgeAdvancedEffects.h b/library/src/main/jni/cge/filters/cgeAdvancedEffects.h
index a5c756e4..aac44680 100644
--- a/library/src/main/jni/cge/filters/cgeAdvancedEffects.h
+++ b/library/src/main/jni/cge/filters/cgeAdvancedEffects.h
@@ -23,6 +23,7 @@
 #include "cgeRandomBlurFilter.h"
 #include "cgeSketchFilter.h"
 #include "cgeWaveformFilter.h"
+#include "cgeHistogramFilter.h"
 
 namespace CGE
 {
@@ -51,6 +52,7 @@ CGESketchFilter* createSketchFilter();
 CGEBeautifyFilter* createBeautifyFilter();
 
 CGEWaveformFilter* createWaveformFilter();
+CGEHistogramFilter* createHistogramFilter();
 } // namespace CGE
 
 #endif
diff --git a/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp b/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp
index 92fc3fb6..ea1be8f7 100644
--- a/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp
+++ b/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp
@@ -1093,6 +1093,24 @@ CGEImageFilterInterface* CGEDataParsingEngine::advancedStyleParser(const char* p
     {
         ADJUSTHELP_COMMON_FUNC2(pstr, CGECrosshatchFilter, setCrosshatchSpacing, setLineWidth);
     }
+    else if (strcmp(buffer, "hist") == 0)
+    {
+        float x, y, value1, value2, r, g, b, a = 1.0f;
+        if (sscanf(pstr, "%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f", &x, &y, &value1, &value2, &r, &g, &b, &a) < 7)
+        {
+            LOG_ERROR_PARAM(pstr);
+            return nullptr;
+        }
+
+        CGEHistogramFilter* filter = createHistogramFilter();
+        if (filter != nullptr)
+        {
+            proc = filter;
+            filter->setFormPosition(x, y);
+            filter->setFormSize(value1, value2);
+            filter->setColor(r, g, b, a);
+        }
+    }
     else if (strcmp(buffer, "waveform") == 0)
     {
         float x, y, width, height;
diff --git a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
new file mode 100644
index 00000000..00318ce1
--- /dev/null
+++ b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
@@ -0,0 +1,101 @@
+#include "cgeHistogramFilter.h"
+
+#include <EGL/egl.h>
+
+static CGEConstString s_vshHistogram = "#version 320 es\n" CGE_SHADER_STRING_PRECISION_H(
+layout(location = 0) in vec2 position;
+layout(location = 0) out vec2 textureCoordinate;
+void main() {
+	gl_Position = vec4(position, 0.0, 1.0);
+	textureCoordinate = (position.xy + 1.0) / 2.0;
+});
+
+static CGEConstString s_fshHistogram = "#version 320 es\n" CGE_SHADER_STRING(
+		precision highp float;
+precision highp int;
+// GLSL代码
+layout(location = 0) in vec2 textureCoordinate;
+layout(binding = 0) uniform sampler2D inputImageTexture;
+layout (binding = 1, rgba32f) uniform writeonly highp image2D histogram; // 直方图
+void main() {
+	vec4 color = texture(inputImageTexture, textureCoordinate);
+
+	int binIndex = int(clamp(color.r * 255.0f, 0.0f, 254.99999));
+
+	imageAtomicAdd(histogram, ivec2(binIndex), 1);
+});
+
+
+namespace CGE
+{
+	CGEHistogramFilter::~CGEHistogramFilter(){}
+
+	bool CGEHistogramFilter::init()
+	{
+		if (initShadersFromString(s_vshHistogram, s_fshHistogram))
+		{
+			m_program.bind();
+			setFormPosition(0.1f, 0.1f);
+			setFormSize(0.3f, 0.3f);
+			setColor(0.0f, 0.0f, 0.0f, 0.5f);
+			m_drawer.reset(TextureDrawer::create());
+			m_drawer->setFlipScale(1.0f, -1.0f); // flip upside down, meet the gl coord.
+			m_renderTarget = std::make_unique<FrameBufferWithTexture>();
+			return true;
+		}
+
+		return false;
+	}
+
+	void CGEHistogramFilter::render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID)
+	{
+		auto&& sz = handler->getOutputFBOSize();
+		if (sz.width != m_renderTarget->width() || m_renderTarget->texture() == 0)
+		{
+			m_renderTarget->bindTexture2D(256, sz.height);
+		}
+
+		m_renderTarget->bind();
+		glClearColor(0, 0, 0, 1);
+		glClear(GL_COLOR_BUFFER_BIT);
+
+		glFinish();
+
+		m_program.bind();
+		/// 渲染不写入, 使用 imageStore 写入.
+		glColorMask(false, false, false, false);
+
+		glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
+		glEnableVertexAttribArray(0);
+		glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
+		glActiveTexture(GL_TEXTURE0);
+		glBindTexture(GL_TEXTURE_2D, srcTexture);
+
+		glActiveTexture(GL_TEXTURE1);
+		glBindTexture(GL_TEXTURE_2D, 0);
+		glBindImageTexture(1, m_renderTarget->texture(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
+
+		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+		glColorMask(true, true, true, true);
+		glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
+
+		handler->setAsTarget();
+		glViewport(m_position[0] * sz.width, m_position[1] * sz.height, m_size[0] * sz.width, m_size[1] * sz.height);
+		m_drawer->drawTexture(m_renderTarget->texture());
+	}
+
+	void CGEHistogramFilter::setFormPosition(float left, float top)
+	{
+		m_position = { left, top };
+	}
+
+	void CGEHistogramFilter::setFormSize(float width, float height)
+	{
+		m_size = { width, height };
+	}
+
+	void CGEHistogramFilter::setColor(float r, float g, float b, float a)
+	{
+		m_color = { r, g, b, a };
+	}
+} // namespace CGE
\ No newline at end of file
diff --git a/library/src/main/jni/cge/filters/cgeHistogramFilter.h b/library/src/main/jni/cge/filters/cgeHistogramFilter.h
new file mode 100644
index 00000000..1e238fe9
--- /dev/null
+++ b/library/src/main/jni/cge/filters/cgeHistogramFilter.h
@@ -0,0 +1,41 @@
+#ifndef _HISTOGRAMFILTER_H_
+#define _HISTOGRAMFILTER_H_
+
+#include "cgeImageFilter.h"
+#include "cgeTextureUtils.h"
+#include "cgeVec.h"
+namespace CGE
+{
+	class CGEHistogramFilter : public CGEImageFilterInterface
+	{
+	public:
+		~CGEHistogramFilter() override;
+
+		/**
+         * @brief 左上角的点
+         */
+		void setFormPosition(float left, float top);
+		/**
+         * @brief 相对大小
+         */
+		void setFormSize(float width, float height);
+
+		/**
+         * @brief 背景色
+         */
+		void setColor(float r, float g, float b, float a);
+
+		bool init() override;
+
+		void render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID) override;
+
+	protected:
+		std::unique_ptr<TextureDrawer> m_drawer;
+		std::unique_ptr<FrameBufferWithTexture> m_renderTarget;
+		Vec2f m_position;
+		Vec2f m_size;
+		Vec4f m_color;
+	};
+} // namespace CGE
+
+#endif
\ No newline at end of file

From 8f12da3e87070176c2a8699f644a55d7b0df6bfe Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Wed, 1 Mar 2023 08:53:28 +0800
Subject: [PATCH 02/10] Fix Histogram render2Texture
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

修正获取纹理像素,直方图数据传入图像数据方式
---
 .../jni/cge/filters/cgeHistogramFilter.cpp    | 210 ++++++++++--------
 1 file changed, 119 insertions(+), 91 deletions(-)

diff --git a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
index 00318ce1..bb27bca0 100644
--- a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
+++ b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
@@ -1,101 +1,129 @@
+
 #include "cgeHistogramFilter.h"
 
 #include <EGL/egl.h>
+#include <array>
+#include <GLES3/gl3.h>
 
 static CGEConstString s_vshHistogram = "#version 320 es\n" CGE_SHADER_STRING_PRECISION_H(
-layout(location = 0) in vec2 position;
-layout(location = 0) out vec2 textureCoordinate;
-void main() {
-	gl_Position = vec4(position, 0.0, 1.0);
-	textureCoordinate = (position.xy + 1.0) / 2.0;
-});
+    layout(location = 0) in vec2 position;
+    layout(location = 0) out vec2 textureCoordinate;
+    void main() {
+        gl_Position = vec4(position, 0.0, 1.0);
+        textureCoordinate = (position.xy + 1.0) / 2.0;
+    });
 
 static CGEConstString s_fshHistogram = "#version 320 es\n" CGE_SHADER_STRING(
-		precision highp float;
-precision highp int;
-// GLSL代码
-layout(location = 0) in vec2 textureCoordinate;
-layout(binding = 0) uniform sampler2D inputImageTexture;
-layout (binding = 1, rgba32f) uniform writeonly highp image2D histogram; // 直方图
-void main() {
-	vec4 color = texture(inputImageTexture, textureCoordinate);
-
-	int binIndex = int(clamp(color.r * 255.0f, 0.0f, 254.99999));
-
-	imageAtomicAdd(histogram, ivec2(binIndex), 1);
-});
-
+    precision highp float;
+    precision highp int;
+    layout(location = 0) in vec2 textureCoordinate;
+    layout(binding = 0) uniform sampler2D inputImageTexture;
+    layout(rgba8, binding = 1) writeonly uniform highp uimage2D outputImage;
+    layout(location = 0) out vec4 fragColor;
+
+    void main() {
+        vec4 color = texture(inputImageTexture, textureCoordinate);
+        float lum = dot(color.rgb, vec3(0.299, 0.587, 0.114));
+        int newLoc = int(lum * 255.0);
+        if (newLoc >= 0 && newLoc < 256) {
+            imageAtomicAdd(outputImage, ivec2(newLoc, 0), 1);
+        }
+        fragColor = vec4(1.0);
+    });
 
 namespace CGE
 {
-	CGEHistogramFilter::~CGEHistogramFilter(){}
-
-	bool CGEHistogramFilter::init()
-	{
-		if (initShadersFromString(s_vshHistogram, s_fshHistogram))
-		{
-			m_program.bind();
-			setFormPosition(0.1f, 0.1f);
-			setFormSize(0.3f, 0.3f);
-			setColor(0.0f, 0.0f, 0.0f, 0.5f);
-			m_drawer.reset(TextureDrawer::create());
-			m_drawer->setFlipScale(1.0f, -1.0f); // flip upside down, meet the gl coord.
-			m_renderTarget = std::make_unique<FrameBufferWithTexture>();
-			return true;
-		}
-
-		return false;
-	}
-
-	void CGEHistogramFilter::render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID)
-	{
-		auto&& sz = handler->getOutputFBOSize();
-		if (sz.width != m_renderTarget->width() || m_renderTarget->texture() == 0)
-		{
-			m_renderTarget->bindTexture2D(256, sz.height);
-		}
-
-		m_renderTarget->bind();
-		glClearColor(0, 0, 0, 1);
-		glClear(GL_COLOR_BUFFER_BIT);
-
-		glFinish();
-
-		m_program.bind();
-		/// 渲染不写入, 使用 imageStore 写入.
-		glColorMask(false, false, false, false);
-
-		glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
-		glEnableVertexAttribArray(0);
-		glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
-		glActiveTexture(GL_TEXTURE0);
-		glBindTexture(GL_TEXTURE_2D, srcTexture);
-
-		glActiveTexture(GL_TEXTURE1);
-		glBindTexture(GL_TEXTURE_2D, 0);
-		glBindImageTexture(1, m_renderTarget->texture(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
-
-		glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-		glColorMask(true, true, true, true);
-		glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
-
-		handler->setAsTarget();
-		glViewport(m_position[0] * sz.width, m_position[1] * sz.height, m_size[0] * sz.width, m_size[1] * sz.height);
-		m_drawer->drawTexture(m_renderTarget->texture());
-	}
-
-	void CGEHistogramFilter::setFormPosition(float left, float top)
-	{
-		m_position = { left, top };
-	}
-
-	void CGEHistogramFilter::setFormSize(float width, float height)
-	{
-		m_size = { width, height };
-	}
-
-	void CGEHistogramFilter::setColor(float r, float g, float b, float a)
-	{
-		m_color = { r, g, b, a };
-	}
-} // namespace CGE
\ No newline at end of file
+    CGEHistogramFilter::~CGEHistogramFilter(){}
+
+    bool CGEHistogramFilter::init()
+    {
+        if (initShadersFromString(s_vshHistogram, s_fshHistogram))
+        {
+            m_program.bind();
+            setFormPosition(0.1f, 0.1f);
+            setFormSize(0.3f, 0.3f);
+            setColor(0.0f, 0.0f, 0.0f, 0.5f);
+            m_drawer.reset(TextureDraw::create());
+            m_drawer->setFlipScale(1.0f, -1.0f);
+            m_renderTarget = std::make_unique<FrameBufferWithTexture>();
+            return true;
+        }
+
+        return false;
+    }
+
+    void CGEHistogramFilter::render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID)
+    {
+        auto&& sz = handler->getOutputFBOSize();
+        if (sz.width != m_renderTarget->width() || m_renderTarget->texture() == 0)
+        {
+            m_renderTarget->bindTexture2D(sz.width, 256);
+        }
+
+        m_renderTarget->bind();
+        glClearColor(0, 0, 0, 1);
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        glFinish();
+
+        m_program.bind();
+        glColorMask(false, false, false, false);
+
+        glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
+        glEnableVertexAttribArray(0);
+        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, srcTexture);
+
+        glUniform1i(m_program.uniformLocation("inputImageTexture"), 0);
+
+        // 获取纹理尺寸,用于计算像素位置
+        const auto texSize = handler->getOutputFBOSize();
+        // 清空直方图数组
+        std::array<float, 256> histogram{};
+        // 遍历纹理像素,计算亮度直方图
+        std::vector<unsigned char> pixels(texSize.width * texSize.height * 4);
+        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+        for (int i = 0; i < pixels.size(); i += 4) {
+            const auto r = pixels[i];
+            const auto g = pixels[i + 1];
+            const auto b = pixels[i + 2];
+            const auto lum = 0.299f * r + 0.587f * g + 0.114f * b;
+            histogram[static_cast<int>(lum * 255)]++;
+        }
+
+        // 将直方图数据传入图像数据,写入 GLSL Image 中
+        auto data = m_renderTarget->mapBuffer();
+        for (int i = 0; i < histogram.size(); i++) {
+            const auto height = static_cast<int>(histogram[i] * 256);
+            for (int j = 0; j < height; j++) {
+                const auto offset = i + j * 256;
+                data[offset] = 255;
+            }
+        }
+        m_renderTarget->unmapBuffer();
+
+        // 绘制直方图
+        const auto position = m_position * Vec2f(sz.width, sz.height);
+        const auto size = m_size * Vec2f(sz.width, sz.height);
+        m_drawer->setTexture(m_renderTarget->texture(), 256, 256);
+        m_drawer->setColor(m_color);
+        m_drawer->setDrawRect(position[0], position[1], size[0], size[1]);
+        m_drawer->draw();
+
+    }
+    void CGEHistogramFilter::setFormPosition(float left, float top)
+    {
+        m_position = {left, top};
+    }
+
+    void CGEHistogramFilter::setFormSize(float width, float height)
+    {
+        m_size = {width, height};
+    }
+
+    void CGEHistogramFilter::setColor(float r, float g, float b, float a)
+    {
+        m_color = {r, g, b, a};
+    }
+}

From 1e9b233b084a2703a73e4fc0ff039720902a3fa3 Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Wed, 1 Mar 2023 08:58:56 +0800
Subject: [PATCH 03/10] Fix FrameBufferWithTexture
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

在FrameBufferWithTexture类中如何定义mapBuffer()和unmapBuffer()
---
 .../main/jni/cge/common/cgeGLFunctions.cpp    | 74 ++++++++++++++++++-
 1 file changed, 72 insertions(+), 2 deletions(-)

diff --git a/library/src/main/jni/cge/common/cgeGLFunctions.cpp b/library/src/main/jni/cge/common/cgeGLFunctions.cpp
index fd4a53fa..cbec232f 100644
--- a/library/src/main/jni/cge/common/cgeGLFunctions.cpp
+++ b/library/src/main/jni/cge/common/cgeGLFunctions.cpp
@@ -1,4 +1,4 @@
-/*
+/*
  * cgeGLFunctions.cpp
  *
  *  Created on: 2013-12-5
@@ -6,7 +6,7 @@
  */
 
 #include "cgeGLFunctions.h"
-
+#include <EGL/egl.h>
 #include <cmath>
 
 CGE_LOG_CODE(
@@ -390,4 +390,74 @@ bool FrameBufferWithTexture::checkStatus()
     return ret == GL_FRAMEBUFFER_COMPLETE;
 }
 
+//////////////
+
+    FrameBufferTexture::FrameBufferTexture() : m_fbo(0), m_texture(0), m_width(0), m_height(0)
+    {
+        glGenFramebuffers(1, &m_fbo);
+        assert(m_fbo != 0);
+    }
+
+    FrameBufferTexture::~FrameBufferTexture()
+    {
+        glDeleteFramebuffers(1, &m_fbo);
+        glDeleteTextures(1, &m_texture);
+    }
+
+    GLuint FrameBufferTexture::texture() const
+    {
+        return m_texture;
+    }
+
+    GLsizei FrameBufferTexture::width() const
+    {
+        return m_width;
+    }
+
+    GLsizei FrameBufferTexture::height() const
+    {
+        return m_height;
+    }
+
+    void FrameBufferTexture::bindTexture2D(GLsizei width, GLsizei height)
+    {
+        if (m_texture == 0)
+        {
+            glGenTextures(1, &m_texture);
+            assert(m_texture != 0);
+        }
+
+        glBindTexture(GL_TEXTURE_2D, m_texture);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, width, height, 0, GL_RED, GL_FLOAT, nullptr);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        glBindTexture(GL_TEXTURE_2D, 0);
+
+        m_width = width;
+        m_height = height;
+    }
+
+    void FrameBufferTexture::bind()
+    {
+        glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
+    }
+
+    unsigned char* FrameBufferTexture::mapBuffer()
+    {
+        glBindTexture(GL_TEXTURE_2D, m_texture);
+        glPixelStorei(GL_PACK_ALIGNMENT, 1);
+        const auto bufferSize = m_width * m_height * sizeof(float);
+        auto buffer = new unsigned char[bufferSize];
+        glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
+        return buffer;
+    }
+
+    void FrameBufferTexture::unmapBuffer()
+    {
+        glBindTexture(GL_TEXTURE_2D, 0);
+    }
+
 } // namespace CGE

From 6bdf355726b3678edc7ab60cfc2b0f6b241c82c8 Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Wed, 1 Mar 2023 09:01:24 +0800
Subject: [PATCH 04/10] Fix FrameBufferWithTexture support Histogram
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

在FrameBufferWithTexture类中如何定义mapBuffer()和unmapBuffer()
---
 .../src/main/jni/cge/common/cgeGLFunctions.h  | 26 +++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/library/src/main/jni/cge/common/cgeGLFunctions.h b/library/src/main/jni/cge/common/cgeGLFunctions.h
index f317cdcd..d1596248 100644
--- a/library/src/main/jni/cge/common/cgeGLFunctions.h
+++ b/library/src/main/jni/cge/common/cgeGLFunctions.h
@@ -1,4 +1,4 @@
-/*
+/*
  * cgeGLFunctions.h
  *
  *  Created on: 2013-12-5
@@ -103,13 +103,14 @@ class FrameBuffer
         bindTexture2D(texID, attachment);
         glViewport(x, y, w, h);
     }
-
     inline GLuint fbo() { return m_framebuffer; }
 
+
 protected:
     GLuint m_framebuffer;
 };
 
+
 struct CGESizei
 {
     CGESizei() :
@@ -210,6 +211,27 @@ class FrameBufferWithTexture : protected FrameBuffer, public TextureObject
     GLuint m_renderBuffer = 0;
 };
 
+class FrameBufferTexture
+    {
+    public:
+    FrameBufferTexture();
+        ~FrameBufferTexture();
+
+        GLuint texture() const;
+        GLsizei width() const;
+        GLsizei height() const;
+        void bindTexture2D(GLsizei width, GLsizei height);
+        void bind();
+        unsigned char* mapBuffer();
+        void unmapBuffer();
+
+    private:
+        GLuint m_fbo;
+        GLuint m_texture;
+        GLsizei m_width;
+        GLsizei m_height;
+};
+
 struct CGELuminance
 {
     enum

From 615498bee018ac331ae3fa0c1d01e673fd6cce2b Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Wed, 1 Mar 2023 09:48:33 +0800
Subject: [PATCH 05/10] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E8=8E=B7=E5=8F=96?=
 =?UTF-8?q?=E5=83=8F=E7=B4=A0=E6=95=B0=E6=8D=AE=E6=96=B9=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

delete glGetTexImage
---
 .../jni/cge/filters/cgeHistogramFilter.cpp    | 99 +++++++++----------
 1 file changed, 47 insertions(+), 52 deletions(-)

diff --git a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
index bb27bca0..1833731c 100644
--- a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
+++ b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
@@ -3,63 +3,58 @@
 
 #include <EGL/egl.h>
 #include <array>
-#include <GLES3/gl3.h>
 
 static CGEConstString s_vshHistogram = "#version 320 es\n" CGE_SHADER_STRING_PRECISION_H(
-    layout(location = 0) in vec2 position;
-    layout(location = 0) out vec2 textureCoordinate;
-    void main() {
-        gl_Position = vec4(position, 0.0, 1.0);
-        textureCoordinate = (position.xy + 1.0) / 2.0;
-    });
+        layout(location = 0) in vec2 position;
+        layout(location = 0) out vec2 textureCoordinate;
+        void main() {
+            gl_Position = vec4(position, 0.0, 1.0);
+            textureCoordinate = (position.xy + 1.0) / 2.0;
+        });
 
 static CGEConstString s_fshHistogram = "#version 320 es\n" CGE_SHADER_STRING(
-    precision highp float;
-    precision highp int;
-    layout(location = 0) in vec2 textureCoordinate;
-    layout(binding = 0) uniform sampler2D inputImageTexture;
-    layout(rgba8, binding = 1) writeonly uniform highp uimage2D outputImage;
-    layout(location = 0) out vec4 fragColor;
-
-    void main() {
-        vec4 color = texture(inputImageTexture, textureCoordinate);
-        float lum = dot(color.rgb, vec3(0.299, 0.587, 0.114));
-        int newLoc = int(lum * 255.0);
-        if (newLoc >= 0 && newLoc < 256) {
-            imageAtomicAdd(outputImage, ivec2(newLoc, 0), 1);
-        }
-        fragColor = vec4(1.0);
-    });
+        precision highp float;
+        precision highp int;
+        layout(location = 0) in vec2 textureCoordinate;
+        layout(rgba8ui, binding = 0) uniform readonly highp uimage2D inputImageTexture;
+        layout(rgba8ui, binding = 1) uniform writeonly highp uimage2D outputImage;
+        layout(location = 0) out vec4 fragColor;
+
+        void main() {
+            fragColor = vec4(1.0);
+
+            vec4 color = texture(inputImageTexture, textureCoordinate);
+            float lum = dot(color.rgb, vec3(0.299, 0.587, 0.114));
+            int newLoc = int(lum * 255.0);
+            if (newLoc >= 0 && newLoc < 256) {
+                ivec2 location = ivec2(newLoc, 0);
+                atomicAdd(imageAtomic(outputImage, location), 1);
+            }
+        });
 
-namespace CGE
-{
-    CGEHistogramFilter::~CGEHistogramFilter(){}
+namespace CGE {
 
-    bool CGEHistogramFilter::init()
-    {
-        if (initShadersFromString(s_vshHistogram, s_fshHistogram))
-        {
+    CGEHistogramFilter::~CGEHistogramFilter() {}
+
+    bool CGEHistogramFilter::init() {
+        if (initShadersFromString(s_vshHistogram, s_fshHistogram)) {
             m_program.bind();
             setFormPosition(0.1f, 0.1f);
             setFormSize(0.3f, 0.3f);
-            setColor(0.0f, 0.0f, 0.0f, 0.5f);
-            m_drawer.reset(TextureDraw::create());
+            m_drawer.reset(TextureDrawer::create());
             m_drawer->setFlipScale(1.0f, -1.0f);
-            m_renderTarget = std::make_unique<FrameBufferWithTexture>();
+            m_renderTarget = std::make_unique<FrameBufferTexture>();
             return true;
         }
 
         return false;
     }
 
-    void CGEHistogramFilter::render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID)
-    {
+    void CGEHistogramFilter::render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID) {
         auto&& sz = handler->getOutputFBOSize();
-        if (sz.width != m_renderTarget->width() || m_renderTarget->texture() == 0)
-        {
+        if (sz.width != m_renderTarget->width() || m_renderTarget->texture() == 0) {
             m_renderTarget->bindTexture2D(sz.width, 256);
         }
-
         m_renderTarget->bind();
         glClearColor(0, 0, 0, 1);
         glClear(GL_COLOR_BUFFER_BIT);
@@ -83,7 +78,8 @@ namespace CGE
         std::array<float, 256> histogram{};
         // 遍历纹理像素,计算亮度直方图
         std::vector<unsigned char> pixels(texSize.width * texSize.height * 4);
-        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+        glReadPixels(0, 0, texSize.width, texSize.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
+//        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
         for (int i = 0; i < pixels.size(); i += 4) {
             const auto r = pixels[i];
             const auto g = pixels[i + 1];
@@ -97,21 +93,25 @@ namespace CGE
         for (int i = 0; i < histogram.size(); i++) {
             const auto height = static_cast<int>(histogram[i] * 256);
             for (int j = 0; j < height; j++) {
-                const auto offset = i + j * 256;
-                data[offset] = 255;
+                const auto pixel = reinterpret_cast<unsigned char*>(data) + j * m_renderTarget->width() * 4 + i * 4;
+                pixel[0] = 255;
+                pixel[1] = 255;
+                pixel[2] = 255;
+                pixel[3] = 255;
             }
         }
         m_renderTarget->unmapBuffer();
 
+        glViewport(m_position[0] * sz.width, m_position[1] * sz.height, m_size[0] * sz.width, m_size[1] * sz.height);
         // 绘制直方图
-        const auto position = m_position * Vec2f(sz.width, sz.height);
-        const auto size = m_size * Vec2f(sz.width, sz.height);
-        m_drawer->setTexture(m_renderTarget->texture(), 256, 256);
-        m_drawer->setColor(m_color);
-        m_drawer->setDrawRect(position[0], position[1], size[0], size[1]);
-        m_drawer->draw();
+        m_drawer->drawTexture(m_renderTarget->texture());
 
+        glColorMask(true, true, true, true);
+
+        glDisableVertexAttribArray(0);
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
     }
+
     void CGEHistogramFilter::setFormPosition(float left, float top)
     {
         m_position = {left, top};
@@ -121,9 +121,4 @@ namespace CGE
     {
         m_size = {width, height};
     }
-
-    void CGEHistogramFilter::setColor(float r, float g, float b, float a)
-    {
-        m_color = {r, g, b, a};
-    }
 }

From 5c0cf5a02b5ec48a3b9681de283bfc99862809d2 Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Wed, 1 Mar 2023 09:50:32 +0800
Subject: [PATCH 06/10] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=83=8C=E6=99=AF?=
 =?UTF-8?q?=E8=AE=BE=E8=AE=BE=E7=BD=AEsetColor?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

删除背景设设置setColor
---
 .../main/jni/cge/filters/cgeHistogramFilter.h | 46 +++++++------------
 1 file changed, 17 insertions(+), 29 deletions(-)

diff --git a/library/src/main/jni/cge/filters/cgeHistogramFilter.h b/library/src/main/jni/cge/filters/cgeHistogramFilter.h
index 1e238fe9..3b032b2a 100644
--- a/library/src/main/jni/cge/filters/cgeHistogramFilter.h
+++ b/library/src/main/jni/cge/filters/cgeHistogramFilter.h
@@ -4,38 +4,26 @@
 #include "cgeImageFilter.h"
 #include "cgeTextureUtils.h"
 #include "cgeVec.h"
-namespace CGE
-{
-	class CGEHistogramFilter : public CGEImageFilterInterface
-	{
-	public:
-		~CGEHistogramFilter() override;
 
-		/**
-         * @brief 左上角的点
-         */
-		void setFormPosition(float left, float top);
-		/**
-         * @brief 相对大小
-         */
-		void setFormSize(float width, float height);
+namespace CGE{
+class CGEHistogramFilter : public CGEImageFilterInterface
+    {
+    public:
+        ~CGEHistogramFilter() override;
 
-		/**
-         * @brief 背景色
-         */
-		void setColor(float r, float g, float b, float a);
+        void setFormPosition(float left, float top);
 
-		bool init() override;
+        void setFormSize(float width, float height);
 
-		void render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID) override;
+        bool init() override;
 
-	protected:
-		std::unique_ptr<TextureDrawer> m_drawer;
-		std::unique_ptr<FrameBufferWithTexture> m_renderTarget;
-		Vec2f m_position;
-		Vec2f m_size;
-		Vec4f m_color;
-	};
-} // namespace CGE
+        void render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID) override;
 
-#endif
\ No newline at end of file
+    protected:
+        std::unique_ptr<TextureDrawer> m_drawer;
+        std::unique_ptr<FrameBufferTexture> m_renderTarget;
+        Vec2f m_position;
+        Vec2f m_size;
+    };
+}
+#endif

From 15b06e821cd95f7f89cf1a14b66471d1119ea579 Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Wed, 1 Mar 2023 09:54:13 +0800
Subject: [PATCH 07/10] =?UTF-8?q?=E4=BF=AE=E6=94=B9Histogram=20=E5=8F=82?=
 =?UTF-8?q?=E6=95=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

修改Histogram 参数
---
 .../jni/cge/filters/cgeDataParsingEngine.cpp  | 29 +++++++++----------
 1 file changed, 14 insertions(+), 15 deletions(-)

diff --git a/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp b/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp
index ea1be8f7..3bcfd6e8 100644
--- a/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp
+++ b/library/src/main/jni/cge/filters/cgeDataParsingEngine.cpp
@@ -1093,24 +1093,23 @@ CGEImageFilterInterface* CGEDataParsingEngine::advancedStyleParser(const char* p
     {
         ADJUSTHELP_COMMON_FUNC2(pstr, CGECrosshatchFilter, setCrosshatchSpacing, setLineWidth);
     }
-    else if (strcmp(buffer, "hist") == 0)
-    {
-        float x, y, value1, value2, r, g, b, a = 1.0f;
-        if (sscanf(pstr, "%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f%*c%f", &x, &y, &value1, &value2, &r, &g, &b, &a) < 7)
+        else if (strcmp(buffer, "hist") == 0)
         {
-            LOG_ERROR_PARAM(pstr);
-            return nullptr;
-        }
+            float x, y, width, height;
+            if (sscanf(pstr, "%f%*c%f%*c%f%*c%f", &x, &y, &width, &height) < 4)
+            {
+                LOG_ERROR_PARAM(pstr);
+                return nullptr;
+            }
 
-        CGEHistogramFilter* filter = createHistogramFilter();
-        if (filter != nullptr)
-        {
-            proc = filter;
-            filter->setFormPosition(x, y);
-            filter->setFormSize(value1, value2);
-            filter->setColor(r, g, b, a);
+            CGEHistogramFilter* filter = createHistogramFilter();
+            if (filter != nullptr)
+            {
+                proc = filter;
+                filter->setFormPosition(x, y);
+                filter->setFormSize(width, height);
+            }
         }
-    }
     else if (strcmp(buffer, "waveform") == 0)
     {
         float x, y, width, height;

From 00539c96ae87b1566af27c54454d0dff5996da86 Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Thu, 2 Mar 2023 17:29:08 +0800
Subject: [PATCH 08/10] Fix erro

Fix error: use of undeclared identifier 'glGetTexImage'
---
 library/src/main/jni/cge/common/cgeGLFunctions.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/library/src/main/jni/cge/common/cgeGLFunctions.cpp b/library/src/main/jni/cge/common/cgeGLFunctions.cpp
index cbec232f..ff20ff20 100644
--- a/library/src/main/jni/cge/common/cgeGLFunctions.cpp
+++ b/library/src/main/jni/cge/common/cgeGLFunctions.cpp
@@ -451,7 +451,8 @@ bool FrameBufferWithTexture::checkStatus()
         glPixelStorei(GL_PACK_ALIGNMENT, 1);
         const auto bufferSize = m_width * m_height * sizeof(float);
         auto buffer = new unsigned char[bufferSize];
-        glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
+        glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+//        glGetTexImage(GL_TEXTURE_2D, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
         return buffer;
     }
 

From 9006143de4da8c7de5a57c618a8277ae58f97428 Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Thu, 2 Mar 2023 18:24:39 +0800
Subject: [PATCH 09/10] try fix 'imageAtomic'

try fix No matching function for call to 'imageAtomic'
---
 library/src/main/jni/cge/filters/cgeHistogramFilter.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
index 1833731c..7b5882cb 100644
--- a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
+++ b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
@@ -27,8 +27,10 @@ static CGEConstString s_fshHistogram = "#version 320 es\n" CGE_SHADER_STRING(
             float lum = dot(color.rgb, vec3(0.299, 0.587, 0.114));
             int newLoc = int(lum * 255.0);
             if (newLoc >= 0 && newLoc < 256) {
+                //vec2 location = vec2(newLoc, 0.0);
                 ivec2 location = ivec2(newLoc, 0);
                 atomicAdd(imageAtomic(outputImage, location), 1);
+                //imageAtomic(outputImage, ivec2(location.x, location.y), uvec4(1, 0, 0, 0));
             }
         });
 

From 5b720861c323069ab0e6c17105cd87cf28ee4a96 Mon Sep 17 00:00:00 2001
From: xiaodi86 <51728141+xiaodi86@users.noreply.github.com>
Date: Fri, 3 Mar 2023 08:40:41 +0800
Subject: [PATCH 10/10] Update cgeHistogramFilter.cpp

---
 library/src/main/jni/cge/filters/cgeHistogramFilter.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
index 7b5882cb..7e50c6ff 100644
--- a/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
+++ b/library/src/main/jni/cge/filters/cgeHistogramFilter.cpp
@@ -55,7 +55,7 @@ namespace CGE {
     void CGEHistogramFilter::render2Texture(CGEImageHandlerInterface* handler, GLuint srcTexture, GLuint vertexBufferID) {
         auto&& sz = handler->getOutputFBOSize();
         if (sz.width != m_renderTarget->width() || m_renderTarget->texture() == 0) {
-            m_renderTarget->bindTexture2D(sz.width, 256);
+            m_renderTarget->bindTexture2D(sz.width, sz.height);
         }
         m_renderTarget->bind();
         glClearColor(0, 0, 0, 1);