vispy 0.14.0__cp311-cp311-macosx_11_0_arm64.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.

Potentially problematic release.


This version of vispy might be problematic. Click here for more details.

Files changed (519) hide show
  1. vispy/__init__.py +33 -0
  2. vispy/app/__init__.py +15 -0
  3. vispy/app/_default_app.py +76 -0
  4. vispy/app/_detect_eventloop.py +148 -0
  5. vispy/app/application.py +263 -0
  6. vispy/app/backends/__init__.py +52 -0
  7. vispy/app/backends/_egl.py +264 -0
  8. vispy/app/backends/_glfw.py +513 -0
  9. vispy/app/backends/_jupyter_rfb.py +278 -0
  10. vispy/app/backends/_offscreen_util.py +121 -0
  11. vispy/app/backends/_osmesa.py +235 -0
  12. vispy/app/backends/_pyglet.py +451 -0
  13. vispy/app/backends/_pyqt4.py +36 -0
  14. vispy/app/backends/_pyqt5.py +36 -0
  15. vispy/app/backends/_pyqt6.py +40 -0
  16. vispy/app/backends/_pyside.py +37 -0
  17. vispy/app/backends/_pyside2.py +52 -0
  18. vispy/app/backends/_pyside6.py +53 -0
  19. vispy/app/backends/_qt.py +968 -0
  20. vispy/app/backends/_sdl2.py +444 -0
  21. vispy/app/backends/_template.py +244 -0
  22. vispy/app/backends/_test.py +8 -0
  23. vispy/app/backends/_tk.py +800 -0
  24. vispy/app/backends/_wx.py +476 -0
  25. vispy/app/backends/tests/__init__.py +0 -0
  26. vispy/app/backends/tests/test_offscreen_util.py +52 -0
  27. vispy/app/backends/tests/test_rfb.py +77 -0
  28. vispy/app/base.py +294 -0
  29. vispy/app/canvas.py +828 -0
  30. vispy/app/qt.py +92 -0
  31. vispy/app/tests/__init__.py +0 -0
  32. vispy/app/tests/qt-designer.ui +58 -0
  33. vispy/app/tests/test_app.py +442 -0
  34. vispy/app/tests/test_backends.py +164 -0
  35. vispy/app/tests/test_canvas.py +122 -0
  36. vispy/app/tests/test_context.py +92 -0
  37. vispy/app/tests/test_qt.py +47 -0
  38. vispy/app/tests/test_simultaneous.py +134 -0
  39. vispy/app/timer.py +174 -0
  40. vispy/color/__init__.py +17 -0
  41. vispy/color/_color_dict.py +193 -0
  42. vispy/color/color_array.py +447 -0
  43. vispy/color/color_space.py +181 -0
  44. vispy/color/colormap.py +1134 -0
  45. vispy/color/tests/__init__.py +0 -0
  46. vispy/color/tests/test_color.py +352 -0
  47. vispy/conftest.py +12 -0
  48. vispy/ext/__init__.py +0 -0
  49. vispy/ext/cocoapy.py +1542 -0
  50. vispy/ext/cubehelix.py +138 -0
  51. vispy/ext/egl.py +375 -0
  52. vispy/ext/fontconfig.py +118 -0
  53. vispy/ext/gdi32plus.py +206 -0
  54. vispy/ext/osmesa.py +105 -0
  55. vispy/geometry/__init__.py +23 -0
  56. vispy/geometry/_triangulation_debugger.py +171 -0
  57. vispy/geometry/calculations.py +134 -0
  58. vispy/geometry/curves.py +399 -0
  59. vispy/geometry/generation.py +643 -0
  60. vispy/geometry/isocurve.py +175 -0
  61. vispy/geometry/isosurface.py +465 -0
  62. vispy/geometry/meshdata.py +698 -0
  63. vispy/geometry/normals.py +78 -0
  64. vispy/geometry/parametric.py +56 -0
  65. vispy/geometry/polygon.py +137 -0
  66. vispy/geometry/rect.py +210 -0
  67. vispy/geometry/tests/__init__.py +0 -0
  68. vispy/geometry/tests/test_calculations.py +23 -0
  69. vispy/geometry/tests/test_generation.py +56 -0
  70. vispy/geometry/tests/test_meshdata.py +106 -0
  71. vispy/geometry/tests/test_triangulation.py +506 -0
  72. vispy/geometry/torusknot.py +142 -0
  73. vispy/geometry/triangulation.py +876 -0
  74. vispy/gloo/__init__.py +56 -0
  75. vispy/gloo/buffer.py +505 -0
  76. vispy/gloo/context.py +272 -0
  77. vispy/gloo/framebuffer.py +257 -0
  78. vispy/gloo/gl/__init__.py +234 -0
  79. vispy/gloo/gl/_constants.py +332 -0
  80. vispy/gloo/gl/_es2.py +986 -0
  81. vispy/gloo/gl/_gl2.py +1365 -0
  82. vispy/gloo/gl/_proxy.py +499 -0
  83. vispy/gloo/gl/_pyopengl2.py +362 -0
  84. vispy/gloo/gl/dummy.py +24 -0
  85. vispy/gloo/gl/es2.py +62 -0
  86. vispy/gloo/gl/gl2.py +98 -0
  87. vispy/gloo/gl/glplus.py +168 -0
  88. vispy/gloo/gl/pyopengl2.py +97 -0
  89. vispy/gloo/gl/tests/__init__.py +0 -0
  90. vispy/gloo/gl/tests/test_basics.py +282 -0
  91. vispy/gloo/gl/tests/test_functionality.py +566 -0
  92. vispy/gloo/gl/tests/test_names.py +246 -0
  93. vispy/gloo/gl/tests/test_use.py +71 -0
  94. vispy/gloo/glir.py +1816 -0
  95. vispy/gloo/globject.py +101 -0
  96. vispy/gloo/preprocessor.py +67 -0
  97. vispy/gloo/program.py +543 -0
  98. vispy/gloo/tests/__init__.py +0 -0
  99. vispy/gloo/tests/test_buffer.py +558 -0
  100. vispy/gloo/tests/test_context.py +119 -0
  101. vispy/gloo/tests/test_framebuffer.py +195 -0
  102. vispy/gloo/tests/test_glir.py +307 -0
  103. vispy/gloo/tests/test_globject.py +35 -0
  104. vispy/gloo/tests/test_program.py +302 -0
  105. vispy/gloo/tests/test_texture.py +732 -0
  106. vispy/gloo/tests/test_use_gloo.py +187 -0
  107. vispy/gloo/tests/test_util.py +60 -0
  108. vispy/gloo/tests/test_wrappers.py +261 -0
  109. vispy/gloo/texture.py +1045 -0
  110. vispy/gloo/util.py +129 -0
  111. vispy/gloo/wrappers.py +762 -0
  112. vispy/glsl/__init__.py +42 -0
  113. vispy/glsl/antialias/antialias.glsl +7 -0
  114. vispy/glsl/antialias/cap-butt.glsl +31 -0
  115. vispy/glsl/antialias/cap-round.glsl +29 -0
  116. vispy/glsl/antialias/cap-square.glsl +30 -0
  117. vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
  118. vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
  119. vispy/glsl/antialias/cap.glsl +67 -0
  120. vispy/glsl/antialias/caps.glsl +67 -0
  121. vispy/glsl/antialias/filled.glsl +50 -0
  122. vispy/glsl/antialias/outline.glsl +40 -0
  123. vispy/glsl/antialias/stroke.glsl +43 -0
  124. vispy/glsl/arrowheads/angle.glsl +99 -0
  125. vispy/glsl/arrowheads/arrowheads.frag +60 -0
  126. vispy/glsl/arrowheads/arrowheads.glsl +12 -0
  127. vispy/glsl/arrowheads/arrowheads.vert +83 -0
  128. vispy/glsl/arrowheads/curved.glsl +48 -0
  129. vispy/glsl/arrowheads/inhibitor.glsl +26 -0
  130. vispy/glsl/arrowheads/stealth.glsl +46 -0
  131. vispy/glsl/arrowheads/triangle.glsl +97 -0
  132. vispy/glsl/arrowheads/util.glsl +13 -0
  133. vispy/glsl/arrows/angle-30.glsl +12 -0
  134. vispy/glsl/arrows/angle-60.glsl +12 -0
  135. vispy/glsl/arrows/angle-90.glsl +12 -0
  136. vispy/glsl/arrows/arrow.frag +39 -0
  137. vispy/glsl/arrows/arrow.vert +49 -0
  138. vispy/glsl/arrows/arrows.glsl +17 -0
  139. vispy/glsl/arrows/common.glsl +187 -0
  140. vispy/glsl/arrows/curved.glsl +63 -0
  141. vispy/glsl/arrows/stealth.glsl +50 -0
  142. vispy/glsl/arrows/triangle-30.glsl +12 -0
  143. vispy/glsl/arrows/triangle-60.glsl +12 -0
  144. vispy/glsl/arrows/triangle-90.glsl +12 -0
  145. vispy/glsl/arrows/util.glsl +98 -0
  146. vispy/glsl/build_spatial_filters.py +660 -0
  147. vispy/glsl/collections/agg-fast-path.frag +20 -0
  148. vispy/glsl/collections/agg-fast-path.vert +78 -0
  149. vispy/glsl/collections/agg-glyph.frag +60 -0
  150. vispy/glsl/collections/agg-glyph.vert +33 -0
  151. vispy/glsl/collections/agg-marker.frag +35 -0
  152. vispy/glsl/collections/agg-marker.vert +48 -0
  153. vispy/glsl/collections/agg-path.frag +55 -0
  154. vispy/glsl/collections/agg-path.vert +166 -0
  155. vispy/glsl/collections/agg-point.frag +21 -0
  156. vispy/glsl/collections/agg-point.vert +35 -0
  157. vispy/glsl/collections/agg-segment.frag +32 -0
  158. vispy/glsl/collections/agg-segment.vert +75 -0
  159. vispy/glsl/collections/marker.frag +38 -0
  160. vispy/glsl/collections/marker.vert +48 -0
  161. vispy/glsl/collections/raw-path.frag +15 -0
  162. vispy/glsl/collections/raw-path.vert +24 -0
  163. vispy/glsl/collections/raw-point.frag +14 -0
  164. vispy/glsl/collections/raw-point.vert +31 -0
  165. vispy/glsl/collections/raw-segment.frag +18 -0
  166. vispy/glsl/collections/raw-segment.vert +26 -0
  167. vispy/glsl/collections/raw-triangle.frag +13 -0
  168. vispy/glsl/collections/raw-triangle.vert +26 -0
  169. vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
  170. vispy/glsl/collections/sdf-glyph.frag +80 -0
  171. vispy/glsl/collections/sdf-glyph.vert +59 -0
  172. vispy/glsl/collections/tick-labels.vert +71 -0
  173. vispy/glsl/colormaps/autumn.glsl +20 -0
  174. vispy/glsl/colormaps/blues.glsl +20 -0
  175. vispy/glsl/colormaps/color-space.glsl +17 -0
  176. vispy/glsl/colormaps/colormaps.glsl +24 -0
  177. vispy/glsl/colormaps/cool.glsl +20 -0
  178. vispy/glsl/colormaps/fire.glsl +21 -0
  179. vispy/glsl/colormaps/gray.glsl +20 -0
  180. vispy/glsl/colormaps/greens.glsl +20 -0
  181. vispy/glsl/colormaps/hot.glsl +22 -0
  182. vispy/glsl/colormaps/ice.glsl +20 -0
  183. vispy/glsl/colormaps/icefire.glsl +23 -0
  184. vispy/glsl/colormaps/parse.py +40 -0
  185. vispy/glsl/colormaps/reds.glsl +20 -0
  186. vispy/glsl/colormaps/spring.glsl +20 -0
  187. vispy/glsl/colormaps/summer.glsl +20 -0
  188. vispy/glsl/colormaps/user.glsl +22 -0
  189. vispy/glsl/colormaps/util.glsl +41 -0
  190. vispy/glsl/colormaps/wheel.glsl +21 -0
  191. vispy/glsl/colormaps/winter.glsl +20 -0
  192. vispy/glsl/lines/agg.frag +320 -0
  193. vispy/glsl/lines/agg.vert +241 -0
  194. vispy/glsl/markers/arrow.glsl +12 -0
  195. vispy/glsl/markers/asterisk.glsl +16 -0
  196. vispy/glsl/markers/chevron.glsl +14 -0
  197. vispy/glsl/markers/clover.glsl +20 -0
  198. vispy/glsl/markers/club.glsl +31 -0
  199. vispy/glsl/markers/cross.glsl +17 -0
  200. vispy/glsl/markers/diamond.glsl +12 -0
  201. vispy/glsl/markers/disc.glsl +9 -0
  202. vispy/glsl/markers/ellipse.glsl +67 -0
  203. vispy/glsl/markers/hbar.glsl +9 -0
  204. vispy/glsl/markers/heart.glsl +15 -0
  205. vispy/glsl/markers/infinity.glsl +15 -0
  206. vispy/glsl/markers/marker-sdf.frag +74 -0
  207. vispy/glsl/markers/marker-sdf.vert +41 -0
  208. vispy/glsl/markers/marker.frag +36 -0
  209. vispy/glsl/markers/marker.vert +46 -0
  210. vispy/glsl/markers/markers.glsl +24 -0
  211. vispy/glsl/markers/pin.glsl +18 -0
  212. vispy/glsl/markers/ring.glsl +11 -0
  213. vispy/glsl/markers/spade.glsl +28 -0
  214. vispy/glsl/markers/square.glsl +10 -0
  215. vispy/glsl/markers/tag.glsl +11 -0
  216. vispy/glsl/markers/triangle.glsl +14 -0
  217. vispy/glsl/markers/vbar.glsl +9 -0
  218. vispy/glsl/math/circle-through-2-points.glsl +30 -0
  219. vispy/glsl/math/constants.glsl +48 -0
  220. vispy/glsl/math/double.glsl +114 -0
  221. vispy/glsl/math/functions.glsl +20 -0
  222. vispy/glsl/math/point-to-line-distance.glsl +31 -0
  223. vispy/glsl/math/point-to-line-projection.glsl +29 -0
  224. vispy/glsl/math/signed-line-distance.glsl +27 -0
  225. vispy/glsl/math/signed-segment-distance.glsl +30 -0
  226. vispy/glsl/misc/regular-grid.frag +244 -0
  227. vispy/glsl/misc/spatial-filters.frag +1407 -0
  228. vispy/glsl/misc/viewport-NDC.glsl +20 -0
  229. vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
  230. vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
  231. vispy/glsl/transforms/hammer.glsl +44 -0
  232. vispy/glsl/transforms/identity.glsl +6 -0
  233. vispy/glsl/transforms/identity_forward.glsl +23 -0
  234. vispy/glsl/transforms/identity_inverse.glsl +23 -0
  235. vispy/glsl/transforms/linear-scale.glsl +127 -0
  236. vispy/glsl/transforms/log-scale.glsl +126 -0
  237. vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
  238. vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
  239. vispy/glsl/transforms/panzoom.glsl +10 -0
  240. vispy/glsl/transforms/polar.glsl +41 -0
  241. vispy/glsl/transforms/position.glsl +44 -0
  242. vispy/glsl/transforms/power-scale.glsl +139 -0
  243. vispy/glsl/transforms/projection.glsl +7 -0
  244. vispy/glsl/transforms/pvm.glsl +13 -0
  245. vispy/glsl/transforms/rotate.glsl +45 -0
  246. vispy/glsl/transforms/trackball.glsl +15 -0
  247. vispy/glsl/transforms/translate.glsl +35 -0
  248. vispy/glsl/transforms/transverse_mercator.glsl +38 -0
  249. vispy/glsl/transforms/viewport-clipping.glsl +14 -0
  250. vispy/glsl/transforms/viewport-transform.glsl +16 -0
  251. vispy/glsl/transforms/viewport.glsl +50 -0
  252. vispy/glsl/transforms/x.glsl +24 -0
  253. vispy/glsl/transforms/y.glsl +19 -0
  254. vispy/glsl/transforms/z.glsl +14 -0
  255. vispy/io/__init__.py +20 -0
  256. vispy/io/_data/spatial-filters.npy +0 -0
  257. vispy/io/datasets.py +94 -0
  258. vispy/io/image.py +231 -0
  259. vispy/io/mesh.py +122 -0
  260. vispy/io/stl.py +167 -0
  261. vispy/io/tests/__init__.py +0 -0
  262. vispy/io/tests/test_image.py +47 -0
  263. vispy/io/tests/test_io.py +121 -0
  264. vispy/io/wavefront.py +350 -0
  265. vispy/plot/__init__.py +36 -0
  266. vispy/plot/fig.py +58 -0
  267. vispy/plot/plotwidget.py +522 -0
  268. vispy/plot/tests/__init__.py +0 -0
  269. vispy/plot/tests/test_plot.py +46 -0
  270. vispy/scene/__init__.py +43 -0
  271. vispy/scene/cameras/__init__.py +27 -0
  272. vispy/scene/cameras/_base.py +38 -0
  273. vispy/scene/cameras/arcball.py +106 -0
  274. vispy/scene/cameras/base_camera.py +538 -0
  275. vispy/scene/cameras/fly.py +474 -0
  276. vispy/scene/cameras/magnify.py +163 -0
  277. vispy/scene/cameras/panzoom.py +308 -0
  278. vispy/scene/cameras/perspective.py +333 -0
  279. vispy/scene/cameras/tests/__init__.py +0 -0
  280. vispy/scene/cameras/tests/test_cameras.py +27 -0
  281. vispy/scene/cameras/tests/test_link.py +53 -0
  282. vispy/scene/cameras/tests/test_perspective.py +122 -0
  283. vispy/scene/cameras/turntable.py +173 -0
  284. vispy/scene/canvas.py +639 -0
  285. vispy/scene/events.py +85 -0
  286. vispy/scene/node.py +644 -0
  287. vispy/scene/subscene.py +20 -0
  288. vispy/scene/tests/__init__.py +0 -0
  289. vispy/scene/tests/test_canvas.py +119 -0
  290. vispy/scene/tests/test_node.py +142 -0
  291. vispy/scene/tests/test_visuals.py +141 -0
  292. vispy/scene/visuals.py +276 -0
  293. vispy/scene/widgets/__init__.py +18 -0
  294. vispy/scene/widgets/anchor.py +25 -0
  295. vispy/scene/widgets/axis.py +88 -0
  296. vispy/scene/widgets/colorbar.py +176 -0
  297. vispy/scene/widgets/console.py +351 -0
  298. vispy/scene/widgets/grid.py +509 -0
  299. vispy/scene/widgets/label.py +50 -0
  300. vispy/scene/widgets/tests/__init__.py +0 -0
  301. vispy/scene/widgets/tests/test_colorbar.py +47 -0
  302. vispy/scene/widgets/viewbox.py +199 -0
  303. vispy/scene/widgets/widget.py +478 -0
  304. vispy/testing/__init__.py +51 -0
  305. vispy/testing/_runners.py +446 -0
  306. vispy/testing/_testing.py +416 -0
  307. vispy/testing/image_tester.py +473 -0
  308. vispy/testing/rendered_array_tester.py +85 -0
  309. vispy/testing/tests/__init__.py +0 -0
  310. vispy/testing/tests/test_testing.py +20 -0
  311. vispy/util/__init__.py +17 -0
  312. vispy/util/bunch.py +15 -0
  313. vispy/util/check_environment.py +57 -0
  314. vispy/util/config.py +490 -0
  315. vispy/util/dpi/__init__.py +19 -0
  316. vispy/util/dpi/_linux.py +69 -0
  317. vispy/util/dpi/_quartz.py +26 -0
  318. vispy/util/dpi/_win32.py +34 -0
  319. vispy/util/dpi/tests/__init__.py +0 -0
  320. vispy/util/dpi/tests/test_dpi.py +16 -0
  321. vispy/util/eq.py +41 -0
  322. vispy/util/event.py +774 -0
  323. vispy/util/fetching.py +276 -0
  324. vispy/util/filter.py +44 -0
  325. vispy/util/fonts/__init__.py +14 -0
  326. vispy/util/fonts/_freetype.py +73 -0
  327. vispy/util/fonts/_quartz.py +192 -0
  328. vispy/util/fonts/_triage.py +36 -0
  329. vispy/util/fonts/_vispy_fonts.py +20 -0
  330. vispy/util/fonts/_win32.py +105 -0
  331. vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
  332. vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
  333. vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
  334. vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
  335. vispy/util/fonts/tests/__init__.py +0 -0
  336. vispy/util/fonts/tests/test_font.py +45 -0
  337. vispy/util/fourier.py +69 -0
  338. vispy/util/frozen.py +25 -0
  339. vispy/util/gallery_scraper.py +268 -0
  340. vispy/util/keys.py +91 -0
  341. vispy/util/logs.py +358 -0
  342. vispy/util/osmesa_gl.py +17 -0
  343. vispy/util/profiler.py +135 -0
  344. vispy/util/ptime.py +16 -0
  345. vispy/util/quaternion.py +229 -0
  346. vispy/util/svg/__init__.py +18 -0
  347. vispy/util/svg/base.py +20 -0
  348. vispy/util/svg/color.py +219 -0
  349. vispy/util/svg/element.py +51 -0
  350. vispy/util/svg/geometry.py +478 -0
  351. vispy/util/svg/group.py +66 -0
  352. vispy/util/svg/length.py +81 -0
  353. vispy/util/svg/number.py +25 -0
  354. vispy/util/svg/path.py +332 -0
  355. vispy/util/svg/shapes.py +57 -0
  356. vispy/util/svg/style.py +59 -0
  357. vispy/util/svg/svg.py +40 -0
  358. vispy/util/svg/transform.py +223 -0
  359. vispy/util/svg/transformable.py +28 -0
  360. vispy/util/svg/viewport.py +73 -0
  361. vispy/util/tests/__init__.py +0 -0
  362. vispy/util/tests/test_config.py +58 -0
  363. vispy/util/tests/test_docstring_parameters.py +123 -0
  364. vispy/util/tests/test_emitter_group.py +262 -0
  365. vispy/util/tests/test_event_emitter.py +743 -0
  366. vispy/util/tests/test_fourier.py +35 -0
  367. vispy/util/tests/test_gallery_scraper.py +112 -0
  368. vispy/util/tests/test_import.py +127 -0
  369. vispy/util/tests/test_key.py +22 -0
  370. vispy/util/tests/test_logging.py +45 -0
  371. vispy/util/tests/test_run.py +14 -0
  372. vispy/util/tests/test_transforms.py +42 -0
  373. vispy/util/tests/test_vispy.py +48 -0
  374. vispy/util/transforms.py +201 -0
  375. vispy/util/wrappers.py +155 -0
  376. vispy/version.py +4 -0
  377. vispy/visuals/__init__.py +50 -0
  378. vispy/visuals/_scalable_textures.py +485 -0
  379. vispy/visuals/axis.py +678 -0
  380. vispy/visuals/border.py +208 -0
  381. vispy/visuals/box.py +79 -0
  382. vispy/visuals/collections/__init__.py +30 -0
  383. vispy/visuals/collections/agg_fast_path_collection.py +219 -0
  384. vispy/visuals/collections/agg_path_collection.py +197 -0
  385. vispy/visuals/collections/agg_point_collection.py +52 -0
  386. vispy/visuals/collections/agg_segment_collection.py +142 -0
  387. vispy/visuals/collections/array_list.py +401 -0
  388. vispy/visuals/collections/base_collection.py +482 -0
  389. vispy/visuals/collections/collection.py +253 -0
  390. vispy/visuals/collections/path_collection.py +23 -0
  391. vispy/visuals/collections/point_collection.py +19 -0
  392. vispy/visuals/collections/polygon_collection.py +25 -0
  393. vispy/visuals/collections/raw_path_collection.py +119 -0
  394. vispy/visuals/collections/raw_point_collection.py +113 -0
  395. vispy/visuals/collections/raw_polygon_collection.py +77 -0
  396. vispy/visuals/collections/raw_segment_collection.py +112 -0
  397. vispy/visuals/collections/raw_triangle_collection.py +78 -0
  398. vispy/visuals/collections/segment_collection.py +19 -0
  399. vispy/visuals/collections/triangle_collection.py +16 -0
  400. vispy/visuals/collections/util.py +168 -0
  401. vispy/visuals/colorbar.py +699 -0
  402. vispy/visuals/cube.py +41 -0
  403. vispy/visuals/ellipse.py +163 -0
  404. vispy/visuals/filters/__init__.py +10 -0
  405. vispy/visuals/filters/base_filter.py +242 -0
  406. vispy/visuals/filters/clipper.py +60 -0
  407. vispy/visuals/filters/clipping_planes.py +122 -0
  408. vispy/visuals/filters/color.py +181 -0
  409. vispy/visuals/filters/markers.py +28 -0
  410. vispy/visuals/filters/mesh.py +796 -0
  411. vispy/visuals/filters/picking.py +60 -0
  412. vispy/visuals/filters/tests/__init__.py +3 -0
  413. vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
  414. vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
  415. vispy/visuals/glsl/__init__.py +1 -0
  416. vispy/visuals/glsl/antialiasing.py +133 -0
  417. vispy/visuals/glsl/color.py +63 -0
  418. vispy/visuals/graphs/__init__.py +1 -0
  419. vispy/visuals/graphs/graph.py +240 -0
  420. vispy/visuals/graphs/layouts/__init__.py +55 -0
  421. vispy/visuals/graphs/layouts/circular.py +49 -0
  422. vispy/visuals/graphs/layouts/force_directed.py +211 -0
  423. vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
  424. vispy/visuals/graphs/layouts/random.py +52 -0
  425. vispy/visuals/graphs/tests/__init__.py +1 -0
  426. vispy/visuals/graphs/tests/test_layouts.py +139 -0
  427. vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
  428. vispy/visuals/graphs/util.py +120 -0
  429. vispy/visuals/gridlines.py +105 -0
  430. vispy/visuals/gridmesh.py +98 -0
  431. vispy/visuals/histogram.py +58 -0
  432. vispy/visuals/image.py +688 -0
  433. vispy/visuals/image_complex.py +130 -0
  434. vispy/visuals/infinite_line.py +199 -0
  435. vispy/visuals/instanced_mesh.py +152 -0
  436. vispy/visuals/isocurve.py +213 -0
  437. vispy/visuals/isoline.py +241 -0
  438. vispy/visuals/isosurface.py +113 -0
  439. vispy/visuals/line/__init__.py +6 -0
  440. vispy/visuals/line/arrow.py +289 -0
  441. vispy/visuals/line/dash_atlas.py +90 -0
  442. vispy/visuals/line/line.py +545 -0
  443. vispy/visuals/line_plot.py +135 -0
  444. vispy/visuals/linear_region.py +199 -0
  445. vispy/visuals/markers.py +810 -0
  446. vispy/visuals/mesh.py +373 -0
  447. vispy/visuals/mesh_normals.py +159 -0
  448. vispy/visuals/plane.py +54 -0
  449. vispy/visuals/polygon.py +145 -0
  450. vispy/visuals/rectangle.py +196 -0
  451. vispy/visuals/regular_polygon.py +56 -0
  452. vispy/visuals/scrolling_lines.py +197 -0
  453. vispy/visuals/shaders/__init__.py +17 -0
  454. vispy/visuals/shaders/compiler.py +206 -0
  455. vispy/visuals/shaders/expression.py +99 -0
  456. vispy/visuals/shaders/function.py +788 -0
  457. vispy/visuals/shaders/multiprogram.py +145 -0
  458. vispy/visuals/shaders/parsing.py +140 -0
  459. vispy/visuals/shaders/program.py +161 -0
  460. vispy/visuals/shaders/shader_object.py +162 -0
  461. vispy/visuals/shaders/tests/__init__.py +0 -0
  462. vispy/visuals/shaders/tests/test_function.py +486 -0
  463. vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
  464. vispy/visuals/shaders/tests/test_parsing.py +57 -0
  465. vispy/visuals/shaders/variable.py +272 -0
  466. vispy/visuals/spectrogram.py +169 -0
  467. vispy/visuals/sphere.py +80 -0
  468. vispy/visuals/surface_plot.py +192 -0
  469. vispy/visuals/tests/__init__.py +0 -0
  470. vispy/visuals/tests/test_arrows.py +109 -0
  471. vispy/visuals/tests/test_axis.py +120 -0
  472. vispy/visuals/tests/test_collections.py +15 -0
  473. vispy/visuals/tests/test_colorbar.py +179 -0
  474. vispy/visuals/tests/test_colormap.py +97 -0
  475. vispy/visuals/tests/test_ellipse.py +122 -0
  476. vispy/visuals/tests/test_histogram.py +24 -0
  477. vispy/visuals/tests/test_image.py +390 -0
  478. vispy/visuals/tests/test_image_complex.py +36 -0
  479. vispy/visuals/tests/test_infinite_line.py +53 -0
  480. vispy/visuals/tests/test_instanced_mesh.py +50 -0
  481. vispy/visuals/tests/test_isosurface.py +22 -0
  482. vispy/visuals/tests/test_linear_region.py +152 -0
  483. vispy/visuals/tests/test_markers.py +54 -0
  484. vispy/visuals/tests/test_mesh.py +261 -0
  485. vispy/visuals/tests/test_mesh_normals.py +218 -0
  486. vispy/visuals/tests/test_polygon.py +112 -0
  487. vispy/visuals/tests/test_rectangle.py +163 -0
  488. vispy/visuals/tests/test_regular_polygon.py +111 -0
  489. vispy/visuals/tests/test_scalable_textures.py +180 -0
  490. vispy/visuals/tests/test_sdf.py +73 -0
  491. vispy/visuals/tests/test_spectrogram.py +42 -0
  492. vispy/visuals/tests/test_text.py +95 -0
  493. vispy/visuals/tests/test_volume.py +542 -0
  494. vispy/visuals/tests/test_windbarb.py +33 -0
  495. vispy/visuals/text/__init__.py +7 -0
  496. vispy/visuals/text/_sdf_cpu.cpython-311-darwin.so +0 -0
  497. vispy/visuals/text/_sdf_cpu.pyx +110 -0
  498. vispy/visuals/text/_sdf_gpu.py +316 -0
  499. vispy/visuals/text/text.py +675 -0
  500. vispy/visuals/transforms/__init__.py +34 -0
  501. vispy/visuals/transforms/_util.py +191 -0
  502. vispy/visuals/transforms/base_transform.py +233 -0
  503. vispy/visuals/transforms/chain.py +300 -0
  504. vispy/visuals/transforms/interactive.py +98 -0
  505. vispy/visuals/transforms/linear.py +564 -0
  506. vispy/visuals/transforms/nonlinear.py +398 -0
  507. vispy/visuals/transforms/tests/__init__.py +0 -0
  508. vispy/visuals/transforms/tests/test_transforms.py +243 -0
  509. vispy/visuals/transforms/transform_system.py +339 -0
  510. vispy/visuals/tube.py +173 -0
  511. vispy/visuals/visual.py +923 -0
  512. vispy/visuals/volume.py +1335 -0
  513. vispy/visuals/windbarb.py +291 -0
  514. vispy/visuals/xyz_axis.py +34 -0
  515. vispy-0.14.0.dist-info/LICENSE.txt +36 -0
  516. vispy-0.14.0.dist-info/METADATA +218 -0
  517. vispy-0.14.0.dist-info/RECORD +519 -0
  518. vispy-0.14.0.dist-info/WHEEL +5 -0
  519. vispy-0.14.0.dist-info/top_level.txt +1 -0
vispy/gloo/texture.py ADDED
@@ -0,0 +1,1045 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -----------------------------------------------------------------------------
3
+ # Copyright (c) Vispy Development Team. All Rights Reserved.
4
+ # Distributed under the (new) BSD License. See LICENSE.txt for more info.
5
+ # -----------------------------------------------------------------------------
6
+
7
+ import math
8
+
9
+ import numpy as np
10
+ import warnings
11
+
12
+ from .globject import GLObject
13
+ from .util import check_enum
14
+
15
+
16
+ def get_dtype_limits(dtype):
17
+ if np.issubdtype(dtype, np.floating):
18
+ info = np.finfo(dtype)
19
+ else:
20
+ info = np.iinfo(dtype)
21
+ return info.min, info.max
22
+
23
+
24
+ def convert_dtype_and_clip(data, dtype, copy=False):
25
+ """
26
+ cast dtype to a new one, but first clip data to the new dtype's limits if needed
27
+ """
28
+ old_min, old_max = get_dtype_limits(data.dtype)
29
+ new_min, new_max = get_dtype_limits(dtype)
30
+ if new_max >= old_max and new_min <= old_min:
31
+ # no need to clip
32
+ return np.array(data, dtype=dtype, copy=copy)
33
+ else:
34
+ # to reduce copying, we clip into a pre-generated array of the right dtype
35
+ new_data = np.empty_like(data, dtype=dtype)
36
+ # allow "unsafe" casting here as we're explicitly clipping to the
37
+ # range of the new dtype - this was a default before numpy 1.25
38
+ np.clip(data, new_min, new_max, out=new_data, casting="unsafe")
39
+ return new_data
40
+
41
+
42
+ def downcast_to_32bit_if_needed(data, copy=False, dtype=None):
43
+ """Downcast to 32bit dtype if necessary."""
44
+ if dtype is None:
45
+ dtype = data.dtype
46
+ dtype = np.dtype(dtype)
47
+ if dtype.itemsize > 4:
48
+ warnings.warn(
49
+ f"GPUs can't support dtypes bigger than 32-bit, but got '{dtype}'. "
50
+ "Precision will be lost due to downcasting to 32-bit.",
51
+ stacklevel=2,
52
+ )
53
+
54
+ size = min(dtype.itemsize, 4)
55
+ kind = dtype.kind
56
+
57
+ new_dtype = np.dtype(f'{kind}{size}')
58
+ return convert_dtype_and_clip(data, new_dtype, copy=copy)
59
+
60
+
61
+ class BaseTexture(GLObject):
62
+ """
63
+ A Texture is used to represent a topological set of scalar values.
64
+
65
+ Parameters
66
+ ----------
67
+ data : ndarray | tuple | None
68
+ Texture data in the form of a numpy array (or something that
69
+ can be turned into one). A tuple with the shape of the texture
70
+ can also be given.
71
+ format : str | enum | None
72
+ The format of the texture: 'luminance', 'alpha',
73
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
74
+ is chosen automatically based on the number of channels.
75
+ When the data has one channel, 'luminance' is assumed.
76
+ resizable : bool
77
+ Indicates whether texture can be resized. Default True.
78
+ interpolation : str | None
79
+ Interpolation mode, must be one of: 'nearest', 'linear'.
80
+ Default 'nearest'.
81
+ wrapping : str | None
82
+ Wrapping mode, must be one of: 'repeat', 'clamp_to_edge',
83
+ 'mirrored_repeat'. Default 'clamp_to_edge'.
84
+ shape : tuple | None
85
+ Optional. A tuple with the shape of the texture. If ``data``
86
+ is also a tuple, it will override the value of ``shape``.
87
+ internalformat : str | None
88
+ Internal format to use.
89
+ resizeable : None
90
+ Deprecated version of `resizable`.
91
+ """
92
+
93
+ _ndim = 2
94
+
95
+ _formats = {
96
+ 1: 'luminance', # or alpha, or red
97
+ 2: 'luminance_alpha', # or rg
98
+ 3: 'rgb',
99
+ 4: 'rgba'
100
+ }
101
+
102
+ _inv_formats = {
103
+ 'luminance': 1,
104
+ 'alpha': 1,
105
+ 'red': 1,
106
+ 'luminance_alpha': 2,
107
+ 'rg': 2,
108
+ 'rgb': 3,
109
+ 'rgba': 4,
110
+ 'depth_component': 1,
111
+ }
112
+
113
+ # NOTE: non-normalized formats ending with 'i' and 'ui' are currently
114
+ # disabled as they don't work with the current VisPy implementation.
115
+ # Attempting to use them along with the additional enums defined in
116
+ # vispy/gloo/glir.py produces an invalid operation from OpenGL.
117
+ _inv_internalformats = dict([
118
+ (base + suffix, channels)
119
+ for base, channels in [('r', 1), ('rg', 2), ('rgb', 3), ('rgba', 4)]
120
+ for suffix in ['8', '16', '16f', '32f'] # , '8i', '8ui', '32i', '32ui']
121
+ ] + [
122
+ ('luminance', 1),
123
+ ('alpha', 1),
124
+ ('red', 1),
125
+ ('luminance_alpha', 2),
126
+ ('rg', 2),
127
+ ('rgb', 3),
128
+ ('rgba', 4),
129
+ ('depth_component', 1),
130
+ ])
131
+
132
+ def __init__(self, data=None, format=None, resizable=True,
133
+ interpolation=None, wrapping=None, shape=None,
134
+ internalformat=None, resizeable=None):
135
+ GLObject.__init__(self)
136
+ if resizeable is not None:
137
+ resizable = resizeable
138
+ warnings.warn(
139
+ "resizeable has been deprecated in favor of "
140
+ "resizable and will be removed next release",
141
+ DeprecationWarning,
142
+ stacklevel=2,
143
+ )
144
+
145
+ # Init shape and format
146
+ self._resizable = True # at least while we're in init
147
+ self._shape = tuple([0 for i in range(self._ndim+1)])
148
+ self._format = format
149
+ self._internalformat = internalformat
150
+
151
+ # Set texture parameters (before setting data)
152
+ self.interpolation = interpolation or 'nearest'
153
+ self.wrapping = wrapping or 'clamp_to_edge'
154
+
155
+ # Set data or shape (shape arg is for backward compat)
156
+ if isinstance(data, tuple):
157
+ shape, data = data, None
158
+ if data is not None:
159
+ if shape is not None:
160
+ raise ValueError('Texture needs data or shape, not both.')
161
+ data = np.array(data, copy=False)
162
+ # So we can test the combination
163
+ self._resize(data.shape, format, internalformat)
164
+ self._set_data(data)
165
+ elif shape is not None:
166
+ self._resize(shape, format, internalformat)
167
+ else:
168
+ raise ValueError("Either data or shape must be given")
169
+
170
+ # Set resizable (at end of init)
171
+ self._resizable = bool(resizable)
172
+
173
+ def _normalize_shape(self, data_or_shape):
174
+ # Get data and shape from input
175
+ if isinstance(data_or_shape, np.ndarray):
176
+ data = data_or_shape
177
+ shape = data.shape
178
+ else:
179
+ assert isinstance(data_or_shape, tuple)
180
+ data = None
181
+ shape = data_or_shape
182
+ # Check and correct
183
+ if shape:
184
+ if len(shape) < self._ndim:
185
+ raise ValueError("Too few dimensions for texture")
186
+ elif len(shape) > self._ndim + 1:
187
+ raise ValueError("Too many dimensions for texture")
188
+ elif len(shape) == self._ndim:
189
+ shape = shape + (1,)
190
+ else: # if len(shape) == self._ndim + 1:
191
+ if shape[-1] > 4:
192
+ raise ValueError("Too many channels for texture")
193
+ # Return
194
+ return data.reshape(shape) if data is not None else shape
195
+
196
+ @property
197
+ def shape(self):
198
+ """Data shape (last dimension indicates number of color channels)"""
199
+ return self._shape
200
+
201
+ @property
202
+ def format(self):
203
+ """The texture format (color channels)."""
204
+ return self._format
205
+
206
+ @property
207
+ def internalformat(self):
208
+ """The texture internalformat."""
209
+ return self._internalformat
210
+
211
+ @property
212
+ def wrapping(self):
213
+ """Texture wrapping mode"""
214
+ value = self._wrapping
215
+ return value[0] if all([v == value[0] for v in value]) else value
216
+
217
+ @wrapping.setter
218
+ def wrapping(self, value):
219
+ # Convert
220
+ if isinstance(value, int) or isinstance(value, str):
221
+ value = (value,) * self._ndim
222
+ elif isinstance(value, (tuple, list)):
223
+ if len(value) != self._ndim:
224
+ raise ValueError('Texture wrapping needs 1 or %i values' %
225
+ self._ndim)
226
+ else:
227
+ raise ValueError('Invalid value for wrapping: %r' % value)
228
+ # Check and set
229
+ valid = 'repeat', 'clamp_to_edge', 'mirrored_repeat'
230
+ value = tuple([check_enum(value[i], 'tex wrapping', valid)
231
+ for i in range(self._ndim)])
232
+ self._wrapping = value
233
+ self._glir.command('WRAPPING', self._id, value)
234
+
235
+ @property
236
+ def interpolation(self):
237
+ """Texture interpolation for minification and magnification."""
238
+ value = self._interpolation
239
+ return value[0] if value[0] == value[1] else value
240
+
241
+ @interpolation.setter
242
+ def interpolation(self, value):
243
+ # Convert
244
+ if isinstance(value, int) or isinstance(value, str):
245
+ value = (value,) * 2
246
+ elif isinstance(value, (tuple, list)):
247
+ if len(value) != 2:
248
+ raise ValueError('Texture interpolation needs 1 or 2 values')
249
+ else:
250
+ raise ValueError('Invalid value for interpolation: %r' % value)
251
+ # Check and set
252
+ valid = 'nearest', 'linear'
253
+ value = (check_enum(value[0], 'tex interpolation', valid),
254
+ check_enum(value[1], 'tex interpolation', valid))
255
+ self._interpolation = value
256
+ self._glir.command('INTERPOLATION', self._id, *value)
257
+
258
+ def resize(self, shape, format=None, internalformat=None):
259
+ """Set the texture size and format
260
+
261
+ Parameters
262
+ ----------
263
+ shape : tuple of integers
264
+ New texture shape in zyx order. Optionally, an extra dimention
265
+ may be specified to indicate the number of color channels.
266
+ format : str | enum | None
267
+ The format of the texture: 'luminance', 'alpha',
268
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
269
+ is chosen automatically based on the number of channels.
270
+ When the data has one channel, 'luminance' is assumed.
271
+ internalformat : str | enum | None
272
+ The internal (storage) format of the texture: 'luminance',
273
+ 'alpha', 'r8', 'r16', 'r16f', 'r32f'; 'luminance_alpha',
274
+ 'rg8', 'rg16', 'rg16f', 'rg32f'; 'rgb', 'rgb8', 'rgb16',
275
+ 'rgb16f', 'rgb32f'; 'rgba', 'rgba8', 'rgba16', 'rgba16f',
276
+ 'rgba32f'. If None, the internalformat is chosen
277
+ automatically based on the number of channels. This is a
278
+ hint which may be ignored by the OpenGL implementation.
279
+ """
280
+ return self._resize(shape, format, internalformat)
281
+
282
+ def _check_format_change(self, format, num_channels):
283
+ # Determine format
284
+ if format is None:
285
+ format = self._formats[num_channels]
286
+ # Keep current format if channels match
287
+ if self._format and \
288
+ self._inv_formats[self._format] == self._inv_formats[format]:
289
+ format = self._format
290
+ else:
291
+ format = check_enum(format)
292
+
293
+ if format not in self._inv_formats:
294
+ raise ValueError('Invalid texture format: %r.' % format)
295
+ elif num_channels != self._inv_formats[format]:
296
+ raise ValueError('Format does not match with given shape. '
297
+ '(format expects %d elements, data has %d)' %
298
+ (self._inv_formats[format], num_channels))
299
+ return format
300
+
301
+ def _check_internalformat_change(self, internalformat, num_channels):
302
+ if internalformat is None:
303
+ # Keep current internalformat if channels match
304
+ if self._internalformat and \
305
+ self._inv_internalformats[self._internalformat] == num_channels:
306
+ internalformat = self._internalformat
307
+ else:
308
+ internalformat = check_enum(internalformat)
309
+
310
+ if internalformat is None:
311
+ pass
312
+ elif internalformat not in self._inv_internalformats:
313
+ raise ValueError(
314
+ 'Invalid texture internalformat: %r. Allowed formats: %r'
315
+ % (internalformat, self._inv_internalformats)
316
+ )
317
+ elif num_channels != self._inv_internalformats[internalformat]:
318
+ raise ValueError('Internalformat does not match with given shape.')
319
+ return internalformat
320
+
321
+ def _resize(self, shape, format=None, internalformat=None):
322
+ """Internal method for resize."""
323
+ shape = self._normalize_shape(shape)
324
+
325
+ # Check
326
+ if not self._resizable:
327
+ raise RuntimeError("Texture is not resizable")
328
+
329
+ format = self._check_format_change(format, shape[-1])
330
+ internalformat = self._check_internalformat_change(internalformat, shape[-1])
331
+
332
+ # Store and send GLIR command
333
+ self._shape = shape
334
+ self._format = format
335
+ self._internalformat = internalformat
336
+ self._glir.command('SIZE', self._id, self._shape, self._format,
337
+ self._internalformat)
338
+
339
+ def set_data(self, data, offset=None, copy=False):
340
+ """Set texture data
341
+
342
+ Parameters
343
+ ----------
344
+ data : ndarray
345
+ Data to be uploaded
346
+ offset: int | tuple of ints
347
+ Offset in texture where to start copying data
348
+ copy: bool
349
+ Since the operation is deferred, data may change before
350
+ data is actually uploaded to GPU memory. Asking explicitly
351
+ for a copy will prevent this behavior.
352
+
353
+ Notes
354
+ -----
355
+ This operation implicitly resizes the texture to the shape of
356
+ the data if given offset is None.
357
+ """
358
+ return self._set_data(data, offset, copy)
359
+
360
+ def _set_data(self, data, offset=None, copy=False):
361
+ """Internal method for set_data."""
362
+ # Copy if needed, check/normalize shape
363
+ data = downcast_to_32bit_if_needed(data, copy=copy)
364
+ data = self._normalize_shape(data)
365
+
366
+ # Maybe resize to purge DATA commands?
367
+ if offset is None:
368
+ self._resize(data.shape)
369
+ elif all([i == 0 for i in offset]) and data.shape == self._shape:
370
+ self._resize(data.shape)
371
+
372
+ # Convert offset to something usable
373
+ offset = offset or tuple([0 for i in range(self._ndim)])
374
+ assert len(offset) == self._ndim
375
+
376
+ # Check if data fits
377
+ for i in range(len(data.shape)-1):
378
+ if offset[i] + data.shape[i] > self._shape[i]:
379
+ raise ValueError("Data is too large")
380
+
381
+ # Send GLIR command
382
+ self._glir.command('DATA', self._id, offset, data)
383
+
384
+ def __setitem__(self, key, data):
385
+ """x.__getitem__(y) <==> x[y]"""
386
+ # Make sure key is a tuple
387
+ if isinstance(key, (int, slice)) or key == Ellipsis:
388
+ key = (key,)
389
+
390
+ # Default is to access the whole texture
391
+ shape = self._shape
392
+ slices = [slice(0, shape[i]) for i in range(len(shape))]
393
+
394
+ # Check last key/Ellipsis to decide on the order
395
+ keys = key[::+1]
396
+ dims = range(0, len(key))
397
+ if key[0] == Ellipsis:
398
+ keys = key[::-1]
399
+ dims = range(len(self._shape) - 1,
400
+ len(self._shape) - 1 - len(keys), -1)
401
+
402
+ # Find exact range for each key
403
+ for k, dim in zip(keys, dims):
404
+ size = self._shape[dim]
405
+ if isinstance(k, int):
406
+ if k < 0:
407
+ k += size
408
+ if k < 0 or k > size:
409
+ raise IndexError("Texture assignment index out of range")
410
+ start, stop = k, k + 1
411
+ slices[dim] = slice(start, stop, 1)
412
+ elif isinstance(k, slice):
413
+ start, stop, step = k.indices(size)
414
+ if step != 1:
415
+ raise IndexError("Cannot access non-contiguous data")
416
+ if stop < start:
417
+ start, stop = stop, start
418
+ slices[dim] = slice(start, stop, step)
419
+ elif k == Ellipsis:
420
+ pass
421
+ else:
422
+ raise TypeError("Texture indices must be integers")
423
+
424
+ offset = tuple([s.start for s in slices])[:self._ndim]
425
+ shape = tuple([s.stop - s.start for s in slices])
426
+ size = np.prod(shape) if len(shape) > 0 else 1
427
+
428
+ # Make sure data is an array
429
+ if not isinstance(data, np.ndarray):
430
+ data = np.array(data, copy=False)
431
+ # Make sure data is big enough
432
+ if data.shape != shape:
433
+ data = np.resize(data, shape)
434
+
435
+ # Set data (deferred)
436
+ self._set_data(data=data, offset=offset, copy=False)
437
+
438
+ def __repr__(self):
439
+ return "<%s shape=%r format=%r at 0x%x>" % (
440
+ self.__class__.__name__, self._shape, self._format, id(self))
441
+
442
+
443
+ # --------------------------------------------------------- Texture1D class ---
444
+ class Texture1D(BaseTexture):
445
+ """One dimensional texture
446
+
447
+ Parameters
448
+ ----------
449
+ data : ndarray | tuple | None
450
+ Texture data in the form of a numpy array (or something that
451
+ can be turned into one). A tuple with the shape of the texture
452
+ can also be given.
453
+ format : str | enum | None
454
+ The format of the texture: 'luminance', 'alpha',
455
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
456
+ is chosen automatically based on the number of channels.
457
+ When the data has one channel, 'luminance' is assumed.
458
+ resizable : bool
459
+ Indicates whether texture can be resized. Default True.
460
+ interpolation : str | None
461
+ Interpolation mode, must be one of: 'nearest', 'linear'.
462
+ Default 'nearest'.
463
+ wrapping : str | None
464
+ Wrapping mode, must be one of: 'repeat', 'clamp_to_edge',
465
+ 'mirrored_repeat'. Default 'clamp_to_edge'.
466
+ shape : tuple | None
467
+ Optional. A tuple with the shape of the texture. If ``data``
468
+ is also a tuple, it will override the value of ``shape``.
469
+ internalformat : str | None
470
+ Internal format to use.
471
+ resizeable : None
472
+ Deprecated version of `resizable`.
473
+ """
474
+
475
+ _ndim = 1
476
+ _GLIR_TYPE = 'Texture1D'
477
+
478
+ def __init__(self, data=None, format=None, resizable=True,
479
+ interpolation=None, wrapping=None, shape=None,
480
+ internalformat=None, resizeable=None):
481
+ BaseTexture.__init__(self, data, format, resizable, interpolation,
482
+ wrapping, shape, internalformat, resizeable)
483
+
484
+ @property
485
+ def width(self):
486
+ """Texture width"""
487
+ return self._shape[0]
488
+
489
+ @property
490
+ def glsl_type(self):
491
+ """GLSL declaration strings required for a variable to hold this data."""
492
+ return 'uniform', 'sampler1D'
493
+
494
+ @property
495
+ def glsl_sampler_type(self):
496
+ """GLSL type of the sampler."""
497
+ return 'sampler1D'
498
+
499
+ @property
500
+ def glsl_sample(self):
501
+ """GLSL function that samples the texture."""
502
+ return 'texture1D'
503
+
504
+
505
+ # --------------------------------------------------------- Texture2D class ---
506
+ class Texture2D(BaseTexture):
507
+ """Two dimensional texture
508
+
509
+ Parameters
510
+ ----------
511
+ data : ndarray
512
+ Texture data shaped as W, or a tuple with the shape for
513
+ the texture (W).
514
+ format : str | enum | None
515
+ The format of the texture: 'luminance', 'alpha',
516
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
517
+ is chosen automatically based on the number of channels.
518
+ When the data has one channel, 'luminance' is assumed.
519
+ resizable : bool
520
+ Indicates whether texture can be resized. Default True.
521
+ interpolation : str
522
+ Interpolation mode, must be one of: 'nearest', 'linear'.
523
+ Default 'nearest'.
524
+ wrapping : str
525
+ Wrapping mode, must be one of: 'repeat', 'clamp_to_edge',
526
+ 'mirrored_repeat'. Default 'clamp_to_edge'.
527
+ shape : tuple
528
+ Optional. A tuple with the shape HxW. If ``data``
529
+ is also a tuple, it will override the value of ``shape``.
530
+ internalformat : str | None
531
+ Internal format to use.
532
+ resizeable : None
533
+ Deprecated version of `resizable`.
534
+ """
535
+
536
+ _ndim = 2
537
+ _GLIR_TYPE = 'Texture2D'
538
+
539
+ def __init__(self, data=None, format=None, resizable=True,
540
+ interpolation=None, wrapping=None, shape=None,
541
+ internalformat=None, resizeable=None):
542
+ BaseTexture.__init__(self, data, format, resizable, interpolation,
543
+ wrapping, shape, internalformat, resizeable)
544
+
545
+ @property
546
+ def height(self):
547
+ """Texture height"""
548
+ return self._shape[0]
549
+
550
+ @property
551
+ def width(self):
552
+ """Texture width"""
553
+ return self._shape[1]
554
+
555
+ @property
556
+ def glsl_type(self):
557
+ """GLSL declaration strings required for a variable to hold this data."""
558
+ return 'uniform', 'sampler2D'
559
+
560
+ @property
561
+ def glsl_sampler_type(self):
562
+ """GLSL type of the sampler."""
563
+ return 'sampler2D'
564
+
565
+ @property
566
+ def glsl_sample(self):
567
+ """GLSL function that samples the texture."""
568
+ return 'texture2D'
569
+
570
+
571
+ # --------------------------------------------------------- Texture3D class ---
572
+ class Texture3D(BaseTexture):
573
+ """Three dimensional texture
574
+
575
+ Parameters
576
+ ----------
577
+ data : ndarray | tuple | None
578
+ Texture data in the form of a numpy array (or something that
579
+ can be turned into one). A tuple with the shape of the texture
580
+ can also be given.
581
+ format : str | enum | None
582
+ The format of the texture: 'luminance', 'alpha',
583
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
584
+ is chosen automatically based on the number of channels.
585
+ When the data has one channel, 'luminance' is assumed.
586
+ resizable : bool
587
+ Indicates whether texture can be resized. Default True.
588
+ interpolation : str | None
589
+ Interpolation mode, must be one of: 'nearest', 'linear'.
590
+ Default 'nearest'.
591
+ wrapping : str | None
592
+ Wrapping mode, must be one of: 'repeat', 'clamp_to_edge',
593
+ 'mirrored_repeat'. Default 'clamp_to_edge'.
594
+ shape : tuple | None
595
+ Optional. A tuple with the shape of the texture. If ``data``
596
+ is also a tuple, it will override the value of ``shape``.
597
+ internalformat : str | None
598
+ Internal format to use.
599
+ resizeable : None
600
+ Deprecated version of `resizable`.
601
+ """
602
+
603
+ _ndim = 3
604
+ _GLIR_TYPE = 'Texture3D'
605
+
606
+ def __init__(self, data=None, format=None, resizable=True,
607
+ interpolation=None, wrapping=None, shape=None,
608
+ internalformat=None, resizeable=None):
609
+ BaseTexture.__init__(self, data, format, resizable, interpolation,
610
+ wrapping, shape, internalformat, resizeable)
611
+
612
+ @property
613
+ def width(self):
614
+ """Texture width"""
615
+ return self._shape[2]
616
+
617
+ @property
618
+ def height(self):
619
+ """Texture height"""
620
+ return self._shape[1]
621
+
622
+ @property
623
+ def depth(self):
624
+ """Texture depth"""
625
+ return self._shape[0]
626
+
627
+ @property
628
+ def glsl_type(self):
629
+ """GLSL declaration strings required for a variable to hold this data."""
630
+ return 'uniform', 'sampler3D'
631
+
632
+ @property
633
+ def glsl_sampler_type(self):
634
+ """GLSL type of the sampler."""
635
+ return 'sampler3D'
636
+
637
+ @property
638
+ def glsl_sample(self):
639
+ """GLSL function that samples the texture."""
640
+ return 'texture3D'
641
+
642
+
643
+ # --------------------------------------------------------- TextureCube class ---
644
+ class TextureCube(BaseTexture):
645
+ """Texture Cube
646
+
647
+ Parameters
648
+ ----------
649
+ data : ndarray | tuple | None
650
+ Texture data in the form of a numpy array (or something that
651
+ can be turned into one). A tuple with the shape of the texture
652
+ can also be given.
653
+ format : str | enum | None
654
+ The format of the texture: 'luminance', 'alpha',
655
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
656
+ is chosen automatically based on the number of channels.
657
+ When the data has one channel, 'luminance' is assumed.
658
+ resizable : bool
659
+ Indicates whether texture can be resized. Default True.
660
+ interpolation : str | None
661
+ Interpolation mode, must be one of: 'nearest', 'linear'.
662
+ Default 'nearest'.
663
+ wrapping : str | None
664
+ Wrapping mode, must be one of: 'repeat', 'clamp_to_edge',
665
+ 'mirrored_repeat'. Default 'clamp_to_edge'.
666
+ shape : tuple | None
667
+ Optional. A tuple with the shape of the texture. If ``data``
668
+ is also a tuple, it will override the value of ``shape``.
669
+ internalformat : str | None
670
+ Internal format to use.
671
+ resizeable : None
672
+ Deprecated version of `resizable`.
673
+ """
674
+
675
+ _ndim = 3
676
+ _GLIR_TYPE = 'TextureCube'
677
+
678
+ def __init__(self, data=None, format=None, resizable=True,
679
+ interpolation=None, wrapping=None, shape=None,
680
+ internalformat=None, resizeable=None):
681
+ BaseTexture.__init__(self, data, format, resizable, interpolation,
682
+ wrapping, shape, internalformat, resizeable)
683
+ if self._shape[0] != 6:
684
+ raise ValueError("Texture cube require arrays first dimension to be 6 :"
685
+ " {} was given.".format(self._shape[0]))
686
+
687
+ @property
688
+ def height(self):
689
+ """Texture height"""
690
+ return self._shape[1]
691
+
692
+ @property
693
+ def width(self):
694
+ """Texture width"""
695
+ return self._shape[2]
696
+
697
+ @property
698
+ def depth(self):
699
+ """Texture depth"""
700
+ return self._shape[0]
701
+
702
+ @property
703
+ def glsl_type(self):
704
+ """GLSL declaration strings required for a variable to hold this data."""
705
+ return 'uniform', 'samplerCube'
706
+
707
+ @property
708
+ def glsl_sampler_type(self):
709
+ """GLSL type of the sampler."""
710
+ return 'samplerCube'
711
+
712
+ @property
713
+ def glsl_sample(self):
714
+ """GLSL function that samples the texture."""
715
+ return 'textureCube'
716
+
717
+
718
+ # ------------------------------------------------- TextureEmulated3D class ---
719
+ class TextureEmulated3D(Texture2D):
720
+ """Two dimensional texture that is emulating a three dimensional texture
721
+
722
+ Parameters
723
+ ----------
724
+ data : ndarray | tuple | None
725
+ Texture data in the form of a numpy array (or something that
726
+ can be turned into one). A tuple with the shape of the texture
727
+ can also be given.
728
+ format : str | enum | None
729
+ The format of the texture: 'luminance', 'alpha',
730
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
731
+ is chosen automatically based on the number of channels.
732
+ When the data has one channel, 'luminance' is assumed.
733
+ resizable : bool
734
+ Indicates whether texture can be resized. Default True.
735
+ interpolation : str | None
736
+ Interpolation mode, must be one of: 'nearest', 'linear'.
737
+ Default 'nearest'.
738
+ wrapping : str | None
739
+ Wrapping mode, must be one of: 'repeat', 'clamp_to_edge',
740
+ 'mirrored_repeat'. Default 'clamp_to_edge'.
741
+ shape : tuple | None
742
+ Optional. A tuple with the shape of the texture. If ``data``
743
+ is also a tuple, it will override the value of ``shape``.
744
+ internalformat : str | None
745
+ Internal format to use.
746
+ resizeable : None
747
+ Deprecated version of `resizable`.
748
+ """
749
+
750
+ # TODO: does GL's nearest use floor or round?
751
+ _glsl_sample_nearest = """
752
+ vec4 sample(sampler2D tex, vec3 texcoord) {
753
+ // Don't let adjacent frames be interpolated into this one
754
+ texcoord.x = min(texcoord.x * $shape.x, $shape.x - 0.5);
755
+ texcoord.x = max(0.5, texcoord.x) / $shape.x;
756
+ texcoord.y = min(texcoord.y * $shape.y, $shape.y - 0.5);
757
+ texcoord.y = max(0.5, texcoord.y) / $shape.y;
758
+
759
+ float index = floor(texcoord.z * $shape.z);
760
+
761
+ // Do a lookup in the 2D texture
762
+ float u = (mod(index, $r) + texcoord.x) / $r;
763
+ float v = (floor(index / $r) + texcoord.y) / $c;
764
+
765
+ return texture2D(tex, vec2(u,v));
766
+ }
767
+ """
768
+
769
+ _glsl_sample_linear = """
770
+ vec4 sample(sampler2D tex, vec3 texcoord) {
771
+ // Don't let adjacent frames be interpolated into this one
772
+ texcoord.x = min(texcoord.x * $shape.x, $shape.x - 0.5);
773
+ texcoord.x = max(0.5, texcoord.x) / $shape.x;
774
+ texcoord.y = min(texcoord.y * $shape.y, $shape.y - 0.5);
775
+ texcoord.y = max(0.5, texcoord.y) / $shape.y;
776
+
777
+ float z = texcoord.z * $shape.z;
778
+ float zindex1 = floor(z);
779
+ float u1 = (mod(zindex1, $r) + texcoord.x) / $r;
780
+ float v1 = (floor(zindex1 / $r) + texcoord.y) / $c;
781
+
782
+ float zindex2 = zindex1 + 1.0;
783
+ float u2 = (mod(zindex2, $r) + texcoord.x) / $r;
784
+ float v2 = (floor(zindex2 / $r) + texcoord.y) / $c;
785
+
786
+ vec4 s1 = texture2D(tex, vec2(u1, v1));
787
+ vec4 s2 = texture2D(tex, vec2(u2, v2));
788
+
789
+ return s1 * (zindex2 - z) + s2 * (z - zindex1);
790
+ }
791
+ """
792
+
793
+ _gl_max_texture_size = 1024 # For now, we just set this manually
794
+
795
+ def __init__(self, data=None, format=None, resizable=True,
796
+ interpolation=None, wrapping=None, shape=None,
797
+ internalformat=None, resizeable=None):
798
+ from ..visuals.shaders import Function
799
+
800
+ self._set_emulated_shape(data)
801
+ Texture2D.__init__(self, self._normalize_emulated_shape(data),
802
+ format, resizable, interpolation, wrapping,
803
+ shape, internalformat, resizeable)
804
+ if self.interpolation == 'nearest':
805
+ self._glsl_sample = Function(self.__class__._glsl_sample_nearest)
806
+ else:
807
+ self._glsl_sample = Function(self.__class__._glsl_sample_linear)
808
+ self._update_variables()
809
+
810
+ def _set_emulated_shape(self, data_or_shape):
811
+ if isinstance(data_or_shape, np.ndarray):
812
+ self._emulated_shape = data_or_shape.shape
813
+ else:
814
+ assert isinstance(data_or_shape, tuple)
815
+ self._emulated_shape = tuple(data_or_shape)
816
+
817
+ depth, width = self._emulated_shape[0], self._emulated_shape[1]
818
+ self._r = TextureEmulated3D._gl_max_texture_size // width
819
+ self._c = depth // self._r
820
+ if math.fmod(depth, self._r):
821
+ self._c += 1
822
+
823
+ def _normalize_emulated_shape(self, data_or_shape):
824
+ if isinstance(data_or_shape, np.ndarray):
825
+ new_shape = self._normalize_emulated_shape(data_or_shape.shape)
826
+ new_data = np.empty(new_shape, dtype=data_or_shape.dtype)
827
+ for j in range(self._c):
828
+ for i in range(self._r):
829
+ i0, i1 = i * self.width, (i+1) * self.width
830
+ j0, j1 = j * self.height, (j+1) * self.height
831
+ k = j * self._r + i
832
+ if k >= self.depth:
833
+ break
834
+ new_data[j0:j1, i0:i1] = data_or_shape[k]
835
+
836
+ return new_data
837
+
838
+ assert isinstance(data_or_shape, tuple)
839
+ return (self._c * self.height, self._r * self.width) + \
840
+ data_or_shape[3:]
841
+
842
+ def _update_variables(self):
843
+ self._glsl_sample['shape'] = self.shape[:3][::-1]
844
+ # On Windows with Python 2.7, self._c can end up being a long
845
+ # integer because Numpy array shapes return long integers. This
846
+ # causes issues when setting the gloo variables since these are
847
+ # expected to be native ints, so we cast the integers to ints
848
+ # to avoid this.
849
+ # Newer GLSL compilers do not implicitly cast types so these integers
850
+ # must be converted to floats lastly
851
+ self._glsl_sample['c'] = float(int(self._c))
852
+ self._glsl_sample['r'] = float(int(self._r))
853
+
854
+ def set_data(self, data, offset=None, copy=False):
855
+ """Set texture data
856
+
857
+ Parameters
858
+ ----------
859
+ data : ndarray
860
+ Data to be uploaded
861
+ offset: int | tuple of ints
862
+ Offset in texture where to start copying data
863
+ copy: bool
864
+ Since the operation is deferred, data may change before
865
+ data is actually uploaded to GPU memory. Asking explicitly
866
+ for a copy will prevent this behavior.
867
+
868
+ Notes
869
+ -----
870
+ This operation implicitely resizes the texture to the shape of
871
+ the data if given offset is None.
872
+ """
873
+ self._set_emulated_shape(data)
874
+ Texture2D.set_data(self, self._normalize_emulated_shape(data),
875
+ offset, copy)
876
+ self._update_variables()
877
+
878
+ def resize(self, shape, format=None, internalformat=None):
879
+ """Set the texture size and format
880
+
881
+ Parameters
882
+ ----------
883
+ shape : tuple of integers
884
+ New texture shape in zyx order. Optionally, an extra dimention
885
+ may be specified to indicate the number of color channels.
886
+ format : str | enum | None
887
+ The format of the texture: 'luminance', 'alpha',
888
+ 'luminance_alpha', 'rgb', or 'rgba'. If not given the format
889
+ is chosen automatically based on the number of channels.
890
+ When the data has one channel, 'luminance' is assumed.
891
+ internalformat : str | enum | None
892
+ The internal (storage) format of the texture: 'luminance',
893
+ 'alpha', 'r8', 'r16', 'r16f', 'r32f'; 'luminance_alpha',
894
+ 'rg8', 'rg16', 'rg16f', 'rg32f'; 'rgb', 'rgb8', 'rgb16',
895
+ 'rgb16f', 'rgb32f'; 'rgba', 'rgba8', 'rgba16', 'rgba16f',
896
+ 'rgba32f'. If None, the internalformat is chosen
897
+ automatically based on the number of channels. This is a
898
+ hint which may be ignored by the OpenGL implementation.
899
+ """
900
+ self._set_emulated_shape(shape)
901
+ Texture2D.resize(self, self._normalize_emulated_shape(shape),
902
+ format, internalformat)
903
+ self._update_variables()
904
+
905
+ @property
906
+ def shape(self):
907
+ """Data shape (last dimension indicates number of color channels)"""
908
+ return self._emulated_shape
909
+
910
+ @property
911
+ def width(self):
912
+ """Texture width"""
913
+ return self._emulated_shape[2]
914
+
915
+ @property
916
+ def height(self):
917
+ """Texture height"""
918
+ return self._emulated_shape[1]
919
+
920
+ @property
921
+ def depth(self):
922
+ """Texture depth"""
923
+ return self._emulated_shape[0]
924
+
925
+ @property
926
+ def glsl_sample(self):
927
+ """GLSL function that samples the texture."""
928
+ return self._glsl_sample
929
+
930
+
931
+ # ------------------------------------------------------ TextureAtlas class ---
932
+ class TextureAtlas(Texture2D):
933
+ """Group multiple small data regions into a larger texture.
934
+
935
+ The algorithm is based on the article by Jukka Jylänki : "A Thousand Ways
936
+ to Pack the Bin - A Practical Approach to Two-Dimensional Rectangle Bin
937
+ Packing", February 27, 2010. More precisely, this is an implementation of
938
+ the Skyline Bottom-Left algorithm based on C++ sources provided by Jukka
939
+ Jylänki at: http://clb.demon.fi/files/RectangleBinPack/.
940
+
941
+ Parameters
942
+ ----------
943
+ shape : tuple of int
944
+ Texture shape (optional).
945
+ dtype : numpy.dtype object
946
+ Texture starting data type (default: float32)
947
+
948
+ Notes
949
+ -----
950
+ This creates a 2D texture that holds 1D float32 data.
951
+ An example of simple access:
952
+
953
+ >>> atlas = TextureAtlas()
954
+ >>> bounds = atlas.get_free_region(20, 30)
955
+ >>> atlas.set_region(bounds, np.random.rand(20, 30).T)
956
+ """
957
+
958
+ def __init__(self, shape=(1024, 1024), dtype=np.float32):
959
+ shape = np.array(shape, int)
960
+ assert shape.ndim == 1 and shape.size == 2
961
+ shape = tuple(2 ** (np.log2(shape) + 0.5).astype(int)) + (3,)
962
+ self._atlas_nodes = [(0, 0, shape[1])]
963
+ data = np.zeros(shape, dtype)
964
+ super(TextureAtlas, self).__init__(data, interpolation='linear',
965
+ wrapping='clamp_to_edge')
966
+
967
+ def get_free_region(self, width, height):
968
+ """Get a free region of given size and allocate it
969
+
970
+ Parameters
971
+ ----------
972
+ width : int
973
+ Width of region to allocate
974
+ height : int
975
+ Height of region to allocate
976
+
977
+ Returns
978
+ -------
979
+ bounds : tuple | None
980
+ A newly allocated region as (x, y, w, h) or None
981
+ (if failed).
982
+ """
983
+ best_height = best_width = np.inf
984
+ best_index = -1
985
+ for i in range(len(self._atlas_nodes)):
986
+ y = self._fit(i, width, height)
987
+ if y >= 0:
988
+ node = self._atlas_nodes[i]
989
+ if (y+height < best_height or
990
+ (y+height == best_height and node[2] < best_width)):
991
+ best_height = y+height
992
+ best_index = i
993
+ best_width = node[2]
994
+ region = node[0], y, width, height
995
+ if best_index == -1:
996
+ return None
997
+
998
+ node = region[0], region[1] + height, width
999
+ self._atlas_nodes.insert(best_index, node)
1000
+ i = best_index+1
1001
+ while i < len(self._atlas_nodes):
1002
+ node = self._atlas_nodes[i]
1003
+ prev_node = self._atlas_nodes[i-1]
1004
+ if node[0] < prev_node[0]+prev_node[2]:
1005
+ shrink = prev_node[0]+prev_node[2] - node[0]
1006
+ x, y, w = self._atlas_nodes[i]
1007
+ self._atlas_nodes[i] = x+shrink, y, w-shrink
1008
+ if self._atlas_nodes[i][2] <= 0:
1009
+ del self._atlas_nodes[i]
1010
+ i -= 1
1011
+ else:
1012
+ break
1013
+ else:
1014
+ break
1015
+ i += 1
1016
+
1017
+ # Merge nodes
1018
+ i = 0
1019
+ while i < len(self._atlas_nodes)-1:
1020
+ node = self._atlas_nodes[i]
1021
+ next_node = self._atlas_nodes[i+1]
1022
+ if node[1] == next_node[1]:
1023
+ self._atlas_nodes[i] = node[0], node[1], node[2]+next_node[2]
1024
+ del self._atlas_nodes[i+1]
1025
+ else:
1026
+ i += 1
1027
+
1028
+ return region
1029
+
1030
+ def _fit(self, index, width, height):
1031
+ """Test if region (width, height) fit into self._atlas_nodes[index]"""
1032
+ node = self._atlas_nodes[index]
1033
+ x, y = node[0], node[1]
1034
+ width_left = width
1035
+ if x+width > self._shape[1]:
1036
+ return -1
1037
+ i = index
1038
+ while width_left > 0:
1039
+ node = self._atlas_nodes[i]
1040
+ y = max(y, node[1])
1041
+ if y+height > self._shape[0]:
1042
+ return -1
1043
+ width_left -= node[2]
1044
+ i += 1
1045
+ return y