├── .clang-format
├── .gitignore
├── CMakeLists.txt
├── Image
└── 1.jpg
├── README.md
├── include
├── OS-ImGui.h
├── OS-ImGui_Base.h
├── OS-ImGui_Exception.hpp
├── OS-ImGui_Struct.h
├── imgui
│ ├── font.h
│ ├── imconfig.h
│ ├── imgui.h
│ ├── imgui_impl_android.h
│ ├── imgui_impl_opengl3.h
│ ├── imgui_internal.h
│ ├── imstb_rectpack.h
│ ├── imstb_textedit.h
│ ├── imstb_truetype.h
│ └── stb_image.h
└── utils
│ ├── NativeSurfaceUtils.h
│ └── touch.h
├── outputs
└── arm64-v8a
│ └── OSImGui
└── src
├── OSImGui
├── OS-ImGui.cpp
└── OS-ImGui_Base.cpp
├── imgui
├── imgui.cpp
├── imgui_draw.cpp
├── imgui_impl_android.cpp
├── imgui_impl_opengl3.cpp
├── imgui_tables.cpp
├── imgui_widgets.cpp
└── stb_image.cpp
├── main_demo.cpp
└── utils
└── touch.cpp
/.clang-format:
--------------------------------------------------------------------------------
1 | # 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto
2 | # BasedOnStyle: LLVM
3 |
4 | Language: Cpp
5 |
6 | # 访问说明符(public、private等)的偏移
7 | AccessModifierOffset: -4
8 |
9 | # 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
10 | AlignAfterOpenBracket: Align
11 |
12 | # 连续赋值时,对齐所有等号
13 | AlignConsecutiveAssignments: false
14 |
15 | # 连续声明时,对齐所有声明的变量名
16 | AlignConsecutiveDeclarations: false
17 |
18 | # 右对齐逃脱换行(使用反斜杠换行)的反斜杠
19 | AlignEscapedNewlines: Right
20 |
21 | # 水平对齐二元和三元表达式的操作数
22 | AlignOperands: true
23 |
24 | # 对齐连续的尾随的注释
25 | AlignTrailingComments: true
26 |
27 | # 不允许函数声明的所有参数在放在下一行
28 | AllowAllParametersOfDeclarationOnNextLine: false
29 |
30 | # 不允许短的块放在同一行
31 | AllowShortBlocksOnASingleLine: true
32 |
33 | # 允许短的case标签放在同一行
34 | AllowShortCaseLabelsOnASingleLine: true
35 |
36 | # 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All
37 | AllowShortFunctionsOnASingleLine: None
38 |
39 | # 允许短的if语句保持在同一行
40 | AllowShortIfStatementsOnASingleLine: true
41 |
42 | # 允许短的循环保持在同一行
43 | AllowShortLoopsOnASingleLine: true
44 |
45 | # 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数),
46 | # AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义)
47 | AlwaysBreakAfterReturnType: None
48 |
49 | # 总是在多行string字面量前换行
50 | AlwaysBreakBeforeMultilineStrings: false
51 |
52 | # 总是在template声明后换行
53 | AlwaysBreakTemplateDeclarations: true
54 |
55 | # false表示函数实参要么都在同一行,要么都各自一行
56 | BinPackArguments: true
57 |
58 | # false表示所有形参要么都在同一行,要么都各自一行
59 | BinPackParameters: true
60 |
61 | # 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效
62 | BraceWrapping:
63 | # class定义后面
64 | AfterClass: false
65 | # 控制语句后面
66 | AfterControlStatement: false
67 | # enum定义后面
68 | AfterEnum: false
69 | # 函数定义后面
70 | AfterFunction: false
71 | # 命名空间定义后面
72 | AfterNamespace: false
73 | # struct定义后面
74 | AfterStruct: false
75 | # union定义后面
76 | AfterUnion: false
77 | # extern之后
78 | AfterExternBlock: false
79 | # catch之前
80 | BeforeCatch: false
81 | # else之前
82 | BeforeElse: false
83 | # 缩进大括号
84 | IndentBraces: false
85 | # 分离空函数
86 | SplitEmptyFunction: false
87 | # 分离空语句
88 | SplitEmptyRecord: false
89 | # 分离空命名空间
90 | SplitEmptyNamespace: false
91 |
92 | # 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行)
93 | BreakBeforeBinaryOperators: NonAssignment
94 |
95 | # 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似),
96 | # Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似),
97 | # Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom
98 | # 注:这里认为语句块也属于函数
99 | BreakBeforeBraces: Custom
100 |
101 | # 在三元运算符前换行
102 | BreakBeforeTernaryOperators: false
103 |
104 | # 在构造函数的初始化列表的冒号后换行
105 | BreakConstructorInitializers: AfterColon
106 |
107 | #BreakInheritanceList: AfterColon
108 |
109 | BreakStringLiterals: false
110 |
111 | # 每行字符的限制,0表示没有限制
112 | ColumnLimit: 0
113 |
114 | CompactNamespaces: true
115 |
116 | # 构造函数的初始化列表要么都在同一行,要么都各自一行
117 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
118 |
119 | # 构造函数的初始化列表的缩进宽度
120 | ConstructorInitializerIndentWidth: 4
121 |
122 | # 延续的行的缩进宽度
123 | ContinuationIndentWidth: 4
124 |
125 | # 去除C++11的列表初始化的大括号{后和}前的空格
126 | Cpp11BracedListStyle: true
127 |
128 | # 继承最常用的指针和引用的对齐方式
129 | DerivePointerAlignment: false
130 |
131 | # 固定命名空间注释
132 | FixNamespaceComments: true
133 |
134 | # 缩进case标签
135 | IndentCaseLabels: false
136 |
137 | IndentPPDirectives: None
138 |
139 | # 缩进宽度
140 | IndentWidth: 4
141 |
142 | # 函数返回类型换行时,缩进函数声明或函数定义的函数名
143 | IndentWrappedFunctionNames: false
144 |
145 | # 保留在块开始处的空行
146 | KeepEmptyLinesAtTheStartOfBlocks: false
147 |
148 | # 连续空行的最大数量
149 | MaxEmptyLinesToKeep: 1
150 |
151 | # 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All
152 | NamespaceIndentation: None
153 |
154 | # 指针和引用的对齐: Left, Right, Middle
155 | PointerAlignment: Right
156 |
157 | # 允许重新排版注释
158 | ReflowComments: true
159 |
160 | # 允许排序#include
161 | SortIncludes: false
162 |
163 | # 允许排序 using 声明
164 | SortUsingDeclarations: false
165 |
166 | # 在C风格类型转换后添加空格
167 | SpaceAfterCStyleCast: false
168 |
169 | # 在Template 关键字后面添加空格
170 | SpaceAfterTemplateKeyword: true
171 |
172 | # 在赋值运算符之前添加空格
173 | SpaceBeforeAssignmentOperators: true
174 |
175 | # SpaceBeforeCpp11BracedList: true
176 |
177 | # SpaceBeforeCtorInitializerColon: true
178 |
179 | # SpaceBeforeInheritanceColon: true
180 |
181 | # 开圆括号之前添加一个空格: Never, ControlStatements, Always
182 | SpaceBeforeParens: ControlStatements
183 |
184 | # SpaceBeforeRangeBasedForLoopColon: true
185 |
186 | # 在空的圆括号中添加空格
187 | SpaceInEmptyParentheses: false
188 |
189 | # 在尾随的评论前添加的空格数(只适用于//)
190 | SpacesBeforeTrailingComments: 1
191 |
192 | # 在尖括号的<后和>前添加空格
193 | SpacesInAngles: false
194 |
195 | # 在C风格类型转换的括号中添加空格
196 | SpacesInCStyleCastParentheses: false
197 |
198 | # 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格
199 | SpacesInContainerLiterals: true
200 |
201 | # 在圆括号的(后和)前添加空格
202 | SpacesInParentheses: false
203 |
204 | # 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响
205 | SpacesInSquareBrackets: false
206 |
207 | # 标准: Cpp03, Cpp11, Auto
208 | Standard: Cpp11
209 |
210 | # tab宽度
211 | TabWidth: 4
212 |
213 | # 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always
214 | UseTab: Never
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | build/
3 | output/
4 | .cache/
5 | .vscode/
6 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.21)
2 |
3 | set(NDK_PATH /Users/jiangnight/Library/Android/sdk/ndk/r27_goron)
4 | set(CMAKE_SYSTEM_NAME ANDROID)
5 | set(CMAKE_BUILD_TYPE Release)
6 | set(CMAKE_SYSTEM_VERSION 21)
7 | set(ANDROID_PLATFORM 21)
8 | set(ANDROID_ABI arm64-v8a)
9 | set(ANDROID_NDK ${NDK_PATH})
10 | set(CMAKE_TOOLCHAIN_FILE ${NDK_PATH}/build/cmake/android.toolchain.cmake)
11 | set(ANDROID_SDK_ROOT ${NDK_PATH})
12 |
13 | project(OSImGui)
14 | set(CMAKE_CXX_STANDARD 20)
15 |
16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -irobf-cse -Wno-error=format-security -fexceptions -fvisibility=hidden -DNDEBUG -O2 -w")
17 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s")
18 |
19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/outputs/${CMAKE_ANDROID_ARCH_ABI}/) # 重定向输出产物
20 |
21 | # CMake头文件设置
22 | FILE(GLOB_RECURSE FILE_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h*)
23 | FILE(GLOB_RECURSE FILE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.c*)
24 |
25 |
26 | include_directories(
27 | include/
28 | include/imgui
29 | include/utils
30 | )
31 |
32 | add_executable(${PROJECT_NAME}
33 | ${FILE_SOURCES}
34 | )
35 |
36 | target_link_libraries(${PROJECT_NAME} PRIVATE
37 | EGL log android GLESv3
38 | )
--------------------------------------------------------------------------------
/Image/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jiang-Night/OS-ImGui-Android/2ec468fa85d4462e7d13aa1cb63234efbcfa8e6d/Image/1.jpg
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OS-ImGui-Android
2 | Android Platform Rapid Development ImGui.
3 |
4 | 一个简单的imgui库,基于[Dear-ImGui](https://github.com/ocornut/imgui).
5 |
6 | 项目参考[Liv](https://github.com/TKazer/OS-ImGui).
7 |
8 | 仅需几分钟,快速搭建imgui环境,让人简单的上手imgui
9 |
10 | ## 特点
11 | * 代码框架简洁,使用方便,快速开发
12 |
13 | * 易于使用
14 | > Only one line of code is needed to call.
15 |
16 | * 多样绘制
17 | >
18 |
19 | ## 示例
20 | 在main.cpp有使用案例
21 | ~~~ c++
22 |
23 | void Imgui_demo() {
24 | ImGui::Begin("Test");
25 | ImGui::Text("Test Windows");
26 | ImGui::Checkbox("Line", &isLine);
27 | if (ImGui::Button("exit")) {
28 | Gui.Quit();
29 | exit(0);
30 | }
31 | Gui.MyCheckBox("Test1", &isLine1);
32 | Gui.MyCheckBox2("Test2", &isLine2);
33 | Gui.MyCheckBox3("Test3", &isLine3);
34 | Gui.MyCheckBox4("Test4", &isLine4);
35 | Gui.SwitchForRight("Test5", &isLine5);
36 | Gui.SwitchForLeft("Test6", &isLine6);
37 |
38 | ImGui::End();
39 |
40 | if (isLine) {
41 | Gui.Line(Vec2{0, 0}, Vec2{1000, 1000}, ImColor{255, 255, 255, 255}, 10);
42 | }
43 | }
44 |
45 |
46 | int main() {
47 | Gui.NewWindow("SurafceName", Imgui_demo);
48 | return 0;
49 | }
50 | ~~~
51 |
52 | ## 未来待做
53 | - [ ] 适配vulkan
54 | - [ ] 适配内部注入版本
55 | - [ ] 添加更多样式 以及更方便的使用方法
56 |
57 |
--------------------------------------------------------------------------------
/include/OS-ImGui.h:
--------------------------------------------------------------------------------
1 | #ifndef OS_IMGUI_H
2 | #define OS_IMGUI_H
3 | #include "OS-ImGui_Base.h"
4 | #include "OS-ImGui_Struct.h"
5 | #include "imgui.h"
6 |
7 | namespace OSImGui {
8 |
9 | class OSImGui : public OSImGui_Base, public Singleton {
10 | public:
11 | // 文本
12 | void Text(std::string Text, Vec2 Pos, ImColor Color, float FontSize = 15);
13 | // 描边文本
14 | void
15 | StrokeText(std::string Text, Vec2 Pos, ImColor Color, float FontSize = 15);
16 | // 矩形
17 | void Rectangle(Vec2 Pos, Vec2 Size, ImColor Color, float Thickness, float Rounding = 0);
18 | void RectangleFilled(Vec2 Pos, Vec2 Size, ImColor Color, float Rounding = 0, int Nums = 15);
19 | void HollowRect(Vec4 Pos, ImColor color, float thickness = 1.f);
20 | // 线
21 | void Line(Vec2 From, Vec2 To, ImColor Color, float Thickness);
22 | // 圆形
23 | void Circle(Vec2 Center, float Radius, ImColor Color, float Thickness, int Num = 50);
24 | void CircleFilled(Vec2 Center, float Radius, ImColor Color, int Num = 50);
25 | // 连接点
26 | void ConnectPoints(std::vector Points, ImColor Color, float Thickness);
27 | // 圆弧
28 | void Arc(ImVec2 Center, float Radius, ImColor Color, float Thickness, float Aangle_begin, float Angle_end, float Nums = 15);
29 | // 勾选框
30 | void MyCheckBox(const char *str_id, bool *v);
31 | void MyCheckBox2(const char *str_id, bool *v);
32 | void MyCheckBox3(const char *str_id, bool *v);
33 | void MyCheckBox4(const char *str_id, bool *v);
34 | // 半圆
35 | void HalfCircle(Vec2 Pos, float radius, ImVec4 color, int segments, int thickness, float arc_degree);
36 | // 图片
37 | void Image(Vec2 Pos, int w, int h, ImTextureID Texture);
38 | // 水印
39 | void Watermark(std::string licenseKey);
40 | // 轮廓方框
41 | void OutlineBox(int x, int y, int w, int h, ImVec4 color, float thickness);
42 | // 左Switch
43 | bool SwitchForLeft(const char *str_id, bool *v);
44 | // 右Switch
45 | bool SwitchForRight(const char *str_id, bool *v);
46 | // 加载png
47 | ImTextureID createTexturePNGFromMem(unsigned char *buf, int len);
48 | };
49 |
50 | }; // namespace OSImGui
51 |
52 | inline OSImGui::OSImGui &Gui = OSImGui::OSImGui::get();
53 |
54 | #endif // OS_IMGUI_H
--------------------------------------------------------------------------------
/include/OS-ImGui_Base.h:
--------------------------------------------------------------------------------
1 | #ifndef IMGUI_BASE_H
2 | #define IMGUI_BASE_H
3 | #include
4 | #include
5 | #include
6 | namespace OSImGui {
7 |
8 | class NativeWindows {
9 | private:
10 | ANativeWindow *SurfaceWindow;
11 |
12 | public:
13 | NativeWindows();
14 | ~NativeWindows();
15 | void InitSurfaceWindow(std::string Name);
16 | ANativeWindow *GetSurfaceWindow() {
17 | return SurfaceWindow;
18 | }
19 | };
20 |
21 | static NativeWindows Surface;
22 |
23 | class OSImGui_Base {
24 | public:
25 | // 回调函数
26 | std::function CallBackFn = nullptr;
27 | std::function TextureCallBackFn =
28 | nullptr; // 如果有需要加载纹理的情况下 传入
29 | // 退出标识
30 | bool EndFlags = false;
31 |
32 | public:
33 | // 创建窗口
34 | void NewWindow(std::string WindowName, std::function CallBack,
35 | std::function TextureCallBack);
36 | void Quit() {
37 | EndFlags = true;
38 | }
39 |
40 | void MainLoop(); // 类似循环
41 | bool InitImGui(ANativeWindow *SurfaceWindow); // 初始化imgui窗口
42 | void CleanImGui(); // 清除imgui窗口
43 | };
44 |
45 | } // namespace OSImGui
46 |
47 | #endif // IMGUI_BASE_H
--------------------------------------------------------------------------------
/include/OS-ImGui_Exception.hpp:
--------------------------------------------------------------------------------
1 | #ifndef IMGUI_EXCEPTION_HPP
2 | #define IMGUI_EXCEPTION_HPP
3 |
4 | #include
5 | #include
6 |
7 | namespace OSImGui {
8 | class OSException : public std::exception {
9 | public:
10 | OSException() : Error_("[OS-Exception] Unkown Error") {}
11 | OSException(std::string Error) : Error_("[OS-Exception] " + Error) {}
12 | char const *what() const throw() { return Error_.c_str(); }
13 |
14 | private:
15 | std::string Error_ = "";
16 | };
17 | } // namespace OSImGui
18 |
19 | #endif
--------------------------------------------------------------------------------
/include/OS-ImGui_Struct.h:
--------------------------------------------------------------------------------
1 | #ifndef OS_IMGUI_STRUCT_H
2 | #define OS_IMGUI_STRUCT_H
3 |
4 | #include "imgui/imgui.h"
5 |
6 | /****************************************************
7 | * Copyright (C) : JiangNight
8 | * @file : OSImGui_Struct.h
9 | * @author : Liv
10 | * @email : wan1298178043@gmail.com
11 | * @version : 1.0
12 | * @date : 2024/10/1 02:54
13 | ****************************************************/
14 |
15 | class Vec2 {
16 | public:
17 | float x, y;
18 |
19 | public:
20 | Vec2() :
21 | x(0.f), y(0.f) {}
22 | Vec2(float x_, float y_) :
23 | x(x_), y(y_) {}
24 | Vec2(int x_, int y_) :
25 | x(x_), y(y_) {}
26 | Vec2(ImVec2 imVec) :
27 | x(imVec.x), y(imVec.y) {}
28 |
29 | Vec2 &operator=(ImVec2 &imVec) {
30 | x = imVec.x;
31 | y = imVec.y;
32 | return *this;
33 | }
34 |
35 | Vec2 operator+(Vec2 Vec2_) { return {x + Vec2_.x, y + Vec2_.y}; }
36 | Vec2 operator-(Vec2 Vec2_) { return {x - Vec2_.x, y - Vec2_.y}; }
37 | Vec2 operator*(Vec2 Vec2_) { return {x * Vec2_.x, y * Vec2_.y}; }
38 | Vec2 operator/(Vec2 Vec2_) { return {x / Vec2_.x, y / Vec2_.y}; }
39 | Vec2 operator*(float n) { return {x * n, y * n}; }
40 | Vec2 operator/(float n) { return {x / n, y / n}; }
41 |
42 | bool operator==(Vec2 Vec2_) { return x == Vec2_.x && y == Vec2_.y; }
43 | bool operator!=(Vec2 Vec2_) { return x != Vec2_.x || y != Vec2_.y; }
44 |
45 | ImVec2 ToImVec2() { return ImVec2(x, y); }
46 | float Length() { return sqrtf(powf(x, 2) + powf(y, 2)); }
47 |
48 | float DistanceTo(const Vec2 &Pos) {
49 | return sqrtf(powf(Pos.x - x, 2) + powf(Pos.y - y, 2));
50 | }
51 | };
52 |
53 | class Vec3 {
54 | public:
55 | float x, y, z;
56 |
57 | public:
58 | Vec3() :
59 | x(0.f), y(0.f), z(0.f) {}
60 | Vec3(float x_, float y_, float z_) :
61 | x(x_), y(y_), z(z_) {}
62 |
63 | float Dot(Vec3 Vec3_) { return x * Vec3_.x + y * Vec3_.y + z * Vec3_.z; }
64 |
65 | Vec3 operator+(Vec3 Vec3_) { return {x + Vec3_.x, y + Vec3_.y, z + Vec3_.z}; }
66 | Vec3 operator-(Vec3 Vec3_) { return {x - Vec3_.x, y - Vec3_.y, z - Vec3_.z}; }
67 | Vec3 operator*(Vec3 Vec3_) { return {x * Vec3_.x, y * Vec3_.y, z * Vec3_.z}; }
68 | Vec3 operator/(Vec3 Vec3_) { return {x / Vec3_.x, y / Vec3_.y, z / Vec3_.z}; }
69 | Vec3 operator*(float n) { return {x * n, y * n, z * n}; }
70 | Vec3 operator/(float n) { return {x * n, y * n, z * n}; }
71 |
72 | bool operator==(Vec3 Vec3_) { return x == Vec3_.x && y == Vec3_.y && z == Vec3_.z; }
73 | bool operator!=(Vec3 Vec3_) { return x != Vec3_.x || y != Vec3_.y || z != Vec3_.z; }
74 |
75 | float Length() { return sqrtf(powf(x, 2) + powf(y, 2) + powf(z, 2)); }
76 |
77 | float DistanceTo(const Vec3 &Pos) {
78 | return sqrtf(powf(Pos.x - x, 2) + powf(Pos.y - y, 2) + powf(Pos.z - z, 2));
79 | }
80 | };
81 |
82 | class Vec4 {
83 | public:
84 | float x, y, w, h;
85 |
86 | public:
87 | Vec4() :
88 | x(0.f), y(0.f), w(0.f), h(0.f) {}
89 |
90 | Vec4(float x_, float y_, float w_, float h_) :
91 | x(x_), y(y_), w(w_), h(h_) {}
92 |
93 | // 运算符重载
94 | Vec4 operator+(const Vec4 &Vec4_) const { return {x + Vec4_.x, y + Vec4_.y, w + Vec4_.w, h + Vec4_.h}; }
95 | Vec4 operator-(const Vec4 &Vec4_) const { return {x - Vec4_.x, y - Vec4_.y, w - Vec4_.w, h - Vec4_.h}; }
96 | Vec4 operator*(float n) const { return {x * n, y * n, w * n, h * n}; }
97 | Vec4 operator/(float n) const { return {x / n, y / n, w / n, h / n}; }
98 |
99 | bool operator==(const Vec4 &Vec4_) const { return x == Vec4_.x && y == Vec4_.y && w == Vec4_.w && h == Vec4_.h; }
100 | bool operator!=(const Vec4 &Vec4_) const { return !(*this == Vec4_); }
101 | // 计算面积
102 | float Area() const { return w * h; }
103 | // 计算与另一个Vec4的距离
104 | float DistanceTo(const Vec4 &Pos) const {
105 | return sqrtf(powf(Pos.x - x, 2) + powf(Pos.y - y, 2) + powf(Pos.w - w, 2) + powf(Pos.h - h, 2));
106 | }
107 | };
108 | // 单例设计
109 | template
110 | class Singleton {
111 | public:
112 | static T &get() {
113 | static T instance;
114 | return instance;
115 | }
116 | };
117 |
118 | #endif // OS_IMGUI_STRUCT_H
--------------------------------------------------------------------------------
/include/imgui/imconfig.h:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------------
2 | // DEAR IMGUI COMPILE-TIME OPTIONS
3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
5 | //-----------------------------------------------------------------------------
6 | // A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/rebased branch with your modifications to it)
7 | // B) or '#define IMGUI_USER_CONFIG "my_imgui_config.h"' in your project and then add directives in your own file without touching this template.
8 | //-----------------------------------------------------------------------------
9 | // You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
10 | // files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
11 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
12 | // Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
13 | //-----------------------------------------------------------------------------
14 |
15 | #pragma once
16 |
17 | //---- Define assertion handler. Defaults to calling assert().
18 | // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
19 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
20 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
21 |
22 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
23 | // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
24 | // DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
25 | // for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
26 | //#define IMGUI_API __declspec( dllexport )
27 | //#define IMGUI_API __declspec( dllimport )
28 |
29 | //---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
30 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
31 | //#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
32 |
33 | //---- Disable all of Dear ImGui or don't implement standard windows/tools.
34 | // It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
35 | //#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
36 | //#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
37 | //#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
38 |
39 | //---- Don't implement some functions to reduce linkage requirements.
40 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
41 | //#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
42 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
43 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
44 | //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
45 | //#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
46 | //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
47 | //#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
48 | //#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function.
49 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
50 | //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
51 |
52 | //---- Include imgui_user.h at the end of imgui.h as a convenience
53 | //#define IMGUI_INCLUDE_IMGUI_USER_H
54 |
55 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
56 | //#define IMGUI_USE_BGRA_PACKED_COLOR
57 |
58 | //---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
59 | //#define IMGUI_USE_WCHAR32
60 |
61 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
62 | // By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
63 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
64 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
65 | //#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
66 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
67 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
68 |
69 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
70 | // Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
71 | //#define IMGUI_USE_STB_SPRINTF
72 |
73 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
74 | // Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
75 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
76 | //#define IMGUI_ENABLE_FREETYPE
77 |
78 | //---- Use stb_truetype to build and rasterize the font atlas (default)
79 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
80 | //#define IMGUI_ENABLE_STB_TRUETYPE
81 |
82 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4.
83 | // This will be inlined as part of ImVec2 and ImVec4 class declarations.
84 | /*
85 | #define IM_VEC2_CLASS_EXTRA \
86 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \
87 | operator MyVec2() const { return MyVec2(x,y); }
88 |
89 | #define IM_VEC4_CLASS_EXTRA \
90 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \
91 | operator MyVec4() const { return MyVec4(x,y,z,w); }
92 | */
93 | //---- ...Or use Dear ImGui's own very basic math operators.
94 | //#define IMGUI_DEFINE_MATH_OPERATORS
95 |
96 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices.
97 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
98 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
99 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
100 | //#define ImDrawIdx unsigned int
101 |
102 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
103 | //struct ImDrawList;
104 | //struct ImDrawCmd;
105 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
106 | //#define ImDrawCallback MyImDrawCallback
107 |
108 | //---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
109 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
110 | //#define IM_DEBUG_BREAK IM_ASSERT(0)
111 | //#define IM_DEBUG_BREAK __debugbreak()
112 |
113 | //---- Debug Tools: Enable slower asserts
114 | //#define IMGUI_DEBUG_PARANOID
115 |
116 | //---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
117 | /*
118 | namespace ImGui
119 | {
120 | void MyFunction(const char* name, MyMatrix44* mtx);
121 | }
122 | */
123 |
--------------------------------------------------------------------------------
/include/imgui/imgui_impl_android.h:
--------------------------------------------------------------------------------
1 | // dear imgui: Platform Binding for Android native app
2 | // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
3 |
4 | // Implemented features:
5 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
6 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
7 | // Missing features:
8 | // [ ] Platform: Clipboard support.
9 | // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
10 | // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
11 | // Important:
12 | // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
13 | // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
14 | // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
15 |
16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
18 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
19 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
20 |
21 | #pragma once
22 | #include "imgui.h" // IMGUI_IMPL_API
23 | #ifndef IMGUI_DISABLE
24 |
25 | struct ANativeWindow;
26 | struct AInputEvent;
27 |
28 | IMGUI_IMPL_API bool ImGui_ImplAndroid_Init(ANativeWindow* window);
29 | IMGUI_IMPL_API int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event);
30 | IMGUI_IMPL_API void ImGui_ImplAndroid_Shutdown();
31 | IMGUI_IMPL_API void ImGui_ImplAndroid_NewFrame();
32 |
33 | #endif // #ifndef IMGUI_DISABLE
34 |
--------------------------------------------------------------------------------
/include/imgui/imgui_impl_opengl3.h:
--------------------------------------------------------------------------------
1 | // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
2 | // - Desktop GL: 2.x 3.x 4.x
3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
4 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
5 |
6 | // Implemented features:
7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
8 | // [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
9 |
10 | // About WebGL/ES:
11 | // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
12 | // - This is done automatically on iOS, Android and Emscripten targets.
13 | // - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
14 |
15 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
16 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
17 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
18 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
19 |
20 | // About GLSL version:
21 | // The 'glsl_version' initialization parameter should be nullptr (default) or a "#version XXX" string.
22 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es"
23 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
24 |
25 | #pragma once
26 | #include "imgui.h" // IMGUI_IMPL_API
27 | #ifndef IMGUI_DISABLE
28 |
29 | // Backend API
30 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
31 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
32 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
33 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
34 |
35 | // (Optional) Called by Init/NewFrame/Shutdown
36 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
37 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
38 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
39 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
40 |
41 | // Specific OpenGL ES versions
42 | //#define IMGUI_IMPL_OPENGL_ES2 // Auto-detected on Emscripten
43 | //#define IMGUI_IMPL_OPENGL_ES3 // Auto-detected on iOS/Android
44 |
45 | // You can explicitly select GLES2 or GLES3 API by using one of the '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line.
46 | #if !defined(IMGUI_IMPL_OPENGL_ES2) \
47 | && !defined(IMGUI_IMPL_OPENGL_ES3)
48 |
49 | // Try to detect GLES on matching platforms
50 | #if defined(__APPLE__)
51 | #include
52 | #endif
53 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
54 | #define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"
55 | #elif defined(__EMSCRIPTEN__) || defined(__amigaos4__)
56 | #define IMGUI_IMPL_OPENGL_ES2 // Emscripten -> GL ES 2, "#version 100"
57 | #else
58 | // Otherwise imgui_impl_opengl3_loader.h will be used.
59 | #endif
60 |
61 | #endif
62 |
63 | #endif // #ifndef IMGUI_DISABLE
64 |
--------------------------------------------------------------------------------
/include/imgui/imstb_rectpack.h:
--------------------------------------------------------------------------------
1 | // [DEAR IMGUI]
2 | // This is a slightly modified version of stb_rect_pack.h 1.01.
3 | // Grep for [DEAR IMGUI] to find the changes.
4 | //
5 | // stb_rect_pack.h - v1.01 - public domain - rectangle packing
6 | // Sean Barrett 2014
7 | //
8 | // Useful for e.g. packing rectangular textures into an atlas.
9 | // Does not do rotation.
10 | //
11 | // Before #including,
12 | //
13 | // #define STB_RECT_PACK_IMPLEMENTATION
14 | //
15 | // in the file that you want to have the implementation.
16 | //
17 | // Not necessarily the awesomest packing method, but better than
18 | // the totally naive one in stb_truetype (which is primarily what
19 | // this is meant to replace).
20 | //
21 | // Has only had a few tests run, may have issues.
22 | //
23 | // More docs to come.
24 | //
25 | // No memory allocations; uses qsort() and assert() from stdlib.
26 | // Can override those by defining STBRP_SORT and STBRP_ASSERT.
27 | //
28 | // This library currently uses the Skyline Bottom-Left algorithm.
29 | //
30 | // Please note: better rectangle packers are welcome! Please
31 | // implement them to the same API, but with a different init
32 | // function.
33 | //
34 | // Credits
35 | //
36 | // Library
37 | // Sean Barrett
38 | // Minor features
39 | // Martins Mozeiko
40 | // github:IntellectualKitty
41 | //
42 | // Bugfixes / warning fixes
43 | // Jeremy Jaussaud
44 | // Fabian Giesen
45 | //
46 | // Version history:
47 | //
48 | // 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section
49 | // 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
50 | // 0.99 (2019-02-07) warning fixes
51 | // 0.11 (2017-03-03) return packing success/fail result
52 | // 0.10 (2016-10-25) remove cast-away-const to avoid warnings
53 | // 0.09 (2016-08-27) fix compiler warnings
54 | // 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
55 | // 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
56 | // 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
57 | // 0.05: added STBRP_ASSERT to allow replacing assert
58 | // 0.04: fixed minor bug in STBRP_LARGE_RECTS support
59 | // 0.01: initial release
60 | //
61 | // LICENSE
62 | //
63 | // See end of file for license information.
64 |
65 | //////////////////////////////////////////////////////////////////////////////
66 | //
67 | // INCLUDE SECTION
68 | //
69 |
70 | #ifndef STB_INCLUDE_STB_RECT_PACK_H
71 | #define STB_INCLUDE_STB_RECT_PACK_H
72 |
73 | #define STB_RECT_PACK_VERSION 1
74 |
75 | #ifdef STBRP_STATIC
76 | #define STBRP_DEF static
77 | #else
78 | #define STBRP_DEF extern
79 | #endif
80 |
81 | #ifdef __cplusplus
82 | extern "C" {
83 | #endif
84 |
85 | typedef struct stbrp_context stbrp_context;
86 | typedef struct stbrp_node stbrp_node;
87 | typedef struct stbrp_rect stbrp_rect;
88 |
89 | typedef int stbrp_coord;
90 |
91 | #define STBRP__MAXVAL 0x7fffffff
92 | // Mostly for internal use, but this is the maximum supported coordinate value.
93 |
94 | STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
95 | // Assign packed locations to rectangles. The rectangles are of type
96 | // 'stbrp_rect' defined below, stored in the array 'rects', and there
97 | // are 'num_rects' many of them.
98 | //
99 | // Rectangles which are successfully packed have the 'was_packed' flag
100 | // set to a non-zero value and 'x' and 'y' store the minimum location
101 | // on each axis (i.e. bottom-left in cartesian coordinates, top-left
102 | // if you imagine y increasing downwards). Rectangles which do not fit
103 | // have the 'was_packed' flag set to 0.
104 | //
105 | // You should not try to access the 'rects' array from another thread
106 | // while this function is running, as the function temporarily reorders
107 | // the array while it executes.
108 | //
109 | // To pack into another rectangle, you need to call stbrp_init_target
110 | // again. To continue packing into the same rectangle, you can call
111 | // this function again. Calling this multiple times with multiple rect
112 | // arrays will probably produce worse packing results than calling it
113 | // a single time with the full rectangle array, but the option is
114 | // available.
115 | //
116 | // The function returns 1 if all of the rectangles were successfully
117 | // packed and 0 otherwise.
118 |
119 | struct stbrp_rect
120 | {
121 | // reserved for your use:
122 | int id;
123 |
124 | // input:
125 | stbrp_coord w, h;
126 |
127 | // output:
128 | stbrp_coord x, y;
129 | int was_packed; // non-zero if valid packing
130 |
131 | }; // 16 bytes, nominally
132 |
133 |
134 | STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
135 | // Initialize a rectangle packer to:
136 | // pack a rectangle that is 'width' by 'height' in dimensions
137 | // using temporary storage provided by the array 'nodes', which is 'num_nodes' long
138 | //
139 | // You must call this function every time you start packing into a new target.
140 | //
141 | // There is no "shutdown" function. The 'nodes' memory must stay valid for
142 | // the following stbrp_pack_rects() call (or calls), but can be freed after
143 | // the call (or calls) finish.
144 | //
145 | // Note: to guarantee best results, either:
146 | // 1. make sure 'num_nodes' >= 'width'
147 | // or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
148 | //
149 | // If you don't do either of the above things, widths will be quantized to multiples
150 | // of small integers to guarantee the algorithm doesn't run out of temporary storage.
151 | //
152 | // If you do #2, then the non-quantized algorithm will be used, but the algorithm
153 | // may run out of temporary storage and be unable to pack some rectangles.
154 |
155 | STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
156 | // Optionally call this function after init but before doing any packing to
157 | // change the handling of the out-of-temp-memory scenario, described above.
158 | // If you call init again, this will be reset to the default (false).
159 |
160 |
161 | STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
162 | // Optionally select which packing heuristic the library should use. Different
163 | // heuristics will produce better/worse results for different data sets.
164 | // If you call init again, this will be reset to the default.
165 |
166 | enum
167 | {
168 | STBRP_HEURISTIC_Skyline_default=0,
169 | STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
170 | STBRP_HEURISTIC_Skyline_BF_sortHeight
171 | };
172 |
173 |
174 | //////////////////////////////////////////////////////////////////////////////
175 | //
176 | // the details of the following structures don't matter to you, but they must
177 | // be visible so you can handle the memory allocations for them
178 |
179 | struct stbrp_node
180 | {
181 | stbrp_coord x,y;
182 | stbrp_node *next;
183 | };
184 |
185 | struct stbrp_context
186 | {
187 | int width;
188 | int height;
189 | int align;
190 | int init_mode;
191 | int heuristic;
192 | int num_nodes;
193 | stbrp_node *active_head;
194 | stbrp_node *free_head;
195 | stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
196 | };
197 |
198 | #ifdef __cplusplus
199 | }
200 | #endif
201 |
202 | #endif
203 |
204 | //////////////////////////////////////////////////////////////////////////////
205 | //
206 | // IMPLEMENTATION SECTION
207 | //
208 |
209 | #ifdef STB_RECT_PACK_IMPLEMENTATION
210 | #ifndef STBRP_SORT
211 | #include
212 | #define STBRP_SORT qsort
213 | #endif
214 |
215 | #ifndef STBRP_ASSERT
216 | #include
217 | #define STBRP_ASSERT assert
218 | #endif
219 |
220 | #ifdef _MSC_VER
221 | #define STBRP__NOTUSED(v) (void)(v)
222 | #define STBRP__CDECL __cdecl
223 | #else
224 | #define STBRP__NOTUSED(v) (void)sizeof(v)
225 | #define STBRP__CDECL
226 | #endif
227 |
228 | enum
229 | {
230 | STBRP__INIT_skyline = 1
231 | };
232 |
233 | STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
234 | {
235 | switch (context->init_mode) {
236 | case STBRP__INIT_skyline:
237 | STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
238 | context->heuristic = heuristic;
239 | break;
240 | default:
241 | STBRP_ASSERT(0);
242 | }
243 | }
244 |
245 | STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
246 | {
247 | if (allow_out_of_mem)
248 | // if it's ok to run out of memory, then don't bother aligning them;
249 | // this gives better packing, but may fail due to OOM (even though
250 | // the rectangles easily fit). @TODO a smarter approach would be to only
251 | // quantize once we've hit OOM, then we could get rid of this parameter.
252 | context->align = 1;
253 | else {
254 | // if it's not ok to run out of memory, then quantize the widths
255 | // so that num_nodes is always enough nodes.
256 | //
257 | // I.e. num_nodes * align >= width
258 | // align >= width / num_nodes
259 | // align = ceil(width/num_nodes)
260 |
261 | context->align = (context->width + context->num_nodes-1) / context->num_nodes;
262 | }
263 | }
264 |
265 | STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
266 | {
267 | int i;
268 |
269 | for (i=0; i < num_nodes-1; ++i)
270 | nodes[i].next = &nodes[i+1];
271 | nodes[i].next = NULL;
272 | context->init_mode = STBRP__INIT_skyline;
273 | context->heuristic = STBRP_HEURISTIC_Skyline_default;
274 | context->free_head = &nodes[0];
275 | context->active_head = &context->extra[0];
276 | context->width = width;
277 | context->height = height;
278 | context->num_nodes = num_nodes;
279 | stbrp_setup_allow_out_of_mem(context, 0);
280 |
281 | // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
282 | context->extra[0].x = 0;
283 | context->extra[0].y = 0;
284 | context->extra[0].next = &context->extra[1];
285 | context->extra[1].x = (stbrp_coord) width;
286 | context->extra[1].y = (1<<30);
287 | context->extra[1].next = NULL;
288 | }
289 |
290 | // find minimum y position if it starts at x1
291 | static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
292 | {
293 | stbrp_node *node = first;
294 | int x1 = x0 + width;
295 | int min_y, visited_width, waste_area;
296 |
297 | STBRP__NOTUSED(c);
298 |
299 | STBRP_ASSERT(first->x <= x0);
300 |
301 | #if 0
302 | // skip in case we're past the node
303 | while (node->next->x <= x0)
304 | ++node;
305 | #else
306 | STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
307 | #endif
308 |
309 | STBRP_ASSERT(node->x <= x0);
310 |
311 | min_y = 0;
312 | waste_area = 0;
313 | visited_width = 0;
314 | while (node->x < x1) {
315 | if (node->y > min_y) {
316 | // raise min_y higher.
317 | // we've accounted for all waste up to min_y,
318 | // but we'll now add more waste for everything we've visted
319 | waste_area += visited_width * (node->y - min_y);
320 | min_y = node->y;
321 | // the first time through, visited_width might be reduced
322 | if (node->x < x0)
323 | visited_width += node->next->x - x0;
324 | else
325 | visited_width += node->next->x - node->x;
326 | } else {
327 | // add waste area
328 | int under_width = node->next->x - node->x;
329 | if (under_width + visited_width > width)
330 | under_width = width - visited_width;
331 | waste_area += under_width * (min_y - node->y);
332 | visited_width += under_width;
333 | }
334 | node = node->next;
335 | }
336 |
337 | *pwaste = waste_area;
338 | return min_y;
339 | }
340 |
341 | typedef struct
342 | {
343 | int x,y;
344 | stbrp_node **prev_link;
345 | } stbrp__findresult;
346 |
347 | static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
348 | {
349 | int best_waste = (1<<30), best_x, best_y = (1 << 30);
350 | stbrp__findresult fr;
351 | stbrp_node **prev, *node, *tail, **best = NULL;
352 |
353 | // align to multiple of c->align
354 | width = (width + c->align - 1);
355 | width -= width % c->align;
356 | STBRP_ASSERT(width % c->align == 0);
357 |
358 | // if it can't possibly fit, bail immediately
359 | if (width > c->width || height > c->height) {
360 | fr.prev_link = NULL;
361 | fr.x = fr.y = 0;
362 | return fr;
363 | }
364 |
365 | node = c->active_head;
366 | prev = &c->active_head;
367 | while (node->x + width <= c->width) {
368 | int y,waste;
369 | y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
370 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
371 | // bottom left
372 | if (y < best_y) {
373 | best_y = y;
374 | best = prev;
375 | }
376 | } else {
377 | // best-fit
378 | if (y + height <= c->height) {
379 | // can only use it if it first vertically
380 | if (y < best_y || (y == best_y && waste < best_waste)) {
381 | best_y = y;
382 | best_waste = waste;
383 | best = prev;
384 | }
385 | }
386 | }
387 | prev = &node->next;
388 | node = node->next;
389 | }
390 |
391 | best_x = (best == NULL) ? 0 : (*best)->x;
392 |
393 | // if doing best-fit (BF), we also have to try aligning right edge to each node position
394 | //
395 | // e.g, if fitting
396 | //
397 | // ____________________
398 | // |____________________|
399 | //
400 | // into
401 | //
402 | // | |
403 | // | ____________|
404 | // |____________|
405 | //
406 | // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
407 | //
408 | // This makes BF take about 2x the time
409 |
410 | if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
411 | tail = c->active_head;
412 | node = c->active_head;
413 | prev = &c->active_head;
414 | // find first node that's admissible
415 | while (tail->x < width)
416 | tail = tail->next;
417 | while (tail) {
418 | int xpos = tail->x - width;
419 | int y,waste;
420 | STBRP_ASSERT(xpos >= 0);
421 | // find the left position that matches this
422 | while (node->next->x <= xpos) {
423 | prev = &node->next;
424 | node = node->next;
425 | }
426 | STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
427 | y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
428 | if (y + height <= c->height) {
429 | if (y <= best_y) {
430 | if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
431 | best_x = xpos;
432 | //STBRP_ASSERT(y <= best_y); [DEAR IMGUI]
433 | best_y = y;
434 | best_waste = waste;
435 | best = prev;
436 | }
437 | }
438 | }
439 | tail = tail->next;
440 | }
441 | }
442 |
443 | fr.prev_link = best;
444 | fr.x = best_x;
445 | fr.y = best_y;
446 | return fr;
447 | }
448 |
449 | static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
450 | {
451 | // find best position according to heuristic
452 | stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
453 | stbrp_node *node, *cur;
454 |
455 | // bail if:
456 | // 1. it failed
457 | // 2. the best node doesn't fit (we don't always check this)
458 | // 3. we're out of memory
459 | if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
460 | res.prev_link = NULL;
461 | return res;
462 | }
463 |
464 | // on success, create new node
465 | node = context->free_head;
466 | node->x = (stbrp_coord) res.x;
467 | node->y = (stbrp_coord) (res.y + height);
468 |
469 | context->free_head = node->next;
470 |
471 | // insert the new node into the right starting point, and
472 | // let 'cur' point to the remaining nodes needing to be
473 | // stiched back in
474 |
475 | cur = *res.prev_link;
476 | if (cur->x < res.x) {
477 | // preserve the existing one, so start testing with the next one
478 | stbrp_node *next = cur->next;
479 | cur->next = node;
480 | cur = next;
481 | } else {
482 | *res.prev_link = node;
483 | }
484 |
485 | // from here, traverse cur and free the nodes, until we get to one
486 | // that shouldn't be freed
487 | while (cur->next && cur->next->x <= res.x + width) {
488 | stbrp_node *next = cur->next;
489 | // move the current node to the free list
490 | cur->next = context->free_head;
491 | context->free_head = cur;
492 | cur = next;
493 | }
494 |
495 | // stitch the list back in
496 | node->next = cur;
497 |
498 | if (cur->x < res.x + width)
499 | cur->x = (stbrp_coord) (res.x + width);
500 |
501 | #ifdef _DEBUG
502 | cur = context->active_head;
503 | while (cur->x < context->width) {
504 | STBRP_ASSERT(cur->x < cur->next->x);
505 | cur = cur->next;
506 | }
507 | STBRP_ASSERT(cur->next == NULL);
508 |
509 | {
510 | int count=0;
511 | cur = context->active_head;
512 | while (cur) {
513 | cur = cur->next;
514 | ++count;
515 | }
516 | cur = context->free_head;
517 | while (cur) {
518 | cur = cur->next;
519 | ++count;
520 | }
521 | STBRP_ASSERT(count == context->num_nodes+2);
522 | }
523 | #endif
524 |
525 | return res;
526 | }
527 |
528 | static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
529 | {
530 | const stbrp_rect *p = (const stbrp_rect *) a;
531 | const stbrp_rect *q = (const stbrp_rect *) b;
532 | if (p->h > q->h)
533 | return -1;
534 | if (p->h < q->h)
535 | return 1;
536 | return (p->w > q->w) ? -1 : (p->w < q->w);
537 | }
538 |
539 | static int STBRP__CDECL rect_original_order(const void *a, const void *b)
540 | {
541 | const stbrp_rect *p = (const stbrp_rect *) a;
542 | const stbrp_rect *q = (const stbrp_rect *) b;
543 | return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
544 | }
545 |
546 | STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
547 | {
548 | int i, all_rects_packed = 1;
549 |
550 | // we use the 'was_packed' field internally to allow sorting/unsorting
551 | for (i=0; i < num_rects; ++i) {
552 | rects[i].was_packed = i;
553 | }
554 |
555 | // sort according to heuristic
556 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
557 |
558 | for (i=0; i < num_rects; ++i) {
559 | if (rects[i].w == 0 || rects[i].h == 0) {
560 | rects[i].x = rects[i].y = 0; // empty rect needs no space
561 | } else {
562 | stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
563 | if (fr.prev_link) {
564 | rects[i].x = (stbrp_coord) fr.x;
565 | rects[i].y = (stbrp_coord) fr.y;
566 | } else {
567 | rects[i].x = rects[i].y = STBRP__MAXVAL;
568 | }
569 | }
570 | }
571 |
572 | // unsort
573 | STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
574 |
575 | // set was_packed flags and all_rects_packed status
576 | for (i=0; i < num_rects; ++i) {
577 | rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
578 | if (!rects[i].was_packed)
579 | all_rects_packed = 0;
580 | }
581 |
582 | // return the all_rects_packed status
583 | return all_rects_packed;
584 | }
585 | #endif
586 |
587 | /*
588 | ------------------------------------------------------------------------------
589 | This software is available under 2 licenses -- choose whichever you prefer.
590 | ------------------------------------------------------------------------------
591 | ALTERNATIVE A - MIT License
592 | Copyright (c) 2017 Sean Barrett
593 | Permission is hereby granted, free of charge, to any person obtaining a copy of
594 | this software and associated documentation files (the "Software"), to deal in
595 | the Software without restriction, including without limitation the rights to
596 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
597 | of the Software, and to permit persons to whom the Software is furnished to do
598 | so, subject to the following conditions:
599 | The above copyright notice and this permission notice shall be included in all
600 | copies or substantial portions of the Software.
601 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
602 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
603 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
604 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
605 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
606 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
607 | SOFTWARE.
608 | ------------------------------------------------------------------------------
609 | ALTERNATIVE B - Public Domain (www.unlicense.org)
610 | This is free and unencumbered software released into the public domain.
611 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
612 | software, either in source code form or as a compiled binary, for any purpose,
613 | commercial or non-commercial, and by any means.
614 | In jurisdictions that recognize copyright laws, the author or authors of this
615 | software dedicate any and all copyright interest in the software to the public
616 | domain. We make this dedication for the benefit of the public at large and to
617 | the detriment of our heirs and successors. We intend this dedication to be an
618 | overt act of relinquishment in perpetuity of all present and future rights to
619 | this software under copyright law.
620 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
621 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
622 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
623 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
624 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
625 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
626 | ------------------------------------------------------------------------------
627 | */
628 |
--------------------------------------------------------------------------------
/include/imgui/stb_image.h:
--------------------------------------------------------------------------------
1 | /* stbi-1.18 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
2 | when you control the images you're loading
3 |
4 | QUICK NOTES:
5 | Primarily of interest to game developers and other people who can
6 | avoid problematic images and only need the trivial interface
7 |
8 | JPEG baseline (no JPEG progressive, no oddball channel decimations)
9 | PNG 8-bit only
10 | BMP non-1bpp, non-RLE
11 | TGA (not sure what subset, if a subset)
12 | PSD (composited view only, no extra channels)
13 | HDR (radiance rgbE format)
14 | writes BMP,TGA (define STBI_NO_WRITE to remove code)
15 | decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code)
16 | supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
17 |
18 | TODO:
19 | stbi_info_*
20 |
21 | history:
22 | 1.18 fix a threading bug (local mutable static)
23 | 1.17 support interlaced PNG
24 | 1.16 major bugfix - convert_format converted one too many pixels
25 | 1.15 initialize some fields for thread safety
26 | 1.14 fix threadsafe conversion bug; header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
27 | 1.13 threadsafe
28 | 1.12 const qualifiers in the API
29 | 1.11 Support installable IDCT, colorspace conversion routines
30 | 1.10 Fixes for 64-bit (don't use "unsigned long")
31 | optimized upsampling by Fabian "ryg" Giesen
32 | 1.09 Fix format-conversion for PSD code (bad global variables!)
33 | 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz
34 | 1.07 attempt to fix C++ warning/errors again
35 | 1.06 attempt to fix C++ warning/errors again
36 | 1.05 fix TGA loading to return correct *comp and use good luminance calc
37 | 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free
38 | 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR
39 | 1.02 support for (subset of) HDR files, float interface for preferred access to them
40 | 1.01 fix bug: possible bug in handling right-side up bmps... not sure
41 | fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all
42 | 1.00 interface to zlib that skips zlib header
43 | 0.99 correct handling of alpha in palette
44 | 0.98 TGA loader by lonesock; dynamically add loaders (untested)
45 | 0.97 jpeg errors on too large a file; also catch another malloc failure
46 | 0.96 fix detection of invalid v value - particleman@mollyrocket forum
47 | 0.95 during header scan, seek to markers in case of padding
48 | 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
49 | 0.93 handle jpegtran output; verbose errors
50 | 0.92 read 4,8,16,24,32-bit BMP files of several formats
51 | 0.91 output 24-bit Windows 3.0 BMP files
52 | 0.90 fix a few more warnings; bump version number to approach 1.0
53 | 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd
54 | 0.60 fix compiling as c++
55 | 0.59 fix warnings: merge Dave Moore's -Wall fixes
56 | 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian
57 | 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less
58 | than 16 available
59 | 0.56 fix bug: zlib uncompressed mode len vs. nlen
60 | 0.55 fix bug: restart_interval not initialized to 0
61 | 0.54 allow NULL for 'int *comp'
62 | 0.53 fix bug in png 3->4; speedup png decoding
63 | 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments
64 | 0.51 obey req_comp requests, 1-component jpegs return as 1-component,
65 | on 'test' only check type, not whether we support this variant
66 | */
67 |
68 |
69 | #ifndef STBI_INCLUDE_STB_IMAGE_H
70 | #define STBI_INCLUDE_STB_IMAGE_H
71 |
72 | //// begin header file ////////////////////////////////////////////////////
73 | //
74 | // Limitations:
75 | // - no progressive/interlaced support (jpeg, png)
76 | // - 8-bit samples only (jpeg, png)
77 | // - not threadsafe
78 | // - channel subsampling of at most 2 in each dimension (jpeg)
79 | // - no delayed line count (jpeg) -- IJG doesn't support either
80 | //
81 | // Basic usage (see HDR discussion below):
82 | // int x,y,n;
83 | // unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
84 | // // ... process data if not NULL ...
85 | // // ... x = width, y = height, n = # 8-bit components per pixel ...
86 | // // ... replace '0' with '1'..'4' to force that many components per pixel
87 | // stbi_image_free(data)
88 | //
89 | // Standard parameters:
90 | // int *x -- outputs image width in pixels
91 | // int *y -- outputs image height in pixels
92 | // int *comp -- outputs # of image components in image file
93 | // int req_comp -- if non-zero, # of image components requested in result
94 | //
95 | // The return value from an image loader is an 'unsigned char *' which points
96 | // to the pixel data. The pixel data consists of *y scanlines of *x pixels,
97 | // with each pixel consisting of N interleaved 8-bit components; the first
98 | // pixel pointed to is top-left-most in the image. There is no padding between
99 | // image scanlines or between pixels, regardless of format. The number of
100 | // components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
101 | // If req_comp is non-zero, *comp has the number of components that _would_
102 | // have been output otherwise. E.g. if you set req_comp to 4, you will always
103 | // get RGBA output, but you can check *comp to easily see if it's opaque.
104 | //
105 | // An output image with N components has the following components interleaved
106 | // in this order in each pixel:
107 | //
108 | // N=#comp components
109 | // 1 grey
110 | // 2 grey, alpha
111 | // 3 red, green, blue
112 | // 4 red, green, blue, alpha
113 | //
114 | // If image loading fails for any reason, the return value will be NULL,
115 | // and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
116 | // can be queried for an extremely brief, end-user unfriendly explanation
117 | // of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
118 | // compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
119 | // more user-friendly ones.
120 | //
121 | // Paletted PNG and BMP images are automatically depalettized.
122 | //
123 | //
124 | // ===========================================================================
125 | //
126 | // HDR image support (disable by defining STBI_NO_HDR)
127 | //
128 | // stb_image now supports loading HDR images in general, and currently
129 | // the Radiance .HDR file format, although the support is provided
130 | // generically. You can still load any file through the existing interface;
131 | // if you attempt to load an HDR file, it will be automatically remapped to
132 | // LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
133 | // both of these constants can be reconfigured through this interface:
134 | //
135 | // stbi_hdr_to_ldr_gamma(2.2f);
136 | // stbi_hdr_to_ldr_scale(1.0f);
137 | //
138 | // (note, do not use _inverse_ constants; stbi_image will invert them
139 | // appropriately).
140 | //
141 | // Additionally, there is a new, parallel interface for loading files as
142 | // (linear) floats to preserve the full dynamic range:
143 | //
144 | // float *data = stbi_loadf(filename, &x, &y, &n, 0);
145 | //
146 | // If you load LDR images through this interface, those images will
147 | // be promoted to floating point values, run through the inverse of
148 | // constants corresponding to the above:
149 | //
150 | // stbi_ldr_to_hdr_scale(1.0f);
151 | // stbi_ldr_to_hdr_gamma(2.2f);
152 | //
153 | // Finally, given a filename (or an open file or memory block--see header
154 | // file for details) containing image data, you can query for the "most
155 | // appropriate" interface to use (that is, whether the image is HDR or
156 | // not), using:
157 | //
158 | // stbi_is_hdr(char *filename);
159 |
160 | #ifndef STBI_NO_STDIO
161 | #include
162 | #endif
163 | #define STBI_VERSION 1
164 |
165 | enum
166 | {
167 | STBI_default = 0, // only used for req_comp
168 |
169 | STBI_grey = 1,
170 | STBI_grey_alpha = 2,
171 | STBI_rgb = 3,
172 | STBI_rgb_alpha = 4
173 | };
174 |
175 | typedef unsigned char stbi_uc;
176 |
177 | #ifdef __cplusplus
178 | extern "C" {
179 | #endif
180 |
181 | // WRITING API
182 |
183 | #if !defined(STBI_NO_WRITE) && !defined(STBI_NO_STDIO)
184 | // write a BMP/TGA file given tightly packed 'comp' channels (no padding, nor bmp-stride-padding)
185 | // (you must include the appropriate extension in the filename).
186 | // returns TRUE on success, FALSE if couldn't open file, error writing file
187 | int stbi_write_bmp (char const *filename, int x, int y, int comp, void *data);
188 | int stbi_write_tga (char const *filename, int x, int y, int comp, void *data);
189 | #endif
190 |
191 | // PRIMARY API - works on images of any type
192 |
193 | // load image by filename, open file, or memory buffer
194 | #ifndef STBI_NO_STDIO
195 | stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
196 | stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
197 | int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
198 | #endif
199 | stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
200 | // for stbi_load_from_file, file pointer is left pointing immediately after image
201 |
202 | #ifndef STBI_NO_HDR
203 | #ifndef STBI_NO_STDIO
204 | float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp);
205 | float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
206 | #endif
207 | float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
208 |
209 | void stbi_hdr_to_ldr_gamma(float gamma);
210 | void stbi_hdr_to_ldr_scale(float scale);
211 |
212 | void stbi_ldr_to_hdr_gamma(float gamma);
213 | void stbi_ldr_to_hdr_scale(float scale);
214 |
215 | #endif // STBI_NO_HDR
216 |
217 | // get a VERY brief reason for failure
218 | // NOT THREADSAFE
219 | char *stbi_failure_reason (void);
220 |
221 | // free the loaded image -- this is just free()
222 | void stbi_image_free (void *retval_from_stbi_load);
223 |
224 | // get image dimensions & components without fully decoding
225 | int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
226 | int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
227 | #ifndef STBI_NO_STDIO
228 | int stbi_info (char const *filename, int *x, int *y, int *comp);
229 | int stbi_is_hdr (char const *filename);
230 | int stbi_is_hdr_from_file(FILE *f);
231 | #endif
232 |
233 | // ZLIB client - used by PNG, available for other purposes
234 |
235 | char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
236 | char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
237 | int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
238 |
239 | char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
240 | int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
241 |
242 | // TYPE-SPECIFIC ACCESS
243 |
244 | // is it a jpeg?
245 | int stbi_jpeg_test_memory (stbi_uc const *buffer, int len);
246 | stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
247 | int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
248 |
249 | #ifndef STBI_NO_STDIO
250 | stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp);
251 | int stbi_jpeg_test_file (FILE *f);
252 | stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
253 |
254 | int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp);
255 | int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp);
256 | #endif
257 |
258 | // is it a png?
259 | int stbi_png_test_memory (stbi_uc const *buffer, int len);
260 | stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
261 | int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp);
262 |
263 | #ifndef STBI_NO_STDIO
264 | stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp);
265 | int stbi_png_info (char const *filename, int *x, int *y, int *comp);
266 | int stbi_png_test_file (FILE *f);
267 | stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
268 | int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp);
269 | #endif
270 |
271 | // is it a bmp?
272 | int stbi_bmp_test_memory (stbi_uc const *buffer, int len);
273 |
274 | stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp);
275 | stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
276 | #ifndef STBI_NO_STDIO
277 | int stbi_bmp_test_file (FILE *f);
278 | stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
279 | #endif
280 |
281 | // is it a tga?
282 | int stbi_tga_test_memory (stbi_uc const *buffer, int len);
283 |
284 | stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp);
285 | stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
286 | #ifndef STBI_NO_STDIO
287 | int stbi_tga_test_file (FILE *f);
288 | stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
289 | #endif
290 |
291 | // is it a psd?
292 | int stbi_psd_test_memory (stbi_uc const *buffer, int len);
293 |
294 | stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp);
295 | stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
296 | #ifndef STBI_NO_STDIO
297 | int stbi_psd_test_file (FILE *f);
298 | stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
299 | #endif
300 |
301 | // is it an hdr?
302 | int stbi_hdr_test_memory (stbi_uc const *buffer, int len);
303 |
304 | float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp);
305 | float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
306 | #ifndef STBI_NO_STDIO
307 | int stbi_hdr_test_file (FILE *f);
308 | float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
309 | #endif
310 |
311 | // define new loaders
312 | typedef struct
313 | {
314 | int (*test_memory)(stbi_uc const *buffer, int len);
315 | stbi_uc * (*load_from_memory)(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
316 | #ifndef STBI_NO_STDIO
317 | int (*test_file)(FILE *f);
318 | stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp);
319 | #endif
320 | } stbi_loader;
321 |
322 | // register a loader by filling out the above structure (you must defined ALL functions)
323 | // returns 1 if added or already added, 0 if not added (too many loaders)
324 | // NOT THREADSAFE
325 | int stbi_register_loader(stbi_loader *loader);
326 |
327 | // define faster low-level operations (typically SIMD support)
328 | #if STBI_SIMD
329 | typedef void (*stbi_idct_8x8)(uint8 *out, int out_stride, short data[64], unsigned short *dequantize);
330 | // compute an integer IDCT on "input"
331 | // input[x] = data[x] * dequantize[x]
332 | // write results to 'out': 64 samples, each run of 8 spaced by 'out_stride'
333 | // CLAMP results to 0..255
334 | typedef void (*stbi_YCbCr_to_RGB_run)(uint8 *output, uint8 const *y, uint8 const *cb, uint8 const *cr, int count, int step);
335 | // compute a conversion from YCbCr to RGB
336 | // 'count' pixels
337 | // write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B
338 | // y: Y input channel
339 | // cb: Cb input channel; scale/biased to be 0..255
340 | // cr: Cr input channel; scale/biased to be 0..255
341 |
342 | void stbi_install_idct(stbi_idct_8x8 func);
343 | void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func);
344 | #endif // STBI_SIMD
345 |
346 | #ifdef __cplusplus
347 | }
348 | #endif
349 |
350 | //
351 | //
352 | //// end header file /////////////////////////////////////////////////////
353 | #endif // STBI_INCLUDE_STB_IMAGE_H
354 |
--------------------------------------------------------------------------------
/include/utils/NativeSurfaceUtils.h:
--------------------------------------------------------------------------------
1 | #ifndef NATIVE_SURFACE_UTILS_H // !NATIVE_SURFACE_UTILS_H
2 | #define NATIVE_SURFACE_UTILS_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | #define ResolveMethod(ClassName, MethodName, Handle, MethodSignature) \
14 | ClassName##__##MethodName = \
15 | reinterpret_cast( \
16 | symbolMethod.Find(Handle, MethodSignature)); \
17 | if (nullptr == ClassName##__##MethodName) { \
18 | __android_log_print(ANDROID_LOG_ERROR, "ImGui", \
19 | "[-] Method not found: %s -> %s::%s", MethodSignature, \
20 | #ClassName, #MethodName); \
21 | }
22 |
23 | namespace android {
24 | namespace detail {
25 | namespace ui {
26 | struct LayerStack {
27 | uint32_t id =
28 | UINT32_MAX; // 图层是Z轴叠加的,声明我们的Z轴值为最大,surface就在最上层
29 | };
30 | // 这个枚举类是拿到设备类获取现在设备朝向使用的
31 | enum class Rotation {
32 | Rotation0 = 0,
33 | Rotation90 = 1,
34 | Rotation180 = 2,
35 | Rotation270 = 3
36 | };
37 | struct Size {
38 | int32_t width = -1;
39 | int32_t height = -1;
40 | };
41 | struct DisplayState {
42 | LayerStack layerStack;
43 | Rotation orientation = Rotation::Rotation0;
44 | Size layerStackSpaceRect;
45 | };
46 | typedef int64_t nsecs_t; // nano-seconds
47 |
48 | struct DisplayInfo {
49 | uint32_t w{0};
50 | uint32_t h{0};
51 | float xdpi{0};
52 | float ydpi{0};
53 | float fps{0};
54 | float density{0};
55 | uint8_t orientation{0};
56 | bool secure{false};
57 | nsecs_t appVsyncOffset{0};
58 | nsecs_t presentationDeadline{0};
59 | uint32_t viewportW{0};
60 | uint32_t viewportH{0};
61 | };
62 | enum class DisplayType { DisplayIdMain = 0,
63 | DisplayIdHdmi = 1 };
64 |
65 | struct PhysicalDisplayId {
66 | uint64_t value;
67 | };
68 | } // namespace ui
69 | struct String8; // 安卓创建surface传参surface窗口名需要string8格式的字符串
70 |
71 | struct LayerMetadata; // surface元数据,看源码就知道啦,创建surface需要传入这个
72 |
73 | struct Surface;
74 |
75 | struct SurfaceControl;
76 |
77 | struct SurfaceComposerClientTransaction;
78 |
79 | struct
80 | SurfaceComposerClient; // surface代理客户端,安卓的binder机制了解下就知道这个是干什么的
81 | template
82 | struct StrongPointer {
83 | union {
84 | any_t *pointer;
85 | char padding[sizeof(std::max_align_t)];
86 | };
87 |
88 | inline any_t *operator->() const {
89 | return pointer;
90 | }
91 |
92 | inline any_t *get() const {
93 | return pointer;
94 | }
95 |
96 | inline explicit operator bool() const {
97 | return nullptr != pointer;
98 | }
99 | };
100 |
101 | // 下面这个函数指针结构体是保存需要用到的函数指针,分别从/system/lib64/libutils.so和/system/lib64/libgui.so上拿到
102 | struct Functionals {
103 | struct SymbolMethod {
104 | void *(*Open)(const char *filename, int flag) = nullptr;
105 |
106 | void *(*Find)(void *handle, const char *symbol) = nullptr;
107 |
108 | int (*Close)(void *handle) = nullptr;
109 | };
110 |
111 | size_t systemVersion = 13;
112 |
113 | void (*RefBase__IncStrong)(void *thiz, void *id) = nullptr;
114 |
115 | void (*RefBase__DecStrong)(void *thiz, void *id) = nullptr;
116 |
117 | void (*String8__Constructor)(void *thiz, const char *const data) = nullptr;
118 |
119 | void (*String8__Destructor)(void *thiz) = nullptr;
120 |
121 | void (*LayerMetadata__Constructor)(void *thiz) = nullptr;
122 |
123 | void (*SurfaceComposerClient__Constructor)(void *thiz) = nullptr;
124 |
125 | void (*SurfaceComposerClient__Destructor)(void *thiz) = nullptr;
126 |
127 | StrongPointer (*SurfaceComposerClient__CreateSurface)(
128 | void *thiz, void *name, uint32_t w, uint32_t h, int32_t format,
129 | uint32_t flags, void *parentHandle, void *layerMetadata,
130 | uint32_t *outTransformHint) = nullptr;
131 |
132 | StrongPointer (*SurfaceComposerClient__GetInternalDisplayToken)() =
133 | nullptr;
134 |
135 | StrongPointer (*SurfaceComposerClient__GetBuiltInDisplay)(
136 | ui::DisplayType type) = nullptr;
137 |
138 | int32_t (*SurfaceComposerClient__GetDisplayState)(
139 | StrongPointer &display, ui::DisplayState *displayState) = nullptr;
140 |
141 | int32_t (*SurfaceComposerClient__GetDisplayInfo)(
142 | StrongPointer &display, ui::DisplayInfo *displayInfo) = nullptr;
143 |
144 | std::vector (
145 | *SurfaceComposerClient__GetPhysicalDisplayIds)() = nullptr;
146 |
147 | StrongPointer (*SurfaceComposerClient__GetPhysicalDisplayToken)(
148 | ui::PhysicalDisplayId displayId) = nullptr;
149 |
150 | void (*SurfaceComposerClient__Transaction__Constructor)(void *thiz) = nullptr;
151 |
152 | void *(*SurfaceComposerClient__Transaction__SetLayer)(
153 | void *thiz, StrongPointer &surfaceControl, int32_t z) = nullptr;
154 |
155 | void *(*SurfaceComposerClient__Transaction__SetTrustedOverlay)(
156 | void *thiz, StrongPointer &surfaceControl,
157 | bool isTrustedOverlay) = nullptr;
158 |
159 | int32_t (*SurfaceComposerClient__Transaction__Apply)(void *thiz,
160 | bool synchronous,
161 | bool oneWay) = nullptr;
162 |
163 | int32_t (*SurfaceControl__Validate)(void *thiz) = nullptr;
164 |
165 | StrongPointer (*SurfaceControl__GetSurface)(void *thiz) = nullptr;
166 |
167 | void (*SurfaceControl__DisConnect)(void *thiz) = nullptr;
168 |
169 | Functionals(const SymbolMethod &symbolMethod) {
170 | std::string systemVersionString(128, 0);
171 | systemVersionString.resize(__system_property_get(
172 | "ro.build.version.release", systemVersionString.data()));
173 | if (!systemVersionString.empty())
174 | systemVersion = std::stoi(systemVersionString);
175 |
176 | if (9 > systemVersion) {
177 | __android_log_print(ANDROID_LOG_ERROR, "ImGui",
178 | "[-] Unsupported system version: %zu", systemVersion);
179 | return;
180 | }
181 |
182 | static std::unordered_map>
183 | patchesTable = {
184 | {
185 | 15,
186 | {
187 | {reinterpret_cast(&LayerMetadata__Constructor),
188 | "_ZN7android3gui13LayerMetadataC2Ev"},
189 | {reinterpret_cast(
190 | &SurfaceComposerClient__CreateSurface),
191 | "_ZN7android21SurfaceComposerClient13createSurfaceERKNS_"
192 | "7String8EjjiiRKNS_2spINS_7IBinderEEENS_"
193 | "3gui13LayerMetadataEPj"},
194 | },
195 | },
196 | {
197 | 14,
198 | {
199 | {reinterpret_cast(&LayerMetadata__Constructor),
200 | "_ZN7android3gui13LayerMetadataC2Ev"},
201 | {reinterpret_cast(
202 | &SurfaceComposerClient__CreateSurface),
203 | "_ZN7android21SurfaceComposerClient13createSurfaceERKNS_"
204 | "7String8EjjiiRKNS_2spINS_7IBinderEEENS_"
205 | "3gui13LayerMetadataEPj"},
206 | },
207 | },
208 | {
209 | 12,
210 | {
211 | {reinterpret_cast(
212 | &SurfaceComposerClient__Transaction__Apply),
213 | "_ZN7android21SurfaceComposerClient11Transaction5applyEb"},
214 | },
215 | },
216 | {
217 | 11,
218 | {
219 | {reinterpret_cast(
220 | &SurfaceComposerClient__CreateSurface),
221 | "_ZN7android21SurfaceComposerClient13createSurfaceERKNS_"
222 | "7String8EjjijPNS_14SurfaceControlENS_13LayerMetadataEPj"},
223 | {reinterpret_cast(&SurfaceControl__GetSurface),
224 | "_ZNK7android14SurfaceControl10getSurfaceEv"},
225 | },
226 | },
227 | {
228 | 10,
229 | {
230 | {reinterpret_cast(
231 | &SurfaceComposerClient__CreateSurface),
232 | "_ZN7android21SurfaceComposerClient13createSurfaceERKNS_"
233 | "7String8EjjijPNS_14SurfaceControlENS_13LayerMetadataE"},
234 | {reinterpret_cast(&SurfaceControl__GetSurface),
235 | "_ZNK7android14SurfaceControl10getSurfaceEv"},
236 | },
237 | },
238 | {
239 | 9,
240 | {
241 | {reinterpret_cast(
242 | &SurfaceComposerClient__CreateSurface),
243 | "_ZN7android21SurfaceComposerClient13createSurfaceERKNS_"
244 | "7String8EjjijPNS_14SurfaceControlEii"},
245 | {reinterpret_cast(
246 | &SurfaceComposerClient__GetBuiltInDisplay),
247 | "_ZN7android21SurfaceComposerClient17getBuiltInDisplayEi"},
248 | {reinterpret_cast(&SurfaceControl__GetSurface),
249 | "_ZNK7android14SurfaceControl10getSurfaceEv"},
250 | },
251 | },
252 | };
253 |
254 | #ifdef __LP64__
255 | auto libgui = symbolMethod.Open("/system/lib64/libgui.so", RTLD_LAZY);
256 | auto libutils = symbolMethod.Open("/system/lib64/libutils.so", RTLD_LAZY);
257 | #else
258 | auto libgui = symbolMethod.Open("/system/lib/libgui.so", RTLD_LAZY);
259 | auto libutils = symbolMethod.Open("/system/lib/libutils.so", RTLD_LAZY);
260 | #endif
261 |
262 | ResolveMethod(RefBase, IncStrong, libutils,
263 | "_ZNK7android7RefBase9incStrongEPKv");
264 | ResolveMethod(RefBase, DecStrong, libutils,
265 | "_ZNK7android7RefBase9decStrongEPKv");
266 |
267 | ResolveMethod(String8, Constructor, libutils, "_ZN7android7String8C2EPKc");
268 | ResolveMethod(String8, Destructor, libutils, "_ZN7android7String8D2Ev");
269 |
270 | ResolveMethod(LayerMetadata, Constructor, libgui,
271 | "_ZN7android13LayerMetadataC2Ev");
272 |
273 | ResolveMethod(SurfaceComposerClient, Constructor, libgui,
274 | "_ZN7android21SurfaceComposerClientC2Ev");
275 | ResolveMethod(SurfaceComposerClient, CreateSurface, libgui,
276 | "_ZN7android21SurfaceComposerClient13createSurfaceERKNS_"
277 | "7String8EjjijRKNS_2spINS_7IBinderEEENS_13LayerMetadataEPj");
278 | ResolveMethod(
279 | SurfaceComposerClient, GetInternalDisplayToken, libgui,
280 | "_ZN7android21SurfaceComposerClient23getInternalDisplayTokenEv");
281 | ResolveMethod(SurfaceComposerClient, GetDisplayState, libgui,
282 | "_ZN7android21SurfaceComposerClient15getDisplayStateERKNS_"
283 | "2spINS_7IBinderEEEPNS_2ui12DisplayStateE");
284 | ResolveMethod(SurfaceComposerClient, GetDisplayInfo, libgui,
285 | "_ZN7android21SurfaceComposerClient14getDisplayInfoERKNS_"
286 | "2spINS_7IBinderEEEPNS_11DisplayInfoE");
287 | ResolveMethod(
288 | SurfaceComposerClient, GetPhysicalDisplayIds, libgui,
289 | "_ZN7android21SurfaceComposerClient21getPhysicalDisplayIdsEv");
290 | ResolveMethod(SurfaceComposerClient, GetPhysicalDisplayToken, libgui,
291 | "_ZN7android21SurfaceComposerClient23getPhysicalDisplayTokenE"
292 | "NS_17PhysicalDisplayIdE");
293 |
294 | ResolveMethod(SurfaceComposerClient__Transaction, Constructor, libgui,
295 | "_ZN7android21SurfaceComposerClient11TransactionC2Ev");
296 | ResolveMethod(SurfaceComposerClient__Transaction, SetLayer, libgui,
297 | "_ZN7android21SurfaceComposerClient11Transaction8setLayerERKN"
298 | "S_2spINS_14SurfaceControlEEEi");
299 | ResolveMethod(SurfaceComposerClient__Transaction, SetTrustedOverlay, libgui,
300 | "_ZN7android21SurfaceComposerClient11Transaction17setTrustedO"
301 | "verlayERKNS_2spINS_14SurfaceControlEEEb");
302 | ResolveMethod(SurfaceComposerClient__Transaction, Apply, libgui,
303 | "_ZN7android21SurfaceComposerClient11Transaction5applyEbb");
304 |
305 | ResolveMethod(SurfaceControl, Validate, libgui,
306 | "_ZNK7android14SurfaceControl8validateEv");
307 | ResolveMethod(SurfaceControl, GetSurface, libgui,
308 | "_ZN7android14SurfaceControl10getSurfaceEv");
309 | ResolveMethod(SurfaceControl, DisConnect, libgui,
310 | "_ZN7android14SurfaceControl10disconnectEv");
311 |
312 | if (patchesTable.contains(systemVersion)) {
313 | for (const auto &[patchTo, signature] : patchesTable.at(systemVersion)) {
314 | *patchTo = symbolMethod.Find(libgui, signature);
315 | if (nullptr != *patchTo)
316 | continue;
317 |
318 | __android_log_print(ANDROID_LOG_ERROR, "ImGui",
319 | "[-] Patch method not found: %s", signature);
320 | }
321 | }
322 |
323 | symbolMethod.Close(libutils);
324 | symbolMethod.Close(libgui);
325 | }
326 |
327 | // 这里是为了保证单例的C++设计模式,让类只能创建一份对象
328 | static const Functionals &
329 | GetInstance(const SymbolMethod &symbolMethod = {
330 | .Open = dlopen,
331 | .Find = dlsym,
332 | .Close = dlclose}) {
333 | static Functionals functionals(symbolMethod);
334 |
335 | return functionals;
336 | }
337 | };
338 |
339 | // 下面这个几个结构体都是抄安卓源码,这些都是在初始化surface需要传参的
340 | struct String8 {
341 | char data[1024];
342 |
343 | String8(const char *const string) {
344 | Functionals::GetInstance().String8__Constructor(data, string);
345 | }
346 |
347 | ~String8() {
348 | Functionals::GetInstance().String8__Destructor(data);
349 | }
350 |
351 | operator void *() {
352 | return reinterpret_cast(data);
353 | }
354 | };
355 |
356 | struct LayerMetadata {
357 | char data[1024];
358 |
359 | LayerMetadata() {
360 | if (9 < Functionals::GetInstance().systemVersion)
361 | Functionals::GetInstance().LayerMetadata__Constructor(data);
362 | }
363 |
364 | operator void *() {
365 | if (9 < Functionals::GetInstance().systemVersion)
366 | return reinterpret_cast(data);
367 | else
368 | return nullptr;
369 | }
370 | };
371 |
372 | struct Surface {};
373 |
374 | struct SurfaceControl {
375 | void *data;
376 |
377 | SurfaceControl() :
378 | data(nullptr) {
379 | }
380 |
381 | SurfaceControl(void *data) :
382 | data(data) {
383 | }
384 |
385 | int32_t Validate() {
386 | if (nullptr == data)
387 | return 0;
388 |
389 | return Functionals::GetInstance().SurfaceControl__Validate(data);
390 | }
391 |
392 | Surface *GetSurface() {
393 | if (nullptr == data)
394 | return nullptr;
395 |
396 | auto result = Functionals::GetInstance().SurfaceControl__GetSurface(data);
397 |
398 | return reinterpret_cast(
399 | reinterpret_cast(result.pointer) + sizeof(std::max_align_t) / 2);
400 | }
401 |
402 | void DisConnect() {
403 | if (nullptr == data)
404 | return;
405 |
406 | Functionals::GetInstance().SurfaceControl__DisConnect(data);
407 | }
408 |
409 | void DestroySurface(Surface *surface) {
410 | if (nullptr == data || nullptr == surface)
411 | return;
412 |
413 | Functionals::GetInstance().RefBase__DecStrong(
414 | reinterpret_cast(reinterpret_cast(surface) - sizeof(std::max_align_t) / 2),
415 | this);
416 | DisConnect();
417 | Functionals::GetInstance().RefBase__DecStrong(data, this);
418 | }
419 | };
420 |
421 | struct SurfaceComposerClientTransaction {
422 | char data[1024];
423 |
424 | SurfaceComposerClientTransaction() {
425 | Functionals::GetInstance().SurfaceComposerClient__Transaction__Constructor(
426 | data);
427 | }
428 |
429 | void *SetLayer(StrongPointer &surfaceControl, int32_t z) {
430 | return Functionals::GetInstance()
431 | .SurfaceComposerClient__Transaction__SetLayer(data, surfaceControl, z);
432 | }
433 |
434 | void *SetTrustedOverlay(StrongPointer &surfaceControl,
435 | bool isTrustedOverlay) {
436 | return Functionals::GetInstance()
437 | .SurfaceComposerClient__Transaction__SetTrustedOverlay(
438 | data, surfaceControl, isTrustedOverlay);
439 | }
440 |
441 | int32_t Apply(bool synchronous, bool oneWay) {
442 | if (12 >= Functionals::GetInstance().systemVersion)
443 | return reinterpret_cast(
444 | Functionals::GetInstance().SurfaceComposerClient__Transaction__Apply)(
445 | data, synchronous);
446 | else
447 | return Functionals::GetInstance()
448 | .SurfaceComposerClient__Transaction__Apply(data, synchronous, oneWay);
449 | }
450 | };
451 |
452 | struct SurfaceComposerClient {
453 | char data[1024];
454 |
455 | SurfaceComposerClient() {
456 | Functionals::GetInstance().SurfaceComposerClient__Constructor(data);
457 | Functionals::GetInstance().RefBase__IncStrong(data, this);
458 | }
459 |
460 | // public static final int SECURE = 0x00000080;
461 | // public static final int HIDDEN = 0x00000004;
462 | // 函数第二个参数pass_rec_select:0是0x40,1是0x81,2是不隐藏
463 | SurfaceControl CreateSurface(const char *name, int32_t width,
464 | int32_t height) {
465 | void *parentHandle = nullptr;
466 | String8 windowName(name);
467 | LayerMetadata layerMetadata;
468 | uint32_t flags = 0;
469 |
470 | if (12 <= Functionals::GetInstance().systemVersion) {
471 | static void *fakeParentHandleForBinder = nullptr;
472 | parentHandle = &fakeParentHandleForBinder;
473 | }
474 | static int HIDDEN = 0x00000004;
475 | static int SKIP_SCREENSHOT = 0x00000040;
476 | static int SECURE = 0x00000080;
477 | static int DISPLAY_DECORATION = 0x00000200;
478 | static int PROTECTED_APP = 0x00000800;
479 | static int SURFACE_HIDDEN = 0x01;
480 | static int eProtectedByDRM = 0x00001000;
481 |
482 | static int flag;
483 | // 判断过录屏 Android 10+
484 | // flag = SKIP_SCREENSHOT | eProtectedByDRM | SURFACE_HIDDEN |
485 | // PROTECTED_APP;
486 | flag = 0x0;
487 | auto result =
488 | Functionals::GetInstance().SurfaceComposerClient__CreateSurface(
489 | data, windowName, width + height, width + height, 1, flag,
490 | parentHandle, layerMetadata, nullptr);
491 |
492 | if (12 <= Functionals::GetInstance().systemVersion) {
493 | static SurfaceComposerClientTransaction transaction;
494 |
495 | transaction.SetTrustedOverlay(result, true);
496 | transaction.Apply(false, true);
497 | }
498 | return {result.get()};
499 | }
500 |
501 | bool GetDisplayInfo(ui::DisplayState *displayInfo) {
502 | StrongPointer defaultDisplay;
503 |
504 | if (9 >= Functionals::GetInstance().systemVersion)
505 | defaultDisplay =
506 | Functionals::GetInstance().SurfaceComposerClient__GetBuiltInDisplay(
507 | ui::DisplayType::DisplayIdMain);
508 | else {
509 | if (14 > Functionals::GetInstance().systemVersion)
510 | defaultDisplay = Functionals::GetInstance()
511 | .SurfaceComposerClient__GetInternalDisplayToken();
512 | else {
513 | auto displayIds = Functionals::GetInstance()
514 | .SurfaceComposerClient__GetPhysicalDisplayIds();
515 | if (displayIds.empty())
516 | return false;
517 |
518 | defaultDisplay =
519 | Functionals::GetInstance()
520 | .SurfaceComposerClient__GetPhysicalDisplayToken(displayIds[0]);
521 | }
522 | }
523 |
524 | if (nullptr == defaultDisplay.get())
525 | return false;
526 |
527 | if (11 <= Functionals::GetInstance().systemVersion)
528 | return 0 == Functionals::GetInstance().SurfaceComposerClient__GetDisplayState(defaultDisplay, displayInfo);
529 | else {
530 | ui::DisplayInfo realDisplayInfo{};
531 | if (0 != Functionals::GetInstance().SurfaceComposerClient__GetDisplayInfo(defaultDisplay, &realDisplayInfo))
532 | return false;
533 |
534 | displayInfo->layerStackSpaceRect.width = realDisplayInfo.w;
535 | displayInfo->layerStackSpaceRect.height = realDisplayInfo.h;
536 | displayInfo->orientation =
537 | static_cast(realDisplayInfo.orientation);
538 |
539 | return true;
540 | }
541 | }
542 | };
543 | } // namespace detail
544 |
545 | class ANativeWindowCreator {
546 | public:
547 | struct DisplayInfo {
548 | int32_t theta;
549 | int32_t width;
550 | int32_t height;
551 | };
552 |
553 | public:
554 | static detail::SurfaceComposerClient &GetComposerInstance() {
555 | static detail::SurfaceComposerClient surfaceComposerClient;
556 |
557 | return surfaceComposerClient;
558 | }
559 |
560 | static DisplayInfo GetDisplayInfo() {
561 | auto &surfaceComposerClient = GetComposerInstance();
562 | detail::ui::DisplayState displayInfo{};
563 |
564 | if (!surfaceComposerClient.GetDisplayInfo(&displayInfo))
565 | return {};
566 |
567 | return DisplayInfo{
568 | .theta = 90 * static_cast(displayInfo.orientation),
569 | .width = displayInfo.layerStackSpaceRect.width,
570 | .height = displayInfo.layerStackSpaceRect.height,
571 | };
572 | }
573 |
574 | static ANativeWindow *Create(const char *name, int32_t width = -1,
575 | int32_t height = -1) {
576 | auto &surfaceComposerClient = GetComposerInstance();
577 |
578 | while (-1 == width || -1 == height) {
579 | detail::ui::DisplayState displayInfo{};
580 |
581 | if (!surfaceComposerClient.GetDisplayInfo(&displayInfo))
582 | break;
583 |
584 | width = displayInfo.layerStackSpaceRect.width;
585 | height = displayInfo.layerStackSpaceRect.height;
586 | break;
587 | }
588 |
589 | auto surfaceControl =
590 | surfaceComposerClient.CreateSurface(name, width, height);
591 | auto nativeWindow =
592 | reinterpret_cast(surfaceControl.GetSurface());
593 |
594 | m_cachedSurfaceControl.emplace(nativeWindow, std::move(surfaceControl));
595 | return nativeWindow;
596 | }
597 |
598 | static void Destroy(ANativeWindow *nativeWindow) {
599 | if (!m_cachedSurfaceControl.count(nativeWindow))
600 | return;
601 |
602 | m_cachedSurfaceControl[nativeWindow].DestroySurface(
603 | reinterpret_cast(nativeWindow));
604 | m_cachedSurfaceControl.erase(nativeWindow);
605 | }
606 |
607 | private:
608 | inline static std::unordered_map
609 | m_cachedSurfaceControl;
610 | };
611 | } // namespace android
612 |
613 | #endif // !NATIVE_SURFACE_UTILS_H
--------------------------------------------------------------------------------
/include/utils/touch.h:
--------------------------------------------------------------------------------
1 | #include
2 | void Down(int Slot, int X, int Y);
3 | void Up(int id);
4 | void Move(int Slot, int X, int Y);
5 | void InitTouch(bool);
6 | void handleVolumeupEvent();
--------------------------------------------------------------------------------
/outputs/arm64-v8a/OSImGui:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Jiang-Night/OS-ImGui-Android/2ec468fa85d4462e7d13aa1cb63234efbcfa8e6d/outputs/arm64-v8a/OSImGui
--------------------------------------------------------------------------------
/src/OSImGui/OS-ImGui.cpp:
--------------------------------------------------------------------------------
1 |
2 | #pragma once
3 | #include "OS-ImGui.h"
4 | #include "OS-ImGui_Struct.h"
5 | #include "imgui_internal.h"
6 | #include "stb_image.h"
7 | #include
8 |
9 | namespace OSImGui {
10 | void OSImGui::Text(std::string Text, Vec2 Pos, ImColor Color, float FontSize) {
11 | float TextWidth = ImGui::GetFont()->CalcTextSizeA(FontSize, FLT_MAX, 0.f, Text.c_str()).x;
12 | ImVec2 Pos_ = {Pos.x - TextWidth / 2, Pos.y};
13 | ImGui::GetForegroundDrawList()->AddText(ImGui::GetFont(), FontSize, Pos_, Color, Text.c_str());
14 | }
15 |
16 | void OSImGui::StrokeText(std::string Text, Vec2 Pos, ImColor Color, float FontSize) {
17 | this->Text(Text, Vec2(Pos.x - 1, Pos.y + 1), ImColor(0, 0, 0), FontSize);
18 | this->Text(Text, Vec2(Pos.x - 1, Pos.y - 1), ImColor(0, 0, 0), FontSize);
19 | this->Text(Text, Vec2(Pos.x + 1, Pos.y + 1), ImColor(0, 0, 0), FontSize);
20 | this->Text(Text, Vec2(Pos.x + 1, Pos.y - 1), ImColor(0, 0, 0), FontSize);
21 | this->Text(Text, Pos, Color, FontSize);
22 | }
23 |
24 | void OSImGui::Rectangle(Vec2 Pos, Vec2 Size, ImColor Color, float Thickness, float Rounding) {
25 | ImGui::GetForegroundDrawList()->AddRect(Pos.ToImVec2(), (Pos + Size).ToImVec2(), Color, Rounding, 0, Thickness);
26 | }
27 |
28 | void OSImGui::RectangleFilled(Vec2 Pos, Vec2 Size, ImColor Color, float Rounding, int Nums) {
29 | ImDrawList *DrawList = ImGui::GetForegroundDrawList();
30 | ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All;
31 | ImVec2 a = Pos.ToImVec2();
32 | ImVec2 b = {Pos.x + Size.x, Pos.y + Size.y};
33 | Rounding = ImMin(Rounding, fabsf(Size.x) * (((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f) - 1.0f);
34 | Rounding = ImMin(Rounding, fabsf(Size.y) * (((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f) - 1.0f);
35 | if (Rounding <= 0.0f || rounding_corners == 0) {
36 | DrawList->PathLineTo(a);
37 | DrawList->PathLineTo(ImVec2(b.x, a.y));
38 | DrawList->PathLineTo(b);
39 | DrawList->PathLineTo(ImVec2(a.x, b.y));
40 | } else {
41 | DrawList->PathArcTo(ImVec2(a.x + Rounding, a.y + Rounding), Rounding, IM_PI, IM_PI / 2.f * 3.f, Nums);
42 | DrawList->PathArcTo(ImVec2(b.x - Rounding, a.y + Rounding), Rounding, IM_PI / 2.f * 3.f, IM_PI * 2.f, Nums);
43 | DrawList->PathArcTo(ImVec2(b.x - Rounding, b.y - Rounding), Rounding, 0.f, IM_PI / 2.f, Nums);
44 | DrawList->PathArcTo(ImVec2(a.x + Rounding, b.y - Rounding), Rounding, IM_PI / 2.f, IM_PI, Nums);
45 | }
46 | DrawList->PathFillConvex(Color);
47 | }
48 |
49 | void OSImGui::HollowRect(Vec4 Pos, ImColor color, float thickness) {
50 | int iw = Pos.w / 4;
51 | int ih = Pos.h / 4;
52 | // top
53 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x, Pos.y), ImVec2(Pos.x + iw, Pos.y), color, thickness); // left
54 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x + Pos.w - iw, Pos.y), ImVec2(Pos.x + Pos.w, Pos.y), color, thickness); // right
55 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x, Pos.y), ImVec2(Pos.x, Pos.y + ih), color, thickness); // top left
56 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x + Pos.w - 1, Pos.y), ImVec2(Pos.x + Pos.w - 1, Pos.y + ih), color, thickness); // top right
57 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x, Pos.y + Pos.h), ImVec2(Pos.x + iw, Pos.y + Pos.h), color, thickness); // left
58 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x + Pos.w - iw, Pos.y + Pos.h), ImVec2(Pos.x + Pos.w, Pos.y + Pos.h), color, thickness); // right
59 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x, Pos.y + Pos.h - ih), ImVec2(Pos.x, Pos.y + Pos.h), color, thickness); // bottom left
60 | ImGui::GetForegroundDrawList()->AddLine(ImVec2(Pos.x + Pos.w - 1, Pos.y + Pos.h - ih), ImVec2(Pos.x + Pos.w - 1, Pos.y + Pos.h), color, thickness); // bottom right
61 | }
62 |
63 | void OSImGui::Line(Vec2 From, Vec2 To, ImColor Color, float Thickness) {
64 | ImGui::GetForegroundDrawList()->AddLine(From.ToImVec2(), To.ToImVec2(), Color, Thickness);
65 | }
66 |
67 | void OSImGui::Circle(Vec2 Center, float Radius, ImColor Color, float Thickness, int Num) {
68 | ImGui::GetForegroundDrawList()->AddCircle(Center.ToImVec2(), Radius, Color, Num, Thickness);
69 | }
70 | void OSImGui::CircleFilled(Vec2 Center, float Radius, ImColor Color, int Num) {
71 | ImGui::GetForegroundDrawList()->AddCircleFilled(Center.ToImVec2(), Radius, Color, Num);
72 | }
73 |
74 | void OSImGui::ConnectPoints(std::vector Points, ImColor Color, float Thickness) {
75 | if (Points.size() <= 0)
76 | return;
77 | for (int i = 0; i < Points.size() - 1; i++) {
78 | Line(Points[i], Points[i + 1], Color, Thickness);
79 | if (i == Points.size() - 2)
80 | Line(Points[i + 1], Points[0], Color, Thickness);
81 | }
82 | }
83 |
84 | void OSImGui::Arc(ImVec2 Center, float Radius, ImColor Color, float Thickness, float Angle_begin, float Angle_end, float Nums) {
85 | ImDrawList *DrawList = ImGui::GetForegroundDrawList();
86 | float angle = (Angle_end - Angle_begin) / Nums;
87 | for (int i = 0; i < Nums; i++) {
88 | float angle_ = i * angle + Angle_begin - IM_PI / 2;
89 | DrawList->PathLineTo({Center.x - Radius * cos(angle_), Center.y - Radius * sin(angle_)});
90 | }
91 | DrawList->PathStroke(Color, false, Thickness);
92 | }
93 | void OSImGui::MyCheckBox(const char *str_id, bool *v) {
94 | ImVec2 p = ImGui::GetCursorScreenPos();
95 | ImDrawList *DrawList = ImGui::GetWindowDrawList();
96 | float Height = ImGui::GetFrameHeight();
97 | float Width = Height * 1.7f;
98 | float Radius = Height / 2 - 2;
99 |
100 | ImGui::InvisibleButton(str_id, ImVec2(Width, Height));
101 | if (ImGui::IsItemClicked())
102 | *v = !(*v);
103 | // 组件移动动画
104 | float t = *v ? 1.0f : 0.f;
105 | ImGuiContext &g = *GImGui;
106 | float AnimationSpeed = 0.08f;
107 | if (g.LastActiveId == g.CurrentWindow->GetID(str_id)) {
108 | float T_Animation = ImSaturate(g.LastActiveIdTimer / AnimationSpeed);
109 | t = *v ? (T_Animation) : (1.0f - T_Animation);
110 | }
111 | // 鼠标悬停颜色
112 | ImU32 Color;
113 | if (ImGui::IsItemHovered())
114 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.85f, 0.24f, 0.15f, 1.0f), ImVec4(0.55f, 0.85f, 0.13f, 1.000f), t));
115 | else
116 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.90f, 0.29f, 0.20f, 1.0f), ImVec4(0.60f, 0.90f, 0.18f, 1.000f), t));
117 | // 组件绘制
118 | DrawList->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + Width, p.y + Height), Color, Height);
119 | DrawList->AddCircleFilled(ImVec2(p.x + Radius + t * (Width - Radius * 2) + (t == 0 ? 2 : -2), p.y + Radius + 2), Radius, IM_COL32(255, 255, 255, 255), 360);
120 | DrawList->AddCircle(ImVec2(p.x + Radius + t * (Width - Radius * 2) + (t == 0 ? 2 : -2), p.y + Radius + 2), Radius, IM_COL32(20, 20, 20, 80), 360, 1);
121 |
122 | ImGui::SameLine();
123 | ImGui::Text(str_id);
124 | }
125 |
126 | void OSImGui::MyCheckBox2(const char *str_id, bool *v) {
127 | ImVec2 p = ImGui::GetCursorScreenPos();
128 | ImDrawList *DrawList = ImGui::GetWindowDrawList();
129 | float Height = ImGui::GetFrameHeight();
130 | float Width = Height * 1.7f;
131 | float Radius = Height / 2 - 2;
132 |
133 | ImGui::InvisibleButton(str_id, ImVec2(Width, Height));
134 | if (ImGui::IsItemClicked())
135 | *v = !(*v);
136 | // 组件移动动画
137 | float t = *v ? 1.0f : 0.f;
138 | ImGuiContext &g = *GImGui;
139 | float AnimationSpeed = 0.15f;
140 | if (g.LastActiveId == g.CurrentWindow->GetID(str_id)) {
141 | float T_Animation = ImSaturate(g.LastActiveIdTimer / AnimationSpeed);
142 | t = *v ? (T_Animation) : (1.0f - T_Animation);
143 | }
144 | // 鼠标悬停颜色
145 | ImU32 Color;
146 | if (ImGui::IsItemHovered())
147 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.08f, 0.18f, 0.21f, 1.0f), ImVec4(0.10f, 0.48f, 0.68f, 1.000f), t));
148 | else
149 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.12f, 0.22f, 0.25f, 1.0f), ImVec4(0.14f, 0.52f, 0.72f, 1.000f), t));
150 | // 组件绘制
151 | DrawList->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + Width, p.y + Height), Color, 360);
152 | DrawList->AddCircleFilled(ImVec2(p.x + Radius + 2 + t * (Width - (Radius + 2) * 2), p.y + Radius + 2), Radius + 2, IM_COL32(255, 255, 255, 255), 360);
153 | DrawList->AddCircleFilled(ImVec2(p.x + Radius + t * (Width - Radius * 2) + (t == 0 ? 2 : -2), p.y + Radius + 2), Radius, IM_COL32(230, 230, 230, 255), 360);
154 | if (*v)
155 | DrawList->AddText(ImVec2(p.x + 45, p.y + 2), ImColor{255, 255, 255, 255}, str_id);
156 | else
157 | DrawList->AddText(ImVec2(p.x + 45, p.y + 2), ImColor{185, 185, 185, 255}, str_id);
158 | }
159 |
160 | void OSImGui::MyCheckBox3(const char *str_id, bool *v) {
161 | ImVec2 p = ImGui::GetCursorScreenPos();
162 | ImDrawList *DrawList = ImGui::GetWindowDrawList();
163 | float Height = ImGui::GetFrameHeight();
164 | float Width = Height;
165 | float Left = 8;
166 | float Right = Left * 1.5f;
167 | ImGui::InvisibleButton(str_id, ImVec2(Width, Height));
168 |
169 | if (ImGui::IsItemClicked())
170 | *v = !(*v);
171 | // 组件移动动画
172 | float t = *v ? 1.0f : 0.f;
173 | ImGuiContext &g = *GImGui;
174 | float AnimationSpeed = 0.12f;
175 | if (g.LastActiveId == g.CurrentWindow->GetID(str_id)) {
176 | float T_Animation = ImSaturate(g.LastActiveIdTimer / AnimationSpeed);
177 | t = *v ? (T_Animation) : (1.0f - T_Animation);
178 | }
179 | // 鼠标悬停颜色
180 | ImU32 Color;
181 | ImU32 TickColor1, TickColor2;
182 | if (ImGui::IsItemHovered())
183 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.75f, 0.75f, 0.75f, 1.0f), ImVec4(0.05f, 0.85f, 0.25f, 1.000f), t));
184 | else
185 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.8f, 0.8f, 0.8f, 1.0f), ImVec4(0.1f, 0.9f, 0.3f, 1.000f), t));
186 |
187 | TickColor1 = IM_COL32(255, 255, 255, 255 * t);
188 | TickColor2 = IM_COL32(180, 180, 180, 255 * (1 - t));
189 |
190 | float Size = Width;
191 | float Scale = (float)(Size) / 20.0f;
192 | // 底色
193 | DrawList->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + Width, p.y + Height), Color, 5, 15);
194 | // 选中勾
195 | DrawList->AddLine(ImVec2(p.x + 3 * Scale, p.y + Size / 2 - 2 * Scale), ImVec2(p.x + Size / 2 - 1 * Scale, p.y + Size - 5 * Scale), TickColor1, 3 * Scale);
196 | DrawList->AddLine(ImVec2(p.x + Size - 3 * Scale - 1, p.y + 3 * Scale + 1), ImVec2(p.x + Size / 2 - 1 * Scale, p.y + Size - 5 * Scale), TickColor1, 3 * Scale);
197 | // 未选中勾
198 | DrawList->AddLine(ImVec2(p.x + 3 * Scale, p.y + Size / 2 - 2 * Scale), ImVec2(p.x + Size / 2 - 1 * Scale, p.y + Size - 5 * Scale), TickColor2, 3 * Scale);
199 | DrawList->AddLine(ImVec2(p.x + Size - 3 * Scale - 1, p.y + 3 * Scale + 1), ImVec2(p.x + Size / 2 - 1 * Scale, p.y + Size - 5 * Scale), TickColor2, 3 * Scale);
200 | ImGui::SameLine();
201 | ImGui::Text(str_id);
202 | }
203 |
204 | void OSImGui::MyCheckBox4(const char *str_id, bool *v) {
205 | ImVec2 p = ImGui::GetCursorScreenPos();
206 | ImDrawList *DrawList = ImGui::GetWindowDrawList();
207 | float Height = ImGui::GetFrameHeight();
208 | float Width = Height;
209 | ImGui::InvisibleButton(str_id, ImVec2(Width, Height));
210 |
211 | if (ImGui::IsItemClicked())
212 | *v = !(*v);
213 | // 组件动画
214 | float t = *v ? 1.0f : 0.f;
215 | ImGuiContext &g = *GImGui;
216 | float AnimationSpeed = 0.12f;
217 | if (g.LastActiveId == g.CurrentWindow->GetID(str_id)) {
218 | float T_Animation = ImSaturate(g.LastActiveIdTimer / AnimationSpeed);
219 | t = *v ? (T_Animation) : (1.0f - T_Animation);
220 | }
221 | // bg 0.74 0.72 0.81-> 0.69 0.77 0.76
222 | ImU32 BgColor;
223 | if (ImGui::IsItemHovered())
224 | BgColor = ImGui::GetColorU32(ImVec4(0.69f, 0.69f, 0.69f, 1.0f));
225 | else
226 | BgColor = ImGui::GetColorU32(ImVec4(0.74f, 0.74f, 0.74f, 1.0f));
227 | DrawList->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + Width, p.y + Width), BgColor);
228 |
229 | ImU32 FrColor;
230 | FrColor = ImGui::GetColorU32(ImVec4(0.f, 0.f, 0.f, 0.5f * t));
231 | DrawList->AddRectFilled(ImVec2(p.x + Width / 5, p.y + Width / 5), ImVec2(p.x + Width - Width / 5, p.y + Width - Width / 5), FrColor);
232 |
233 | ImGui::SameLine();
234 | ImGui::Text(str_id);
235 | }
236 | void OSImGui::HalfCircle(Vec2 Pos, float radius, ImVec4 color, int segments, int thickness, float arc_degree) {
237 | ImGui::GetForegroundDrawList()->AddHalfCircle(ImVec2(Pos.x, Pos.y), radius, ImGui::ColorConvertFloat4ToU32(color), segments, thickness, arc_degree);
238 | }
239 |
240 | void OSImGui::Image(Vec2 Pos, int w, int h, ImTextureID Texture) {
241 | ImGui::GetForegroundDrawList()->AddImage(Texture, ImVec2(Pos.x, Pos.y), ImVec2(Pos.x + w, Pos.y + h));
242 | }
243 |
244 | void OSImGui::Watermark(std::string licenseKey) {
245 | ImGuiIO &io = ImGui::GetIO();
246 | ImGuiWindow *window = ImGui::GetCurrentWindow();
247 | // 获取当前窗口的位置和大小
248 | ImVec2 window_pos = ImGui::GetWindowPos();
249 | ImVec2 window_size = ImGui::GetWindowSize();
250 | // 设置文本颜色
251 | ImU32 text_color = IM_COL32(128, 128, 128, 200);
252 | // 设置文本大小
253 | window->DrawList->PushTextureID(io.Fonts->TexID);
254 | window->DrawList->PushClipRectFullScreen();
255 | // 计算文字宽高
256 | ImVec2 textSize = ImGui::CalcTextSize(licenseKey.c_str());
257 | float textWidth = textSize.x;
258 | float textHeight = textSize.y;
259 | // 设置文本间距
260 | float padding = 60.0f;
261 | // 绘制在ImGui窗口背景上
262 | for (float x = padding; x < window_size.x; x += textWidth + padding) {
263 | for (float y = padding; y < window_size.y; y += textHeight + padding) {
264 | ImVec2 watermarkPos = ImVec2(window_pos.x + x, window_pos.y + y);
265 | // 检查文本是否超出窗口范围
266 | if (watermarkPos.x + textWidth <= window_pos.x + window_size.x && watermarkPos.y + textHeight <= window_pos.y + window_size.y) {
267 | window->DrawList->AddText(watermarkPos, text_color, licenseKey.c_str());
268 | }
269 | }
270 | }
271 | // 恢复裁剪区域
272 | window->DrawList->PopClipRect();
273 | }
274 |
275 | void OSImGui::OutlineBox(int x, int y, int w, int h, ImVec4 color, float thickness) {
276 | this->Rectangle(Vec2{x, y}, Vec2{w, h}, ImVec4(0.f, 0.f, 0.f, 1.f), thickness);
277 | this->Rectangle(Vec2{x + 1, y + 1}, Vec2{w - 2, h - 2}, color, thickness);
278 | this->Rectangle(Vec2{x + 2, y + 2}, Vec2{w - 4, h - 4}, ImVec4(0.f, 0.f, 0.f, 1.f), thickness);
279 | }
280 |
281 | bool OSImGui::SwitchForLeft(const char *str_id, bool *v) {
282 | ImVec2 p = ImGui::GetCursorScreenPos();
283 | ImDrawList *DrawList = ImGui::GetWindowDrawList();
284 | float Height = ImGui::GetFrameHeight();
285 | float Width = Height * 1.7f;
286 | float Radius = Height / 2 - 2;
287 |
288 | ImGui::InvisibleButton(str_id, ImVec2(Width, Height));
289 |
290 | if (ImGui::IsItemClicked())
291 | *v = !(*v);
292 |
293 | // 组件移动动画
294 | float t = *v ? 1.0f : 0.f;
295 | ImGuiContext &g = *GImGui;
296 | float AnimationSpeed = 0.08f;
297 | if (g.LastActiveId == g.CurrentWindow->GetID(str_id)) {
298 | float T_Animation = ImSaturate(g.LastActiveIdTimer / AnimationSpeed);
299 | t = *v ? (T_Animation) : (1.0f - T_Animation);
300 | }
301 |
302 | // 鼠标悬停颜色
303 | ImU32 Color;
304 | if (ImGui::IsItemHovered())
305 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.85f, 0.24f, 0.15f, 1.0f), ImVec4(0.55f, 0.85f, 0.13f, 1.000f), t));
306 | else
307 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.90f, 0.29f, 0.20f, 1.0f), ImVec4(0.60f, 0.90f, 0.18f, 1.000f), t));
308 |
309 | // 组件绘制
310 | DrawList->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + Width, p.y + Height), Color, Height);
311 | DrawList->AddCircleFilled(ImVec2(p.x + Radius + t * (Width - Radius * 2) + (t == 0 ? 2 : -2), p.y + Radius + 2), Radius, IM_COL32(255, 255, 255, 255), 360);
312 | DrawList->AddCircle(ImVec2(p.x + Radius + t * (Width - Radius * 2) + (t == 0 ? 2 : -2), p.y + Radius + 2), Radius, IM_COL32(20, 20, 20, 80), 360, 1);
313 |
314 | ImGui::SameLine();
315 | ImGui::Text(str_id);
316 |
317 | return *v; // 返回复选框是否被点击
318 | }
319 |
320 | bool OSImGui::SwitchForRight(const char *str_id, bool *v) {
321 | ImGui::Text(str_id); // 先绘制文本
322 |
323 | ImGui::SameLine(0, 140); // 保持水平布局
324 |
325 | ImVec2 p = ImGui::GetCursorScreenPos();
326 | ImDrawList *DrawList = ImGui::GetWindowDrawList();
327 | float Height = ImGui::GetFrameHeight();
328 | float Width = Height * 1.7f;
329 | float Radius = Height / 2 - 2;
330 |
331 | ImGui::InvisibleButton(str_id, ImVec2(Width, Height));
332 |
333 | if (ImGui::IsItemClicked())
334 | *v = !(*v);
335 |
336 | // 组件移动动画
337 | float t = *v ? 1.0f : 0.f;
338 | ImGuiContext &g = *GImGui;
339 | float AnimationSpeed = 0.08f;
340 | if (g.LastActiveId == g.CurrentWindow->GetID(str_id)) {
341 | float T_Animation = ImSaturate(g.LastActiveIdTimer / AnimationSpeed);
342 | t = *v ? (T_Animation) : (1.0f - T_Animation);
343 | }
344 |
345 | // 鼠标悬停颜色
346 | ImU32 Color;
347 | if (ImGui::IsItemHovered())
348 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.85f, 0.24f, 0.15f, 1.0f), ImVec4(0.55f, 0.85f, 0.13f, 1.000f), t));
349 | else
350 | Color = ImGui::GetColorU32(ImLerp(ImVec4(0.90f, 0.29f, 0.20f, 1.0f), ImVec4(0.60f, 0.90f, 0.18f, 1.000f), t));
351 |
352 | // 组件绘制
353 | DrawList->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + Width, p.y + Height), Color, Height);
354 | DrawList->AddCircleFilled(ImVec2(p.x + Radius + t * (Width - Radius * 2) + (t == 0 ? 2 : -2), p.y + Radius + 2), Radius, IM_COL32(255, 255, 255, 255), 360);
355 | DrawList->AddCircle(ImVec2(p.x + Radius + t * (Width - Radius * 2) + (t == 0 ? 2 : -2), p.y + Radius + 2), Radius, IM_COL32(20, 20, 20, 80), 360, 1);
356 |
357 | return *v; // 返回复选框是否被点击
358 | }
359 |
360 | ImTextureID OSImGui::createTexturePNGFromMem(unsigned char *buf, int len) {
361 | int w, h, n;
362 | stbi_uc *data = stbi_png_load_from_memory(buf, len, &w, &h, &n, 0);
363 | GLuint texture;
364 | glGenTextures(1, &texture);
365 | glEnable(GL_TEXTURE_2D);
366 | glBindTexture(GL_TEXTURE_2D, texture);
367 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
368 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
369 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
370 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
371 | if (n == 3) {
372 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE,
373 | data);
374 | } else {
375 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
376 | data);
377 | }
378 | stbi_image_free(data);
379 |
380 | return (ImTextureID)texture;
381 | }
382 |
383 | } // namespace OSImGui
384 |
--------------------------------------------------------------------------------
/src/OSImGui/OS-ImGui_Base.cpp:
--------------------------------------------------------------------------------
1 | #include "OS-ImGui_Base.h"
2 | #include "NativeSurfaceUtils.h"
3 | #include "OS-ImGui_Exception.hpp"
4 | #include "font.h"
5 | #include "imgui.h"
6 | #include "imgui_impl_android.h"
7 | #include "imgui_impl_opengl3.h"
8 | #include "touch.h"
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | int screen_x, screen_y, Orientation, touchScreenX, touchScreenY, _ScreenX, _ScreenY;
15 |
16 | namespace OSImGui {
17 |
18 | EGLDisplay m_EglDisplay = EGL_NO_DISPLAY;
19 | EGLSurface m_EglSurface = EGL_NO_SURFACE;
20 | EGLContext m_EglContext = EGL_NO_CONTEXT;
21 |
22 | bool CreateOpenGLWindow(ANativeWindow *m_Window) {
23 | const EGLint egl_attributes[] = {EGL_BLUE_SIZE,
24 | 8,
25 | EGL_GREEN_SIZE,
26 | 8,
27 | EGL_RED_SIZE,
28 | 8,
29 | EGL_ALPHA_SIZE,
30 | 8,
31 | EGL_DEPTH_SIZE,
32 | 16,
33 | EGL_RENDERABLE_TYPE,
34 | EGL_OPENGL_ES3_BIT,
35 | EGL_SURFACE_TYPE,
36 | EGL_WINDOW_BIT,
37 | EGL_NONE};
38 |
39 | m_EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
40 | eglInitialize(m_EglDisplay, nullptr, nullptr);
41 | EGLint num_configs = 0;
42 | eglChooseConfig(m_EglDisplay, egl_attributes, nullptr, 0, &num_configs);
43 | EGLConfig egl_config;
44 | eglChooseConfig(m_EglDisplay, egl_attributes, &egl_config, 1, &num_configs);
45 | EGLint egl_format;
46 | eglGetConfigAttrib(m_EglDisplay, egl_config, EGL_NATIVE_VISUAL_ID,
47 | &egl_format);
48 | ANativeWindow_setBuffersGeometry(m_Window, 0, 0, egl_format);
49 |
50 | const EGLint egl_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 3,
51 | EGL_NONE};
52 | m_EglContext = eglCreateContext(m_EglDisplay, egl_config, EGL_NO_CONTEXT,
53 | egl_context_attributes);
54 | m_EglSurface =
55 | eglCreateWindowSurface(m_EglDisplay, egl_config, m_Window, nullptr);
56 | eglMakeCurrent(m_EglDisplay, m_EglSurface, m_EglSurface, m_EglContext);
57 | glClearColor(0.0, 0.0, 0.0, 0.0);
58 | return true;
59 | }
60 |
61 | void updateScreen() {
62 | android::detail::ui::DisplayState info;
63 | static android::detail::SurfaceComposerClient client;
64 | client.GetDisplayInfo(&info);
65 | screen_x = info.layerStackSpaceRect.width;
66 | screen_y = info.layerStackSpaceRect.height;
67 | touchScreenX = std::min(screen_x, screen_y);
68 | touchScreenY = std::max(screen_x, screen_y);
69 | _ScreenX = std::max(screen_x, screen_y) / 2;
70 | _ScreenY = std::min(screen_x, screen_y) / 2;
71 | switch (info.orientation) {
72 | case android::detail::ui::Rotation::Rotation0:
73 | Orientation = 0;
74 | break;
75 | case android::detail::ui::Rotation::Rotation90:
76 | Orientation = 1;
77 | break;
78 | case android::detail::ui::Rotation::Rotation180:
79 | Orientation = 2;
80 | break;
81 | case android::detail::ui::Rotation::Rotation270:
82 | Orientation = 3;
83 | break;
84 | }
85 | }
86 |
87 | bool OSImGui_Base::InitImGui(ANativeWindow *SurfaceWindow) {
88 | ANativeWindow_acquire(SurfaceWindow);
89 | CreateOpenGLWindow(SurfaceWindow);
90 | IMGUI_CHECKVERSION();
91 | ImGui::CreateContext();
92 | ImGuiStyle *style = &ImGui::GetStyle();
93 | ImGui::StyleColorsClassic(style);
94 | ImGuiIO &io = ImGui::GetIO();
95 | io.IniFilename = nullptr;
96 | io.LogFilename = nullptr;
97 | io.FontGlobalScale = 1.3f;
98 | ImFont *font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(
99 | font_compressed_data_base85, 36.f, nullptr,
100 | io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
101 | IM_ASSERT(font != NULL);
102 | ImGui::GetStyle().ScaleAllSizes(3.0f);
103 |
104 | if (!ImGui_ImplOpenGL3_Init("#version 300 es"))
105 | throw OSException("ImGui_ImplOpenGL3_Init call failed.");
106 |
107 | if (!ImGui_ImplAndroid_Init(SurfaceWindow))
108 | throw OSException("ImGui_ImplAndroid_Init call failed.");
109 |
110 | return true;
111 | }
112 |
113 | void OSImGui_Base::CleanImGui() {
114 | ImGui_ImplOpenGL3_Shutdown();
115 | ImGui_ImplAndroid_Shutdown();
116 | eglMakeCurrent(m_EglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
117 | eglDestroyContext(m_EglDisplay, m_EglContext);
118 | eglDestroySurface(m_EglDisplay, m_EglSurface);
119 | eglTerminate(m_EglDisplay);
120 | m_EglDisplay = EGL_NO_DISPLAY;
121 | m_EglSurface = EGL_NO_SURFACE;
122 | m_EglContext = EGL_NO_CONTEXT;
123 | }
124 |
125 | void OSImGui_Base::NewWindow(std::string WindowName,
126 | std::function CallBack,
127 | std::function TextureCallBack) {
128 | std::string WName;
129 |
130 | if (!CallBack)
131 | throw OSException("CallBack is not null");
132 |
133 | if (WindowName.empty())
134 | throw OSException("WindowName is empty");
135 |
136 | this->CallBackFn = CallBack;
137 |
138 | Surface.InitSurfaceWindow(WName);
139 |
140 | if (!Surface.GetSurfaceWindow())
141 | throw OSException("Create Window Error");
142 |
143 | try {
144 | InitImGui(Surface.GetSurfaceWindow());
145 | } catch (OSException e) {
146 | throw e;
147 | }
148 |
149 | updateScreen();
150 | InitTouch(false);
151 |
152 | if (TextureCallBack) {
153 | this->TextureCallBackFn = TextureCallBack;
154 | this->TextureCallBackFn();
155 | }
156 |
157 | MainLoop();
158 | }
159 |
160 | void OSImGui_Base::MainLoop() {
161 | while (!EndFlags) {
162 | updateScreen();
163 | glViewport(0, 0, (int)screen_x, (int)screen_y);
164 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
165 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
166 | ImGui_ImplOpenGL3_NewFrame();
167 | ImGui_ImplAndroid_NewFrame();
168 | ImGui::NewFrame();
169 |
170 | this->CallBackFn();
171 |
172 | ImGui::Render();
173 | glClear(GL_COLOR_BUFFER_BIT);
174 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
175 | eglSwapBuffers(m_EglDisplay, m_EglSurface);
176 | }
177 | CleanImGui();
178 | }
179 |
180 | NativeWindows::NativeWindows() {
181 | // TODO 暂时还不知道写什么 先放着
182 | }
183 |
184 | void NativeWindows::InitSurfaceWindow(std::string Name) {
185 | this->SurfaceWindow = android::ANativeWindowCreator::Create(Name.c_str());
186 | }
187 |
188 | NativeWindows::~NativeWindows() {
189 | if (SurfaceWindow)
190 | android::ANativeWindowCreator::Destroy(SurfaceWindow);
191 | }
192 |
193 | } // namespace OSImGui
--------------------------------------------------------------------------------
/src/imgui/imgui_impl_android.cpp:
--------------------------------------------------------------------------------
1 | // dear imgui: Platform Binding for Android native app
2 | // This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
3 |
4 | // Implemented features:
5 | // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
6 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen.
7 | // Missing features:
8 | // [ ] Platform: Clipboard support.
9 | // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
10 | // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
11 | // Important:
12 | // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
13 | // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
14 | // - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
15 |
16 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
17 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
18 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
19 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
20 |
21 | // CHANGELOG
22 | // (minor and older changes stripped away, please see git history for details)
23 | // 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
24 | // 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
25 | // 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
26 | // 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
27 | // 2021-03-04: Initial version.
28 |
29 | #include "imgui.h"
30 | #ifndef IMGUI_DISABLE
31 | #include "imgui_impl_android.h"
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | // Android data
39 | static double g_Time = 0.0;
40 | static ANativeWindow* g_Window;
41 | static char g_LogTag[] = "ImGuiExample";
42 |
43 | static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code)
44 | {
45 | switch (key_code)
46 | {
47 | case AKEYCODE_TAB: return ImGuiKey_Tab;
48 | case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow;
49 | case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow;
50 | case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow;
51 | case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow;
52 | case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp;
53 | case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown;
54 | case AKEYCODE_MOVE_HOME: return ImGuiKey_Home;
55 | case AKEYCODE_MOVE_END: return ImGuiKey_End;
56 | case AKEYCODE_INSERT: return ImGuiKey_Insert;
57 | case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete;
58 | case AKEYCODE_DEL: return ImGuiKey_Backspace;
59 | case AKEYCODE_SPACE: return ImGuiKey_Space;
60 | case AKEYCODE_ENTER: return ImGuiKey_Enter;
61 | case AKEYCODE_ESCAPE: return ImGuiKey_Escape;
62 | case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
63 | case AKEYCODE_COMMA: return ImGuiKey_Comma;
64 | case AKEYCODE_MINUS: return ImGuiKey_Minus;
65 | case AKEYCODE_PERIOD: return ImGuiKey_Period;
66 | case AKEYCODE_SLASH: return ImGuiKey_Slash;
67 | case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon;
68 | case AKEYCODE_EQUALS: return ImGuiKey_Equal;
69 | case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket;
70 | case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash;
71 | case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket;
72 | case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent;
73 | case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock;
74 | case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock;
75 | case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock;
76 | case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen;
77 | case AKEYCODE_BREAK: return ImGuiKey_Pause;
78 | case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0;
79 | case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1;
80 | case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2;
81 | case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3;
82 | case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4;
83 | case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5;
84 | case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6;
85 | case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7;
86 | case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8;
87 | case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9;
88 | case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal;
89 | case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide;
90 | case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply;
91 | case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract;
92 | case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd;
93 | case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter;
94 | case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual;
95 | case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl;
96 | case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift;
97 | case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt;
98 | case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper;
99 | case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl;
100 | case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift;
101 | case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt;
102 | case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper;
103 | case AKEYCODE_MENU: return ImGuiKey_Menu;
104 | case AKEYCODE_0: return ImGuiKey_0;
105 | case AKEYCODE_1: return ImGuiKey_1;
106 | case AKEYCODE_2: return ImGuiKey_2;
107 | case AKEYCODE_3: return ImGuiKey_3;
108 | case AKEYCODE_4: return ImGuiKey_4;
109 | case AKEYCODE_5: return ImGuiKey_5;
110 | case AKEYCODE_6: return ImGuiKey_6;
111 | case AKEYCODE_7: return ImGuiKey_7;
112 | case AKEYCODE_8: return ImGuiKey_8;
113 | case AKEYCODE_9: return ImGuiKey_9;
114 | case AKEYCODE_A: return ImGuiKey_A;
115 | case AKEYCODE_B: return ImGuiKey_B;
116 | case AKEYCODE_C: return ImGuiKey_C;
117 | case AKEYCODE_D: return ImGuiKey_D;
118 | case AKEYCODE_E: return ImGuiKey_E;
119 | case AKEYCODE_F: return ImGuiKey_F;
120 | case AKEYCODE_G: return ImGuiKey_G;
121 | case AKEYCODE_H: return ImGuiKey_H;
122 | case AKEYCODE_I: return ImGuiKey_I;
123 | case AKEYCODE_J: return ImGuiKey_J;
124 | case AKEYCODE_K: return ImGuiKey_K;
125 | case AKEYCODE_L: return ImGuiKey_L;
126 | case AKEYCODE_M: return ImGuiKey_M;
127 | case AKEYCODE_N: return ImGuiKey_N;
128 | case AKEYCODE_O: return ImGuiKey_O;
129 | case AKEYCODE_P: return ImGuiKey_P;
130 | case AKEYCODE_Q: return ImGuiKey_Q;
131 | case AKEYCODE_R: return ImGuiKey_R;
132 | case AKEYCODE_S: return ImGuiKey_S;
133 | case AKEYCODE_T: return ImGuiKey_T;
134 | case AKEYCODE_U: return ImGuiKey_U;
135 | case AKEYCODE_V: return ImGuiKey_V;
136 | case AKEYCODE_W: return ImGuiKey_W;
137 | case AKEYCODE_X: return ImGuiKey_X;
138 | case AKEYCODE_Y: return ImGuiKey_Y;
139 | case AKEYCODE_Z: return ImGuiKey_Z;
140 | case AKEYCODE_F1: return ImGuiKey_F1;
141 | case AKEYCODE_F2: return ImGuiKey_F2;
142 | case AKEYCODE_F3: return ImGuiKey_F3;
143 | case AKEYCODE_F4: return ImGuiKey_F4;
144 | case AKEYCODE_F5: return ImGuiKey_F5;
145 | case AKEYCODE_F6: return ImGuiKey_F6;
146 | case AKEYCODE_F7: return ImGuiKey_F7;
147 | case AKEYCODE_F8: return ImGuiKey_F8;
148 | case AKEYCODE_F9: return ImGuiKey_F9;
149 | case AKEYCODE_F10: return ImGuiKey_F10;
150 | case AKEYCODE_F11: return ImGuiKey_F11;
151 | case AKEYCODE_F12: return ImGuiKey_F12;
152 | default: return ImGuiKey_None;
153 | }
154 | }
155 |
156 | int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
157 | {
158 | ImGuiIO& io = ImGui::GetIO();
159 | int32_t event_type = AInputEvent_getType(input_event);
160 | switch (event_type)
161 | {
162 | case AINPUT_EVENT_TYPE_KEY:
163 | {
164 | int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
165 | int32_t event_scan_code = AKeyEvent_getScanCode(input_event);
166 | int32_t event_action = AKeyEvent_getAction(input_event);
167 | int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
168 |
169 | io.AddKeyEvent(ImGuiMod_Ctrl, (event_meta_state & AMETA_CTRL_ON) != 0);
170 | io.AddKeyEvent(ImGuiMod_Shift, (event_meta_state & AMETA_SHIFT_ON) != 0);
171 | io.AddKeyEvent(ImGuiMod_Alt, (event_meta_state & AMETA_ALT_ON) != 0);
172 | io.AddKeyEvent(ImGuiMod_Super, (event_meta_state & AMETA_META_ON) != 0);
173 |
174 | switch (event_action)
175 | {
176 | // FIXME: AKEY_EVENT_ACTION_DOWN and AKEY_EVENT_ACTION_UP occur at once as soon as a touch pointer
177 | // goes up from a key. We use a simple key event queue/ and process one event per key per frame in
178 | // ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
179 | case AKEY_EVENT_ACTION_DOWN:
180 | case AKEY_EVENT_ACTION_UP:
181 | {
182 | ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code);
183 | if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP))
184 | {
185 | io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN);
186 | io.SetKeyEventNativeData(key, event_key_code, event_scan_code);
187 | }
188 |
189 | break;
190 | }
191 | default:
192 | break;
193 | }
194 | break;
195 | }
196 | case AINPUT_EVENT_TYPE_MOTION:
197 | {
198 | int32_t event_action = AMotionEvent_getAction(input_event);
199 | int32_t event_pointer_index = (event_action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
200 | event_action &= AMOTION_EVENT_ACTION_MASK;
201 |
202 | switch (AMotionEvent_getToolType(input_event, event_pointer_index))
203 | {
204 | case AMOTION_EVENT_TOOL_TYPE_MOUSE:
205 | io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
206 | break;
207 | case AMOTION_EVENT_TOOL_TYPE_STYLUS:
208 | case AMOTION_EVENT_TOOL_TYPE_ERASER:
209 | io.AddMouseSourceEvent(ImGuiMouseSource_Pen);
210 | break;
211 | case AMOTION_EVENT_TOOL_TYPE_FINGER:
212 | default:
213 | io.AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
214 | break;
215 | }
216 |
217 | switch (event_action)
218 | {
219 | case AMOTION_EVENT_ACTION_DOWN:
220 | case AMOTION_EVENT_ACTION_UP:
221 | // Physical mouse buttons (and probably other physical devices) also invoke the actions AMOTION_EVENT_ACTION_DOWN/_UP,
222 | // but we have to process them separately to identify the actual button pressed. This is done below via
223 | // AMOTION_EVENT_ACTION_BUTTON_PRESS/_RELEASE. Here, we only process "FINGER" input (and "UNKNOWN", as a fallback).
224 | if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
225 | || (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN))
226 | {
227 | io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
228 | io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN);
229 | }
230 | break;
231 | case AMOTION_EVENT_ACTION_BUTTON_PRESS:
232 | case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
233 | {
234 | int32_t button_state = AMotionEvent_getButtonState(input_event);
235 | io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
236 | io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
237 | io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
238 | }
239 | break;
240 | case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
241 | case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
242 | io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
243 | break;
244 | case AMOTION_EVENT_ACTION_SCROLL:
245 | io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index));
246 | break;
247 | default:
248 | break;
249 | }
250 | }
251 | return 1;
252 | default:
253 | break;
254 | }
255 |
256 | return 0;
257 | }
258 |
259 | bool ImGui_ImplAndroid_Init(ANativeWindow* window)
260 | {
261 | g_Window = window;
262 | g_Time = 0.0;
263 |
264 | // Setup backend capabilities flags
265 | ImGuiIO& io = ImGui::GetIO();
266 | io.BackendPlatformName = "imgui_impl_android";
267 |
268 | return true;
269 | }
270 |
271 | void ImGui_ImplAndroid_Shutdown()
272 | {
273 | ImGuiIO& io = ImGui::GetIO();
274 | io.BackendPlatformName = nullptr;
275 | }
276 |
277 | void ImGui_ImplAndroid_NewFrame()
278 | {
279 | ImGuiIO& io = ImGui::GetIO();
280 |
281 | // Setup display size (every frame to accommodate for window resizing)
282 | int32_t window_width = ANativeWindow_getWidth(g_Window);
283 | int32_t window_height = ANativeWindow_getHeight(g_Window);
284 | int display_width = window_width;
285 | int display_height = window_height;
286 |
287 | io.DisplaySize = ImVec2((float)window_width, (float)window_height);
288 | if (window_width > 0 && window_height > 0)
289 | io.DisplayFramebufferScale = ImVec2((float)display_width / window_width, (float)display_height / window_height);
290 |
291 | // Setup time step
292 | struct timespec current_timespec;
293 | clock_gettime(CLOCK_MONOTONIC, ¤t_timespec);
294 | double current_time = (double)(current_timespec.tv_sec) + (current_timespec.tv_nsec / 1000000000.0);
295 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
296 | g_Time = current_time;
297 | }
298 |
299 | //-----------------------------------------------------------------------------
300 |
301 | #endif // #ifndef IMGUI_DISABLE
302 |
--------------------------------------------------------------------------------
/src/imgui/imgui_impl_opengl3.cpp:
--------------------------------------------------------------------------------
1 | // dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
2 | // - Desktop GL: 2.x 3.x 4.x
3 | // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
4 | // This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
5 |
6 | // Implemented features:
7 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
8 | // [x] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
9 |
10 | // About WebGL/ES:
11 | // - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
12 | // - This is done automatically on iOS, Android and Emscripten targets.
13 | // - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
14 |
15 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
16 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
17 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
18 | // Read online: https://github.com/ocornut/imgui/tree/master/docs
19 |
20 | // CHANGELOG
21 | // (minor and older changes stripped away, please see git history for details)
22 | // 2023-06-20: OpenGL: Fixed erroneous use glGetIntegerv(GL_CONTEXT_PROFILE_MASK) on contexts lower than 3.2. (#6539, #6333)
23 | // 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375)
24 | // 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333)
25 | // 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224)
26 | // 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530)
27 | // 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224)
28 | // 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes).
29 | // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
30 | // 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'.
31 | // 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
32 | // 2022-05-13: OpenGL: Fixed state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
33 | // 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
34 | // 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
35 | // 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
36 | // 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
37 | // 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
38 | // 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
39 | // 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
40 | // 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
41 | // 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
42 | // 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
43 | // 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
44 | // 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
45 | // 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
46 | // 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
47 | // 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
48 | // 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
49 | // 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
50 | // 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
51 | // 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
52 | // 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
53 | // 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
54 | // 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
55 | // 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
56 | // 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
57 | // 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
58 | // 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
59 | // 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
60 | // 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
61 | // 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
62 | // 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
63 | // 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
64 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
65 | // 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
66 | // 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
67 | // 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
68 | // 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
69 | // 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
70 | // 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
71 | // 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
72 | // 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
73 | // 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a nullptr pointer.
74 | // 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
75 | // 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
76 | // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
77 | // 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
78 | // 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
79 | // 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
80 | // 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
81 | // 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
82 | // 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
83 |
84 | //----------------------------------------
85 | // OpenGL GLSL GLSL
86 | // version version string
87 | //----------------------------------------
88 | // 2.0 110 "#version 110"
89 | // 2.1 120 "#version 120"
90 | // 3.0 130 "#version 130"
91 | // 3.1 140 "#version 140"
92 | // 3.2 150 "#version 150"
93 | // 3.3 330 "#version 330 core"
94 | // 4.0 400 "#version 400 core"
95 | // 4.1 410 "#version 410 core"
96 | // 4.2 420 "#version 410 core"
97 | // 4.3 430 "#version 430 core"
98 | // ES 2.0 100 "#version 100" = WebGL 1.0
99 | // ES 3.0 300 "#version 300 es" = WebGL 2.0
100 | //----------------------------------------
101 |
102 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
103 | #define _CRT_SECURE_NO_WARNINGS
104 | #endif
105 |
106 | #include "imgui.h"
107 | #ifndef IMGUI_DISABLE
108 | #include "imgui_impl_opengl3.h"
109 | #include
110 | #include // intptr_t
111 | #if defined(__APPLE__)
112 | #include
113 | #endif
114 |
115 | // Clang/GCC warnings with -Weverything
116 | #if defined(__clang__)
117 | #pragma clang diagnostic push
118 | #pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
119 | #pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
120 | #pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used
121 | #pragma clang diagnostic ignored "-Wnonportable-system-include-path"
122 | #pragma clang diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
123 | #endif
124 | #if defined(__GNUC__)
125 | #pragma GCC diagnostic push
126 | #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
127 | #pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx'
128 | #pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
129 | #endif
130 |
131 | // GL includes
132 | #if defined(IMGUI_IMPL_OPENGL_ES2)
133 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
134 | #include // Use GL ES 2
135 | #else
136 | #include // Use GL ES 2
137 | #endif
138 | #if defined(__EMSCRIPTEN__)
139 | #ifndef GL_GLEXT_PROTOTYPES
140 | #define GL_GLEXT_PROTOTYPES
141 | #endif
142 | #include
143 | #endif
144 | #elif defined(IMGUI_IMPL_OPENGL_ES3)
145 | #if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
146 | #include // Use GL ES 3
147 | #else
148 | #include // Use GL ES 3
149 | #endif
150 | #elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
151 | // Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
152 | // Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w.
153 | // In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
154 | // If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
155 | // - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
156 | // - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
157 | // Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
158 | #define IMGL3W_IMPL
159 | #include "imgui_impl_opengl3_loader.h"
160 | #endif
161 |
162 | // Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
163 | #ifndef IMGUI_IMPL_OPENGL_ES2
164 | #define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
165 | #elif defined(__EMSCRIPTEN__)
166 | #define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
167 | #define glBindVertexArray glBindVertexArrayOES
168 | #define glGenVertexArrays glGenVertexArraysOES
169 | #define glDeleteVertexArrays glDeleteVertexArraysOES
170 | #define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
171 | #endif
172 |
173 | // Desktop GL 2.0+ has glPolygonMode() which GL ES and WebGL don't have.
174 | #ifdef GL_POLYGON_MODE
175 | #define IMGUI_IMPL_HAS_POLYGON_MODE
176 | #endif
177 |
178 | // Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
179 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
180 | #define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
181 | #endif
182 |
183 | // Desktop GL 3.3+ and GL ES 3.0+ have glBindSampler()
184 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && (defined(IMGUI_IMPL_OPENGL_ES3) || defined(GL_VERSION_3_3))
185 | #define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
186 | #endif
187 |
188 | // Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
189 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
190 | #define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
191 | #endif
192 |
193 | // Desktop GL use extension detection
194 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
195 | #define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
196 | #endif
197 |
198 | // [Debugging]
199 | //#define IMGUI_IMPL_OPENGL_DEBUG
200 | #ifdef IMGUI_IMPL_OPENGL_DEBUG
201 | #include
202 | #define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check
203 | #else
204 | #define GL_CALL(_CALL) _CALL // Call without error check
205 | #endif
206 |
207 | // OpenGL Data
208 | struct ImGui_ImplOpenGL3_Data
209 | {
210 | GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
211 | char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
212 | bool GlProfileIsES2;
213 | bool GlProfileIsES3;
214 | bool GlProfileIsCompat;
215 | GLint GlProfileMask;
216 | GLuint FontTexture;
217 | GLuint ShaderHandle;
218 | GLint AttribLocationTex; // Uniforms location
219 | GLint AttribLocationProjMtx;
220 | GLuint AttribLocationVtxPos; // Vertex attributes location
221 | GLuint AttribLocationVtxUV;
222 | GLuint AttribLocationVtxColor;
223 | unsigned int VboHandle, ElementsHandle;
224 | GLsizeiptr VertexBufferSize;
225 | GLsizeiptr IndexBufferSize;
226 | bool HasClipOrigin;
227 | bool UseBufferSubData;
228 |
229 | ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
230 | };
231 |
232 | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
233 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
234 | static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
235 | {
236 | return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
237 | }
238 |
239 | // OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
240 | #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
241 | struct ImGui_ImplOpenGL3_VtxAttribState
242 | {
243 | GLint Enabled, Size, Type, Normalized, Stride;
244 | GLvoid* Ptr;
245 |
246 | void GetState(GLint index)
247 | {
248 | glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled);
249 | glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size);
250 | glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type);
251 | glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized);
252 | glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride);
253 | glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr);
254 | }
255 | void SetState(GLint index)
256 | {
257 | glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr);
258 | if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index);
259 | }
260 | };
261 | #endif
262 |
263 | // Functions
264 | bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
265 | {
266 | ImGuiIO& io = ImGui::GetIO();
267 | IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
268 |
269 | // Initialize our loader
270 | #if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
271 | if (imgl3wInit() != 0)
272 | {
273 | fprintf(stderr, "Failed to initialize OpenGL loader!\n");
274 | return false;
275 | }
276 | #endif
277 |
278 | // Setup backend capabilities flags
279 | ImGui_ImplOpenGL3_Data* bd = IM_NEW(ImGui_ImplOpenGL3_Data)();
280 | io.BackendRendererUserData = (void*)bd;
281 | io.BackendRendererName = "imgui_impl_opengl3";
282 |
283 | // Query for GL version (e.g. 320 for GL 3.2)
284 | #if defined(IMGUI_IMPL_OPENGL_ES2)
285 | // GLES 2
286 | bd->GlVersion = 200;
287 | bd->GlProfileIsES2 = true;
288 | #else
289 | // Desktop or GLES 3
290 | GLint major = 0;
291 | GLint minor = 0;
292 | glGetIntegerv(GL_MAJOR_VERSION, &major);
293 | glGetIntegerv(GL_MINOR_VERSION, &minor);
294 | if (major == 0 && minor == 0)
295 | {
296 | // Query GL_VERSION in desktop GL 2.x, the string will start with "."
297 | const char* gl_version = (const char*)glGetString(GL_VERSION);
298 | sscanf(gl_version, "%d.%d", &major, &minor);
299 | }
300 | bd->GlVersion = (GLuint)(major * 100 + minor * 10);
301 | #if defined(GL_CONTEXT_PROFILE_MASK)
302 | if (bd->GlVersion >= 320)
303 | glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask);
304 | bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0;
305 | #endif
306 |
307 | #if defined(IMGUI_IMPL_OPENGL_ES3)
308 | bd->GlProfileIsES3 = true;
309 | #endif
310 |
311 | bd->UseBufferSubData = false;
312 | /*
313 | // Query vendor to enable glBufferSubData kludge
314 | #ifdef _WIN32
315 | if (const char* vendor = (const char*)glGetString(GL_VENDOR))
316 | if (strncmp(vendor, "Intel", 5) == 0)
317 | bd->UseBufferSubData = true;
318 | #endif
319 | */
320 | #endif
321 |
322 | #ifdef IMGUI_IMPL_OPENGL_DEBUG
323 | printf("GlVersion = %d\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2 = %d, GlProfileIsES3 = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
324 | #endif
325 |
326 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
327 | if (bd->GlVersion >= 320)
328 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
329 | #endif
330 |
331 | // Store GLSL version string so we can refer to it later in case we recreate shaders.
332 | // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.
333 | if (glsl_version == nullptr)
334 | {
335 | #if defined(IMGUI_IMPL_OPENGL_ES2)
336 | glsl_version = "#version 100";
337 | #elif defined(IMGUI_IMPL_OPENGL_ES3)
338 | glsl_version = "#version 300 es";
339 | #elif defined(__APPLE__)
340 | glsl_version = "#version 150";
341 | #else
342 | glsl_version = "#version 130";
343 | #endif
344 | }
345 | IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
346 | strcpy(bd->GlslVersionString, glsl_version);
347 | strcat(bd->GlslVersionString, "\n");
348 |
349 | // Make an arbitrary GL call (we don't actually need the result)
350 | // IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
351 | GLint current_texture;
352 | glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
353 |
354 | // Detect extensions we support
355 | bd->HasClipOrigin = (bd->GlVersion >= 450);
356 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
357 | GLint num_extensions = 0;
358 | glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
359 | for (GLint i = 0; i < num_extensions; i++)
360 | {
361 | const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
362 | if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
363 | bd->HasClipOrigin = true;
364 | }
365 | #endif
366 |
367 | return true;
368 | }
369 |
370 | void ImGui_ImplOpenGL3_Shutdown()
371 | {
372 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
373 | IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
374 | ImGuiIO& io = ImGui::GetIO();
375 |
376 | ImGui_ImplOpenGL3_DestroyDeviceObjects();
377 | io.BackendRendererName = nullptr;
378 | io.BackendRendererUserData = nullptr;
379 | io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
380 | IM_DELETE(bd);
381 | }
382 |
383 | void ImGui_ImplOpenGL3_NewFrame()
384 | {
385 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
386 | IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplOpenGL3_Init()?");
387 |
388 | if (!bd->ShaderHandle)
389 | ImGui_ImplOpenGL3_CreateDeviceObjects();
390 | }
391 |
392 | static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
393 | {
394 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
395 |
396 | // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
397 | glEnable(GL_BLEND);
398 | glBlendEquation(GL_FUNC_ADD);
399 | glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
400 | glDisable(GL_CULL_FACE);
401 | glDisable(GL_DEPTH_TEST);
402 | glDisable(GL_STENCIL_TEST);
403 | glEnable(GL_SCISSOR_TEST);
404 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
405 | if (bd->GlVersion >= 310)
406 | glDisable(GL_PRIMITIVE_RESTART);
407 | #endif
408 | #ifdef IMGUI_IMPL_HAS_POLYGON_MODE
409 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
410 | #endif
411 |
412 | // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
413 | #if defined(GL_CLIP_ORIGIN)
414 | bool clip_origin_lower_left = true;
415 | if (bd->HasClipOrigin)
416 | {
417 | GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin);
418 | if (current_clip_origin == GL_UPPER_LEFT)
419 | clip_origin_lower_left = false;
420 | }
421 | #endif
422 |
423 | // Setup viewport, orthographic projection matrix
424 | // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
425 | GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height));
426 | float L = draw_data->DisplayPos.x;
427 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
428 | float T = draw_data->DisplayPos.y;
429 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
430 | #if defined(GL_CLIP_ORIGIN)
431 | if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
432 | #endif
433 | const float ortho_projection[4][4] =
434 | {
435 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
436 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
437 | { 0.0f, 0.0f, -1.0f, 0.0f },
438 | { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
439 | };
440 | glUseProgram(bd->ShaderHandle);
441 | glUniform1i(bd->AttribLocationTex, 0);
442 | glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
443 |
444 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
445 | if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
446 | glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
447 | #endif
448 |
449 | (void)vertex_array_object;
450 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
451 | glBindVertexArray(vertex_array_object);
452 | #endif
453 |
454 | // Bind vertex/index buffers and setup attributes for ImDrawVert
455 | GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle));
456 | GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle));
457 | GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxPos));
458 | GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxUV));
459 | GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxColor));
460 | GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)));
461 | GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)));
462 | GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)));
463 | }
464 |
465 | // OpenGL3 Render function.
466 | // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
467 | // This is in order to be able to run within an OpenGL engine that doesn't do so.
468 | void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
469 | {
470 | // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
471 | int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
472 | int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
473 | if (fb_width <= 0 || fb_height <= 0)
474 | return;
475 |
476 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
477 |
478 | // Backup GL state
479 | GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
480 | glActiveTexture(GL_TEXTURE0);
481 | GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
482 | GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
483 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
484 | GLuint last_sampler; if (bd->GlVersion >= 330 || bd->GlProfileIsES3) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
485 | #endif
486 | GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
487 | #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
488 | // This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
489 | GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
490 | ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos);
491 | ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV);
492 | ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor);
493 | #endif
494 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
495 | GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
496 | #endif
497 | #ifdef IMGUI_IMPL_HAS_POLYGON_MODE
498 | GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
499 | #endif
500 | GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
501 | GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
502 | GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
503 | GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
504 | GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
505 | GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
506 | GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
507 | GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
508 | GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
509 | GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
510 | GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
511 | GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
512 | GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
513 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
514 | GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
515 | #endif
516 |
517 | // Setup desired GL state
518 | // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
519 | // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
520 | GLuint vertex_array_object = 0;
521 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
522 | GL_CALL(glGenVertexArrays(1, &vertex_array_object));
523 | #endif
524 | ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
525 |
526 | // Will project scissor/clipping rectangles into framebuffer space
527 | ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
528 | ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
529 |
530 | // Render command lists
531 | for (int n = 0; n < draw_data->CmdListsCount; n++)
532 | {
533 | const ImDrawList* cmd_list = draw_data->CmdLists[n];
534 |
535 | // Upload vertex/index buffers
536 | // - OpenGL drivers are in a very sorry state nowadays....
537 | // During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports
538 | // of leaks on Intel GPU when using multi-viewports on Windows.
539 | // - After this we kept hearing of various display corruptions issues. We started disabling on non-Intel GPU, but issues still got reported on Intel.
540 | // - We are now back to using exclusively glBufferData(). So bd->UseBufferSubData IS ALWAYS FALSE in this code.
541 | // We are keeping the old code path for a while in case people finding new issues may want to test the bd->UseBufferSubData path.
542 | // - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues.
543 | const GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
544 | const GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
545 | if (bd->UseBufferSubData)
546 | {
547 | if (bd->VertexBufferSize < vtx_buffer_size)
548 | {
549 | bd->VertexBufferSize = vtx_buffer_size;
550 | GL_CALL(glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, nullptr, GL_STREAM_DRAW));
551 | }
552 | if (bd->IndexBufferSize < idx_buffer_size)
553 | {
554 | bd->IndexBufferSize = idx_buffer_size;
555 | GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW));
556 | }
557 | GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data));
558 | GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data));
559 | }
560 | else
561 | {
562 | GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW));
563 | GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW));
564 | }
565 |
566 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
567 | {
568 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
569 | if (pcmd->UserCallback != nullptr)
570 | {
571 | // User callback, registered via ImDrawList::AddCallback()
572 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
573 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
574 | ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
575 | else
576 | pcmd->UserCallback(cmd_list, pcmd);
577 | }
578 | else
579 | {
580 | // Project scissor/clipping rectangles into framebuffer space
581 | ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
582 | ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
583 | if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
584 | continue;
585 |
586 | // Apply scissor/clipping rectangle (Y is inverted in OpenGL)
587 | GL_CALL(glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
588 |
589 | // Bind texture, Draw
590 | GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
591 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
592 | if (bd->GlVersion >= 320)
593 | GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset));
594 | else
595 | #endif
596 | GL_CALL(glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))));
597 | }
598 | }
599 | }
600 |
601 | // Destroy the temporary VAO
602 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
603 | GL_CALL(glDeleteVertexArrays(1, &vertex_array_object));
604 | #endif
605 |
606 | // Restore modified GL state
607 | // This "glIsProgram()" check is required because if the program is "pending deletion" at the time of binding backup, it will have been deleted by now and will cause an OpenGL error. See #6220.
608 | if (last_program == 0 || glIsProgram(last_program)) glUseProgram(last_program);
609 | glBindTexture(GL_TEXTURE_2D, last_texture);
610 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
611 | if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
612 | glBindSampler(0, last_sampler);
613 | #endif
614 | glActiveTexture(last_active_texture);
615 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
616 | glBindVertexArray(last_vertex_array_object);
617 | #endif
618 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
619 | #ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
620 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
621 | last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos);
622 | last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV);
623 | last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor);
624 | #endif
625 | glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
626 | glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
627 | if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
628 | if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
629 | if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
630 | if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
631 | if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
632 | #ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
633 | if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
634 | #endif
635 |
636 | #ifdef IMGUI_IMPL_HAS_POLYGON_MODE
637 | // Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons
638 | if (bd->GlVersion <= 310 || bd->GlProfileIsCompat)
639 | {
640 | glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]);
641 | glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]);
642 | }
643 | else
644 | {
645 | glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
646 | }
647 | #endif // IMGUI_IMPL_HAS_POLYGON_MODE
648 |
649 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
650 | glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
651 | (void)bd; // Not all compilation paths use this
652 | }
653 |
654 | bool ImGui_ImplOpenGL3_CreateFontsTexture()
655 | {
656 | ImGuiIO& io = ImGui::GetIO();
657 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
658 |
659 | // Build texture atlas
660 | unsigned char* pixels;
661 | int width, height;
662 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
663 |
664 | // Upload texture to graphics system
665 | // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
666 | GLint last_texture;
667 | GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
668 | GL_CALL(glGenTextures(1, &bd->FontTexture));
669 | GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
670 | GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
671 | GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
672 | #ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
673 | GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
674 | #endif
675 | GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
676 |
677 | // Store our identifier
678 | io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
679 |
680 | // Restore state
681 | GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture));
682 |
683 | return true;
684 | }
685 |
686 | void ImGui_ImplOpenGL3_DestroyFontsTexture()
687 | {
688 | ImGuiIO& io = ImGui::GetIO();
689 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
690 | if (bd->FontTexture)
691 | {
692 | glDeleteTextures(1, &bd->FontTexture);
693 | io.Fonts->SetTexID(0);
694 | bd->FontTexture = 0;
695 | }
696 | }
697 |
698 | // 如果出现错误,请在 github 上报告。您可以尝试不同的 GL 上下文版本或 GLSL 版本。请参见本文件顶部的 GL<>GLSL 版本表。
699 | static bool CheckShader(GLuint handle, const char* desc)
700 | {
701 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
702 | GLint status = 0, log_length = 0;
703 | glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
704 | glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
705 | if ((GLboolean)status == GL_FALSE)
706 | fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
707 | if (log_length > 1)
708 | {
709 | ImVector buf;
710 | buf.resize((int)(log_length + 1));
711 | glGetShaderInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
712 | fprintf(stderr, "%s\n", buf.begin());
713 | }
714 | return (GLboolean)status == GL_TRUE;
715 | }
716 |
717 | // If you get an error please report on GitHub. You may try different GL context version or GLSL version.
718 | static bool CheckProgram(GLuint handle, const char* desc)
719 | {
720 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
721 | GLint status = 0, log_length = 0;
722 | glGetProgramiv(handle, GL_LINK_STATUS, &status);
723 | glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
724 | if ((GLboolean)status == GL_FALSE)
725 | fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
726 | if (log_length > 1)
727 | {
728 | ImVector buf;
729 | buf.resize((int)(log_length + 1));
730 | glGetProgramInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
731 | fprintf(stderr, "%s\n", buf.begin());
732 | }
733 | return (GLboolean)status == GL_TRUE;
734 | }
735 |
736 | bool ImGui_ImplOpenGL3_CreateDeviceObjects()
737 | {
738 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
739 |
740 | // Backup GL state
741 | GLint last_texture, last_array_buffer;
742 | glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
743 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
744 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
745 | GLint last_vertex_array;
746 | glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
747 | #endif
748 |
749 | // Parse GLSL version string
750 | int glsl_version = 130;
751 | sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
752 |
753 | const GLchar* vertex_shader_glsl_120 =
754 | "uniform mat4 ProjMtx;\n"
755 | "attribute vec2 Position;\n"
756 | "attribute vec2 UV;\n"
757 | "attribute vec4 Color;\n"
758 | "varying vec2 Frag_UV;\n"
759 | "varying vec4 Frag_Color;\n"
760 | "void main()\n"
761 | "{\n"
762 | " Frag_UV = UV;\n"
763 | " Frag_Color = Color;\n"
764 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
765 | "}\n";
766 |
767 | const GLchar* vertex_shader_glsl_130 =
768 | "uniform mat4 ProjMtx;\n"
769 | "in vec2 Position;\n"
770 | "in vec2 UV;\n"
771 | "in vec4 Color;\n"
772 | "out vec2 Frag_UV;\n"
773 | "out vec4 Frag_Color;\n"
774 | "void main()\n"
775 | "{\n"
776 | " Frag_UV = UV;\n"
777 | " Frag_Color = Color;\n"
778 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
779 | "}\n";
780 |
781 | const GLchar* vertex_shader_glsl_300_es =
782 | "precision highp float;\n"
783 | "layout (location = 0) in vec2 Position;\n"
784 | "layout (location = 1) in vec2 UV;\n"
785 | "layout (location = 2) in vec4 Color;\n"
786 | "uniform mat4 ProjMtx;\n"
787 | "out vec2 Frag_UV;\n"
788 | "out vec4 Frag_Color;\n"
789 | "void main()\n"
790 | "{\n"
791 | " Frag_UV = UV;\n"
792 | " Frag_Color = Color;\n"
793 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
794 | "}\n";
795 |
796 | const GLchar* vertex_shader_glsl_410_core =
797 | "layout (location = 0) in vec2 Position;\n"
798 | "layout (location = 1) in vec2 UV;\n"
799 | "layout (location = 2) in vec4 Color;\n"
800 | "uniform mat4 ProjMtx;\n"
801 | "out vec2 Frag_UV;\n"
802 | "out vec4 Frag_Color;\n"
803 | "void main()\n"
804 | "{\n"
805 | " Frag_UV = UV;\n"
806 | " Frag_Color = Color;\n"
807 | " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
808 | "}\n";
809 |
810 | const GLchar* fragment_shader_glsl_120 =
811 | "#ifdef GL_ES\n"
812 | " precision mediump float;\n"
813 | "#endif\n"
814 | "uniform sampler2D Texture;\n"
815 | "varying vec2 Frag_UV;\n"
816 | "varying vec4 Frag_Color;\n"
817 | "void main()\n"
818 | "{\n"
819 | " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
820 | "}\n";
821 |
822 | const GLchar* fragment_shader_glsl_130 =
823 | "uniform sampler2D Texture;\n"
824 | "in vec2 Frag_UV;\n"
825 | "in vec4 Frag_Color;\n"
826 | "out vec4 Out_Color;\n"
827 | "void main()\n"
828 | "{\n"
829 | " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
830 | "}\n";
831 |
832 | const GLchar* fragment_shader_glsl_300_es =
833 | "precision mediump float;\n"
834 | "uniform sampler2D Texture;\n"
835 | "in vec2 Frag_UV;\n"
836 | "in vec4 Frag_Color;\n"
837 | "layout (location = 0) out vec4 Out_Color;\n"
838 | "void main()\n"
839 | "{\n"
840 | " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
841 | "}\n";
842 |
843 | const GLchar* fragment_shader_glsl_410_core =
844 | "in vec2 Frag_UV;\n"
845 | "in vec4 Frag_Color;\n"
846 | "uniform sampler2D Texture;\n"
847 | "layout (location = 0) out vec4 Out_Color;\n"
848 | "void main()\n"
849 | "{\n"
850 | " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
851 | "}\n";
852 |
853 | // Select shaders matching our GLSL versions
854 | const GLchar* vertex_shader = nullptr;
855 | const GLchar* fragment_shader = nullptr;
856 | if (glsl_version < 130)
857 | {
858 | vertex_shader = vertex_shader_glsl_120;
859 | fragment_shader = fragment_shader_glsl_120;
860 | }
861 | else if (glsl_version >= 410)
862 | {
863 | vertex_shader = vertex_shader_glsl_410_core;
864 | fragment_shader = fragment_shader_glsl_410_core;
865 | }
866 | else if (glsl_version == 300)
867 | {
868 | vertex_shader = vertex_shader_glsl_300_es;
869 | fragment_shader = fragment_shader_glsl_300_es;
870 | }
871 | else
872 | {
873 | vertex_shader = vertex_shader_glsl_130;
874 | fragment_shader = fragment_shader_glsl_130;
875 | }
876 |
877 | // Create shaders
878 | const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
879 | GLuint vert_handle = glCreateShader(GL_VERTEX_SHADER);
880 | glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr);
881 | glCompileShader(vert_handle);
882 | CheckShader(vert_handle, "vertex shader");
883 |
884 | const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
885 | GLuint frag_handle = glCreateShader(GL_FRAGMENT_SHADER);
886 | glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr);
887 | glCompileShader(frag_handle);
888 | CheckShader(frag_handle, "fragment shader");
889 |
890 | // Link
891 | bd->ShaderHandle = glCreateProgram();
892 | glAttachShader(bd->ShaderHandle, vert_handle);
893 | glAttachShader(bd->ShaderHandle, frag_handle);
894 | glLinkProgram(bd->ShaderHandle);
895 | CheckProgram(bd->ShaderHandle, "shader program");
896 |
897 | glDetachShader(bd->ShaderHandle, vert_handle);
898 | glDetachShader(bd->ShaderHandle, frag_handle);
899 | glDeleteShader(vert_handle);
900 | glDeleteShader(frag_handle);
901 |
902 | bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
903 | bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
904 | bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
905 | bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
906 | bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
907 |
908 | // Create buffers
909 | glGenBuffers(1, &bd->VboHandle);
910 | glGenBuffers(1, &bd->ElementsHandle);
911 |
912 | ImGui_ImplOpenGL3_CreateFontsTexture();
913 |
914 | // Restore modified GL state
915 | glBindTexture(GL_TEXTURE_2D, last_texture);
916 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
917 | #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
918 | glBindVertexArray(last_vertex_array);
919 | #endif
920 |
921 | return true;
922 | }
923 |
924 | void ImGui_ImplOpenGL3_DestroyDeviceObjects()
925 | {
926 | ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
927 | if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
928 | if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
929 | if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
930 | ImGui_ImplOpenGL3_DestroyFontsTexture();
931 | }
932 |
933 | //-----------------------------------------------------------------------------
934 |
935 | #if defined(__GNUC__)
936 | #pragma GCC diagnostic pop
937 | #endif
938 | #if defined(__clang__)
939 | #pragma clang diagnostic pop
940 | #endif
941 |
942 | #endif // #ifndef IMGUI_DISABLE
943 |
--------------------------------------------------------------------------------
/src/main_demo.cpp:
--------------------------------------------------------------------------------
1 | #include "OS-ImGui.h"
2 | #include "OS-ImGui_Struct.h"
3 | #include "imgui.h"
4 | #include
5 | #include
6 | #include
7 |
8 | bool isLine = false;
9 | bool isLine1 = false;
10 | bool isLine2 = false;
11 | bool isLine3 = false;
12 | bool isLine4 = false;
13 | bool isLine5 = false;
14 | bool isLine6 = false;
15 |
16 | void Imgui_demo() {
17 | ImGui::Begin("Test");
18 | ImGui::Text("Test Windows");
19 | ImGui::Checkbox("Line", &isLine);
20 | if (ImGui::Button("exit")) {
21 | Gui.Quit();
22 | exit(0);
23 | }
24 | Gui.MyCheckBox("Test1", &isLine1);
25 | Gui.MyCheckBox2("Test2", &isLine2);
26 | Gui.MyCheckBox3("Test3", &isLine3);
27 | Gui.MyCheckBox4("Test4", &isLine4);
28 | Gui.SwitchForRight("Test5", &isLine5);
29 | Gui.SwitchForLeft("Test6", &isLine6);
30 |
31 | ImGui::End();
32 |
33 | if (isLine) {
34 | Gui.Line(Vec2{0, 0}, Vec2{1000, 1000}, ImColor{255, 255, 255, 255}, 10);
35 | }
36 | }
37 |
38 | int main() {
39 | Gui.NewWindow("SurafceName", Imgui_demo,nullptr);
40 |
41 | std::cout << "Hello, World!" << std::endl;
42 | return 0;
43 | }
44 |
--------------------------------------------------------------------------------
/src/utils/touch.cpp:
--------------------------------------------------------------------------------
1 | // Self lib
2 | // System libs
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | // User libs
17 | #include "touch.h"
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | extern std::vector touchPositions;
24 | extern std::vector boxPositions;
25 |
26 | #define maxE 5 // 最大允许获得的event数量 设置为5 过多会导致多线程资源浪费
27 | #define maxF 10 // 最大手指 10个
28 | #define UNGRAB 0
29 | #define GRAB 1
30 |
31 | struct touchObj {
32 | bool isTmpDown = false;
33 | bool isDown = false;
34 | int x = 0;
35 | int y = 0;
36 | int id = 0;
37 | };
38 |
39 | struct targ {
40 | int fdNum;
41 | float S2TX;
42 | float S2TY;
43 | };
44 |
45 | // Var
46 | int fdNum = 0, origfd[maxE], nowfd;
47 | static struct input_event event[128];
48 | static struct input_event upEvent[3];
49 | int inputFd;
50 | bool bPad = false; // 判断是否为特殊平板
51 | float touchScreenx, touchScreeny;
52 | float offsetx = 0.0f, offsety = 0.0f;
53 | float halfOffsetx = 0.0f, halfOffsety = 0.0f;
54 | float t2sx, t2sy;
55 | static pthread_t touch_loop; // 触摸线程
56 | struct touchObj Finger[maxE][maxF];
57 | int screenX, screenY; // uinput注册设备 也是minCnt设备的触摸屏的xy
58 | float imgui_x, imgui_y = 0;
59 | bool isUpdate = false;
60 | bool isOnIMGUI = false;
61 | bool touchInit = false;
62 | extern bool showMenu;
63 | extern int Orientation;
64 | extern int touchScreenX, touchScreenY;
65 |
66 | std::string exec(std::string command) {
67 | char buffer[128];
68 | std::string result = "";
69 | // Open pipe to file
70 | FILE *pipe = popen(command.c_str(), "r");
71 | if (!pipe) {
72 | return "popen failed!";
73 | }
74 | // read till end of process:
75 | while (!feof(pipe)) {
76 | // use buffer to read and add to result
77 | if (fgets(buffer, 128, pipe) != nullptr) {
78 | result += buffer;
79 | }
80 | }
81 | pclose(pipe);
82 | return result;
83 | }
84 |
85 | int get_touch_event_num() {
86 | DIR *dir = opendir("/dev/input/");
87 | dirent *ptr = NULL;
88 | int eventCount = 0;
89 | while ((ptr = readdir(dir))) {
90 | if (strstr(ptr->d_name, "event")) {
91 | eventCount++;
92 | }
93 | }
94 | closedir(dir);
95 | int *fdArray = (int *)malloc(eventCount * sizeof(int));
96 | for (int i = 0; i < eventCount; i++) {
97 | char temp[128];
98 | sprintf(temp, "/dev/input/event%d", i);
99 | fdArray[i] = open(temp, O_RDWR | O_NONBLOCK);
100 | }
101 | int ret = -1;
102 | input_event ie;
103 | for (;;) {
104 | for (int i = 0; i < eventCount; i++) {
105 | memset(&ie, 0, sizeof(ie));
106 | read(fdArray[i], &ie, sizeof(ie));
107 | if (ie.type == EV_ABS && ie.code == ABS_MT_TRACKING_ID &&
108 | ie.value == -1) { // 屏幕触摸
109 | ret = i;
110 | break;
111 | }
112 | }
113 | if (ret >= 0) {
114 | break;
115 | }
116 | usleep(10000);
117 | }
118 | for (int i = 0; i < eventCount; i++) {
119 | close(fdArray[i]);
120 | }
121 | free(fdArray);
122 | return ret;
123 | }
124 | int get_volume_event_num(int code) {
125 | DIR *dir = opendir("/dev/input/");
126 | dirent *ptr = NULL;
127 | int eventCount = 0;
128 | while ((ptr = readdir(dir))) {
129 | if (strstr(ptr->d_name, "event")) {
130 | eventCount++;
131 | }
132 | }
133 | closedir(dir);
134 | int *fdArray = (int *)malloc(eventCount * sizeof(int));
135 | for (int i = 0; i < eventCount; i++) {
136 | char temp[128];
137 | sprintf(temp, "/dev/input/event%d", i);
138 | fdArray[i] = open(temp, O_RDWR | O_NONBLOCK);
139 | }
140 | int ret = -1;
141 | input_event ie;
142 | for (;;) {
143 | for (int i = 0; i < eventCount; i++) {
144 | memset(&ie, 0, sizeof(ie));
145 | read(fdArray[i], &ie, sizeof(ie));
146 | if (ie.type == EV_KEY && ie.code == code) { // 音量按下
147 | ret = i;
148 | break;
149 | }
150 | }
151 | if (ret >= 0) {
152 | break;
153 | }
154 | usleep(10000);
155 | }
156 | for (int i = 0; i < eventCount; i++) {
157 | close(fdArray[i]);
158 | }
159 | free(fdArray);
160 | return ret;
161 | }
162 |
163 | void dispatchIMGUITouchEvent(input_event ie) {
164 | int latest = 0;
165 | ImGuiIO &io = ImGui::GetIO();
166 | if (ie.type != EV_ABS) {
167 | return;
168 | }
169 | if (ie.code == ABS_MT_SLOT) {
170 | latest = ie.value;
171 | return;
172 | }
173 | if (latest != 0) {
174 | return;
175 | }
176 | if (ie.code == ABS_MT_TRACKING_ID) {
177 | if (ie.value == -1) {
178 | io.MouseDown[0] = false;
179 | } else {
180 | io.MouseDown[0] = true;
181 | }
182 | return;
183 | }
184 | isUpdate = false;
185 | if (ie.code == ABS_MT_POSITION_X) {
186 | imgui_x = (ie.value - halfOffsetx) * t2sx;
187 | isUpdate = true;
188 | }
189 | if (ie.code == ABS_MT_POSITION_Y) {
190 | imgui_y = (ie.value - halfOffsety) * t2sy;
191 | isUpdate = true;
192 | }
193 | if (!isUpdate) {
194 | return;
195 | }
196 | if (bPad) {
197 | switch (Orientation) {
198 | case 0:
199 | io.MousePos = ImVec2(touchScreeny - imgui_y, imgui_x);
200 | break;
201 | case 1:
202 | io.MousePos = ImVec2(imgui_x, imgui_y);
203 | break;
204 | case 2:
205 | io.MousePos = ImVec2(imgui_y, touchScreenx - imgui_x);
206 | break;
207 | case 3:
208 | io.MousePos = ImVec2(touchScreenx - imgui_x, touchScreeny - imgui_y);
209 | break;
210 | }
211 | } else {
212 | switch (Orientation) {
213 | case 0:
214 | io.MousePos = ImVec2(imgui_x, imgui_y);
215 | break;
216 | case 1:
217 | io.MousePos = ImVec2(imgui_y, touchScreenx - imgui_x);
218 | break;
219 | case 2:
220 | io.MousePos = ImVec2(touchScreenx - imgui_x, touchScreeny - imgui_y);
221 | break;
222 | case 3:
223 | io.MousePos = ImVec2(touchScreeny - imgui_y, imgui_x);
224 | break;
225 | }
226 | }
227 | }
228 |
229 | // 上传报文
230 | void Upload() {
231 | int tmpCnt = 0, tmpCnt2 = 0, i, j;
232 | int size = rand() % 30;
233 | for (i = 0; i < fdNum; i++) {
234 | for (j = 0; j < maxF; j++) {
235 | if (Finger[i][j].isDown) {
236 | tmpCnt2++; // 有手指按下了 计数
237 | if (tmpCnt2 > 10) { // 如果手指大于10了 那不正常 break
238 | break;
239 | }
240 | event[tmpCnt].type = EV_ABS;
241 | event[tmpCnt].code = ABS_X;
242 | event[tmpCnt].value = Finger[i][j].x;
243 | tmpCnt++;
244 |
245 | event[tmpCnt].type = EV_ABS;
246 | event[tmpCnt].code = ABS_Y;
247 | event[tmpCnt].value = Finger[i][j].y;
248 | tmpCnt++;
249 |
250 | event[tmpCnt].type = EV_ABS;
251 | event[tmpCnt].code = ABS_MT_POSITION_X;
252 | event[tmpCnt].value = Finger[i][j].x;
253 | tmpCnt++;
254 |
255 | event[tmpCnt].type = EV_ABS;
256 | event[tmpCnt].code = ABS_MT_POSITION_Y;
257 | event[tmpCnt].value = Finger[i][j].y;
258 | tmpCnt++;
259 |
260 | event[tmpCnt].type = EV_ABS;
261 | event[tmpCnt].code = ABS_MT_TOUCH_MAJOR;
262 | event[tmpCnt].value = size;
263 | tmpCnt++;
264 |
265 | event[tmpCnt].type = EV_ABS;
266 | event[tmpCnt].code = ABS_MT_WIDTH_MAJOR;
267 | event[tmpCnt].value = size;
268 | tmpCnt++;
269 |
270 | event[tmpCnt].type = EV_ABS;
271 | event[tmpCnt].code = ABS_MT_TRACKING_ID;
272 | event[tmpCnt].value = Finger[i][j].id;
273 | tmpCnt++;
274 |
275 | event[tmpCnt].type = EV_SYN;
276 | event[tmpCnt].code = SYN_MT_REPORT;
277 | event[tmpCnt].value = 0;
278 | tmpCnt++;
279 | }
280 | }
281 | }
282 | if (tmpCnt == 0) { //
283 | event[tmpCnt].type = EV_SYN;
284 | event[tmpCnt].code = SYN_MT_REPORT;
285 | event[tmpCnt].value = 0;
286 | tmpCnt++;
287 | }
288 | event[tmpCnt].type = EV_SYN;
289 | event[tmpCnt].code = SYN_REPORT;
290 | event[tmpCnt].value = 0;
291 | tmpCnt++;
292 | // 写报文
293 | write(nowfd, event, sizeof(struct input_event) * tmpCnt);
294 | }
295 |
296 | void Down(int id, int x, int y) {
297 | int num = fdNum - 1;
298 | Finger[num][id].id = (num * 2 + 1) * maxF + id;
299 | if (bPad) {
300 | switch (Orientation) {
301 | case 0:
302 | Finger[num][id].x = (y / t2sx + halfOffsetx);
303 | Finger[num][id].y = (touchScreeny - x) / t2sy + halfOffsety;
304 | break;
305 | case 1:
306 | Finger[num][id].x = ((x / t2sx) + halfOffsetx);
307 | Finger[num][id].y = ((y / t2sy) + halfOffsety);
308 | break;
309 | case 2:
310 | // y = touchScreenx - (Finger[num][id].x - halfOffsetx) * t2sx;
311 | Finger[num][id].x = (touchScreenx - y) / t2sx + halfOffsetx;
312 | // x = (Finger[num][id].y - halfOffsety) * t2sy;
313 | Finger[num][id].y = (x / t2sy + halfOffsety);
314 | break;
315 | case 3:
316 | // x = touchScreenx - (Finger[num][id].x - halfOffsetx) * t2sx;
317 | Finger[num][id].x = ((touchScreenx - x) / t2sx) + halfOffsetx;
318 | // y = touchScreeny - (Finger[num][id].y - halfOffsety) * t2sy;
319 | Finger[num][id].y = ((touchScreeny - y) / t2sy) + halfOffsety;
320 | break;
321 | }
322 | } else {
323 | switch (Orientation) {
324 | case 0:
325 | Finger[num][id].x = ((x / t2sx) + halfOffsetx);
326 | Finger[num][id].y = ((y / t2sy) + halfOffsety);
327 | break;
328 | case 1:
329 | Finger[num][id].x = (touchScreenx - y) / t2sx + halfOffsetx;
330 | Finger[num][id].y = (x / t2sy + halfOffsety);
331 | break;
332 | case 2:
333 | Finger[num][id].x = ((touchScreenx - x) / t2sx) + halfOffsetx;
334 | Finger[num][id].y = ((touchScreeny - y) / t2sy) + halfOffsety;
335 | break;
336 | case 3:
337 | Finger[num][id].x = (y / t2sx + halfOffsetx);
338 | Finger[num][id].y = (touchScreeny - x) / t2sy + halfOffsety;
339 | break;
340 | }
341 | }
342 | Finger[num][id].isDown = true;
343 | Upload();
344 | }
345 |
346 | void Move(int id, int x, int y) {
347 | int num = fdNum - 1;
348 | Finger[num][id].id = (num * 2 + 1) * maxF + id;
349 | if (bPad) {
350 | switch (Orientation) {
351 | case 0:
352 | Finger[num][id].x = (y / t2sx + halfOffsetx);
353 | Finger[num][id].y = (touchScreeny - x) / t2sy + halfOffsety;
354 | break;
355 | case 1:
356 | Finger[num][id].x = ((x / t2sx) + halfOffsetx);
357 | Finger[num][id].y = ((y / t2sy) + halfOffsety);
358 | break;
359 | case 2:
360 | Finger[num][id].x = (touchScreenx - y) / t2sx + halfOffsetx;
361 | Finger[num][id].y = (x / t2sy + halfOffsety);
362 | break;
363 | case 3:
364 | Finger[num][id].x = ((touchScreenx - x) / t2sx) + halfOffsetx;
365 | Finger[num][id].y = ((touchScreeny - y) / t2sy) + halfOffsety;
366 | break;
367 | }
368 | } else {
369 | switch (Orientation) {
370 | case 0:
371 | Finger[num][id].x = ((x / t2sx) + halfOffsetx);
372 | Finger[num][id].y = ((y / t2sy) + halfOffsety);
373 | break;
374 | case 1:
375 | Finger[num][id].x = (touchScreenx - y) / t2sx + halfOffsetx;
376 | Finger[num][id].y = (x / t2sy + halfOffsety);
377 | break;
378 | case 2:
379 | Finger[num][id].x = ((touchScreenx - x) / t2sx) + halfOffsetx;
380 | Finger[num][id].y = ((touchScreeny - y) / t2sy) + halfOffsety;
381 | break;
382 | case 3:
383 | Finger[num][id].x = (y / t2sx + halfOffsetx);
384 | Finger[num][id].y = (touchScreeny - x) / t2sy + halfOffsety;
385 | break;
386 | }
387 | }
388 | Finger[num][id].isDown = true;
389 | Upload();
390 | }
391 |
392 | void Up(int id) {
393 | int num = fdNum - 1;
394 | Finger[num][id].isDown = false;
395 | Upload();
396 | }
397 |
398 | // 生成随机字符串
399 | char *_genRandomString(int length) {
400 | int flag, i;
401 | srand((unsigned)time(NULL));
402 | char *tmpString = (char *)malloc(length * sizeof(char));
403 | for (i = 0; i < length - 1; i++) {
404 | flag = rand() % 3;
405 | switch (flag) {
406 | case 0:
407 | tmpString[i] = 'A' + rand() % 26;
408 | break;
409 | case 1:
410 | tmpString[i] = 'a' + rand() % 26;
411 | break;
412 | case 2:
413 | tmpString[i] = '0' + rand() % 10;
414 | break;
415 | default:
416 | tmpString[i] = 'x';
417 | break;
418 | }
419 | }
420 | tmpString[length - 1] = '\0';
421 | return tmpString;
422 | }
423 |
424 | // 对设备随机注册一些bit 使其难以被识别
425 | void randomRegisterDevices(int fd) {
426 | int nums[41] = {ABS_X,
427 | ABS_Y,
428 | ABS_Z,
429 | ABS_RX,
430 | ABS_RY,
431 | ABS_RZ,
432 | ABS_THROTTLE,
433 | ABS_RUDDER,
434 | ABS_WHEEL,
435 | ABS_GAS,
436 | ABS_BRAKE,
437 | ABS_HAT0Y,
438 | ABS_HAT1X,
439 | ABS_HAT1Y,
440 | ABS_HAT2X,
441 | ABS_HAT2Y,
442 | ABS_HAT3X,
443 | ABS_HAT3Y,
444 | ABS_PRESSURE,
445 | ABS_DISTANCE,
446 | ABS_TILT_X,
447 | ABS_TILT_Y,
448 | ABS_TOOL_WIDTH,
449 | ABS_VOLUME,
450 | ABS_MISC,
451 | ABS_MT_TOUCH_MAJOR,
452 | ABS_MT_TOUCH_MINOR,
453 | ABS_MT_WIDTH_MAJOR,
454 | ABS_MT_WIDTH_MINOR,
455 | ABS_MT_ORIENTATION,
456 | ABS_MT_POSITION_X,
457 | ABS_MT_POSITION_Y,
458 | ABS_MT_TOOL_TYPE,
459 | ABS_MT_BLOB_ID,
460 | ABS_MT_TRACKING_ID,
461 | ABS_MT_PRESSURE,
462 | ABS_MT_DISTANCE,
463 | ABS_MT_TOOL_X,
464 | ABS_MT_TOOL_Y,
465 | ABS_MAX,
466 | ABS_CNT};
467 | for (int i = 0; i < 41; i++) {
468 | int num = rand() % 41;
469 | ioctl(fd, UI_SET_ABSBIT, nums[num]);
470 | }
471 | }
472 | targ tmp;
473 | void *TypeA(void *arg) {
474 | int i = tmp.fdNum;
475 | float S2TX = tmp.S2TX;
476 | float S2TY = tmp.S2TY;
477 | struct input_event ie;
478 | int latest = 0;
479 | float Xcache, Ycache;
480 | while (true) {
481 | struct input_event iel[32];
482 | int32_t readSize = read(origfd[i], &iel, sizeof(iel));
483 | if (readSize <= 0 || (readSize % sizeof(struct input_event)) != 0) {
484 | continue;
485 | }
486 | size_t count = size_t(readSize) / sizeof(struct input_event);
487 | for (size_t j = 0; j < count; j++) {
488 | struct input_event ie = iel[j];
489 | dispatchIMGUITouchEvent(ie);
490 | if (isOnIMGUI) {
491 | continue;
492 | }
493 | if (ie.code == ABS_MT_SLOT) {
494 | latest = ie.value;
495 | continue;
496 | }
497 | if (ie.code == ABS_MT_TRACKING_ID) {
498 | if (ie.value == -1) { // 手指放开了
499 | Finger[i][latest].isDown = false;
500 | } else {
501 | Finger[i][latest].id = (i * 2 + 1) * maxF + latest;
502 | Finger[i][latest].isDown = true;
503 | }
504 | continue;
505 | }
506 | if (ie.code == ABS_MT_POSITION_X) {
507 | Finger[i][latest].id = (i * 2 + 1) * maxF + latest;
508 | Finger[i][latest].x = (int)(ie.value * S2TX);
509 | Xcache = (int)(ie.value * S2TX);
510 | Finger[i][latest].isTmpDown = true;
511 | continue;
512 | }
513 | if (ie.code == ABS_MT_POSITION_Y) {
514 | Finger[i][latest].id = (i * 2 + 1) * maxF + latest;
515 | Finger[i][latest].y = (int)(ie.value * S2TY);
516 | Ycache = (int)(ie.value * S2TY);
517 | Finger[i][latest].isTmpDown = true;
518 | continue;
519 | }
520 | if (ie.code == SYN_REPORT) {
521 | if (Finger[i][latest].isTmpDown) {
522 | Upload();
523 | }
524 | continue;
525 | }
526 | }
527 | usleep(100);
528 | }
529 | return 0;
530 | }
531 |
532 | // 初始化触摸和imgui触摸处理
533 | void handleAndroidTouchAndIMGUI() { // 初始化触摸设置
534 | char temp[128];
535 | DIR *dir = opendir("/dev/input/");
536 | dirent *ptr = NULL;
537 | int eventCount = 0;
538 | int touch_num = get_touch_event_num(); // 获取触摸屏的event
539 | // 遍历/dev/input/event 获取全部的event事件数量
540 | while ((ptr = readdir(dir)) != NULL) {
541 | if (strstr(ptr->d_name, "event")) {
542 | eventCount++;
543 | }
544 | }
545 | struct input_absinfo abs, absX[maxE], absY[maxE];
546 | int fd, i, tmp1, tmp2;
547 | int minCnt =
548 | eventCount + 1; // 因为要判断出minCnt 所以minCnt必须至少比eventCount大1
549 | fdNum = 0;
550 | int touch_fd, index;
551 | // 遍历全部的event数量 获取到全部的可用触摸设备
552 | for (i = 0; i <= eventCount; i++) {
553 | sprintf(temp, "/dev/input/event%d", i);
554 | fd = open(temp, O_RDWR);
555 | if (fd) { // 如果fd被打开成功
556 | uint8_t *bits = NULL;
557 | ssize_t bits_size = 0;
558 | int res, j, k;
559 | bool itmp1 = false, itmp2 = false, itmp3 = false;
560 | // 获取每个event事件的配置 匹配bit是否有我们的目标 如果都存在
561 | // 则说明为触摸设备
562 | while (1) {
563 | res = ioctl(fd, EVIOCGBIT(EV_ABS, bits_size), bits);
564 | if (res < bits_size) {
565 | break;
566 | }
567 | bits_size = res + 16;
568 | bits = (uint8_t *)realloc(bits, bits_size * 2);
569 | if (bits == NULL) {
570 | printf("获取事件失败\n");
571 | exit(0);
572 | }
573 | }
574 | // 获取每个event事件的配置 匹配bit是否有我们的目标 如果都存在
575 | // 则说明为触摸设备
576 | for (j = 0; j < res; j++) {
577 | for (k = 0; k < 8; k++) {
578 | if (bits[j] & 1 << k && ioctl(fd, EVIOCGABS(j * 8 + k), &abs) == 0) {
579 | if (j * 8 + k == ABS_MT_SLOT) {
580 | itmp1 = true;
581 | continue;
582 | }
583 | if (j * 8 + k == ABS_MT_POSITION_X) {
584 | itmp2 = true;
585 | continue;
586 | }
587 | if (j * 8 + k == ABS_MT_POSITION_Y) {
588 | itmp3 = true;
589 | continue;
590 | }
591 | }
592 | }
593 | }
594 | if (itmp1 && itmp2 && itmp3) {
595 | tmp1 = ioctl(fd, EVIOCGABS(ABS_MT_POSITION_X), &absX[fdNum]);
596 | tmp2 = ioctl(fd, EVIOCGABS(ABS_MT_POSITION_Y), &absY[fdNum]);
597 | if (tmp1 == 0 && tmp2 == 0) {
598 | // 如果tmp1和tmp2 都是0 则说明本次遍历的event是触摸设备
599 | // if (i < minCnt) { // 后续会选取最小的minCnt作为伪造设备的根据
600 | if (i == touch_num) {
601 | origfd[0] = fd; // 做一个存储
602 | ioctl(fd, EVIOCGRAB,
603 | GRAB); // 对原event做屏蔽 以防止和我们创造的event抢接管权
604 | // 原触摸程序会选取最小的触摸设备文件作为模拟创建的对象
605 | // 但是这里为了方便部分多设备文件的分辨率和触摸屏分辨率不一样的情况
606 | // 统一模拟创建为触摸屏设备文件
607 | // 也就是固定minCnt为touch event
608 | screenX =
609 | absX[fdNum].maximum; // 获取最小event数的设备文件的screenX和Y
610 | // 也就是触摸屏大小
611 | screenY = absY[fdNum].maximum;
612 | minCnt = i;
613 | touch_fd = fd;
614 | index = fdNum;
615 | }
616 | fdNum++;
617 | if (fdNum >= maxE) { // 如果fd数量大于我们规定的最大数 则不再遍历
618 | // 太多线程浪费资源
619 | break;
620 | }
621 | }
622 | }
623 | }
624 | }
625 | // close(fd); // 确保fd在这里是close的
626 | // 判断minCnt是否有获取成功 后续会选取最小的minCnt作为伪造设备的根据
627 | if (minCnt > eventCount) {
628 | printf("获取屏幕驱动失败\n");
629 | exit(0);
630 | }
631 | // 创建uinput设备
632 | struct uinput_user_dev ui_dev;
633 | nowfd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
634 | if (nowfd <= 0) {
635 | printf("打开驱动失败\n");
636 | exit(0);
637 | }
638 | srand((unsigned)time(NULL));
639 | memset(&ui_dev, 0, sizeof(ui_dev));
640 | char name[128], n2[128];
641 | for (int i = 0; i < rand() % 7 + 6; i++) {
642 | sprintf(n2, "%c", 'a' + rand() % 26);
643 | strcat(name, n2);
644 | }
645 |
646 | strncpy(ui_dev.name, name, UINPUT_MAX_NAME_SIZE);
647 | sprintf(name, "");
648 | for (int i = 0; i < rand() % 7 + 6; i++) {
649 | sprintf(n2, "%c", 'a' + rand() % 26);
650 | strcat(name, n2);
651 | }
652 |
653 | ioctl(nowfd, UI_SET_PHYS, name);
654 | // ui_dev.id.bustype = rand()%2==0?0:rand()%2+0x18;BUS_USB;
655 | ui_dev.id.vendor = rand() % 3;
656 | ui_dev.id.product = rand() % 3;
657 | ui_dev.id.version = (rand() % 2 == 0 ? 0 : 0x100);
658 |
659 | struct input_id id;
660 | if (!ioctl(touch_fd, EVIOCGID, &id)) {
661 | ui_dev.id.bustype = id.bustype;
662 | ui_dev.id.vendor = id.vendor;
663 | ui_dev.id.product = id.product;
664 | ui_dev.id.version = id.version;
665 | }
666 |
667 | ui_dev.absmin[ABS_MT_POSITION_X] = 0;
668 | ui_dev.absmax[ABS_MT_POSITION_X] = screenX;
669 | ui_dev.absmin[ABS_MT_POSITION_Y] = 0;
670 | ui_dev.absmax[ABS_MT_POSITION_Y] = screenY;
671 | ui_dev.absmin[ABS_MT_TOUCH_MAJOR] = 0;
672 | ui_dev.absmax[ABS_MT_TOUCH_MAJOR] = 255;
673 | ui_dev.absmin[ABS_MT_WIDTH_MAJOR] = 0;
674 | ui_dev.absmax[ABS_MT_WIDTH_MAJOR] = 255;
675 | ui_dev.absmin[ABS_X] = 0;
676 | ui_dev.absmax[ABS_X] = screenX;
677 | ui_dev.absmin[ABS_Y] = 0;
678 | ui_dev.absmax[ABS_Y] = screenY;
679 | ioctl(nowfd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
680 | ioctl(nowfd, UI_SET_EVBIT, EV_ABS);
681 | ioctl(nowfd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
682 | ioctl(nowfd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
683 | ioctl(nowfd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
684 | ioctl(nowfd, UI_SET_EVBIT, EV_SYN);
685 | ioctl(nowfd, UI_SET_ABSBIT, ABS_X);
686 | ioctl(nowfd, UI_SET_ABSBIT, ABS_Y);
687 | ioctl(nowfd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR);
688 | ioctl(nowfd, UI_SET_ABSBIT, ABS_MT_WIDTH_MAJOR);
689 | randomRegisterDevices(nowfd); // 随机注册一些bit 使其难以被识别
690 | // 获取原event的bit 并且模仿注册
691 | uint8_t *bits = NULL;
692 | ssize_t bits_size = 0;
693 | int res, j, k;
694 | while (1) {
695 | res = ioctl(touch_fd, EVIOCGBIT(EV_KEY, bits_size), bits);
696 | if (res < bits_size) {
697 | break;
698 | }
699 | bits_size = res + 16;
700 | bits = (uint8_t *)realloc(bits, bits_size * 2);
701 | if (bits == NULL) {
702 | printf("获取事件失败\n");
703 | exit(0);
704 | }
705 | }
706 | for (j = 0; j < res; j++) {
707 | for (k = 0; k < 8; k++) {
708 | if (bits[j] & 1 << k) {
709 | if (j * 8 + k == BTN_TOUCH || j * 8 + k == BTN_TOOL_FINGER) {
710 | continue;
711 | }
712 | ioctl(nowfd, UI_SET_KEYBIT, j * 8 + k);
713 | }
714 | }
715 | }
716 | // 上步骤疑似存在问题
717 |
718 | write(nowfd, &ui_dev, sizeof(ui_dev));
719 | if (ioctl(nowfd, UI_DEV_CREATE)) {
720 | printf("Heaven : Unable to create UINPUT device.\n");
721 | return;
722 | }
723 | bPad = false;
724 | // 手机有修改分辨率情况的适配
725 | if (screenX > screenY) {
726 | bPad = true; // 特殊平板手机判断
727 | }
728 | auto marketname = exec("getprop ro.product.vendor.marketname");
729 | if (marketname.find("Xiaomi Pad 6") != -1) {
730 | bPad = false; // 小米6
731 | }
732 | if (bPad) { // 对特殊平板的转化判断
733 | touchScreenx = touchScreenY;
734 | touchScreeny = touchScreenX;
735 | } else {
736 | touchScreenx = touchScreenX;
737 | touchScreeny = touchScreenY;
738 | }
739 | // 计算比率
740 | t2sx = float(touchScreenx) / (screenX - offsetx);
741 | t2sy = float(touchScreeny) / (screenY - offsety);
742 | // 为每个触摸设备创建触摸代理线程
743 | tmp.fdNum = 0;
744 | // 其余触摸设备的触摸屏大小不一定和minCnt的触摸屏大小完全一致 做比例转化
745 | tmp.S2TX =
746 | (float)(screenX - offsetx) / (float)(absX[index].maximum - offsetx);
747 | tmp.S2TY =
748 | (float)(screenY - offsety) / (float)(absY[index].maximum - offsety);
749 | pthread_create(&touch_loop, NULL, TypeA, nullptr);
750 | touchInit = true;
751 | }
752 | // 纯只读处理UI
753 | void handleIMGUITouchEvent() {
754 | char temp[19];
755 | sprintf(temp, "/dev/input/event%d", get_touch_event_num());
756 | inputFd = open(temp, O_RDWR);
757 | struct input_absinfo absX, absY;
758 | ioctl(inputFd, EVIOCGABS(ABS_MT_POSITION_X), &absX);
759 | ioctl(inputFd, EVIOCGABS(ABS_MT_POSITION_Y), &absY);
760 | bPad = false;
761 | if (absX.maximum > absY.maximum) {
762 | bPad = true; // 特殊平板手机判断
763 | }
764 | auto marketname = exec("getprop ro.product.vendor.marketname");
765 | if (marketname.find("Xiaomi Pad 6") != -1) {
766 | bPad = false; // 小米6
767 | }
768 | if (bPad) { // 对特殊平板的转化判断
769 | touchScreenx = touchScreenY;
770 | touchScreeny = touchScreenX;
771 | } else {
772 | touchScreenx = touchScreenX;
773 | touchScreeny = touchScreenY;
774 | }
775 | // printf("bPad:%d %f %f\n", bPad, touchScreenx, touchScreeny);
776 | // 计算比率
777 | t2sx = float(touchScreenx) / (absX.maximum - offsetx);
778 | t2sy = float(touchScreeny) / (absY.maximum - offsety);
779 | int latest = 0;
780 | bool isUpdate = false;
781 | ImGuiIO &io = ImGui::GetIO();
782 | for (;;) {
783 | struct input_event iel[32];
784 | int32_t readSize = read(inputFd, &iel, sizeof(struct input_event));
785 | if (readSize <= 0 || (readSize % sizeof(struct input_event)) != 0) {
786 | continue;
787 | }
788 | size_t count = size_t(readSize) / sizeof(struct input_event);
789 | for (size_t j = 0; j < count; j++) {
790 | struct input_event ie = iel[j];
791 | if (ie.type != EV_ABS) {
792 | continue;
793 | }
794 | if (ie.code == ABS_MT_SLOT) {
795 | latest = ie.value;
796 | continue;
797 | }
798 | if (latest != 0) {
799 | continue;
800 | }
801 | if (ie.code == ABS_MT_TRACKING_ID) {
802 | if (ie.value == -1) {
803 | io.MouseDown[0] = false;
804 | } else {
805 | io.MouseDown[0] = true;
806 | }
807 | continue;
808 | }
809 | isUpdate = false;
810 | float x, y;
811 | if (ie.code == ABS_MT_POSITION_X) {
812 | x = (ie.value - halfOffsetx) * t2sx;
813 | isUpdate = true;
814 | }
815 | if (ie.code == ABS_MT_POSITION_Y) {
816 | y = (ie.value - halfOffsety) * t2sy;
817 | isUpdate = true;
818 | }
819 | if (!isUpdate) {
820 | continue;
821 | }
822 | if (bPad) {
823 | switch (Orientation) {
824 | case 0:
825 | io.MousePos = ImVec2(touchScreeny - y, x);
826 | break;
827 | case 1:
828 | io.MousePos = ImVec2(x, y);
829 | break;
830 | case 2:
831 | io.MousePos = ImVec2(y, touchScreenx - x);
832 | break;
833 | case 3:
834 | io.MousePos = ImVec2(touchScreenx - x, touchScreeny - y);
835 | break;
836 | }
837 | } else {
838 | switch (Orientation) {
839 | case 0:
840 | io.MousePos = ImVec2(x, y);
841 | break;
842 | case 1:
843 | io.MousePos = ImVec2(y, touchScreenx - x);
844 | break;
845 | case 2:
846 | io.MousePos = ImVec2(touchScreenx - x, touchScreeny - y);
847 | break;
848 | case 3:
849 | io.MousePos = ImVec2(touchScreeny - y, x);
850 | break;
851 | }
852 | }
853 | }
854 | usleep(100);
855 | }
856 | }
857 |
858 | void InitTouch(bool isReadOnly) {
859 | if (isReadOnly) {
860 | std::thread *touch_thread = new std::thread(handleIMGUITouchEvent);
861 | touch_thread->detach();
862 | } else {
863 | std::thread *touch_thread = new std::thread(handleAndroidTouchAndIMGUI);
864 | touch_thread->detach();
865 | }
866 | }
867 |
868 | void handleVolumeupEvent() {
869 | // 上音量键
870 | std::thread([]() {
871 | int fd;
872 | char temp[19];
873 | sprintf(temp, "/dev/input/event%d", get_volume_event_num(KEY_VOLUMEUP));
874 | // printf("%s\n", temp);
875 | fd = open(temp, O_RDWR);
876 | for (;;) {
877 | struct input_event iel[32];
878 | int32_t readSize = read(fd, &iel, sizeof(struct input_event));
879 | if (readSize <= 0 || (readSize % sizeof(struct input_event)) != 0) {
880 | continue;
881 | }
882 | size_t count = size_t(readSize) / sizeof(struct input_event);
883 | for (int j = 0; j < count; j++) {
884 | auto ie = iel[j];
885 | if (ie.type == EV_KEY && ie.code == KEY_VOLUMEUP && ie.value == 0) {
886 | showMenu = !showMenu;
887 | }
888 | }
889 | std::this_thread::sleep_for(std::chrono::milliseconds(200));
890 | }
891 | }).detach();
892 | }
--------------------------------------------------------------------------------