├── .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 | } --------------------------------------------------------------------------------