filly 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. filly-0.1.0/.github/workflows/wheels.yml +135 -0
  2. filly-0.1.0/.gitignore +10 -0
  3. filly-0.1.0/CMakeLists.txt +95 -0
  4. filly-0.1.0/LICENSE +21 -0
  5. filly-0.1.0/NOTES.md +8 -0
  6. filly-0.1.0/PKG-INFO +159 -0
  7. filly-0.1.0/README.md +133 -0
  8. filly-0.1.0/docs/explanation/assumptions.md +343 -0
  9. filly-0.1.0/docs/explanation/design.md +695 -0
  10. filly-0.1.0/docs/explanation/material-precompilation.md +1208 -0
  11. filly-0.1.0/docs/explanation/web.md +162 -0
  12. filly-0.1.0/docs/how-to/build.md +322 -0
  13. filly-0.1.0/docs/how-to/gl-hosts.md +255 -0
  14. filly-0.1.0/docs/how-to/profile.md +337 -0
  15. filly-0.1.0/docs/how-to/psychopy.md +276 -0
  16. filly-0.1.0/docs/how-to/reference-comparison.md +238 -0
  17. filly-0.1.0/docs/how-to/stress-test.md +91 -0
  18. filly-0.1.0/docs/how-to/web.md +231 -0
  19. filly-0.1.0/docs/images/README.md +48 -0
  20. filly-0.1.0/docs/images/amber-orthographic.png +0 -0
  21. filly-0.1.0/docs/images/amber-perspective.png +0 -0
  22. filly-0.1.0/docs/images/horse.gif +0 -0
  23. filly-0.1.0/docs/images/horse.png +0 -0
  24. filly-0.1.0/docs/images/iridescence-environment.png +0 -0
  25. filly-0.1.0/docs/images/iridescence-studio.png +0 -0
  26. filly-0.1.0/docs/reference/api.md +1236 -0
  27. filly-0.1.0/docs/reference/performance.md +483 -0
  28. filly-0.1.0/docs/reference/sample-assets.csv +151 -0
  29. filly-0.1.0/docs/reference/sample-assets.md +204 -0
  30. filly-0.1.0/docs/reference/validation.md +791 -0
  31. filly-0.1.0/docs/tutorials/offscreen.md +68 -0
  32. filly-0.1.0/examples/assets/ATTRIBUTION.md +14 -0
  33. filly-0.1.0/examples/assets/wooden_playground_horse.glb +0 -0
  34. filly-0.1.0/examples/drifting_grating.py +120 -0
  35. filly-0.1.0/examples/moderngl_shared.py +31 -0
  36. filly-0.1.0/examples/psychopy_shared.py +234 -0
  37. filly-0.1.0/examples/psychopy_stress.py +236 -0
  38. filly-0.1.0/examples/pyglet_shared.py +132 -0
  39. filly-0.1.0/examples/screenshot.py +167 -0
  40. filly-0.1.0/examples/shapes.py +92 -0
  41. filly-0.1.0/examples/stereo.py +101 -0
  42. filly-0.1.0/examples/zengl_shared.py +33 -0
  43. filly-0.1.0/native/animation.inc +258 -0
  44. filly-0.1.0/native/archive_materials.cpp +396 -0
  45. filly-0.1.0/native/bindings.cpp +716 -0
  46. filly-0.1.0/native/egl_platform.cpp +332 -0
  47. filly-0.1.0/native/egl_platform.h +64 -0
  48. filly-0.1.0/native/engine_config.h +36 -0
  49. filly-0.1.0/native/features.inc +847 -0
  50. filly-0.1.0/native/gl_interop.cpp +405 -0
  51. filly-0.1.0/native/gl_interop.h +55 -0
  52. filly-0.1.0/native/gl_interop_web.cpp +121 -0
  53. filly-0.1.0/native/gltf_prepare.cpp +1973 -0
  54. filly-0.1.0/native/gltf_prepare.h +240 -0
  55. filly-0.1.0/native/json.cpp +247 -0
  56. filly-0.1.0/native/json.h +49 -0
  57. filly-0.1.0/native/libwebp.cmake +35 -0
  58. filly-0.1.0/native/materials/check_refraction.cmake +21 -0
  59. filly-0.1.0/native/materials/diffuse_transmission.mat.in +156 -0
  60. filly-0.1.0/native/materials/embed.cmake +16 -0
  61. filly-0.1.0/native/materials/encode.mat.in +70 -0
  62. filly-0.1.0/native/materials/fxaa.mat +87 -0
  63. filly-0.1.0/native/materials/materials.cmake +256 -0
  64. filly-0.1.0/native/materials/output.cmake +56 -0
  65. filly-0.1.0/native/materials/specular_glossiness.mat.in +68 -0
  66. filly-0.1.0/native/materials/surface.mat.in +202 -0
  67. filly-0.1.0/native/materials/unlit.mat.in +40 -0
  68. filly-0.1.0/native/materials.h +26 -0
  69. filly-0.1.0/native/memory.inc +88 -0
  70. filly-0.1.0/native/output_pass.cpp +37 -0
  71. filly-0.1.0/native/output_pass.h +20 -0
  72. filly-0.1.0/native/refraction.h +57 -0
  73. filly-0.1.0/native/renderer.cpp +2749 -0
  74. filly-0.1.0/native/renderer.h +554 -0
  75. filly-0.1.0/native/resources.inc +455 -0
  76. filly-0.1.0/native/shapes.cpp +140 -0
  77. filly-0.1.0/native/slots.inc +295 -0
  78. filly-0.1.0/native/vendor/cgltf/LICENSE +7 -0
  79. filly-0.1.0/native/vendor/cgltf/README.md +8 -0
  80. filly-0.1.0/native/vendor/cgltf/cgltf.h +7175 -0
  81. filly-0.1.0/native/vendor/meshoptimizer/LICENSE.md +21 -0
  82. filly-0.1.0/native/vendor/meshoptimizer/README.md +9 -0
  83. filly-0.1.0/native/vendor/meshoptimizer/indexcodec.cpp +688 -0
  84. filly-0.1.0/native/vendor/meshoptimizer/meshoptimizer.h +1447 -0
  85. filly-0.1.0/native/vendor/meshoptimizer/vertexcodec.cpp +1910 -0
  86. filly-0.1.0/native/vendor/meshoptimizer/vertexfilter.cpp +1493 -0
  87. filly-0.1.0/native/webp_provider.cpp +153 -0
  88. filly-0.1.0/native/webp_provider.h +9 -0
  89. filly-0.1.0/pyproject.toml +41 -0
  90. filly-0.1.0/spec.md +1285 -0
  91. filly-0.1.0/src/filly/__init__.py +43 -0
  92. filly-0.1.0/src/filly/_memory.py +111 -0
  93. filly-0.1.0/src/filly/_stress.py +46 -0
  94. filly-0.1.0/src/filly/benchmark.py +64 -0
  95. filly-0.1.0/src/filly/integrations/__init__.py +1 -0
  96. filly-0.1.0/src/filly/integrations/_host.py +156 -0
  97. filly-0.1.0/src/filly/integrations/moderngl.py +72 -0
  98. filly-0.1.0/src/filly/integrations/psychopy.py +182 -0
  99. filly-0.1.0/src/filly/integrations/pyglet.py +87 -0
  100. filly-0.1.0/src/filly/integrations/zengl.py +80 -0
  101. filly-0.1.0/src/filly/samples/ATTRIBUTION.md +11 -0
  102. filly-0.1.0/src/filly/samples/__init__.py +14 -0
  103. filly-0.1.0/src/filly/samples/suzanne.glb +0 -0
  104. filly-0.1.0/tests/conftest.py +90 -0
  105. filly-0.1.0/tests/data/README.md +22 -0
  106. filly-0.1.0/tests/data/green.ktx2 +0 -0
  107. filly-0.1.0/tests/data/green.webp +0 -0
  108. filly-0.1.0/tests/data/quadrants.webp +0 -0
  109. filly-0.1.0/tests/test_animation_pointer.py +349 -0
  110. filly-0.1.0/tests/test_camera_aspect.py +104 -0
  111. filly-0.1.0/tests/test_clone.py +269 -0
  112. filly-0.1.0/tests/test_controls.py +234 -0
  113. filly-0.1.0/tests/test_effects.py +177 -0
  114. filly-0.1.0/tests/test_encoding.py +502 -0
  115. filly-0.1.0/tests/test_features.py +570 -0
  116. filly-0.1.0/tests/test_framing.py +237 -0
  117. filly-0.1.0/tests/test_gl_hosts.py +617 -0
  118. filly-0.1.0/tests/test_gltf_surface_camera.py +338 -0
  119. filly-0.1.0/tests/test_headless.py +106 -0
  120. filly-0.1.0/tests/test_host_texture.py +148 -0
  121. filly-0.1.0/tests/test_interop.py +308 -0
  122. filly-0.1.0/tests/test_iridescence_dielectric.py +44 -0
  123. filly-0.1.0/tests/test_large_scene.py +121 -0
  124. filly-0.1.0/tests/test_lifecycle.py +212 -0
  125. filly-0.1.0/tests/test_light_pointer.py +87 -0
  126. filly-0.1.0/tests/test_lighting.py +144 -0
  127. filly-0.1.0/tests/test_logging.py +29 -0
  128. filly-0.1.0/tests/test_material_limits.py +161 -0
  129. filly-0.1.0/tests/test_material_paths.py +236 -0
  130. filly-0.1.0/tests/test_mesh.py +243 -0
  131. filly-0.1.0/tests/test_native_imports.py +30 -0
  132. filly-0.1.0/tests/test_native_preparation.py +117 -0
  133. filly-0.1.0/tests/test_node_tree.py +95 -0
  134. filly-0.1.0/tests/test_psychopy.py +352 -0
  135. filly-0.1.0/tests/test_refraction.py +211 -0
  136. filly-0.1.0/tests/test_render_calls.py +133 -0
  137. filly-0.1.0/tests/test_renderer.py +281 -0
  138. filly-0.1.0/tests/test_rendering_options.py +313 -0
  139. filly-0.1.0/tests/test_samples.py +44 -0
  140. filly-0.1.0/tests/test_scene_extensions.py +265 -0
  141. filly-0.1.0/tests/test_stress.py +36 -0
  142. filly-0.1.0/tests/test_textures.py +412 -0
  143. filly-0.1.0/tests/test_volume.py +94 -0
  144. filly-0.1.0/tests/test_web.py +310 -0
  145. filly-0.1.0/tests/web/api.html +355 -0
  146. filly-0.1.0/tests/web/handover.html +264 -0
  147. filly-0.1.0/tests/web/package-lock.json +923 -0
  148. filly-0.1.0/tests/web/package.json +9 -0
  149. filly-0.1.0/tests/web/run_page.mjs +58 -0
  150. filly-0.1.0/tools/benchmark_refraction.py +79 -0
  151. filly-0.1.0/tools/benchmark_uploads.py +94 -0
  152. filly-0.1.0/tools/build_filament_linux.py +141 -0
  153. filly-0.1.0/tools/build_filament_web.sh +109 -0
  154. filly-0.1.0/tools/build_filly_web.sh +44 -0
  155. filly-0.1.0/tools/check_native_imports.py +150 -0
  156. filly-0.1.0/tools/check_sample_assets.py +294 -0
  157. filly-0.1.0/tools/ci_linux.sh +11 -0
  158. filly-0.1.0/tools/compare_reference.py +357 -0
  159. filly-0.1.0/tools/fetch_filament.py +41 -0
  160. filly-0.1.0/tools/make_suzanne.py +95 -0
  161. filly-0.1.0/tools/profile_frame.py +1105 -0
  162. filly-0.1.0/tools/profile_matrix.py +201 -0
  163. filly-0.1.0/tools/profile_rdc_replay.py +182 -0
  164. filly-0.1.0/tools/profile_tracy.py +326 -0
  165. filly-0.1.0/web/CMakeLists.txt +85 -0
  166. filly-0.1.0/web/bindings.cpp +589 -0
  167. filly-0.1.0/web/filly.js +1386 -0
  168. filly-0.1.0/web/gl_tracking.js +61 -0
@@ -0,0 +1,135 @@
1
+ name: Build wheels
2
+
3
+ # Every run builds and tests the wheels and the sdist. A pushed tag vX.Y.Z whose version matches
4
+ # pyproject.toml also publishes them to PyPI. A manual run can publish to TestPyPI instead, to
5
+ # rehearse a release. Publishing uses PyPI trusted publishing: no token is stored here.
6
+ on:
7
+ workflow_dispatch:
8
+ inputs:
9
+ testpypi:
10
+ description: Publish the build to TestPyPI
11
+ type: boolean
12
+ default: false
13
+ pull_request:
14
+ push:
15
+ branches: [main, master]
16
+ tags: ['v*']
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ concurrency:
22
+ group: wheels-${{ github.workflow }}-${{ github.ref }}
23
+ cancel-in-progress: true
24
+
25
+ jobs:
26
+ wheels:
27
+ name: ${{ matrix.os }} wheels
28
+ runs-on: ${{ matrix.os }}
29
+ timeout-minutes: 90
30
+ strategy:
31
+ fail-fast: false
32
+ matrix:
33
+ os: [ubuntu-24.04, windows-2022]
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: actions/setup-python@v5
37
+ with:
38
+ python-version: '3.12'
39
+ - name: Cache Linux SDK
40
+ if: runner.os == 'Linux'
41
+ uses: actions/cache@v4
42
+ with:
43
+ path: .deps/filament-linux
44
+ key: filament-linux-x86_64-manylinux228-${{ hashFiles('tools/build_filament_linux.py', 'tools/ci_linux.sh') }}
45
+ - name: Cache Windows SDK
46
+ if: runner.os == 'Windows'
47
+ uses: actions/cache@v4
48
+ with:
49
+ path: .deps
50
+ key: filament-windows-x86_64-${{ hashFiles('tools/fetch_filament.py') }}
51
+ - name: Build, repair, audit, and test wheels
52
+ uses: pypa/cibuildwheel@v4.2.1
53
+ env:
54
+ CIBW_BUILD: 'cp310-* cp311-* cp312-* cp313-* cp314-*'
55
+ CIBW_SKIP: '*-musllinux* *-win32 *-win_arm64'
56
+ CIBW_ARCHS_LINUX: x86_64
57
+ CIBW_ARCHS_WINDOWS: AMD64
58
+ CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
59
+ CIBW_BEFORE_ALL_LINUX: bash {package}/tools/ci_linux.sh
60
+ CIBW_BEFORE_ALL_WINDOWS: python {package}/tools/fetch_filament.py
61
+ CIBW_ENVIRONMENT_LINUX: 'CC=clang CXX=clang++ CMAKE_ARGS="-DFILAMENT_ROOT=/project/.deps/filament-linux" LIBGL_ALWAYS_SOFTWARE=1'
62
+ CIBW_TEST_REQUIRES: 'pytest pillow pyglet==1.4.11'
63
+ CIBW_TEST_COMMAND_LINUX: 'timeout 600 xvfb-run -a python -m pytest {project}/tests -q -m "not psychopy" -o faulthandler_timeout=60'
64
+ # Hosted Windows runners do not supply a reliable OpenGL rendering device.
65
+ CIBW_TEST_COMMAND_WINDOWS: 'python -m pytest {project}/tests/test_stress.py {project}/tests/test_native_imports.py -q'
66
+ - name: Check extension imports
67
+ shell: bash
68
+ run: python tools/check_native_imports.py wheelhouse/*.whl
69
+ - uses: actions/upload-artifact@v4
70
+ with:
71
+ name: wheels-${{ matrix.os }}
72
+ path: wheelhouse/*.whl
73
+ if-no-files-found: error
74
+
75
+ sdist:
76
+ name: sdist
77
+ runs-on: ubuntu-24.04
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ - uses: actions/setup-python@v5
81
+ with:
82
+ python-version: '3.12'
83
+ - name: Check that the tag matches the version
84
+ if: startsWith(github.ref, 'refs/tags/v')
85
+ shell: python
86
+ run: |
87
+ import os, tomllib
88
+ with open("pyproject.toml", "rb") as file:
89
+ version = tomllib.load(file)["project"]["version"]
90
+ tag = os.environ["GITHUB_REF_NAME"]
91
+ if tag != f"v{version}":
92
+ raise SystemExit(f"Tag {tag} does not match version {version} in pyproject.toml")
93
+ - name: Build the sdist
94
+ run: pipx run build --sdist
95
+ - uses: actions/upload-artifact@v4
96
+ with:
97
+ name: sdist
98
+ path: dist/*.tar.gz
99
+ if-no-files-found: error
100
+
101
+ publish:
102
+ name: Publish to PyPI
103
+ needs: [wheels, sdist]
104
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
105
+ runs-on: ubuntu-24.04
106
+ environment:
107
+ name: pypi
108
+ url: https://pypi.org/p/filly
109
+ permissions:
110
+ id-token: write
111
+ steps:
112
+ - uses: actions/download-artifact@v4
113
+ with:
114
+ path: dist
115
+ merge-multiple: true
116
+ - uses: pypa/gh-action-pypi-publish@release/v1
117
+
118
+ publish-testpypi:
119
+ name: Publish to TestPyPI
120
+ needs: [wheels, sdist]
121
+ if: github.event_name == 'workflow_dispatch' && inputs.testpypi
122
+ runs-on: ubuntu-24.04
123
+ environment:
124
+ name: testpypi
125
+ url: https://test.pypi.org/p/filly
126
+ permissions:
127
+ id-token: write
128
+ steps:
129
+ - uses: actions/download-artifact@v4
130
+ with:
131
+ path: dist
132
+ merge-multiple: true
133
+ - uses: pypa/gh-action-pypi-publish@release/v1
134
+ with:
135
+ repository-url: https://test.pypi.org/legacy/
filly-0.1.0/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ .venv/
2
+ .deps/
3
+ build/
4
+ dist/
5
+ __pycache__/
6
+ .pytest_cache/
7
+ *.egg-info/
8
+ *.pyd
9
+ *.so
10
+ tests/web/node_modules/
@@ -0,0 +1,95 @@
1
+ cmake_minimum_required(VERSION 3.28...3.31)
2
+ project(filly VERSION 0.1.0 LANGUAGES CXX)
3
+
4
+ find_package(Python 3.10 REQUIRED COMPONENTS Interpreter Development.Module OPTIONAL_COMPONENTS Development.SABIModule)
5
+ find_package(nanobind CONFIG REQUIRED)
6
+
7
+ set(FILAMENT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/.deps" CACHE PATH "Filament 1.77.1 SDK directory")
8
+ if(NOT EXISTS "${FILAMENT_ROOT}/include/filament/Engine.h")
9
+ message(FATAL_ERROR "Filament SDK missing. See docs/how-to/build.md for the platform SDK and FILAMENT_ROOT.")
10
+ endif()
11
+
12
+ if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8 OR NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|amd64|x86_64)$"
13
+ OR NOT (WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux"))
14
+ message(FATAL_ERROR "Supported targets are Windows and Linux x86_64.")
15
+ endif()
16
+ if(WIN32)
17
+ # Hybrid CRT: static C++ runtime and vcruntime, dynamic UCRT (see the link options below).
18
+ # Python ships no msvcp140.dll, and a host process that loaded an older one first (MATLAB,
19
+ # Qt applications) can crash code built with a newer toolset. This applies to nanobind and
20
+ # libwebp too, because both are built as targets of this project.
21
+ set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
22
+ set(FILAMENT_LIB_DIR "${FILAMENT_ROOT}/lib/x86_64/mt")
23
+ else()
24
+ set(FILAMENT_LIB_DIR "${FILAMENT_ROOT}/lib/x86_64")
25
+ # Keep the system GL dispatch library external to manylinux wheels.
26
+ set(OpenGL_GL_PREFERENCE LEGACY)
27
+ find_package(OpenGL REQUIRED)
28
+ find_package(X11 REQUIRED)
29
+ find_package(Threads REQUIRED)
30
+ endif()
31
+ set(FILAMENT_LIBRARIES gltfio_core filament-iblprefilter filament backend filabridge filaflat
32
+ geometry ibl utils bluegl smol-v stb dracodec meshoptimizer
33
+ mikktspace uberzlib zstd basis_transcoder ktxreader image abseil)
34
+ if(WIN32)
35
+ list(APPEND FILAMENT_LIBRARIES bluevk)
36
+ endif()
37
+ foreach(name IN LISTS FILAMENT_LIBRARIES)
38
+ add_library(filament_sdk_${name} STATIC IMPORTED)
39
+ set_target_properties(filament_sdk_${name} PROPERTIES
40
+ IMPORTED_LOCATION "${FILAMENT_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
41
+ list(APPEND FILAMENT_LINK_TARGETS filament_sdk_${name})
42
+ endforeach()
43
+
44
+ include(native/libwebp.cmake)
45
+
46
+ # The output-pass materials and the material archive are embedded as C arrays.
47
+ enable_language(C)
48
+ set(FILLY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
49
+ include(native/materials/output.cmake)
50
+
51
+ # glTF materials come from filly's precompiled material archive (native/materials), built here
52
+ # with the SDK's matc and uberz. The module has no material compiler. See
53
+ # docs/explanation/material-precompilation.md.
54
+ include(native/materials/materials.cmake)
55
+
56
+ add_library(filly_core STATIC native/renderer.cpp native/output_pass.cpp native/gl_interop.cpp native/archive_materials.cpp
57
+ native/gltf_prepare.cpp native/json.cpp native/shapes.cpp native/webp_provider.cpp native/egl_platform.cpp
58
+ native/vendor/meshoptimizer/vertexcodec.cpp native/vendor/meshoptimizer/indexcodec.cpp
59
+ native/vendor/meshoptimizer/vertexfilter.cpp)
60
+ target_compile_features(filly_core PUBLIC cxx_std_20)
61
+ target_link_libraries(filly_core PRIVATE filly_output_materials filly_material_archive)
62
+ set_target_properties(filly_core PROPERTIES POSITION_INDEPENDENT_CODE ON)
63
+ target_include_directories(filly_core PUBLIC native PRIVATE "${FILAMENT_ROOT}/include" "${libwebp_SOURCE_DIR}/src")
64
+ target_link_libraries(filly_core PRIVATE webpdecoder)
65
+ if(MSVC)
66
+ target_compile_options(filly_core PRIVATE /Zc:__cplusplus /bigobj /EHsc)
67
+ target_link_libraries(filly_core PRIVATE ${FILAMENT_LINK_TARGETS} opengl32 gdi32 user32 shlwapi ws2_32)
68
+ else()
69
+ # Filament's static archives contain circular references.
70
+ target_link_libraries(filly_core PRIVATE -Wl,--start-group ${FILAMENT_LINK_TARGETS} -Wl,--end-group
71
+ OpenGL::GL X11::X11 Threads::Threads ${CMAKE_DL_LIBS})
72
+ target_compile_options(filly_core PRIVATE -fvisibility=hidden)
73
+ endif()
74
+
75
+ nanobind_add_module(_native STABLE_ABI NOSTRIP native/bindings.cpp)
76
+ target_link_libraries(_native PRIVATE filly_core)
77
+ if(MSVC)
78
+ # The UCRT is part of Windows 10 and later, and one shared copy keeps a single heap and
79
+ # locale state per process. The static runtime objects request libucrt.lib by default.
80
+ target_link_options(_native PRIVATE /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib)
81
+ else()
82
+ # Filament marks its public API visible, and the C++ template instantiations are visible
83
+ # regardless of -fvisibility. Exported, they could bind to another copy of Filament, libwebp,
84
+ # or a different libstdc++ build in the process, so only the module entry point is exported.
85
+ set(FILLY_EXPORTS "${CMAKE_CURRENT_BINARY_DIR}/_native.map")
86
+ file(WRITE "${FILLY_EXPORTS}" "{\n global: PyInit__native;\n local: *;\n};\n")
87
+ target_link_options(_native PRIVATE "LINKER:--version-script=${FILLY_EXPORTS}")
88
+ set_property(TARGET _native APPEND PROPERTY LINK_DEPENDS "${FILLY_EXPORTS}")
89
+ endif()
90
+ install(TARGETS _native LIBRARY DESTINATION filly RUNTIME DESTINATION filly)
91
+ install(FILES "${FILAMENT_ROOT}/LICENSE" DESTINATION filly/licenses RENAME Filament.txt)
92
+ install(FILES native/vendor/meshoptimizer/LICENSE.md DESTINATION filly/licenses RENAME meshoptimizer.txt)
93
+ install(FILES native/vendor/cgltf/LICENSE DESTINATION filly/licenses RENAME cgltf.txt)
94
+ install(FILES "${libwebp_SOURCE_DIR}/COPYING" DESTINATION filly/licenses RENAME libwebp.txt)
95
+ install(FILES "${libwebp_SOURCE_DIR}/PATENTS" DESTINATION filly/licenses RENAME libwebp-PATENTS.txt)
filly-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alex Forrence
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
filly-0.1.0/NOTES.md ADDED
@@ -0,0 +1,8 @@
1
+ Misc things
2
+ - ~~psychopy frequently operates in floats, even for window sizes. Accept floats
3
+ for SharedTarget and coerce to ints?~~ Done: target sizes accept integral floats;
4
+ fractional or non-finite values raise ValueError.
5
+ - KHR_xmp_json_ld?
6
+ - Feels like wheel was reinvented unnecessarily, e.g. some of the custom shaders?
7
+ - FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB seems awkward for user
8
+
filly-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.4
2
+ Name: filly
3
+ Version: 0.1.0
4
+ Summary: A Python 3D renderer for glTF scenes, built on Google Filament
5
+ Author: Alex Forrence
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Project-URL: Homepage, https://github.com/aforren1/filly
9
+ Project-URL: Documentation, https://github.com/aforren1/filly#readme
10
+ Project-URL: Issues, https://github.com/aforren1/filly/issues
11
+ Requires-Python: >=3.10
12
+ Requires-Dist: numpy>=1.24
13
+ Provides-Extra: examples
14
+ Requires-Dist: Pillow>=10; extra == "examples"
15
+ Provides-Extra: psychopy
16
+ Requires-Dist: psychopy-lib==2026.2.4; extra == "psychopy"
17
+ Provides-Extra: pyglet
18
+ Requires-Dist: pyglet>=1.4.11; extra == "pyglet"
19
+ Provides-Extra: moderngl
20
+ Requires-Dist: pyglet>=1.4.11; extra == "moderngl"
21
+ Requires-Dist: moderngl>=5.12; extra == "moderngl"
22
+ Provides-Extra: zengl
23
+ Requires-Dist: pyglet>=1.4.11; extra == "zengl"
24
+ Requires-Dist: zengl>=2.7; extra == "zengl"
25
+ Description-Content-Type: text/markdown
26
+
27
+ # filly
28
+
29
+ filly is a Python 3D renderer for glTF scenes, built on
30
+ [Google Filament](https://github.com/google/filament).
31
+
32
+ Filly can load a glTF model, light it, pose it, and render it. You get the result as a NumPy image, or
33
+ filly draws it into an OpenGL texture that your own window shows. Your program keeps control of
34
+ the window and of frame timing, so filly fits into applications that already own a display loop,
35
+ such as PsychoPy experiments or pyglet, moderngl, and zengl programs.
36
+
37
+ ![A wooden playground horse rocking on its spring, rendered with filly](docs/images/horse.gif)
38
+
39
+ *"[Wooden Playground Horse](https://sketchfab.com/3d-models/wooden-playground-horse-aa1c440f48a44e558dcc9097b35a6a6d)" by [Batuhan13](https://sketchfab.com/Batuhan13),
40
+ [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/). See [attribution](examples/assets/ATTRIBUTION.md).*
41
+
42
+ ## Install
43
+
44
+ filly is not on PyPI yet. [Build it from source](docs/how-to/build.md).
45
+
46
+ It needs Python 3.10 or later, Windows or Linux on x86_64, and an OpenGL 4.1 driver. On Linux,
47
+ offscreen rendering works without a display. macOS is not supported at this time.
48
+
49
+ ## Render an image
50
+
51
+ ```python
52
+ import filly
53
+ from PIL import Image # only to save the image
54
+
55
+ with filly.Renderer() as renderer:
56
+ scene = renderer.create_scene()
57
+ horse = scene.load("examples/assets/wooden_playground_horse.glb")
58
+ horse.apply_animation(0, 1.25) # a pose from its spring animation
59
+
60
+ camera = scene.create_camera()
61
+ camera.set_perspective(fov_y=30, near=0.1, far=100)
62
+ camera.frame(horse, direction=(-1, -0.3, -1), aspect=800 / 600)
63
+ scene.camera = camera
64
+ scene.add_directional_light(direction=(-1, -1, -2), intensity=100_000)
65
+
66
+ target = renderer.create_render_target(width=800, height=600)
67
+ renderer.render(scene, target)
68
+ Image.fromarray(target.read()).save("horse.png") # (600, 800, 4) uint8 RGBA
69
+ ```
70
+
71
+ ## Draw in a PsychoPy window
72
+
73
+ filly renders into a texture that PsychoPy draws directly, with no copy through the CPU.
74
+
75
+ ```python
76
+ from psychopy import core, visual
77
+ from filly.integrations.psychopy import SharedTarget, create_renderer
78
+
79
+ win = visual.Window((1024, 768), units="pix")
80
+ renderer = create_renderer(win) # shares the window's OpenGL context
81
+ scene = renderer.create_scene()
82
+ horse = scene.load("examples/assets/wooden_playground_horse.glb")
83
+ camera = scene.create_camera()
84
+ camera.set_perspective(fov_y=30, near=0.1, far=100)
85
+ camera.frame(horse, aspect=1)
86
+ scene.camera = camera
87
+ scene.add_directional_light(direction=(-1, -1, -2), intensity=100_000)
88
+
89
+ target = SharedTarget(renderer, win, 512, 512)
90
+ stim = target.as_psychopy_texture() # an ImageStim
91
+ clock = core.Clock()
92
+ while clock.getTime() < 3:
93
+ horse.apply_animation(0, clock.getTime())
94
+ renderer.render(scene, target)
95
+ stim.draw()
96
+ win.flip()
97
+
98
+ target.close()
99
+ renderer.close()
100
+ win.close()
101
+ ```
102
+
103
+ Close the target, then the renderer, then the window. The same pattern works with a
104
+ [pyglet, moderngl, or zengl window](docs/how-to/gl-hosts.md).
105
+
106
+ ## Features
107
+
108
+ - **glTF 2.0:** GLB and glTF files, skinning, morph targets, animation, material variants, and
109
+ the common material extensions, such as clearcoat, sheen, transmission, and iridescence.
110
+ See [asset compatibility](docs/reference/api.md#asset-compatibility).
111
+ - **Cameras and lights:** perspective and orthographic cameras, camera framing, and directional,
112
+ sun, point, and spot lights with optional shadows. Image-based lighting comes from an HDR
113
+ panorama or prefiltered KTX files.
114
+ - **Stimuli from arrays:** textures and meshes from NumPy arrays, updated in place each frame,
115
+ for gratings, noise, or deforming shapes.
116
+ - **Predictable output:** sRGB (default) or linear. Effects such as antialiasing,
117
+ fog, and bloom are off until you enable them. With default settings, the same scene gives the same pixels on every frame.
118
+ - **Several views per frame:** each `render()` call can take its own camera and viewport, for example for side-by-side stereo.
119
+ - **Browsers:** the same core compiles to WebAssembly for WebGL2. It renders into a texture that the page's own renderer draws, such as PIXI in PsychoJS. See
120
+ [the web build](docs/explanation/web.md).
121
+
122
+ ## Examples
123
+
124
+ See the `examples/` folder.
125
+
126
+ | Example | Shows |
127
+ | --- | --- |
128
+ | `screenshot.py` | The animation above (`--gif`), or a still image, rendered offscreen. |
129
+ | `psychopy_shared.py` | A model in a PsychoPy window. Pass your own GLB path. |
130
+ | `pyglet_shared.py`, `moderngl_shared.py`, `zengl_shared.py` | The same in other OpenGL hosts. |
131
+ | `drifting_grating.py` | A texture updated every frame on a tilted plane. |
132
+ | `stereo.py` | Two cameras side by side in one window. |
133
+ | `shapes.py` | Generated and deforming meshes. |
134
+
135
+ ## Documentation
136
+
137
+ - Tutorial: [render an image](docs/tutorials/offscreen.md)
138
+ - How-to guides: [build and test](docs/how-to/build.md),
139
+ [use PsychoPy](docs/how-to/psychopy.md), [use other OpenGL hosts](docs/how-to/gl-hosts.md),
140
+ [measure timing](docs/how-to/stress-test.md), [profile a frame](docs/how-to/profile.md),
141
+ [compare with Filament's viewer](docs/how-to/reference-comparison.md),
142
+ [use filly in a web page](docs/how-to/web.md)
143
+ - Reference: [API](docs/reference/api.md), [performance](docs/reference/performance.md),
144
+ [validation](docs/reference/validation.md), [sample assets](docs/reference/sample-assets.md)
145
+ - Explanation: [design and limits](docs/explanation/design.md),
146
+ [tested assumptions](docs/explanation/assumptions.md),
147
+ [material precompilation](docs/explanation/material-precompilation.md),
148
+ [the web build](docs/explanation/web.md)
149
+
150
+ ## License
151
+
152
+ filly is released under the [MIT License](LICENSE).
153
+
154
+ It links [Filament](https://github.com/google/filament) (Apache 2.0),
155
+ [meshoptimizer](https://github.com/zeux/meshoptimizer) (MIT),
156
+ [libwebp](https://chromium.googlesource.com/webm/libwebp) (BSD), and
157
+ [cgltf](https://github.com/jkuhlmann/cgltf) (MIT). Their licenses are installed with the package.
158
+ The sample model `filly.samples.SUZANNE` is modified from Suzanne by Norbert Nopper (UX3D), from
159
+ the Khronos glTF Sample Assets, under CC0 1.0.
filly-0.1.0/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # filly
2
+
3
+ filly is a Python 3D renderer for glTF scenes, built on
4
+ [Google Filament](https://github.com/google/filament).
5
+
6
+ Filly can load a glTF model, light it, pose it, and render it. You get the result as a NumPy image, or
7
+ filly draws it into an OpenGL texture that your own window shows. Your program keeps control of
8
+ the window and of frame timing, so filly fits into applications that already own a display loop,
9
+ such as PsychoPy experiments or pyglet, moderngl, and zengl programs.
10
+
11
+ ![A wooden playground horse rocking on its spring, rendered with filly](docs/images/horse.gif)
12
+
13
+ *"[Wooden Playground Horse](https://sketchfab.com/3d-models/wooden-playground-horse-aa1c440f48a44e558dcc9097b35a6a6d)" by [Batuhan13](https://sketchfab.com/Batuhan13),
14
+ [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/). See [attribution](examples/assets/ATTRIBUTION.md).*
15
+
16
+ ## Install
17
+
18
+ filly is not on PyPI yet. [Build it from source](docs/how-to/build.md).
19
+
20
+ It needs Python 3.10 or later, Windows or Linux on x86_64, and an OpenGL 4.1 driver. On Linux,
21
+ offscreen rendering works without a display. macOS is not supported at this time.
22
+
23
+ ## Render an image
24
+
25
+ ```python
26
+ import filly
27
+ from PIL import Image # only to save the image
28
+
29
+ with filly.Renderer() as renderer:
30
+ scene = renderer.create_scene()
31
+ horse = scene.load("examples/assets/wooden_playground_horse.glb")
32
+ horse.apply_animation(0, 1.25) # a pose from its spring animation
33
+
34
+ camera = scene.create_camera()
35
+ camera.set_perspective(fov_y=30, near=0.1, far=100)
36
+ camera.frame(horse, direction=(-1, -0.3, -1), aspect=800 / 600)
37
+ scene.camera = camera
38
+ scene.add_directional_light(direction=(-1, -1, -2), intensity=100_000)
39
+
40
+ target = renderer.create_render_target(width=800, height=600)
41
+ renderer.render(scene, target)
42
+ Image.fromarray(target.read()).save("horse.png") # (600, 800, 4) uint8 RGBA
43
+ ```
44
+
45
+ ## Draw in a PsychoPy window
46
+
47
+ filly renders into a texture that PsychoPy draws directly, with no copy through the CPU.
48
+
49
+ ```python
50
+ from psychopy import core, visual
51
+ from filly.integrations.psychopy import SharedTarget, create_renderer
52
+
53
+ win = visual.Window((1024, 768), units="pix")
54
+ renderer = create_renderer(win) # shares the window's OpenGL context
55
+ scene = renderer.create_scene()
56
+ horse = scene.load("examples/assets/wooden_playground_horse.glb")
57
+ camera = scene.create_camera()
58
+ camera.set_perspective(fov_y=30, near=0.1, far=100)
59
+ camera.frame(horse, aspect=1)
60
+ scene.camera = camera
61
+ scene.add_directional_light(direction=(-1, -1, -2), intensity=100_000)
62
+
63
+ target = SharedTarget(renderer, win, 512, 512)
64
+ stim = target.as_psychopy_texture() # an ImageStim
65
+ clock = core.Clock()
66
+ while clock.getTime() < 3:
67
+ horse.apply_animation(0, clock.getTime())
68
+ renderer.render(scene, target)
69
+ stim.draw()
70
+ win.flip()
71
+
72
+ target.close()
73
+ renderer.close()
74
+ win.close()
75
+ ```
76
+
77
+ Close the target, then the renderer, then the window. The same pattern works with a
78
+ [pyglet, moderngl, or zengl window](docs/how-to/gl-hosts.md).
79
+
80
+ ## Features
81
+
82
+ - **glTF 2.0:** GLB and glTF files, skinning, morph targets, animation, material variants, and
83
+ the common material extensions, such as clearcoat, sheen, transmission, and iridescence.
84
+ See [asset compatibility](docs/reference/api.md#asset-compatibility).
85
+ - **Cameras and lights:** perspective and orthographic cameras, camera framing, and directional,
86
+ sun, point, and spot lights with optional shadows. Image-based lighting comes from an HDR
87
+ panorama or prefiltered KTX files.
88
+ - **Stimuli from arrays:** textures and meshes from NumPy arrays, updated in place each frame,
89
+ for gratings, noise, or deforming shapes.
90
+ - **Predictable output:** sRGB (default) or linear. Effects such as antialiasing,
91
+ fog, and bloom are off until you enable them. With default settings, the same scene gives the same pixels on every frame.
92
+ - **Several views per frame:** each `render()` call can take its own camera and viewport, for example for side-by-side stereo.
93
+ - **Browsers:** the same core compiles to WebAssembly for WebGL2. It renders into a texture that the page's own renderer draws, such as PIXI in PsychoJS. See
94
+ [the web build](docs/explanation/web.md).
95
+
96
+ ## Examples
97
+
98
+ See the `examples/` folder.
99
+
100
+ | Example | Shows |
101
+ | --- | --- |
102
+ | `screenshot.py` | The animation above (`--gif`), or a still image, rendered offscreen. |
103
+ | `psychopy_shared.py` | A model in a PsychoPy window. Pass your own GLB path. |
104
+ | `pyglet_shared.py`, `moderngl_shared.py`, `zengl_shared.py` | The same in other OpenGL hosts. |
105
+ | `drifting_grating.py` | A texture updated every frame on a tilted plane. |
106
+ | `stereo.py` | Two cameras side by side in one window. |
107
+ | `shapes.py` | Generated and deforming meshes. |
108
+
109
+ ## Documentation
110
+
111
+ - Tutorial: [render an image](docs/tutorials/offscreen.md)
112
+ - How-to guides: [build and test](docs/how-to/build.md),
113
+ [use PsychoPy](docs/how-to/psychopy.md), [use other OpenGL hosts](docs/how-to/gl-hosts.md),
114
+ [measure timing](docs/how-to/stress-test.md), [profile a frame](docs/how-to/profile.md),
115
+ [compare with Filament's viewer](docs/how-to/reference-comparison.md),
116
+ [use filly in a web page](docs/how-to/web.md)
117
+ - Reference: [API](docs/reference/api.md), [performance](docs/reference/performance.md),
118
+ [validation](docs/reference/validation.md), [sample assets](docs/reference/sample-assets.md)
119
+ - Explanation: [design and limits](docs/explanation/design.md),
120
+ [tested assumptions](docs/explanation/assumptions.md),
121
+ [material precompilation](docs/explanation/material-precompilation.md),
122
+ [the web build](docs/explanation/web.md)
123
+
124
+ ## License
125
+
126
+ filly is released under the [MIT License](LICENSE).
127
+
128
+ It links [Filament](https://github.com/google/filament) (Apache 2.0),
129
+ [meshoptimizer](https://github.com/zeux/meshoptimizer) (MIT),
130
+ [libwebp](https://chromium.googlesource.com/webm/libwebp) (BSD), and
131
+ [cgltf](https://github.com/jkuhlmann/cgltf) (MIT). Their licenses are installed with the package.
132
+ The sample model `filly.samples.SUZANNE` is modified from Suzanne by Norbert Nopper (UX3D), from
133
+ the Khronos glTF Sample Assets, under CC0 1.0.