OpenGLContext 3.0.0a1__py3-none-any.whl

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 (417) hide show
  1. OpenGLContext/__init__.py +151 -0
  2. OpenGLContext/arrays.py +2 -0
  3. OpenGLContext/atlas.py +300 -0
  4. OpenGLContext/audio/__init__.py +32 -0
  5. OpenGLContext/audio/scene.py +130 -0
  6. OpenGLContext/audio/settings.py +82 -0
  7. OpenGLContext/bin/__init__.py +0 -0
  8. OpenGLContext/bin/choosecontext.py +224 -0
  9. OpenGLContext/bin/choosefonts.py +209 -0
  10. OpenGLContext/bin/gltest.py +121 -0
  11. OpenGLContext/bin/gltf_demo.py +492 -0
  12. OpenGLContext/bin/gltf_regression.py +645 -0
  13. OpenGLContext/bin/gltf_view.py +30 -0
  14. OpenGLContext/bin/keyboardevents.py +93 -0
  15. OpenGLContext/bin/lorentz.py +109 -0
  16. OpenGLContext/bin/physics_cook.py +81 -0
  17. OpenGLContext/bin/profile_view.py +38 -0
  18. OpenGLContext/bin/terrain_view.py +581 -0
  19. OpenGLContext/bin/tiles_view.py +39 -0
  20. OpenGLContext/bin/ui_demo.py +228 -0
  21. OpenGLContext/bin/view.py +341 -0
  22. OpenGLContext/bin/vrml_view.py +42 -0
  23. OpenGLContext/capture.py +125 -0
  24. OpenGLContext/context.py +1253 -0
  25. OpenGLContext/contextconfig.py +177 -0
  26. OpenGLContext/contextdefinition.py +275 -0
  27. OpenGLContext/debug/__init__.py +6 -0
  28. OpenGLContext/debug/bufferimage.py +80 -0
  29. OpenGLContext/debug/leaks.py +13 -0
  30. OpenGLContext/debug/logcontext.py +9 -0
  31. OpenGLContext/debug/logs.py +15 -0
  32. OpenGLContext/debug/state.py +329 -0
  33. OpenGLContext/displaylist.py +69 -0
  34. OpenGLContext/doinchildmatrix.py +34 -0
  35. OpenGLContext/drawcube.py +58 -0
  36. OpenGLContext/events/__init__.py +10 -0
  37. OpenGLContext/events/default_config.py +29 -0
  38. OpenGLContext/events/event.py +65 -0
  39. OpenGLContext/events/eventhandlermixin.py +214 -0
  40. OpenGLContext/events/eventmanager.py +269 -0
  41. OpenGLContext/events/fxevents.py +90 -0
  42. OpenGLContext/events/glfwevents.py +424 -0
  43. OpenGLContext/events/glutevents.py +184 -0
  44. OpenGLContext/events/inputstate.py +129 -0
  45. OpenGLContext/events/internaltime.py +161 -0
  46. OpenGLContext/events/keyboardevents.py +153 -0
  47. OpenGLContext/events/mouseevents.py +473 -0
  48. OpenGLContext/events/pygameevents.py +162 -0
  49. OpenGLContext/events/systemtime.py +12 -0
  50. OpenGLContext/events/timeeventgeneratormanager.py +40 -0
  51. OpenGLContext/events/timeevents.py +143 -0
  52. OpenGLContext/events/timer.py +170 -0
  53. OpenGLContext/events/tkevents.py +172 -0
  54. OpenGLContext/events/wxevents.py +185 -0
  55. OpenGLContext/extensionmanager.py +158 -0
  56. OpenGLContext/framecounter.py +74 -0
  57. OpenGLContext/frustum.py +135 -0
  58. OpenGLContext/glfwcontext.py +395 -0
  59. OpenGLContext/glfwinteractivecontext.py +34 -0
  60. OpenGLContext/glfwvrmlcontext.py +11 -0
  61. OpenGLContext/glutcontext.py +224 -0
  62. OpenGLContext/glutinteractivecontext.py +24 -0
  63. OpenGLContext/gluttestingcontext.py +11 -0
  64. OpenGLContext/glutvrmlcontext.py +25 -0
  65. OpenGLContext/glutvrmltestingcontext.py +48 -0
  66. OpenGLContext/hud.py +404 -0
  67. OpenGLContext/interactivecontext.py +29 -0
  68. OpenGLContext/loaders/__init__.py +1 -0
  69. OpenGLContext/loaders/base.py +84 -0
  70. OpenGLContext/loaders/cc0.py +137 -0
  71. OpenGLContext/loaders/gltf/__init__.py +71 -0
  72. OpenGLContext/loaders/gltf/accessors.py +255 -0
  73. OpenGLContext/loaders/gltf/animation.py +611 -0
  74. OpenGLContext/loaders/gltf/draco.py +166 -0
  75. OpenGLContext/loaders/gltf/environment_sky.py +416 -0
  76. OpenGLContext/loaders/gltf/loader.py +80 -0
  77. OpenGLContext/loaders/gltf/materials.py +298 -0
  78. OpenGLContext/loaders/gltf/meshes.py +292 -0
  79. OpenGLContext/loaders/gltf/samples.py +162 -0
  80. OpenGLContext/loaders/gltf/scene.py +673 -0
  81. OpenGLContext/loaders/gltf/specular_glossiness.py +154 -0
  82. OpenGLContext/loaders/gltf/textures.py +155 -0
  83. OpenGLContext/loaders/gltf/transforms.py +261 -0
  84. OpenGLContext/loaders/gltf_demos.py +511 -0
  85. OpenGLContext/loaders/hdr.py +228 -0
  86. OpenGLContext/loaders/hdri.py +83 -0
  87. OpenGLContext/loaders/loader.py +255 -0
  88. OpenGLContext/loaders/obj.py +299 -0
  89. OpenGLContext/loaders/resolver.py +536 -0
  90. OpenGLContext/loaders/tiles3d/__init__.py +9 -0
  91. OpenGLContext/loaders/tiles3d/boundingvolume.py +120 -0
  92. OpenGLContext/loaders/tiles3d/dem.py +71 -0
  93. OpenGLContext/loaders/tiles3d/fetch.py +102 -0
  94. OpenGLContext/loaders/tiles3d/foliage.py +786 -0
  95. OpenGLContext/loaders/tiles3d/frustum.py +70 -0
  96. OpenGLContext/loaders/tiles3d/geomorph.py +57 -0
  97. OpenGLContext/loaders/tiles3d/gltf_uploader.py +246 -0
  98. OpenGLContext/loaders/tiles3d/loadmanager.py +121 -0
  99. OpenGLContext/loaders/tiles3d/physics_colliders.py +78 -0
  100. OpenGLContext/loaders/tiles3d/procedural.py +355 -0
  101. OpenGLContext/loaders/tiles3d/residency.py +102 -0
  102. OpenGLContext/loaders/tiles3d/runtime.py +168 -0
  103. OpenGLContext/loaders/tiles3d/sample.py +212 -0
  104. OpenGLContext/loaders/tiles3d/scatter.py +77 -0
  105. OpenGLContext/loaders/tiles3d/screenspaceerror.py +31 -0
  106. OpenGLContext/loaders/tiles3d/tileset.py +390 -0
  107. OpenGLContext/loaders/tiles3d/traversal.py +108 -0
  108. OpenGLContext/loaders/tiles3d/vegetation.py +361 -0
  109. OpenGLContext/loaders/vrml97.py +133 -0
  110. OpenGLContext/looptrace.py +307 -0
  111. OpenGLContext/move/__init__.py +0 -0
  112. OpenGLContext/move/bindingstore.py +232 -0
  113. OpenGLContext/move/direct.py +156 -0
  114. OpenGLContext/move/dragwatcher.py +42 -0
  115. OpenGLContext/move/examinemanager.py +100 -0
  116. OpenGLContext/move/followcam.py +121 -0
  117. OpenGLContext/move/modes.py +522 -0
  118. OpenGLContext/move/movementmanager.py +74 -0
  119. OpenGLContext/move/navigation.py +137 -0
  120. OpenGLContext/move/physicsplatform.py +203 -0
  121. OpenGLContext/move/physicswalk.py +469 -0
  122. OpenGLContext/move/smooth.py +68 -0
  123. OpenGLContext/move/terrainwalk.py +451 -0
  124. OpenGLContext/move/trackball.py +92 -0
  125. OpenGLContext/move/viewplatform.py +283 -0
  126. OpenGLContext/move/viewplatformmixin.py +335 -0
  127. OpenGLContext/nav/__init__.py +13 -0
  128. OpenGLContext/nav/navmesh.py +476 -0
  129. OpenGLContext/passes/__init__.py +0 -0
  130. OpenGLContext/passes/_flat.py +1317 -0
  131. OpenGLContext/passes/asyncpick.py +216 -0
  132. OpenGLContext/passes/bloom.py +257 -0
  133. OpenGLContext/passes/flatcompat.py +246 -0
  134. OpenGLContext/passes/flatcore.py +198 -0
  135. OpenGLContext/passes/flateffects.py +372 -0
  136. OpenGLContext/passes/ibl.py +711 -0
  137. OpenGLContext/passes/instancing.py +775 -0
  138. OpenGLContext/passes/pbrpass.py +829 -0
  139. OpenGLContext/passes/renderpass.py +79 -0
  140. OpenGLContext/passes/renderstats.py +55 -0
  141. OpenGLContext/passes/rendervisitor.py +60 -0
  142. OpenGLContext/passes/selection.py +450 -0
  143. OpenGLContext/passes/selectionbuffers.py +442 -0
  144. OpenGLContext/passes/shaderpass.py +1018 -0
  145. OpenGLContext/passes/shaderpass_shadow.py +197 -0
  146. OpenGLContext/passes/shadersource.py +121 -0
  147. OpenGLContext/passes/shadowcaps.py +182 -0
  148. OpenGLContext/passes/shadowmap.py +330 -0
  149. OpenGLContext/passes/shadowmath.py +290 -0
  150. OpenGLContext/passes/shadowmixin.py +906 -0
  151. OpenGLContext/passes/shadowpool.py +186 -0
  152. OpenGLContext/passes/transmission.py +124 -0
  153. OpenGLContext/physics/__init__.py +16 -0
  154. OpenGLContext/physics/debugdraw.py +370 -0
  155. OpenGLContext/physics/demo.py +157 -0
  156. OpenGLContext/physics/gltf_world.py +185 -0
  157. OpenGLContext/physics/manager.py +84 -0
  158. OpenGLContext/physics/threaded.py +93 -0
  159. OpenGLContext/plugins.py +61 -0
  160. OpenGLContext/pygamecontext.py +178 -0
  161. OpenGLContext/pygameinteractivecontext.py +36 -0
  162. OpenGLContext/pygametestingcontext.py +10 -0
  163. OpenGLContext/pygamevrmlcontext.py +13 -0
  164. OpenGLContext/quaternion.py +190 -0
  165. OpenGLContext/renderoptions.py +280 -0
  166. OpenGLContext/resources/__init__.py +36 -0
  167. OpenGLContext/resources/available_contexts.txt +4 -0
  168. OpenGLContext/resources/available_contexts_txt.py +9 -0
  169. OpenGLContext/resources/context_icon_png.py +46 -0
  170. OpenGLContext/resources/context_icon_small_png.py +21 -0
  171. OpenGLContext/resources/disk_icon_hi_png.py +14 -0
  172. OpenGLContext/resources/disk_icon_png.py +15 -0
  173. OpenGLContext/resources/environment/pimbackground_BK.jpg +0 -0
  174. OpenGLContext/resources/environment/pimbackground_DN.jpg +0 -0
  175. OpenGLContext/resources/environment/pimbackground_FR.jpg +0 -0
  176. OpenGLContext/resources/environment/pimbackground_LF.jpg +0 -0
  177. OpenGLContext/resources/environment/pimbackground_RT.jpg +0 -0
  178. OpenGLContext/resources/environment/pimbackground_UP.jpg +0 -0
  179. OpenGLContext/resources/environment/studio_BK.jpg +0 -0
  180. OpenGLContext/resources/environment/studio_DN.jpg +0 -0
  181. OpenGLContext/resources/environment/studio_FR.jpg +0 -0
  182. OpenGLContext/resources/environment/studio_LF.jpg +0 -0
  183. OpenGLContext/resources/environment/studio_RT.jpg +0 -0
  184. OpenGLContext/resources/environment/studio_UP.jpg +0 -0
  185. OpenGLContext/resources/environment/studiobright_BK.jpg +0 -0
  186. OpenGLContext/resources/environment/studiobright_DN.jpg +0 -0
  187. OpenGLContext/resources/environment/studiobright_FR.jpg +0 -0
  188. OpenGLContext/resources/environment/studiobright_LF.jpg +0 -0
  189. OpenGLContext/resources/environment/studiobright_RT.jpg +0 -0
  190. OpenGLContext/resources/environment/studiobright_UP.jpg +0 -0
  191. OpenGLContext/resources/green_arrow_right_png.py +47 -0
  192. OpenGLContext/resources/legacy_lighting.vert.txt +37 -0
  193. OpenGLContext/resources/legacy_lighting_vert_txt.py +18 -0
  194. OpenGLContext/resources/lights.vert.txt +107 -0
  195. OpenGLContext/resources/lights_vert_txt.py +23 -0
  196. OpenGLContext/resources/phongprecalc_vert.py +30 -0
  197. OpenGLContext/resources/phongweights_frag.py +47 -0
  198. OpenGLContext/resources/pygame_icon_png.py +47 -0
  199. OpenGLContext/resources/red_arrow_right_png.py +50 -0
  200. OpenGLContext/resources/simpleshader.frag.txt +3 -0
  201. OpenGLContext/resources/simpleshader.vert.txt +3 -0
  202. OpenGLContext/resources/simpleshader_frag_txt.py +9 -0
  203. OpenGLContext/resources/simpleshader_vert_txt.py +10 -0
  204. OpenGLContext/scenegraph/__init__.py +19 -0
  205. OpenGLContext/scenegraph/appearance.py +107 -0
  206. OpenGLContext/scenegraph/arraygeometry.py +238 -0
  207. OpenGLContext/scenegraph/audio.py +632 -0
  208. OpenGLContext/scenegraph/background.py +108 -0
  209. OpenGLContext/scenegraph/basenodes.py +50 -0
  210. OpenGLContext/scenegraph/billboard.py +14 -0
  211. OpenGLContext/scenegraph/boundingvolume.py +494 -0
  212. OpenGLContext/scenegraph/box.py +180 -0
  213. OpenGLContext/scenegraph/collision.py +14 -0
  214. OpenGLContext/scenegraph/coordinate.py +20 -0
  215. OpenGLContext/scenegraph/coordinatebounded.py +18 -0
  216. OpenGLContext/scenegraph/cubebackground.py +207 -0
  217. OpenGLContext/scenegraph/extrusions.py +275 -0
  218. OpenGLContext/scenegraph/fog.py +123 -0
  219. OpenGLContext/scenegraph/gear.py +323 -0
  220. OpenGLContext/scenegraph/group.py +20 -0
  221. OpenGLContext/scenegraph/grouping.py +140 -0
  222. OpenGLContext/scenegraph/hdrbackground.py +384 -0
  223. OpenGLContext/scenegraph/ifscompiler.py +633 -0
  224. OpenGLContext/scenegraph/imagetexture.py +365 -0
  225. OpenGLContext/scenegraph/indexedfaceset.py +238 -0
  226. OpenGLContext/scenegraph/indexedlineset.py +418 -0
  227. OpenGLContext/scenegraph/indexedpolygons.py +422 -0
  228. OpenGLContext/scenegraph/inline.py +79 -0
  229. OpenGLContext/scenegraph/instancedgl.py +187 -0
  230. OpenGLContext/scenegraph/interpolators.py +122 -0
  231. OpenGLContext/scenegraph/light.py +213 -0
  232. OpenGLContext/scenegraph/lod.py +22 -0
  233. OpenGLContext/scenegraph/material.py +96 -0
  234. OpenGLContext/scenegraph/material_fields.py +50 -0
  235. OpenGLContext/scenegraph/mouseover.py +43 -0
  236. OpenGLContext/scenegraph/nodepath.py +52 -0
  237. OpenGLContext/scenegraph/nurbs.py +637 -0
  238. OpenGLContext/scenegraph/nurbssampling.py +101 -0
  239. OpenGLContext/scenegraph/nurbstess.py +316 -0
  240. OpenGLContext/scenegraph/nurbstrim.py +54 -0
  241. OpenGLContext/scenegraph/particles.py +786 -0
  242. OpenGLContext/scenegraph/pbrmaterial.py +229 -0
  243. OpenGLContext/scenegraph/pbrmesh.py +558 -0
  244. OpenGLContext/scenegraph/physicsbody.py +72 -0
  245. OpenGLContext/scenegraph/pointset.py +257 -0
  246. OpenGLContext/scenegraph/polygon.py +166 -0
  247. OpenGLContext/scenegraph/polygonsort.py +119 -0
  248. OpenGLContext/scenegraph/polygontessellator.py +213 -0
  249. OpenGLContext/scenegraph/quadrics.py +494 -0
  250. OpenGLContext/scenegraph/scenegraph.py +21 -0
  251. OpenGLContext/scenegraph/shadergeometry.py +403 -0
  252. OpenGLContext/scenegraph/shaders.py +812 -0
  253. OpenGLContext/scenegraph/shape.py +243 -0
  254. OpenGLContext/scenegraph/simplebackground.py +34 -0
  255. OpenGLContext/scenegraph/spherebackground.py +462 -0
  256. OpenGLContext/scenegraph/switch.py +75 -0
  257. OpenGLContext/scenegraph/teapot.py +439 -0
  258. OpenGLContext/scenegraph/teapot_nurbs.py +291 -0
  259. OpenGLContext/scenegraph/teapot_nurbs_data.py +384 -0
  260. OpenGLContext/scenegraph/terrain/__init__.py +12 -0
  261. OpenGLContext/scenegraph/terrain/heightfield.py +172 -0
  262. OpenGLContext/scenegraph/terrain/splat.py +224 -0
  263. OpenGLContext/scenegraph/tessellationlod.py +97 -0
  264. OpenGLContext/scenegraph/text/__init__.py +1 -0
  265. OpenGLContext/scenegraph/text/_toolsfont.py +200 -0
  266. OpenGLContext/scenegraph/text/font.py +452 -0
  267. OpenGLContext/scenegraph/text/fontprovider.py +193 -0
  268. OpenGLContext/scenegraph/text/fonts/__init__.py +75 -0
  269. OpenGLContext/scenegraph/text/fonts/font_atlas_10.py +133 -0
  270. OpenGLContext/scenegraph/text/fonts/font_atlas_12.py +158 -0
  271. OpenGLContext/scenegraph/text/fonts/font_atlas_14.py +176 -0
  272. OpenGLContext/scenegraph/text/fonts/font_atlas_16.py +204 -0
  273. OpenGLContext/scenegraph/text/fonts/font_atlas_18.py +222 -0
  274. OpenGLContext/scenegraph/text/fonts/font_atlas_20.py +244 -0
  275. OpenGLContext/scenegraph/text/fonts/font_atlas_24.py +294 -0
  276. OpenGLContext/scenegraph/text/fonts/font_atlas_28.py +339 -0
  277. OpenGLContext/scenegraph/text/fonts/font_atlas_32.py +390 -0
  278. OpenGLContext/scenegraph/text/fontstyle3d.py +62 -0
  279. OpenGLContext/scenegraph/text/glutfont.py +186 -0
  280. OpenGLContext/scenegraph/text/pygamefont.py +213 -0
  281. OpenGLContext/scenegraph/text/shaderfont.py +340 -0
  282. OpenGLContext/scenegraph/text/shadertext.py +433 -0
  283. OpenGLContext/scenegraph/text/text.py +75 -0
  284. OpenGLContext/scenegraph/text/toolsfont.py +819 -0
  285. OpenGLContext/scenegraph/text/ttfregistry.py +135 -0
  286. OpenGLContext/scenegraph/text/wglfont.py +228 -0
  287. OpenGLContext/scenegraph/text/wglfontprovider.py +37 -0
  288. OpenGLContext/scenegraph/text/wxfont.py +314 -0
  289. OpenGLContext/scenegraph/texturetransform.py +66 -0
  290. OpenGLContext/scenegraph/tilesterrain.py +95 -0
  291. OpenGLContext/scenegraph/timesensor.py +51 -0
  292. OpenGLContext/scenegraph/transform.py +180 -0
  293. OpenGLContext/scenegraph/vegetation/__init__.py +20 -0
  294. OpenGLContext/scenegraph/vegetation/base.py +96 -0
  295. OpenGLContext/scenegraph/vegetation/billboards.py +145 -0
  296. OpenGLContext/scenegraph/vegetation/clumps.py +260 -0
  297. OpenGLContext/scenegraph/vegetation/grid.py +112 -0
  298. OpenGLContext/scenegraph/vegetation/nearmesh.py +185 -0
  299. OpenGLContext/scenegraph/vertex.py +54 -0
  300. OpenGLContext/scenegraph/viewpoint.py +42 -0
  301. OpenGLContext/scenegraph/winding.py +49 -0
  302. OpenGLContext/shaders/_brdf_inc.glsl +124 -0
  303. OpenGLContext/shaders/_common_inc.glsl +24 -0
  304. OpenGLContext/shaders/_cubemap_inc.glsl +26 -0
  305. OpenGLContext/shaders/_lights_inc.glsl +32 -0
  306. OpenGLContext/shaders/_objectid_inc.glsl +14 -0
  307. OpenGLContext/shaders/_shadow_inc.glsl +254 -0
  308. OpenGLContext/shaders/_vrml97_lighting_inc.glsl +78 -0
  309. OpenGLContext/shaders/hdr_background.frag +32 -0
  310. OpenGLContext/shaders/hdr_background.vert +15 -0
  311. OpenGLContext/shaders/ibl_brdf.frag +78 -0
  312. OpenGLContext/shaders/ibl_env.frag +53 -0
  313. OpenGLContext/shaders/ibl_equirect.frag +19 -0
  314. OpenGLContext/shaders/ibl_fullscreen.vert +11 -0
  315. OpenGLContext/shaders/ibl_irradiance.frag +40 -0
  316. OpenGLContext/shaders/ibl_prefilter.frag +56 -0
  317. OpenGLContext/shaders/particle.frag +42 -0
  318. OpenGLContext/shaders/particle.vert +52 -0
  319. OpenGLContext/shaders/pbr.frag +906 -0
  320. OpenGLContext/shaders/pbr.vert +70 -0
  321. OpenGLContext/shaders/shadow_depth.frag +4 -0
  322. OpenGLContext/shaders/shadow_depth.vert +18 -0
  323. OpenGLContext/shaders/terrain_splat.frag +80 -0
  324. OpenGLContext/shaders/terrain_splat.vert +16 -0
  325. OpenGLContext/shaders/veg_billboard.frag +35 -0
  326. OpenGLContext/shaders/veg_billboard.vert +17 -0
  327. OpenGLContext/shaders/veg_clump.frag +27 -0
  328. OpenGLContext/shaders/veg_mesh.frag +26 -0
  329. OpenGLContext/shaders/veg_mesh.vert +17 -0
  330. OpenGLContext/shaders/vrml97_background.frag +17 -0
  331. OpenGLContext/shaders/vrml97_background.vert +24 -0
  332. OpenGLContext/shaders/vrml97_lighting.frag +111 -0
  333. OpenGLContext/shaders/vrml97_lighting.vert +50 -0
  334. OpenGLContext/shaders/vrml97_line.frag +23 -0
  335. OpenGLContext/shaders/vrml97_line.vert +24 -0
  336. OpenGLContext/shaders/vrml97_point.frag +36 -0
  337. OpenGLContext/shaders/vrml97_point.vert +21 -0
  338. OpenGLContext/shaders/vrml97_unlit.frag +59 -0
  339. OpenGLContext/shaders/vrml97_unlit.vert +18 -0
  340. OpenGLContext/shaders/vrml97_vertex_color.frag +85 -0
  341. OpenGLContext/shaders/vrml97_vertex_color.vert +34 -0
  342. OpenGLContext/stalltrace.py +637 -0
  343. OpenGLContext/testing/__init__.py +67 -0
  344. OpenGLContext/testing/display.py +30 -0
  345. OpenGLContext/testing/event_injector.py +564 -0
  346. OpenGLContext/testing/framebuffer_comparison.py +842 -0
  347. OpenGLContext/testing/gl_env.py +39 -0
  348. OpenGLContext/testing/paths.py +23 -0
  349. OpenGLContext/testing/process_exit.py +30 -0
  350. OpenGLContext/testing/report_generator.py +594 -0
  351. OpenGLContext/testing/subprocess_runner.py +411 -0
  352. OpenGLContext/testingcontext.py +36 -0
  353. OpenGLContext/tests/test_atlas.py +62 -0
  354. OpenGLContext/tests/test_configs.py +27 -0
  355. OpenGLContext/tests/test_polygonsort.py +45 -0
  356. OpenGLContext/tests/test_utilities.py +84 -0
  357. OpenGLContext/tests/test_viewplatform.py +39 -0
  358. OpenGLContext/texture.py +449 -0
  359. OpenGLContext/texturecache.py +37 -0
  360. OpenGLContext/triangleutilities.py +89 -0
  361. OpenGLContext/ui/__init__.py +39 -0
  362. OpenGLContext/ui/bindings.py +243 -0
  363. OpenGLContext/ui/console.py +339 -0
  364. OpenGLContext/ui/debugoverlay.py +519 -0
  365. OpenGLContext/ui/dialogs.py +124 -0
  366. OpenGLContext/ui/draw.py +617 -0
  367. OpenGLContext/ui/gallery.py +425 -0
  368. OpenGLContext/ui/generate.py +195 -0
  369. OpenGLContext/ui/geometry.py +88 -0
  370. OpenGLContext/ui/hudwidgets.py +1053 -0
  371. OpenGLContext/ui/layout.py +263 -0
  372. OpenGLContext/ui/metrics.py +218 -0
  373. OpenGLContext/ui/overlay.py +412 -0
  374. OpenGLContext/ui/panel.py +459 -0
  375. OpenGLContext/ui/pictures.py +261 -0
  376. OpenGLContext/ui/screen.py +177 -0
  377. OpenGLContext/ui/scroll.py +297 -0
  378. OpenGLContext/ui/session.py +329 -0
  379. OpenGLContext/ui/settings.py +273 -0
  380. OpenGLContext/ui/skin.py +330 -0
  381. OpenGLContext/ui/widgets.py +1199 -0
  382. OpenGLContext/userpaths.py +48 -0
  383. OpenGLContext/utilities.py +94 -0
  384. OpenGLContext/vectorutilities.py +101 -0
  385. OpenGLContext/viewer/__init__.py +60 -0
  386. OpenGLContext/viewer/adapters/__init__.py +150 -0
  387. OpenGLContext/viewer/adapters/base.py +157 -0
  388. OpenGLContext/viewer/adapters/gltf.py +31 -0
  389. OpenGLContext/viewer/adapters/obj.py +20 -0
  390. OpenGLContext/viewer/adapters/scenegraph.py +71 -0
  391. OpenGLContext/viewer/adapters/tiles.py +296 -0
  392. OpenGLContext/viewer/adapters/vrml.py +25 -0
  393. OpenGLContext/viewer/asyncscene.py +117 -0
  394. OpenGLContext/viewer/caption.py +126 -0
  395. OpenGLContext/viewer/capture.py +77 -0
  396. OpenGLContext/viewer/debug.py +78 -0
  397. OpenGLContext/viewer/environment.py +131 -0
  398. OpenGLContext/viewer/framing.py +111 -0
  399. OpenGLContext/viewer/library.py +235 -0
  400. OpenGLContext/viewer/menu.py +218 -0
  401. OpenGLContext/viewer/options.py +150 -0
  402. OpenGLContext/viewer/overlay.py +63 -0
  403. OpenGLContext/viewer/sceneviewer.py +1056 -0
  404. OpenGLContext/viewer/screens.py +172 -0
  405. OpenGLContext/viewer/source.py +56 -0
  406. OpenGLContext/visitor.py +68 -0
  407. OpenGLContext/vrmlcontext.py +72 -0
  408. OpenGLContext/wxcontext.py +424 -0
  409. OpenGLContext/wxinteractivecontext.py +25 -0
  410. OpenGLContext/wxtestingcontext.py +9 -0
  411. OpenGLContext/wxvrmlcontext.py +13 -0
  412. openglcontext-3.0.0a1.dist-info/METADATA +650 -0
  413. openglcontext-3.0.0a1.dist-info/RECORD +417 -0
  414. openglcontext-3.0.0a1.dist-info/WHEEL +5 -0
  415. openglcontext-3.0.0a1.dist-info/entry_points.txt +11 -0
  416. openglcontext-3.0.0a1.dist-info/licenses/license.txt +89 -0
  417. openglcontext-3.0.0a1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,228 @@
1
+ #! /usr/bin/env python
2
+ """Overlay UI demonstration: the settings screen, the console and a skin.
3
+
4
+ Run it and press the keys it prints:
5
+
6
+ oglc-ui # the default flat skin
7
+ oglc-ui --skin # the same screens, painted with nine-slice artwork
8
+
9
+ F10 the settings screen -- every rendering feature the pass reads
10
+ F9 the console, with the engine's own log going into it
11
+ F8 a licence notice, to show a wall of text scrolling
12
+ F7 a yes/no question
13
+ F5 save a screenshot (into the current directory)
14
+ Alt+f the developer overlay -- a HUD layer rather than a panel, so it takes
15
+ no input and these screens draw over it (see docs/hud.html)
16
+
17
+ The artwork the ``--skin`` mode uses is drawn at start-up rather than shipped,
18
+ so the demo shows what a nine-slice does -- corners that stay square while the
19
+ frame stretches -- without a binary in the repository.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import argparse
25
+ import logging
26
+ import os
27
+ import sys
28
+ from typing import Any, List, Optional
29
+
30
+ from OpenGLContext import testingcontext
31
+ from OpenGLContext.contextdefinition import ContextDefinition
32
+ from OpenGLContext.move import modes as movemodes
33
+ from OpenGLContext.scenegraph.appearance import Appearance
34
+ from OpenGLContext.scenegraph.box import Box
35
+ from OpenGLContext.scenegraph.transform import Transform
36
+ from OpenGLContext.scenegraph.light import DirectionalLight
37
+ from OpenGLContext.scenegraph.material import Material
38
+ from OpenGLContext.scenegraph.quadrics import Sphere
39
+ from OpenGLContext.scenegraph.scenegraph import SceneGraph
40
+ from OpenGLContext.scenegraph.shape import Shape
41
+ from OpenGLContext.ui import bindings, console, dialogs, settings
42
+ from OpenGLContext.ui.overlay import OverlayMixin
43
+
44
+ log = logging.getLogger(__name__)
45
+ BaseContext: Any = testingcontext.getInteractive()
46
+
47
+ #: A short licence-shaped wall of text, so the notice screen has to scroll.
48
+ NOTICE = '\n\n'.join([
49
+ 'OpenGLContext is distributed under a BSD-style licence.',
50
+ 'Redistribution and use in source and binary forms, with or without '
51
+ 'modification, are permitted provided that the following conditions are '
52
+ 'met: redistributions of source code must retain the above copyright '
53
+ 'notice, this list of conditions and the following disclaimer; '
54
+ 'redistributions in binary form must reproduce the above copyright notice, '
55
+ 'this list of conditions and the following disclaimer in the documentation '
56
+ 'and/or other materials provided with the distribution.',
57
+ 'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS '
58
+ 'IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, '
59
+ 'THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR '
60
+ 'PURPOSE ARE DISCLAIMED.',
61
+ ] + ['Paragraph %d of a notice nobody can style away.' % (index,)
62
+ for index in range(1, 40)])
63
+
64
+
65
+ def build_skin(directory: str) -> Any:
66
+ """Draw a nine-slice set into ``directory`` and return a Skin using it.
67
+
68
+ Generated rather than shipped: what this demonstrates is that one image
69
+ serves every widget size, and an image drawn here is as good a proof of
70
+ that as one drawn in an editor -- with nothing binary to keep in step.
71
+ """
72
+ from PIL import Image, ImageDraw
73
+ from OpenGLContext.ui.skin import NineSlice, Skin
74
+
75
+ def frame(name: str, fill: Any, edge: Any, size: int = 24,
76
+ border: int = 8) -> str:
77
+ image = Image.new('RGBA', (size, size), (0, 0, 0, 0))
78
+ draw = ImageDraw.Draw(image)
79
+ draw.rounded_rectangle([0, 0, size - 1, size - 1], radius=border - 1,
80
+ fill=fill, outline=edge, width=2)
81
+ path = os.path.join(directory, '%s.png' % (name,))
82
+ image.save(path)
83
+ return path
84
+
85
+ def slice(name: str, fill: Any, edge: Any) -> NineSlice:
86
+ return NineSlice(url=[frame(name, fill, edge)], border=(8, 8, 8, 8))
87
+
88
+ return Skin(
89
+ panelImage=slice('panel', (18, 22, 32, 230), (90, 110, 150, 255)),
90
+ buttonImage=slice('button', (38, 46, 62, 245), (110, 130, 170, 255)),
91
+ buttonHoverImage=slice('button_hover', (64, 88, 130, 250),
92
+ (150, 190, 250, 255)),
93
+ buttonDownImage=slice('button_down', (24, 30, 42, 255),
94
+ (90, 110, 150, 255)),
95
+ buttonDisabledImage=slice('button_off', (28, 30, 34, 180),
96
+ (60, 66, 76, 255)),
97
+ fieldImage=slice('field', (12, 14, 20, 250), (80, 96, 130, 255)),
98
+ switchOffImage=slice('switch_off', (12, 14, 20, 250), (110, 130, 170, 255)),
99
+ switchOnImage=slice('switch_on', (60, 120, 80, 250), (140, 220, 160, 255)),
100
+ trackImage=slice('track', (12, 14, 20, 250), (70, 84, 112, 255)),
101
+ thumbImage=slice('thumb', (120, 150, 200, 255), (200, 220, 255, 255)),
102
+ panelPadding=20.0,
103
+ )
104
+
105
+
106
+ def movement_modes() -> List[Any]:
107
+ """The ways of moving this demo offers, so the settings screen has some."""
108
+ return [
109
+ movemodes.WalkMode(name='walk'),
110
+ movemodes.FlyMode(name='fly'),
111
+ movemodes.FPSMode(name='fps'),
112
+ ]
113
+
114
+
115
+ class UIDemoContext(OverlayMixin, BaseContext):
116
+ """A scene with the overlay screens bound to function keys.
117
+
118
+ The mix-in comes first so its event routing runs before the navigation
119
+ mix-in's: while a modal panel is up the movement sampler is not fed at all.
120
+ """
121
+
122
+ skinned: bool = False
123
+ skinDirectory: str = ''
124
+ console: Optional[console.ConsolePanel] = None
125
+ skin: Any = None
126
+
127
+ # Supplied by the interactive context this is built on.
128
+ addEventHandler: Any
129
+ frameCounter: Any
130
+ triggerRedraw: Any
131
+
132
+ def OnInit(self) -> None: # pragma: no cover - needs a window
133
+ self.skin = build_skin(self.skinDirectory) if self.skinned else None
134
+ self.sg = SceneGraph(children=[
135
+ DirectionalLight(direction=(-0.4, -1, -0.6), intensity=1.0),
136
+ Transform(translation=(-2, 0, 0), children=[Shape(
137
+ geometry=Sphere(radius=1.0),
138
+ appearance=Appearance(material=Material(
139
+ diffuseColor=(0.7, 0.3, 0.25))))]),
140
+ Transform(translation=(2, 0, 0), children=[Shape(
141
+ geometry=Box(size=(1.6, 1.6, 1.6)),
142
+ appearance=Appearance(material=Material(
143
+ diffuseColor=(0.25, 0.45, 0.7))))]),
144
+ ])
145
+ # ``keyboard`` key-downs, not ``keypress``: a function key produces no
146
+ # character, so GLFW raises no keypress for one and a keypress binding
147
+ # would be accepted and then never fire.
148
+ for key, handler in (('<F10>', self.openSettings),
149
+ ('<F9>', self.openConsole),
150
+ ('<F8>', self.openNotice),
151
+ ('<F7>', self.askSomething),
152
+ ('<F6>', self.openBindings)):
153
+ self.addEventHandler('keyboard', name=key, state=1,
154
+ function=handler)
155
+ sys.stdout.write(__doc__.split('Run it and press')[1])
156
+ sys.stdout.flush()
157
+
158
+ # -- the screens ------------------------------------------------------
159
+ def _skinned(self, panel: Any) -> Any:
160
+ if self.skin is not None:
161
+ panel.skin = self.skin
162
+ return panel
163
+
164
+ def openSettings(self, event: Any) -> None: # pragma: no cover - needs a window
165
+ panel = settings.settings_panel(self)
166
+ self.pushOverlay(self._skinned(panel))
167
+
168
+ def openBindings(self, event: Any) -> None: # pragma: no cover - needs a window
169
+ panel = bindings.open_bindings(self)
170
+ if panel is not None:
171
+ self._skinned(panel)
172
+
173
+ def openConsole(self, event: Any) -> None: # pragma: no cover - needs a window
174
+ registry = console.CommandRegistry()
175
+ registry.add('shadows', self._shadowsCommand,
176
+ 'turn shadows on or off: shadows on|off')
177
+ registry.add('fps', lambda panel: '%.1f' % (
178
+ self.frameCounter.recentFps(),), 'the recent frame rate')
179
+ panel = self._skinned(console.console_panel(registry=registry))
180
+ panel.write('Type "help" for the commands.')
181
+ # Engine warnings go where a player can read them.
182
+ logging.getLogger('OpenGLContext').addHandler(
183
+ console.ConsoleLogHandler(panel))
184
+ self.console = panel
185
+ self.pushOverlay(panel)
186
+
187
+ def _shadowsCommand(self, panel: Any, state: str = '') -> str:
188
+ if state:
189
+ self.contextDefinition.shadows = state.lower() in ('on', '1', 'true')
190
+ self.triggerRedraw(1)
191
+ return 'shadows are %s' % (
192
+ 'on' if self.contextDefinition.shadows else 'off',)
193
+
194
+ def openNotice(self, event: Any) -> None: # pragma: no cover - needs a window
195
+ self.pushOverlay(self._skinned(
196
+ dialogs.notice('Licence', NOTICE)))
197
+
198
+ def askSomething(self, event: Any) -> None: # pragma: no cover - needs a window
199
+ self.pushOverlay(self._skinned(dialogs.confirm(
200
+ 'Download the high-resolution texture pack?',
201
+ detail='About 40MB, cached for next time.',
202
+ yes='Download', no='Not now',
203
+ on_answer=lambda yes: log.warning('answered %s', yes))))
204
+
205
+
206
+ def main() -> int:
207
+ parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
208
+ parser.add_argument('--skin', action='store_true',
209
+ help='paint the screens with generated nine-slice artwork')
210
+ parser.add_argument('--skin-dir', default='',
211
+ help='where to write that artwork (default: a temp dir)')
212
+ options = parser.parse_args()
213
+ directory = options.skin_dir
214
+ if options.skin and not directory:
215
+ import tempfile
216
+ directory = tempfile.mkdtemp(prefix='oglc-ui-skin-')
217
+ UIDemoContext.skinned = bool(options.skin)
218
+ UIDemoContext.skinDirectory = directory
219
+ UIDemoContext.ContextMainLoop(definition=ContextDefinition(
220
+ title='OpenGLContext overlay UI',
221
+ size=(1024, 720),
222
+ movementModes=movement_modes(),
223
+ ))
224
+ return 0
225
+
226
+
227
+ if __name__ == '__main__':
228
+ sys.exit(main())
@@ -0,0 +1,341 @@
1
+ #! /usr/bin/env python
2
+ """Walk-around viewer for a 3D scene (``oglc-view``).
3
+
4
+ Opens a local file **or an http(s) URL**, renders it with the metallic/roughness
5
+ PBR pass, and lets you walk through it with the keyboard/mouse. What format the
6
+ source is in is worked out from the source itself, so one command opens them
7
+ all:
8
+
9
+ =============================== ==============================================
10
+ ``.gltf`` ``.glb`` a glTF 2.0 model
11
+ ``.wrl`` ``.wrz`` ``.vrml`` a VRML97 world
12
+ =============================== ==============================================
13
+
14
+ Every format gets everything the viewer can do. If the file contains no lights, a
15
+ default sun + fill rig is added so the scene is never rendered in the dark;
16
+ shadows are on by default. A scene that brings its own sky keeps it.
17
+
18
+ A model with no camera of its own is centred and auto-framed. The fit is on the
19
+ *model*: a part the file stranded far outside the rest is still drawn but does
20
+ not push the camera back to take it in, and the viewer prints a line saying how
21
+ many such parts there are and how far out they go. See docs/viewer.html.
22
+
23
+ Each camera the scene defines becomes a ``Viewpoint`` node, so PageUp/PageDown
24
+ cycle between them through OpenGLContext's standard viewpoint mechanism; cameras
25
+ are referred to by name where they have one. ``--capture`` renders the scene to a
26
+ PNG and exits, after a short settle delay so the analytic-sky IBL has converged.
27
+
28
+ Usage::
29
+
30
+ oglc-view path/to/model.glb
31
+ oglc-view path/to/world.wrl
32
+ oglc-view https://example.com/model.glb
33
+ oglc-view model.glb --camera aerial --capture shot.png --capture-delay 0.5
34
+ oglc-view model.glb --list-cameras
35
+ GLTF=path/to/model.gltf oglc-view
36
+
37
+ A ``.glb`` is self-contained, so URLs work cleanly. A ``.gltf`` URL fetches only
38
+ that file; models that reference external ``.bin``/texture files by relative URI
39
+ will be missing those (download the whole model set locally instead).
40
+
41
+ Controls (OpenGLContext's default view-platform navigation)::
42
+
43
+ Up / Down arrow walk forward / back
44
+ Left / Right arrow turn (yaw) left / right
45
+ Ctrl + Up/Down look up / down (pitch)
46
+ Alt + Up/Down move up / down (fly)
47
+ Alt + Left/Right strafe (slide) left / right
48
+ - level the horizon
49
+ right-mouse drag orbit / examine about a point
50
+ PgUp / PgDn (or p / n) cycle named cameras (if any)
51
+ g toggle walk (physics) / free-fly
52
+ k pause / resume animation; [ / ] switch animation
53
+ t stop/start the turntable (stopping resets orientation)
54
+ F2 save a screenshot (iso-dated PNG in the current directory)
55
+ Alt + s the same thing through the engine's own handler,
56
+ named for the program: oglc-view-screen-0001.png,
57
+ also in the current directory
58
+ Alt + f the developer overlay: frame rate and time, which
59
+ renderer features are on, what the last frame cost
60
+ in shapes and draw calls, and where the camera is
61
+ (see docs/hud.html)
62
+
63
+ Free-fly by default; ``--physics`` (or ``g``) walks the scene instead, with
64
+ gravity and collision keeping you on the ground and out of walls. ``g`` again
65
+ returns to free-fly, so a viewpoint inside the geometry is never a trap.
66
+
67
+ The viewer itself is :mod:`OpenGLContext.viewer`, which an application can embed
68
+ without this command line, and the formats it opens are the adapters registered
69
+ in :mod:`OpenGLContext.viewer.adapters`; see docs/gltf.html.
70
+ """
71
+ import argparse
72
+ import os
73
+ import sys
74
+ from typing import Any, Optional
75
+
76
+ os.environ.setdefault('OPENGLCONTEXT_PROFILE', 'core')
77
+ os.environ.setdefault('OPENGLCONTEXT_BACKEND', 'glfw')
78
+ os.environ.setdefault('OPENGLCONTEXT_RENDERER', 'pbr')
79
+ os.environ.setdefault('OPENGLCONTEXT_SHADOWS', '1')
80
+ # The directional-shadow cascade count is left fps-adaptive for interactive use:
81
+ # each extra cascade is a full depth pass over the whole scene (the dominant
82
+ # shadow-pass cost), so the controller sheds cascades when the frame rate sags.
83
+ # It is pinned only for --capture (see apply_render_env), where a reproducible
84
+ # frame matters more than the frame rate.
85
+ # Keep the warm analytic sky, but at reduced strength so the sun's cast shadows
86
+ # read clearly instead of being washed out by full-strength ambient.
87
+ os.environ.setdefault('OPENGLCONTEXT_IBL_INTENSITY', '0.4')
88
+
89
+ from OpenGLContext.viewer.adapters import (
90
+ UnknownSourceType, adapter_for, adapter_named, known_sources,
91
+ )
92
+ from OpenGLContext.viewer.sceneviewer import ViewerContext
93
+ from OpenGLContext.viewer.options import ViewerOptions
94
+ from OpenGLContext.viewer.source import resolve_source
95
+
96
+
97
+ # -- command line ---------------------------------------------------------
98
+
99
+ def _parse_size(text: str) -> tuple[int, int]:
100
+ """Parse a ``WxH`` window size into an (int, int) tuple."""
101
+ try:
102
+ w, h = (int(v) for v in text.lower().split('x'))
103
+ return (w, h)
104
+ except Exception:
105
+ raise argparse.ArgumentTypeError("size must be WxH, e.g. 1100x680") from None
106
+
107
+
108
+ def _format_names() -> list[str]:
109
+ """The registered adapter names, for ``--format``'s help."""
110
+ from OpenGLContext import plugins
111
+ return sorted(entry.name for entry in plugins.Adapter.all())
112
+
113
+
114
+ def _parse_vec3(text: str) -> tuple[float, ...]:
115
+ """Parse an ``X,Y,Z`` world-space point."""
116
+ parts = text.split(',')
117
+ if len(parts) != 3:
118
+ raise argparse.ArgumentTypeError('expected X,Y,Z, got %r' % text)
119
+ return tuple(float(v) for v in parts)
120
+
121
+
122
+ def build_parser(prog: str = 'oglc-view') -> argparse.ArgumentParser:
123
+ """The viewer's command line.
124
+
125
+ Every option is declared ``default=argparse.SUPPRESS`` so that an option
126
+ nobody passed leaves the corresponding :class:`ViewerOptions` field alone.
127
+ The defaults are the dataclass's, stated once, and the help text below
128
+ names them where a user needs to know.
129
+ """
130
+ parser = argparse.ArgumentParser(
131
+ prog=prog,
132
+ description='Walk-around viewer for a 3D scene: %s.' % ', '.join(
133
+ # Suffixes and conventional file names; the content types the same
134
+ # adapters answer to are not something anyone types.
135
+ key for key in known_sources() if '/' not in key),
136
+ formatter_class=argparse.RawDescriptionHelpFormatter,
137
+ argument_default=argparse.SUPPRESS,
138
+ epilog="A local path or an http(s) URL. .glb is self-contained (URLs work "
139
+ "cleanly); a .gltf that references external .bin/textures should be "
140
+ "downloaded locally as a set. Falls back to the GLTF env var.",
141
+ )
142
+ parser.add_argument('source', nargs='?',
143
+ help='scene file path or http(s) URL (or set GLTF=...)')
144
+ parser.add_argument('--format', metavar='NAME',
145
+ help='read the source as this format instead of guessing '
146
+ 'from its name (%s); for a URL that serves a scene '
147
+ 'from a path with no suffix'
148
+ % ', '.join(_format_names()))
149
+ parser.add_argument('--camera', metavar='NAME|INDEX',
150
+ help='initial camera, by the name the scene gives it '
151
+ '(preferred) or 0-based index')
152
+ parser.add_argument('--list-cameras', action='store_true',
153
+ help="print the scene's camera names and exit")
154
+ parser.add_argument('--no-cameras', action='store_true',
155
+ help="ignore the scene's own cameras; centre and auto-frame it")
156
+ parser.add_argument('--capture', metavar='PATH',
157
+ help='render to PATH (PNG) after settling, then exit')
158
+ parser.add_argument('--capture-delay', type=float, metavar='SECONDS',
159
+ help='seconds to let the scene settle before --capture (default 0.5)')
160
+ parser.add_argument('--frames', type=int, metavar='N',
161
+ help='minimum frames to render before --capture (default 10)')
162
+ parser.add_argument('--shadows', action=argparse.BooleanOptionalAction,
163
+ help='force shadows on/off (default: on)')
164
+ parser.add_argument('--lights', choices=['auto', 'on', 'off'],
165
+ help="default light rig: auto (add only if the file has none), "
166
+ "on (always add), off (never add)")
167
+ parser.add_argument('--ibl-intensity', type=float, metavar='SCALE',
168
+ help='scale the analytic-sky ambient/IBL contribution')
169
+ parser.add_argument('--environment', metavar='PREFIX|HDR|NAME',
170
+ help='image-based environment: a cubemap face prefix '
171
+ '(<PREFIX>{RT,LF,UP,DN,FR,BK}.jpg), an equirectangular '
172
+ 'Radiance .hdr panorama (local path or http(s) URL), or a '
173
+ 'bundled CC0 HDRI name (e.g. studio_small_03). Reflected '
174
+ 'by metals and drawn as the skybox. Pins full IBL.')
175
+ parser.add_argument('--background', metavar='SPEC',
176
+ help="background: 'sky' (default), 'none', or 'R,G,B'")
177
+ parser.add_argument('--size', type=_parse_size, metavar='WxH',
178
+ help='window size, e.g. 1100x680')
179
+ # Streaming sources (3D Tiles): ignored by a format that is read once.
180
+ parser.add_argument('--sse', type=float, metavar='PIXELS',
181
+ help='streamed datasets: max screen-space error in '
182
+ 'pixels; lower = more detail (default 16)')
183
+ parser.add_argument('--memory', type=int, metavar='MiB',
184
+ help='streamed datasets: resident tile memory budget '
185
+ '(default 512)')
186
+ parser.add_argument('--no-recenter', dest='no_recenter', action='store_true',
187
+ help='streamed datasets: do not shift a geospatial '
188
+ '(Earth-centred) dataset to the origin')
189
+ parser.add_argument('--cache-dir', dest='cache_dir', metavar='DIR',
190
+ help='where to cache data fetched from a URL')
191
+ parser.add_argument('--physics', action=argparse.BooleanOptionalAction,
192
+ help='walk the model with gravity + collision (default off, so '
193
+ 'an isolated/floorless model stays framed instead of the '
194
+ 'avatar falling past it); press "g" or pass --physics to walk')
195
+ parser.add_argument('--turntable', action='store_true',
196
+ help='slowly rotate the model')
197
+ parser.add_argument('--no-rotate', dest='no_rotate', action='store_true',
198
+ help='never rotate the model (fixed orientation, to line a '
199
+ 'capture up with a reference image)')
200
+ parser.add_argument('--animation', metavar='NAME|INDEX',
201
+ help='play this glTF animation (name or 0-based index); '
202
+ 'default: play the first animation if any')
203
+ parser.add_argument('--no-animation', dest='animate', action='store_false',
204
+ help='do not play embedded animations')
205
+ parser.add_argument('--anim-time', type=float, metavar='SECONDS',
206
+ help='pin the animation to this time (deterministic capture)')
207
+ parser.add_argument('--yaw', type=float,
208
+ help='initial model yaw (radians) when auto-framing '
209
+ '(default -0.62, or the YAW env var)')
210
+ parser.add_argument('--margin', type=float, metavar='FACTOR',
211
+ help='auto-frame fit factor (default 1.15); below 1 pulls '
212
+ 'the camera in so the model fills more of the frame')
213
+ parser.add_argument('--elevation', type=float, metavar='FRAC',
214
+ help='auto-frame camera height as a fraction of the model '
215
+ 'radius (default 0.22)')
216
+ parser.add_argument('--tilt', type=float, metavar='RADIANS',
217
+ help='auto-frame downward camera tilt in radians (default 0.10)')
218
+ parser.add_argument('--eye', type=_parse_vec3, metavar='X,Y,Z',
219
+ help='explicit camera position (world space); with --look-at '
220
+ 'this bypasses auto-framing (e.g. an interior shot)')
221
+ parser.add_argument('--look-at', dest='look_at', type=_parse_vec3,
222
+ metavar='X,Y,Z', help='explicit camera target (world space)')
223
+ return parser
224
+
225
+
226
+ def parse_args(argv: list[str] | None = None, prog: str = 'oglc-view',
227
+ options: ViewerOptions | None = None) -> ViewerOptions:
228
+ """Parse the viewer's command line into a :class:`ViewerOptions` (no GL).
229
+
230
+ ``options`` is filled in and returned when given, so a program built on this
231
+ one can start from its own defaults and let the user override them.
232
+ """
233
+ return build_parser(prog).parse_args(
234
+ argv, namespace=options if options is not None else ViewerOptions())
235
+
236
+
237
+ def _is_hdr_environment(spec: str | None) -> bool:
238
+ """Whether ``--environment SPEC`` names a Radiance ``.hdr`` panorama.
239
+
240
+ An equirectangular ``.hdr``/``.pic`` (local path or http(s) URL) is treated as
241
+ an HDR IBL source + skybox; anything else is a six-face cubemap prefix. The
242
+ query string of a URL is ignored so a CDN link with parameters still matches.
243
+ """
244
+ if not spec:
245
+ return False
246
+ path = spec.split('?', 1)[0].split('#', 1)[0]
247
+ return path.lower().endswith(('.hdr', '.pic'))
248
+
249
+
250
+ def apply_render_env(args: ViewerOptions) -> None:
251
+ """Translate render-affecting options into the variables the renderer reads.
252
+
253
+ These are start-up switches read once by the passes (see
254
+ :mod:`OpenGLContext.renderoptions`), so they are set before a context exists
255
+ rather than carried on the options object.
256
+ """
257
+ if args.shadows is not None:
258
+ os.environ['OPENGLCONTEXT_SHADOWS'] = '1' if args.shadows else '0'
259
+ if args.ibl_intensity is not None:
260
+ os.environ['OPENGLCONTEXT_IBL_INTENSITY'] = str(args.ibl_intensity)
261
+ if args.environment:
262
+ from OpenGLContext.loaders import hdri
263
+ try:
264
+ args.environment = hdri.resolve(args.environment) # catalogue name -> URL
265
+ except KeyError:
266
+ pass # not a catalogue name; treat as a cubemap prefix / path
267
+ environment: str = args.environment
268
+ if _is_hdr_environment(environment):
269
+ # An equirectangular Radiance .hdr (local path or URL): drives the IBL
270
+ # probe and the HDR skybox. The probe loads it via OPENGLCONTEXT_ENV_HDR.
271
+ os.environ['OPENGLCONTEXT_ENV_HDR'] = environment
272
+ else:
273
+ os.environ['OPENGLCONTEXT_ENV_CUBEMAP'] = environment
274
+ os.environ.setdefault('OPENGLCONTEXT_IBL', 'full') # env probe needs full IBL
275
+ elif (args.background == 'none'
276
+ and not os.environ.get('OPENGLCONTEXT_ENV_CUBEMAP')
277
+ and not os.environ.get('OPENGLCONTEXT_ENV_HDR')):
278
+ # A self-lit scene (its own KHR_lights_punctual, black backdrop, NO env probe)
279
+ # must get no analytic-sky IBL, or the ambient sky washes it pale grey instead
280
+ # of the dark scene its lights make. But only when there is genuinely no
281
+ # environment: the browser demo defaults --background 'none' yet loads an env
282
+ # cubemap probe for metals to reflect, so forcing IBL off there rendered every
283
+ # metal black. Honour an explicit env cubemap or HDR panorama.
284
+ os.environ['OPENGLCONTEXT_IBL'] = 'off'
285
+ if args.capture:
286
+ # a --capture run wants a clean frame, not the fps overlay
287
+ os.environ['OPENGLCONTEXT_DISABLE_FPS_DISPLAY'] = '1'
288
+ # A capture must be reproducible: pin the otherwise fps-adaptive cascade
289
+ # count so the shadows don't vary with the frame rate between runs. An
290
+ # explicit user setting still wins.
291
+ os.environ.setdefault('OPENGLCONTEXT_SHADOW_CASCADES', '3')
292
+ # Nobody is watching a capture, and a *mapped* surface is what makes it
293
+ # hang: a compositor throttles the swap to its own frame callback, and
294
+ # with no window on screen consuming frames the swap never returns. A
295
+ # hidden window renders and reads back identically. Both stay
296
+ # overridable, since watching a capture happen is how you find out why
297
+ # it looks wrong.
298
+ os.environ.setdefault('OPENGLCONTEXT_HIDDEN', '1')
299
+ os.environ.setdefault('OPENGLCONTEXT_NO_VSYNC', '1')
300
+
301
+
302
+ class TestContext(ViewerContext):
303
+ """``oglc-view`` itself: the viewing component, configured from the command line."""
304
+
305
+
306
+ def _list_cameras(source: str, format: Optional[str] = None) -> int:
307
+ """Print the scene's camera names, for choosing one with ``--camera``.
308
+
309
+ The adapter answers, so this works for every format rather than only the one
310
+ the listing was first written for.
311
+ """
312
+ adapter = adapter_named(format) if format else adapter_for(source)
313
+ scene = adapter.load(source)
314
+ if not scene.cameras:
315
+ sys.stdout.write("(no cameras defined in %s)\n" % os.path.basename(source))
316
+ for i, camera in enumerate(scene.cameras):
317
+ sys.stdout.write("%d: %s\n" % (i, camera.get('name') or 'camera'))
318
+ return 0
319
+
320
+
321
+ def main(argv: Optional[list[str]] = None, prog: str = 'oglc-view') -> Any:
322
+ parser = build_parser(prog)
323
+ options = parser.parse_args(argv, namespace=ViewerOptions())
324
+ source = options.source or os.environ.get('GLTF')
325
+ if options.list_cameras and not source:
326
+ parser.error('nothing to list cameras for (pass a path or a URL)')
327
+
328
+ if options.list_cameras:
329
+ try:
330
+ return _list_cameras(resolve_source(source) or source, options.format)
331
+ except UnknownSourceType as error:
332
+ parser.error(str(error))
333
+
334
+ apply_render_env(options)
335
+ TestContext.options = options
336
+ return TestContext.ContextMainLoop(size=options.size) if options.size \
337
+ else TestContext.ContextMainLoop()
338
+
339
+
340
+ if __name__ == "__main__": # pragma: no cover - CLI entry point
341
+ main()
@@ -0,0 +1,42 @@
1
+ #! /usr/bin/env python
2
+ """``oglc-vrml`` -- the former VRML97-only viewer, now an alias for ``oglc-view``.
3
+
4
+ There is one viewer, and it works out the format from the source, so the command
5
+ that opens a ``.wrl`` is the command that opens a ``.glb``. A VRML world opened
6
+ this way gains everything that was previously only in the glTF viewer: framing,
7
+ loading in the background, camera cycling over the world's own ``Viewpoint``
8
+ nodes, a caption, screenshots, ``--capture``, and walking with gravity and
9
+ collision. See :mod:`OpenGLContext.bin.view`.
10
+
11
+ The old ``--shaders`` / ``--no-shaders`` switches are gone: they reached into the
12
+ render pass from inside ``Redraw`` to turn on shader rendering, and the viewer
13
+ now renders through the core-profile PBR pass as a matter of course. A world
14
+ that genuinely wants the compatibility pipeline gets it from the environment,
15
+ which is where every other renderer switch lives::
16
+
17
+ OPENGLCONTEXT_PROFILE=compatibility oglc-view world.wrl
18
+
19
+ This name is kept for one release cycle so existing scripts and documentation
20
+ keep working, and prints where to go instead. It will then be removed.
21
+ """
22
+ import sys
23
+ from typing import Any, Optional
24
+
25
+ from OpenGLContext.bin.view import main as view_main
26
+
27
+ #: What to type now. Named here so the notice and the replacement cannot drift.
28
+ REPLACEMENT = 'oglc-view'
29
+
30
+
31
+ def main(argv: Optional[list] = None) -> Any:
32
+ """Run ``oglc-view``, having said that is what this now is."""
33
+ sys.stderr.write(
34
+ "oglc-vrml is deprecated and will be removed; use %s instead "
35
+ "(it opens every format, and a world gets the full viewer).\n"
36
+ % REPLACEMENT)
37
+ sys.stderr.flush()
38
+ return view_main(argv, prog='oglc-vrml')
39
+
40
+
41
+ if __name__ == "__main__": # pragma: no cover - CLI entry point
42
+ main()