├── .clang-format ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── demo ├── demo.cpp ├── imgui │ ├── LICENSE │ ├── README.md │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_impl_dx11.cpp │ ├── imgui_impl_dx11.h │ ├── imgui_impl_win32.cpp │ ├── imgui_impl_win32.h │ ├── imgui_internal.h │ ├── imgui_tables.cpp │ ├── imgui_widgets.cpp │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ └── imstb_truetype.h └── main.cpp ├── openfbxConfig.cmake.in ├── projects ├── genie ├── genie.exe ├── genie.lua └── genie_vs19.bat ├── runtime ├── a.FBX ├── b.fbx ├── c.FBX ├── d.fbx └── license.txt └── src ├── libdeflate.c ├── libdeflate.h ├── ofbx.cpp └── ofbx.h /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | 3 | AlignAfterOpenBracket : false 4 | AlignEscapedNewlinesLeft : true 5 | AlignConsecutiveAssignments : false 6 | AllowAllParametersOfDeclarationOnNextLine : false 7 | AccessModifierOffset : -4 8 | AllowShortCaseLabelsOnASingleLine : true 9 | AllowShortFunctionsOnASingleLine : Inline 10 | AllowShortIfStatementsOnASingleLine : true 11 | AllowShortLoopsOnASingleLine : true 12 | AlwaysBreakAfterDefinitionReturnType : None 13 | BinPackArguments : false 14 | BinPackParameters : false 15 | BreakBeforeBraces : Allman 16 | BreakConstructorInitializersBeforeComma : true 17 | ColumnLimit : 120 18 | ConstructorInitializerIndentWidth : 4 19 | ConstructorInitializerAllOnOneLineOrOnePerLine : false 20 | ContinuationIndentWidth : 4 21 | IndentCaseLabels : true 22 | IndentWidth : 4 23 | KeepEmptyLinesAtTheStartOfBlocks : true 24 | MaxEmptyLinesToKeep : 2 25 | NamespaceIndentation : None 26 | PenaltyBreakBeforeFirstCallParameter : 0 27 | PenaltyReturnTypeOnItsOwnLine : 1000 28 | PointerAlignment : Left 29 | SpaceAfterCStyleCast : false 30 | SpaceBeforeAssignmentOperators : true 31 | SpaceBeforeParens : true 32 | SpaceInEmptyParentheses : false 33 | SpacesBeforeTrailingComments : 1 34 | SpacesInAngles : false 35 | SpacesInCStyleCastParentheses : false 36 | SpacesInParentheses : false 37 | SpacesInSquareBrackets : false 38 | Standard : Cpp11 39 | TabWidth : 4 40 | UseTab : true 41 | 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push] 3 | jobs: 4 | windows: 5 | runs-on: windows-2019 6 | steps: 7 | - uses: actions/checkout@v1 8 | with: 9 | fetch-depth: 1 10 | - name: make project 11 | working-directory: projects 12 | run: | 13 | ./genie.exe vs2019 14 | - name: build engine 15 | working-directory: projects 16 | shell: cmd 17 | run: | 18 | "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/MSBuild/Current/Bin/MSBuild.exe" tmp/vs2019/OpenFBX.sln /p:Configuration=RelWithDebInfo 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | projects/tmp/* 30 | 31 | # Executables 32 | *.out 33 | *.app 34 | 35 | runtime/imgui.ini 36 | build/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | 3 | project(OpenFBX LANGUAGES CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | 7 | include(GNUInstallDirs) 8 | include(FetchContent) 9 | 10 | FetchContent_Declare( 11 | libdeflate 12 | GIT_REPOSITORY https://github.com/ebiggers/libdeflate.git 13 | GIT_TAG master 14 | ) 15 | FetchContent_MakeAvailable(libdeflate) 16 | 17 | # Check if libdeflate_static is already defined 18 | if(NOT TARGET libdeflate_static) 19 | add_library(libdeflate_static STATIC IMPORTED) 20 | set_target_properties(libdeflate_static PROPERTIES 21 | IMPORTED_LOCATION "${libdeflate_SOURCE_DIR}/libdeflate.a" 22 | INTERFACE_INCLUDE_DIRECTORIES "${libdeflate_SOURCE_DIR}" 23 | ) 24 | endif() 25 | 26 | # Check if libdeflate_shared is already defined 27 | if(NOT TARGET libdeflate_shared) 28 | add_library(libdeflate_shared SHARED IMPORTED) 29 | set_target_properties(libdeflate_shared PROPERTIES 30 | IMPORTED_LOCATION "${libdeflate_SOURCE_DIR}/libdeflate.so" 31 | INTERFACE_INCLUDE_DIRECTORIES "${libdeflate_SOURCE_DIR}" 32 | ) 33 | endif() 34 | 35 | add_library(OpenFBX src/ofbx.cpp) 36 | target_link_libraries(OpenFBX PRIVATE libdeflate_static) 37 | 38 | target_include_directories(OpenFBX 39 | PUBLIC 40 | $ 41 | $ 42 | PRIVATE 43 | ${libdeflate_SOURCE_DIR} 44 | ) 45 | 46 | target_compile_definitions(OpenFBX PRIVATE _LARGEFILE64_SOURCE) 47 | set_target_properties(OpenFBX PROPERTIES 48 | WINDOWS_EXPORT_ALL_SYMBOLS ON 49 | POSITION_INDEPENDENT_CODE ON) 50 | 51 | install(TARGETS OpenFBX EXPORT openfbxTargets 52 | RUNTIME DESTINATION bin 53 | ARCHIVE DESTINATION lib 54 | LIBRARY DESTINATION lib 55 | INCLUDES DESTINATION include) 56 | 57 | include(CMakePackageConfigHelpers) 58 | configure_package_config_file( 59 | openfbxConfig.cmake.in 60 | "${CMAKE_CURRENT_BINARY_DIR}/openfbxConfig.cmake" 61 | INSTALL_DESTINATION "${CMAKE_INSTALL_DATADIR}/openfbx" 62 | ) 63 | 64 | install( 65 | FILES "${CMAKE_CURRENT_BINARY_DIR}/openfbxConfig.cmake" 66 | DESTINATION "${CMAKE_INSTALL_DATADIR}/openfbx" 67 | ) 68 | 69 | install( 70 | EXPORT openfbxTargets 71 | FILE openfbxTargets.cmake 72 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/openfbx 73 | ) 74 | 75 | install(FILES ${CMAKE_SOURCE_DIR}/src/ofbx.h 76 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} 77 | ) 78 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Mikulas Florek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Discord Chat](https://img.shields.io/discord/480318777943392266.svg)](https://discord.gg/RgFybs6) 2 | [![License](http://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) 3 | ![build status](https://github.com/nem0/openfbx/actions/workflows/build.yml/badge.svg) 4 | 5 | # OpenFBX 6 | 7 | Lightweight open source FBX importer. Used in [Lumix Engine](https://github.com/nem0/lumixengine) and [Flax Engine](https://flaxengine.com/). It's an *almost* full-featured importer. It can load geometry (with uvs, normals, tangents, colors), skeletons, animations, blend shapes, materials, textures, cameras and lights. 8 | 9 | [UFBX](https://github.com/bqqbarbhg/ufbx) is similar project in C. 10 | Using [libdeflate](https://github.com/ebiggers/libdeflate) for decompression. 11 | 12 | ## Use the library in your own project 13 | 14 | Note: It's recommended to be familiar with fbx format to use this library, you can read about it more [here](http://help.autodesk.com/view/FBX/2017/ENU/?guid=__files_GUID_F194000D_5AD4_49C1_86CC_5DAC2CE64E97_htm). 15 | 16 | 1. add files from [src](https://github.com/nem0/OpenFBX/tree/master/src) to your project 17 | 2. use 18 | 19 | See [demo](https://github.com/nem0/OpenFBX/blob/master/demo/main.cpp#L203) as an example how to use the library. 20 | See [Lumix Engine](https://github.com/nem0/LumixEngine/blob/master/src/renderer/editor/fbx_importer.cpp) as more advanced use case. 21 | 22 | Alternatively, CMake support is provided by community but it's not supported by me - @nem0. 23 | 24 | ## Compile demo project 25 | 26 | 1. download source code 27 | 2. execute [projects/genie_vs19.bat](https://github.com/nem0/OpenFBX/blob/master/projects/genie_vs19.bat) 28 | 3. open projects/tmp/vs2019/OpenFBX.sln in Visual Studio 2019 29 | 4. compile and run 30 | 31 | Demo is windows only. Library is multiplatform. 32 | 33 | ![ofbx](https://user-images.githubusercontent.com/153526/27876079-eea3c872-61b5-11e7-9fce-3a7c558fb0d2.png) 34 | -------------------------------------------------------------------------------- /demo/demo.cpp: -------------------------------------------------------------------------------- 1 | #include "../src/ofbx.h" 2 | #include "imgui.h" 3 | #include "imgui_impl_win32.h" 4 | #include "imgui_impl_dx11.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | ofbx::IScene* g_scene = nullptr; 12 | const ofbx::IElement* g_selected_element = nullptr; 13 | const ofbx::Object* g_selected_object = nullptr; 14 | 15 | template 16 | void catProperty(char(&out)[N], const ofbx::IElementProperty& prop) 17 | { 18 | char tmp[127]; 19 | switch (prop.getType()) 20 | { 21 | case ofbx::IElementProperty::DOUBLE: sprintf_s(tmp, "%f", prop.getValue().toDouble()); break; 22 | case ofbx::IElementProperty::LONG: sprintf_s(tmp, "%" PRId64, prop.getValue().toU64()); break; 23 | case ofbx::IElementProperty::INTEGER: sprintf_s(tmp, "%d", prop.getValue().toInt()); break; 24 | case ofbx::IElementProperty::STRING: prop.getValue().toString(tmp); break; 25 | default: sprintf_s(tmp, "Type: %c", (char)prop.getType()); break; 26 | } 27 | strcat_s(out, tmp); 28 | } 29 | 30 | void gui(const ofbx::IElement& parent) { 31 | for (const ofbx::IElement* element = parent.getFirstChild(); element; element = element->getSibling()) { 32 | auto id = element->getID(); 33 | char label[1024]; 34 | id.toString(label); 35 | strcat_s(label, " ("); 36 | ofbx::IElementProperty* prop = element->getFirstProperty(); 37 | bool first = true; 38 | while (prop) 39 | { 40 | if (!first) 41 | strcat_s(label, ", "); 42 | first = false; 43 | catProperty(label, *prop); 44 | prop = prop->getNext(); 45 | } 46 | strcat_s(label, ")"); 47 | 48 | ImGui::PushID((const void*)id.begin); 49 | ImGuiTreeNodeFlags flags = g_selected_element == element ? ImGuiTreeNodeFlags_Selected : 0; 50 | if (!element->getFirstChild()) flags |= ImGuiTreeNodeFlags_Leaf; 51 | if (ImGui::TreeNodeEx(label, flags)) { 52 | if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) g_selected_element = element; 53 | if (element->getFirstChild()) gui(*element); 54 | ImGui::TreePop(); 55 | } 56 | else 57 | { 58 | if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) g_selected_element = element; 59 | } 60 | ImGui::PopID(); 61 | } 62 | } 63 | 64 | template 65 | void toString(ofbx::DataView view, char (&out)[N]) 66 | { 67 | int len = int(view.end - view.begin); 68 | if (len > sizeof(out) - 1) len = sizeof(out) - 1; 69 | strncpy(out, (const char*)view.begin, len); 70 | out[len] = 0; 71 | } 72 | 73 | template 74 | void showArray(const char* label, const char* format, ofbx::IElementProperty& prop) 75 | { 76 | if (!ImGui::CollapsingHeader(label)) return; 77 | 78 | int count = prop.getCount(); 79 | ImGui::Text("Count: %d", count); 80 | std::vector tmp; 81 | tmp.resize(count); 82 | prop.getValues(&tmp[0], int(sizeof(tmp[0]) * tmp.size())); 83 | for (T v : tmp) 84 | { 85 | ImGui::Text(format, v); 86 | } 87 | } 88 | 89 | 90 | void gui(ofbx::IElementProperty& prop) 91 | { 92 | ImGui::PushID((void*)&prop); 93 | char tmp[256]; 94 | switch (prop.getType()) 95 | { 96 | case ofbx::IElementProperty::LONG: ImGui::Text("Long: %" PRId64, prop.getValue().toU64()); break; 97 | case ofbx::IElementProperty::FLOAT: ImGui::Text("Float: %f", prop.getValue().toFloat()); break; 98 | case ofbx::IElementProperty::DOUBLE: ImGui::Text("Double: %f", prop.getValue().toDouble()); break; 99 | case ofbx::IElementProperty::INTEGER: ImGui::Text("Integer: %d", prop.getValue().toInt()); break; 100 | case ofbx::IElementProperty::ARRAY_FLOAT: showArray("float array", "%f", prop); break; 101 | case ofbx::IElementProperty::ARRAY_DOUBLE: showArray("double array", "%f", prop); break; 102 | case ofbx::IElementProperty::ARRAY_INT: showArray("int array", "%d", prop); break; 103 | case ofbx::IElementProperty::ARRAY_LONG: showArray("long array", "%" PRId64, prop); break; 104 | case ofbx::IElementProperty::STRING: 105 | toString(prop.getValue(), tmp); 106 | ImGui::Text("String: %s", tmp); 107 | break; 108 | default: 109 | ImGui::Text("Other: %c", (char)prop.getType()); 110 | break; 111 | } 112 | 113 | ImGui::PopID(); 114 | if (prop.getNext()) gui(*prop.getNext()); 115 | } 116 | 117 | static void guiCurve(const ofbx::Object& object) { 118 | const ofbx::AnimationCurve& curve = static_cast(object); 119 | 120 | const int c = curve.getKeyCount(); 121 | for (int i = 0; i < c; ++i) { 122 | const float t = (float)ofbx::fbxTimeToSeconds(curve.getKeyTime()[i]); 123 | const float v = curve.getKeyValue()[i]; 124 | ImGui::Text("%fs: %f ", t, v); 125 | 126 | } 127 | } 128 | 129 | void guiObjects(const ofbx::Object& object) 130 | { 131 | const char* label; 132 | switch (object.getType()) 133 | { 134 | case ofbx::Object::Type::GEOMETRY: label = "geometry"; break; 135 | case ofbx::Object::Type::MESH: label = "mesh"; break; 136 | case ofbx::Object::Type::MATERIAL: label = "material"; break; 137 | case ofbx::Object::Type::ROOT: label = "root"; break; 138 | case ofbx::Object::Type::TEXTURE: label = "texture"; break; 139 | case ofbx::Object::Type::NULL_NODE: label = "null"; break; 140 | case ofbx::Object::Type::LIMB_NODE: label = "limb node"; break; 141 | case ofbx::Object::Type::NODE_ATTRIBUTE: label = "node attribute"; break; 142 | case ofbx::Object::Type::CLUSTER: label = "cluster"; break; 143 | case ofbx::Object::Type::SKIN: label = "skin"; break; 144 | case ofbx::Object::Type::ANIMATION_STACK: label = "animation stack"; break; 145 | case ofbx::Object::Type::ANIMATION_LAYER: label = "animation layer"; break; 146 | case ofbx::Object::Type::ANIMATION_CURVE: label = "animation curve"; break; 147 | case ofbx::Object::Type::ANIMATION_CURVE_NODE: label = "animation curve node"; break; 148 | case ofbx::Object::Type::LIGHT: label = "light"; break; 149 | case ofbx::Object::Type::CAMERA: label = "camera"; break; 150 | default: assert(false); break; 151 | } 152 | 153 | ImGuiTreeNodeFlags flags = g_selected_object == &object ? ImGuiTreeNodeFlags_Selected : 0; 154 | char tmp[128]; 155 | sprintf_s(tmp, "%" PRId64 " %s (%s)", object.id, object.name, label); 156 | if (ImGui::TreeNodeEx(tmp, flags)) 157 | { 158 | if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) g_selected_object = &object; 159 | int i = 0; 160 | while (ofbx::Object* child = object.resolveObjectLink(i)) 161 | { 162 | guiObjects(*child); 163 | ++i; 164 | } 165 | if(object.getType() == ofbx::Object::Type::ANIMATION_CURVE) { 166 | guiCurve(object); 167 | } 168 | 169 | ImGui::TreePop(); 170 | } 171 | else 172 | { 173 | if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) g_selected_object = &object; 174 | } 175 | } 176 | 177 | void guiObjects(const ofbx::IScene& scene) 178 | { 179 | if (!ImGui::Begin("Objects")) 180 | { 181 | ImGui::End(); 182 | return; 183 | } 184 | const ofbx::Object* root = scene.getRoot(); 185 | if (root) guiObjects(*root); 186 | 187 | int count = scene.getAnimationStackCount(); 188 | for (int i = 0; i < count; ++i) 189 | { 190 | const ofbx::Object* stack = scene.getAnimationStack(i); 191 | guiObjects(*stack); 192 | } 193 | 194 | ImGui::End(); 195 | } 196 | 197 | 198 | void demoGUI() { 199 | if (ImGui::Begin("Elements")) { 200 | const ofbx::IElement* root = g_scene->getRootElement(); 201 | if (root && root->getFirstChild()) gui(*root); 202 | } 203 | ImGui::End(); 204 | 205 | if (ImGui::Begin("Properties") && g_selected_element) 206 | { 207 | ofbx::IElementProperty* prop = g_selected_element->getFirstProperty(); 208 | if (prop) gui(*prop); 209 | } 210 | ImGui::End(); 211 | guiObjects(*g_scene); 212 | } 213 | 214 | 215 | bool saveAsOBJ(ofbx::IScene& scene, const char* path) 216 | { 217 | FILE* fp = fopen(path, "wb"); 218 | if (!fp) return false; 219 | int indices_offset = 0; 220 | int mesh_count = scene.getMeshCount(); 221 | 222 | // output unindexed geometry 223 | for (int mesh_idx = 0; mesh_idx < mesh_count; ++mesh_idx) { 224 | const ofbx::Mesh& mesh = *scene.getMesh(mesh_idx); 225 | const ofbx::GeometryData& geom = mesh.getGeometryData(); 226 | const ofbx::Vec3Attributes positions = geom.getPositions(); 227 | const ofbx::Vec3Attributes normals = geom.getNormals(); 228 | const ofbx::Vec2Attributes uvs = geom.getUVs(); 229 | 230 | // each ofbx::Mesh can have several materials == partitions 231 | for (int partition_idx = 0; partition_idx < geom.getPartitionCount(); ++partition_idx) { 232 | fprintf(fp, "o obj%d_%d\ng grp%d\n", mesh_idx, partition_idx, mesh_idx); 233 | const ofbx::GeometryPartition& partition = geom.getPartition(partition_idx); 234 | 235 | // partitions most likely have several polygons, they are not triangles necessarily, use ofbx::triangulate if you want triangles 236 | for (int polygon_idx = 0; polygon_idx < partition.polygon_count; ++polygon_idx) { 237 | const ofbx::GeometryPartition::Polygon& polygon = partition.polygons[polygon_idx]; 238 | 239 | for (int i = polygon.from_vertex; i < polygon.from_vertex + polygon.vertex_count; ++i) { 240 | ofbx::Vec3 v = positions.get(i); 241 | fprintf(fp, "v %f %f %f\n", v.x, v.y, v.z); 242 | } 243 | 244 | bool has_normals = normals.values != nullptr; 245 | if (has_normals) { 246 | // normals.indices might be different than positions.indices 247 | // but normals.get(i) is normal for positions.get(i) 248 | for (int i = polygon.from_vertex; i < polygon.from_vertex + polygon.vertex_count; ++i) { 249 | ofbx::Vec3 n = normals.get(i); 250 | fprintf(fp, "vn %f %f %f\n", n.x, n.y, n.z); 251 | } 252 | } 253 | 254 | bool has_uvs = uvs.values != nullptr; 255 | if (has_uvs) { 256 | for (int i = polygon.from_vertex; i < polygon.from_vertex + polygon.vertex_count; ++i) { 257 | ofbx::Vec2 uv = uvs.get(i); 258 | fprintf(fp, "vt %f %f\n", uv.x, uv.y); 259 | } 260 | } 261 | } 262 | 263 | for (int polygon_idx = 0; polygon_idx < partition.polygon_count; ++polygon_idx) { 264 | const ofbx::GeometryPartition::Polygon& polygon = partition.polygons[polygon_idx]; 265 | fputs("f ", fp); 266 | for (int i = polygon.from_vertex; i < polygon.from_vertex + polygon.vertex_count; ++i) { 267 | fprintf(fp, "%d ", 1 + i + indices_offset); 268 | } 269 | fputs("\n", fp); 270 | } 271 | 272 | indices_offset += positions.count; 273 | } 274 | } 275 | fclose(fp); 276 | return true; 277 | } 278 | 279 | 280 | bool initOpenFBX(const char* filepath, HWND hwnd) { 281 | static char s_TimeString[256]; 282 | FILE* fp = fopen(filepath, "rb"); 283 | 284 | if (!fp) return false; 285 | 286 | fseek(fp, 0, SEEK_END); 287 | long file_size = ftell(fp); 288 | fseek(fp, 0, SEEK_SET); 289 | auto* content = new ofbx::u8[file_size]; 290 | fread(content, 1, file_size, fp); 291 | 292 | // Start Timer 293 | LARGE_INTEGER frequency; 294 | QueryPerformanceFrequency(&frequency); 295 | LARGE_INTEGER start; 296 | QueryPerformanceCounter(&start); 297 | 298 | // Ignoring certain nodes will only stop them from being processed not tokenised (i.e. they will still be in the tree) 299 | ofbx::LoadFlags flags = 300 | // ofbx::LoadFlags::IGNORE_MODELS | 301 | ofbx::LoadFlags::IGNORE_BLEND_SHAPES | 302 | ofbx::LoadFlags::IGNORE_CAMERAS | 303 | ofbx::LoadFlags::IGNORE_LIGHTS | 304 | // ofbx::LoadFlags::IGNORE_TEXTURES | 305 | ofbx::LoadFlags::IGNORE_SKIN | 306 | ofbx::LoadFlags::IGNORE_BONES | 307 | ofbx::LoadFlags::IGNORE_PIVOTS | 308 | // ofbx::LoadFlags::IGNORE_MATERIALS | 309 | ofbx::LoadFlags::IGNORE_POSES | 310 | ofbx::LoadFlags::IGNORE_VIDEOS | 311 | ofbx::LoadFlags::IGNORE_LIMBS | 312 | // ofbx::LoadFlags::IGNORE_MESHES | 313 | ofbx::LoadFlags::IGNORE_ANIMATIONS; 314 | 315 | g_scene = ofbx::load((ofbx::u8*)content, file_size, (ofbx::u16)flags); 316 | 317 | // Stop Timer 318 | LARGE_INTEGER stop; 319 | QueryPerformanceCounter(&stop); 320 | double elapsed = (double)(stop.QuadPart - start.QuadPart) / (double)frequency.QuadPart; 321 | snprintf(s_TimeString, 322 | sizeof(s_TimeString), 323 | "Loading took %f seconds (%.0f ms) to load %s file of size %d bytes (%f MB) \r ", 324 | elapsed, 325 | elapsed * 1000.0, 326 | filepath, 327 | file_size, 328 | (double)file_size / (1024.0 * 1024.0)); 329 | 330 | 331 | if(!g_scene) { 332 | OutputDebugString(ofbx::getError()); 333 | } 334 | else { 335 | //saveAsOBJ(*g_scene, "out.obj"); 336 | } 337 | delete[] content; 338 | fclose(fp); 339 | saveAsOBJ(*g_scene, "out.obj"); 340 | 341 | // Make the window title s_TimeString 342 | SetWindowText(hwnd, s_TimeString); 343 | return true; 344 | } 345 | -------------------------------------------------------------------------------- /demo/imgui/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Omar Cornut and ImGui contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/imgui/README.md: -------------------------------------------------------------------------------- 1 | dear imgui, 2 | ===== 3 | [![Build Status](https://travis-ci.org/ocornut/imgui.svg?branch=master)](https://travis-ci.org/ocornut/imgui) 4 | [![Coverity Status](https://scan.coverity.com/projects/4720/badge.svg)](https://scan.coverity.com/projects/4720) 5 | 6 | (This library is free and will stay free, but needs your support to sustain its development. There are lots of desirable new features and maintenance to do. If you work for a company using ImGui or have the means to do so, please consider financial support) 7 | 8 | [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) 9 | 10 | dear imgui (AKA ImGui), is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (no external dependencies). 11 | 12 | ImGui is designed to enable fast iteration and empower programmers to create content creation tools and visualization/debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and thus lacks certain features normally found in more high-level libraries. 13 | 14 | ImGui is particularly suited to integration in realtime 3D applications, fullscreen applications, embedded applications, games, or any applications on consoles platforms where operating system features are non-standard. 15 | 16 | ImGui is self-contained within a few files that you can easily copy and compile into your application/engine: 17 | 18 | - imgui.cpp 19 | - imgui.h 20 | - imgui_demo.cpp 21 | - imgui_draw.cpp 22 | - imgui_internal.h 23 | - imconfig.h (empty by default, user-editable) 24 | - stb_rect_pack.h 25 | - stb_textedit.h 26 | - stb_truetype.h 27 | 28 | No specific build process is required. You can add the .cpp files to your project or #include them from an existing file. 29 | 30 | Your code passes mouse/keyboard inputs and settings to ImGui (see example applications for more details). After ImGui is setup, you can use it like in this example: 31 | 32 | ![screenshot of sample code alongside its output with ImGui](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/code_sample_01.png) 33 | 34 | ImGui outputs vertex buffers and simple command-lists that you can render in your application. The number of draw calls and state changes is typically very small. Because it doesn't know or touch graphics state directly, you can call ImGui commands anywhere in your code (e.g. in the middle of a running algorithm, or in the middle of your own rendering process). Refer to the sample applications in the examples/ folder for instructions on how to integrate ImGui with your existing codebase. 35 | 36 | ImGui allows you create elaborate tools as well as very short-lived ones. On the extreme side of short-liveness: using the Edit&Continue feature of modern compilers you can add a few widgets to tweaks variables while your application is running, and remove the code a minute later! ImGui is not just for tweaking values. You can use it to trace a running algorithm by just emitting text commands. You can use it along with your own reflection data to browse your dataset live. You can use it to expose the internals of a subsystem in your engine, to create a logger, an inspection tool, a profiler, a debugger, etc. 37 | 38 | Demo 39 | ---- 40 | 41 | You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at the features of ImGui, you can download Windows binaries of the demo app here. 42 | - [imgui-demo-binaries-20151226.zip](http://www.miracleworld.net/imgui/binaries/imgui-demo-binaries-20151226.zip) (Windows binaries, ImGui 1.47 2015/12/26, 4 executables, 515 KB) 43 | 44 | 45 | Gallery 46 | ------- 47 | 48 | See the [Screenshots Thread](https://github.com/ocornut/imgui/issues/123) for some user creations. 49 | 50 | ![screenshot 1](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_01.png) 51 | ![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/examples_02.png) 52 | 53 | [![profiler](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler-880.jpg)](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v148/profiler.png) 54 | 55 | ![screenshot 2](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_01.png) 56 | ![screenshot 3](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_02.png) 57 | ![screenshot 4](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/test_window_03.png) 58 | ![screenshot 5](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v140/test_window_05_menus.png) 59 | ![screenshot 6](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v143/skinning_sample_02.png) 60 | ![screenshot 7](https://cloud.githubusercontent.com/assets/8225057/7903336/96f0fb7c-07d0-11e5-95d6-41c6a1595e5a.png) 61 | 62 | ImGui can load TTF fonts. UTF-8 is supported for text display and input. Here using Arial Unicode font to display Japanese. Initialize custom font with: 63 | ``` 64 | ImGuiIO& io = ImGui::GetIO(); 65 | io.Fonts->AddFontFromFileTTF("ArialUni.ttf", 18.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); 66 | 67 | // For Microsoft IME, pass your HWND to enable IME positioning: 68 | io.ImeWindowHandle = my_hwnd; 69 | ``` 70 | ![Japanese screenshot](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/code_sample_01_jp.png) 71 | 72 | References 73 | ---------- 74 | 75 | The Immediate Mode GUI paradigm may at first appear unusual to some users. This is mainly because "Retained Mode" GUIs have been so widespread and predominant. The following links can give you a better understanding about how Immediate Mode GUIs works. 76 | - [Johannes 'johno' Norneby's article](http://www.johno.se/book/imgui.html). 77 | - [A presentation by Rickard Gustafsson and Johannes Algelind](http://www.cse.chalmers.se/edu/year/2011/course/TDA361/Advanced%20Computer%20Graphics/IMGUI.pdf). 78 | - [Jari Komppa's tutorial on building an ImGui library](http://iki.fi/sol/imgui/). 79 | - [Casey Muratori's original video that popularized the concept](https://mollyrocket.com/861). 80 | 81 | See the [Links page](https://github.com/ocornut/imgui/wiki/Links) for third-party bindings to different languages and frameworks. 82 | 83 | Frequently Asked Question (FAQ) 84 | ------------------------------- 85 | 86 | Where is the documentation? 87 | 88 | - The documentation is at the top of imgui.cpp + effectively imgui.h. 89 | - Example code is in imgui_demo.cpp and particularly the ImGui::ShowTestWindow() function. It covers most features of ImGui so you can read the code and call the function itself to see its output. 90 | - Standalone example applications using e.g. OpenGL/DirectX are provided in the examples/ folder. 91 | - We obviously needs better documentation! Consider contributing or becoming a [Patron](http://www.patreon.com/imgui) to promote this effort. 92 | 93 | Why the odd dual naming, "dear imgui" vs "ImGui"? 94 | 95 | The library started its life and is best known as "ImGui" only due to the fact that I didn't give it a proper name when I released it. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations. It seemed confusing and unfair to hog the name. To reduce the ambiguity without affecting existing codebases, I have decided on an alternate, longer name "dear imgui" that people can use to refer to this specific library in ambiguous situations. 96 | 97 | How do I update to a newer version of ImGui? 98 |
Can I have multiple widgets with the same label? Can I have widget without a label? (Yes) 99 |
I integrated ImGui in my engine and the text or lines are blurry.. 100 |
I integrated ImGui in my engine and some elements are disappearing when I move windows around.. 101 |
How can I load a different font than the default? 102 |
How can I load multiple fonts? 103 |
How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic? 104 | 105 | See the FAQ in imgui.cpp for answers. 106 | 107 | How do you use ImGui on a platform that may not have a mouse or keyboard? 108 | 109 | I recommend using [Synergy](http://synergy-project.org) ([sources](https://github.com/synergy/synergy)). In particular, the _src/micro/uSynergy.c_ file contains a small client that you can use on any platform to connect to your host PC. You can seamlessly use your PC input devices from a video game console or a tablet. ImGui allows to increase the hit box of widgets (via the _TouchPadding_ setting) to accommodate a little for the lack of precision of touch inputs, but it is recommended you use a mouse to allow optimising for screen real-estate. 110 | 111 | Can you create elaborate/serious tools with ImGui? 112 | 113 | Yes. I have written data browsers, debuggers, profilers and all sort of non-trivial tools with the library. In my experience the simplicity of the API is very empowering. Your UI runs close to your live data. Make the tools always-on and everybody in the team will be inclined to create new tools (as opposed to more "offline" UI toolkits where only a fraction of your team effectively creates tools). 114 | 115 | ImGui is very programmer centric and the immediate-mode GUI paradigm might requires you to readjust some habits before you can realize its full potential. Many programmers have unfortunately been taught by their environment to make unnecessarily complicated things. ImGui is about making things that are simple, efficient and powerful. 116 | 117 | Is ImGui fast? 118 | 119 | Probably fast enough for most uses. Down to the fundation of its visual design, ImGui is engineered to be fairly performant both in term of CPU and GPU usage. Running elaborate code and creating elaborate UI will of course have a cost but ImGui aims to minimize it. 120 | 121 | Mileage may vary but the following screenshot can give you a rough idea of the cost of running and rendering UI code (In the case of a trivial demo application like this one, your driver/os setup are likely to be the bottleneck. Testing performance as part of a real application is recommended). 122 | 123 | ![performance screenshot](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v138/performance_01.png) 124 | 125 | This is showing framerate for the full application loop on my 2011 iMac running Windows 7, OpenGL, AMD Radeon HD 6700M with an optimized executable. In contrast, librairies featuring higher-quality rendering and layouting techniques may have a higher resources footprint. 126 | 127 | If you intend to display large lists of items (say, 1000+) it can be beneficial for your code to perform clipping manually - one way is using helpers such as ImGuiListClipper - in order to avoid submitting them to ImGui in the first place. Even though ImGui will discard your clipped items it still needs to calculate their size and that overhead will add up if you have thousands of items. If you can handle clipping and height positionning yourself then browsing a list with millions of items isn't a problem. 128 | 129 | Can you reskin the look of ImGui? 130 | 131 | You can alter the look of the interface to some degree: changing colors, sizes, padding, rounding, fonts. However, as ImGui is designed and optimised to create debug tools, the amount of skinning you can apply is limited. There is only so much you can stray away from the default look and feel of the interface. 132 | 133 | This is [LumixEngine](https://github.com/nem0/LumixEngine) with a minor skinning hack + a docking/tabs extension (both of which you can find in the Issues section and will eventually be merged). 134 | 135 | [![Skinning in LumixEngine](https://cloud.githubusercontent.com/assets/8225057/13198792/92808c5c-d812-11e5-9507-16b63918b05b.jpg)](https://cloud.githubusercontent.com/assets/8225057/13044612/59f07aec-d3cf-11e5-8ccb-39adf2e13e69.png) 136 | 137 | Why using C++ (as opposed to C)? 138 | 139 | ImGui takes advantage of a few C++ features for convenience but nothing anywhere Boost-insanity/quagmire. In particular, function overloading and default parameters are used to make the API easier to use and code more terse. Doing so I believe the API is sitting on a sweet spot and giving up on those features would make the API more cumbersome. Other features such as namespace, constructors and templates (in the case of the ImVector<> class) are also relied on as a convenience but could be removed. 140 | 141 | There is an unofficial but reasonably maintained [c-api for ImGui](https://github.com/Extrawurst/cimgui) by Stephan Dilly. I would suggest using your target language functionality to try replicating the function overloading and default parameters used in C++ else the API may be harder to use. It was really designed with C++ in mind and may not make the same amount of sense with another language. Also see [Links](https://github.com/ocornut/imgui/wiki/Links) for third-party bindings to other languages. 142 | 143 | Donate 144 | ------ 145 | 146 | Can I donate to support the development of ImGui? 147 | 148 | [![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5Q73FPZ9C526U) 149 | 150 | I'm currently an independent developer and your contributions are useful. I have setup an [**ImGui Patreon page**](http://www.patreon.com/imgui) if you want to donate and enable me to spend more time improving the library. If your company uses ImGui please consider making a contribution. One-off donations are also greatly appreciated. I am available for hire to work on or with ImGui. Thanks! 151 | 152 | Credits 153 | ------- 154 | 155 | Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com). 156 | 157 | I first discovered imgui principles at [Q-Games](http://www.q-games.com) where Atman had dropped his own simple imgui implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating on it. 158 | 159 | Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT license). 160 | 161 | Embeds [stb_textedit.h, stb_truetype.h, stb_rectpack.h](https://github.com/nothings/stb/) by Sean Barrett (public domain). 162 | 163 | Inspiration, feedback, and testing for early versions: Casey Muratori, Atman Binstock, Mikko Mononen, Emmanuel Briney, Stefan Kamoda, Anton Mikhailov, Matt Willis. And everybody posting feedback, questions and patches on the GitHub. 164 | 165 | ImGui development is financially supported on [**Patreon**](http://www.patreon.com/imgui). 166 | 167 | Special supporters: 168 | - Jetha Chan, Wild Sheep Studio, Pastagames, Mārtiņš Možeiko, Daniel Collin, Stefano Cristiano. 169 | 170 | And: 171 | - Michel Courtine, César Leblic, Dale Kim, Alex Evans, Rui Figueira, Paul Patrashcu, Jerome Lanquetot, Ctrl Alt Ninja, Paul Fleming, Neil Henning, Stephan Dilly, Neil Blakey-Milner, Aleksei, NeiloGD, Justin Paver, FiniteSol, Vincent Pancaldi, James Billot, Robin Hübner, furrtek, Eric, Simon Barratt, Game Atelier, Julian Bosch, Simon Lundmark, Vincent Hamm. 172 | 173 | And other supporters; thanks! 174 | 175 | License 176 | ------- 177 | 178 | Dear ImGui is licensed under the MIT License, see LICENSE for more information. 179 | -------------------------------------------------------------------------------- /demo/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 IMGUI_USE_STB_SPRINTF is defined. 66 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 67 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 68 | //#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined. 69 | 70 | //---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined) 71 | // 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. 72 | //#define IMGUI_USE_STB_SPRINTF 73 | 74 | //---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui) 75 | // 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). 76 | // On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'. 77 | //#define IMGUI_ENABLE_FREETYPE 78 | 79 | //---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT) 80 | // Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided). 81 | // Only works in combination with IMGUI_ENABLE_FREETYPE. 82 | // (implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement) 83 | //#define IMGUI_ENABLE_FREETYPE_LUNASVG 84 | 85 | //---- Use stb_truetype to build and rasterize the font atlas (default) 86 | // The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend. 87 | //#define IMGUI_ENABLE_STB_TRUETYPE 88 | 89 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 90 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 91 | /* 92 | #define IM_VEC2_CLASS_EXTRA \ 93 | constexpr ImVec2(const MyVec2& f) : x(f.x), y(f.y) {} \ 94 | operator MyVec2() const { return MyVec2(x,y); } 95 | 96 | #define IM_VEC4_CLASS_EXTRA \ 97 | constexpr ImVec4(const MyVec4& f) : x(f.x), y(f.y), z(f.z), w(f.w) {} \ 98 | operator MyVec4() const { return MyVec4(x,y,z,w); } 99 | */ 100 | //---- ...Or use Dear ImGui's own very basic math operators. 101 | //#define IMGUI_DEFINE_MATH_OPERATORS 102 | 103 | //---- Use 32-bit vertex indices (default is 16-bit) is one way to allow large meshes with more than 64K vertices. 104 | // Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices). 105 | // Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer. 106 | // Read about ImGuiBackendFlags_RendererHasVtxOffset for details. 107 | //#define ImDrawIdx unsigned int 108 | 109 | //---- Override ImDrawCallback signature (will need to modify renderer backends accordingly) 110 | //struct ImDrawList; 111 | //struct ImDrawCmd; 112 | //typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data); 113 | //#define ImDrawCallback MyImDrawCallback 114 | 115 | //---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase) 116 | // (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.) 117 | //#define IM_DEBUG_BREAK IM_ASSERT(0) 118 | //#define IM_DEBUG_BREAK __debugbreak() 119 | 120 | //---- Debug Tools: Enable slower asserts 121 | //#define IMGUI_DEBUG_PARANOID 122 | 123 | //---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files) 124 | /* 125 | namespace ImGui 126 | { 127 | void MyFunction(const char* name, MyMatrix44* mtx); 128 | } 129 | */ 130 | -------------------------------------------------------------------------------- /demo/imgui/imgui_impl_dx11.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX11 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. 7 | // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. 8 | 9 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 10 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 11 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 12 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 13 | 14 | // CHANGELOG 15 | // (minor and older changes stripped away, please see git history for details) 16 | // 2023-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. 17 | // 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11. 18 | // 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). 19 | // 2021-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement) 20 | // 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer. 21 | // 2019-08-01: DirectX11: Fixed code querying the Geometry Shader state (would generally error with Debug layer enabled). 22 | // 2019-07-21: DirectX11: Backup, clear and restore Geometry Shader is any is bound when calling ImGui_ImplDX10_RenderDrawData. Clearing Hull/Domain/Compute shaders without backup/restore. 23 | // 2019-05-29: DirectX11: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. 24 | // 2019-04-30: DirectX11: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. 25 | // 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile(). 26 | // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. 27 | // 2018-08-01: DirectX11: Querying for IDXGIFactory instead of IDXGIFactory1 to increase compatibility. 28 | // 2018-07-13: DirectX11: Fixed unreleased resources in Init and Shutdown functions. 29 | // 2018-06-08: Misc: Extracted imgui_impl_dx11.cpp/.h away from the old combined DX11+Win32 example. 30 | // 2018-06-08: DirectX11: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. 31 | // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX11_RenderDrawData() in the .h file so you can call it yourself. 32 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. 33 | // 2016-05-07: DirectX11: Disabling depth-write. 34 | 35 | #include "imgui.h" 36 | #ifndef IMGUI_DISABLE 37 | #include "imgui_impl_dx11.h" 38 | 39 | // DirectX 40 | #include 41 | #include 42 | #include 43 | #ifdef _MSC_VER 44 | #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. 45 | #endif 46 | 47 | // DirectX11 data 48 | struct ImGui_ImplDX11_Data 49 | { 50 | ID3D11Device* pd3dDevice; 51 | ID3D11DeviceContext* pd3dDeviceContext; 52 | IDXGIFactory* pFactory; 53 | ID3D11Buffer* pVB; 54 | ID3D11Buffer* pIB; 55 | ID3D11VertexShader* pVertexShader; 56 | ID3D11InputLayout* pInputLayout; 57 | ID3D11Buffer* pVertexConstantBuffer; 58 | ID3D11PixelShader* pPixelShader; 59 | ID3D11SamplerState* pFontSampler; 60 | ID3D11ShaderResourceView* pFontTextureView; 61 | ID3D11RasterizerState* pRasterizerState; 62 | ID3D11BlendState* pBlendState; 63 | ID3D11DepthStencilState* pDepthStencilState; 64 | int VertexBufferSize; 65 | int IndexBufferSize; 66 | 67 | ImGui_ImplDX11_Data() { memset((void*)this, 0, sizeof(*this)); VertexBufferSize = 5000; IndexBufferSize = 10000; } 68 | }; 69 | 70 | struct VERTEX_CONSTANT_BUFFER_DX11 71 | { 72 | float mvp[4][4]; 73 | }; 74 | 75 | // Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts 76 | // It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts. 77 | static ImGui_ImplDX11_Data* ImGui_ImplDX11_GetBackendData() 78 | { 79 | return ImGui::GetCurrentContext() ? (ImGui_ImplDX11_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; 80 | } 81 | 82 | // Forward Declarations 83 | static void ImGui_ImplDX11_InitPlatformInterface(); 84 | static void ImGui_ImplDX11_ShutdownPlatformInterface(); 85 | 86 | // Functions 87 | static void ImGui_ImplDX11_SetupRenderState(ImDrawData* draw_data, ID3D11DeviceContext* ctx) 88 | { 89 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 90 | 91 | // Setup viewport 92 | D3D11_VIEWPORT vp; 93 | memset(&vp, 0, sizeof(D3D11_VIEWPORT)); 94 | vp.Width = draw_data->DisplaySize.x; 95 | vp.Height = draw_data->DisplaySize.y; 96 | vp.MinDepth = 0.0f; 97 | vp.MaxDepth = 1.0f; 98 | vp.TopLeftX = vp.TopLeftY = 0; 99 | ctx->RSSetViewports(1, &vp); 100 | 101 | // Setup shader and vertex buffers 102 | unsigned int stride = sizeof(ImDrawVert); 103 | unsigned int offset = 0; 104 | ctx->IASetInputLayout(bd->pInputLayout); 105 | ctx->IASetVertexBuffers(0, 1, &bd->pVB, &stride, &offset); 106 | ctx->IASetIndexBuffer(bd->pIB, sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT, 0); 107 | ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 108 | ctx->VSSetShader(bd->pVertexShader, nullptr, 0); 109 | ctx->VSSetConstantBuffers(0, 1, &bd->pVertexConstantBuffer); 110 | ctx->PSSetShader(bd->pPixelShader, nullptr, 0); 111 | ctx->PSSetSamplers(0, 1, &bd->pFontSampler); 112 | ctx->GSSetShader(nullptr, nullptr, 0); 113 | ctx->HSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. 114 | ctx->DSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. 115 | ctx->CSSetShader(nullptr, nullptr, 0); // In theory we should backup and restore this as well.. very infrequently used.. 116 | 117 | // Setup blend state 118 | const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f }; 119 | ctx->OMSetBlendState(bd->pBlendState, blend_factor, 0xffffffff); 120 | ctx->OMSetDepthStencilState(bd->pDepthStencilState, 0); 121 | ctx->RSSetState(bd->pRasterizerState); 122 | } 123 | 124 | // Render function 125 | void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) 126 | { 127 | // Avoid rendering when minimized 128 | if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f) 129 | return; 130 | 131 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 132 | ID3D11DeviceContext* ctx = bd->pd3dDeviceContext; 133 | 134 | // Create and grow vertex/index buffers if needed 135 | if (!bd->pVB || bd->VertexBufferSize < draw_data->TotalVtxCount) 136 | { 137 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } 138 | bd->VertexBufferSize = draw_data->TotalVtxCount + 5000; 139 | D3D11_BUFFER_DESC desc; 140 | memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); 141 | desc.Usage = D3D11_USAGE_DYNAMIC; 142 | desc.ByteWidth = bd->VertexBufferSize * sizeof(ImDrawVert); 143 | desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 144 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 145 | desc.MiscFlags = 0; 146 | if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVB) < 0) 147 | return; 148 | } 149 | if (!bd->pIB || bd->IndexBufferSize < draw_data->TotalIdxCount) 150 | { 151 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } 152 | bd->IndexBufferSize = draw_data->TotalIdxCount + 10000; 153 | D3D11_BUFFER_DESC desc; 154 | memset(&desc, 0, sizeof(D3D11_BUFFER_DESC)); 155 | desc.Usage = D3D11_USAGE_DYNAMIC; 156 | desc.ByteWidth = bd->IndexBufferSize * sizeof(ImDrawIdx); 157 | desc.BindFlags = D3D11_BIND_INDEX_BUFFER; 158 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 159 | if (bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pIB) < 0) 160 | return; 161 | } 162 | 163 | // Upload vertex/index data into a single contiguous GPU buffer 164 | D3D11_MAPPED_SUBRESOURCE vtx_resource, idx_resource; 165 | if (ctx->Map(bd->pVB, 0, D3D11_MAP_WRITE_DISCARD, 0, &vtx_resource) != S_OK) 166 | return; 167 | if (ctx->Map(bd->pIB, 0, D3D11_MAP_WRITE_DISCARD, 0, &idx_resource) != S_OK) 168 | return; 169 | ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource.pData; 170 | ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource.pData; 171 | for (int n = 0; n < draw_data->CmdListsCount; n++) 172 | { 173 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 174 | memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); 175 | memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); 176 | vtx_dst += cmd_list->VtxBuffer.Size; 177 | idx_dst += cmd_list->IdxBuffer.Size; 178 | } 179 | ctx->Unmap(bd->pVB, 0); 180 | ctx->Unmap(bd->pIB, 0); 181 | 182 | // Setup orthographic projection matrix into our constant buffer 183 | // 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. 184 | { 185 | D3D11_MAPPED_SUBRESOURCE mapped_resource; 186 | if (ctx->Map(bd->pVertexConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource) != S_OK) 187 | return; 188 | VERTEX_CONSTANT_BUFFER_DX11* constant_buffer = (VERTEX_CONSTANT_BUFFER_DX11*)mapped_resource.pData; 189 | float L = draw_data->DisplayPos.x; 190 | float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; 191 | float T = draw_data->DisplayPos.y; 192 | float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; 193 | float mvp[4][4] = 194 | { 195 | { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, 196 | { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, 197 | { 0.0f, 0.0f, 0.5f, 0.0f }, 198 | { (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f }, 199 | }; 200 | memcpy(&constant_buffer->mvp, mvp, sizeof(mvp)); 201 | ctx->Unmap(bd->pVertexConstantBuffer, 0); 202 | } 203 | 204 | // Backup DX state that will be modified to restore it afterwards (unfortunately this is very ugly looking and verbose. Close your eyes!) 205 | struct BACKUP_DX11_STATE 206 | { 207 | UINT ScissorRectsCount, ViewportsCount; 208 | D3D11_RECT ScissorRects[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; 209 | D3D11_VIEWPORT Viewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; 210 | ID3D11RasterizerState* RS; 211 | ID3D11BlendState* BlendState; 212 | FLOAT BlendFactor[4]; 213 | UINT SampleMask; 214 | UINT StencilRef; 215 | ID3D11DepthStencilState* DepthStencilState; 216 | ID3D11ShaderResourceView* PSShaderResource; 217 | ID3D11SamplerState* PSSampler; 218 | ID3D11PixelShader* PS; 219 | ID3D11VertexShader* VS; 220 | ID3D11GeometryShader* GS; 221 | UINT PSInstancesCount, VSInstancesCount, GSInstancesCount; 222 | ID3D11ClassInstance *PSInstances[256], *VSInstances[256], *GSInstances[256]; // 256 is max according to PSSetShader documentation 223 | D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology; 224 | ID3D11Buffer* IndexBuffer, *VertexBuffer, *VSConstantBuffer; 225 | UINT IndexBufferOffset, VertexBufferStride, VertexBufferOffset; 226 | DXGI_FORMAT IndexBufferFormat; 227 | ID3D11InputLayout* InputLayout; 228 | }; 229 | BACKUP_DX11_STATE old = {}; 230 | old.ScissorRectsCount = old.ViewportsCount = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; 231 | ctx->RSGetScissorRects(&old.ScissorRectsCount, old.ScissorRects); 232 | ctx->RSGetViewports(&old.ViewportsCount, old.Viewports); 233 | ctx->RSGetState(&old.RS); 234 | ctx->OMGetBlendState(&old.BlendState, old.BlendFactor, &old.SampleMask); 235 | ctx->OMGetDepthStencilState(&old.DepthStencilState, &old.StencilRef); 236 | ctx->PSGetShaderResources(0, 1, &old.PSShaderResource); 237 | ctx->PSGetSamplers(0, 1, &old.PSSampler); 238 | old.PSInstancesCount = old.VSInstancesCount = old.GSInstancesCount = 256; 239 | ctx->PSGetShader(&old.PS, old.PSInstances, &old.PSInstancesCount); 240 | ctx->VSGetShader(&old.VS, old.VSInstances, &old.VSInstancesCount); 241 | ctx->VSGetConstantBuffers(0, 1, &old.VSConstantBuffer); 242 | ctx->GSGetShader(&old.GS, old.GSInstances, &old.GSInstancesCount); 243 | 244 | ctx->IAGetPrimitiveTopology(&old.PrimitiveTopology); 245 | ctx->IAGetIndexBuffer(&old.IndexBuffer, &old.IndexBufferFormat, &old.IndexBufferOffset); 246 | ctx->IAGetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); 247 | ctx->IAGetInputLayout(&old.InputLayout); 248 | 249 | // Setup desired DX state 250 | ImGui_ImplDX11_SetupRenderState(draw_data, ctx); 251 | 252 | // Render command lists 253 | // (Because we merged all buffers into a single one, we maintain our own offset into them) 254 | int global_idx_offset = 0; 255 | int global_vtx_offset = 0; 256 | ImVec2 clip_off = draw_data->DisplayPos; 257 | for (int n = 0; n < draw_data->CmdListsCount; n++) 258 | { 259 | const ImDrawList* cmd_list = draw_data->CmdLists[n]; 260 | for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) 261 | { 262 | const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; 263 | if (pcmd->UserCallback != nullptr) 264 | { 265 | // User callback, registered via ImDrawList::AddCallback() 266 | // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) 267 | if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) 268 | ImGui_ImplDX11_SetupRenderState(draw_data, ctx); 269 | else 270 | pcmd->UserCallback(cmd_list, pcmd); 271 | } 272 | else 273 | { 274 | // Project scissor/clipping rectangles into framebuffer space 275 | ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y); 276 | ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y); 277 | if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) 278 | continue; 279 | 280 | // Apply scissor/clipping rectangle 281 | const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y }; 282 | ctx->RSSetScissorRects(1, &r); 283 | 284 | // Bind texture, Draw 285 | ID3D11ShaderResourceView* texture_srv = (ID3D11ShaderResourceView*)pcmd->GetTexID(); 286 | ctx->PSSetShaderResources(0, 1, &texture_srv); 287 | ctx->DrawIndexed(pcmd->ElemCount, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset); 288 | } 289 | } 290 | global_idx_offset += cmd_list->IdxBuffer.Size; 291 | global_vtx_offset += cmd_list->VtxBuffer.Size; 292 | } 293 | 294 | // Restore modified DX state 295 | ctx->RSSetScissorRects(old.ScissorRectsCount, old.ScissorRects); 296 | ctx->RSSetViewports(old.ViewportsCount, old.Viewports); 297 | ctx->RSSetState(old.RS); if (old.RS) old.RS->Release(); 298 | ctx->OMSetBlendState(old.BlendState, old.BlendFactor, old.SampleMask); if (old.BlendState) old.BlendState->Release(); 299 | ctx->OMSetDepthStencilState(old.DepthStencilState, old.StencilRef); if (old.DepthStencilState) old.DepthStencilState->Release(); 300 | ctx->PSSetShaderResources(0, 1, &old.PSShaderResource); if (old.PSShaderResource) old.PSShaderResource->Release(); 301 | ctx->PSSetSamplers(0, 1, &old.PSSampler); if (old.PSSampler) old.PSSampler->Release(); 302 | ctx->PSSetShader(old.PS, old.PSInstances, old.PSInstancesCount); if (old.PS) old.PS->Release(); 303 | for (UINT i = 0; i < old.PSInstancesCount; i++) if (old.PSInstances[i]) old.PSInstances[i]->Release(); 304 | ctx->VSSetShader(old.VS, old.VSInstances, old.VSInstancesCount); if (old.VS) old.VS->Release(); 305 | ctx->VSSetConstantBuffers(0, 1, &old.VSConstantBuffer); if (old.VSConstantBuffer) old.VSConstantBuffer->Release(); 306 | ctx->GSSetShader(old.GS, old.GSInstances, old.GSInstancesCount); if (old.GS) old.GS->Release(); 307 | for (UINT i = 0; i < old.VSInstancesCount; i++) if (old.VSInstances[i]) old.VSInstances[i]->Release(); 308 | ctx->IASetPrimitiveTopology(old.PrimitiveTopology); 309 | ctx->IASetIndexBuffer(old.IndexBuffer, old.IndexBufferFormat, old.IndexBufferOffset); if (old.IndexBuffer) old.IndexBuffer->Release(); 310 | ctx->IASetVertexBuffers(0, 1, &old.VertexBuffer, &old.VertexBufferStride, &old.VertexBufferOffset); if (old.VertexBuffer) old.VertexBuffer->Release(); 311 | ctx->IASetInputLayout(old.InputLayout); if (old.InputLayout) old.InputLayout->Release(); 312 | } 313 | 314 | static void ImGui_ImplDX11_CreateFontsTexture() 315 | { 316 | // Build texture atlas 317 | ImGuiIO& io = ImGui::GetIO(); 318 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 319 | unsigned char* pixels; 320 | int width, height; 321 | io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); 322 | 323 | // Upload texture to graphics system 324 | { 325 | D3D11_TEXTURE2D_DESC desc; 326 | ZeroMemory(&desc, sizeof(desc)); 327 | desc.Width = width; 328 | desc.Height = height; 329 | desc.MipLevels = 1; 330 | desc.ArraySize = 1; 331 | desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 332 | desc.SampleDesc.Count = 1; 333 | desc.Usage = D3D11_USAGE_DEFAULT; 334 | desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 335 | desc.CPUAccessFlags = 0; 336 | 337 | ID3D11Texture2D* pTexture = nullptr; 338 | D3D11_SUBRESOURCE_DATA subResource; 339 | subResource.pSysMem = pixels; 340 | subResource.SysMemPitch = desc.Width * 4; 341 | subResource.SysMemSlicePitch = 0; 342 | bd->pd3dDevice->CreateTexture2D(&desc, &subResource, &pTexture); 343 | IM_ASSERT(pTexture != nullptr); 344 | 345 | // Create texture view 346 | D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; 347 | ZeroMemory(&srvDesc, sizeof(srvDesc)); 348 | srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 349 | srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 350 | srvDesc.Texture2D.MipLevels = desc.MipLevels; 351 | srvDesc.Texture2D.MostDetailedMip = 0; 352 | bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, &bd->pFontTextureView); 353 | pTexture->Release(); 354 | } 355 | 356 | // Store our identifier 357 | io.Fonts->SetTexID((ImTextureID)bd->pFontTextureView); 358 | 359 | // Create texture sampler 360 | // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling) 361 | { 362 | D3D11_SAMPLER_DESC desc; 363 | ZeroMemory(&desc, sizeof(desc)); 364 | desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; 365 | desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; 366 | desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; 367 | desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; 368 | desc.MipLODBias = 0.f; 369 | desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; 370 | desc.MinLOD = 0.f; 371 | desc.MaxLOD = 0.f; 372 | bd->pd3dDevice->CreateSamplerState(&desc, &bd->pFontSampler); 373 | } 374 | } 375 | 376 | bool ImGui_ImplDX11_CreateDeviceObjects() 377 | { 378 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 379 | if (!bd->pd3dDevice) 380 | return false; 381 | if (bd->pFontSampler) 382 | ImGui_ImplDX11_InvalidateDeviceObjects(); 383 | 384 | // By using D3DCompile() from / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A) 385 | // If you would like to use this DX11 sample code but remove this dependency you can: 386 | // 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution] 387 | // 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL. 388 | // See https://github.com/ocornut/imgui/pull/638 for sources and details. 389 | 390 | // Create the vertex shader 391 | { 392 | static const char* vertexShader = 393 | "cbuffer vertexBuffer : register(b0) \ 394 | {\ 395 | float4x4 ProjectionMatrix; \ 396 | };\ 397 | struct VS_INPUT\ 398 | {\ 399 | float2 pos : POSITION;\ 400 | float4 col : COLOR0;\ 401 | float2 uv : TEXCOORD0;\ 402 | };\ 403 | \ 404 | struct PS_INPUT\ 405 | {\ 406 | float4 pos : SV_POSITION;\ 407 | float4 col : COLOR0;\ 408 | float2 uv : TEXCOORD0;\ 409 | };\ 410 | \ 411 | PS_INPUT main(VS_INPUT input)\ 412 | {\ 413 | PS_INPUT output;\ 414 | output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\ 415 | output.col = input.col;\ 416 | output.uv = input.uv;\ 417 | return output;\ 418 | }"; 419 | 420 | ID3DBlob* vertexShaderBlob; 421 | if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vertexShaderBlob, nullptr))) 422 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! 423 | if (bd->pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &bd->pVertexShader) != S_OK) 424 | { 425 | vertexShaderBlob->Release(); 426 | return false; 427 | } 428 | 429 | // Create the input layout 430 | D3D11_INPUT_ELEMENT_DESC local_layout[] = 431 | { 432 | { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 433 | { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 434 | { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, 435 | }; 436 | if (bd->pd3dDevice->CreateInputLayout(local_layout, 3, vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), &bd->pInputLayout) != S_OK) 437 | { 438 | vertexShaderBlob->Release(); 439 | return false; 440 | } 441 | vertexShaderBlob->Release(); 442 | 443 | // Create the constant buffer 444 | { 445 | D3D11_BUFFER_DESC desc; 446 | desc.ByteWidth = sizeof(VERTEX_CONSTANT_BUFFER_DX11); 447 | desc.Usage = D3D11_USAGE_DYNAMIC; 448 | desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 449 | desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 450 | desc.MiscFlags = 0; 451 | bd->pd3dDevice->CreateBuffer(&desc, nullptr, &bd->pVertexConstantBuffer); 452 | } 453 | } 454 | 455 | // Create the pixel shader 456 | { 457 | static const char* pixelShader = 458 | "struct PS_INPUT\ 459 | {\ 460 | float4 pos : SV_POSITION;\ 461 | float4 col : COLOR0;\ 462 | float2 uv : TEXCOORD0;\ 463 | };\ 464 | sampler sampler0;\ 465 | Texture2D texture0;\ 466 | \ 467 | float4 main(PS_INPUT input) : SV_Target\ 468 | {\ 469 | float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \ 470 | return out_col; \ 471 | }"; 472 | 473 | ID3DBlob* pixelShaderBlob; 474 | if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &pixelShaderBlob, nullptr))) 475 | return false; // NB: Pass ID3DBlob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob! 476 | if (bd->pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &bd->pPixelShader) != S_OK) 477 | { 478 | pixelShaderBlob->Release(); 479 | return false; 480 | } 481 | pixelShaderBlob->Release(); 482 | } 483 | 484 | // Create the blending setup 485 | { 486 | D3D11_BLEND_DESC desc; 487 | ZeroMemory(&desc, sizeof(desc)); 488 | desc.AlphaToCoverageEnable = false; 489 | desc.RenderTarget[0].BlendEnable = true; 490 | desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; 491 | desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 492 | desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 493 | desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; 494 | desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; 495 | desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 496 | desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 497 | bd->pd3dDevice->CreateBlendState(&desc, &bd->pBlendState); 498 | } 499 | 500 | // Create the rasterizer state 501 | { 502 | D3D11_RASTERIZER_DESC desc; 503 | ZeroMemory(&desc, sizeof(desc)); 504 | desc.FillMode = D3D11_FILL_SOLID; 505 | desc.CullMode = D3D11_CULL_NONE; 506 | desc.ScissorEnable = true; 507 | desc.DepthClipEnable = true; 508 | bd->pd3dDevice->CreateRasterizerState(&desc, &bd->pRasterizerState); 509 | } 510 | 511 | // Create depth-stencil State 512 | { 513 | D3D11_DEPTH_STENCIL_DESC desc; 514 | ZeroMemory(&desc, sizeof(desc)); 515 | desc.DepthEnable = false; 516 | desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; 517 | desc.DepthFunc = D3D11_COMPARISON_ALWAYS; 518 | desc.StencilEnable = false; 519 | desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 520 | desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 521 | desc.BackFace = desc.FrontFace; 522 | bd->pd3dDevice->CreateDepthStencilState(&desc, &bd->pDepthStencilState); 523 | } 524 | 525 | ImGui_ImplDX11_CreateFontsTexture(); 526 | 527 | return true; 528 | } 529 | 530 | void ImGui_ImplDX11_InvalidateDeviceObjects() 531 | { 532 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 533 | if (!bd->pd3dDevice) 534 | return; 535 | 536 | if (bd->pFontSampler) { bd->pFontSampler->Release(); bd->pFontSampler = nullptr; } 537 | if (bd->pFontTextureView) { bd->pFontTextureView->Release(); bd->pFontTextureView = nullptr; ImGui::GetIO().Fonts->SetTexID(0); } // We copied data->pFontTextureView to io.Fonts->TexID so let's clear that as well. 538 | if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } 539 | if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } 540 | if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } 541 | if (bd->pDepthStencilState) { bd->pDepthStencilState->Release(); bd->pDepthStencilState = nullptr; } 542 | if (bd->pRasterizerState) { bd->pRasterizerState->Release(); bd->pRasterizerState = nullptr; } 543 | if (bd->pPixelShader) { bd->pPixelShader->Release(); bd->pPixelShader = nullptr; } 544 | if (bd->pVertexConstantBuffer) { bd->pVertexConstantBuffer->Release(); bd->pVertexConstantBuffer = nullptr; } 545 | if (bd->pInputLayout) { bd->pInputLayout->Release(); bd->pInputLayout = nullptr; } 546 | if (bd->pVertexShader) { bd->pVertexShader->Release(); bd->pVertexShader = nullptr; } 547 | } 548 | 549 | bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context) 550 | { 551 | ImGuiIO& io = ImGui::GetIO(); 552 | IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); 553 | 554 | // Setup backend capabilities flags 555 | ImGui_ImplDX11_Data* bd = IM_NEW(ImGui_ImplDX11_Data)(); 556 | io.BackendRendererUserData = (void*)bd; 557 | io.BackendRendererName = "imgui_impl_dx11"; 558 | io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. 559 | io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) 560 | 561 | // Get factory from device 562 | IDXGIDevice* pDXGIDevice = nullptr; 563 | IDXGIAdapter* pDXGIAdapter = nullptr; 564 | IDXGIFactory* pFactory = nullptr; 565 | 566 | if (device->QueryInterface(IID_PPV_ARGS(&pDXGIDevice)) == S_OK) 567 | if (pDXGIDevice->GetParent(IID_PPV_ARGS(&pDXGIAdapter)) == S_OK) 568 | if (pDXGIAdapter->GetParent(IID_PPV_ARGS(&pFactory)) == S_OK) 569 | { 570 | bd->pd3dDevice = device; 571 | bd->pd3dDeviceContext = device_context; 572 | bd->pFactory = pFactory; 573 | } 574 | if (pDXGIDevice) pDXGIDevice->Release(); 575 | if (pDXGIAdapter) pDXGIAdapter->Release(); 576 | bd->pd3dDevice->AddRef(); 577 | bd->pd3dDeviceContext->AddRef(); 578 | 579 | if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) 580 | ImGui_ImplDX11_InitPlatformInterface(); 581 | 582 | return true; 583 | } 584 | 585 | void ImGui_ImplDX11_Shutdown() 586 | { 587 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 588 | IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); 589 | ImGuiIO& io = ImGui::GetIO(); 590 | 591 | ImGui_ImplDX11_ShutdownPlatformInterface(); 592 | ImGui_ImplDX11_InvalidateDeviceObjects(); 593 | if (bd->pFactory) { bd->pFactory->Release(); } 594 | if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } 595 | if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); } 596 | io.BackendRendererName = nullptr; 597 | io.BackendRendererUserData = nullptr; 598 | io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasViewports); 599 | IM_DELETE(bd); 600 | } 601 | 602 | void ImGui_ImplDX11_NewFrame() 603 | { 604 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 605 | IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplDX11_Init()?"); 606 | 607 | if (!bd->pFontSampler) 608 | ImGui_ImplDX11_CreateDeviceObjects(); 609 | } 610 | 611 | //-------------------------------------------------------------------------------------------------------- 612 | // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT 613 | // This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. 614 | // If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. 615 | //-------------------------------------------------------------------------------------------------------- 616 | 617 | // Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. 618 | struct ImGui_ImplDX11_ViewportData 619 | { 620 | IDXGISwapChain* SwapChain; 621 | ID3D11RenderTargetView* RTView; 622 | 623 | ImGui_ImplDX11_ViewportData() { SwapChain = nullptr; RTView = nullptr; } 624 | ~ImGui_ImplDX11_ViewportData() { IM_ASSERT(SwapChain == nullptr && RTView == nullptr); } 625 | }; 626 | 627 | static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport) 628 | { 629 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 630 | ImGui_ImplDX11_ViewportData* vd = IM_NEW(ImGui_ImplDX11_ViewportData)(); 631 | viewport->RendererUserData = vd; 632 | 633 | // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*). 634 | // Some backends will leave PlatformHandleRaw == 0, in which case we assume PlatformHandle will contain the HWND. 635 | HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle; 636 | IM_ASSERT(hwnd != 0); 637 | 638 | // Create swap chain 639 | DXGI_SWAP_CHAIN_DESC sd; 640 | ZeroMemory(&sd, sizeof(sd)); 641 | sd.BufferDesc.Width = (UINT)viewport->Size.x; 642 | sd.BufferDesc.Height = (UINT)viewport->Size.y; 643 | sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 644 | sd.SampleDesc.Count = 1; 645 | sd.SampleDesc.Quality = 0; 646 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 647 | sd.BufferCount = 1; 648 | sd.OutputWindow = hwnd; 649 | sd.Windowed = TRUE; 650 | sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 651 | sd.Flags = 0; 652 | 653 | IM_ASSERT(vd->SwapChain == nullptr && vd->RTView == nullptr); 654 | bd->pFactory->CreateSwapChain(bd->pd3dDevice, &sd, &vd->SwapChain); 655 | 656 | // Create the render target 657 | if (vd->SwapChain) 658 | { 659 | ID3D11Texture2D* pBackBuffer; 660 | vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); 661 | bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView); 662 | pBackBuffer->Release(); 663 | } 664 | } 665 | 666 | static void ImGui_ImplDX11_DestroyWindow(ImGuiViewport* viewport) 667 | { 668 | // The main viewport (owned by the application) will always have RendererUserData == nullptr since we didn't create the data for it. 669 | if (ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData) 670 | { 671 | if (vd->SwapChain) 672 | vd->SwapChain->Release(); 673 | vd->SwapChain = nullptr; 674 | if (vd->RTView) 675 | vd->RTView->Release(); 676 | vd->RTView = nullptr; 677 | IM_DELETE(vd); 678 | } 679 | viewport->RendererUserData = nullptr; 680 | } 681 | 682 | static void ImGui_ImplDX11_SetWindowSize(ImGuiViewport* viewport, ImVec2 size) 683 | { 684 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 685 | ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData; 686 | if (vd->RTView) 687 | { 688 | vd->RTView->Release(); 689 | vd->RTView = nullptr; 690 | } 691 | if (vd->SwapChain) 692 | { 693 | ID3D11Texture2D* pBackBuffer = nullptr; 694 | vd->SwapChain->ResizeBuffers(0, (UINT)size.x, (UINT)size.y, DXGI_FORMAT_UNKNOWN, 0); 695 | vd->SwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); 696 | if (pBackBuffer == nullptr) { fprintf(stderr, "ImGui_ImplDX11_SetWindowSize() failed creating buffers.\n"); return; } 697 | bd->pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &vd->RTView); 698 | pBackBuffer->Release(); 699 | } 700 | } 701 | 702 | static void ImGui_ImplDX11_RenderWindow(ImGuiViewport* viewport, void*) 703 | { 704 | ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); 705 | ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData; 706 | ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); 707 | bd->pd3dDeviceContext->OMSetRenderTargets(1, &vd->RTView, nullptr); 708 | if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) 709 | bd->pd3dDeviceContext->ClearRenderTargetView(vd->RTView, (float*)&clear_color); 710 | ImGui_ImplDX11_RenderDrawData(viewport->DrawData); 711 | } 712 | 713 | static void ImGui_ImplDX11_SwapBuffers(ImGuiViewport* viewport, void*) 714 | { 715 | ImGui_ImplDX11_ViewportData* vd = (ImGui_ImplDX11_ViewportData*)viewport->RendererUserData; 716 | vd->SwapChain->Present(0, 0); // Present without vsync 717 | } 718 | 719 | static void ImGui_ImplDX11_InitPlatformInterface() 720 | { 721 | ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); 722 | platform_io.Renderer_CreateWindow = ImGui_ImplDX11_CreateWindow; 723 | platform_io.Renderer_DestroyWindow = ImGui_ImplDX11_DestroyWindow; 724 | platform_io.Renderer_SetWindowSize = ImGui_ImplDX11_SetWindowSize; 725 | platform_io.Renderer_RenderWindow = ImGui_ImplDX11_RenderWindow; 726 | platform_io.Renderer_SwapBuffers = ImGui_ImplDX11_SwapBuffers; 727 | } 728 | 729 | static void ImGui_ImplDX11_ShutdownPlatformInterface() 730 | { 731 | ImGui::DestroyPlatformWindows(); 732 | } 733 | 734 | //----------------------------------------------------------------------------- 735 | 736 | #endif // #ifndef IMGUI_DISABLE 737 | -------------------------------------------------------------------------------- /demo/imgui/imgui_impl_dx11.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer Backend for DirectX11 2 | // This needs to be used along with a Platform Backend (e.g. Win32) 3 | 4 | // Implemented features: 5 | // [X] Renderer: User texture binding. Use 'ID3D11ShaderResourceView*' as ImTextureID. Read the FAQ about ImTextureID! 6 | // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. 7 | // [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. 8 | 9 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 10 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 11 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 12 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 13 | 14 | #pragma once 15 | #include "imgui.h" // IMGUI_IMPL_API 16 | #ifndef IMGUI_DISABLE 17 | 18 | struct ID3D11Device; 19 | struct ID3D11DeviceContext; 20 | 21 | IMGUI_IMPL_API bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_context); 22 | IMGUI_IMPL_API void ImGui_ImplDX11_Shutdown(); 23 | IMGUI_IMPL_API void ImGui_ImplDX11_NewFrame(); 24 | IMGUI_IMPL_API void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data); 25 | 26 | // Use if you want to reset your rendering device without losing Dear ImGui state. 27 | IMGUI_IMPL_API void ImGui_ImplDX11_InvalidateDeviceObjects(); 28 | IMGUI_IMPL_API bool ImGui_ImplDX11_CreateDeviceObjects(); 29 | 30 | #endif // #ifndef IMGUI_DISABLE 31 | -------------------------------------------------------------------------------- /demo/imgui/imgui_impl_win32.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Backend for Windows (standard windows API for 32-bits AND 64-bits applications) 2 | // This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..) 3 | 4 | // Implemented features: 5 | // [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui) 6 | // [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen/Pen. 7 | // [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 VK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] 8 | // [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. 10 | // [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'. 11 | 12 | // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. 13 | // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. 14 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 15 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 16 | 17 | #pragma once 18 | #include "imgui.h" // IMGUI_IMPL_API 19 | #ifndef IMGUI_DISABLE 20 | 21 | IMGUI_IMPL_API bool ImGui_ImplWin32_Init(void* hwnd); 22 | IMGUI_IMPL_API bool ImGui_ImplWin32_InitForOpenGL(void* hwnd); 23 | IMGUI_IMPL_API void ImGui_ImplWin32_Shutdown(); 24 | IMGUI_IMPL_API void ImGui_ImplWin32_NewFrame(); 25 | 26 | // Win32 message handler your application need to call. 27 | // - Intentionally commented out in a '#if 0' block to avoid dragging dependencies on from this helper. 28 | // - You should COPY the line below into your .cpp code to forward declare the function and then you can call it. 29 | // - Call from your application's message handler. Keep calling your message handler unless this function returns TRUE. 30 | 31 | #if 0 32 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 33 | #endif 34 | 35 | // DPI-related helpers (optional) 36 | // - Use to enable DPI awareness without having to create an application manifest. 37 | // - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps. 38 | // - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc. 39 | // but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime, 40 | // neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies. 41 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableDpiAwareness(); 42 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd); // HWND hwnd 43 | IMGUI_IMPL_API float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor); // HMONITOR monitor 44 | 45 | // Transparency related helpers (optional) [experimental] 46 | // - Use to enable alpha compositing transparency with the desktop. 47 | // - Use together with e.g. clearing your framebuffer with zero-alpha. 48 | IMGUI_IMPL_API void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd); // HWND hwnd 49 | 50 | #endif // #ifndef IMGUI_DISABLE 51 | -------------------------------------------------------------------------------- /demo/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 | -------------------------------------------------------------------------------- /demo/main.cpp: -------------------------------------------------------------------------------- 1 | // see demo.cpp for OpenFBX related stuff 2 | 3 | 4 | 5 | // Dear ImGui: standalone example application for DirectX 11 6 | // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. 7 | // Read online: https://github.com/ocornut/imgui/tree/master/docs 8 | 9 | #include "../src/ofbx.h" 10 | #include "imgui.h" 11 | #include "imgui_impl_win32.h" 12 | #include "imgui_impl_dx11.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // Data 20 | static ID3D11Device* g_pd3dDevice = nullptr; 21 | static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; 22 | static IDXGISwapChain* g_pSwapChain = nullptr; 23 | static UINT g_ResizeWidth = 0, g_ResizeHeight = 0; 24 | static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr; 25 | 26 | // Forward declarations of helper functions 27 | bool CreateDeviceD3D(HWND hWnd); 28 | void CleanupDeviceD3D(); 29 | void CreateRenderTarget(); 30 | void CleanupRenderTarget(); 31 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 32 | 33 | bool initOpenFBX(const char* filepath, HWND hwnd); 34 | void demoGUI(); 35 | 36 | // Main code 37 | int main(int, char**) 38 | { 39 | // Create application window 40 | //ImGui_ImplWin32_EnableDpiAwareness(); 41 | WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; 42 | ::RegisterClassExW(&wc); 43 | HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); 44 | 45 | // Initialize Direct3D 46 | if (!CreateDeviceD3D(hwnd)) 47 | { 48 | CleanupDeviceD3D(); 49 | ::UnregisterClassW(wc.lpszClassName, wc.hInstance); 50 | return 1; 51 | } 52 | 53 | // Show the window 54 | ::ShowWindow(hwnd, SW_SHOWDEFAULT); 55 | ::UpdateWindow(hwnd); 56 | 57 | // Setup Dear ImGui context 58 | IMGUI_CHECKVERSION(); 59 | ImGui::CreateContext(); 60 | ImGuiIO& io = ImGui::GetIO(); (void)io; 61 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 62 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 63 | io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking 64 | io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows 65 | //io.ConfigViewportsNoAutoMerge = true; 66 | //io.ConfigViewportsNoTaskBarIcon = true; 67 | //io.ConfigViewportsNoDefaultParent = true; 68 | //io.ConfigDockingAlwaysTabBar = true; 69 | //io.ConfigDockingTransparentPayload = true; 70 | //io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME-DPI: Experimental. THIS CURRENTLY DOESN'T WORK AS EXPECTED. DON'T USE IN USER APP! 71 | //io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; // FIXME-DPI: Experimental. 72 | 73 | // Setup Dear ImGui style 74 | ImGui::StyleColorsDark(); 75 | //ImGui::StyleColorsLight(); 76 | 77 | // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. 78 | ImGuiStyle& style = ImGui::GetStyle(); 79 | if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) 80 | { 81 | style.WindowRounding = 0.0f; 82 | style.Colors[ImGuiCol_WindowBg].w = 1.0f; 83 | } 84 | 85 | // Setup Platform/Renderer backends 86 | ImGui_ImplWin32_Init(hwnd); 87 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); 88 | 89 | initOpenFBX("a.fbx", hwnd); 90 | 91 | // Load Fonts 92 | // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. 93 | // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. 94 | // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). 95 | // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. 96 | // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. 97 | // - Read 'docs/FONTS.md' for more instructions and details. 98 | // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! 99 | //io.Fonts->AddFontDefault(); 100 | //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf", 18.0f); 101 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf", 16.0f); 102 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); 103 | //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f); 104 | //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf", 18.0f, nullptr, io.Fonts->GetGlyphRangesJapanese()); 105 | //IM_ASSERT(font != nullptr); 106 | 107 | // Our state 108 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 109 | 110 | // Main loop 111 | bool done = false; 112 | while (!done) 113 | { 114 | // Poll and handle messages (inputs, window resize, etc.) 115 | // See the WndProc() function below for our to dispatch events to the Win32 backend. 116 | MSG msg; 117 | while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) 118 | { 119 | ::TranslateMessage(&msg); 120 | ::DispatchMessage(&msg); 121 | if (msg.message == WM_QUIT) 122 | done = true; 123 | } 124 | if (done) 125 | break; 126 | 127 | // Handle window resize (we don't resize directly in the WM_SIZE handler) 128 | if (g_ResizeWidth != 0 && g_ResizeHeight != 0) 129 | { 130 | CleanupRenderTarget(); 131 | g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0); 132 | g_ResizeWidth = g_ResizeHeight = 0; 133 | CreateRenderTarget(); 134 | } 135 | 136 | // Start the Dear ImGui frame 137 | ImGui_ImplDX11_NewFrame(); 138 | ImGui_ImplWin32_NewFrame(); 139 | ImGui::NewFrame(); 140 | 141 | demoGUI(); 142 | 143 | // Rendering 144 | ImGui::Render(); 145 | const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; 146 | g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr); 147 | g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); 148 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 149 | 150 | // Update and Render additional Platform Windows 151 | if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) 152 | { 153 | ImGui::UpdatePlatformWindows(); 154 | ImGui::RenderPlatformWindowsDefault(); 155 | } 156 | 157 | g_pSwapChain->Present(1, 0); // Present with vsync 158 | //g_pSwapChain->Present(0, 0); // Present without vsync 159 | } 160 | 161 | // Cleanup 162 | ImGui_ImplDX11_Shutdown(); 163 | ImGui_ImplWin32_Shutdown(); 164 | ImGui::DestroyContext(); 165 | 166 | CleanupDeviceD3D(); 167 | ::DestroyWindow(hwnd); 168 | ::UnregisterClassW(wc.lpszClassName, wc.hInstance); 169 | 170 | return 0; 171 | } 172 | 173 | // Helper functions 174 | bool CreateDeviceD3D(HWND hWnd) 175 | { 176 | // Setup swap chain 177 | DXGI_SWAP_CHAIN_DESC sd; 178 | ZeroMemory(&sd, sizeof(sd)); 179 | sd.BufferCount = 2; 180 | sd.BufferDesc.Width = 0; 181 | sd.BufferDesc.Height = 0; 182 | sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 183 | sd.BufferDesc.RefreshRate.Numerator = 60; 184 | sd.BufferDesc.RefreshRate.Denominator = 1; 185 | sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 186 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 187 | sd.OutputWindow = hWnd; 188 | sd.SampleDesc.Count = 1; 189 | sd.SampleDesc.Quality = 0; 190 | sd.Windowed = TRUE; 191 | sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 192 | 193 | UINT createDeviceFlags = 0; 194 | //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 195 | D3D_FEATURE_LEVEL featureLevel; 196 | const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; 197 | HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); 198 | if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available. 199 | res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); 200 | if (res != S_OK) 201 | return false; 202 | 203 | CreateRenderTarget(); 204 | return true; 205 | } 206 | 207 | void CleanupDeviceD3D() 208 | { 209 | CleanupRenderTarget(); 210 | if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; } 211 | if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; } 212 | if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; } 213 | } 214 | 215 | void CreateRenderTarget() 216 | { 217 | ID3D11Texture2D* pBackBuffer; 218 | g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); 219 | g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView); 220 | pBackBuffer->Release(); 221 | } 222 | 223 | void CleanupRenderTarget() 224 | { 225 | if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; } 226 | } 227 | 228 | #ifndef WM_DPICHANGED 229 | #define WM_DPICHANGED 0x02E0 // From Windows SDK 8.1+ headers 230 | #endif 231 | 232 | // Forward declare message handler from imgui_impl_win32.cpp 233 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 234 | 235 | // Win32 message handler 236 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 237 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. 238 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. 239 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 240 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 241 | { 242 | if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) 243 | return true; 244 | 245 | switch (msg) 246 | { 247 | case WM_SIZE: 248 | if (wParam == SIZE_MINIMIZED) 249 | return 0; 250 | g_ResizeWidth = (UINT)LOWORD(lParam); // Queue resize 251 | g_ResizeHeight = (UINT)HIWORD(lParam); 252 | return 0; 253 | case WM_SYSCOMMAND: 254 | if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu 255 | return 0; 256 | break; 257 | case WM_DESTROY: 258 | ::PostQuitMessage(0); 259 | return 0; 260 | case WM_DPICHANGED: 261 | if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_DpiEnableScaleViewports) 262 | { 263 | //const int dpi = HIWORD(wParam); 264 | //printf("WM_DPICHANGED to %d (%.0f%%)\n", dpi, (float)dpi / 96.0f * 100.0f); 265 | const RECT* suggested_rect = (RECT*)lParam; 266 | ::SetWindowPos(hWnd, nullptr, suggested_rect->left, suggested_rect->top, suggested_rect->right - suggested_rect->left, suggested_rect->bottom - suggested_rect->top, SWP_NOZORDER | SWP_NOACTIVATE); 267 | } 268 | break; 269 | } 270 | return ::DefWindowProcW(hWnd, msg, wParam, lParam); 271 | } 272 | -------------------------------------------------------------------------------- /openfbxConfig.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(CMakeFindDependencyMacro) 4 | find_dependency(libdeflate) 5 | 6 | include("${CMAKE_CURRENT_LIST_DIR}/openfbxTargets.cmake") 7 | 8 | check_required_components(libdeflate) -------------------------------------------------------------------------------- /projects/genie: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nem0/OpenFBX/82a43d9191f2250145fddc219b4083667c33f2a5/projects/genie -------------------------------------------------------------------------------- /projects/genie.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nem0/OpenFBX/82a43d9191f2250145fddc219b4083667c33f2a5/projects/genie.exe -------------------------------------------------------------------------------- /projects/genie.lua: -------------------------------------------------------------------------------- 1 | local ide_dir = iif(_ACTION == nil, "vs2015", _ACTION) 2 | if "linux-gcc" == _OPTIONS["gcc"] then 3 | ide_dir = "gcc" 4 | elseif "linux-gcc-5" == _OPTIONS["gcc"] then 5 | ide_dir = "gcc5" 6 | elseif "linux-clang" == _OPTIONS["gcc"] then 7 | ide_dir = "clang" 8 | end 9 | 10 | local LOCATION = "tmp/" .. ide_dir 11 | local BINARY_DIR = LOCATION .. "/bin/" 12 | local build_physics = true 13 | local build_unit_tests = true 14 | local build_app = true 15 | local build_studio = true 16 | local build_gui = _ACTION == "vs2015" 17 | local build_steam = false 18 | local build_game = false 19 | newoption { 20 | trigger = "gcc", 21 | value = "GCC", 22 | description = "Choose GCC flavor", 23 | allowed = { 24 | { "asmjs", "Emscripten/asm.js" }, 25 | { "android-x86", "Android - x86" }, 26 | { "linux-gcc", "Linux (GCC compiler)" }, 27 | { "linux-gcc-5", "Linux (GCC-5 compiler)" }, 28 | { "linux-clang", "Linux (Clang compiler)" } 29 | } 30 | } 31 | 32 | 33 | 34 | function strip() 35 | configuration { "asmjs" } 36 | postbuildcommands { 37 | "$(SILENT) echo Running asmjs finalize.", 38 | "$(SILENT) \"$(EMSCRIPTEN)/emcc\" -O2 " 39 | -- .. "-s EMTERPRETIFY=1 " 40 | -- .. "-s EMTERPRETIFY_ASYNC=1 " 41 | .. "-s TOTAL_MEMORY=268435456 " 42 | -- .. "-s ALLOW_MEMORY_GROWTH=1 " 43 | -- .. "-s USE_WEBGL2=1 " 44 | .. "--memory-init-file 1 " 45 | .. "\"$(TARGET)\" -o \"$(TARGET)\".html " 46 | -- .. "--preload-file ../../../examples/runtime@/" 47 | } 48 | 49 | configuration { "android-x86", "Release" } 50 | postbuildcommands { 51 | "$(SILENT) echo Stripping symbols.", 52 | "$(SILENT) $(ANDROID_NDK_X86)/bin/i686-linux-android-strip -s \"$(TARGET)\"" 53 | } 54 | 55 | configuration {} 56 | end 57 | 58 | 59 | function defaultConfigurations() 60 | configuration "Debug" 61 | targetdir(BINARY_DIR .. "Debug") 62 | defines { "DEBUG", "_DEBUG" } 63 | flags { "Symbols" } 64 | 65 | configuration "Release" 66 | targetdir(BINARY_DIR .. "Release") 67 | defines { "NDEBUG" } 68 | flags { "Optimize" } 69 | 70 | configuration "RelWithDebInfo" 71 | targetdir(BINARY_DIR .. "RelWithDebInfo") 72 | defines { "NDEBUG" } 73 | flags { "Symbols", "Optimize" } 74 | 75 | configuration "linux" 76 | buildoptions { "-std=c++14" } 77 | links { "pthread" } 78 | 79 | configuration { "asmjs" } 80 | buildoptions { "-std=c++14" } 81 | 82 | end 83 | 84 | function linkLib(lib) 85 | links {lib} 86 | 87 | for conf,conf_dir in pairs({Debug="debug", Release="release", RelWithDebInfo="release"}) do 88 | for platform,target_platform in pairs({win="windows", linux="linux", }) do 89 | configuration { "x64", conf, target_platform } 90 | libdirs {"../external/" .. lib .. "/lib/" .. platform .. "64" .. "_" .. ide_dir .. "/" .. conf_dir} 91 | libdirs {"../external/" .. lib .. "/dll/" .. platform .. "64" .. "_" .. ide_dir .. "/" .. conf_dir} 92 | end 93 | end 94 | for conf,conf_dir in pairs({Debug="debug", Release="release", RelWithDebInfo="release"}) do 95 | configuration { "android-x86", conf } 96 | libdirs {"../external/" .. lib .. "/lib/android-x86_gmake/" .. conf_dir} 97 | end 98 | configuration {} 99 | end 100 | 101 | 102 | function forceLink(name) 103 | 104 | configuration { "linux-*" } 105 | linkoptions {"-u " .. name} 106 | configuration { "x64", "vs*" } 107 | linkoptions {"/INCLUDE:" .. name} 108 | configuration {} 109 | end 110 | 111 | solution "OpenFBX" 112 | if _ACTION == "gmake" then 113 | configuration { "android-*" } 114 | flags { 115 | "NoImportLib", 116 | } 117 | includedirs { 118 | "$(ANDROID_NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/4.9/include", 119 | "$(ANDROID_NDK_ROOT)/sources/android/native_app_glue", 120 | } 121 | linkoptions { 122 | "-nostdlib", 123 | "-static-libgcc", 124 | } 125 | links { 126 | "c", 127 | "dl", 128 | "m", 129 | "android", 130 | "log", 131 | "gnustl_static", 132 | "gcc", 133 | } 134 | buildoptions { 135 | "-fPIC", 136 | "-no-canonical-prefixes", 137 | "-Wa,--noexecstack", 138 | "-fstack-protector", 139 | "-ffunction-sections", 140 | "-Wno-psabi", 141 | "-Wunused-value", 142 | "-Wundef", 143 | } 144 | buildoptions_cpp { 145 | "-std=c++14", 146 | } 147 | linkoptions { 148 | "-no-canonical-prefixes", 149 | "-Wl,--no-undefined", 150 | "-Wl,-z,noexecstack", 151 | "-Wl,-z,relro", 152 | "-Wl,-z,now", 153 | } 154 | 155 | configuration { "android-x86" } 156 | androidPlatform = "android-24" 157 | libdirs { 158 | path.join(_libDir, "lib/android-x86"), 159 | "$(ANDROID_NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86", 160 | } 161 | includedirs { 162 | "$(ANDROID_NDK_ROOT)/sources/cxx-stl/gnu-libstdc++/4.9/libs/x86/include", 163 | } 164 | buildoptions { 165 | "--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86"), 166 | "-march=i686", 167 | "-mtune=atom", 168 | "-mstackrealign", 169 | "-msse3", 170 | "-mfpmath=sse", 171 | "-Wunused-value", 172 | "-Wundef", 173 | } 174 | linkoptions { 175 | "--sysroot=" .. path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86"), 176 | path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86/usr/lib/crtbegin_so.o"), 177 | path.join("$(ANDROID_NDK_ROOT)/platforms", androidPlatform, "arch-x86/usr/lib/crtend_so.o"), 178 | } 179 | 180 | configuration {} 181 | 182 | if "asmjs" == _OPTIONS["gcc"] then 183 | if not os.getenv("EMSCRIPTEN") then 184 | print("Set EMSCRIPTEN enviroment variable.") 185 | end 186 | premake.gcc.cc = "\"$(EMSCRIPTEN)/emcc\"" 187 | premake.gcc.cxx = "\"$(EMSCRIPTEN)/em++\"" 188 | premake.gcc.ar = "\"$(EMSCRIPTEN)/emar\"" 189 | _G["premake"].gcc.llvm = true 190 | premake.gcc.llvm = true 191 | LOCATION = "tmp/emscripten_gmake" 192 | 193 | elseif "android-x86" == _OPTIONS["gcc"] then 194 | if not os.getenv("ANDROID_NDK_X86") or not os.getenv("ANDROID_NDK_ROOT") then 195 | print("Set ANDROID_NDK_X86 and ANDROID_NDK_ROOT envrionment variables.") 196 | end 197 | 198 | premake.gcc.cc = "\"$(ANDROID_NDK_X86)/bin/i686-linux-android-gcc\"" 199 | premake.gcc.cxx = "\"$(ANDROID_NDK_X86)/bin/i686-linux-android-g++\"" 200 | premake.gcc.ar = "\"$(ANDROID_NDK_X86)/bin/i686-linux-android-ar\"" 201 | LOCATION = "tmp/android-x86_gmake" 202 | 203 | elseif "linux-gcc" == _OPTIONS["gcc"] then 204 | LOCATION = "tmp/gcc" 205 | 206 | elseif "linux-gcc-5" == _OPTIONS["gcc"] then 207 | premake.gcc.cc = "gcc-5" 208 | premake.gcc.cxx = "g++-5" 209 | premake.gcc.ar = "ar" 210 | LOCATION = "tmp/gcc5" 211 | 212 | elseif "linux-clang" == _OPTIONS["gcc"] then 213 | premake.gcc.cc = "clang" 214 | premake.gcc.cxx = "clang++" 215 | premake.gcc.ar = "ar" 216 | LOCATION = "tmp/clang" 217 | 218 | end 219 | BINARY_DIR = LOCATION .. "/bin/" 220 | end 221 | 222 | configuration { "linux-*" } 223 | buildoptions { 224 | "-fPIC", 225 | "-no-canonical-prefixes", 226 | "-Wa,--noexecstack", 227 | "-fstack-protector", 228 | "-ffunction-sections", 229 | "-Wno-psabi", 230 | "-Wunused-value", 231 | "-Wundef", 232 | "-msse2", 233 | } 234 | linkoptions { 235 | "-Wl,--gc-sections", 236 | } 237 | 238 | configuration { "linux-*", "x32" } 239 | buildoptions { 240 | "-m32", 241 | } 242 | 243 | configuration { "linux-*", "x64" } 244 | buildoptions { 245 | "-m64", 246 | } 247 | 248 | configuration {} 249 | 250 | configurations { "Debug", "Release", "RelWithDebInfo" } 251 | platforms { "x64" } 252 | flags { 253 | --"FatalWarnings", 254 | "StaticRuntime", 255 | "NoPCH", 256 | "NoExceptions", 257 | "NoRTTI", 258 | "NoEditAndContinue" 259 | } 260 | includedirs {"../src" } 261 | location(LOCATION) 262 | language "C++" 263 | startproject "studio" 264 | 265 | configuration { "vs*" } 266 | defines { "_HAS_EXCEPTIONS=0" } 267 | 268 | configuration "not macosx" 269 | removefiles { "../src/**/osx/*"} 270 | 271 | configuration "not linux" 272 | removefiles { "../src/**/linux/*"} 273 | 274 | configuration "not windows" 275 | removefiles { "../src/**/win/*"} 276 | 277 | configuration "asmjs" 278 | removefiles { "../src/**/win/*"} 279 | 280 | configuration "android-*" 281 | removefiles { "../src/**/win/*"} 282 | 283 | configuration "not asmjs" 284 | removefiles { "../src/**/asmjs/*"} 285 | 286 | 287 | project "openfbx" 288 | kind "WindowedApp" 289 | 290 | debugdir ("../runtime") 291 | 292 | includedirs { "../demo/imgui" } 293 | files { "../src/**.c", "../src/**.cpp", "../demo/**.cpp", "../demo/**.h", "../src/**.h", "genie.lua" } 294 | defaultConfigurations() 295 | 296 | configuration {} 297 | defines {"_CRT_SECURE_NO_WARNINGS", "_HAS_ITERATOR_DEBUGGING=0" } 298 | 299 | configuration "Release" 300 | flags { "NoExceptions", "NoFramePointer", "NoIncrementalLink", "NoRTTI", "OptimizeSize", "No64BitChecks" } 301 | -- linkoptions { "/NODEFAULTLIB"} 302 | linkoptions { "/MANIFEST:NO"} 303 | -------------------------------------------------------------------------------- /projects/genie_vs19.bat: -------------------------------------------------------------------------------- 1 | genie.exe vs2019 -------------------------------------------------------------------------------- /runtime/a.FBX: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nem0/OpenFBX/82a43d9191f2250145fddc219b4083667c33f2a5/runtime/a.FBX -------------------------------------------------------------------------------- /runtime/b.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nem0/OpenFBX/82a43d9191f2250145fddc219b4083667c33f2a5/runtime/b.fbx -------------------------------------------------------------------------------- /runtime/c.FBX: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nem0/OpenFBX/82a43d9191f2250145fddc219b4083667c33f2a5/runtime/c.FBX -------------------------------------------------------------------------------- /runtime/d.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nem0/OpenFBX/82a43d9191f2250145fddc219b4083667c33f2a5/runtime/d.fbx -------------------------------------------------------------------------------- /runtime/license.txt: -------------------------------------------------------------------------------- 1 | All rights reservered 2 | Only for personal use 3 | Do not distribute files in this directory -------------------------------------------------------------------------------- /src/libdeflate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libdeflate.h - public header for libdeflate 3 | */ 4 | 5 | #ifndef LIBDEFLATE_H 6 | #define LIBDEFLATE_H 7 | 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #define LIBDEFLATE_VERSION_MAJOR 1 16 | #define LIBDEFLATE_VERSION_MINOR 18 17 | #define LIBDEFLATE_VERSION_STRING "1.18" 18 | 19 | /* 20 | * Users of libdeflate.dll on Windows can define LIBDEFLATE_DLL to cause 21 | * __declspec(dllimport) to be used. This should be done when it's easy to do. 22 | * Otherwise it's fine to skip it, since it is a very minor performance 23 | * optimization that is irrelevant for most use cases of libdeflate. 24 | */ 25 | #ifndef LIBDEFLATEAPI 26 | # if defined(LIBDEFLATE_DLL) && (defined(_WIN32) || defined(__CYGWIN__)) 27 | # define LIBDEFLATEAPI __declspec(dllimport) 28 | # else 29 | # define LIBDEFLATEAPI 30 | # endif 31 | #endif 32 | 33 | /* ========================================================================== */ 34 | /* Compression */ 35 | /* ========================================================================== */ 36 | 37 | struct libdeflate_compressor; 38 | struct libdeflate_options; 39 | 40 | /* 41 | * libdeflate_alloc_compressor() allocates a new compressor that supports 42 | * DEFLATE, zlib, and gzip compression. 'compression_level' is the compression 43 | * level on a zlib-like scale but with a higher maximum value (1 = fastest, 6 = 44 | * medium/default, 9 = slow, 12 = slowest). Level 0 is also supported and means 45 | * "no compression", specifically "create a valid stream, but only emit 46 | * uncompressed blocks" (this will expand the data slightly). 47 | * 48 | * The return value is a pointer to the new compressor, or NULL if out of memory 49 | * or if the compression level is invalid (i.e. outside the range [0, 12]). 50 | * 51 | * Note: for compression, the sliding window size is defined at compilation time 52 | * to 32768, the largest size permissible in the DEFLATE format. It cannot be 53 | * changed at runtime. 54 | * 55 | * A single compressor is not safe to use by multiple threads concurrently. 56 | * However, different threads may use different compressors concurrently. 57 | */ 58 | LIBDEFLATEAPI struct libdeflate_compressor * 59 | libdeflate_alloc_compressor(int compression_level); 60 | 61 | /* 62 | * Like libdeflate_alloc_compressor(), but adds the 'options' argument. 63 | */ 64 | LIBDEFLATEAPI struct libdeflate_compressor * 65 | libdeflate_alloc_compressor_ex(int compression_level, 66 | const struct libdeflate_options *options); 67 | 68 | /* 69 | * libdeflate_deflate_compress() performs raw DEFLATE compression on a buffer of 70 | * data. It attempts to compress 'in_nbytes' bytes of data located at 'in' and 71 | * write the result to 'out', which has space for 'out_nbytes_avail' bytes. The 72 | * return value is the compressed size in bytes, or 0 if the data could not be 73 | * compressed to 'out_nbytes_avail' bytes or fewer (but see note below). 74 | * 75 | * If compression is successful, then the output data is guaranteed to be a 76 | * valid DEFLATE stream that decompresses to the input data. No other 77 | * guarantees are made about the output data. Notably, different versions of 78 | * libdeflate can produce different compressed data for the same uncompressed 79 | * data, even at the same compression level. Do ***NOT*** do things like 80 | * writing tests that compare compressed data to a golden output, as this can 81 | * break when libdeflate is updated. (This property isn't specific to 82 | * libdeflate; the same is true for zlib and other compression libraries too.) 83 | */ 84 | LIBDEFLATEAPI size_t 85 | libdeflate_deflate_compress(struct libdeflate_compressor *compressor, 86 | const void *in, size_t in_nbytes, 87 | void *out, size_t out_nbytes_avail); 88 | 89 | /* 90 | * libdeflate_deflate_compress_bound() returns a worst-case upper bound on the 91 | * number of bytes of compressed data that may be produced by compressing any 92 | * buffer of length less than or equal to 'in_nbytes' using 93 | * libdeflate_deflate_compress() with the specified compressor. This bound will 94 | * necessarily be a number greater than or equal to 'in_nbytes'. It may be an 95 | * overestimate of the true upper bound. The return value is guaranteed to be 96 | * the same for all invocations with the same compressor and same 'in_nbytes'. 97 | * 98 | * As a special case, 'compressor' may be NULL. This causes the bound to be 99 | * taken across *any* libdeflate_compressor that could ever be allocated with 100 | * this build of the library, with any options. 101 | * 102 | * Note that this function is not necessary in many applications. With 103 | * block-based compression, it is usually preferable to separately store the 104 | * uncompressed size of each block and to store any blocks that did not compress 105 | * to less than their original size uncompressed. In that scenario, there is no 106 | * need to know the worst-case compressed size, since the maximum number of 107 | * bytes of compressed data that may be used would always be one less than the 108 | * input length. You can just pass a buffer of that size to 109 | * libdeflate_deflate_compress() and store the data uncompressed if 110 | * libdeflate_deflate_compress() returns 0, indicating that the compressed data 111 | * did not fit into the provided output buffer. 112 | */ 113 | LIBDEFLATEAPI size_t 114 | libdeflate_deflate_compress_bound(struct libdeflate_compressor *compressor, 115 | size_t in_nbytes); 116 | 117 | /* 118 | * Like libdeflate_deflate_compress(), but uses the zlib wrapper format instead 119 | * of raw DEFLATE. 120 | */ 121 | LIBDEFLATEAPI size_t 122 | libdeflate_zlib_compress(struct libdeflate_compressor *compressor, 123 | const void *in, size_t in_nbytes, 124 | void *out, size_t out_nbytes_avail); 125 | 126 | /* 127 | * Like libdeflate_deflate_compress_bound(), but assumes the data will be 128 | * compressed with libdeflate_zlib_compress() rather than with 129 | * libdeflate_deflate_compress(). 130 | */ 131 | LIBDEFLATEAPI size_t 132 | libdeflate_zlib_compress_bound(struct libdeflate_compressor *compressor, 133 | size_t in_nbytes); 134 | 135 | /* 136 | * Like libdeflate_deflate_compress(), but uses the gzip wrapper format instead 137 | * of raw DEFLATE. 138 | */ 139 | LIBDEFLATEAPI size_t 140 | libdeflate_gzip_compress(struct libdeflate_compressor *compressor, 141 | const void *in, size_t in_nbytes, 142 | void *out, size_t out_nbytes_avail); 143 | 144 | /* 145 | * Like libdeflate_deflate_compress_bound(), but assumes the data will be 146 | * compressed with libdeflate_gzip_compress() rather than with 147 | * libdeflate_deflate_compress(). 148 | */ 149 | LIBDEFLATEAPI size_t 150 | libdeflate_gzip_compress_bound(struct libdeflate_compressor *compressor, 151 | size_t in_nbytes); 152 | 153 | /* 154 | * libdeflate_free_compressor() frees a compressor that was allocated with 155 | * libdeflate_alloc_compressor(). If a NULL pointer is passed in, no action is 156 | * taken. 157 | */ 158 | LIBDEFLATEAPI void 159 | libdeflate_free_compressor(struct libdeflate_compressor *compressor); 160 | 161 | /* ========================================================================== */ 162 | /* Decompression */ 163 | /* ========================================================================== */ 164 | 165 | struct libdeflate_decompressor; 166 | struct libdeflate_options; 167 | 168 | /* 169 | * libdeflate_alloc_decompressor() allocates a new decompressor that can be used 170 | * for DEFLATE, zlib, and gzip decompression. The return value is a pointer to 171 | * the new decompressor, or NULL if out of memory. 172 | * 173 | * This function takes no parameters, and the returned decompressor is valid for 174 | * decompressing data that was compressed at any compression level and with any 175 | * sliding window size. 176 | * 177 | * A single decompressor is not safe to use by multiple threads concurrently. 178 | * However, different threads may use different decompressors concurrently. 179 | */ 180 | LIBDEFLATEAPI struct libdeflate_decompressor * 181 | libdeflate_alloc_decompressor(void); 182 | 183 | /* 184 | * Like libdeflate_alloc_decompressor(), but adds the 'options' argument. 185 | */ 186 | LIBDEFLATEAPI struct libdeflate_decompressor * 187 | libdeflate_alloc_decompressor_ex(const struct libdeflate_options *options); 188 | 189 | /* 190 | * Result of a call to libdeflate_deflate_decompress(), 191 | * libdeflate_zlib_decompress(), or libdeflate_gzip_decompress(). 192 | */ 193 | enum libdeflate_result { 194 | /* Decompression was successful. */ 195 | LIBDEFLATE_SUCCESS = 0, 196 | 197 | /* Decompression failed because the compressed data was invalid, 198 | * corrupt, or otherwise unsupported. */ 199 | LIBDEFLATE_BAD_DATA = 1, 200 | 201 | /* A NULL 'actual_out_nbytes_ret' was provided, but the data would have 202 | * decompressed to fewer than 'out_nbytes_avail' bytes. */ 203 | LIBDEFLATE_SHORT_OUTPUT = 2, 204 | 205 | /* The data would have decompressed to more than 'out_nbytes_avail' 206 | * bytes. */ 207 | LIBDEFLATE_INSUFFICIENT_SPACE = 3, 208 | }; 209 | 210 | /* 211 | * libdeflate_deflate_decompress() decompresses a DEFLATE stream from the buffer 212 | * 'in' with compressed size up to 'in_nbytes' bytes. The uncompressed data is 213 | * written to 'out', a buffer with size 'out_nbytes_avail' bytes. If 214 | * decompression succeeds, then 0 (LIBDEFLATE_SUCCESS) is returned. Otherwise, 215 | * a nonzero result code such as LIBDEFLATE_BAD_DATA is returned, and the 216 | * contents of the output buffer are undefined. 217 | * 218 | * Decompression stops at the end of the DEFLATE stream (as indicated by the 219 | * BFINAL flag), even if it is actually shorter than 'in_nbytes' bytes. 220 | * 221 | * libdeflate_deflate_decompress() can be used in cases where the actual 222 | * uncompressed size is known (recommended) or unknown (not recommended): 223 | * 224 | * - If the actual uncompressed size is known, then pass the actual 225 | * uncompressed size as 'out_nbytes_avail' and pass NULL for 226 | * 'actual_out_nbytes_ret'. This makes libdeflate_deflate_decompress() fail 227 | * with LIBDEFLATE_SHORT_OUTPUT if the data decompressed to fewer than the 228 | * specified number of bytes. 229 | * 230 | * - If the actual uncompressed size is unknown, then provide a non-NULL 231 | * 'actual_out_nbytes_ret' and provide a buffer with some size 232 | * 'out_nbytes_avail' that you think is large enough to hold all the 233 | * uncompressed data. In this case, if the data decompresses to less than 234 | * or equal to 'out_nbytes_avail' bytes, then 235 | * libdeflate_deflate_decompress() will write the actual uncompressed size 236 | * to *actual_out_nbytes_ret and return 0 (LIBDEFLATE_SUCCESS). Otherwise, 237 | * it will return LIBDEFLATE_INSUFFICIENT_SPACE if the provided buffer was 238 | * not large enough but no other problems were encountered, or another 239 | * nonzero result code if decompression failed for another reason. 240 | */ 241 | LIBDEFLATEAPI enum libdeflate_result 242 | libdeflate_deflate_decompress(struct libdeflate_decompressor *decompressor, 243 | const void *in, size_t in_nbytes, 244 | void *out, size_t out_nbytes_avail, 245 | size_t *actual_out_nbytes_ret); 246 | 247 | /* 248 | * Like libdeflate_deflate_decompress(), but adds the 'actual_in_nbytes_ret' 249 | * argument. If decompression succeeds and 'actual_in_nbytes_ret' is not NULL, 250 | * then the actual compressed size of the DEFLATE stream (aligned to the next 251 | * byte boundary) is written to *actual_in_nbytes_ret. 252 | */ 253 | LIBDEFLATEAPI enum libdeflate_result 254 | libdeflate_deflate_decompress_ex(struct libdeflate_decompressor *decompressor, 255 | const void *in, size_t in_nbytes, 256 | void *out, size_t out_nbytes_avail, 257 | size_t *actual_in_nbytes_ret, 258 | size_t *actual_out_nbytes_ret); 259 | 260 | /* 261 | * Like libdeflate_deflate_decompress(), but assumes the zlib wrapper format 262 | * instead of raw DEFLATE. 263 | * 264 | * Decompression will stop at the end of the zlib stream, even if it is shorter 265 | * than 'in_nbytes'. If you need to know exactly where the zlib stream ended, 266 | * use libdeflate_zlib_decompress_ex(). 267 | */ 268 | LIBDEFLATEAPI enum libdeflate_result 269 | libdeflate_zlib_decompress(struct libdeflate_decompressor *decompressor, 270 | const void *in, size_t in_nbytes, 271 | void *out, size_t out_nbytes_avail, 272 | size_t *actual_out_nbytes_ret); 273 | 274 | /* 275 | * Like libdeflate_zlib_decompress(), but adds the 'actual_in_nbytes_ret' 276 | * argument. If 'actual_in_nbytes_ret' is not NULL and the decompression 277 | * succeeds (indicating that the first zlib-compressed stream in the input 278 | * buffer was decompressed), then the actual number of input bytes consumed is 279 | * written to *actual_in_nbytes_ret. 280 | */ 281 | LIBDEFLATEAPI enum libdeflate_result 282 | libdeflate_zlib_decompress_ex(struct libdeflate_decompressor *decompressor, 283 | const void *in, size_t in_nbytes, 284 | void *out, size_t out_nbytes_avail, 285 | size_t *actual_in_nbytes_ret, 286 | size_t *actual_out_nbytes_ret); 287 | 288 | /* 289 | * Like libdeflate_deflate_decompress(), but assumes the gzip wrapper format 290 | * instead of raw DEFLATE. 291 | * 292 | * If multiple gzip-compressed members are concatenated, then only the first 293 | * will be decompressed. Use libdeflate_gzip_decompress_ex() if you need 294 | * multi-member support. 295 | */ 296 | LIBDEFLATEAPI enum libdeflate_result 297 | libdeflate_gzip_decompress(struct libdeflate_decompressor *decompressor, 298 | const void *in, size_t in_nbytes, 299 | void *out, size_t out_nbytes_avail, 300 | size_t *actual_out_nbytes_ret); 301 | 302 | /* 303 | * Like libdeflate_gzip_decompress(), but adds the 'actual_in_nbytes_ret' 304 | * argument. If 'actual_in_nbytes_ret' is not NULL and the decompression 305 | * succeeds (indicating that the first gzip-compressed member in the input 306 | * buffer was decompressed), then the actual number of input bytes consumed is 307 | * written to *actual_in_nbytes_ret. 308 | */ 309 | LIBDEFLATEAPI enum libdeflate_result 310 | libdeflate_gzip_decompress_ex(struct libdeflate_decompressor *decompressor, 311 | const void *in, size_t in_nbytes, 312 | void *out, size_t out_nbytes_avail, 313 | size_t *actual_in_nbytes_ret, 314 | size_t *actual_out_nbytes_ret); 315 | 316 | /* 317 | * libdeflate_free_decompressor() frees a decompressor that was allocated with 318 | * libdeflate_alloc_decompressor(). If a NULL pointer is passed in, no action 319 | * is taken. 320 | */ 321 | LIBDEFLATEAPI void 322 | libdeflate_free_decompressor(struct libdeflate_decompressor *decompressor); 323 | 324 | /* ========================================================================== */ 325 | /* Checksums */ 326 | /* ========================================================================== */ 327 | 328 | /* 329 | * libdeflate_adler32() updates a running Adler-32 checksum with 'len' bytes of 330 | * data and returns the updated checksum. When starting a new checksum, the 331 | * required initial value for 'adler' is 1. This value is also returned when 332 | * 'buffer' is specified as NULL. 333 | */ 334 | LIBDEFLATEAPI uint32_t 335 | libdeflate_adler32(uint32_t adler, const void *buffer, size_t len); 336 | 337 | 338 | /* 339 | * libdeflate_crc32() updates a running CRC-32 checksum with 'len' bytes of data 340 | * and returns the updated checksum. When starting a new checksum, the required 341 | * initial value for 'crc' is 0. This value is also returned when 'buffer' is 342 | * specified as NULL. 343 | */ 344 | LIBDEFLATEAPI uint32_t 345 | libdeflate_crc32(uint32_t crc, const void *buffer, size_t len); 346 | 347 | /* ========================================================================== */ 348 | /* Custom memory allocator */ 349 | /* ========================================================================== */ 350 | 351 | /* 352 | * Install a custom memory allocator which libdeflate will use for all memory 353 | * allocations by default. 'malloc_func' is a function that must behave like 354 | * malloc(), and 'free_func' is a function that must behave like free(). 355 | * 356 | * The per-(de)compressor custom memory allocator that can be specified in 357 | * 'struct libdeflate_options' takes priority over this. 358 | * 359 | * This doesn't affect the free() function that will be used to free 360 | * (de)compressors that were already in existence when this is called. 361 | */ 362 | LIBDEFLATEAPI void 363 | libdeflate_set_memory_allocator(void *(*malloc_func)(size_t), 364 | void (*free_func)(void *)); 365 | 366 | /* 367 | * Advanced options. This is the options structure that 368 | * libdeflate_alloc_compressor_ex() and libdeflate_alloc_decompressor_ex() 369 | * require. Most users won't need this and should just use the non-"_ex" 370 | * functions instead. If you do need this, it should be initialized like this: 371 | * 372 | * struct libdeflate_options options; 373 | * 374 | * memset(&options, 0, sizeof(options)); 375 | * options.sizeof_options = sizeof(options); 376 | * // Then set the fields that you need to override the defaults for. 377 | */ 378 | struct libdeflate_options { 379 | 380 | /* 381 | * This field must be set to the struct size. This field exists for 382 | * extensibility, so that fields can be appended to this struct in 383 | * future versions of libdeflate while still supporting old binaries. 384 | */ 385 | size_t sizeof_options; 386 | 387 | /* 388 | * An optional custom memory allocator to use for this (de)compressor. 389 | * 'malloc_func' must be a function that behaves like malloc(), and 390 | * 'free_func' must be a function that behaves like free(). 391 | * 392 | * This is useful in cases where a process might have multiple users of 393 | * libdeflate who want to use different memory allocators. For example, 394 | * a library might want to use libdeflate with a custom memory allocator 395 | * without interfering with user code that might use libdeflate too. 396 | * 397 | * This takes priority over the "global" memory allocator (which by 398 | * default is malloc() and free(), but can be changed by 399 | * libdeflate_set_memory_allocator()). Moreover, libdeflate will never 400 | * call the "global" memory allocator if a per-(de)compressor custom 401 | * allocator is always given. 402 | */ 403 | void *(*malloc_func)(size_t); 404 | void (*free_func)(void *); 405 | }; 406 | 407 | #ifdef __cplusplus 408 | } 409 | #endif 410 | 411 | #endif /* LIBDEFLATE_H */ 412 | -------------------------------------------------------------------------------- /src/ofbx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace ofbx 5 | { 6 | 7 | 8 | typedef unsigned char u8; 9 | typedef unsigned short u16; 10 | typedef unsigned int u32; 11 | #if defined(_WIN32) || defined(__ANDROID__) 12 | typedef long long i64; 13 | typedef unsigned long long u64; 14 | #else 15 | typedef long i64; 16 | typedef unsigned long u64; 17 | #endif 18 | 19 | static_assert(sizeof(u8) == 1, "u8 is not 1 byte"); 20 | static_assert(sizeof(u32) == 4, "u32 is not 4 bytes"); 21 | static_assert(sizeof(u64) == 8, "u64 is not 8 bytes"); 22 | static_assert(sizeof(i64) == 8, "i64 is not 8 bytes"); 23 | 24 | typedef decltype(sizeof(0)) usize; 25 | 26 | using JobFunction = void (*)(void*); 27 | using JobProcessor = void (*)(JobFunction, void*, void*, u32, u32); 28 | 29 | // Ignoring certain nodes will only stop them from being processed not tokenised (i.e. they will still be in the tree) 30 | enum class LoadFlags : u16 31 | { 32 | NONE = 0, 33 | KEEP_MATERIAL_MAP = 1 << 0, // keep material map even if IGNORE_GEOMETRY is used 34 | IGNORE_GEOMETRY = 1 << 1, 35 | IGNORE_BLEND_SHAPES = 1 << 2, 36 | IGNORE_CAMERAS = 1 << 3, 37 | IGNORE_LIGHTS = 1 << 4, 38 | IGNORE_TEXTURES = 1 << 5, 39 | IGNORE_SKIN = 1 << 6, 40 | IGNORE_BONES = 1 << 7, 41 | IGNORE_PIVOTS = 1 << 8, 42 | IGNORE_ANIMATIONS = 1 << 9, 43 | IGNORE_MATERIALS = 1 << 10, 44 | IGNORE_POSES = 1 << 11, 45 | IGNORE_VIDEOS = 1 << 12, 46 | IGNORE_LIMBS = 1 << 13, 47 | IGNORE_MESHES = 1 << 14, 48 | IGNORE_MODELS = 1 << 15, 49 | }; 50 | 51 | constexpr LoadFlags operator|(LoadFlags lhs, LoadFlags rhs) 52 | { 53 | return static_cast(static_cast(lhs) | static_cast(rhs)); 54 | } 55 | 56 | inline LoadFlags& operator|=(LoadFlags& lhs, LoadFlags rhs) 57 | { 58 | return lhs = lhs | rhs; 59 | } 60 | 61 | struct DVec2 { double x, y; }; 62 | struct DVec3 { double x, y, z; }; 63 | struct DVec4 { double x, y, z, w; }; 64 | struct DMatrix { double m[16]; /* last 4 are translation */ }; 65 | struct DQuat{ double x, y, z, w; }; 66 | 67 | struct FVec2 { float x, y; }; 68 | struct FVec3 { float x, y, z; }; 69 | struct FVec4 { float x, y, z, w; }; 70 | struct FMatrix { float m[16]; }; 71 | struct FQuat{ float x, y, z, w; }; 72 | 73 | #ifndef OFBX_DOUBLE_PRECISION 74 | // use floats for vertices, normals, uvs, ... 75 | using Vec2 = FVec2; 76 | using Vec3 = FVec3; 77 | using Vec4 = FVec4; 78 | using Matrix = FMatrix; 79 | using Quat = FQuat; 80 | #else 81 | // use doubles for vertices, normals, uvs, ... 82 | using Vec2 = DVec2; 83 | using Vec3 = DVec3; 84 | using Vec4 = DVec4; 85 | using Matrix = DMatrix; 86 | using Quat = DQuat; 87 | #endif 88 | 89 | struct Color 90 | { 91 | float r, g, b; 92 | }; 93 | 94 | 95 | struct DataView 96 | { 97 | const u8* begin = nullptr; 98 | const u8* end = nullptr; 99 | bool is_binary = true; 100 | 101 | bool operator!=(const char* rhs) const { return !(*this == rhs); } 102 | bool operator==(const char* rhs) const; 103 | 104 | u64 toU64() const; 105 | i64 toI64() const; 106 | int toInt() const; 107 | u32 toU32() const; 108 | bool toBool() const; 109 | double toDouble() const; 110 | float toFloat() const; 111 | 112 | template 113 | void toString(char(&out)[N]) const 114 | { 115 | char* cout = out; 116 | const u8* cin = begin; 117 | while (cin != end && cout - out < N - 1) 118 | { 119 | *cout = (char)*cin; 120 | ++cin; 121 | ++cout; 122 | } 123 | *cout = '\0'; 124 | } 125 | }; 126 | 127 | 128 | struct IElementProperty 129 | { 130 | enum Type : unsigned char 131 | { 132 | LONG = 'L', 133 | INTEGER = 'I', 134 | STRING = 'S', 135 | FLOAT = 'F', 136 | DOUBLE = 'D', 137 | ARRAY_DOUBLE = 'd', 138 | ARRAY_INT = 'i', 139 | ARRAY_LONG = 'l', 140 | ARRAY_FLOAT = 'f', 141 | BINARY = 'R', 142 | NONE = ' ' 143 | }; 144 | virtual ~IElementProperty() {} 145 | virtual Type getType() const = 0; 146 | virtual IElementProperty* getNext() const = 0; 147 | virtual DataView getValue() const = 0; 148 | virtual int getCount() const = 0; 149 | virtual bool getValues(double* values, int max_size) const = 0; 150 | virtual bool getValues(int* values, int max_size) const = 0; 151 | virtual bool getValues(float* values, int max_size) const = 0; 152 | virtual bool getValues(u64* values, int max_size) const = 0; 153 | virtual bool getValues(i64* values, int max_size) const = 0; 154 | }; 155 | 156 | 157 | struct IElement 158 | { 159 | virtual ~IElement() = default; 160 | virtual IElement* getFirstChild() const = 0; 161 | virtual IElement* getSibling() const = 0; 162 | virtual DataView getID() const = 0; 163 | virtual IElementProperty* getFirstProperty() const = 0; 164 | }; 165 | 166 | 167 | enum class RotationOrder 168 | { 169 | EULER_XYZ, 170 | EULER_XZY, 171 | EULER_YZX, 172 | EULER_YXZ, 173 | EULER_ZXY, 174 | EULER_ZYX, 175 | SPHERIC_XYZ // Currently unsupported. Treated as EULER_XYZ. 176 | }; 177 | 178 | 179 | struct AnimationCurveNode; 180 | struct AnimationLayer; 181 | struct Scene; 182 | struct IScene; 183 | 184 | 185 | struct Object 186 | { 187 | enum class Type 188 | { 189 | ROOT, 190 | GEOMETRY, 191 | SHAPE, 192 | MATERIAL, 193 | MESH, 194 | TEXTURE, 195 | LIMB_NODE, 196 | NULL_NODE, 197 | CAMERA, 198 | LIGHT, 199 | NODE_ATTRIBUTE, 200 | CLUSTER, 201 | SKIN, 202 | BLEND_SHAPE, 203 | BLEND_SHAPE_CHANNEL, 204 | ANIMATION_STACK, 205 | ANIMATION_LAYER, 206 | ANIMATION_CURVE, 207 | ANIMATION_CURVE_NODE, 208 | POSE 209 | }; 210 | 211 | Object(const Scene& _scene, const IElement& _element); 212 | 213 | virtual ~Object() {} 214 | virtual Type getType() const = 0; 215 | 216 | const IScene& getScene() const; 217 | Object* resolveObjectLink(int idx) const; 218 | Object* resolveObjectLink(Type type, const char* property, int idx) const; 219 | Object* resolveObjectLinkReverse(Type type) const; 220 | Object* getParent() const { return parent; } 221 | 222 | RotationOrder getRotationOrder() const; 223 | DVec3 getRotationOffset() const; 224 | DVec3 getRotationPivot() const; 225 | DVec3 getPostRotation() const; 226 | DVec3 getScalingOffset() const; 227 | DVec3 getScalingPivot() const; 228 | DVec3 getPreRotation() const; 229 | DVec3 getLocalTranslation() const; 230 | DVec3 getLocalRotation() const; 231 | DVec3 getLocalScaling() const; 232 | DMatrix getGlobalTransform() const; 233 | DMatrix getLocalTransform() const; 234 | DMatrix evalLocal(const DVec3& translation, const DVec3& rotation) const; 235 | DMatrix evalLocal(const DVec3& translation, const DVec3& rotation, const DVec3& scaling) const; 236 | bool isNode() const { return is_node; } 237 | 238 | 239 | template T* resolveObjectLink(int idx) const 240 | { 241 | return static_cast(resolveObjectLink(T::s_type, nullptr, idx)); 242 | } 243 | 244 | u64 id; 245 | u32 depth = 0xffFFffFF; 246 | Object* parent = nullptr; 247 | char name[128]; 248 | const IElement& element; 249 | const Object* node_attribute; 250 | 251 | protected: 252 | friend struct Scene; 253 | bool is_node; 254 | const Scene& scene; 255 | }; 256 | 257 | 258 | struct Pose : Object { 259 | static const Type s_type = Type::POSE; 260 | Pose(const Scene& _scene, const IElement& _element); 261 | 262 | virtual DMatrix getMatrix() const = 0; 263 | virtual const Object* getNode() const = 0; 264 | }; 265 | 266 | 267 | struct Texture : Object 268 | { 269 | enum TextureType 270 | { 271 | DIFFUSE, 272 | NORMAL, 273 | SPECULAR, 274 | SHININESS, 275 | AMBIENT, 276 | EMISSIVE, 277 | REFLECTION, 278 | COUNT 279 | }; 280 | 281 | static const Type s_type = Type::TEXTURE; 282 | 283 | Texture(const Scene& _scene, const IElement& _element); 284 | virtual DataView getFileName() const = 0; 285 | virtual DataView getRelativeFileName() const = 0; 286 | virtual DataView getEmbeddedData() const = 0; 287 | }; 288 | 289 | struct Light : Object 290 | { 291 | public: 292 | enum class LightType 293 | { 294 | POINT, 295 | DIRECTIONAL, 296 | SPOT, 297 | AREA, 298 | VOLUME, 299 | COUNT 300 | }; 301 | 302 | enum class DecayType 303 | { 304 | NO_DECAY, 305 | LINEAR, 306 | QUADRATIC, 307 | CUBIC, 308 | COUNT 309 | }; 310 | 311 | Light(const Scene& _scene, const IElement& _element) 312 | : Object(_scene, _element) 313 | { 314 | // Initialize the light properties here 315 | } 316 | 317 | // Light type 318 | virtual LightType getLightType() const = 0; 319 | 320 | // Light properties 321 | virtual bool doesCastLight() const = 0; 322 | virtual bool doesDrawVolumetricLight() const = 0; 323 | virtual bool doesDrawGroundProjection() const = 0; 324 | virtual bool doesDrawFrontFacingVolumetricLight() const = 0; 325 | virtual Color getColor() const = 0; 326 | virtual double getIntensity() const = 0; 327 | virtual double getInnerAngle() const = 0; 328 | virtual double getOuterAngle() const = 0; 329 | virtual double getFog() const = 0; 330 | virtual DecayType getDecayType() const = 0; 331 | virtual double getDecayStart() const = 0; 332 | 333 | // Near attenuation 334 | virtual bool doesEnableNearAttenuation() const = 0; 335 | virtual double getNearAttenuationStart() const = 0; 336 | virtual double getNearAttenuationEnd() const = 0; 337 | 338 | // Far attenuation 339 | virtual bool doesEnableFarAttenuation() const = 0; 340 | virtual double getFarAttenuationStart() const = 0; 341 | virtual double getFarAttenuationEnd() const = 0; 342 | 343 | // Shadows 344 | virtual const Texture* getShadowTexture() const = 0; 345 | virtual bool doesCastShadows() const = 0; 346 | virtual Color getShadowColor() const = 0; 347 | }; 348 | 349 | struct Camera : Object 350 | { 351 | enum class ProjectionType 352 | { 353 | PERSPECTIVE, 354 | ORTHOGRAPHIC, 355 | COUNT 356 | }; 357 | 358 | enum class ApertureMode // Used to determine how to calculate the FOV 359 | { 360 | HORIZANDVERT, 361 | HORIZONTAL, 362 | VERTICAL, 363 | FOCALLENGTH, 364 | COUNT 365 | }; 366 | 367 | enum class GateFit 368 | { 369 | NONE, 370 | VERTICAL, 371 | HORIZONTAL, 372 | FILL, 373 | OVERSCAN, 374 | STRETCH, 375 | COUNT 376 | }; 377 | 378 | static const Type s_type = Type::CAMERA; 379 | 380 | Camera(const Scene& _scene, const IElement& _element) 381 | : Object(_scene, _element) 382 | { 383 | } 384 | 385 | virtual Type getType() const { return Type::CAMERA; } 386 | virtual ProjectionType getProjectionType() const = 0; 387 | virtual ApertureMode getApertureMode() const = 0; 388 | 389 | virtual double getFilmHeight() const = 0; 390 | virtual double getFilmWidth() const = 0; 391 | 392 | virtual double getAspectHeight() const = 0; 393 | virtual double getAspectWidth() const = 0; 394 | 395 | virtual double getNearPlane() const = 0; 396 | virtual double getFarPlane() const = 0; 397 | virtual double getOrthoZoom() const = 0; 398 | virtual bool doesAutoComputeClipPanes() const = 0; 399 | 400 | virtual GateFit getGateFit() const = 0; 401 | virtual double getFilmAspectRatio() const = 0; 402 | virtual double getFocalLength() const = 0; 403 | virtual double getFocusDistance() const = 0; 404 | 405 | virtual DVec3 getBackgroundColor() const = 0; 406 | virtual DVec3 getInterestPosition() const = 0; 407 | }; 408 | 409 | struct Material : Object 410 | { 411 | static const Type s_type = Type::MATERIAL; 412 | 413 | Material(const Scene& _scene, const IElement& _element); 414 | 415 | virtual Color getDiffuseColor() const = 0; 416 | virtual Color getSpecularColor() const = 0; 417 | virtual Color getReflectionColor() const = 0; 418 | virtual Color getAmbientColor() const = 0; 419 | virtual Color getEmissiveColor() const = 0; 420 | 421 | virtual double getDiffuseFactor() const = 0; 422 | virtual double getSpecularFactor() const = 0; 423 | virtual double getReflectionFactor() const = 0; 424 | virtual double getShininess() const = 0; 425 | virtual double getShininessExponent() const = 0; 426 | virtual double getAmbientFactor() const = 0; 427 | virtual double getBumpFactor() const = 0; 428 | virtual double getEmissiveFactor() const = 0; 429 | 430 | virtual const Texture* getTexture(Texture::TextureType type) const = 0; 431 | }; 432 | 433 | 434 | struct Cluster : Object 435 | { 436 | static const Type s_type = Type::CLUSTER; 437 | 438 | Cluster(const Scene& _scene, const IElement& _element); 439 | 440 | virtual const int* getIndices() const = 0; 441 | virtual int getIndicesCount() const = 0; 442 | virtual const double* getWeights() const = 0; 443 | virtual int getWeightsCount() const = 0; 444 | virtual DMatrix getTransformMatrix() const = 0; 445 | virtual DMatrix getTransformLinkMatrix() const = 0; 446 | virtual const Object* getLink() const = 0; 447 | }; 448 | 449 | 450 | struct Skin : Object 451 | { 452 | static const Type s_type = Type::SKIN; 453 | 454 | Skin(const Scene& _scene, const IElement& _element); 455 | 456 | virtual int getClusterCount() const = 0; 457 | virtual const Cluster* getCluster(int idx) const = 0; 458 | }; 459 | 460 | 461 | struct BlendShapeChannel : Object 462 | { 463 | static const Type s_type = Type::BLEND_SHAPE_CHANNEL; 464 | 465 | BlendShapeChannel(const Scene& _scene, const IElement& _element); 466 | 467 | virtual double getDeformPercent() const = 0; 468 | virtual int getShapeCount() const = 0; 469 | virtual const struct Shape* getShape(int idx) const = 0; 470 | }; 471 | 472 | 473 | struct BlendShape : Object 474 | { 475 | static const Type s_type = Type::BLEND_SHAPE; 476 | 477 | BlendShape(const Scene& _scene, const IElement& _element); 478 | 479 | virtual int getBlendShapeChannelCount() const = 0; 480 | virtual const BlendShapeChannel* getBlendShapeChannel(int idx) const = 0; 481 | }; 482 | 483 | 484 | struct NodeAttribute : Object 485 | { 486 | static const Type s_type = Type::NODE_ATTRIBUTE; 487 | 488 | NodeAttribute(const Scene& _scene, const IElement& _element); 489 | 490 | virtual DataView getAttributeType() const = 0; 491 | }; 492 | 493 | 494 | struct Vec2Attributes { 495 | const Vec2* values = nullptr; 496 | const int* indices = nullptr; 497 | int count = 0; 498 | 499 | Vec2Attributes() {} 500 | Vec2Attributes(const Vec2* v, const int* i, int c) : values(v), indices(i), count(c) {} 501 | 502 | Vec2 get(int i) const { return indices ? values[indices[i]] : values[i]; } 503 | }; 504 | 505 | struct Vec3Attributes { 506 | const Vec3* values = nullptr; 507 | const int* indices = nullptr; 508 | int count = 0; 509 | int values_count = 0; 510 | 511 | Vec3Attributes() {} 512 | Vec3Attributes(const Vec3* v, const int* i, int c, int vc) : values(v), indices(i), count(c), values_count(vc) {} 513 | 514 | Vec3 get(int i) const { return indices ? values[indices[i]] : values[i]; } 515 | }; 516 | 517 | struct Vec4Attributes { 518 | const Vec4* values = nullptr; 519 | const int* indices = nullptr; 520 | int count = 0; 521 | 522 | Vec4Attributes() {} 523 | Vec4Attributes(const Vec4* v, const int* i, int c) : values(v), indices(i), count(c) {} 524 | 525 | Vec4 get(int i) const { return indices ? values[indices[i]] : values[i]; } 526 | }; 527 | 528 | // subset of polygons with same material 529 | struct GeometryPartition { 530 | struct Polygon { 531 | const int from_vertex; // index into VecNAttributes::indices 532 | const int vertex_count; 533 | }; 534 | const Polygon* polygons; 535 | const int polygon_count; 536 | const int max_polygon_triangles; // max triangles in single polygon, can be used for preallocation 537 | const int triangles_count; // number of triangles after polygon triangulation, can be used for preallocation 538 | }; 539 | 540 | // if we use LoadFlags::IGNORE_GEOMETRY, values here are empty/invalid, with a few exceptions 541 | struct GeometryData { 542 | virtual ~GeometryData() {} 543 | 544 | virtual Vec3Attributes getPositions() const = 0; 545 | virtual Vec3Attributes getNormals() const = 0; 546 | virtual Vec2Attributes getUVs(int index = 0) const = 0; 547 | virtual Vec4Attributes getColors() const = 0; 548 | virtual Vec3Attributes getTangents() const = 0; 549 | virtual int getPartitionCount() const = 0; 550 | virtual GeometryPartition getPartition(int partition_index) const = 0; 551 | 552 | // if we use LoadFlags::KEEP_MATERIAL_MAP, following is valid even if we use IGNORE_GEOMETRY 553 | virtual const int getMaterialMapSize() const = 0; 554 | virtual const int* getMaterialMap() const = 0; 555 | 556 | // returns true if there are vertices in the geometry 557 | // this has valid value even if we use LoadFlags::IGNORE_GEOMETRY 558 | virtual bool hasVertices() const = 0; 559 | }; 560 | 561 | 562 | struct Geometry : Object { 563 | static const Type s_type = Type::GEOMETRY; 564 | static const int s_uvs_max = 4; 565 | 566 | Geometry(const Scene& _scene, const IElement& _element); 567 | 568 | virtual const GeometryData& getGeometryData() const = 0; 569 | virtual const Skin* getSkin() const = 0; 570 | virtual const BlendShape* getBlendShape() const = 0; 571 | }; 572 | 573 | 574 | struct Shape : Object 575 | { 576 | static const Type s_type = Type::SHAPE; 577 | 578 | Shape(const Scene& _scene, const IElement& _element); 579 | 580 | virtual const Vec3* getVertices() const = 0; 581 | virtual int getVertexCount() const = 0; 582 | 583 | virtual const int* getIndices() const = 0; 584 | virtual int getIndexCount() const = 0; 585 | 586 | virtual const Vec3* getNormals() const = 0; 587 | }; 588 | 589 | 590 | struct Mesh : Object { 591 | static const Type s_type = Type::MESH; 592 | 593 | Mesh(const Scene& _scene, const IElement& _element); 594 | 595 | virtual const Pose* getPose() const = 0; 596 | virtual const Geometry* getGeometry() const = 0; 597 | virtual DMatrix getGeometricMatrix() const = 0; 598 | virtual const Material* getMaterial(int idx) const = 0; 599 | virtual int getMaterialCount() const = 0; 600 | // this will use data from `Geometry` if available and from `Mesh` otherwise 601 | virtual const GeometryData& getGeometryData() const = 0; 602 | virtual const Skin* getSkin() const = 0; 603 | virtual const BlendShape* getBlendShape() const = 0; 604 | }; 605 | 606 | 607 | struct AnimationStack : Object 608 | { 609 | static const Type s_type = Type::ANIMATION_STACK; 610 | 611 | AnimationStack(const Scene& _scene, const IElement& _element); 612 | virtual const AnimationLayer* getLayer(int index) const = 0; 613 | }; 614 | 615 | 616 | struct AnimationLayer : Object 617 | { 618 | static const Type s_type = Type::ANIMATION_LAYER; 619 | 620 | AnimationLayer(const Scene& _scene, const IElement& _element); 621 | 622 | virtual const AnimationCurveNode* getCurveNode(int index) const = 0; 623 | virtual const AnimationCurveNode* getCurveNode(const Object& bone, const char* property) const = 0; 624 | }; 625 | 626 | 627 | struct AnimationCurve : Object 628 | { 629 | static const Type s_type = Type::ANIMATION_CURVE; 630 | 631 | AnimationCurve(const Scene& _scene, const IElement& _element); 632 | 633 | virtual int getKeyCount() const = 0; 634 | virtual const i64* getKeyTime() const = 0; 635 | virtual const float* getKeyValue() const = 0; 636 | }; 637 | 638 | 639 | struct AnimationCurveNode : Object 640 | { 641 | static const Type s_type = Type::ANIMATION_CURVE_NODE; 642 | 643 | AnimationCurveNode(const Scene& _scene, const IElement& _element); 644 | 645 | virtual DataView getBoneLinkProperty() const = 0; 646 | virtual const AnimationCurve* getCurve(int idx) const = 0; 647 | virtual DVec3 getNodeLocalTransform(double time) const = 0; 648 | virtual const Object* getBone() const = 0; 649 | }; 650 | 651 | 652 | struct TakeInfo 653 | { 654 | DataView name; 655 | DataView filename; 656 | double local_time_from; 657 | double local_time_to; 658 | double reference_time_from; 659 | double reference_time_to; 660 | }; 661 | 662 | 663 | // Specifies which canonical axis represents up in the system (typically Y or Z). 664 | enum UpVector 665 | { 666 | UpVector_AxisX = 0, 667 | UpVector_AxisY = 1, 668 | UpVector_AxisZ = 2 669 | }; 670 | 671 | 672 | // Specifies the third vector of the system. 673 | enum CoordSystem 674 | { 675 | CoordSystem_RightHanded = 0, 676 | CoordSystem_LeftHanded = 1 677 | }; 678 | 679 | 680 | // http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/index.html?url=cpp_ref/class_fbx_time.html,topicNumber=cpp_ref_class_fbx_time_html29087af6-8c2c-4e9d-aede-7dc5a1c2436c,hash=a837590fd5310ff5df56ffcf7c394787e 681 | enum FrameRate 682 | { 683 | FrameRate_DEFAULT = 0, 684 | FrameRate_120 = 1, 685 | FrameRate_100 = 2, 686 | FrameRate_60 = 3, 687 | FrameRate_50 = 4, 688 | FrameRate_48 = 5, 689 | FrameRate_30 = 6, 690 | FrameRate_30_DROP = 7, 691 | FrameRate_NTSC_DROP_FRAME = 8, 692 | FrameRate_NTSC_FULL_FRAME = 9, 693 | FrameRate_PAL = 10, 694 | FrameRate_CINEMA = 11, 695 | FrameRate_1000 = 12, 696 | FrameRate_CINEMA_ND = 13, 697 | FrameRate_CUSTOM = 14, 698 | }; 699 | 700 | 701 | struct GlobalSettings 702 | { 703 | UpVector UpAxis = UpVector_AxisY; 704 | int UpAxisSign = 1; 705 | // this seems to be 1-2 in Autodesk (odd/even parity), and 0-2 in Blender (axis as in UpAxis) 706 | // I recommend to ignore FrontAxis and use just UpVector 707 | int FrontAxis = 1; 708 | int FrontAxisSign = 1; 709 | CoordSystem CoordAxis = CoordSystem_RightHanded; 710 | int CoordAxisSign = 1; 711 | int OriginalUpAxis = 0; 712 | int OriginalUpAxisSign = 1; 713 | float UnitScaleFactor = 1; 714 | float OriginalUnitScaleFactor = 1; 715 | double TimeSpanStart = 0L; 716 | double TimeSpanStop = 0L; 717 | FrameRate TimeMode = FrameRate_DEFAULT; 718 | float CustomFrameRate = -1.0f; 719 | }; 720 | 721 | 722 | struct IScene 723 | { 724 | virtual void destroy() = 0; 725 | 726 | // Root Node 727 | virtual const IElement* getRootElement() const = 0; 728 | virtual const Object* getRoot() const = 0; 729 | 730 | // Meshes 731 | virtual int getMeshCount() const = 0; 732 | virtual const Mesh* getMesh(int index) const = 0; 733 | 734 | // Geometry 735 | virtual int getGeometryCount() const = 0; 736 | virtual const Geometry* getGeometry(int index) const = 0; 737 | 738 | // Animations 739 | virtual int getAnimationStackCount() const = 0; 740 | virtual const AnimationStack* getAnimationStack(int index) const = 0; 741 | 742 | // Cameras 743 | virtual int getCameraCount() const = 0; 744 | virtual const Camera* getCamera(int index) const = 0; 745 | 746 | // Lights 747 | virtual int getLightCount() const = 0; 748 | virtual const Light* getLight(int index) const = 0; 749 | 750 | // Scene Objects (Everything in scene) 751 | virtual const Object* const* getAllObjects() const = 0; 752 | virtual int getAllObjectCount() const = 0; 753 | 754 | // Embedded files/Data 755 | virtual int getEmbeddedDataCount() const = 0; 756 | virtual DataView getEmbeddedData(int index) const = 0; 757 | virtual DataView getEmbeddedFilename(int index) const = 0; 758 | virtual bool isEmbeddedBase64(int index) const = 0; 759 | // data are encoded in returned property and all ->next properties 760 | virtual const IElementProperty* getEmbeddedBase64Data(int index) const = 0; 761 | 762 | // Scene Misc 763 | virtual const TakeInfo* getTakeInfo(const char* name) const = 0; 764 | virtual float getSceneFrameRate() const = 0; 765 | virtual const GlobalSettings* getGlobalSettings() const = 0; 766 | 767 | protected: 768 | virtual ~IScene() {} 769 | }; 770 | 771 | 772 | IScene* load(const u8* data, usize size, u16 flags, JobProcessor job_processor = nullptr, void* job_user_ptr = nullptr); 773 | const char* getError(); 774 | double fbxTimeToSeconds(i64 value); 775 | i64 secondsToFbxTime(double value); 776 | 777 | // TODO nonconvex 778 | inline u32 triangulate(const GeometryData& geom, const GeometryPartition::Polygon& polygon, int* tri_indices) { 779 | if (polygon.vertex_count < 3) return 0; 780 | if (polygon.vertex_count == 3) { 781 | tri_indices[0] = polygon.from_vertex; 782 | tri_indices[1] = polygon.from_vertex + 1; 783 | tri_indices[2] = polygon.from_vertex + 2; 784 | return 3; 785 | } 786 | else if (polygon.vertex_count == 4) { 787 | tri_indices[0] = polygon.from_vertex + 0; 788 | tri_indices[1] = polygon.from_vertex + 1; 789 | tri_indices[2] = polygon.from_vertex + 2; 790 | 791 | tri_indices[3] = polygon.from_vertex + 0; 792 | tri_indices[4] = polygon.from_vertex + 2; 793 | tri_indices[5] = polygon.from_vertex + 3; 794 | return 6; 795 | } 796 | 797 | for (int tri = 0; tri < polygon.vertex_count - 2; ++tri) { 798 | tri_indices[tri * 3 + 0] = polygon.from_vertex; 799 | tri_indices[tri * 3 + 1] = polygon.from_vertex + 1 + tri; 800 | tri_indices[tri * 3 + 2] = polygon.from_vertex + 2 + tri; 801 | } 802 | return 3 * (polygon.vertex_count - 2); 803 | } 804 | 805 | 806 | } // namespace ofbx 807 | 808 | #ifdef OFBX_DEFAULT_DELETER 809 | #include 810 | 811 | template <> struct ::std::default_delete 812 | { 813 | default_delete() = default; 814 | template constexpr default_delete(default_delete) noexcept {} 815 | void operator()(ofbx::IScene* scene) const noexcept 816 | { 817 | if (scene) 818 | { 819 | scene->destroy(); 820 | } 821 | } 822 | }; 823 | #endif 824 | --------------------------------------------------------------------------------