├── .appveyor.yml ├── .cmakeformat ├── .flake8 ├── .github └── workflows │ ├── build.yml │ └── tests.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── MANIFEST.in ├── README.md ├── examples ├── __init__.py ├── assets │ ├── meshes │ │ └── bunny.bin │ ├── shaders │ │ ├── cubes.FragmentShader.frag │ │ ├── cubes.VertexShader.vert │ │ ├── mesh.FragmentShader.frag │ │ ├── mesh.VertexShader.vert │ │ ├── textures.FragmentShader.frag │ │ ├── textures.VertexShader.vert │ │ └── varying.def.sc │ └── textures │ │ └── python_logo.png ├── cubes │ ├── __init__.py │ └── cubes.py ├── example_window.py ├── helloworld │ ├── __init__.py │ ├── helloworld.py │ ├── python_image.py │ └── screenshot.png ├── mesh │ ├── __init__.py │ └── mesh.py ├── textures │ ├── __init__.py │ └── textures.py └── utils │ ├── __init__.py │ ├── imgui_utils.py │ └── matrix_utils.py ├── noxfile.py ├── poetry.lock ├── pybgfx ├── __init__.py ├── constants.py ├── initializor.py └── utils │ ├── __init__.py │ ├── imgui_utils.py │ ├── mesh_utils.py │ └── shaders_utils.py ├── pyproject.toml ├── setup.py ├── src ├── CMakeLists.txt ├── cmake_modules │ ├── ExportAllSymbolsWindows.cmake │ ├── FindCppyy.cmake │ ├── FindLibClang.cmake │ └── FindWindowsSDK.cmake ├── extras │ ├── bgfx_extra.cpp │ ├── bgfx_extra.h │ ├── imgui_extra.cpp │ └── imgui_extra.h └── scripts │ └── rename_runtime.bat └── tests ├── __init__.py ├── osmesa_context.py └── test_examples.py /.appveyor.yml: -------------------------------------------------------------------------------- 1 | shallow_clone: false 2 | 3 | os: 4 | - Visual Studio 2017 5 | 6 | platform: 7 | - x64 8 | 9 | configuration: 10 | - Release 11 | 12 | environment: 13 | VCVAR2017: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat' 14 | 15 | matrix: 16 | - PYTHON: "C:\\Python39-x64" 17 | PYTHON_VERSION: "3.9.x" 18 | PYTHON_ARCH: "64" 19 | 20 | - PYTHON: "C:\\Python38-x64" 21 | PYTHON_VERSION: "3.8.x" 22 | PYTHON_ARCH: "64" 23 | 24 | - PYTHON: "C:\\Python37-x64" 25 | PYTHON_VERSION: "3.7.x" 26 | PYTHON_ARCH: "64" 27 | 28 | install: 29 | - git submodule update --init --recursive 30 | - ps: | 31 | if (-not (Test-Path $env:PYTHON)) { 32 | curl -o install_python.ps1 https://raw.githubusercontent.com/matthew-brett/multibuild/devel/install_python.ps1 33 | .\install_python.ps1 34 | } 35 | - ps: if (-not (Test-Path $env:PYTHON)) { throw "No $env:PYTHON" } 36 | - "set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" 37 | - python --version 38 | 39 | build_script: 40 | # Build the compiled extension 41 | - call "%VCVAR2017%" x86_amd64 42 | - cmd: | 43 | "%PYTHON%\\python.exe" -m pip install --upgrade pip 44 | "%PYTHON%\\python.exe" -m pip install --upgrade setuptools 45 | set "CI_BUILD=1" && "%PYTHON%\\python.exe" -m pip wheel --wheel-dir=%cd%\dist . --verbose 46 | 47 | artifacts: 48 | # Archive the generated packages in the ci.appveyor.com build report. 49 | - path: dist\bgfx_python* 50 | 51 | #on_success: 52 | # - TODO: upload the content of dist/*.whl to a public wheelhouse 53 | # -------------------------------------------------------------------------------- /.cmakeformat: -------------------------------------------------------------------------------- 1 | # ---------------------------------- 2 | # Options affecting listfile parsing 3 | # ---------------------------------- 4 | with section("parse"): 5 | 6 | # Specify structure for custom cmake functions 7 | additional_commands = { 'foo': { 'flags': ['BAR', 'BAZ'], 8 | 'kwargs': {'DEPENDS': '*', 'HEADERS': '*', 'SOURCES': '*'}}} 9 | 10 | # Override configurations per-command where available 11 | override_spec = {} 12 | 13 | # Specify variable tags. 14 | vartags = [] 15 | 16 | # Specify property tags. 17 | proptags = [] 18 | 19 | # ----------------------------- 20 | # Options affecting formatting. 21 | # ----------------------------- 22 | with section("format"): 23 | 24 | # Disable formatting entirely, making cmake-format a no-op 25 | disable = False 26 | 27 | # How wide to allow formatted cmake files 28 | line_width = 120 29 | 30 | # How many spaces to tab for indent 31 | tab_size = 2 32 | 33 | # If true, lines are indented using tab characters (utf-8 0x09) instead of 34 | # space characters (utf-8 0x20). In cases where the layout would 35 | # require a fractional tab character, the behavior of the fractional 36 | # indentation is governed by 37 | use_tabchars = False 38 | 39 | # If is True, then the value of this variable indicates how 40 | # fractional indentions are handled during whitespace replacement. If set to 41 | # 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set 42 | # to `round-up` fractional indentation is replaced with a single tab character 43 | # (utf-8 0x09) effectively shifting the column to the next tabstop 44 | fractional_tab_policy = 'use-space' 45 | 46 | # If an argument group contains more than this many sub-groups (parg or kwarg 47 | # groups) then force it to a vertical layout. 48 | max_subgroups_hwrap = 2 49 | 50 | # If a positional argument group contains more than this many arguments, then 51 | # force it to a vertical layout. 52 | max_pargs_hwrap = 6 53 | 54 | # If a cmdline positional group consumes more than this many lines without 55 | # nesting, then invalidate the layout (and nest) 56 | max_rows_cmdline = 2 57 | 58 | # If true, separate flow control names from their parentheses with a space 59 | separate_ctrl_name_with_space = False 60 | 61 | # If true, separate function names from parentheses with a space 62 | separate_fn_name_with_space = False 63 | 64 | # If a statement is wrapped to more than one line, than dangle the closing 65 | # parenthesis on its own line. 66 | dangle_parens = False 67 | 68 | # If the trailing parenthesis must be 'dangled' on its on line, then align it 69 | # to this reference: `prefix`: the start of the statement, `prefix-indent`: 70 | # the start of the statement, plus one indentation level, `child`: align to 71 | # the column of the arguments 72 | dangle_align = 'prefix' 73 | 74 | # If the statement spelling length (including space and parenthesis) is 75 | # smaller than this amount, then force reject nested layouts. 76 | min_prefix_chars = 4 77 | 78 | # If the statement spelling length (including space and parenthesis) is larger 79 | # than the tab width by more than this amount, then force reject un-nested 80 | # layouts. 81 | max_prefix_chars = 10 82 | 83 | # If a candidate layout is wrapped horizontally but it exceeds this many 84 | # lines, then reject the layout. 85 | max_lines_hwrap = 2 86 | 87 | # What style line endings to use in the output. 88 | line_ending = 'unix' 89 | 90 | # Format command names consistently as 'lower' or 'upper' case 91 | command_case = 'canonical' 92 | 93 | # Format keywords consistently as 'lower' or 'upper' case 94 | keyword_case = 'unchanged' 95 | 96 | # A list of command names which should always be wrapped 97 | always_wrap = [] 98 | 99 | # If true, the argument lists which are known to be sortable will be sorted 100 | # lexicographicall 101 | enable_sort = True 102 | 103 | # If true, the parsers may infer whether or not an argument list is sortable 104 | # (without annotation). 105 | autosort = False 106 | 107 | # By default, if cmake-format cannot successfully fit everything into the 108 | # desired linewidth it will apply the last, most agressive attempt that it 109 | # made. If this flag is True, however, cmake-format will print error, exit 110 | # with non-zero status code, and write-out nothing 111 | require_valid_layout = False 112 | 113 | # A dictionary mapping layout nodes to a list of wrap decisions. See the 114 | # documentation for more information. 115 | layout_passes = {} 116 | 117 | # ------------------------------------------------ 118 | # Options affecting comment reflow and formatting. 119 | # ------------------------------------------------ 120 | with section("markup"): 121 | 122 | # What character to use for bulleted lists 123 | bullet_char = '*' 124 | 125 | # What character to use as punctuation after numerals in an enumerated list 126 | enum_char = '.' 127 | 128 | # If comment markup is enabled, don't reflow the first comment block in each 129 | # listfile. Use this to preserve formatting of your copyright/license 130 | # statements. 131 | first_comment_is_literal = False 132 | 133 | # If comment markup is enabled, don't reflow any comment block which matches 134 | # this (regex) pattern. Default is `None` (disabled). 135 | literal_comment_pattern = None 136 | 137 | # Regular expression to match preformat fences in comments default= 138 | # ``r'^\s*([`~]{3}[`~]*)(.*)$'`` 139 | fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$' 140 | 141 | # Regular expression to match rulers in comments default= 142 | # ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'`` 143 | ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$' 144 | 145 | # If a comment line matches starts with this pattern then it is explicitly a 146 | # trailing comment for the preceeding argument. Default is '#<' 147 | explicit_trailing_pattern = '#<' 148 | 149 | # If a comment line starts with at least this many consecutive hash 150 | # characters, then don't lstrip() them off. This allows for lazy hash rulers 151 | # where the first hash char is not separated by space 152 | hashruler_min_length = 10 153 | 154 | # If true, then insert a space between the first hash char and remaining hash 155 | # chars in a hash ruler, and normalize its length to fill the column 156 | canonicalize_hashrulers = True 157 | 158 | # enable comment markup parsing and reflow 159 | enable_markup = True 160 | 161 | # ---------------------------- 162 | # Options affecting the linter 163 | # ---------------------------- 164 | with section("lint"): 165 | 166 | # a list of lint codes to disable 167 | disabled_codes = [] 168 | 169 | # regular expression pattern describing valid function names 170 | function_pattern = '[0-9a-z_]+' 171 | 172 | # regular expression pattern describing valid macro names 173 | macro_pattern = '[0-9A-Z_]+' 174 | 175 | # regular expression pattern describing valid names for variables with global 176 | # (cache) scope 177 | global_var_pattern = '[A-Z][0-9A-Z_]+' 178 | 179 | # regular expression pattern describing valid names for variables with global 180 | # scope (but internal semantic) 181 | internal_var_pattern = '_[A-Z][0-9A-Z_]+' 182 | 183 | # regular expression pattern describing valid names for variables with local 184 | # scope 185 | local_var_pattern = '[a-z][a-z0-9_]+' 186 | 187 | # regular expression pattern describing valid names for privatedirectory 188 | # variables 189 | private_var_pattern = '_[0-9a-z_]+' 190 | 191 | # regular expression pattern describing valid names for public directory 192 | # variables 193 | public_var_pattern = '[A-Z][0-9A-Z_]+' 194 | 195 | # regular expression pattern describing valid names for function/macro 196 | # arguments and loop variables. 197 | argument_var_pattern = '[a-z][a-z0-9_]+' 198 | 199 | # regular expression pattern describing valid names for keywords used in 200 | # functions or macros 201 | keyword_pattern = '[A-Z][0-9A-Z_]+' 202 | 203 | # In the heuristic for C0201, how many conditionals to match within a loop in 204 | # before considering the loop a parser. 205 | max_conditionals_custom_parser = 2 206 | 207 | # Require at least this many newlines between statements 208 | min_statement_spacing = 1 209 | 210 | # Require no more than this many newlines between statements 211 | max_statement_spacing = 2 212 | max_returns = 6 213 | max_branches = 12 214 | max_arguments = 5 215 | max_localvars = 15 216 | max_statements = 50 217 | 218 | # ------------------------------- 219 | # Options affecting file encoding 220 | # ------------------------------- 221 | with section("encode"): 222 | 223 | # If true, emit the unicode byte-order mark (BOM) at the start of the file 224 | emit_byteorder_mark = False 225 | 226 | # Specify the encoding of the input file. Defaults to utf-8 227 | input_encoding = 'utf-8' 228 | 229 | # Specify the encoding of the output file. Defaults to utf-8. Note that cmake 230 | # only claims to support utf-8 so be careful when using anything else 231 | output_encoding = 'utf-8' 232 | 233 | # ------------------------------------- 234 | # Miscellaneous configurations options. 235 | # ------------------------------------- 236 | with section("misc"): 237 | 238 | # A dictionary containing any per-command configuration overrides. Currently 239 | # only `command_case` is supported. 240 | per_command = {} 241 | 242 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | select = B,B9,BLK,C,E,F,I,S,W 3 | ignore = E203,E501,W503,E731,F405,F403,F401 4 | max-line-length = 128 5 | per-file-ignores = tests/*:S101 6 | import-order-style = google 7 | application-import-names = src,tests -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build_wheels: 7 | if: "!contains(github.event.commits[0].message, '[skip ci]')" 8 | name: Build wheels on ${{ matrix.os }} 9 | runs-on: ${{ matrix.os }} 10 | continue-on-error: true 11 | strategy: 12 | matrix: 13 | os: [ubuntu-20.04, macos-10.15] 14 | steps: 15 | - uses: actions/checkout@v2 16 | with: 17 | submodules: true 18 | 19 | - name: Set up Python 3.8 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: 3.8 23 | 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install setuptools wheel scikit-build cmake ninja loguru cibuildwheel==1.7.2 cppyy clang 28 | 29 | - name: Build wheels 30 | shell: bash 31 | run: | 32 | if [[ ! -e /usr/include ]]; then 33 | export SDKROOT="$(xcrun --show-sdk-path)" 34 | fi 35 | python -m cibuildwheel --output-dir wheelhouse 36 | env: 37 | CIBW_BUILD_VERBOSITY: 0 38 | CIBW_SKIP: "*-manylinux_i686" 39 | CIBW_BUILD: "cp37-* cp38-* cp39-*" 40 | CIBW_BEFORE_BUILD_MACOS: "pip install --upgrade delocate" 41 | CIBW_REPAIR_WHEEL_COMMAND_MACOS: "delocate-listdeps {wheel} && mkdir -p {dest_dir} && cp {wheel} {dest_dir}" 42 | CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel show {wheel} && auditwheel repair --plat linux_x86_64 -w {dest_dir} {wheel}" 43 | CIBW_BEFORE_BUILD_LINUX: | 44 | pip install clang==5.0 && \ 45 | yum install -y freeglut freeglut-devel libX11-devel mesa-libGLU-devel byacc 46 | CIBW_MANYLINUX_X86_64_IMAGE: ghcr.io/fbertola/manylinux2014_gcc:1.0.5 47 | 48 | - name: Upload artifact 49 | uses: actions/upload-artifact@v2 50 | with: 51 | path: wheelhouse/*.whl 52 | 53 | build_sdist: 54 | name: Build source distribution 55 | runs-on: ubuntu-latest 56 | steps: 57 | - uses: actions/checkout@v2 58 | 59 | - uses: actions/setup-python@v2 60 | name: Install Python 61 | with: 62 | python-version: "3.7" 63 | 64 | - name: Install dependencies 65 | run: | 66 | python -m pip install --upgrade pip 67 | pip install setuptools wheel scikit-build cmake ninja loguru 68 | 69 | - name: Build sdist 70 | run: python setup.py sdist 71 | 72 | - uses: actions/upload-artifact@v2 73 | with: 74 | path: dist/*.tar.gz -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [push] 4 | 5 | jobs: 6 | run_tests: 7 | name: Run tests 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Set up Python 3.8 13 | uses: actions/setup-python@v2 14 | with: 15 | python-version: 3.8 16 | 17 | - name: Install System dependencies 18 | run: | 19 | sudo apt-get update 20 | sudo apt-get install libosmesa6-dev -y 21 | 22 | - name: Install Python dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install poetry nox 26 | 27 | - name: Run tests 28 | run: | 29 | # rm -rf bgfx 30 | # /usr/bin/xvfb-run --auto-servernum nox -rs tests -- tests 31 | true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # PyCharm project folders 107 | .idea 108 | 109 | # SciKit-Build files 110 | _skbuild/ 111 | 112 | .DS_Store 113 | tags 114 | upload.sh 115 | shaders_cache* 116 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dependencies/bgfx"] 2 | path = dependencies/bgfx 3 | url = https://github.com/bkaradzic/bgfx 4 | [submodule "dependencies/bimg"] 5 | path = dependencies/bimg 6 | url = https://github.com/bkaradzic/bimg 7 | [submodule "dependencies/bx"] 8 | path = dependencies/bx 9 | url = https://github.com/bkaradzic/bx 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2021, Federico Bertola 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | exclude LICENSE README.md CONTRIBUTING.md CODE_OF_CONDUCT.md CHANGELOG.rst NOTICES HISTORY.txt pyproject.toml 2 | exclude .editorconfig .travis.yml .env appveyor.yml tox.ini pytest.ini 3 | exclude .gitmodules 4 | exclude src 5 | exclude examples 6 | 7 | recursive-include pybgfx *.pcm *.rootmap *.map 8 | recursive-include pybgfx *.sh 9 | recursive-include pybgfx/utils *.py 10 | recursive-include docs Makefile *.rst *.py *.bat 11 | recursive-include docs/_templates *.html 12 | recursive-include docs/_static *.js *.css *.png 13 | recursive-exclude docs requirements*.txt 14 | recursive-exclude pybgfx *.pyi 15 | recursive-exclude pybgfx *.typed 16 | 17 | prune .github 18 | prune docs/build 19 | prune tests 20 | prune dependencies 21 | prune scripts 22 | prune _skbuild -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |
3 | BGFX Python 4 |
5 |

6 | 7 |

Python 3.7+ wrapper for the BGFX library.

8 | 9 |

10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 |

22 | 23 |

24 | Key Features • 25 | How To Use • • 26 | Using ImGUI • 27 | Examples • 28 | Logging • 29 | Credits • 30 | License 31 |

32 | 33 |

34 | 35 |

36 | 37 | ## Key Features 38 | 39 | * Uses [Cppyy](https://cppyy.readthedocs.io/en/latest/) to natively wrap the C++ interface. No _CTypes_ or ugly C interfaces. 40 | * Unless specified, the GIL is released for every invocation and pointers are passed by reference. This will ensure great overall performances. 41 | * Maintains the original documentation; use `help()` on a class or function to view it. 42 | * Compiles shaders on-the-fly, so you don't have to. 43 | * Ships with [ImGui](https://github.com/ocornut/imgui) integrated in the BGFX rendering pipeline. 44 | 45 | ## How To Use 46 | 47 | ### Precompiled wheels 48 | 49 | Precompiled wheels are available for Windows, Linux and MacOS. 50 | To install the latest published release, simply run: 51 | 52 | ```bash 53 | $ pip install bgfx-python 54 | ``` 55 | 56 | ### Install from source 57 | 58 | To install the latest version, you'll need to clone this repository and its submodules: 59 | 60 | ```bash 61 | $ git clone --depth=1 https://github.com/fbertola/bgfx-python 62 | $ git submodule update --init --recursive 63 | ``` 64 | 65 | Then, make sure to have `make`, `cmake` and `ninja` installed in your system. 66 | 67 | Install the required dependency through `poetry`: 68 | 69 | ```bash 70 | $ pip install poetry 71 | $ poetry install 72 | ``` 73 | 74 | Finally, simply build and install the wheel. 75 | 76 | ```bash 77 | $ pip setup.py install 78 | ``` 79 | 80 | ### Installing on MacOS 81 | 82 | Building on MacOS X > 10.14 requires you to also install the SDK headers: 83 | 84 | ```bash 85 | xcode-select --install 86 | open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg 87 | export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk 88 | ``` 89 | 90 | ### Installing on Windows 91 | 92 | The easiest way is to install [Visual Studio 2017 Community Edition](https://visualstudio.microsoft.com/it/vs/). If you have [Chocolatey](https://chocolatey.org/install) installed, then run: 93 | 94 | ```bash 95 | choco install visualstudio2017community 96 | ``` 97 | 98 | Before building the package, make sure to activate all the environment variables required by the compiler: 99 | 100 | ```bash 101 | call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64 102 | ``` 103 | 104 | ## Using ImGUI 105 | 106 | Two modules are exposed: 107 | * *ImGui*, which provides a standard wrapper around all the ImGui funcions and classes. 108 | * *ImGuiExtra*, which provides some additional functions to integrate ImGui in the BGFX rendering pipline. 109 | 110 | To use it in your application, simply follow this template: 111 | 112 | ```python 113 | # Setup the application 114 | def init(): 115 | ImGuiExtra.create() 116 | 117 | # Destroy the application 118 | def destroy(): 119 | ImGuiExtra.destroy() 120 | 121 | # Update the application, rendering each fram 122 | def update(): 123 | ImGuiExtra.beginFrame( 124 | mouse_x, mouse_y, buttons_states, 0, width, height 125 | ) 126 | 127 | # Other ImGui drawing directives... 128 | 129 | ImGuiExtra.endFrame() 130 | ``` 131 | 132 | ## Logging 133 | 134 | [Loguru](https://github.com/Delgan/loguru) is used for logging inside `bgfx_python`. By default the logger is disabled; to enable it, use the following instructions: 135 | 136 | ```python 137 | from loguru import logger 138 | 139 | logger.enable("bgfx") 140 | ``` 141 | 142 | ## Examples 143 | 144 | You will find some examples in the `examples` folder, be sure to check them out. 145 | For a more advanced example, see the [Natrix](https://github.com/fbertola/Natrix) project. 146 | 147 | ## Credits 148 | 149 | This software uses the following open source packages: 150 | 151 | - [bgfx](https://github.com/bkaradzic/bgfx) 152 | - [cppyy](https://cppyy.readthedocs.io/en/latest/) 153 | 154 | 155 | [License (BSD 2-clause)](https://raw.githubusercontent.com/fbertola/bgfx-python/master/LICENSE) 156 | ----------------------------------------------------------------------- 157 | 158 | 159 | 160 | 161 | 162 | BSD 2-Clause License 163 | 164 | Copyright (c) 2021, Federico Bertola 165 | All rights reserved. 166 | 167 | Redistribution and use in source and binary forms, with or without 168 | modification, are permitted provided that the following conditions are met: 169 | 170 | 1. Redistributions of source code must retain the above copyright notice, this 171 | list of conditions and the following disclaimer. 172 | 173 | 2. Redistributions in binary form must reproduce the above copyright notice, 174 | this list of conditions and the following disclaimer in the documentation 175 | and/or other materials provided with the distribution. 176 | 177 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 178 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 179 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 180 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 181 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 182 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 183 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 184 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 185 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 186 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 187 | 188 | 189 | --- 190 | 191 | > GitHub [@fbertola](https://github.com/fbertola) 192 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/__init__.py -------------------------------------------------------------------------------- /examples/assets/meshes/bunny.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/assets/meshes/bunny.bin -------------------------------------------------------------------------------- /examples/assets/shaders/cubes.FragmentShader.frag: -------------------------------------------------------------------------------- 1 | $input v_color0 2 | 3 | #include 4 | 5 | void main() 6 | { 7 | gl_FragColor = v_color0; 8 | } -------------------------------------------------------------------------------- /examples/assets/shaders/cubes.VertexShader.vert: -------------------------------------------------------------------------------- 1 | $input a_position, a_color0 2 | $output v_color0 3 | 4 | #include 5 | 6 | void main() 7 | { 8 | gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0) ); 9 | v_color0 = a_color0; 10 | } -------------------------------------------------------------------------------- /examples/assets/shaders/mesh.FragmentShader.frag: -------------------------------------------------------------------------------- 1 | $input v_pos, v_view, v_normal, v_color0 2 | 3 | #include 4 | 5 | uniform vec4 u_time; 6 | 7 | vec2 blinn(vec3 _lightDir, vec3 _normal, vec3 _viewDir) 8 | { 9 | float ndotl = dot(_normal, _lightDir); 10 | vec3 reflected = _lightDir - 2.0*ndotl*_normal; // reflect(_lightDir, _normal); 11 | float rdotv = dot(reflected, _viewDir); 12 | return vec2(ndotl, rdotv); 13 | } 14 | 15 | float fresnel(float _ndotl, float _bias, float _pow) 16 | { 17 | float facing = (1.0 - _ndotl); 18 | return max(_bias + (1.0 - _bias) * pow(facing, _pow), 0.0); 19 | } 20 | 21 | vec4 lit(float _ndotl, float _rdotv, float _m) 22 | { 23 | float diff = max(0.0, _ndotl); 24 | float spec = step(0.0, _ndotl) * max(0.0, _rdotv * _m); 25 | return vec4(1.0, diff, spec, 1.0); 26 | } 27 | 28 | void main() 29 | { 30 | vec3 lightDir = vec3(0.0, 0.0, -1.0); 31 | vec3 normal = normalize(v_normal); 32 | vec3 view = normalize(v_view); 33 | vec2 bln = blinn(lightDir, normal, view); 34 | vec4 lc = lit(bln.x, bln.y, 1.0); 35 | float fres = fresnel(bln.x, 0.2, 5.0); 36 | 37 | float index = ( (sin(v_pos.x*3.0+u_time.x)*0.3+0.7) 38 | + ( cos(v_pos.y*3.0+u_time.x)*0.4+0.6) 39 | + ( cos(v_pos.z*3.0+u_time.x)*0.2+0.8) 40 | )*M_PI; 41 | 42 | vec3 color = vec3(sin(index*8.0)*0.4 + 0.6 43 | , sin(index*4.0)*0.4 + 0.6 44 | , sin(index*2.0)*0.4 + 0.6 45 | ) * v_color0.xyz; 46 | 47 | gl_FragColor.xyz = pow(vec3(0.07, 0.06, 0.08) + color*lc.y + fres*pow(lc.z, 128.0), vec3_splat(1.0/2.2) ); 48 | gl_FragColor.w = 1.0; 49 | } 50 | -------------------------------------------------------------------------------- /examples/assets/shaders/mesh.VertexShader.vert: -------------------------------------------------------------------------------- 1 | $input a_position, a_normal 2 | $output v_pos, v_view, v_normal, v_color0 3 | 4 | #include 5 | 6 | uniform vec4 u_time; 7 | 8 | void main() 9 | { 10 | vec3 pos = a_position; 11 | 12 | float sx = sin(pos.x*32.0+u_time.x*4.0)*0.5+0.5; 13 | float cy = cos(pos.y*32.0+u_time.x*4.0)*0.5+0.5; 14 | vec3 displacement = vec3(sx, cy, sx*cy); 15 | vec3 normal = a_normal.xyz*2.0 - 1.0; 16 | 17 | pos = pos + normal*displacement*vec3(0.06, 0.06, 0.06); 18 | 19 | gl_Position = mul(u_modelViewProj, vec4(pos, 1.0) ); 20 | v_pos = gl_Position.xyz; 21 | v_view = mul(u_modelView, vec4(pos, 1.0) ).xyz; 22 | 23 | v_normal = mul(u_modelView, vec4(normal, 0.0) ).xyz; 24 | 25 | float len = length(displacement)*0.4+0.6; 26 | v_color0 = vec4(len, len, len, 1.0); 27 | } 28 | -------------------------------------------------------------------------------- /examples/assets/shaders/textures.FragmentShader.frag: -------------------------------------------------------------------------------- 1 | $input v_color0,v_texcoord0 2 | 3 | #include 4 | SAMPLER2D(s_tex, 0); 5 | 6 | void main() 7 | { 8 | //In this example the color component from the vertex shader is not used 9 | //gl_FragColor = v_color0; 10 | gl_FragColor = texture2D(s_tex,v_texcoord0); 11 | } -------------------------------------------------------------------------------- /examples/assets/shaders/textures.VertexShader.vert: -------------------------------------------------------------------------------- 1 | $input a_position, a_color0, a_texcoord0 2 | $output v_color0, v_texcoord0 3 | 4 | #include 5 | 6 | void main() 7 | { 8 | gl_Position = mul(u_modelViewProj, vec4(a_position, 1.0) ); 9 | v_color0 = a_color0; 10 | v_texcoord0 = a_texcoord0; 11 | } -------------------------------------------------------------------------------- /examples/assets/shaders/varying.def.sc: -------------------------------------------------------------------------------- 1 | vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0); 2 | vec3 v_normal : NORMAL = vec3(0.0, 0.0, 1.0); 3 | vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0); 4 | vec3 v_pos : TEXCOORD1 = vec3(0.0, 0.0, 0.0); 5 | vec3 v_view : TEXCOORD2 = vec3(0.0, 0.0, 0.0); 6 | 7 | vec3 a_position : POSITION; 8 | vec4 a_color0 : COLOR0; 9 | vec2 a_texcoord0 : TEXCOORD0; 10 | vec3 a_normal : NORMAL; -------------------------------------------------------------------------------- /examples/assets/textures/python_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/assets/textures/python_logo.png -------------------------------------------------------------------------------- /examples/cubes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/cubes/__init__.py -------------------------------------------------------------------------------- /examples/cubes/cubes.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ctypes import Structure, c_float, c_uint32, sizeof, c_bool, c_int 3 | from pathlib import Path 4 | 5 | import numpy as np 6 | 7 | # noinspection PyUnresolvedReferences 8 | from pybgfx import bgfx, ImGui 9 | 10 | from pybgfx.utils.imgui_utils import ImGuiExtra 11 | from pybgfx.utils import as_void_ptr 12 | from pybgfx.utils.shaders_utils import ShaderType, load_shader 13 | from pybgfx.constants import ( 14 | BGFX_CLEAR_COLOR, 15 | BGFX_CLEAR_DEPTH, 16 | BGFX_DEBUG_TEXT, 17 | BGFX_RESET_VSYNC, 18 | BGFX_STATE_WRITE_R, 19 | BGFX_STATE_WRITE_G, 20 | BGFX_STATE_WRITE_B, 21 | BGFX_STATE_WRITE_A, 22 | BGFX_STATE_WRITE_Z, 23 | BGFX_STATE_DEPTH_TEST_LESS, 24 | BGFX_STATE_CULL_CW, 25 | BGFX_STATE_MSAA, 26 | BGFX_STATE_PT_POINTS, 27 | BGFX_STATE_PT_LINES, 28 | BGFX_STATE_PT_TRISTRIP, 29 | BGFX_STATE_PT_LINESTRIP, 30 | ) 31 | from examples.example_window import ExampleWindow 32 | from examples.utils.imgui_utils import show_example_dialog 33 | from examples.utils.matrix_utils import look_at, proj, rotate_xy 34 | from loguru import logger 35 | 36 | logger.enable("bgfx") 37 | 38 | 39 | class PosColorVertex(Structure): 40 | _fields_ = [ 41 | ("m_x", c_float), 42 | ("m_y", c_float), 43 | ("m_z", c_float), 44 | ("m_abgr", c_uint32), 45 | ] 46 | 47 | 48 | num_vertices = 8 49 | 50 | cube_vertices = (PosColorVertex * num_vertices)( 51 | PosColorVertex(-1.0, 1.0, 1.0, 0xFF000000), 52 | PosColorVertex(1.0, 1.0, 1.0, 0xFF0000FF), 53 | PosColorVertex(-1.0, -1.0, 1.0, 0xFF00FF00), 54 | PosColorVertex(1.0, -1.0, 1.0, 0xFF00FFFF), 55 | PosColorVertex(-1.0, 1.0, -1.0, 0xFFFF0000), 56 | PosColorVertex(1.0, 1.0, -1.0, 0xFFFF00FF), 57 | PosColorVertex(-1.0, -1.0, -1.0, 0xFFFFFF00), 58 | PosColorVertex(1.0, -1.0, -1.0, 0xFFFFFFFF), 59 | ) 60 | 61 | 62 | primitives = ( 63 | np.array( 64 | [ 65 | 0, 66 | 1, 67 | 2, # 0 68 | 1, 69 | 3, 70 | 2, 71 | 4, 72 | 6, 73 | 5, # 2 74 | 5, 75 | 6, 76 | 7, 77 | 0, 78 | 2, 79 | 4, # 4 80 | 4, 81 | 2, 82 | 6, 83 | 1, 84 | 5, 85 | 3, # 6 86 | 5, 87 | 7, 88 | 3, 89 | 0, 90 | 4, 91 | 1, # 8 92 | 4, 93 | 5, 94 | 1, 95 | 2, 96 | 3, 97 | 6, # 10 98 | 6, 99 | 3, 100 | 7, 101 | ], 102 | dtype=np.uint16, 103 | ), 104 | np.array([0, 1, 2, 3, 7, 1, 5, 0, 4, 2, 6, 7, 4, 5,], dtype=np.uint16), 105 | np.array( 106 | [0, 1, 0, 2, 0, 4, 1, 3, 1, 5, 2, 3, 2, 6, 3, 7, 4, 5, 4, 6, 5, 7, 6, 7,], 107 | dtype=np.uint16, 108 | ), 109 | np.array([0, 2, 3, 1, 5, 7, 6, 4, 0, 2, 6, 4, 5, 7, 3, 1, 0,], dtype=np.uint16), 110 | np.array([0, 1, 2, 3, 4, 5, 6, 7], dtype=np.uint16), 111 | ) 112 | 113 | bgfx_states = ( 114 | 0, 115 | BGFX_STATE_PT_TRISTRIP, 116 | BGFX_STATE_PT_LINES, 117 | BGFX_STATE_PT_LINESTRIP, 118 | BGFX_STATE_PT_POINTS, 119 | ) 120 | 121 | root_path = Path(__file__).parent.parent / "assets" / "shaders" 122 | 123 | 124 | class Cubes(ExampleWindow): 125 | def __init__(self, width, height, title): 126 | super().__init__(width, height, title) 127 | 128 | self.elapsed_time = 0 129 | self.write_r = c_bool(True) 130 | self.write_g = c_bool(True) 131 | self.write_b = c_bool(True) 132 | self.write_a = c_bool(True) 133 | self.primitive_geometry = c_int(0) 134 | 135 | self.init_conf = bgfx.Init() 136 | self.init_conf.debug = True 137 | self.init_conf.resolution.width = self.width 138 | self.init_conf.resolution.height = self.height 139 | self.init_conf.resolution.reset = BGFX_RESET_VSYNC 140 | 141 | def init(self, platform_data): 142 | bgfx.setPlatformData(platform_data) 143 | bgfx.renderFrame() 144 | bgfx.init(self.init_conf) 145 | bgfx.reset( 146 | self.width, self.height, BGFX_RESET_VSYNC, self.init_conf.resolution.format, 147 | ) 148 | 149 | bgfx.setDebug(BGFX_DEBUG_TEXT) 150 | bgfx.setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF, 1.0, 0) 151 | 152 | self.vertex_layout = bgfx.VertexLayout() 153 | self.vertex_layout.begin().add( 154 | bgfx.Attrib.Position, 3, bgfx.AttribType.Float 155 | ).add(bgfx.Attrib.Color0, 4, bgfx.AttribType.Uint8, True).end() 156 | 157 | # Create static vertex buffer 158 | vb_memory = bgfx.copy( 159 | as_void_ptr(cube_vertices), sizeof(PosColorVertex) * num_vertices 160 | ) 161 | self.vertex_buffer = bgfx.createVertexBuffer(vb_memory, self.vertex_layout) 162 | 163 | self.index_buffers = [] 164 | 165 | for i in range(0, len(primitives)): 166 | ib_memory = bgfx.copy(as_void_ptr(primitives[i]), primitives[i].nbytes) 167 | self.index_buffers.append(bgfx.createIndexBuffer(ib_memory)) 168 | 169 | # Create program from shaders. 170 | self.main_program = bgfx.createProgram( 171 | load_shader( 172 | "cubes.VertexShader.vert", ShaderType.VERTEX, root_path=root_path 173 | ), 174 | load_shader( 175 | "cubes.FragmentShader.frag", ShaderType.FRAGMENT, root_path=root_path 176 | ), 177 | True, 178 | ) 179 | 180 | ImGuiExtra.create() 181 | 182 | def shutdown(self): 183 | ImGuiExtra.destroy() 184 | for index_buffer in self.index_buffers: 185 | bgfx.destroy(index_buffer) 186 | bgfx.destroy(self.vertex_buffer) 187 | bgfx.destroy(self.main_program) 188 | bgfx.shutdown() 189 | 190 | def update(self, dt): 191 | self.elapsed_time += dt 192 | mouse_x, mouse_y, buttons_states = self.get_mouse_state() 193 | ImGuiExtra.begin_frame( 194 | int(mouse_x), int(mouse_y), buttons_states, 0, self.width, self.height 195 | ) 196 | 197 | show_example_dialog() 198 | self._create_imgui_cubes_selection_dialog() 199 | 200 | ImGuiExtra.end_frame() 201 | 202 | at = (c_float * 3)(*[0.0, 0.0, 0.0]) 203 | eye = (c_float * 3)(*[0.0, 0.0, -35.0]) 204 | up = (c_float * 3)(*[0.0, 1.0, 0.0]) 205 | 206 | view = look_at(eye, at, up) 207 | projection = proj(60.0, self.width / self.height, 0.1, 100.0) 208 | 209 | bgfx.setViewTransform(0, as_void_ptr(view), as_void_ptr(projection)) 210 | bgfx.setViewRect(0, 0, 0, self.width, self.height) 211 | 212 | bgfx.touch(0) 213 | 214 | for yy in range(0, 11): 215 | for xx in range(0, 11): 216 | mtx = rotate_xy( 217 | self.elapsed_time + xx * 0.21, self.elapsed_time + yy * 0.37 218 | ) 219 | mtx[3, 0] = -15.0 + xx * 3.0 220 | mtx[3, 1] = -15.0 + yy * 3.0 221 | mtx[3, 2] = 0.0 222 | bgfx.setTransform(as_void_ptr(mtx), 1) 223 | 224 | # Set vertex and index buffer. 225 | bgfx.setVertexBuffer(0, self.vertex_buffer, 0, num_vertices) 226 | bgfx.setIndexBuffer( 227 | self.index_buffers[self.primitive_geometry.value], 228 | 0, 229 | primitives[self.primitive_geometry.value].size, 230 | ) 231 | 232 | bgfx.setState( 233 | bgfx_states[self.primitive_geometry.value] 234 | | (BGFX_STATE_WRITE_R if self.write_r.value else 0) 235 | | (BGFX_STATE_WRITE_G if self.write_g.value else 0) 236 | | (BGFX_STATE_WRITE_B if self.write_b.value else 0) 237 | | (BGFX_STATE_WRITE_A if self.write_a.value else 0) 238 | | BGFX_STATE_WRITE_Z 239 | | BGFX_STATE_DEPTH_TEST_LESS 240 | | BGFX_STATE_CULL_CW 241 | | BGFX_STATE_MSAA, 242 | 0, 243 | ) 244 | 245 | bgfx.submit(0, self.main_program, 0, False) 246 | 247 | bgfx.frame() 248 | 249 | def resize(self, width, height): 250 | bgfx.reset( 251 | self.width, self.height, BGFX_RESET_VSYNC, self.init_conf.resolution.format 252 | ) 253 | 254 | def _create_imgui_cubes_selection_dialog(self): 255 | ImGui.SetNextWindowPos( 256 | ImGui.ImVec2(self.width - self.width / 5.0 - 10.0, 10.0), 257 | ImGui.ImGuiCond_FirstUseEver, 258 | ) 259 | ImGui.SetNextWindowSize( 260 | ImGui.ImVec2(self.width / 5.0, self.height / 3.5), 261 | ImGui.ImGuiCond_FirstUseEver, 262 | ) 263 | ImGui.Begin("Settings") 264 | 265 | ImGui.Checkbox("Write R", self.write_r) 266 | ImGui.Checkbox("Write G", self.write_g) 267 | ImGui.Checkbox("Write B", self.write_b) 268 | ImGui.Checkbox("Write A", self.write_a) 269 | 270 | ImGui.Text("Primitive topology:") 271 | ImGui.Combo( 272 | "", 273 | self.primitive_geometry, 274 | ["Triangle List", "Triangle Strip", "Lines", "Line Strip", "Points"], 275 | 5, 276 | ) 277 | 278 | ImGui.End() 279 | 280 | 281 | if __name__ == "__main__": 282 | cubes = Cubes(1280, 720, "examples/cubes") 283 | cubes.run() 284 | -------------------------------------------------------------------------------- /examples/example_window.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import time 3 | import sys 4 | 5 | # noinspection PyPackageRequirements 6 | import cppyy 7 | import glfw 8 | 9 | # noinspection PyUnresolvedReferences 10 | from pybgfx import bgfx 11 | 12 | from pybgfx.utils import as_void_ptr 13 | 14 | # noinspection PyPackageRequirements,PyProtectedMember 15 | from glfw import _glfw as glfw_native 16 | 17 | 18 | class ExampleWindow(object): 19 | def __init__(self, width, height, title): 20 | self.title = title 21 | self.height = height 22 | self.width = width 23 | self.ctx = None 24 | self.window = None 25 | 26 | def init(self, platform_data): 27 | pass 28 | 29 | def shutdown(self): 30 | pass 31 | 32 | def update(self, dt): 33 | pass 34 | 35 | def resize(self, width, height): 36 | pass 37 | 38 | def get_mouse_state(self): 39 | mouse_x, mouse_y = glfw.get_cursor_pos(self.window) 40 | state_mbl = glfw.get_mouse_button(self.window, glfw.MOUSE_BUTTON_LEFT) 41 | state_mbm = glfw.get_mouse_button(self.window, glfw.MOUSE_BUTTON_MIDDLE) 42 | state_mbr = glfw.get_mouse_button(self.window, glfw.MOUSE_BUTTON_RIGHT) 43 | 44 | return ( 45 | mouse_x, 46 | mouse_y, 47 | 1 48 | if state_mbl == glfw.PRESS 49 | else 0 | 1 50 | if state_mbm == glfw.PRESS 51 | else 0 | 1 52 | if state_mbr == glfw.PRESS 53 | else 0, 54 | ) 55 | 56 | # noinspection PyProtectedMember 57 | def run(self): 58 | glfw_native.glfwCreateWindow.argtypes = [ 59 | ctypes.c_int, 60 | ctypes.c_int, 61 | ctypes.c_char_p, 62 | ] 63 | glfw_native.glfwCreateWindow.restype = ctypes.POINTER(glfw._GLFWwindow) 64 | glfw_native.glfwMakeContextCurrent.argtypes = [ctypes.POINTER(glfw._GLFWwindow)] 65 | glfw_native.glfwWindowShouldClose.argtypes = [ctypes.POINTER(glfw._GLFWwindow)] 66 | glfw_native.glfwWindowShouldClose.restype = ctypes.c_int 67 | 68 | glfw.init() 69 | 70 | glfw.window_hint(glfw.CLIENT_API, glfw.NO_API) 71 | 72 | self.window = glfw.create_window( 73 | self.width, self.height, self.title, None, None 74 | ) 75 | 76 | glfw.set_window_size_callback(self.window, self._handle_window_resize) 77 | 78 | handle, display = None, None 79 | 80 | if sys.platform == "darwin": 81 | handle = glfw.get_cocoa_window(self.window) 82 | elif sys.platform == "win32": 83 | handle = glfw.get_win32_window(self.window) 84 | elif sys.platform == "linux": 85 | handle = glfw.get_x11_window(self.window) 86 | display = glfw.get_x11_display() 87 | 88 | data = bgfx.PlatformData() 89 | data.ndt = as_void_ptr(display) if display else cppyy.nullptr 90 | data.nwh = as_void_ptr(handle) 91 | data.context = cppyy.nullptr 92 | data.backBuffer = cppyy.nullptr 93 | data.backBufferDS = cppyy.nullptr 94 | 95 | self.init(data) 96 | 97 | last_time = None 98 | 99 | while not glfw.window_should_close(self.window): 100 | glfw.poll_events() 101 | 102 | now = time.perf_counter() 103 | if not last_time: 104 | last_time = now 105 | 106 | frame_time = now - last_time 107 | last_time = now 108 | 109 | self.update(frame_time) 110 | 111 | self.shutdown() 112 | glfw.destroy_window(self.window) 113 | glfw.terminate() 114 | 115 | def _handle_window_resize(self, window, width, height): 116 | self.width = width 117 | self.height = height 118 | 119 | self.resize(width, height) 120 | -------------------------------------------------------------------------------- /examples/helloworld/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/helloworld/__init__.py -------------------------------------------------------------------------------- /examples/helloworld/helloworld.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # noinspection PyUnresolvedReferences 4 | from pybgfx import bgfx 5 | from pybgfx.utils.imgui_utils import ImGuiExtra 6 | 7 | from pybgfx.constants import ( 8 | BGFX_CLEAR_COLOR, 9 | BGFX_CLEAR_DEPTH, 10 | BGFX_DEBUG_TEXT, 11 | BGFX_RESET_VSYNC, 12 | ) 13 | from examples.example_window import ExampleWindow 14 | from examples.helloworld import python_image 15 | 16 | from examples.utils.imgui_utils import show_example_dialog 17 | 18 | 19 | class HelloWorld(ExampleWindow): 20 | def __init__(self, width, height, title): 21 | super().__init__(width, height, title) 22 | 23 | self.init_conf = bgfx.Init() 24 | self.init_conf.debug = True 25 | self.init_conf.resolution.width = self.width 26 | self.init_conf.resolution.height = self.height 27 | self.init_conf.resolution.reset = BGFX_RESET_VSYNC 28 | 29 | def init(self, platform_data): 30 | bgfx.renderFrame() 31 | bgfx.setPlatformData(platform_data) 32 | bgfx.init(self.init_conf) 33 | 34 | bgfx.setDebug(BGFX_DEBUG_TEXT) 35 | bgfx.setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF, 1.0, 0) 36 | ImGuiExtra.create() 37 | 38 | def shutdown(self): 39 | ImGuiExtra.destroy() 40 | bgfx.shutdown() 41 | 42 | def update(self, dt): 43 | mouse_x, mouse_y, buttons_states = self.get_mouse_state() 44 | ImGuiExtra.begin_frame( 45 | int(mouse_x), int(mouse_y), buttons_states, 0, self.width, self.height 46 | ) 47 | 48 | show_example_dialog() 49 | 50 | ImGuiExtra.end_frame() 51 | 52 | bgfx.setViewRect(0, 0, 0, self.width, self.height) 53 | bgfx.touch(0) 54 | bgfx.dbgTextClear(0, False) 55 | bgfx.dbgTextImage( 56 | int(max(self.width / 2 / 8, 20)) - 20, 57 | int(max(self.height / 2 / 16, 6)) - 6, 58 | 40, 59 | 12, 60 | python_image.logo, 61 | 160, 62 | ) 63 | 64 | stats = bgfx.getStats() 65 | 66 | bgfx.dbgTextPrintf( 67 | 1, 68 | 1, 69 | 0x0F, 70 | "Color can be changed with ANSI \x1b[9;me\x1b[10;ms\x1b[11;mc\x1b[12;ma\x1b[13;mp\x1b[14;me\x1b[0m code too.", 71 | ) 72 | bgfx.dbgTextPrintf( 73 | 80, 74 | 1, 75 | 0x0F, 76 | "\x1b[;0m \x1b[;1m \x1b[; 2m \x1b[; 3m \x1b[; 4m \x1b[; 5m \x1b[; 6m \x1b[; 7m \x1b[0m", 77 | ) 78 | bgfx.dbgTextPrintf( 79 | 80, 80 | 2, 81 | 0x0F, 82 | "\x1b[;8m \x1b[;9m \x1b[;10m \x1b[;11m \x1b[;12m \x1b[;13m \x1b[;14m \x1b[;15m \x1b[0m", 83 | ) 84 | bgfx.dbgTextPrintf( 85 | 1, 86 | 2, 87 | 0x0F, 88 | f"Backbuffer {stats.width}W x {stats.height}H in pixels, debug text {stats.textWidth}W x {stats.textHeight}H in characters.", 89 | ) 90 | 91 | bgfx.frame() 92 | 93 | def resize(self, width, height): 94 | bgfx.reset( 95 | self.width, self.height, BGFX_RESET_VSYNC, self.init_conf.resolution.format 96 | ) 97 | 98 | 99 | if __name__ == "__main__": 100 | test = HelloWorld(1280, 720, "examples/helloworld") 101 | test.run() 102 | -------------------------------------------------------------------------------- /examples/helloworld/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/helloworld/screenshot.png -------------------------------------------------------------------------------- /examples/mesh/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/mesh/__init__.py -------------------------------------------------------------------------------- /examples/mesh/mesh.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ctypes import c_float 3 | from pathlib import Path 4 | 5 | from loguru import logger 6 | 7 | # noinspection PyUnresolvedReferences 8 | from pybgfx import bgfx, ImGui 9 | 10 | from pybgfx.utils.imgui_utils import ImGuiExtra 11 | from pybgfx.utils import as_void_ptr 12 | from pybgfx.utils.mesh_utils import Mesh 13 | from pybgfx.utils.shaders_utils import ShaderType, load_shader 14 | from pybgfx.constants import ( 15 | BGFX_CLEAR_COLOR, 16 | BGFX_CLEAR_DEPTH, 17 | BGFX_DEBUG_TEXT, 18 | BGFX_RESET_VSYNC, 19 | ) 20 | from examples.example_window import ExampleWindow 21 | from examples.utils.imgui_utils import show_example_dialog 22 | from examples.utils.matrix_utils import look_at, proj, rotate_xy 23 | 24 | logger.enable("bgfx") 25 | 26 | root_path = Path(__file__).parent.parent / "assets" / "shaders" 27 | 28 | 29 | class MeshExample(ExampleWindow): 30 | def __init__(self, width, height, title): 31 | super().__init__(width, height, title) 32 | 33 | self.elapsed_time = 0 34 | 35 | self.init_conf = bgfx.Init() 36 | self.init_conf.debug = True 37 | self.init_conf.resolution.width = self.width 38 | self.init_conf.resolution.height = self.height 39 | self.init_conf.resolution.reset = BGFX_RESET_VSYNC 40 | 41 | def init(self, platform_data): 42 | bgfx.setPlatformData(platform_data) 43 | bgfx.renderFrame() 44 | bgfx.init(self.init_conf) 45 | bgfx.reset( 46 | self.width, self.height, BGFX_RESET_VSYNC, self.init_conf.resolution.format, 47 | ) 48 | 49 | bgfx.setDebug(BGFX_DEBUG_TEXT) 50 | bgfx.setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF, 1.0, 0) 51 | 52 | # Create time uniform 53 | self.time_uniform = bgfx.createUniform("u_time", bgfx.UniformType.Vec4) 54 | 55 | # Load Bunny mesh 56 | self.mesh = Mesh( 57 | ( 58 | Path(__file__).parent.parent / "assets" / "meshes" / "bunny.bin" 59 | ).absolute() 60 | ) 61 | 62 | # Create program from shaders. 63 | self.main_program = bgfx.createProgram( 64 | load_shader( 65 | "mesh.VertexShader.vert", ShaderType.VERTEX, root_path=root_path 66 | ), 67 | load_shader( 68 | "mesh.FragmentShader.frag", ShaderType.FRAGMENT, root_path=root_path 69 | ), 70 | True, 71 | ) 72 | 73 | ImGuiExtra.create() 74 | 75 | def shutdown(self): 76 | ImGuiExtra.destroy() 77 | self.mesh.destroy() 78 | bgfx.destroy(self.main_program) 79 | bgfx.destroy(self.time_uniform) 80 | bgfx.shutdown() 81 | 82 | def update(self, dt): 83 | self.elapsed_time += dt 84 | mouse_x, mouse_y, buttons_states = self.get_mouse_state() 85 | ImGuiExtra.begin_frame( 86 | int(mouse_x), int(mouse_y), buttons_states, 0, self.width, self.height 87 | ) 88 | 89 | show_example_dialog() 90 | 91 | ImGuiExtra.end_frame() 92 | 93 | at = (c_float * 3)(*[0.0, 1.0, 0.0]) 94 | eye = (c_float * 3)(*[0.0, 1.0, -2.5]) 95 | up = (c_float * 3)(*[0.0, 1.0, 0.0]) 96 | 97 | view = look_at(eye, at, up) 98 | projection = proj(60.0, self.width / self.height, 0.1, 100.0) 99 | 100 | bgfx.setViewTransform(0, as_void_ptr(view), as_void_ptr(projection)) 101 | bgfx.setViewRect(0, 0, 0, self.width, self.height) 102 | 103 | bgfx.touch(0) 104 | 105 | mtx = rotate_xy(0, self.elapsed_time * 0.37) 106 | 107 | bgfx.setUniform( 108 | self.time_uniform, 109 | as_void_ptr((c_float * 4)(self.elapsed_time, 0.0, 0.0, 0.0)), 110 | ) 111 | 112 | self.mesh.submit(0, self.main_program, mtx) 113 | 114 | bgfx.frame() 115 | 116 | def resize(self, width, height): 117 | bgfx.reset( 118 | self.width, self.height, BGFX_RESET_VSYNC, self.init_conf.resolution.format 119 | ) 120 | 121 | 122 | if __name__ == "__main__": 123 | textures = MeshExample(1280, 720, "examples/mesh") 124 | textures.run() 125 | -------------------------------------------------------------------------------- /examples/textures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/textures/__init__.py -------------------------------------------------------------------------------- /examples/textures/textures.py: -------------------------------------------------------------------------------- 1 | import os 2 | from ctypes import Structure, c_float, c_uint32, sizeof 3 | from pathlib import Path 4 | 5 | import numpy as np 6 | from PIL import Image 7 | from loguru import logger 8 | 9 | # noinspection PyUnresolvedReferences 10 | from pybgfx import bgfx, ImGui 11 | 12 | from pybgfx.utils.imgui_utils import ImGuiExtra 13 | from pybgfx.utils import as_void_ptr 14 | from pybgfx.utils.shaders_utils import ShaderType, load_shader 15 | from pybgfx.constants import ( 16 | BGFX_CLEAR_COLOR, 17 | BGFX_CLEAR_DEPTH, 18 | BGFX_DEBUG_TEXT, 19 | BGFX_RESET_VSYNC, 20 | BGFX_STATE_WRITE_A, 21 | BGFX_STATE_WRITE_Z, 22 | BGFX_STATE_DEPTH_TEST_LESS, 23 | BGFX_STATE_MSAA, 24 | BGFX_TEXTURE_RT, 25 | BGFX_STATE_WRITE_RGB, 26 | ) 27 | from examples.example_window import ExampleWindow 28 | from examples.utils.imgui_utils import show_example_dialog 29 | from examples.utils.matrix_utils import look_at, proj, rotate_xy 30 | 31 | logger.enable("bgfx") 32 | 33 | 34 | class PosColorTexVertex(Structure): 35 | _fields_ = [ 36 | ("m_x", c_float), 37 | ("m_y", c_float), 38 | ("m_z", c_float), 39 | ("m_abgr", c_uint32), 40 | ("m_tex_u", c_float), 41 | ("m_tex_v", c_float), 42 | ] 43 | 44 | 45 | num_vertices = 24 46 | 47 | cube_vertices = (PosColorTexVertex * 24)( 48 | PosColorTexVertex(-1.0, 1.0, 1.0, 0xFF000000, 0, 0), 49 | PosColorTexVertex(1.0, 1.0, 1.0, 0xFF000000, 1, 0), 50 | PosColorTexVertex(-1.0, -1.0, 1.0, 0xFF000000, 0, 1), 51 | PosColorTexVertex(1.0, -1.0, 1.0, 0xFF000000, 1, 1), 52 | PosColorTexVertex(-1.0, 1.0, -1.0, 0xFF000000, 0, 0), 53 | PosColorTexVertex(1.0, 1.0, -1.0, 0xFF000000, 1, 0), 54 | PosColorTexVertex(-1.0, -1.0, -1.0, 0xFF000000, 0, 1), 55 | PosColorTexVertex(1.0, -1.0, -1.0, 0xFF000000, 1, 1), 56 | PosColorTexVertex(-1.0, 1.0, 1.0, 0xFF000000, 0, 0), 57 | PosColorTexVertex(1.0, 1.0, 1.0, 0xFF000000, 1, 0), 58 | PosColorTexVertex(-1.0, 1.0, -1.0, 0xFF000000, 0, 1), 59 | PosColorTexVertex(1.0, 1.0, -1.0, 0xFF000000, 1, 1), 60 | PosColorTexVertex(-1.0, -1.0, 1.0, 0xFF000000, 0, 0), 61 | PosColorTexVertex(1.0, -1.0, 1.0, 0xFF000000, 1, 0), 62 | PosColorTexVertex(-1.0, -1.0, -1.0, 0xFF000000, 0, 1), 63 | PosColorTexVertex(1.0, -1.0, -1.0, 0xFF000000, 1, 1), 64 | PosColorTexVertex(1.0, -1.0, 1.0, 0xFF000000, 0, 0), 65 | PosColorTexVertex(1.0, 1.0, 1.0, 0xFF000000, 1, 0), 66 | PosColorTexVertex(1.0, -1.0, -1.0, 0xFF000000, 0, 1), 67 | PosColorTexVertex(1.0, 1.0, -1.0, 0xFF000000, 1, 1), 68 | PosColorTexVertex(-1.0, -1.0, 1.0, 0xFF000000, 0, 0), 69 | PosColorTexVertex(-1.0, 1.0, 1.0, 0xFF000000, 1, 0), 70 | PosColorTexVertex(-1.0, -1.0, -1.0, 0xFF000000, 0, 1), 71 | PosColorTexVertex(-1.0, 1.0, -1.0, 0xFF000000, 1, 1), 72 | ) 73 | 74 | cube_indices = np.array( 75 | [ 76 | 0, 77 | 2, 78 | 1, 79 | 1, 80 | 2, 81 | 3, 82 | 4, 83 | 5, 84 | 6, 85 | 5, 86 | 7, 87 | 6, 88 | 8, 89 | 10, 90 | 9, 91 | 9, 92 | 10, 93 | 11, 94 | 12, 95 | 13, 96 | 14, 97 | 13, 98 | 15, 99 | 14, 100 | 16, 101 | 18, 102 | 17, 103 | 17, 104 | 18, 105 | 19, 106 | 20, 107 | 21, 108 | 22, 109 | 21, 110 | 23, 111 | 22, 112 | ], 113 | dtype=np.uint16, 114 | ) 115 | 116 | root_path = Path(__file__).parent.parent / "assets" / "shaders" 117 | 118 | 119 | class Textures(ExampleWindow): 120 | def __init__(self, width, height, title): 121 | super().__init__(width, height, title) 122 | 123 | self.elapsed_time = 0 124 | 125 | self.init_conf = bgfx.Init() 126 | self.init_conf.debug = True 127 | self.init_conf.resolution.width = self.width 128 | self.init_conf.resolution.height = self.height 129 | self.init_conf.resolution.reset = BGFX_RESET_VSYNC 130 | 131 | def init(self, platform_data): 132 | bgfx.setPlatformData(platform_data) 133 | bgfx.renderFrame() 134 | bgfx.init(self.init_conf) 135 | bgfx.reset( 136 | self.width, self.height, BGFX_RESET_VSYNC, self.init_conf.resolution.format, 137 | ) 138 | 139 | bgfx.setDebug(BGFX_DEBUG_TEXT) 140 | bgfx.setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x443355FF, 1.0, 0) 141 | 142 | self.vertex_layout = bgfx.VertexLayout() 143 | self.vertex_layout.begin().add( 144 | bgfx.Attrib.Position, 3, bgfx.AttribType.Float 145 | ).add(bgfx.Attrib.Color0, 4, bgfx.AttribType.Uint8, True).add( 146 | bgfx.Attrib.TexCoord0, 2, bgfx.AttribType.Float 147 | ).end() 148 | 149 | # Create static vertex buffer 150 | vb_memory = bgfx.copy( 151 | as_void_ptr(cube_vertices), sizeof(PosColorTexVertex) * num_vertices 152 | ) 153 | self.vertex_buffer = bgfx.createVertexBuffer(vb_memory, self.vertex_layout) 154 | 155 | # Create index buffer 156 | ib_memory = bgfx.copy(as_void_ptr(cube_indices), cube_indices.nbytes) 157 | self.index_buffer = bgfx.createIndexBuffer(ib_memory) 158 | 159 | # Create texture uniform 160 | self.texture_uniform = bgfx.createUniform("s_tex", bgfx.UniformType.Sampler) 161 | 162 | # Load the image using PIL and make the texture 163 | logo = Image.open( 164 | Path(__file__).parent.parent / "assets" / "textures" / "python_logo.png" 165 | ) 166 | image_bytes = logo.tobytes() 167 | logo_memory = bgfx.copy(as_void_ptr(image_bytes), len(image_bytes)) 168 | self.logo_texture = bgfx.createTexture2D( 169 | logo.width, 170 | logo.height, 171 | False, 172 | 1, 173 | bgfx.TextureFormat.RGBA8, 174 | BGFX_TEXTURE_RT, 175 | logo_memory, 176 | ) 177 | 178 | # Create program from shaders. 179 | self.main_program = bgfx.createProgram( 180 | load_shader( 181 | "textures.VertexShader.vert", ShaderType.VERTEX, root_path=root_path 182 | ), 183 | load_shader( 184 | "textures.FragmentShader.frag", ShaderType.FRAGMENT, root_path=root_path 185 | ), 186 | True, 187 | ) 188 | 189 | ImGuiExtra.create() 190 | 191 | def shutdown(self): 192 | ImGuiExtra.destroy() 193 | bgfx.destroy(self.index_buffer) 194 | bgfx.destroy(self.vertex_buffer) 195 | bgfx.destroy(self.texture_uniform) 196 | bgfx.destroy(self.logo_texture) 197 | bgfx.destroy(self.main_program) 198 | bgfx.shutdown() 199 | 200 | def update(self, dt): 201 | self.elapsed_time += dt 202 | mouse_x, mouse_y, buttons_states = self.get_mouse_state() 203 | ImGuiExtra.begin_frame( 204 | int(mouse_x), int(mouse_y), buttons_states, 0, self.width, self.height 205 | ) 206 | 207 | show_example_dialog() 208 | 209 | ImGuiExtra.end_frame() 210 | 211 | at = (c_float * 3)(*[0.0, 0.0, 0.0]) 212 | eye = (c_float * 3)(*[0.0, 0.0, -15.0]) 213 | up = (c_float * 3)(*[0.0, 1.0, 0.0]) 214 | 215 | view = look_at(eye, at, up) 216 | projection = proj(60.0, self.width / self.height, 0.1, 100.0) 217 | 218 | bgfx.setViewTransform(0, as_void_ptr(view), as_void_ptr(projection)) 219 | bgfx.setViewRect(0, 0, 0, self.width, self.height) 220 | 221 | bgfx.touch(0) 222 | 223 | # Set the texture 224 | bgfx.setTexture(0, self.texture_uniform, self.logo_texture) 225 | 226 | for yy in range(-2, 2): 227 | for xx in range(-2, 2): 228 | mtx = rotate_xy( 229 | self.elapsed_time + xx * 0.51, self.elapsed_time + yy * 0.27 230 | ) 231 | mtx[3, 0] = 4 + xx * 3.5 232 | mtx[3, 1] = 2 + yy * 3.5 233 | mtx[3, 2] = 0 234 | bgfx.setTransform(as_void_ptr(mtx), 1) 235 | 236 | # Set vertex and index buffer. 237 | bgfx.setVertexBuffer(0, self.vertex_buffer, 0, num_vertices) 238 | bgfx.setIndexBuffer(self.index_buffer, 0, cube_indices.size) 239 | 240 | bgfx.setState( 241 | 0 242 | | BGFX_STATE_WRITE_RGB 243 | | BGFX_STATE_WRITE_A 244 | | BGFX_STATE_WRITE_Z 245 | | BGFX_STATE_DEPTH_TEST_LESS 246 | | BGFX_STATE_MSAA, 247 | 0, 248 | ) 249 | 250 | bgfx.submit(0, self.main_program, 0, False) 251 | 252 | bgfx.frame() 253 | 254 | def resize(self, width, height): 255 | bgfx.reset( 256 | self.width, self.height, BGFX_RESET_VSYNC, self.init_conf.resolution.format 257 | ) 258 | 259 | 260 | if __name__ == "__main__": 261 | textures = Textures(1280, 720, "examples/textures") 262 | textures.run() 263 | -------------------------------------------------------------------------------- /examples/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/examples/utils/__init__.py -------------------------------------------------------------------------------- /examples/utils/imgui_utils.py: -------------------------------------------------------------------------------- 1 | from array import array 2 | 3 | # noinspection PyUnresolvedReferences 4 | from pybgfx import bgfx, ImGui 5 | 6 | 7 | class SampleData: 8 | m_values = [] 9 | m_offset = 0 10 | m_min = 0.0 11 | m_max = 0.0 12 | m_avg = 0.0 13 | 14 | def __init__(self): 15 | self.reset() 16 | 17 | def reset(self): 18 | self.m_values = [0.0] * 100 19 | self.m_offset = 0 20 | self.m_min = 0.0 21 | self.m_max = 0.0 22 | self.m_avg = 0.0 23 | 24 | def push_sample(self, value: float): 25 | self.m_values[self.m_offset] = value 26 | self.m_offset = (self.m_offset + 1) % 100 27 | 28 | min_val = float("inf") 29 | max_val = float("-inf") 30 | avg_val = 0.0 31 | 32 | for val in self.m_values: 33 | min_val = min(min_val, val) 34 | max_val = max(max_val, val) 35 | avg_val += val 36 | 37 | self.m_min = min_val 38 | self.m_max = max_val 39 | self.m_avg = avg_val / 100.0 40 | 41 | 42 | def bar(width, max_width, height, color): 43 | style = ImGui.GetStyle() 44 | 45 | hovered_color = ImGui.ImVec4( 46 | color.x + color.x * 0.1, 47 | color.y + color.y * 0.1, 48 | color.z + color.z * 0.1, 49 | color.w + color.w * 0.1, 50 | ) 51 | 52 | ImGui.PushStyleColor(ImGui.ImGuiCol_Button, color) 53 | ImGui.PushStyleColor(ImGui.ImGuiCol_ButtonHovered, hovered_color) 54 | ImGui.PushStyleColor(ImGui.ImGuiCol_ButtonActive, color) 55 | ImGui.PushStyleVar(ImGui.ImGuiStyleVar_FrameRounding, 0.0) 56 | ImGui.PushStyleVar( 57 | ImGui.ImGuiStyleVar_ItemSpacing, ImGui.ImVec2(0.0, style.ItemSpacing.y) 58 | ) 59 | 60 | item_hovered = False 61 | 62 | ImGui.Button("", ImGui.ImVec2(width, height)) 63 | item_hovered |= ImGui.IsItemHovered(0) 64 | 65 | ImGui.SameLine() 66 | ImGui.InvisibleButton("", ImGui.ImVec2(max(1.0, max_width - width), height), 0) 67 | item_hovered |= ImGui.IsItemHovered(0) 68 | 69 | ImGui.PopStyleVar(2) 70 | ImGui.PopStyleColor(3) 71 | 72 | return item_hovered 73 | 74 | 75 | s_resourceColor = ImGui.ImVec4(0.5, 0.5, 0.5, 1.0) 76 | s_frame_time = SampleData() 77 | 78 | 79 | def resource_bar(name, tooltip, num, _max, max_width, height): 80 | item_hovered = False 81 | 82 | ImGui.Text(f"{name}: {num:4d} / {_max:4d}") 83 | item_hovered |= ImGui.IsItemHovered(0) 84 | ImGui.SameLine() 85 | 86 | percentage = float(num) / float(_max) 87 | 88 | item_hovered |= bar( 89 | max(1.0, percentage * max_width), max_width, height, s_resourceColor 90 | ) 91 | ImGui.SameLine() 92 | 93 | ImGui.Text(f"{(percentage * 100.0):5.2f}%") 94 | 95 | if item_hovered: 96 | ImGui.SetTooltip(f"{tooltip} {(percentage * 100.0):5.2f}%") 97 | 98 | 99 | def show_example_dialog(): 100 | ImGui.SetNextWindowPos(ImGui.ImVec2(10.0, 70.0), ImGui.ImGuiCond_FirstUseEver) 101 | ImGui.SetNextWindowSize(ImGui.ImVec2(300.0, 500.0), ImGui.ImGuiCond_FirstUseEver) 102 | 103 | ImGui.Begin("\uf080 Statistics") 104 | renderer_name = bgfx.getRendererName(bgfx.getRendererType()) 105 | ImGui.TextWrapped("Current renderer: {}".format(renderer_name)) 106 | ImGui.Separator() 107 | 108 | stats = bgfx.getStats() 109 | to_ms_cpu = 1000.0 / stats.cpuTimerFreq 110 | to_ms_gpu = 1000.0 / stats.gpuTimerFreq 111 | frame_ms = max(float(stats.cpuTimeEnd - stats.cpuTimeBegin), 1.0e-9) 112 | 113 | s_frame_time.push_sample(frame_ms * to_ms_cpu) 114 | 115 | frame_text_overlay = f"\uf063{s_frame_time.m_min:7.3f}ms, \uf062{s_frame_time.m_max:7.3f}ms\nAvg: {s_frame_time.m_avg:7.3f}ms, {(stats.cpuTimerFreq / frame_ms):6.2f} FPS" 116 | ImGui.PushStyleColor( 117 | ImGui.ImGuiCol_PlotHistogram, ImGui.ImVec4(0.0, 0.5, 0.15, 1.0) 118 | ) 119 | ImGui.PushItemWidth(-1) 120 | ImGui.PlotHistogram( 121 | "", 122 | array("f", s_frame_time.m_values), 123 | 100, 124 | s_frame_time.m_offset, 125 | frame_text_overlay, 126 | 0.0, 127 | 60.0, 128 | ImGui.ImVec2(0.0, 45.0), 129 | ) 130 | ImGui.PopItemWidth() 131 | ImGui.PopStyleColor() 132 | 133 | ImGui.Text( 134 | f"Submit CPU {(stats.cpuTimeEnd - stats.cpuTimeBegin) * to_ms_cpu:.3f}, GPU {(stats.gpuTimeEnd - stats.gpuTimeBegin) * to_ms_gpu:.3f} (L: {stats.maxGpuLatency})" 135 | ) 136 | 137 | if stats.gpuMemoryMax > 0: 138 | ImGui.Text(f"GPU mem: {stats.gpuMemoryUsed} / {stats.gpuMemoryMax}") 139 | 140 | if ImGui.CollapsingHeader("\uf12e Resources", ImGui.ImGuiTreeNodeFlags_DefaultOpen): 141 | caps = bgfx.getCaps() 142 | item_height = ImGui.GetTextLineHeightWithSpacing() 143 | max_width = 90.0 144 | ImGui.PushFont(ImGui.Font.Mono) 145 | ImGui.Text("Res: Num / Max") 146 | resource_bar( 147 | "DIB", 148 | "Dynamic index buffers", 149 | stats.numDynamicIndexBuffers, 150 | caps.limits.maxDynamicIndexBuffers, 151 | max_width, 152 | item_height, 153 | ) 154 | resource_bar( 155 | "DVB", 156 | "Dynamic vertex buffers", 157 | stats.numDynamicVertexBuffers, 158 | caps.limits.maxDynamicVertexBuffers, 159 | max_width, 160 | item_height, 161 | ) 162 | resource_bar( 163 | " FB", 164 | "Frame buffers", 165 | stats.numFrameBuffers, 166 | caps.limits.maxFrameBuffers, 167 | max_width, 168 | item_height, 169 | ) 170 | resource_bar( 171 | " IB", 172 | "Index buffers", 173 | stats.numIndexBuffers, 174 | caps.limits.maxIndexBuffers, 175 | max_width, 176 | item_height, 177 | ) 178 | resource_bar( 179 | " OQ", 180 | "Occlusion queries", 181 | stats.numOcclusionQueries, 182 | caps.limits.maxOcclusionQueries, 183 | max_width, 184 | item_height, 185 | ) 186 | resource_bar( 187 | " P", 188 | "Programs", 189 | stats.numPrograms, 190 | caps.limits.maxPrograms, 191 | max_width, 192 | item_height, 193 | ) 194 | resource_bar( 195 | " S", 196 | "Shaders", 197 | stats.numShaders, 198 | caps.limits.maxShaders, 199 | max_width, 200 | item_height, 201 | ) 202 | resource_bar( 203 | " T", 204 | "Textures", 205 | stats.numTextures, 206 | caps.limits.maxTextures, 207 | max_width, 208 | item_height, 209 | ) 210 | resource_bar( 211 | " U", 212 | "Uniforms", 213 | stats.numUniforms, 214 | caps.limits.maxUniforms, 215 | max_width, 216 | item_height, 217 | ) 218 | resource_bar( 219 | " VB", 220 | "Vertex buffers", 221 | stats.numVertexBuffers, 222 | caps.limits.maxVertexBuffers, 223 | max_width, 224 | item_height, 225 | ) 226 | resource_bar( 227 | " VL", 228 | "Vertex layouts", 229 | stats.numVertexLayouts, 230 | caps.limits.maxVertexLayouts, 231 | max_width, 232 | item_height, 233 | ) 234 | ImGui.PopFont() 235 | 236 | ImGui.End() 237 | -------------------------------------------------------------------------------- /examples/utils/matrix_utils.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import math 3 | 4 | import numpy as np 5 | 6 | 7 | def sub(v1, v2): 8 | return [v1[0] - v2[0], v1[1] - v2[1], v1[2] - v2[2]] 9 | 10 | 11 | def cross(v1, v2): 12 | v1x = v1[0] 13 | v1y = v1[1] 14 | v1z = v1[2] 15 | v2x = v2[0] 16 | v2y = v2[1] 17 | v2z = v2[2] 18 | return [ 19 | (v1y * v2z) - (v1z * v2y), 20 | (v1z * v2x) - (v1x * v2z), 21 | (v1x * v2y) - (v1y * v2x), 22 | ] 23 | 24 | 25 | def length(vec3): 26 | return math.sqrt(vec3[0] * vec3[0] + vec3[1] * vec3[1] + vec3[2] * vec3[2]) 27 | 28 | 29 | def normalize(vec3): 30 | l = length(vec3) 31 | return [vec3[0] / l, vec3[1] / l, vec3[2] / l] 32 | 33 | 34 | def look_at(eye, at, up): 35 | """Constructs look-at matrix for right handed coordinate system.""" 36 | view = normalize(sub(at, eye)) 37 | right = normalize(np.cross(up, view)) 38 | 39 | up = np.cross(view, right) 40 | 41 | view = (ctypes.c_float * 16)( 42 | *[ 43 | right[0], 44 | up[0], 45 | view[0], 46 | 0.0, 47 | right[1], 48 | up[1], 49 | view[1], 50 | 0.0, 51 | right[2], 52 | up[2], 53 | view[2], 54 | 0.0, 55 | -np.dot(right, eye), 56 | -np.dot(up, eye), 57 | -np.dot(view, eye), 58 | 1.0, 59 | ] 60 | ) 61 | 62 | return view 63 | 64 | 65 | def proj(fov_y, aspect, near, far): 66 | height = 1.0 / math.tan(math.radians(fov_y) * 0.5) 67 | width = height * 1.0 / aspect 68 | diff = far - near 69 | aa = far / diff 70 | bb = near * aa 71 | 72 | return (ctypes.c_float * 16)( 73 | *[ 74 | width, 75 | 0.0, 76 | 0.0, 77 | 0.0, 78 | 0.0, 79 | height, 80 | 0.0, 81 | 0.0, 82 | 0.0, 83 | 0.0, 84 | aa, 85 | 1.0, 86 | 0.0, 87 | 0.0, 88 | -bb, 89 | 0.0, 90 | ] 91 | ) 92 | 93 | 94 | def ortho(left, right, bottom, top, near, far): 95 | aa = 2.0 / (right - left) 96 | bb = 2.0 / (top - bottom) 97 | cc = 1.0 / (far - near) 98 | dd = (left + right) / (left - right) 99 | ee = (top + bottom) / (bottom - top) 100 | ff = near / (near - far) 101 | 102 | return (ctypes.c_float * 16)( 103 | *[aa, 0.0, 0.0, 0.0, 0.0, bb, 0.0, 0.0, 0.0, 0.0, cc, 0.0, dd, ee, ff, 1.0] 104 | ) 105 | 106 | 107 | def rotate_xy(rot_x, rot_y): 108 | sx, cx = np.sin(rot_x), np.cos(rot_x) 109 | sy, cy = np.sin(rot_y), np.cos(rot_y) 110 | 111 | return np.array( 112 | ( 113 | (cy, 0.0, sy, 0.0), 114 | (sx * sy, cx, -sx * cy, 0.0), 115 | (-cx * sy, sx, cx * cy, 0.0), 116 | (0.0, 0.0, 0.0, 1.0), 117 | ), 118 | dtype=np.float32, 119 | ) 120 | -------------------------------------------------------------------------------- /noxfile.py: -------------------------------------------------------------------------------- 1 | import tempfile 2 | 3 | import nox 4 | 5 | locations = "pybgfx", "tests", "examples", "noxfile.py" 6 | 7 | 8 | def install_with_constraints(session, *args, **kwargs): 9 | with tempfile.NamedTemporaryFile() as requirements: 10 | session.run( 11 | "poetry", 12 | "export", 13 | "--dev", 14 | "--format=requirements.txt", 15 | "--without-hashes", 16 | f"--output={requirements.name}", 17 | external=True, 18 | ) 19 | session.install(f"--constraint={requirements.name}", *args, **kwargs) 20 | 21 | 22 | @nox.session 23 | def black(session): 24 | args = session.posargs or locations 25 | install_with_constraints(session, "black") 26 | session.run("black", *args) 27 | 28 | 29 | @nox.session 30 | def lint(session): 31 | args = session.posargs or locations 32 | install_with_constraints( 33 | session, 34 | "flake8", 35 | "flake8-bandit", 36 | "flake8-black", 37 | "flake8-bugbear", 38 | "flake8-import-order", 39 | ) 40 | session.run("flake8", *args) 41 | 42 | 43 | @nox.session 44 | def safety(session): 45 | with tempfile.NamedTemporaryFile() as requirements: 46 | session.run( 47 | "poetry", 48 | "export", 49 | "--dev", 50 | "--format=requirements.txt", 51 | "--without-hashes", 52 | f"--output={requirements.name}", 53 | external=True, 54 | ) 55 | install_with_constraints(session, "safety") 56 | session.run("safety", "check", f"--file={requirements.name}", "--full-report") 57 | 58 | 59 | @nox.session 60 | def tests(session): 61 | args = session.posargs or ["--cov", "-m", "not e2e"] 62 | session.run("poetry", "install", external=True) 63 | install_with_constraints(session, "pytest", "pytest-mock", "bgfx-python") 64 | session.run("pytest", *args) 65 | -------------------------------------------------------------------------------- /pybgfx/__init__.py: -------------------------------------------------------------------------------- 1 | import platform 2 | from .initializor import initialise 3 | 4 | sys_platform = platform.system() 5 | 6 | if sys_platform == "Darwin": 7 | _lib_name = "libbgfx_pythonCppyy.dylib" 8 | elif sys_platform == "Linux": 9 | _lib_name = "libbgfx_pythonCppyy.so" 10 | else: 11 | _lib_name = "bgfx_pythonCppyy.dll" 12 | 13 | initialise("pybgfx", _lib_name, "bgfx_python.map") 14 | del initialise 15 | -------------------------------------------------------------------------------- /pybgfx/constants.py: -------------------------------------------------------------------------------- 1 | from ctypes import c_uint16, c_uint32, c_uint64, c_uint8 2 | 3 | BGFX_STATE_WRITE_G = c_uint64(0x0000000000000002).value 4 | BGFX_STATE_WRITE_B = c_uint64(0x0000000000000004).value 5 | BGFX_STATE_WRITE_A = c_uint64(0x0000000000000008).value 6 | BGFX_STATE_WRITE_Z = c_uint64(0x0000004000000000).value 7 | BGFX_STATE_WRITE_R = c_uint64(0x0000000000000001).value 8 | BGFX_STATE_WRITE_RGB = 0 | BGFX_STATE_WRITE_R | BGFX_STATE_WRITE_G | BGFX_STATE_WRITE_B 9 | 10 | BGFX_STATE_WRITE_MASK = ( 11 | 0 | BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z 12 | ) 13 | 14 | BGFX_STATE_DEPTH_TEST_LESS = c_uint64(0x0000000000000010).value 15 | BGFX_STATE_DEPTH_TEST_LEQUAL = c_uint64(0x0000000000000020).value 16 | BGFX_STATE_DEPTH_TEST_EQUAL = c_uint64(0x0000000000000030).value 17 | BGFX_STATE_DEPTH_TEST_GEQUAL = c_uint64(0x0000000000000040).value 18 | BGFX_STATE_DEPTH_TEST_GREATER = c_uint64(0x0000000000000050).value 19 | BGFX_STATE_DEPTH_TEST_NOTEQUAL = c_uint64(0x0000000000000060).value 20 | BGFX_STATE_DEPTH_TEST_NEVER = c_uint64(0x0000000000000070).value 21 | BGFX_STATE_DEPTH_TEST_ALWAYS = c_uint64(0x00000000000).value 22 | BGFX_STATE_DEPTH_TEST_SHIFT = 4 23 | BGFX_STATE_DEPTH_TEST_MASK = c_uint64(0x00000000000000F0).value 24 | 25 | BGFX_STATE_BLEND_ZERO = c_uint64(0x0000000000001000).value 26 | BGFX_STATE_BLEND_ONE = c_uint64(0x0000000000002000).value 27 | BGFX_STATE_BLEND_SRC_COLOR = c_uint64(0x0000000000003000).value 28 | BGFX_STATE_BLEND_INV_SRC_COLOR = c_uint64(0x0000000000004000).value 29 | BGFX_STATE_BLEND_SRC_ALPHA = c_uint64(0x0000000000005000).value 30 | BGFX_STATE_BLEND_INV_SRC_ALPHA = c_uint64(0x0000000000006000).value 31 | BGFX_STATE_BLEND_DST_ALPHA = c_uint64(0x0000000000007000).value 32 | BGFX_STATE_BLEND_INV_DST_ALPHA = c_uint64(0x0000000000008000).value 33 | BGFX_STATE_BLEND_DST_COLOR = c_uint64(0x0000000000009000).value 34 | BGFX_STATE_BLEND_INV_DST_COLOR = c_uint64(0x000000000000A000).value 35 | BGFX_STATE_BLEND_SRC_ALPHA_SAT = c_uint64(0x000000000000B000).value 36 | BGFX_STATE_BLEND_FACTOR = c_uint64(0x000000000000C000).value 37 | BGFX_STATE_BLEND_INV_FACTOR = c_uint64(0x000000000000D000).value 38 | BGFX_STATE_BLEND_SHIFT = 12 39 | BGFX_STATE_BLEND_MASK = c_uint64(0x000000000FFFF000).value 40 | 41 | BGFX_STATE_BLEND_EQUATION_ADD = c_uint64(0x0000000000000000).value 42 | BGFX_STATE_BLEND_EQUATION_SUB = c_uint64(0x0000000010000000).value 43 | BGFX_STATE_BLEND_EQUATION_REVSUB = c_uint64(0x0000000020000000).value 44 | BGFX_STATE_BLEND_EQUATION_MIN = c_uint64(0x0000000030000000).value 45 | BGFX_STATE_BLEND_EQUATION_MAX = c_uint64(0x0000000040000000).value 46 | BGFX_STATE_BLEND_EQUATION_SHIFT = 28 47 | BGFX_STATE_BLEND_EQUATION_MASK = c_uint64(0x00000003F0000000).value 48 | 49 | BGFX_STATE_CULL_CW = c_uint64(0x0000001000000000).value 50 | BGFX_STATE_CULL_CCW = c_uint64(0x0000002000000000).value 51 | BGFX_STATE_CULL_SHIFT = 36 52 | BGFX_STATE_CULL_MASK = c_uint64(0x0000003000000000).value 53 | 54 | BGFX_STATE_ALPHA_REF_SHIFT = 40 55 | BGFX_STATE_ALPHA_REF_MASK = c_uint64(0x0000FF0000000000).value 56 | BGFX_STATE_ALPHA_REF = lambda v: ( 57 | (v << BGFX_STATE_ALPHA_REF_SHIFT) & BGFX_STATE_ALPHA_REF_MASK 58 | ) 59 | 60 | BGFX_STATE_PT_TRISTRIP = c_uint64(0x0001000000000000).value 61 | BGFX_STATE_PT_LINES = c_uint64(0x0002000000000000).value 62 | BGFX_STATE_PT_LINESTRIP = c_uint64(0x0003000000000000).value 63 | BGFX_STATE_PT_POINTS = c_uint64(0x0004000000000000).value 64 | BGFX_STATE_PT_SHIFT = 48 65 | BGFX_STATE_PT_MASK = c_uint64(0x0007000000000000).value 66 | 67 | BGFX_STATE_POINT_SIZE_SHIFT = 52 68 | BGFX_STATE_POINT_SIZE_MASK = c_uint64(0x00F0000000000000).value 69 | BGFX_STATE_POINT_SIZE = lambda v: ( 70 | (v << BGFX_STATE_POINT_SIZE_SHIFT) & BGFX_STATE_POINT_SIZE_MASK 71 | ) 72 | 73 | BGFX_STATE_MSAA = c_uint64(0x0100000000000000).value 74 | BGFX_STATE_LINEAA = c_uint64(0x0200000000000000).value 75 | BGFX_STATE_CONSERVATIVE_RASTER = c_uint64(0x0400000000000000).value 76 | BGFX_STATE_NONE = c_uint64(0x0000000000000000).value 77 | BGFX_STATE_BLEND_INDEPENDENT = c_uint64(0x0000000400000000).value 78 | BGFX_STATE_BLEND_ALPHA_TO_COVERAGE = c_uint64(0x0000000800000000).value 79 | BGFX_STATE_DEFAULT = ( 80 | 0 81 | | BGFX_STATE_WRITE_RGB 82 | | BGFX_STATE_WRITE_A 83 | | BGFX_STATE_WRITE_Z 84 | | BGFX_STATE_DEPTH_TEST_LESS 85 | | BGFX_STATE_CULL_CW 86 | | BGFX_STATE_MSAA 87 | ) 88 | 89 | BGFX_STATE_MASK = c_uint64(0xFFFFFFFFFFFFFFFF).value 90 | 91 | BGFX_STATE_RESERVED_SHIFT = 61 92 | 93 | BGFX_STATE_RESERVED_MASK = c_uint64(0xE000000000000000).value 94 | 95 | BGFX_STENCIL_FUNC_REF_SHIFT = 0 96 | 97 | BGFX_STENCIL_FUNC_REF_MASK = c_uint32(0x000000FF).value 98 | BGFX_STENCIL_FUNC_REF = lambda v: ( 99 | (v << BGFX_STENCIL_FUNC_REF_SHIFT) & BGFX_STENCIL_FUNC_REF_MASK 100 | ) 101 | 102 | BGFX_STENCIL_FUNC_RMASK_SHIFT = 8 103 | 104 | BGFX_STENCIL_FUNC_RMASK_MASK = c_uint32(0x0000FF00).value 105 | BGFX_STENCIL_FUNC_RMASK = lambda v: ( 106 | (v << BGFX_STENCIL_FUNC_RMASK_SHIFT) & BGFX_STENCIL_FUNC_RMASK_MASK 107 | ) 108 | 109 | BGFX_STENCIL_NONE = c_uint32(0x00000000).value 110 | BGFX_STENCIL_MASK = c_uint32(0xFFFFFFFF).value 111 | BGFX_STENCIL_DEFAULT = c_uint32(0x00000000).value 112 | 113 | BGFX_STENCIL_TEST_LESS = c_uint32(0x00010000).value 114 | BGFX_STENCIL_TEST_LEQUAL = c_uint32(0x00020000).value 115 | BGFX_STENCIL_TEST_EQUAL = c_uint32(0x00030000).value 116 | BGFX_STENCIL_TEST_GEQUAL = c_uint32(0x00040000).value 117 | BGFX_STENCIL_TEST_GREATER = c_uint32(0x00050000).value 118 | BGFX_STENCIL_TEST_NOTEQUAL = c_uint32(0x00060000).value 119 | BGFX_STENCIL_TEST_NEVER = c_uint32(0x00070000).value 120 | BGFX_STENCIL_TEST_ALWAYS = c_uint32(0x00080000).value 121 | BGFX_STENCIL_TEST_SHIFT = 16 122 | BGFX_STENCIL_TEST_MASK = c_uint32(0x000F0000).value 123 | 124 | BGFX_STENCIL_OP_FAIL_S_ZERO = c_uint32(0x00000000).value 125 | BGFX_STENCIL_OP_FAIL_S_KEEP = c_uint32(0x00100000).value 126 | BGFX_STENCIL_OP_FAIL_S_REPLACE = c_uint32(0x00200000).value 127 | BGFX_STENCIL_OP_FAIL_S_INCR = c_uint32(0x00300000).value 128 | BGFX_STENCIL_OP_FAIL_S_INCRSAT = c_uint32(0x00400000).value 129 | BGFX_STENCIL_OP_FAIL_S_DECR = c_uint32(0x00500000).value 130 | BGFX_STENCIL_OP_FAIL_S_DECRSAT = c_uint32(0x00600000).value 131 | BGFX_STENCIL_OP_FAIL_S_INVERT = c_uint32(0x00700000).value 132 | BGFX_STENCIL_OP_FAIL_S_SHIFT = 20 133 | BGFX_STENCIL_OP_FAIL_S_MASK = c_uint32(0x00F00000).value 134 | 135 | BGFX_STENCIL_OP_FAIL_Z_ZERO = c_uint32(0x00000000).value 136 | BGFX_STENCIL_OP_FAIL_Z_KEEP = c_uint32(0x01000000).value 137 | BGFX_STENCIL_OP_FAIL_Z_REPLACE = c_uint32(0x02000000).value 138 | BGFX_STENCIL_OP_FAIL_Z_INCR = c_uint32(0x03000000).value 139 | BGFX_STENCIL_OP_FAIL_Z_INCRSAT = c_uint32(0x04000000).value 140 | BGFX_STENCIL_OP_FAIL_Z_DECR = c_uint32(0x05000000).value 141 | BGFX_STENCIL_OP_FAIL_Z_DECRSAT = c_uint32(0x06000000).value 142 | BGFX_STENCIL_OP_FAIL_Z_INVERT = c_uint32(0x07000000).value 143 | BGFX_STENCIL_OP_FAIL_Z_SHIFT = 24 144 | BGFX_STENCIL_OP_FAIL_Z_MASK = c_uint32(0x0F000000).value 145 | 146 | BGFX_STENCIL_OP_PASS_Z_ZERO = c_uint32(0x00000000).value 147 | BGFX_STENCIL_OP_PASS_Z_KEEP = c_uint32(0x10000000).value 148 | BGFX_STENCIL_OP_PASS_Z_REPLACE = c_uint32(0x20000000).value 149 | BGFX_STENCIL_OP_PASS_Z_INCR = c_uint32(0x30000000).value 150 | BGFX_STENCIL_OP_PASS_Z_INCRSAT = c_uint32(0x40000000).value 151 | BGFX_STENCIL_OP_PASS_Z_DECR = c_uint32(0x50000000).value 152 | BGFX_STENCIL_OP_PASS_Z_DECRSAT = c_uint32(0x60000000).value 153 | BGFX_STENCIL_OP_PASS_Z_INVERT = c_uint32(0x70000000).value 154 | BGFX_STENCIL_OP_PASS_Z_SHIFT = 28 155 | BGFX_STENCIL_OP_PASS_Z_MASK = c_uint32(0xF0000000).value 156 | 157 | BGFX_CLEAR_NONE = c_uint16(0x0000).value 158 | BGFX_CLEAR_COLOR = c_uint16(0x0001).value 159 | BGFX_CLEAR_DEPTH = c_uint16(0x0002).value 160 | BGFX_CLEAR_STENCIL = c_uint16(0x0004).value 161 | BGFX_CLEAR_DISCARD_COLOR_0 = c_uint16(0x0008).value 162 | BGFX_CLEAR_DISCARD_COLOR_1 = c_uint16(0x0010).value 163 | BGFX_CLEAR_DISCARD_COLOR_2 = c_uint16(0x0020).value 164 | BGFX_CLEAR_DISCARD_COLOR_3 = c_uint16(0x0040).value 165 | BGFX_CLEAR_DISCARD_COLOR_4 = c_uint16(0x0080).value 166 | BGFX_CLEAR_DISCARD_COLOR_5 = c_uint16(0x0100).value 167 | BGFX_CLEAR_DISCARD_COLOR_6 = c_uint16(0x0200).value 168 | BGFX_CLEAR_DISCARD_COLOR_7 = c_uint16(0x0400).value 169 | BGFX_CLEAR_DISCARD_DEPTH = c_uint16(0x0800).value 170 | BGFX_CLEAR_DISCARD_STENCIL = c_uint16(0x1000).value 171 | BGFX_CLEAR_DISCARD_COLOR_MASK = ( 172 | 0 173 | | BGFX_CLEAR_DISCARD_COLOR_0 174 | | BGFX_CLEAR_DISCARD_COLOR_1 175 | | BGFX_CLEAR_DISCARD_COLOR_2 176 | | BGFX_CLEAR_DISCARD_COLOR_3 177 | | BGFX_CLEAR_DISCARD_COLOR_4 178 | | BGFX_CLEAR_DISCARD_COLOR_5 179 | | BGFX_CLEAR_DISCARD_COLOR_6 180 | | BGFX_CLEAR_DISCARD_COLOR_7 181 | ) 182 | 183 | BGFX_CLEAR_DISCARD_MASK = ( 184 | 0 185 | | BGFX_CLEAR_DISCARD_COLOR_MASK 186 | | BGFX_CLEAR_DISCARD_DEPTH 187 | | BGFX_CLEAR_DISCARD_STENCIL 188 | ) 189 | 190 | BGFX_DEBUG_NONE = c_uint32(0x00000000).value 191 | BGFX_DEBUG_WIREFRAME = c_uint32(0x00000001).value 192 | BGFX_DEBUG_IFH = c_uint32(0x00000002).value 193 | BGFX_DEBUG_STATS = c_uint32(0x00000004).value 194 | BGFX_DEBUG_TEXT = c_uint32(0x00000008).value 195 | BGFX_DEBUG_PROFILER = c_uint32(0x00000010).value 196 | 197 | BGFX_BUFFER_COMPUTE_FORMAT_8X1 = c_uint16(0x0001).value 198 | BGFX_BUFFER_COMPUTE_FORMAT_8X2 = c_uint16(0x0002).value 199 | BGFX_BUFFER_COMPUTE_FORMAT_8X4 = c_uint16(0x0003).value 200 | BGFX_BUFFER_COMPUTE_FORMAT_16X1 = c_uint16(0x0004).value 201 | BGFX_BUFFER_COMPUTE_FORMAT_16X2 = c_uint16(0x0005).value 202 | BGFX_BUFFER_COMPUTE_FORMAT_16X4 = c_uint16(0x0006).value 203 | BGFX_BUFFER_COMPUTE_FORMAT_32X1 = c_uint16(0x0007).value 204 | BGFX_BUFFER_COMPUTE_FORMAT_32X2 = c_uint16(0x0008).value 205 | BGFX_BUFFER_COMPUTE_FORMAT_32X4 = c_uint16(0x0009).value 206 | BGFX_BUFFER_COMPUTE_FORMAT_SHIFT = 0 207 | 208 | BGFX_BUFFER_COMPUTE_FORMAT_MASK = c_uint16(0x000F).value 209 | 210 | BGFX_BUFFER_COMPUTE_TYPE_INT = c_uint16(0x0010).value 211 | BGFX_BUFFER_COMPUTE_TYPE_UINT = c_uint16(0x0020).value 212 | BGFX_BUFFER_COMPUTE_TYPE_FLOAT = c_uint16(0x0030).value 213 | BGFX_BUFFER_COMPUTE_TYPE_SHIFT = 4 214 | 215 | BGFX_BUFFER_COMPUTE_TYPE_MASK = c_uint16(0x0030).value 216 | 217 | BGFX_BUFFER_NONE = c_uint16(0x0000).value 218 | BGFX_BUFFER_COMPUTE_READ = c_uint16(0x0100).value 219 | BGFX_BUFFER_COMPUTE_WRITE = c_uint16(0x0200).value 220 | BGFX_BUFFER_DRAW_INDIRECT = c_uint16(0x0400).value 221 | BGFX_BUFFER_ALLOW_RESIZE = c_uint16(0x0800).value 222 | BGFX_BUFFER_INDEX32 = c_uint16(0x1000).value 223 | BGFX_BUFFER_COMPUTE_READ_WRITE = ( 224 | 0 | BGFX_BUFFER_COMPUTE_READ | BGFX_BUFFER_COMPUTE_WRITE 225 | ) 226 | 227 | BGFX_TEXTURE_NONE = c_uint64(0x0000000000000000).value 228 | BGFX_TEXTURE_MSAA_SAMPLE = c_uint64(0x0000000800000000).value 229 | BGFX_TEXTURE_RT = c_uint64(0x0000001000000000).value 230 | BGFX_TEXTURE_COMPUTE_WRITE = c_uint64(0x0000100000000000).value 231 | BGFX_TEXTURE_SRGB = c_uint64(0x0000200000000000).value 232 | BGFX_TEXTURE_BLIT_DST = c_uint64(0x0000400000000000).value 233 | BGFX_TEXTURE_READ_BACK = c_uint64(0x0000800000000000).value 234 | 235 | BGFX_TEXTURE_RT_MSAA_X2 = c_uint64(0x0000002000000000).value 236 | BGFX_TEXTURE_RT_MSAA_X4 = c_uint64(0x0000003000000000).value 237 | BGFX_TEXTURE_RT_MSAA_X8 = c_uint64(0x0000004000000000).value 238 | BGFX_TEXTURE_RT_MSAA_X16 = c_uint64(0x0000005000000000).value 239 | BGFX_TEXTURE_RT_MSAA_SHIFT = 36 240 | 241 | BGFX_TEXTURE_RT_MSAA_MASK = c_uint64(0x0000007000000000).value 242 | 243 | BGFX_TEXTURE_RT_WRITE_ONLY = c_uint64(0x0000008000000000).value 244 | BGFX_TEXTURE_RT_SHIFT = 36 245 | 246 | BGFX_TEXTURE_RT_MASK = c_uint64(0x000000F000000000).value 247 | 248 | BGFX_SAMPLER_U_MIRROR = c_uint32(0x00000001).value 249 | BGFX_SAMPLER_U_CLAMP = c_uint32(0x00000002).value 250 | BGFX_SAMPLER_U_BORDER = c_uint32(0x00000003).value 251 | BGFX_SAMPLER_U_SHIFT = 0 252 | 253 | BGFX_SAMPLER_U_MASK = c_uint32(0x00000003).value 254 | 255 | BGFX_SAMPLER_V_MIRROR = c_uint32(0x00000004).value 256 | BGFX_SAMPLER_V_CLAMP = c_uint32(0x00000008).value 257 | BGFX_SAMPLER_V_BORDER = c_uint32(0x0000000C).value 258 | BGFX_SAMPLER_V_SHIFT = 2 259 | 260 | BGFX_SAMPLER_V_MASK = c_uint32(0x0000000C).value 261 | 262 | BGFX_SAMPLER_W_MIRROR = c_uint32(0x00000010).value 263 | BGFX_SAMPLER_W_CLAMP = c_uint32(0x00000020).value 264 | BGFX_SAMPLER_W_BORDER = c_uint32(0x00000030).value 265 | BGFX_SAMPLER_W_SHIFT = 4 266 | 267 | BGFX_SAMPLER_W_MASK = c_uint32(0x00000030).value 268 | 269 | BGFX_SAMPLER_MIN_POINT = c_uint32(0x00000040).value 270 | BGFX_SAMPLER_MIN_ANISOTROPIC = c_uint32(0x00000080).value 271 | BGFX_SAMPLER_MIN_SHIFT = 6 272 | 273 | BGFX_SAMPLER_MIN_MASK = c_uint32(0x000000C0).value 274 | 275 | BGFX_SAMPLER_MAG_POINT = c_uint32(0x00000100).value 276 | BGFX_SAMPLER_MAG_ANISOTROPIC = c_uint32(0x00000200).value 277 | BGFX_SAMPLER_MAG_SHIFT = 8 278 | 279 | BGFX_SAMPLER_MAG_MASK = c_uint32(0x00000300).value 280 | 281 | BGFX_SAMPLER_MIP_POINT = c_uint32(0x00000400).value 282 | BGFX_SAMPLER_MIP_SHIFT = 10 283 | 284 | BGFX_SAMPLER_MIP_MASK = c_uint32(0x00000400).value 285 | 286 | BGFX_SAMPLER_COMPARE_LESS = c_uint32(0x00010000).value 287 | BGFX_SAMPLER_COMPARE_LEQUAL = c_uint32(0x00020000).value 288 | BGFX_SAMPLER_COMPARE_EQUAL = c_uint32(0x00030000).value 289 | BGFX_SAMPLER_COMPARE_GEQUAL = c_uint32(0x00040000).value 290 | BGFX_SAMPLER_COMPARE_GREATER = c_uint32(0x00050000).value 291 | BGFX_SAMPLER_COMPARE_NOTEQUAL = c_uint32(0x00060000).value 292 | BGFX_SAMPLER_COMPARE_NEVER = c_uint32(0x00070000).value 293 | BGFX_SAMPLER_COMPARE_ALWAYS = c_uint32(0x00080000).value 294 | BGFX_SAMPLER_COMPARE_SHIFT = 16 295 | 296 | BGFX_SAMPLER_COMPARE_MASK = c_uint32(0x000F0000).value 297 | 298 | BGFX_SAMPLER_BORDER_COLOR_SHIFT = 24 299 | 300 | BGFX_SAMPLER_BORDER_COLOR_MASK = c_uint32(0x0F000000).value 301 | BGFX_SAMPLER_BORDER_COLOR = lambda v: ( 302 | c_uint32(v << BGFX_SAMPLER_BORDER_COLOR_SHIFT).value 303 | & BGFX_SAMPLER_BORDER_COLOR_MASK 304 | ) 305 | 306 | BGFX_SAMPLER_RESERVED_SHIFT = 28 307 | 308 | BGFX_SAMPLER_RESERVED_MASK = c_uint32(0xF0000000).value 309 | 310 | BGFX_SAMPLER_NONE = c_uint32(0x00000000).value 311 | BGFX_SAMPLER_SAMPLE_STENCIL = c_uint32(0x00100000).value 312 | BGFX_SAMPLER_POINT = ( 313 | 0 | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT 314 | ) 315 | 316 | BGFX_SAMPLER_UVW_MIRROR = ( 317 | 0 | BGFX_SAMPLER_U_MIRROR | BGFX_SAMPLER_V_MIRROR | BGFX_SAMPLER_W_MIRROR 318 | ) 319 | 320 | BGFX_SAMPLER_UVW_CLAMP = ( 321 | 0 | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP | BGFX_SAMPLER_W_CLAMP 322 | ) 323 | 324 | BGFX_SAMPLER_UVW_BORDER = ( 325 | 0 | BGFX_SAMPLER_U_BORDER | BGFX_SAMPLER_V_BORDER | BGFX_SAMPLER_W_BORDER 326 | ) 327 | 328 | BGFX_SAMPLER_BITS_MASK = ( 329 | 0 330 | | BGFX_SAMPLER_U_MASK 331 | | BGFX_SAMPLER_V_MASK 332 | | BGFX_SAMPLER_W_MASK 333 | | BGFX_SAMPLER_MIN_MASK 334 | | BGFX_SAMPLER_MAG_MASK 335 | | BGFX_SAMPLER_MIP_MASK 336 | | BGFX_SAMPLER_COMPARE_MASK 337 | ) 338 | 339 | BGFX_RESET_MSAA_X2 = c_uint32(0x00000010).value 340 | BGFX_RESET_MSAA_X4 = c_uint32(0x00000020).value 341 | BGFX_RESET_MSAA_X8 = c_uint32(0x00000030).value 342 | BGFX_RESET_MSAA_X16 = c_uint32(0x00000040).value 343 | BGFX_RESET_MSAA_SHIFT = 4 344 | 345 | BGFX_RESET_MSAA_MASK = c_uint32(0x00000070).value 346 | 347 | BGFX_RESET_NONE = c_uint32(0x00000000).value 348 | BGFX_RESET_FULLSCREEN = c_uint32(0x00000001).value 349 | BGFX_RESET_VSYNC = c_uint32(0x00000080).value 350 | BGFX_RESET_MAXANISOTROPY = c_uint32(0x00000100).value 351 | BGFX_RESET_CAPTURE = c_uint32(0x00000200).value 352 | BGFX_RESET_FLUSH_AFTER_RENDER = c_uint32(0x00002000).value 353 | 354 | BGFX_RESET_FLIP_AFTER_RENDER = c_uint32(0x00004000).value 355 | BGFX_RESET_SRGB_BACKBUFFER = c_uint32(0x00008000).value 356 | BGFX_RESET_HDR10 = c_uint32(0x00010000).value 357 | BGFX_RESET_HIDPI = c_uint32(0x00020000).value 358 | BGFX_RESET_DEPTH_CLAMP = c_uint32(0x00040000).value 359 | BGFX_RESET_SUSPEND = c_uint32(0x00080000).value 360 | 361 | BGFX_RESET_FULLSCREEN_SHIFT = 0 362 | 363 | BGFX_RESET_FULLSCREEN_MASK = c_uint32(0x00000001).value 364 | 365 | BGFX_RESET_RESERVED_SHIFT = 31 366 | BGFX_RESET_RESERVED_MASK = c_uint32(0x80000000).value 367 | 368 | BGFX_CAPS_ALPHA_TO_COVERAGE = c_uint64(0x0000000000000001).value 369 | BGFX_CAPS_BLEND_INDEPENDENT = c_uint64(0x0000000000000002).value 370 | BGFX_CAPS_COMPUTE = c_uint64(0x0000000000000004).value 371 | BGFX_CAPS_CONSERVATIVE_RASTER = c_uint64(0x0000000000000008).value 372 | BGFX_CAPS_DRAW_INDIRECT = c_uint64(0x0000000000000010).value 373 | BGFX_CAPS_FRAGMENT_DEPTH = c_uint64(0x0000000000000020).value 374 | BGFX_CAPS_FRAGMENT_ORDERING = c_uint64(0x0000000000000040).value 375 | BGFX_CAPS_FRAMEBUFFER_RW = c_uint64(0x0000000000000080).value 376 | BGFX_CAPS_GRAPHICS_DEBUGGER = c_uint64(0x0000000000000100).value 377 | BGFX_CAPS_RESERVED = c_uint64(0x0000000000000200).value 378 | BGFX_CAPS_HDR10 = c_uint64(0x0000000000000400).value 379 | BGFX_CAPS_HIDPI = c_uint64(0x0000000000000800).value 380 | BGFX_CAPS_INDEX32 = c_uint64(0x0000000000001000).value 381 | BGFX_CAPS_INSTANCING = c_uint64(0x0000000000002000).value 382 | BGFX_CAPS_OCCLUSION_QUERY = c_uint64(0x0000000000004000).value 383 | BGFX_CAPS_RENDERER_MULTITHREADED = c_uint64(0x0000000000008000).value 384 | BGFX_CAPS_SWAP_CHAIN = c_uint64(0x0000000000010000).value 385 | BGFX_CAPS_TEXTURE_2D_ARRAY = c_uint64(0x0000000000020000).value 386 | BGFX_CAPS_TEXTURE_3D = c_uint64(0x0000000000040000).value 387 | BGFX_CAPS_TEXTURE_BLIT = c_uint64(0x0000000000080000).value 388 | BGFX_CAPS_TEXTURE_COMPARE_RESERVED = c_uint64(0x0000000000100000).value 389 | BGFX_CAPS_TEXTURE_COMPARE_LEQUAL = c_uint64(0x0000000000200000).value 390 | BGFX_CAPS_TEXTURE_CUBE_ARRAY = c_uint64(0x0000000000400000).value 391 | BGFX_CAPS_TEXTURE_DIRECT_ACCESS = c_uint64(0x0000000000800000).value 392 | BGFX_CAPS_TEXTURE_READ_BACK = c_uint64(0x0000000001000000).value 393 | BGFX_CAPS_VERTEX_ATTRIB_HALF = c_uint64(0x0000000002000000).value 394 | BGFX_CAPS_VERTEX_ATTRIB_UINT10 = c_uint64(0x0000000004000000).value 395 | BGFX_CAPS_VERTEX_ID = c_uint64(0x0000000008000000).value 396 | 397 | BGFX_CAPS_TEXTURE_COMPARE_ALL = ( 398 | 0 | BGFX_CAPS_TEXTURE_COMPARE_RESERVED | BGFX_CAPS_TEXTURE_COMPARE_LEQUAL 399 | ) 400 | 401 | BGFX_CAPS_FORMAT_TEXTURE_NONE = c_uint16(0x0000).value 402 | BGFX_CAPS_FORMAT_TEXTURE_2D = c_uint16(0x0001).value 403 | BGFX_CAPS_FORMAT_TEXTURE_2D_SRGB = c_uint16(0x0002).value 404 | BGFX_CAPS_FORMAT_TEXTURE_2D_EMULATED = c_uint16(0x0004).value 405 | BGFX_CAPS_FORMAT_TEXTURE_3D = c_uint16(0x0008).value 406 | BGFX_CAPS_FORMAT_TEXTURE_3D_SRGB = c_uint16(0x0010).value 407 | BGFX_CAPS_FORMAT_TEXTURE_3D_EMULATED = c_uint16(0x0020).value 408 | BGFX_CAPS_FORMAT_TEXTURE_CUBE = c_uint16(0x0040).value 409 | BGFX_CAPS_FORMAT_TEXTURE_CUBE_SRGB = c_uint16(0x0080).value 410 | BGFX_CAPS_FORMAT_TEXTURE_CUBE_EMULATED = c_uint16(0x0100).value 411 | BGFX_CAPS_FORMAT_TEXTURE_VERTEX = c_uint16(0x0200).value 412 | BGFX_CAPS_FORMAT_TEXTURE_IMAGE = c_uint16(0x0400).value 413 | BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER = c_uint16(0x0800).value 414 | BGFX_CAPS_FORMAT_TEXTURE_FRAMEBUFFER_MSAA = c_uint16(0x1000).value 415 | BGFX_CAPS_FORMAT_TEXTURE_MSAA = c_uint16(0x2000).value 416 | BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN = c_uint16(0x4000).value 417 | 418 | BGFX_RESOLVE_NONE = c_uint8(0x00) 419 | BGFX_RESOLVE_AUTO_GEN_MIPS = c_uint8(0x01) 420 | 421 | BGFX_PCI_ID_NONE = c_uint16(0x0000).value 422 | BGFX_PCI_ID_SOFTWARE_RASTERIZER = c_uint16(0x0001).value 423 | BGFX_PCI_ID_AMD = c_uint16(0x1002).value 424 | BGFX_PCI_ID_INTEL = c_uint16(0x8086).value 425 | BGFX_PCI_ID_NVIDIA = c_uint16(0x10DE).value 426 | 427 | BGFX_CUBE_MAP_POSITIVE_X = c_uint8(0x00) 428 | BGFX_CUBE_MAP_NEGATIVE_X = c_uint8(0x01) 429 | BGFX_CUBE_MAP_POSITIVE_Y = c_uint8(0x02) 430 | BGFX_CUBE_MAP_NEGATIVE_Y = c_uint8(0x03) 431 | BGFX_CUBE_MAP_POSITIVE_Z = c_uint8(0x04) 432 | BGFX_CUBE_MAP_NEGATIVE_Z = c_uint8(0x05) 433 | 434 | BGFX_STATE_BLEND_FUNC_SEPARATE = lambda _srcRGB, _dstRGB, _srcA, _dstA: ( 435 | 0 | (_srcRGB | (_dstRGB << 4)) | (_srcA | (_dstA << 4) << 8) 436 | ) 437 | BGFX_STATE_BLEND_EQUATION_SEPARATE = lambda _equationRGB, _equationA: ( 438 | _equationRGB | _equationA << 3 439 | ) 440 | BGFX_STATE_BLEND_FUNC = lambda _src, _dst: BGFX_STATE_BLEND_FUNC_SEPARATE( 441 | _src, _dst, _src, _dst 442 | ) 443 | BGFX_STATE_BLEND_EQUATION = lambda _equation: BGFX_STATE_BLEND_EQUATION_SEPARATE( 444 | _equation, _equation 445 | ) 446 | 447 | BGFX_STATE_BLEND_ADD = 0 | BGFX_STATE_BLEND_FUNC( 448 | BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE 449 | ) 450 | 451 | BGFX_STATE_BLEND_ALPHA = 0 | BGFX_STATE_BLEND_FUNC( 452 | BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA 453 | ) 454 | 455 | BGFX_STATE_BLEND_DARKEN = ( 456 | 0 457 | | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE) 458 | | BGFX_STATE_BLEND_EQUATION(BGFX_STATE_BLEND_EQUATION_MIN) 459 | ) 460 | 461 | BGFX_STATE_BLEND_LIGHTEN = ( 462 | 0 463 | | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE) 464 | | BGFX_STATE_BLEND_EQUATION(BGFX_STATE_BLEND_EQUATION_MAX) 465 | ) 466 | 467 | BGFX_STATE_BLEND_MULTIPLY = 0 | BGFX_STATE_BLEND_FUNC( 468 | BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_ZERO 469 | ) 470 | 471 | BGFX_STATE_BLEND_NORMAL = 0 | BGFX_STATE_BLEND_FUNC( 472 | BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_ALPHA 473 | ) 474 | 475 | BGFX_STATE_BLEND_SCREEN = 0 | BGFX_STATE_BLEND_FUNC( 476 | BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_INV_SRC_COLOR 477 | ) 478 | 479 | BGFX_STATE_BLEND_LINEAR_BURN = ( 480 | 0 481 | | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_DST_COLOR, BGFX_STATE_BLEND_INV_DST_COLOR) 482 | | BGFX_STATE_BLEND_EQUATION(BGFX_STATE_BLEND_EQUATION_SUB) 483 | ) 484 | 485 | BGFX_STATE_BLEND_FUNC_RT_x = lambda _src, _dst: 0 | ( 486 | ((_src) >> BGFX_STATE_BLEND_SHIFT) | (((_dst) >> BGFX_STATE_BLEND_SHIFT) << 4) 487 | ) 488 | 489 | BGFX_STATE_BLEND_FUNC_RT_xE = ( 490 | lambda _src, _dst, _equation: 0 491 | | BGFX_STATE_BLEND_FUNC_RT_x(_src, _dst) 492 | | (((_equation) >> BGFX_STATE_BLEND_EQUATION_SHIFT) << 8) 493 | ) 494 | 495 | BGFX_STATE_BLEND_FUNC_RT_1 = lambda _src, _dst: ( 496 | BGFX_STATE_BLEND_FUNC_RT_x(_src, _dst) << 0 497 | ) 498 | BGFX_STATE_BLEND_FUNC_RT_2 = lambda _src, _dst: ( 499 | BGFX_STATE_BLEND_FUNC_RT_x(_src, _dst) << 11 500 | ) 501 | BGFX_STATE_BLEND_FUNC_RT_3 = lambda _src, _dst: ( 502 | BGFX_STATE_BLEND_FUNC_RT_x(_src, _dst) << 22 503 | ) 504 | 505 | BGFX_STATE_BLEND_FUNC_RT_1E = lambda _src, _dst, _equation: ( 506 | BGFX_STATE_BLEND_FUNC_RT_xE(_src, _dst, _equation) << 0 507 | ) 508 | BGFX_STATE_BLEND_FUNC_RT_2E = lambda _src, _dst, _equation: ( 509 | BGFX_STATE_BLEND_FUNC_RT_xE(_src, _dst, _equation) << 11 510 | ) 511 | BGFX_STATE_BLEND_FUNC_RT_3E = lambda _src, _dst, _equation: ( 512 | BGFX_STATE_BLEND_FUNC_RT_xE(_src, _dst, _equation) << 22 513 | ) 514 | -------------------------------------------------------------------------------- /pybgfx/initializor.py: -------------------------------------------------------------------------------- 1 | import gettext 2 | import glob 3 | import importlib.util 4 | import inspect 5 | import json 6 | import os 7 | import re 8 | from pathlib import Path 9 | 10 | import sys 11 | 12 | import cppyy 13 | from loguru import logger 14 | 15 | logger.disable("pybgfx") 16 | 17 | gettext.install(__name__) 18 | 19 | 20 | def initialise(pkg, lib_file, map_file): 21 | pkg_dir = os.path.dirname(__file__) 22 | pkg_module = sys.modules[pkg] 23 | 24 | # 25 | # Load the library. 26 | # 27 | cppyy.add_include_path(pkg_dir + "/include") 28 | cppyy.add_include_path(pkg_dir + "/include/bx") 29 | cppyy.add_include_path(pkg_dir + "/include/bimg") 30 | cppyy.add_include_path(pkg_dir + "/include/bgfx") 31 | cppyy.add_include_path(pkg_dir + "/include/imgui") 32 | cppyy.add_include_path(pkg_dir + "/include/extras") 33 | cppyy.add_include_path(pkg_dir + "/include/examples/common") 34 | 35 | files = fix_map_file_paths(pkg_dir, map_file) 36 | 37 | cppyy.load_reflection_info(os.path.join(pkg_dir, lib_file)) 38 | 39 | add_types_to_namespaces(files, pkg, pkg_module) 40 | 41 | 42 | def add_types_to_namespaces(files, pkg, pkg_module): 43 | for file in files: 44 | add_after_namespaces = [] 45 | 46 | for child in file["children"]: 47 | simple_name = child["name"].split("::")[0] 48 | 49 | if child["kind"] == "namespace": 50 | entity = getattr(cppyy.gbl, simple_name) 51 | if getattr(entity, "__module__", None) == "cppyy.gbl": 52 | setattr(entity, "__module__", pkg) 53 | setattr(pkg_module, simple_name, entity) 54 | else: 55 | add_after_namespaces.append(child) 56 | 57 | for child in add_after_namespaces: 58 | simple_name = child["name"].split("::")[0] 59 | if child["kind"] == "enum": 60 | for enum_value in child["enumerations"]: 61 | enum_value_name = enum_value["name"] 62 | entity = getattr(cppyy.gbl, enum_value_name) 63 | setattr(entity, "__module__", pkg + ".ImGui") 64 | setattr(pkg_module.ImGui, enum_value_name, entity) 65 | elif child["kind"] not in ( 66 | "typedef", 67 | "function", 68 | ) and simple_name.startswith("Im"): 69 | entity = getattr(cppyy.gbl, simple_name) 70 | setattr(entity, "__module__", pkg + ".ImGui") 71 | setattr(pkg_module.ImGui, simple_name, entity) 72 | 73 | 74 | def fix_map_file_paths(pkg_dir, map_file): 75 | include_dir_map = { 76 | "bgfx": os.path.join(pkg_dir, "include/bgfx"), 77 | "dear-imgui": os.path.join(pkg_dir, "include/imgui"), 78 | "imgui": os.path.join(pkg_dir, "include/examples/common/imgui"), 79 | "extras": os.path.join(pkg_dir, "include/extras"), 80 | } 81 | with open(os.path.join(pkg_dir, map_file), "r") as map_file_pointer: 82 | files = json.load(map_file_pointer) 83 | 84 | for file in files: 85 | if file["kind"] == "file": 86 | file_path = Path(file["name"]) 87 | 88 | if not str(file_path).startswith(pkg_dir): 89 | file_name = file_path.name 90 | folder_name = file_path.parent.name 91 | actual_folder = include_dir_map[folder_name] 92 | file["name"] = str((Path(actual_folder) / file_name).absolute()) 93 | logger.info(f"Fixing MAP file entry: {file_path} -> {file['name']}") 94 | 95 | with open(os.path.join(pkg_dir, map_file), "w") as map_file_pointer: 96 | json.dump(files, map_file_pointer) 97 | 98 | return files 99 | -------------------------------------------------------------------------------- /pybgfx/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | from array import ArrayType 3 | from typing import Any 4 | 5 | try: 6 | import numpy 7 | 8 | _is_numpy_array = lambda obj: type(obj) is numpy.ndarray 9 | except Exception: 10 | _is_numpy_array = lambda obj: False 11 | 12 | 13 | def as_void_ptr(obj: Any) -> ctypes.py_object: 14 | """ 15 | Creates a Python Capsule to pass 'void *' arguments to C++ APIs. 16 | Caveat: for other types of pointers, use the `ctypes` interface 17 | or `cppyy.nullptr` for NULL pointers. 18 | 19 | :param obj: the referenced object 20 | :return: a Python Capsule representing a pointer to the object 21 | """ 22 | ctypes.pythonapi.PyCapsule_New.restype = ctypes.py_object 23 | ctypes.pythonapi.PyCapsule_New.argtypes = [ 24 | ctypes.c_void_p, 25 | ctypes.c_char_p, 26 | ctypes.c_void_p, 27 | ] 28 | 29 | if type(obj) == ArrayType: 30 | obj = obj.buffer_info()[0] 31 | 32 | if _is_numpy_array(obj): 33 | obj = obj.ctypes.data_as(ctypes.POINTER(ctypes.c_void_p)) 34 | 35 | if type(obj) != ctypes.c_void_p: 36 | obj = ctypes.cast(obj, ctypes.c_void_p) 37 | 38 | capsule = ctypes.pythonapi.PyCapsule_New(obj, None, None) 39 | 40 | return capsule 41 | -------------------------------------------------------------------------------- /pybgfx/utils/imgui_utils.py: -------------------------------------------------------------------------------- 1 | import cppyy 2 | 3 | 4 | ImGuiExtra = cppyy.gbl._ImGuiExtra() 5 | -------------------------------------------------------------------------------- /pybgfx/utils/mesh_utils.py: -------------------------------------------------------------------------------- 1 | from array import array 2 | from typing import List 3 | 4 | import cppyy 5 | 6 | # noinspection PyUnresolvedReferences 7 | from pybgfx import bgfx 8 | 9 | from loguru import logger 10 | from pathlib import Path 11 | from pybgfx.constants import BGFX_STATE_MASK 12 | 13 | 14 | class Mesh: 15 | def __init__(self, file_path: Path, ram_copy=False): 16 | logger.debug(f"Loading mesh (RAM {ram_copy}): {file_path}") 17 | str_file_path = str(file_path) 18 | self.internal_mesh = cppyy.gbl._MeshLoader().load(str_file_path, ram_copy) 19 | 20 | def submit( 21 | self, 22 | view_id: int, 23 | program: bgfx.ProgramHandle, 24 | matrix: List[float], 25 | state=BGFX_STATE_MASK, 26 | ): 27 | self.internal_mesh.submit(view_id, program, matrix, state) 28 | 29 | def destroy(self): 30 | self.internal_mesh.unload() 31 | -------------------------------------------------------------------------------- /pybgfx/utils/shaders_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import shelve 4 | import subprocess 5 | import tempfile 6 | from enum import Enum 7 | from hashlib import sha256 8 | from pathlib import Path 9 | from typing import List, Optional 10 | 11 | from loguru import logger 12 | 13 | # noinspection PyUnresolvedReferences 14 | from pybgfx import bgfx 15 | from pybgfx.utils import as_void_ptr 16 | 17 | logger.disable("pybgfx") 18 | 19 | _pkg_path = Path(os.path.dirname(__file__)).parent 20 | _default_bin_path = _pkg_path / "bin" 21 | _default_include_dir = _pkg_path / "include" / "shaders" 22 | _os_exe_suffix = ".exe" if platform.system() == "Windows" else "" 23 | 24 | 25 | class ShaderType(Enum): 26 | FRAGMENT = "f" 27 | VERTEX = "v" 28 | COMPUTE = "c" 29 | 30 | 31 | def _md5sum(filename, buf_size=8192) -> str: 32 | m = sha256() 33 | with open(filename, "rb") as f: 34 | data = f.read(buf_size) 35 | while data: 36 | m.update(data) 37 | data = f.read(buf_size) 38 | return m.hexdigest() 39 | 40 | 41 | def _get_platform() -> str: 42 | platforms = {"Windows": "windows", "Linux": "linux", "Darwin": "osx"} 43 | 44 | return platforms.get(platform.system()) 45 | 46 | 47 | def _get_profile(shader_type: ShaderType) -> str: 48 | renderer_type = bgfx.getRendererType() 49 | sys_platform = platform.system() 50 | windows_shader_type = { 51 | ShaderType.FRAGMENT: "ps_", 52 | ShaderType.VERTEX: "vs_", 53 | ShaderType.COMPUTE: "cs_", 54 | } 55 | 56 | if sys_platform == "Darwin": 57 | return "metal" 58 | 59 | elif sys_platform == "Linux": 60 | if renderer_type == bgfx.RendererType.Vulkan: 61 | return "spirv" 62 | else: 63 | return "glsl" 64 | 65 | elif sys_platform == "Windows": 66 | if renderer_type == bgfx.RendererType.Direct3D9: 67 | return windows_shader_type.get(shader_type) + "3_0" 68 | else: 69 | return windows_shader_type.get(shader_type) + "5_0" 70 | 71 | else: 72 | raise ValueError("'{}' is not supported!".format(sys_platform)) 73 | 74 | 75 | def _load_mem(content: bytes) -> bgfx.Memory: 76 | size = len(content) 77 | memory = bgfx.copy(as_void_ptr(content), size) 78 | return memory 79 | 80 | 81 | def _make_paths_absolute(paths: List[str], root_path: str) -> List[str]: 82 | if not root_path: 83 | return paths 84 | 85 | absolute_paths = [] 86 | 87 | for path in paths: 88 | if not os.path.abspath(path): 89 | absolute_paths.append(os.path.join(root_path, path)) 90 | else: 91 | absolute_paths.append(path) 92 | 93 | return absolute_paths 94 | 95 | 96 | def load_shader( 97 | name: str, 98 | shader_type: ShaderType, 99 | include_dirs: Optional[List[str]] = (), 100 | root_path: Optional[Path] = None, 101 | ) -> bgfx.ShaderHandle: 102 | """ 103 | Compiles the given shader for the platform-specific driver and creates 104 | a bgfx::ShaderHandle object. 105 | 106 | :param name: the shader's file name 107 | :param shader_type: the shader's type (e.g. fragment, vertex, compute) 108 | :param include_dirs: additional absolute paths to resolve shader's #include directives 109 | :param root_path: the root path for shaders lookup 110 | :return: a bgfx::ShaderHandle for the compiled shader 111 | """ 112 | 113 | shaders_root_path = Path(".") if not root_path else root_path 114 | complete_path = str((Path(shaders_root_path) / name).absolute()) 115 | md5 = _md5sum(complete_path) 116 | 117 | logger.debug("Loading shader '{}': {}".format(name, md5)) 118 | 119 | with shelve.open("shaders_cache") as cache: 120 | if complete_path in cache and cache[complete_path]["md5"] == md5: 121 | logger.debug( 122 | "Shader '{}' found in cache, skipping compilation".format(name) 123 | ) 124 | memory = _load_mem(cache[complete_path]["content"]) 125 | else: 126 | logger.debug("Shader '{}' not found in cache, compiling...".format(name)) 127 | absolute_include_dir_paths = _make_paths_absolute(include_dirs, root_path) 128 | compiled_shader = compile_shader( 129 | complete_path, shader_type, absolute_include_dir_paths 130 | ) 131 | 132 | with open(compiled_shader, mode="rb") as compiled_shader_fp: 133 | compiled_shader_source = compiled_shader_fp.read() 134 | cache[complete_path] = {"md5": md5, "content": compiled_shader_source} 135 | memory = _load_mem(compiled_shader_source) 136 | 137 | os.unlink(compiled_shader) 138 | 139 | handle = bgfx.createShader(memory) 140 | bgfx.setName(handle, name) 141 | 142 | return handle 143 | 144 | 145 | def compile_shader( 146 | complete_path: str, shader_type: ShaderType, include_dirs: Optional[List[str]] = () 147 | ) -> str: 148 | """ 149 | Compiles the given shader for the platform-specific driver and saves it to 150 | a temporary file. 151 | 152 | :param complete_path: the absolute path of the shader to compile 153 | :param shader_type: the shader's type (e.g. fragment, vertex, compute) 154 | :param include_dirs: additional absolute paths to resolve shader's #include directives 155 | :return: the path of the temporary file containing the compiled shader's source 156 | """ 157 | if not os.path.exists(complete_path): 158 | raise RuntimeError("Shader {} does not exists!".format(complete_path)) 159 | 160 | options = [] 161 | temp_file = tempfile.NamedTemporaryFile(delete=False) 162 | 163 | options.extend(("-f", complete_path)) 164 | options.extend(("-o", temp_file.name)) 165 | options.extend(("-i", str(_default_include_dir))) 166 | 167 | for include_dir in include_dirs: 168 | if not os.path.exists(include_dir) or os.path.isdir(include_dir): 169 | raise RuntimeError( 170 | "{} does not exists or is not a directory!".format(include_dir) 171 | ) 172 | 173 | options.extend(["-i", include_dir]) 174 | 175 | options.extend(("--platform", _get_platform())) 176 | options.extend(("--profile", _get_profile(shader_type))) 177 | options.extend(("--type", shader_type.value)) 178 | 179 | if platform.system() == "Windows": 180 | options.extend(["-O", "1" if shader_type == ShaderType.COMPUTE else "3"]) 181 | 182 | shaderc_bin = str(_default_bin_path / "shadercRelease{}".format(_os_exe_suffix)) 183 | os.chmod(shaderc_bin, 0o774) 184 | 185 | run_args = [shaderc_bin] + options 186 | run_info = subprocess.run(run_args, capture_output=True, text=True) 187 | 188 | if run_info.returncode != 0: 189 | raise RuntimeError( 190 | "Error compiling shader {}:\n{}".format(complete_path, run_info.stdout) 191 | ) 192 | 193 | return temp_file.name 194 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "bgfx-python" 3 | version = "1.0.5" 4 | description = "Python wrapper for BGFX Library" 5 | authors = [ 6 | "Federico Bertola" 7 | ] 8 | license = "MIT" 9 | 10 | readme = "README.md" 11 | 12 | repository = "https://github.com/fbertola/bgfx-python" 13 | 14 | keywords = ["cpp", "bgfx", "opengl", "metal", "directx", "vulkan"] 15 | 16 | classifiers = [ 17 | "License :: OSI Approved :: BSD License", 18 | "Intended Audience :: Developers", 19 | "Operating System :: OS Independent", 20 | "Programming Language :: Python", 21 | "Programming Language :: Python :: 3", 22 | "Programming Language :: Python :: 3.6", 23 | "Programming Language :: Python :: 3.7", 24 | "Programming Language :: Python :: 3.8", 25 | "Programming Language :: Python :: Implementation :: CPython", 26 | "Programming Language :: Python :: Implementation :: PyPy", 27 | "Topic :: Multimedia :: Graphics" 28 | ] 29 | 30 | [tool.poetry.dependencies] 31 | python = "^3.7" 32 | loguru = "^0.5.1" 33 | cppyy = "^2.1.0" 34 | clang = "^11.0" 35 | 36 | [tool.poetry.dev-dependencies] 37 | pytest = "^5.4.3" 38 | pytest-mock = "^1.9" 39 | black = "^19.10b0" 40 | flake8 = "^3.8.3" 41 | flake8-bandit = "^2.1.2" 42 | flake8-black = "^0.2.0" 43 | flake8-bugbear = "^20.1.4" 44 | flake8-import-order = "^0.18.1" 45 | safety = "^1.9.0" 46 | nox = "^2020.5.24" 47 | glfw = "^2.0.0" 48 | numpy = "^1.19.0" 49 | pytest-sugar = "^0.9.4" 50 | pillow = "^8.2.0" 51 | cmakelang = "^0.6.13" 52 | 53 | [tool.black] 54 | line-length = 88 55 | include = '\.pyi?$' 56 | exclude = ''' 57 | /( 58 | \.eggs 59 | | \.git 60 | | \.hg 61 | | \.mypy_cache 62 | | \.tox 63 | | \.venv 64 | | _build 65 | | buck-out 66 | | build 67 | | dist 68 | | tests/.*/setup.py 69 | )/ 70 | ''' 71 | 72 | [build-system] 73 | requires = ["setuptools", "wheel", "scikit-build", "cmake", "ninja", "loguru", "cppyy", "clang"] 74 | 75 | 76 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import io 4 | import os 5 | import sys 6 | 7 | from skbuild import setup 8 | from skbuild.constants import skbuild_plat_name 9 | 10 | here = os.path.abspath(os.path.dirname(__file__)) 11 | 12 | try: 13 | with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: 14 | long_description = '\n' + f.read() 15 | except FileNotFoundError: 16 | long_description = "" 17 | 18 | package_name = "bgfx-python" 19 | version = "2.0.1" 20 | cmake_args = [] 21 | 22 | if sys.platform == 'darwin': 23 | plat_name = skbuild_plat_name() 24 | sep = [pos for pos, char in enumerate(plat_name) if char == '-'] 25 | assert len(sep) == 2 26 | cmake_args.extend(('-DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=' + plat_name[sep[0] + 1:sep[1]], 27 | '-DCMAKE_OSX_ARCHITECTURES:STRING=' + plat_name[sep[1] + 1:])) 28 | 29 | setup( 30 | name=package_name, 31 | version=version, 32 | description='Python wrapper for BGFX Library', 33 | author='Federico Bertola', 34 | url='https://github.com/fbertola/bgfx-python', 35 | packages=['pybgfx'], 36 | cmake_source_dir="src", 37 | cmake_args=cmake_args, 38 | long_description=long_description, 39 | long_description_content_type='text/markdown', 40 | python_requires=">=3.7.0", 41 | include_package_data=True, 42 | zip_safe=False, 43 | license='BSD', 44 | install_requires=[ 45 | 'cppyy', 46 | 'clang', 47 | 'loguru' 48 | ], 49 | classifiers=[ 50 | 'License :: OSI Approved :: BSD License', 51 | 'Intended Audience :: Developers', 52 | 'Operating System :: OS Independent', 53 | 'Programming Language :: Python', 54 | 'Programming Language :: Python :: 3', 55 | 'Programming Language :: Python :: 3.7', 56 | 'Programming Language :: Python :: 3.8', 57 | 'Programming Language :: Python :: 3.9', 58 | 'Programming Language :: Python :: Implementation :: CPython', 59 | 'Programming Language :: Python :: Implementation :: PyPy', 60 | 'Topic :: Multimedia :: Graphics' 61 | ], 62 | ) 63 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(bgfx_python) 2 | cmake_minimum_required(VERSION 3.6.1) 3 | 4 | set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules") 5 | execute_process( 6 | COMMAND cling-config --cmake 7 | OUTPUT_VARIABLE CPPYY_MODULE_PATH 8 | OUTPUT_STRIP_TRAILING_WHITESPACE) 9 | 10 | include(FindCppyy) 11 | 12 | message(STATUS "CPPYY_FOUND = ${Cppyy_FOUND}") 13 | 14 | set(BX_DIR 15 | "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/bx" 16 | CACHE PATH "BX dir" FORCE) 17 | set(BIMG_DIR 18 | "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/bimg" 19 | CACHE PATH "BIMG dir" FORCE) 20 | set(BGFX_DIR 21 | "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/bgfx" 22 | CACHE PATH "BGFX dir" FORCE) 23 | set(IMGUI_DIR 24 | "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/bgfx/3rdparty/dear-imgui" 25 | CACHE PATH "IMGUI dir" FORCE) 26 | set(3RDPARTY_DIR 27 | "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/bgfx/3rdparty" 28 | CACHE PATH "3RDPARTY dir" FORCE) 29 | set(EXAMPLES_COMMON_DIR 30 | "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/bgfx/examples/common" 31 | CACHE PATH "EXAMPLES_COMMON dir" FORCE) 32 | 33 | if(APPLE) 34 | set(BGFX_BUILD_DIR osx-x64) 35 | set(CLING_LIB_SUFFIX ".so") 36 | elseif(WIN32) 37 | set(BGFX_BUILD_DIR win64_vs2017) 38 | set(BGFX_BUILD_PROJ_DIR vs2017) 39 | set(CMAKE_STATIC_LIBRARY_PREFIX "") 40 | set(CLING_LIB_SUFFIX ".lib") 41 | else() 42 | set(BGFX_BUILD_DIR linux64_gcc) 43 | set(CLING_LIB_SUFFIX ".so") 44 | endif() 45 | 46 | message(STATUS "BX_DIR = ${BX_DIR}") 47 | message(STATUS "BIMG_DIR = ${BIMG_DIR}") 48 | message(STATUS "BGFX_DIR = ${BGFX_DIR}") 49 | 50 | string(TOLOWER ${CMAKE_BUILD_TYPE} GENIE_BUILD_TYPE) 51 | 52 | if(APPLE) 53 | set(DIST_COMMAND osx-x64-${GENIE_BUILD_TYPE}) 54 | set(SDKROOT /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk) 55 | set(LINKER_OPTIONS 56 | "-framework Cocoa;-framework QuartzCore;-framework OpenGL;-weak_framework Metal;-weak_framework MetalKit;-Wl,-U,__main_" 57 | ) 58 | elseif(WIN32) 59 | #include(FindWindowsSDK) 60 | set(LINKER_OPTIONS "d3d12.lib;d3d11.lib;dxgi.lib;psapi.lib;d3dcompiler.lib;/FORCE:UNRESOLVED;/FORCE:MULTIPLE;") 61 | set(COMPILER_OPTIONS 62 | "/D__STDC_LIMIT_MACROS;/D__STDC_FORMAT_MACROS;/D__STDC_CONSTANT_MACROS;/D_HAS_EXCEPTIONS=0;/D_CRT_SECURE_NO_WARNINGS" 63 | ) 64 | else() 65 | set(DIST_COMMAND linux-${GENIE_BUILD_TYPE}64) 66 | set(LINKER_OPTIONS "-lGL;-lGLU;-lglut;-lpthread;-lrt;-ldl;-Wl,--start-group;-Wl,--undefined,__main_") 67 | endif() 68 | 69 | if(DEFINED ENV{MANYLINUX_BUILD}) 70 | set(GENIE_FOLDER "/genie") 71 | else() 72 | set(GENIE_FOLDER "${BX_DIR}/tools") 73 | endif() 74 | 75 | if(WIN32) 76 | #set(MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") 77 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ") 78 | 79 | execute_process(COMMAND ${GENIE_FOLDER}/bin/windows/genie --with-tools --with-shared-lib ${BGFX_BUILD_PROJ_DIR} 80 | WORKING_DIRECTORY ${BGFX_DIR}) 81 | 82 | execute_process(COMMAND cmd /c ${CMAKE_CURRENT_SOURCE_DIR}/scripts/rename_runtime.bat 83 | "${BGFX_DIR}/.build/projects/${BGFX_BUILD_PROJ_DIR}" COMMAND_ECHO STDOUT) 84 | 85 | execute_process(COMMAND msbuild bgfx.sln /p:Configuration=${CMAKE_BUILD_TYPE} 86 | WORKING_DIRECTORY "${BGFX_DIR}/.build/projects/${BGFX_BUILD_PROJ_DIR}") 87 | else() 88 | if(APPLE) 89 | execute_process(COMMAND ${GENIE_FOLDER}/bin/darwin/genie --with-tools --with-shared-lib --gcc=osx-x64 gmake 90 | WORKING_DIRECTORY ${BGFX_DIR}) 91 | else() 92 | execute_process(COMMAND ${GENIE_FOLDER}/bin/linux/genie --with-tools --with-shared-lib --gcc=linux-gcc gmake 93 | WORKING_DIRECTORY ${BGFX_DIR}) 94 | endif() 95 | 96 | execute_process(COMMAND make -e ${DIST_COMMAND} CFLAGS+="-fPIC" WORKING_DIRECTORY ${BGFX_DIR}) 97 | endif() 98 | 99 | if(NOT WIN32) 100 | set(CMAKE_MACOSX_RPATH OFF) 101 | set(CMAKE_SKIP_BUILD_RPATH FALSE) 102 | set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) 103 | # set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 104 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 105 | 106 | file(COPY "${Cppyy_DIR}/lib/libCling${CLING_LIB_SUFFIX}" DESTINATION "/tmp/lib") 107 | file(COPY "${Cppyy_DIR}/lib/libCoreLegacy${CLING_LIB_SUFFIX}" DESTINATION "/tmp/lib") 108 | 109 | set(Cppyy_DIR "/tmp") 110 | endif() 111 | 112 | string( 113 | CONCAT 114 | BGFX_LIBRARIES 115 | "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/${CMAKE_STATIC_LIBRARY_PREFIX}bimg_encode${CMAKE_BUILD_TYPE}${CMAKE_STATIC_LIBRARY_SUFFIX};" 116 | "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/${CMAKE_STATIC_LIBRARY_PREFIX}bimg_decode${CMAKE_BUILD_TYPE}${CMAKE_STATIC_LIBRARY_SUFFIX};" 117 | "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/${CMAKE_STATIC_LIBRARY_PREFIX}example-common${CMAKE_BUILD_TYPE}${CMAKE_STATIC_LIBRARY_SUFFIX};" 118 | "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/${CMAKE_STATIC_LIBRARY_PREFIX}bx${CMAKE_BUILD_TYPE}${CMAKE_STATIC_LIBRARY_SUFFIX};" 119 | "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/${CMAKE_STATIC_LIBRARY_PREFIX}bimg${CMAKE_BUILD_TYPE}${CMAKE_STATIC_LIBRARY_SUFFIX};" 120 | "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/${CMAKE_STATIC_LIBRARY_PREFIX}bgfx${CMAKE_BUILD_TYPE}${CMAKE_STATIC_LIBRARY_SUFFIX}") 121 | 122 | string( 123 | CONCAT 124 | CPPYY_LIBRARIES 125 | "${Cppyy_DIR}/lib/libCling${CLING_LIB_SUFFIX};" 126 | "${Cppyy_DIR}/lib/libCoreLegacy${CLING_LIB_SUFFIX}") 127 | 128 | string( 129 | CONCAT INCLUDE_DIRS 130 | "${BX_DIR}/include;" 131 | "${BIMG_DIR}/include;" 132 | "${BGFX_DIR}/include;" 133 | "${BGFX_DIR}/include/bgfx;" 134 | "${IMGUI_DIR};" 135 | "${EXAMPLES_COMMON_DIR};" 136 | "${3RDPARTY_DIR};" 137 | "${CMAKE_CURRENT_SOURCE_DIR}/extras;") 138 | 139 | if(WIN32) 140 | string(CONCAT INCLUDE_DIRS "${BX_DIR}/include/compat/msvc;" "${INCLUDE_DIRS}") 141 | endif() 142 | 143 | string( 144 | CONCAT H_DIRS 145 | "${BGFX_DIR}/include;" 146 | "${BX_DIR}/include;" 147 | "${BGFX_DIR}/include/bgfx;" 148 | "${IMGUI_DIR};" 149 | "${3RDPARTY_DIR};" 150 | "${EXAMPLES_COMMON_DIR};" 151 | "${CMAKE_CURRENT_SOURCE_DIR}/extras;") 152 | 153 | string(CONCAT H_FILES "bgfx.h;" "bgfx/platform.h;" "imgui.h;" "imgui/imgui.h;" "bgfx_extra.h;" "imgui_extra.h") 154 | 155 | if(DEFINED ENV{MANYLINUX_BUILD}) 156 | file(COPY "${Cppyy_DIR}/lib/libCling${CLING_LIB_SUFFIX}" DESTINATION "/usr/lib") 157 | file(COPY "${Cppyy_DIR}/lib/libCoreLegacy${CLING_LIB_SUFFIX}" DESTINATION "/usr/lib") 158 | endif() 159 | 160 | # cmake-format: off 161 | cppyy_add_bindings( 162 | "bgfx_python" 163 | LANGUAGE_STANDARD "17" 164 | TARGET_DIR "pybgfx" 165 | INCLUDE_DIRS ${INCLUDE_DIRS} 166 | COMPILE_OPTIONS ${COMPILER_OPTIONS} 167 | LINK_OPTIONS ${LINKER_OPTIONS} 168 | LINK_LIBRARIES ${BGFX_LIBRARIES} 169 | CPPYY_LIBRARIES ${CPPYY_LIBRARIES} 170 | EXTRA_CODES "${CMAKE_CURRENT_SOURCE_DIR}/extras/imgui_extra.cpp;${CMAKE_CURRENT_SOURCE_DIR}/extras/bgfx_extra.cpp;" 171 | H_DIRS ${H_DIRS} 172 | H_FILES ${H_FILES} 173 | ) 174 | # cmake-format: on 175 | 176 | install(FILES "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/shaderc${CMAKE_BUILD_TYPE}${CMAKE_EXECUTABLE_SUFFIX}" 177 | DESTINATION "pybgfx/bin") 178 | install(FILES "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/geometryc${CMAKE_BUILD_TYPE}${CMAKE_EXECUTABLE_SUFFIX}" 179 | DESTINATION "pybgfx/bin") 180 | install(FILES "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/geometryv${CMAKE_BUILD_TYPE}${CMAKE_EXECUTABLE_SUFFIX}" 181 | DESTINATION "pybgfx/bin") 182 | install(FILES "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/texturec${CMAKE_BUILD_TYPE}${CMAKE_EXECUTABLE_SUFFIX}" 183 | DESTINATION "pybgfx/bin") 184 | install(FILES "${BGFX_DIR}/.build/${BGFX_BUILD_DIR}/bin/texturev${CMAKE_BUILD_TYPE}${CMAKE_EXECUTABLE_SUFFIX}" 185 | DESTINATION "pybgfx/bin") 186 | 187 | file(GLOB bgfx_headers "${BGFX_DIR}/include/bgfx/*.h") 188 | install(FILES ${bgfx_headers} DESTINATION "pybgfx/include/bgfx") 189 | 190 | file(GLOB bx_headers "${BX_DIR}/include/bx/*.h") 191 | install(FILES ${bx_headers} DESTINATION "pybgfx/include/bx") 192 | 193 | file(GLOB bx_inline_headers "${BX_DIR}/include/bx/inline/*.inl") 194 | install(FILES ${bx_inline_headers} DESTINATION "pybgfx/include/bx/inline") 195 | 196 | file(GLOB tinystl_headers "${BX_DIR}/include/tinystl/*.h") 197 | install(FILES ${tinystl_headers} DESTINATION "pybgfx/include/tinystl") 198 | 199 | file(GLOB bimg_headers "${BIMG_DIR}/include/bimg/*.h") 200 | install(FILES ${bimg_headers} DESTINATION "pybgfx/include/bimg") 201 | 202 | file(GLOB bgfx_examples_common_headers "${BGFX_DIR}/examples/common/*.h") 203 | install(FILES ${bgfx_examples_common_headers} DESTINATION "pybgfx/include/examples/common") 204 | 205 | file(GLOB bgfx_examples_common_inline_headers "${BGFX_DIR}/examples/common/*.inl") 206 | install(FILES ${bgfx_examples_common_inline_headers} DESTINATION "pybgfx/include/examples/common") 207 | 208 | install(FILES "${BGFX_DIR}/src/bgfx_compute.sh" DESTINATION "pybgfx/include/shaders") 209 | install(FILES "${BGFX_DIR}/src/bgfx_shader.sh" DESTINATION "pybgfx/include/shaders") 210 | 211 | file(GLOB imgui_headers "${IMGUI_DIR}/*.h") 212 | file(GLOB imgui_widgets_headers "${IMGUI_DIR}/widgets/*.h") 213 | install(FILES ${imgui_headers} DESTINATION "pybgfx/include/imgui") 214 | install(FILES ${imgui_widgets_headers} DESTINATION "pybgfx/include/imgui/widgets") 215 | 216 | file(GLOB extra_headers "${CMAKE_CURRENT_SOURCE_DIR}/extras/*.h") 217 | install(FILES ${extra_headers} DESTINATION "pybgfx/include/extras") 218 | -------------------------------------------------------------------------------- /src/cmake_modules/ExportAllSymbolsWindows.cmake: -------------------------------------------------------------------------------- 1 | 2 | find_program(LIB_EXECUTABLE NAMES lib.exe REQUIRED) 3 | 4 | function(export_all_symbols_windows target) 5 | set(list_args EXPORT_LINK_LIBRARIES ADDITIONAL_OBJS) 6 | cmake_parse_arguments(ARG "" "" "${list_args}" ${ARGN}) 7 | if(NOT "${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") 8 | message(SEND_ERROR "Unexpected arguments specified '${ARG_UNPARSED_ARGUMENTS}'") 9 | endif() 10 | 11 | # #################################################################################################################### 12 | # 13 | # Extract all OBJs paths from the given libraries. 14 | # 15 | foreach(link_library IN LISTS ARG_EXPORT_LINK_LIBRARIES) 16 | if(NOT EXISTS ${link_library}) 17 | message(ERROR "${link_library} does not exist") 18 | endif() 19 | if(NOT IS_ABSOLUTE ${link_library}) 20 | message(ERROR "${link_library} is not an absolute path") 21 | endif() 22 | 23 | execute_process( 24 | COMMAND ${LIB_EXECUTABLE} /nologo /list ${link_library} 25 | OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/exports.def.tmp 26 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 27 | ) 28 | 29 | file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/exports.def.tmp rel_obj_paths) 30 | 31 | foreach(rel_obj_path IN LISTS rel_obj_paths) 32 | get_filename_component(obj_base_path "${link_library}" DIRECTORY) 33 | get_filename_component(abs_obj_path "${rel_obj_path}" ABSOLUTE BASE_DIR "${obj_base_path}") 34 | file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/exports.def.objs "${abs_obj_path}\n") 35 | endforeach(rel_obj_path) 36 | 37 | message(STATUS "bindir = ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/bgfx_pythonCppyy.dir/extras") 38 | endforeach(link_library) 39 | 40 | foreach(additional_obj IN LISTS ARG_ADDITIONAL_OBJS) 41 | file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/exports.def.objs "${additional_obj}\n") 42 | endforeach(additional_obj) 43 | 44 | add_custom_command( 45 | TARGET ${target} 46 | PRE_LINK 47 | COMMAND ${CMAKE_COMMAND} -E __create_def exports.def exports.def.objs 48 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 49 | ) 50 | 51 | set(EXPORT_DEF_FILE 52 | "${CMAKE_CURRENT_BINARY_DIR}/exports.def" 53 | PARENT_SCOPE) 54 | 55 | endfunction(export_all_symbols_windows) 56 | -------------------------------------------------------------------------------- /src/cmake_modules/FindCppyy.cmake: -------------------------------------------------------------------------------- 1 | get_filename_component(BACKEND_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) 2 | get_filename_component(BACKEND_PREFIX "${BACKEND_PREFIX}" PATH) 3 | if(BACKEND_PREFIX STREQUAL "/") 4 | set(BACKEND_PREFIX "") 5 | endif() 6 | 7 | find_program(Cppyy_EXECUTABLE NAMES rootcling) 8 | 9 | if(CPPYY_MODULE_PATH) 10 | # 11 | # Cppyy_DIR: one level above the installed cppyy cmake module path 12 | # 13 | set(Cppyy_DIR ${CPPYY_MODULE_PATH}/../) 14 | # 15 | # Cppyy_INCLUDE_DIRS: Directory with cppyy H_FILES 16 | # 17 | set(Cppyy_INCLUDE_DIRS ${Cppyy_DIR}/include) 18 | # 19 | # Cppyy_VERSION. 20 | # 21 | find_package(ROOT QUIET REQUIRED PATHS ${CPPYY_MODULE_PATH}) 22 | if(ROOT_FOUND) 23 | set(Cppyy_VERSION ${ROOT_VERSION}) 24 | endif() 25 | endif() 26 | 27 | include(FindPackageHandleStandardArgs) 28 | find_package_handle_standard_args( 29 | Cppyy 30 | REQUIRED_VARS Cppyy_EXECUTABLE Cppyy_DIR Cppyy_INCLUDE_DIRS CPPYY_MODULE_PATH 31 | VERSION_VAR Cppyy_VERSION) 32 | mark_as_advanced(Cppyy_VERSION) 33 | 34 | function(cppyy_add_bindings pkg) 35 | set(simple_args LANGUAGE_STANDARD TARGET_DIR) 36 | set(list_args 37 | IMPORTS 38 | GENERATE_OPTIONS 39 | COMPILE_OPTIONS 40 | INCLUDE_DIRS 41 | LINK_OPTIONS 42 | LINK_LIBRARIES 43 | CPPYY_LIBRARIES 44 | H_DIRS 45 | H_FILES 46 | LINKDEFS 47 | EXTRA_CODES 48 | EXTRA_HEADERS 49 | NAMESPACES) 50 | cmake_parse_arguments(ARG "" "${simple_args}" "${list_args}" ${ARGN}) 51 | if(NOT "${ARG_UNPARSED_ARGUMENTS}" STREQUAL "") 52 | message(SEND_ERROR "Unexpected arguments specified '${ARG_UNPARSED_ARGUMENTS}'") 53 | endif() 54 | string(REGEX MATCH "[^\.]+$" pkg_simplename ${pkg}) 55 | string(REGEX REPLACE "\.?${pkg_simplename}" "" pkg_namespace ${pkg}) 56 | set(pkg_dir ${CMAKE_CURRENT_BINARY_DIR}) 57 | string(REPLACE "." "/" tmp ${pkg}) 58 | set(pkg_dir "${pkg_dir}/${tmp}") 59 | set(lib_name "${pkg_namespace}${pkg_simplename}Cppyy") 60 | set(lib_file ${CMAKE_SHARED_LIBRARY_PREFIX}${lib_name}${CMAKE_SHARED_LIBRARY_SUFFIX}) 61 | set(cpp_file ${CMAKE_CURRENT_BINARY_DIR}/${pkg_simplename}.cpp) 62 | set(pcm_file ${pkg_dir}/${pkg_simplename}_rdict.pcm) 63 | set(rootmap_file ${pkg_dir}/${pkg_simplename}.rootmap) 64 | set(extra_map_file ${pkg_dir}/${pkg_simplename}.map) 65 | 66 | # 67 | # Language standard. 68 | # 69 | if("${ARG_LANGUAGE_STANDARD}" STREQUAL "") 70 | set(ARG_LANGUAGE_STANDARD "14") 71 | endif() 72 | 73 | if("${ARG_TARGET_DIR}" STREQUAL "") 74 | set(ARG_TARGET_DIR ${pkg}) 75 | endif() 76 | 77 | # #################################################################################################################### 78 | # 79 | # Make H_FILES with absolute paths. 80 | # 81 | if("${ARG_H_FILES}" STREQUAL "") 82 | message(SEND_ERROR "No H_FILES specified") 83 | endif() 84 | 85 | if("${ARG_H_DIRS}" STREQUAL "") 86 | set(ARG_H_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) 87 | endif() 88 | 89 | set(tmp) 90 | set(relative_h_files) 91 | foreach(h_file IN LISTS ARG_H_FILES) 92 | list(APPEND relative_h_files ${h_file}) 93 | if(NOT IS_ABSOLUTE ${h_file}) 94 | foreach(h_dir IN LISTS ARG_H_DIRS) 95 | if(EXISTS ${h_dir}/${h_file}) 96 | set(h_file ${h_dir}/${h_file}) 97 | break() 98 | endif() 99 | endforeach(h_dir) 100 | endif() 101 | if(NOT EXISTS ${h_file}) 102 | message(WARNING "H_FILES ${h_file} does not exist") 103 | endif() 104 | list(APPEND tmp ${h_file}) 105 | endforeach(h_file) 106 | set(ARG_H_FILES ${tmp}) 107 | 108 | set(linker_args) 109 | foreach(link_option IN LISTS ARG_LINK_OPTIONS) 110 | list(APPEND linker_args "SHELL:${link_option}") 111 | endforeach() 112 | 113 | set(linker_libraries) 114 | foreach(cppyy_library IN LISTS ARG_CPPYY_LIBRARIES) 115 | list(APPEND linker_libraries "${cppyy_library}") 116 | endforeach() 117 | foreach(additional_library IN LISTS ARG_LINK_LIBRARIES) 118 | list(APPEND linker_libraries "${additional_library}") 119 | endforeach() 120 | 121 | # #################################################################################################################### 122 | # 123 | # Create the linkdef.h file with a line for each h_file. 124 | # 125 | set(out_linkdef ${CMAKE_CURRENT_BINARY_DIR}/linkdef.h) 126 | file(WRITE ${out_linkdef} "/* Per H_FILES entries: */\n") 127 | foreach(h_file IN LISTS ARG_H_FILES) 128 | # 129 | # Doubled-up path separators "//" causes errors in rootcling. 130 | # 131 | string(REGEX REPLACE "/+" "/" h_file ${h_file}) 132 | file(APPEND ${out_linkdef} "#pragma link C++ defined_in ${h_file};\n") 133 | endforeach(h_file) 134 | foreach(h_file IN LISTS ARG_EXTRA_HEADERS) 135 | # 136 | # Doubled-up path separators "//" causes errors in rootcling. 137 | # 138 | string(REGEX REPLACE "/+" "/" h_file ${h_file}) 139 | file(APPEND ${out_linkdef} "#pragma extra_include \"${h_file}\";\n") 140 | endforeach(h_file) 141 | 142 | # 143 | # Append any manually-provided linkdef.h content. 144 | # 145 | set(LINKDEF_EXTRACTS) 146 | string(REPLACE "\\" "\\\\" ARG_LINKDEFS "${ARG_LINKDEFS}") 147 | foreach(in_linkdef IN LISTS ARG_LINKDEFS) 148 | if("${in_linkdef}" STREQUAL "") 149 | continue() 150 | endif() 151 | if(NOT IS_ABSOLUTE "${in_linkdef}" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${in_linkdef}") 152 | set(in_linkdef "${CMAKE_CURRENT_SOURCE_DIR}/${in_linkdef}") 153 | endif() 154 | if(EXISTS "${in_linkdef}") 155 | file(APPEND ${out_linkdef} "/* Copied from ${in_linkdef}: */\n") 156 | file(STRINGS ${in_linkdef} in_linkdef NEWLINE_CONSUME) 157 | else() 158 | file(APPEND ${out_linkdef} "/* Inlined: */\n") 159 | endif() 160 | string(REPLACE "\n" ";" in_linkdef "${in_linkdef}") 161 | foreach(line ${in_linkdef}) 162 | file(APPEND ${out_linkdef} "${line}\n") 163 | endforeach() 164 | list(GET in_linkdef 0 in_linkdef) 165 | list(APPEND LINKDEFS_EXTRACTS ${in_linkdef}) 166 | endforeach(in_linkdef) 167 | # 168 | # Record diagnostics. 169 | # 170 | file(APPEND ${out_linkdef} "//\n// Diagnostics.\n//\n") 171 | foreach(arg IN LISTS simple_args list_args) 172 | if(arg STREQUAL "LINKDEFS") 173 | file(APPEND ${out_linkdef} "// ${arg}=\n") 174 | foreach(in_linkdef IN LISTS LINKDEFS_EXTRACTS) 175 | file(APPEND ${out_linkdef} "// ${in_linkdef}...\n") 176 | endforeach(in_linkdef) 177 | else() 178 | file(APPEND ${out_linkdef} "// ${arg}=${ARG_${arg}}\n") 179 | endif() 180 | endforeach(arg) 181 | # #################################################################################################################### 182 | # 183 | # Set up common args. 184 | # 185 | list(APPEND ARG_GENERATE_OPTIONS "-std=c++${ARG_LANGUAGE_STANDARD}") 186 | foreach(dir ${ARG_H_DIRS} ${ARG_INCLUDE_DIRS}) 187 | list(APPEND ARG_GENERATE_OPTIONS "-I${dir}") 188 | endforeach(dir) 189 | 190 | # 191 | # Set up arguments for rootcling. 192 | # 193 | set(cling_args) 194 | list(APPEND cling_args "-f" ${cpp_file}) 195 | list(APPEND cling_args "-s" ${pkg_simplename}) 196 | list(APPEND cling_args "-rmf" ${rootmap_file} "-rml" ${lib_file}) 197 | foreach(in_pcm IN LISTS ARG_IMPORTS) 198 | # 199 | # Create -m options for any imported .pcm files. 200 | # 201 | list(APPEND cling_args "-m" "${in_pcm}") 202 | endforeach(in_pcm) 203 | list(APPEND cling_args "-cxxflags='${ARG_GENERATE_OPTIONS}'") 204 | 205 | # run rootcling 206 | add_custom_command( 207 | OUTPUT ${cpp_file} ${pcm_file} ${rootmap_file} 208 | COMMAND ${Cppyy_EXECUTABLE} ${cling_args} ${relative_h_files} ${out_linkdef} 209 | WORKING_DIRECTORY ${pkg_dir}) 210 | 211 | # ############## ####################### 212 | find_package(LibClang REQUIRED) 213 | get_filename_component(Cppyygen_EXECUTABLE ${Cppyy_EXECUTABLE} DIRECTORY) 214 | set(Cppyygen_EXECUTABLE ${Cppyygen_EXECUTABLE}/cppyy-generator${CMAKE_EXECUTABLE_SUFFIX}) 215 | 216 | # 217 | # Set up arguments for cppyy-generator. 218 | # 219 | if(${CONDA_ACTIVE}) 220 | set(CLANGDEV_INCLUDE $ENV{CONDA_PREFIX}/lib/clang/${CLANG_VERSION_STRING}/include) 221 | message(STATUS "adding conda clangdev includes to cppyy-generator options (${CLANGDEV_INCLUDE})") 222 | list(APPEND ARG_GENERATE_OPTIONS "-I${CLANGDEV_INCLUDE}") 223 | endif() 224 | 225 | # 226 | # Run cppyy-generator. First check dependencies. 227 | # 228 | set(generator_args) 229 | foreach(arg IN LISTS ARG_GENERATE_OPTIONS) 230 | string(REGEX REPLACE "^-" "\\\\-" arg ${arg}) 231 | list(APPEND generator_args ${arg}) 232 | endforeach() 233 | 234 | add_custom_command( 235 | OUTPUT ${extra_map_file} 236 | COMMAND ${LibClang_PYTHON_EXECUTABLE} ${Cppyygen_EXECUTABLE} --libclang ${LibClang_LIBRARY} --flags 237 | "\"${generator_args}\"" ${extra_map_file} ${ARG_H_FILES} 238 | WORKING_DIRECTORY ${pkg_dir} 239 | DEPENDS ${ARG_H_FILES} 240 | WORKING_DIRECTORY ${pkg_dir}) 241 | 242 | # #################################################################################################################### 243 | 244 | # 245 | # Compile/link. 246 | # 247 | add_library(${lib_name} SHARED ${cpp_file} ${pcm_file} ${rootmap_file} ${extra_map_file} ${ARG_EXTRA_CODES}) 248 | set_target_properties(${lib_name} PROPERTIES LINKER_LANGUAGE CXX) 249 | set_property(TARGET ${lib_name} PROPERTY VERSION ${version}) 250 | set_property(TARGET ${lib_name} PROPERTY CXX_STANDARD ${ARG_LANGUAGE_STANDARD}) 251 | set_property(TARGET ${lib_name} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${pkg_dir}) 252 | 253 | # if (UNIX) set_property(TARGET ${lib_name} PROPERTY LINK_WHAT_YOU_USE TRUE) endif() 254 | 255 | if(WIN32) 256 | include(ExportAllSymbolsWindows) 257 | 258 | string( 259 | CONCAT additional_objs_list 260 | "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${lib_name}.dir/${pkg}.cpp.obj;" 261 | "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${lib_name}.dir/extras/bgfx_extra.cpp.obj;" 262 | "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/${lib_name}.dir/extras/imgui_extra.cpp.obj;") 263 | 264 | export_all_symbols_windows(${lib_name} EXPORT_LINK_LIBRARIES "${ARG_LINK_LIBRARIES};" ADDITIONAL_OBJS 265 | ${additional_objs_list}) 266 | list(APPEND linker_args "/DEF:${EXPORT_DEF_FILE}") 267 | endif() 268 | 269 | target_include_directories(${lib_name} PRIVATE ${Cppyy_INCLUDE_DIRS} ${ARG_INCLUDE_DIRS}) 270 | target_compile_options(${lib_name} PRIVATE ${ARG_COMPILE_OPTIONS}) 271 | 272 | target_link_libraries(${lib_name} PUBLIC ${linker_libraries}) 273 | target_link_options(${lib_name} PUBLIC ${linker_args}) 274 | 275 | if(WIN32) 276 | install(TARGETS ${lib_name} RUNTIME DESTINATION ${ARG_TARGET_DIR}) 277 | else() 278 | install(TARGETS ${lib_name} LIBRARY DESTINATION ${ARG_TARGET_DIR}) 279 | endif() 280 | 281 | install(FILES ${pcm_file} ${rootmap_file} ${extra_map_file} DESTINATION ${ARG_TARGET_DIR}) 282 | 283 | if(CMAKE_STRIP) 284 | if(APPLE) 285 | add_custom_command( 286 | TARGET ${lib_name} 287 | POST_BUILD 288 | COMMAND ${CMAKE_STRIP} -x $) 289 | else() 290 | add_custom_command( 291 | TARGET ${lib_name} 292 | POST_BUILD 293 | COMMAND ${CMAKE_STRIP} -s $) 294 | endif() 295 | endif() 296 | 297 | # For security reasons, delete the build RPATH 298 | if(APPLE) 299 | add_custom_command( 300 | TARGET ${lib_name} 301 | POST_BUILD 302 | COMMAND install_name_tool -delete_rpath /tmp/lib $) 303 | endif() 304 | 305 | endfunction(cppyy_add_bindings) 306 | -------------------------------------------------------------------------------- /src/cmake_modules/FindLibClang.cmake: -------------------------------------------------------------------------------- 1 | # .rst: FindLibClang 2 | # ------------ 3 | # 4 | # Find LibClang 5 | # 6 | # Find LibClang headers and library 7 | # 8 | # :: 9 | # 10 | # LibClang_FOUND - True if libclang is found. LibClang_LIBRARY - Clang library to link against. 11 | # LibClang_VERSION - Version number as a string (e.g. "3.9"). LibClang_PYTHON_EXECUTABLE - Compatible python 12 | # version. 13 | 14 | # 15 | # Python support for clang might not be available for Python3. We need to find what we have. 16 | # 17 | set(LIBCLANG_KNOWN_LLVM_VERSIONS 18 | 12.0.1 19 | 11.1.0_1 20 | 11.1.0 21 | 11.0.0 22 | 9.0.0 23 | 9.0 24 | 9 25 | 8.0.0 26 | 8.0 27 | 8 28 | 7.0.1 29 | 7.0.0 30 | 7.0 31 | 7 32 | 6.0.1 33 | 6.0.0 34 | 6.0 35 | 6 36 | 5.0.2 37 | 5.0.1 38 | 5.0.0 39 | 5.0 40 | 5 41 | 4.0.1 42 | 4.0.0 43 | 4.0 44 | 4 45 | 3.9.1 46 | 3.9.0 47 | 3.9 48 | 3.8.1 49 | 3.8.0 50 | 3.8 51 | 3.7.1 52 | 3.7.0 53 | 3.7 54 | 3.6.2 55 | 3.6.1 56 | 3.6.0 57 | 3.6 58 | 3.5.2 59 | 3.5.1 60 | 3.5.0 61 | 3.5 62 | 3.4.2 63 | 3.4.1 64 | 3.4 65 | 3.3 66 | 3.2 67 | 3.1) 68 | 69 | set(libclang_llvm_header_search_paths) 70 | set(libclang_llvm_lib_search_paths # LLVM Fedora 71 | /usr/lib/llvm) 72 | 73 | foreach(version ${LIBCLANG_KNOWN_LLVM_VERSIONS}) 74 | string(REPLACE "." "" undotted_version "${version}") 75 | list( 76 | APPEND 77 | libclang_llvm_header_search_paths 78 | # LLVM Debian/Ubuntu nightly packages: http://llvm.org/apt/ 79 | "/usr/lib/llvm-${version}/include/" 80 | # LLVM MacPorts 81 | "/opt/local/libexec/llvm-${version}/include" 82 | # LLVM Homebrew 83 | "/usr/local/Cellar/llvm/${version}/include" 84 | # LLVM Homebrew/versions 85 | "/usr/local/lib/llvm-${version}/include" 86 | # FreeBSD ports versions 87 | "/usr/local/llvm${undotted_version}/include" 88 | # Gentoo clang-4 89 | "/usr/lib/llvm/${version}/include") 90 | 91 | list( 92 | APPEND 93 | libclang_llvm_lib_search_paths 94 | # LLVM Debian/Ubuntu nightly packages: http://llvm.org/apt/ 95 | "/usr/lib/llvm-${version}/lib/" 96 | # LLVM MacPorts 97 | "/opt/local/libexec/llvm-${version}/lib" 98 | # LLVM Homebrew 99 | "/usr/local/Cellar/llvm/${version}/lib" 100 | # LLVM Homebrew/versions 101 | "/usr/local/lib/llvm-${version}/lib" 102 | # FreeBSD ports versions 103 | "/usr/local/llvm${undotted_version}/lib" 104 | # Gentoo clang-4 105 | "/usr/lib/llvm/${version}/lib") 106 | endforeach() 107 | 108 | find_path( 109 | LibClang_INCLUDE_DIR clang-c/Index.h 110 | PATHS ${libclang_llvm_header_search_paths} 111 | PATH_SUFFIXES LLVM/include # Windows package from http://llvm.org/releases/ 112 | DOC "The path to the directory that contains clang-c/Index.h") 113 | 114 | find_library( 115 | LibClang_LIBRARY 116 | NAMES # On Windows with MSVC, the import library uses the ".imp" file extension instead of the comon ".lib" 117 | libclang.dll libclang clang 118 | PATHS ${libclang_llvm_lib_search_paths} 119 | PATH_SUFFIXES LLVM/bin # Windows package from http://llvm.org/releases/ 120 | DOC "The file that corresponds to the libclang library.") 121 | 122 | get_filename_component(LibClang_LIBRARY_DIR ${LibClang_LIBRARY} PATH) 123 | 124 | function(_find_libclang_python python_executable) 125 | # 126 | # Prefer python3 explicitly or implicitly over python2. 127 | # 128 | foreach(exe IN ITEMS python3 python python2) 129 | execute_process( 130 | COMMAND ${exe} -c 131 | "from clang.cindex import Config; Config.set_library_file(\"${LibClang_LIBRARY}\"); Config().lib" 132 | ERROR_VARIABLE _stderr 133 | RESULT_VARIABLE _rc 134 | OUTPUT_STRIP_TRAILING_WHITESPACE) 135 | if("${_rc}" STREQUAL "0") 136 | set(pyexe ${exe}) 137 | break() 138 | endif() 139 | endforeach() 140 | set(${python_executable} 141 | "${pyexe}" 142 | PARENT_SCOPE) 143 | endfunction(_find_libclang_python) 144 | 145 | # _find_libclang_python(LibClang_PYTHON_EXECUTABLE) 146 | set(LibClang_PYTHON_EXECUTABLE "python") 147 | if(LibClang_LIBRARY) 148 | set(LibClang_LIBRARY ${LibClang_LIBRARY}) 149 | string(REGEX REPLACE ".*clang-\([0-9]+.[0-9]+\).*" "\\1" LibClang_VERSION_TMP "${LibClang_LIBRARY}") 150 | set(LibClang_VERSION 151 | ${LibClang_VERSION_TMP} 152 | CACHE STRING "LibClang version" FORCE) 153 | endif() 154 | 155 | include(FindPackageHandleStandardArgs) 156 | find_package_handle_standard_args( 157 | LibClang 158 | REQUIRED_VARS LibClang_LIBRARY 159 | VERSION_VAR LibClang_VERSION) 160 | 161 | find_program(CLANG_EXE clang++) 162 | execute_process(COMMAND ${CLANG_EXE} --version OUTPUT_VARIABLE clang_full_version_string) 163 | string(REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION_STRING 164 | "${clang_full_version_string}") 165 | 166 | set(CLANG_VERSION_STRING 167 | ${CLANG_VERSION_STRING} 168 | PARENT_SCOPE) 169 | 170 | mark_as_advanced(LibClang_VERSION) 171 | unset(_filename) 172 | unset(_find_libclang_filename) 173 | 174 | -------------------------------------------------------------------------------- /src/cmake_modules/FindWindowsSDK.cmake: -------------------------------------------------------------------------------- 1 | # * Find the Windows SDK aka Platform SDK 2 | # 3 | # Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK 4 | # 5 | # Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case you just want the tool binaries to run, rather 6 | # than the libraries and headers for compiling. 7 | # 8 | # Variables: WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current 9 | # version of visual studio WINDOWSSDK_LATEST_DIR WINDOWSSDK_LATEST_NAME WINDOWSSDK_FOUND_PREFERENCE - if we found an 10 | # entry indicating a "preferred" SDK listed for this visual studio version WINDOWSSDK_PREFERRED_DIR 11 | # WINDOWSSDK_PREFERRED_NAME 12 | # 13 | # WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first. WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no 14 | # duplicates, ordered with preferred first, followed by the rest in descending recency 15 | # 16 | # Functions: windowssdk_name_lookup( ) - Find the name corresponding with the SDK directory 17 | # you pass in, or NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. 18 | # 19 | # windowssdk_build_lookup( ) - Find the build version number corresponding with the SDK 20 | # directory you pass in, or NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work. 21 | # 22 | # get_windowssdk_from_component( ) - Given a library or include dir, find the Windows SDK 23 | # root dir corresponding to it, or NOTFOUND if unrecognized. 24 | # 25 | # get_windowssdk_library_dirs( ) - Find the architecture-appropriate library directories 26 | # corresponding to the SDK directory you pass in (or NOTFOUND if none) 27 | # 28 | # get_windowssdk_library_dirs_multiple( ...) - Find the architecture-appropriate library 29 | # directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at 30 | # all. Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. 31 | # 32 | # get_windowssdk_include_dirs( ) - Find the include directories corresponding to the SDK 33 | # directory you pass in (or NOTFOUND if none) 34 | # 35 | # get_windowssdk_include_dirs_multiple( ...) - Find the include directories corresponding 36 | # to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all. Good for passing 37 | # WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from. 38 | # 39 | # Requires these CMake modules: FindPackageHandleStandardArgs (known included with CMake >=2.6.2) 40 | # 41 | # Original Author: 2012 Ryan Pavlik http://academic.cleardefinition.com Iowa 42 | # State University HCI Graduate Program/VRAC 43 | # 44 | # Copyright Iowa State University 2012. Distributed under the Boost Software License, Version 1.0. (See accompanying 45 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 46 | 47 | set(_preferred_sdk_dirs) # pre-output 48 | set(_win_sdk_dirs) # pre-output 49 | set(_win_sdk_versanddirs) # pre-output 50 | set(_win_sdk_buildsanddirs) # pre-output 51 | set(_winsdk_vistaonly) # search parameters 52 | set(_winsdk_kits) # search parameters 53 | 54 | set(_WINDOWSSDK_ANNOUNCE OFF) 55 | if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY)) 56 | set(_WINDOWSSDK_ANNOUNCE ON) 57 | endif() 58 | macro(_winsdk_announce) 59 | if(_WINSDK_ANNOUNCE) 60 | message(STATUS ${ARGN}) 61 | endif() 62 | endmacro() 63 | 64 | # See https://developer.microsoft.com/en-us/windows/downloads/sdk-archive - although version numbers listed on that page 65 | # don't necessarily match the directory used by the installer. 66 | set(_winsdk_win10vers 67 | 10.0.18362.0 # Win10 1903 "19H1" 68 | 10.0.17763.0 # Win10 1809 "October 2018 Update" 69 | 10.0.17134.0 # Redstone 4 aka Win10 1803 "April 2018 Update" 70 | 10.0.17133.0 # Redstone 4 aka Win10 1803 "April 2018 Update" 71 | 10.0.16299.0 # Redstone 3 aka Win10 1709 "Fall Creators Update" 72 | 10.0.15063.0 # Redstone 2 aka Win10 1703 "Creators Update" 73 | 10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update" 74 | 10.0.10586.0 # TH2 aka Win10 1511 75 | 10.0.10240.0 # Win10 RTM 76 | 10.0.10150.0 # just ucrt 77 | 10.0.10056.0) 78 | 79 | if(WindowsSDK_FIND_COMPONENTS MATCHES "tools") 80 | set(_WINDOWSSDK_IGNOREMSVC ON) 81 | _winsdk_announce("Checking for tools from Windows/Platform SDKs...") 82 | else() 83 | set(_WINDOWSSDK_IGNOREMSVC OFF) 84 | _winsdk_announce("Checking for Windows/Platform SDKs...") 85 | endif() 86 | 87 | # Appends to the three main pre-output lists used only if the path exists and is not already in the list. 88 | function(_winsdk_conditional_append _vername _build _path) 89 | if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) 90 | # Path invalid - do not add 91 | return() 92 | endif() 93 | list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx) 94 | if(_win_sdk_idx GREATER -1) 95 | # Path already in list - do not add 96 | return() 97 | endif() 98 | _winsdk_announce(" - ${_vername}, Build ${_build} @ ${_path}") 99 | # Not yet in the list, so we'll add it 100 | list(APPEND _win_sdk_dirs "${_path}") 101 | set(_win_sdk_dirs 102 | "${_win_sdk_dirs}" 103 | CACHE INTERNAL "" FORCE) 104 | list(APPEND _win_sdk_versanddirs "${_vername}" "${_path}") 105 | set(_win_sdk_versanddirs 106 | "${_win_sdk_versanddirs}" 107 | CACHE INTERNAL "" FORCE) 108 | list(APPEND _win_sdk_buildsanddirs "${_build}" "${_path}") 109 | set(_win_sdk_buildsanddirs 110 | "${_win_sdk_buildsanddirs}" 111 | CACHE INTERNAL "" FORCE) 112 | endfunction() 113 | 114 | # Appends to the "preferred SDK" lists only if the path exists 115 | function(_winsdk_conditional_append_preferred _info _path) 116 | if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}")) 117 | # Path invalid - do not add 118 | return() 119 | endif() 120 | 121 | get_filename_component(_path "${_path}" ABSOLUTE) 122 | 123 | list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx) 124 | if(_win_sdk_idx GREATER -1) 125 | # Path already in list - do not add 126 | return() 127 | endif() 128 | _winsdk_announce(" - Found \"preferred\" SDK ${_info} @ ${_path}") 129 | # Not yet in the list, so we'll add it 130 | list(APPEND _win_sdk_preferred_sdk_dirs "${_path}") 131 | set(_win_sdk_preferred_sdk_dirs 132 | "${_win_sdk_dirs}" 133 | CACHE INTERNAL "" FORCE) 134 | 135 | # Just in case we somehow missed it: 136 | _winsdk_conditional_append("${_info}" "" "${_path}") 137 | endfunction() 138 | 139 | # Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs". If the given version might be in 140 | # both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows and 141 | # HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits", use this macro first, since 142 | # these registry keys usually have more information. 143 | # 144 | # Pass a "default" build number as an extra argument in case we can't find it. 145 | function(_winsdk_check_microsoft_sdks_registry _winsdkver) 146 | set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}") 147 | get_filename_component(_sdkdir "[${SDKKEY};InstallationFolder]" ABSOLUTE) 148 | 149 | set(_sdkname "Windows SDK ${_winsdkver}") 150 | 151 | # Default build number passed as extra argument 152 | set(_build ${ARGN}) 153 | # See if the registry holds a Microsoft-mutilated, err, designated, product name (just using get_filename_component to 154 | # execute the registry lookup) 155 | get_filename_component(_sdkproductname "[${SDKKEY};ProductName]" NAME) 156 | if(NOT "${_sdkproductname}" MATCHES "registry") 157 | # Got a product name 158 | set(_sdkname "${_sdkname} (${_sdkproductname})") 159 | endif() 160 | 161 | # try for a version to augment our name (just using get_filename_component to execute the registry lookup) 162 | get_filename_component(_sdkver "[${SDKKEY};ProductVersion]" NAME) 163 | if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES) 164 | # Got a version 165 | if(NOT "${_sdkver}" MATCHES "\\.\\.") 166 | # and it's not an invalid one with two dots in it: use to override the default build 167 | set(_build ${_sdkver}) 168 | if(NOT "${_sdkname}" MATCHES "${_sdkver}") 169 | # Got a version that's not already in the name, let's use it to improve our name. 170 | set(_sdkname "${_sdkname} (${_sdkver})") 171 | endif() 172 | endif() 173 | endif() 174 | _winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}") 175 | endfunction() 176 | 177 | # Given a name for identification purposes, the build number, and a key (technically a "value name") corresponding to a 178 | # Windows SDK packaged as a "Windows Kit", look for it in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows 179 | # Kits\\Installed Roots Note that the key or "value name" tends to be something weird like KitsRoot81 - no easy way to 180 | # predict, just have to observe them in the wild. Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for 181 | # these: sometimes you get keys in both parts of the registry (in the wow64 portion especially), and the non-"Windows 182 | # Kits" location is often more descriptive. 183 | function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key) 184 | get_filename_component( 185 | _sdkdir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]" ABSOLUTE) 186 | _winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}") 187 | endfunction() 188 | 189 | # Given a name for identification purposes and the build number corresponding to a Windows 10 SDK packaged as a "Windows 190 | # Kit", look for it in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots Doesn't hurt to also try 191 | # _winsdk_check_microsoft_sdks_registry for these: sometimes you get keys in both parts of the registry (in the wow64 192 | # portion especially), and the non-"Windows Kits" location is often more descriptive. 193 | function(_winsdk_check_win10_kits _winkit_build) 194 | get_filename_component(_sdkdir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" 195 | ABSOLUTE) 196 | if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}")) 197 | return() # not found 198 | endif() 199 | if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um") 200 | _winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}") 201 | endif() 202 | endfunction() 203 | 204 | # Given a name for indentification purposes, the build number, and the associated package GUID, look in the registry 205 | # under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\ for that guid and the SDK it points 206 | # to. 207 | function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid) 208 | foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER) 209 | get_filename_component( 210 | _sdkdir "[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]" 211 | ABSOLUTE) 212 | _winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}") 213 | endforeach() 214 | endfunction() 215 | 216 | # 217 | # Detect toolchain information: to know whether it's OK to use Vista+ only SDKs 218 | # 219 | set(_winsdk_vistaonly_ok OFF) 220 | if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC) 221 | # VC 10 and older has broad target support 222 | if(MSVC_VERSION LESS 1700) 223 | # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+ 224 | elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp") 225 | # This is the XP-compatible v110+ toolset 226 | elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90") 227 | # This is the VS2010/VS2008 toolset 228 | else() 229 | # OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset. These versions have no XP (and 230 | # possibly Vista pre-SP1) support 231 | set(_winsdk_vistaonly_ok ON) 232 | if(_WINDOWSSDK_ANNOUNCE AND NOT _WINDOWSSDK_VISTAONLY_PESTERED) 233 | set(_WINDOWSSDK_VISTAONLY_PESTERED 234 | ON 235 | CACHE INTERNAL "" FORCE) 236 | message( 237 | STATUS 238 | "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!" 239 | ) 240 | endif() 241 | endif() 242 | endif() 243 | if(_WINDOWSSDK_IGNOREMSVC) 244 | set(_winsdk_vistaonly_ok ON) 245 | endif() 246 | 247 | # 248 | # MSVC version checks - keeps messy conditionals in one place (messy because of _WINDOWSSDK_IGNOREMSVC) 249 | # 250 | set(_winsdk_msvc_greater_1200 OFF) 251 | if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200))) 252 | set(_winsdk_msvc_greater_1200 ON) 253 | endif() 254 | # Newer than VS .NET/VS Toolkit 2003 255 | set(_winsdk_msvc_greater_1310 OFF) 256 | if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310))) 257 | set(_winsdk_msvc_greater_1310 ON) 258 | endif() 259 | 260 | # VS2005/2008 261 | set(_winsdk_msvc_less_1600 OFF) 262 | if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600))) 263 | set(_winsdk_msvc_less_1600 ON) 264 | endif() 265 | 266 | # VS2013+ 267 | set(_winsdk_msvc_not_less_1800 OFF) 268 | if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800))) 269 | set(_winsdk_msvc_not_less_1800 ON) 270 | endif() 271 | 272 | # 273 | # START body of find module 274 | # 275 | if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 276 | # 277 | # Look for "preferred" SDKs 278 | # 279 | 280 | # Environment variable for SDK dir 281 | if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) 282 | _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") 283 | endif() 284 | 285 | if(_winsdk_msvc_less_1600) 286 | # Per-user current Windows SDK for VS2005/2008 287 | get_filename_component( 288 | _sdkdir "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" ABSOLUTE) 289 | _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") 290 | 291 | # System-wide current Windows SDK for VS2005/2008 292 | get_filename_component( 293 | _sdkdir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" ABSOLUTE) 294 | _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") 295 | endif() 296 | 297 | # 298 | # Begin the massive list of SDK searching! 299 | # 300 | if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) 301 | # These require at least Visual Studio 2013 (VC12) 302 | 303 | _winsdk_check_microsoft_sdks_registry(v10.0A) 304 | 305 | # Windows Software Development Kit (SDK) for Windows 10 Several different versions living in the same directory - if 306 | # nothing else we can assume RTM (10240) 307 | _winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0) 308 | foreach(_win10build ${_winsdk_win10vers}) 309 | _winsdk_check_win10_kits(${_win10build}) 310 | endforeach() 311 | endif() # vista-only and 2013+ 312 | 313 | # Included in Visual Studio 2013 Includes the v120_xp toolset 314 | _winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636) 315 | 316 | if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800) 317 | # Windows Software Development Kit (SDK) for Windows 8.1 http://msdn.microsoft.com/en-gb/windows/desktop/bg162891 318 | _winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0) 319 | _winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81) 320 | endif() # vista-only and 2013+ 321 | 322 | if(_winsdk_vistaonly_ok) 323 | # Included in Visual Studio 2012 324 | _winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727) 325 | 326 | # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5 This is the first version to also include the DirectX 327 | # SDK http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx 328 | _winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384) 329 | _winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot) 330 | endif() # vista-only 331 | 332 | # Included with VS 2012 Update 1 or later Introduces v110_xp toolset 333 | _winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106) 334 | if(_winsdk_vistaonly_ok) 335 | # Microsoft Windows SDK for Windows 7 and .NET Framework 4 336 | # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b 337 | _winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514) 338 | endif() # vista-only 339 | 340 | # Included with VS 2010 341 | _winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385) 342 | 343 | # Windows SDK for Windows 7 and .NET Framework 3.5 SP1 Works with VC9 344 | # http://www.microsoft.com/en-us/download/details.aspx?id=18950 345 | _winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385) 346 | 347 | # Two versions call themselves "v6.1": Older: Windows Vista Update & .NET 3.0 SDK 348 | # http://www.microsoft.com/en-us/download/details.aspx?id=14477 349 | 350 | # Newer: Windows Server 2008 & .NET 3.5 SDK may have broken VS9SP1? they recommend v7.0 instead, or a KB... 351 | # http://www.microsoft.com/en-us/download/details.aspx?id=24826 352 | _winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10) 353 | 354 | # Included in VS 2008 355 | _winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1) 356 | 357 | # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components 358 | # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx 359 | _winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384) 360 | endif() 361 | 362 | # Let's not forget the Platform SDKs, which sometimes are useful! 363 | if(_winsdk_msvc_greater_1200) 364 | _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" 365 | "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1") 366 | _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" 367 | "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3") 368 | endif() 369 | # 370 | # Finally, look for "preferred" SDKs 371 | # 372 | if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003 373 | 374 | # Environment variable for SDK dir 375 | if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL "")) 376 | _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}") 377 | endif() 378 | 379 | if(_winsdk_msvc_less_1600) 380 | # Per-user current Windows SDK for VS2005/2008 381 | get_filename_component( 382 | _sdkdir "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" ABSOLUTE) 383 | _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}") 384 | 385 | # System-wide current Windows SDK for VS2005/2008 386 | get_filename_component( 387 | _sdkdir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" ABSOLUTE) 388 | _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}") 389 | endif() 390 | endif() 391 | 392 | function(windowssdk_name_lookup _dir _outvar) 393 | list(FIND _win_sdk_versanddirs "${_dir}" _diridx) 394 | math(EXPR _idx "${_diridx} - 1") 395 | if(${_idx} GREATER -1) 396 | list(GET _win_sdk_versanddirs ${_idx} _ret) 397 | else() 398 | set(_ret "NOTFOUND") 399 | endif() 400 | set(${_outvar} 401 | "${_ret}" 402 | PARENT_SCOPE) 403 | endfunction() 404 | 405 | function(windowssdk_build_lookup _dir _outvar) 406 | list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx) 407 | math(EXPR _idx "${_diridx} - 1") 408 | if(${_idx} GREATER -1) 409 | list(GET _win_sdk_buildsanddirs ${_idx} _ret) 410 | else() 411 | set(_ret "NOTFOUND") 412 | endif() 413 | set(${_outvar} 414 | "${_ret}" 415 | PARENT_SCOPE) 416 | endfunction() 417 | 418 | # If we found something... 419 | if(_win_sdk_dirs) 420 | list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR) 421 | windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}" WINDOWSSDK_LATEST_NAME) 422 | set(WINDOWSSDK_DIRS ${_win_sdk_dirs}) 423 | 424 | # Fallback, in case no preference found. 425 | set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}") 426 | set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}") 427 | set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS}) 428 | set(WINDOWSSDK_FOUND_PREFERENCE OFF) 429 | endif() 430 | 431 | # If we found indications of a user preference... 432 | if(_win_sdk_preferred_sdk_dirs) 433 | list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR) 434 | windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}" WINDOWSSDK_PREFERRED_NAME) 435 | set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${_win_sdk_preferred_sdk_dirs} ${_win_sdk_dirs}) 436 | list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS) 437 | set(WINDOWSSDK_FOUND_PREFERENCE ON) 438 | endif() 439 | 440 | include(FindPackageHandleStandardArgs) 441 | find_package_handle_standard_args(WindowsSDK "No compatible version of the Windows SDK or Platform SDK found." 442 | WINDOWSSDK_DIRS) 443 | 444 | if(WINDOWSSDK_FOUND) 445 | # Internal: Architecture-appropriate library directory names. 446 | if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM") 447 | if(CMAKE_SIZEOF_VOID_P MATCHES "8") 448 | # Only supported in Win10 SDK and up. 449 | set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture 450 | else() 451 | set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs 452 | set(_winsdk_arch arm) # what the architecture used to be called 453 | set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture 454 | endif() 455 | else() 456 | if(CMAKE_SIZEOF_VOID_P MATCHES "8") 457 | set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs 458 | set(_winsdk_arch amd64) # what the architecture used to be called 459 | set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture 460 | else() 461 | set(_winsdk_archbare) # what the architecture used to be called in oldest SDKs 462 | set(_winsdk_arch i386) # what the architecture used to be called 463 | set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture 464 | endif() 465 | endif() 466 | 467 | function(get_windowssdk_from_component _component _var) 468 | get_filename_component(_component "${_component}" ABSOLUTE) 469 | file(TO_CMAKE_PATH "${_component}" _component) 470 | foreach(_sdkdir ${WINDOWSSDK_DIRS}) 471 | get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE) 472 | string(LENGTH "${_sdkdir}" _sdklen) 473 | file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}") 474 | # If we don't have any "parent directory" items... 475 | if(NOT "${_rel}" MATCHES "[.][.]") 476 | set(${_var} 477 | "${_sdkdir}" 478 | PARENT_SCOPE) 479 | return() 480 | endif() 481 | endforeach() 482 | # Fail. 483 | set(${_var} 484 | "NOTFOUND" 485 | PARENT_SCOPE) 486 | endfunction() 487 | function(get_windowssdk_library_dirs _winsdk_dir _var) 488 | set(_dirs) 489 | set(_suffixes 490 | "lib${_winsdk_archbare}" # SDKs like 7.1A 491 | "lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir 492 | "lib/w2k/${_winsdk_arch}" # Win2k min requirement 493 | "lib/wxp/${_winsdk_arch}" # WinXP min requirement 494 | "lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement 495 | "lib/wlh/${_winsdk_arch}" 496 | "lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement 497 | "lib/win7/${_winsdk_arch}" 498 | "lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement 499 | ) 500 | foreach( 501 | _ver 502 | wlh # Win Vista ("Long Horn") min requirement 503 | win7 # Win 7 min requirement 504 | win8 # Win 8 min requirement 505 | winv6.3 # Win 8.1 min requirement 506 | ) 507 | 508 | list(APPEND _suffixes "lib/${_ver}/${_winsdk_arch}" "lib/${_ver}/um/${_winsdk_arch8}" 509 | "lib/${_ver}/km/${_winsdk_arch8}") 510 | endforeach() 511 | 512 | # Look for WDF libraries in Win10+ SDK 513 | foreach(_mode umdf kmdf) 514 | file( 515 | GLOB _wdfdirs 516 | RELATIVE "${_winsdk_dir}" 517 | "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*") 518 | if(_wdfdirs) 519 | list(APPEND _suffixes ${_wdfdirs}) 520 | endif() 521 | endforeach() 522 | 523 | # Look in each Win10+ SDK version for the components 524 | foreach(_win10ver ${_winsdk_win10vers}) 525 | foreach(_component um km ucrt mmos) 526 | list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}") 527 | endforeach() 528 | endforeach() 529 | 530 | foreach(_suffix ${_suffixes}) 531 | # Check to see if a library actually exists here. 532 | file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib") 533 | if(_libs) 534 | list(APPEND _dirs "${_winsdk_dir}/${_suffix}") 535 | endif() 536 | endforeach() 537 | if("${_dirs}" STREQUAL "") 538 | set(_dirs NOTFOUND) 539 | else() 540 | list(REMOVE_DUPLICATES _dirs) 541 | endif() 542 | set(${_var} 543 | ${_dirs} 544 | PARENT_SCOPE) 545 | endfunction() 546 | function(get_windowssdk_include_dirs _winsdk_dir _var) 547 | set(_dirs) 548 | 549 | set(_subdirs 550 | shared 551 | um 552 | winrt 553 | km 554 | wdf 555 | mmos 556 | ucrt) 557 | set(_suffixes Include) 558 | 559 | foreach(_dir ${_subdirs}) 560 | list(APPEND _suffixes "Include/${_dir}") 561 | endforeach() 562 | 563 | foreach(_ver ${_winsdk_win10vers}) 564 | foreach(_dir ${_subdirs}) 565 | list(APPEND _suffixes "Include/${_ver}/${_dir}") 566 | endforeach() 567 | endforeach() 568 | 569 | foreach(_suffix ${_suffixes}) 570 | # Check to see if a header file actually exists here. 571 | file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h") 572 | if(_headers) 573 | list(APPEND _dirs "${_winsdk_dir}/${_suffix}") 574 | endif() 575 | endforeach() 576 | if("${_dirs}" STREQUAL "") 577 | set(_dirs NOTFOUND) 578 | else() 579 | list(REMOVE_DUPLICATES _dirs) 580 | endif() 581 | set(${_var} 582 | ${_dirs} 583 | PARENT_SCOPE) 584 | endfunction() 585 | function(get_windowssdk_library_dirs_multiple _var) 586 | set(_dirs) 587 | foreach(_sdkdir ${ARGN}) 588 | get_windowssdk_library_dirs("${_sdkdir}" _current_sdk_libdirs) 589 | if(_current_sdk_libdirs) 590 | list(APPEND _dirs ${_current_sdk_libdirs}) 591 | endif() 592 | endforeach() 593 | if("${_dirs}" STREQUAL "") 594 | set(_dirs NOTFOUND) 595 | else() 596 | list(REMOVE_DUPLICATES _dirs) 597 | endif() 598 | set(${_var} 599 | ${_dirs} 600 | PARENT_SCOPE) 601 | endfunction() 602 | function(get_windowssdk_include_dirs_multiple _var) 603 | set(_dirs) 604 | foreach(_sdkdir ${ARGN}) 605 | get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs) 606 | if(_current_sdk_libdirs) 607 | list(APPEND _dirs ${_current_sdk_incdirs}) 608 | endif() 609 | endforeach() 610 | if("${_dirs}" STREQUAL "") 611 | set(_dirs NOTFOUND) 612 | else() 613 | list(REMOVE_DUPLICATES _dirs) 614 | endif() 615 | set(${_var} 616 | ${_dirs} 617 | PARENT_SCOPE) 618 | endfunction() 619 | endif() 620 | -------------------------------------------------------------------------------- /src/extras/bgfx_extra.cpp: -------------------------------------------------------------------------------- 1 | #include "bgfx_extra.h" 2 | 3 | #include 4 | 5 | 6 | bx::DefaultAllocator default_allocator; 7 | bx::AllocatorI * allocator = & default_allocator; 8 | 9 | 10 | Mesh* meshLoadInternal(const char* _filePath, bool _ramcopy) 11 | { 12 | bx::FileReaderI* reader = BX_NEW(allocator, bx::FileReader); 13 | if (bx::open(reader, _filePath) ) 14 | { 15 | Mesh* mesh = new Mesh; 16 | mesh->load(reader, _ramcopy); 17 | bx::close(reader); 18 | return mesh; 19 | } 20 | BX_DELETE(allocator, reader); 21 | return NULL; 22 | } 23 | 24 | Mesh* _MeshLoader::load(const char* _filePath, bool _ramcopy) 25 | { 26 | return meshLoadInternal(_filePath, _ramcopy); 27 | } 28 | 29 | void _MeshLoader::destroy(Mesh* _mesh) 30 | { 31 | _mesh->unload(); 32 | delete _mesh; 33 | } 34 | -------------------------------------------------------------------------------- /src/extras/bgfx_extra.h: -------------------------------------------------------------------------------- 1 | #ifndef BGFX_EXTRA_H_HEADER_GUARD 2 | #define BGFX_EXTRA_H_HEADER_GUARD 3 | 4 | #include 5 | #include 6 | #include 7 | #include "bounds.h" 8 | #include 9 | #include 10 | 11 | 12 | struct MeshState 13 | { 14 | struct Texture 15 | { 16 | uint32_t m_flags; 17 | bgfx::UniformHandle m_sampler; 18 | bgfx::TextureHandle m_texture; 19 | uint8_t m_stage; 20 | }; 21 | 22 | Texture m_textures[4]; 23 | uint64_t m_state; 24 | bgfx::ProgramHandle m_program; 25 | uint8_t m_numTextures; 26 | bgfx::ViewId m_viewId; 27 | }; 28 | 29 | struct Primitive 30 | { 31 | uint32_t m_startIndex; 32 | uint32_t m_numIndices; 33 | uint32_t m_startVertex; 34 | uint32_t m_numVertices; 35 | 36 | Sphere m_sphere; 37 | Aabb m_aabb; 38 | Obb m_obb; 39 | }; 40 | 41 | typedef tinystl::vector PrimitiveArray; 42 | 43 | struct Group 44 | { 45 | Group(); 46 | void reset(); 47 | 48 | bgfx::VertexBufferHandle m_vbh; 49 | bgfx::IndexBufferHandle m_ibh; 50 | uint16_t m_numVertices; 51 | uint8_t* m_vertices; 52 | uint32_t m_numIndices; 53 | uint16_t* m_indices; 54 | Sphere m_sphere; 55 | Aabb m_aabb; 56 | Obb m_obb; 57 | PrimitiveArray m_prims; 58 | }; 59 | typedef tinystl::vector GroupArray; 60 | 61 | struct Mesh 62 | { 63 | void load(bx::ReaderSeekerI* _reader, bool _ramcopy); 64 | void unload(); 65 | void submit(bgfx::ViewId _id, bgfx::ProgramHandle _program, const float* _mtx, uint64_t _state) const; 66 | void submit(const MeshState*const* _state, uint8_t _numPasses, const float* _mtx, uint16_t _numMatrices) const; 67 | 68 | bgfx::VertexLayout m_layout; 69 | GroupArray m_groups; 70 | }; 71 | 72 | struct _MeshLoader 73 | { 74 | Mesh* load(const char* _filePath, bool _ramcopy); 75 | void destroy(Mesh* _mesh); 76 | }; 77 | 78 | #endif // BGFX_EXTRA_H_HEADER_GUARD 79 | -------------------------------------------------------------------------------- /src/extras/imgui_extra.cpp: -------------------------------------------------------------------------------- 1 | #include "imgui_extra.h" 2 | 3 | 4 | void _ImGuiExtra::create(float _fontSize) { 5 | imguiCreate(_fontSize, NULL); 6 | } 7 | 8 | void _ImGuiExtra::destroy() { 9 | imguiDestroy(); 10 | } 11 | 12 | void _ImGuiExtra::begin_frame(int32_t _mx, int32_t _my, uint8_t _button, int32_t _scroll, uint16_t _width, uint16_t _height, int _inputChar, bgfx::ViewId _view) { 13 | imguiBeginFrame(_mx, _my, _button, _scroll, _width, _height, _inputChar, _view); 14 | } 15 | 16 | void _ImGuiExtra::end_frame() { 17 | imguiEndFrame(); 18 | } 19 | -------------------------------------------------------------------------------- /src/extras/imgui_extra.h: -------------------------------------------------------------------------------- 1 | #ifndef IMGUI_EXTRA_H_HEADER_GUARD 2 | #define IMGUI_EXTRA_H_HEADER_GUARD 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class _ImGuiExtra { 9 | public: 10 | //ImguiExtra() : {} 11 | void create(float _fontSize = 18.0f); 12 | void destroy(); 13 | 14 | void begin_frame(int32_t _mx, int32_t _my, uint8_t _button, int32_t _scroll, uint16_t _width, uint16_t _height, int _inputChar = -1, bgfx::ViewId _view = 255); 15 | void end_frame(); 16 | }; 17 | 18 | #endif // IMGUI_EXTRA_H_HEADER_GUARD -------------------------------------------------------------------------------- /src/scripts/rename_runtime.bat: -------------------------------------------------------------------------------- 1 | @powershell -Command "dir -Path %1 -Recurse -Filter *.vcxproj | ForEach-Object { (Get-Content -Path $_.FullName) -replace 'MultiThreaded', 'MultiThreadedDLL' | Set-Content $_.FullName }" 2 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbertola/bgfx-python/b22e45fb880d06aab5833a9edc4a2bf8b212a9fb/tests/__init__.py -------------------------------------------------------------------------------- /tests/osmesa_context.py: -------------------------------------------------------------------------------- 1 | # noinspection PyPackageRequirements 2 | import ctypes 3 | import sys 4 | 5 | # noinspection PyUnresolvedReferences 6 | from bgfx import as_void_ptr, bgfx 7 | import glfw 8 | 9 | # noinspection PyProtectedMember 10 | from glfw import _glfw as glfw_native 11 | 12 | 13 | class OSMesaContext(object): 14 | def __init__(self, width, height, title): 15 | self.title = title 16 | self.height = height 17 | self.width = width 18 | self.ctx = None 19 | self.window = None 20 | 21 | def init(self, platform_data): 22 | pass 23 | 24 | def shutdown(self): 25 | pass 26 | 27 | def update(self, dt): 28 | pass 29 | 30 | def resize(self, width, height): 31 | pass 32 | 33 | # noinspection PyMethodMayBeStatic 34 | def get_mouse_state(self): 35 | return 0, 0, 0 36 | 37 | # noinspection PyProtectedMember 38 | def run(self): 39 | glfw.init() 40 | 41 | glfw.window_hint(glfw.CLIENT_API, glfw.OPENGL_API) 42 | glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 2) 43 | glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) 44 | glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) 45 | glfw.window_hint(glfw.CONTEXT_CREATION_API, glfw.OSMESA_CONTEXT_API) 46 | 47 | self.window = glfw.create_window( 48 | self.width, self.height, self.title, None, None 49 | ) 50 | 51 | handle, display = None, None 52 | 53 | if sys.platform == "linux": 54 | glfw_native.glfwGetX11Window.argtypes = [ctypes.POINTER(glfw._GLFWwindow)] 55 | glfw_native.glfwGetX11Window.restype = ctypes.c_void_p 56 | handle = glfw_native.glfwGetX11Window(self.window) 57 | display = glfw_native.glfwGetX11Display() 58 | 59 | glfw.make_context_current(self.window) 60 | 61 | data = bgfx.PlatformData() 62 | data.ndt = as_void_ptr(display) 63 | data.nwh = as_void_ptr(handle) 64 | data.context = as_void_ptr(glfw.get_os_mesa_context(self.window)) 65 | data.back_buffer = None 66 | data.back_buffer_ds = None 67 | 68 | self.init(data) 69 | 70 | for _ in range(0, 10): 71 | self.update(1.0) 72 | 73 | self.shutdown() 74 | glfw.terminate() 75 | -------------------------------------------------------------------------------- /tests/test_examples.py: -------------------------------------------------------------------------------- 1 | from examples.cubes.cubes import Cubes 2 | from examples.helloworld.helloworld import HelloWorld 3 | from examples.mesh.mesh import MeshExample 4 | 5 | from tests.osmesa_context import OSMesaContext 6 | 7 | 8 | # This test suite use OSMesa to perform rendering on devices that does not 9 | # have a GPU. Paired with XVFB, this will allow to test the library 10 | # loading and the basic rendering calls. 11 | 12 | 13 | def test_helloworld_example(): 14 | HelloWorld.__bases__ = (OSMesaContext,) 15 | test = HelloWorld(1280, 720, "Test") 16 | test.run() 17 | 18 | 19 | def test_cubes_example(): 20 | Cubes.__bases__ = (OSMesaContext,) 21 | test = Cubes(1280, 720, "Test") 22 | test.run() 23 | 24 | 25 | def test_mesh_example(): 26 | MeshExample.__bases__ = (OSMesaContext,) 27 | test = MeshExample(1280, 720, "Test") 28 | test.run() 29 | --------------------------------------------------------------------------------