vispy 0.15.0__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
- vispy/__init__.py +33 -0
- vispy/app/__init__.py +15 -0
- vispy/app/_default_app.py +76 -0
- vispy/app/_detect_eventloop.py +148 -0
- vispy/app/application.py +263 -0
- vispy/app/backends/__init__.py +52 -0
- vispy/app/backends/_egl.py +264 -0
- vispy/app/backends/_glfw.py +513 -0
- vispy/app/backends/_jupyter_rfb.py +278 -0
- vispy/app/backends/_offscreen_util.py +121 -0
- vispy/app/backends/_osmesa.py +235 -0
- vispy/app/backends/_pyglet.py +451 -0
- vispy/app/backends/_pyqt4.py +36 -0
- vispy/app/backends/_pyqt5.py +36 -0
- vispy/app/backends/_pyqt6.py +40 -0
- vispy/app/backends/_pyside.py +37 -0
- vispy/app/backends/_pyside2.py +52 -0
- vispy/app/backends/_pyside6.py +53 -0
- vispy/app/backends/_qt.py +1003 -0
- vispy/app/backends/_sdl2.py +444 -0
- vispy/app/backends/_template.py +244 -0
- vispy/app/backends/_test.py +8 -0
- vispy/app/backends/_tk.py +800 -0
- vispy/app/backends/_wx.py +476 -0
- vispy/app/backends/tests/__init__.py +0 -0
- vispy/app/backends/tests/test_offscreen_util.py +52 -0
- vispy/app/backends/tests/test_rfb.py +77 -0
- vispy/app/base.py +294 -0
- vispy/app/canvas.py +828 -0
- vispy/app/qt.py +92 -0
- vispy/app/tests/__init__.py +0 -0
- vispy/app/tests/qt-designer.ui +58 -0
- vispy/app/tests/test_app.py +442 -0
- vispy/app/tests/test_backends.py +164 -0
- vispy/app/tests/test_canvas.py +122 -0
- vispy/app/tests/test_context.py +92 -0
- vispy/app/tests/test_qt.py +47 -0
- vispy/app/tests/test_simultaneous.py +134 -0
- vispy/app/timer.py +174 -0
- vispy/color/__init__.py +17 -0
- vispy/color/_color_dict.py +193 -0
- vispy/color/color_array.py +447 -0
- vispy/color/color_space.py +181 -0
- vispy/color/colormap.py +1213 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +378 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1522 -0
- vispy/ext/cubehelix.py +138 -0
- vispy/ext/egl.py +375 -0
- vispy/ext/fontconfig.py +118 -0
- vispy/ext/gdi32plus.py +206 -0
- vispy/ext/osmesa.py +105 -0
- vispy/geometry/__init__.py +23 -0
- vispy/geometry/_triangulation_debugger.py +171 -0
- vispy/geometry/calculations.py +162 -0
- vispy/geometry/curves.py +399 -0
- vispy/geometry/generation.py +643 -0
- vispy/geometry/isocurve.py +175 -0
- vispy/geometry/isosurface.py +465 -0
- vispy/geometry/meshdata.py +700 -0
- vispy/geometry/normals.py +78 -0
- vispy/geometry/parametric.py +56 -0
- vispy/geometry/polygon.py +137 -0
- vispy/geometry/rect.py +210 -0
- vispy/geometry/tests/__init__.py +0 -0
- vispy/geometry/tests/test_calculations.py +23 -0
- vispy/geometry/tests/test_generation.py +56 -0
- vispy/geometry/tests/test_meshdata.py +106 -0
- vispy/geometry/tests/test_triangulation.py +594 -0
- vispy/geometry/torusknot.py +142 -0
- vispy/geometry/triangulation.py +876 -0
- vispy/gloo/__init__.py +56 -0
- vispy/gloo/buffer.py +505 -0
- vispy/gloo/context.py +272 -0
- vispy/gloo/framebuffer.py +257 -0
- vispy/gloo/gl/__init__.py +234 -0
- vispy/gloo/gl/_constants.py +332 -0
- vispy/gloo/gl/_es2.py +986 -0
- vispy/gloo/gl/_gl2.py +1365 -0
- vispy/gloo/gl/_proxy.py +499 -0
- vispy/gloo/gl/_pyopengl2.py +362 -0
- vispy/gloo/gl/dummy.py +24 -0
- vispy/gloo/gl/es2.py +62 -0
- vispy/gloo/gl/gl2.py +98 -0
- vispy/gloo/gl/glplus.py +168 -0
- vispy/gloo/gl/pyopengl2.py +97 -0
- vispy/gloo/gl/tests/__init__.py +0 -0
- vispy/gloo/gl/tests/test_basics.py +282 -0
- vispy/gloo/gl/tests/test_functionality.py +568 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1824 -0
- vispy/gloo/globject.py +101 -0
- vispy/gloo/preprocessor.py +67 -0
- vispy/gloo/program.py +543 -0
- vispy/gloo/tests/__init__.py +0 -0
- vispy/gloo/tests/test_buffer.py +558 -0
- vispy/gloo/tests/test_context.py +119 -0
- vispy/gloo/tests/test_framebuffer.py +195 -0
- vispy/gloo/tests/test_glir.py +307 -0
- vispy/gloo/tests/test_globject.py +35 -0
- vispy/gloo/tests/test_program.py +302 -0
- vispy/gloo/tests/test_texture.py +732 -0
- vispy/gloo/tests/test_use_gloo.py +187 -0
- vispy/gloo/tests/test_util.py +60 -0
- vispy/gloo/tests/test_wrappers.py +261 -0
- vispy/gloo/texture.py +1046 -0
- vispy/gloo/util.py +129 -0
- vispy/gloo/wrappers.py +762 -0
- vispy/glsl/__init__.py +42 -0
- vispy/glsl/antialias/antialias.glsl +7 -0
- vispy/glsl/antialias/cap-butt.glsl +31 -0
- vispy/glsl/antialias/cap-round.glsl +29 -0
- vispy/glsl/antialias/cap-square.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
- vispy/glsl/antialias/cap.glsl +67 -0
- vispy/glsl/antialias/caps.glsl +67 -0
- vispy/glsl/antialias/filled.glsl +50 -0
- vispy/glsl/antialias/outline.glsl +40 -0
- vispy/glsl/antialias/stroke.glsl +43 -0
- vispy/glsl/arrowheads/angle.glsl +99 -0
- vispy/glsl/arrowheads/arrowheads.frag +60 -0
- vispy/glsl/arrowheads/arrowheads.glsl +12 -0
- vispy/glsl/arrowheads/arrowheads.vert +83 -0
- vispy/glsl/arrowheads/curved.glsl +48 -0
- vispy/glsl/arrowheads/inhibitor.glsl +26 -0
- vispy/glsl/arrowheads/stealth.glsl +46 -0
- vispy/glsl/arrowheads/triangle.glsl +97 -0
- vispy/glsl/arrowheads/util.glsl +13 -0
- vispy/glsl/arrows/angle-30.glsl +12 -0
- vispy/glsl/arrows/angle-60.glsl +12 -0
- vispy/glsl/arrows/angle-90.glsl +12 -0
- vispy/glsl/arrows/arrow.frag +39 -0
- vispy/glsl/arrows/arrow.vert +49 -0
- vispy/glsl/arrows/arrows.glsl +17 -0
- vispy/glsl/arrows/common.glsl +187 -0
- vispy/glsl/arrows/curved.glsl +63 -0
- vispy/glsl/arrows/stealth.glsl +50 -0
- vispy/glsl/arrows/triangle-30.glsl +12 -0
- vispy/glsl/arrows/triangle-60.glsl +12 -0
- vispy/glsl/arrows/triangle-90.glsl +12 -0
- vispy/glsl/arrows/util.glsl +98 -0
- vispy/glsl/build_spatial_filters.py +660 -0
- vispy/glsl/collections/agg-fast-path.frag +20 -0
- vispy/glsl/collections/agg-fast-path.vert +78 -0
- vispy/glsl/collections/agg-glyph.frag +60 -0
- vispy/glsl/collections/agg-glyph.vert +33 -0
- vispy/glsl/collections/agg-marker.frag +35 -0
- vispy/glsl/collections/agg-marker.vert +48 -0
- vispy/glsl/collections/agg-path.frag +55 -0
- vispy/glsl/collections/agg-path.vert +166 -0
- vispy/glsl/collections/agg-point.frag +21 -0
- vispy/glsl/collections/agg-point.vert +35 -0
- vispy/glsl/collections/agg-segment.frag +32 -0
- vispy/glsl/collections/agg-segment.vert +75 -0
- vispy/glsl/collections/marker.frag +38 -0
- vispy/glsl/collections/marker.vert +48 -0
- vispy/glsl/collections/raw-path.frag +15 -0
- vispy/glsl/collections/raw-path.vert +24 -0
- vispy/glsl/collections/raw-point.frag +14 -0
- vispy/glsl/collections/raw-point.vert +31 -0
- vispy/glsl/collections/raw-segment.frag +18 -0
- vispy/glsl/collections/raw-segment.vert +26 -0
- vispy/glsl/collections/raw-triangle.frag +13 -0
- vispy/glsl/collections/raw-triangle.vert +26 -0
- vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
- vispy/glsl/collections/sdf-glyph.frag +80 -0
- vispy/glsl/collections/sdf-glyph.vert +59 -0
- vispy/glsl/collections/tick-labels.vert +71 -0
- vispy/glsl/colormaps/autumn.glsl +20 -0
- vispy/glsl/colormaps/blues.glsl +20 -0
- vispy/glsl/colormaps/color-space.glsl +17 -0
- vispy/glsl/colormaps/colormaps.glsl +24 -0
- vispy/glsl/colormaps/cool.glsl +20 -0
- vispy/glsl/colormaps/fire.glsl +21 -0
- vispy/glsl/colormaps/gray.glsl +20 -0
- vispy/glsl/colormaps/greens.glsl +20 -0
- vispy/glsl/colormaps/hot.glsl +22 -0
- vispy/glsl/colormaps/ice.glsl +20 -0
- vispy/glsl/colormaps/icefire.glsl +23 -0
- vispy/glsl/colormaps/parse.py +40 -0
- vispy/glsl/colormaps/reds.glsl +20 -0
- vispy/glsl/colormaps/spring.glsl +20 -0
- vispy/glsl/colormaps/summer.glsl +20 -0
- vispy/glsl/colormaps/user.glsl +22 -0
- vispy/glsl/colormaps/util.glsl +41 -0
- vispy/glsl/colormaps/wheel.glsl +21 -0
- vispy/glsl/colormaps/winter.glsl +20 -0
- vispy/glsl/lines/agg.frag +320 -0
- vispy/glsl/lines/agg.vert +241 -0
- vispy/glsl/markers/arrow.glsl +12 -0
- vispy/glsl/markers/asterisk.glsl +16 -0
- vispy/glsl/markers/chevron.glsl +14 -0
- vispy/glsl/markers/clover.glsl +20 -0
- vispy/glsl/markers/club.glsl +31 -0
- vispy/glsl/markers/cross.glsl +17 -0
- vispy/glsl/markers/diamond.glsl +12 -0
- vispy/glsl/markers/disc.glsl +9 -0
- vispy/glsl/markers/ellipse.glsl +67 -0
- vispy/glsl/markers/hbar.glsl +9 -0
- vispy/glsl/markers/heart.glsl +15 -0
- vispy/glsl/markers/infinity.glsl +15 -0
- vispy/glsl/markers/marker-sdf.frag +74 -0
- vispy/glsl/markers/marker-sdf.vert +41 -0
- vispy/glsl/markers/marker.frag +36 -0
- vispy/glsl/markers/marker.vert +46 -0
- vispy/glsl/markers/markers.glsl +24 -0
- vispy/glsl/markers/pin.glsl +18 -0
- vispy/glsl/markers/ring.glsl +11 -0
- vispy/glsl/markers/spade.glsl +28 -0
- vispy/glsl/markers/square.glsl +10 -0
- vispy/glsl/markers/tag.glsl +11 -0
- vispy/glsl/markers/triangle.glsl +14 -0
- vispy/glsl/markers/vbar.glsl +9 -0
- vispy/glsl/math/circle-through-2-points.glsl +30 -0
- vispy/glsl/math/constants.glsl +48 -0
- vispy/glsl/math/double.glsl +114 -0
- vispy/glsl/math/functions.glsl +20 -0
- vispy/glsl/math/point-to-line-distance.glsl +31 -0
- vispy/glsl/math/point-to-line-projection.glsl +29 -0
- vispy/glsl/math/signed-line-distance.glsl +27 -0
- vispy/glsl/math/signed-segment-distance.glsl +30 -0
- vispy/glsl/misc/regular-grid.frag +244 -0
- vispy/glsl/misc/spatial-filters.frag +1407 -0
- vispy/glsl/misc/viewport-NDC.glsl +20 -0
- vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
- vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
- vispy/glsl/transforms/hammer.glsl +44 -0
- vispy/glsl/transforms/identity.glsl +6 -0
- vispy/glsl/transforms/identity_forward.glsl +23 -0
- vispy/glsl/transforms/identity_inverse.glsl +23 -0
- vispy/glsl/transforms/linear-scale.glsl +127 -0
- vispy/glsl/transforms/log-scale.glsl +126 -0
- vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
- vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
- vispy/glsl/transforms/panzoom.glsl +10 -0
- vispy/glsl/transforms/polar.glsl +41 -0
- vispy/glsl/transforms/position.glsl +44 -0
- vispy/glsl/transforms/power-scale.glsl +139 -0
- vispy/glsl/transforms/projection.glsl +7 -0
- vispy/glsl/transforms/pvm.glsl +13 -0
- vispy/glsl/transforms/rotate.glsl +45 -0
- vispy/glsl/transforms/trackball.glsl +15 -0
- vispy/glsl/transforms/translate.glsl +35 -0
- vispy/glsl/transforms/transverse_mercator.glsl +38 -0
- vispy/glsl/transforms/viewport-clipping.glsl +14 -0
- vispy/glsl/transforms/viewport-transform.glsl +16 -0
- vispy/glsl/transforms/viewport.glsl +50 -0
- vispy/glsl/transforms/x.glsl +24 -0
- vispy/glsl/transforms/y.glsl +19 -0
- vispy/glsl/transforms/z.glsl +14 -0
- vispy/io/__init__.py +20 -0
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +94 -0
- vispy/io/image.py +231 -0
- vispy/io/mesh.py +122 -0
- vispy/io/stl.py +167 -0
- vispy/io/tests/__init__.py +0 -0
- vispy/io/tests/test_image.py +47 -0
- vispy/io/tests/test_io.py +121 -0
- vispy/io/wavefront.py +350 -0
- vispy/plot/__init__.py +36 -0
- vispy/plot/fig.py +58 -0
- vispy/plot/plotwidget.py +522 -0
- vispy/plot/tests/__init__.py +0 -0
- vispy/plot/tests/test_plot.py +46 -0
- vispy/scene/__init__.py +43 -0
- vispy/scene/cameras/__init__.py +27 -0
- vispy/scene/cameras/_base.py +38 -0
- vispy/scene/cameras/arcball.py +105 -0
- vispy/scene/cameras/base_camera.py +551 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +311 -0
- vispy/scene/cameras/perspective.py +338 -0
- vispy/scene/cameras/tests/__init__.py +0 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_link.py +53 -0
- vispy/scene/cameras/tests/test_perspective.py +122 -0
- vispy/scene/cameras/turntable.py +183 -0
- vispy/scene/canvas.py +639 -0
- vispy/scene/events.py +85 -0
- vispy/scene/node.py +644 -0
- vispy/scene/subscene.py +20 -0
- vispy/scene/tests/__init__.py +0 -0
- vispy/scene/tests/test_canvas.py +119 -0
- vispy/scene/tests/test_node.py +142 -0
- vispy/scene/tests/test_visuals.py +141 -0
- vispy/scene/visuals.py +276 -0
- vispy/scene/widgets/__init__.py +18 -0
- vispy/scene/widgets/anchor.py +25 -0
- vispy/scene/widgets/axis.py +88 -0
- vispy/scene/widgets/colorbar.py +176 -0
- vispy/scene/widgets/console.py +351 -0
- vispy/scene/widgets/grid.py +509 -0
- vispy/scene/widgets/label.py +50 -0
- vispy/scene/widgets/tests/__init__.py +0 -0
- vispy/scene/widgets/tests/test_colorbar.py +47 -0
- vispy/scene/widgets/viewbox.py +199 -0
- vispy/scene/widgets/widget.py +478 -0
- vispy/testing/__init__.py +51 -0
- vispy/testing/_runners.py +448 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +494 -0
- vispy/testing/rendered_array_tester.py +85 -0
- vispy/testing/tests/__init__.py +0 -0
- vispy/testing/tests/test_testing.py +20 -0
- vispy/util/__init__.py +32 -0
- vispy/util/bunch.py +15 -0
- vispy/util/check_environment.py +57 -0
- vispy/util/config.py +490 -0
- vispy/util/dpi/__init__.py +19 -0
- vispy/util/dpi/_linux.py +69 -0
- vispy/util/dpi/_quartz.py +26 -0
- vispy/util/dpi/_win32.py +34 -0
- vispy/util/dpi/tests/__init__.py +0 -0
- vispy/util/dpi/tests/test_dpi.py +16 -0
- vispy/util/eq.py +41 -0
- vispy/util/event.py +774 -0
- vispy/util/fetching.py +276 -0
- vispy/util/filter.py +44 -0
- vispy/util/fonts/__init__.py +14 -0
- vispy/util/fonts/_freetype.py +73 -0
- vispy/util/fonts/_quartz.py +192 -0
- vispy/util/fonts/_triage.py +36 -0
- vispy/util/fonts/_vispy_fonts.py +20 -0
- vispy/util/fonts/_win32.py +105 -0
- vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
- vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
- vispy/util/fonts/tests/__init__.py +0 -0
- vispy/util/fonts/tests/test_font.py +45 -0
- vispy/util/fourier.py +69 -0
- vispy/util/frozen.py +25 -0
- vispy/util/gallery_scraper.py +268 -0
- vispy/util/keys.py +91 -0
- vispy/util/logs.py +358 -0
- vispy/util/osmesa_gl.py +17 -0
- vispy/util/profiler.py +135 -0
- vispy/util/ptime.py +16 -0
- vispy/util/quaternion.py +229 -0
- vispy/util/svg/__init__.py +18 -0
- vispy/util/svg/base.py +20 -0
- vispy/util/svg/color.py +219 -0
- vispy/util/svg/element.py +51 -0
- vispy/util/svg/geometry.py +478 -0
- vispy/util/svg/group.py +66 -0
- vispy/util/svg/length.py +81 -0
- vispy/util/svg/number.py +25 -0
- vispy/util/svg/path.py +332 -0
- vispy/util/svg/shapes.py +57 -0
- vispy/util/svg/style.py +59 -0
- vispy/util/svg/svg.py +40 -0
- vispy/util/svg/transform.py +223 -0
- vispy/util/svg/transformable.py +28 -0
- vispy/util/svg/viewport.py +73 -0
- vispy/util/tests/__init__.py +0 -0
- vispy/util/tests/test_config.py +58 -0
- vispy/util/tests/test_docstring_parameters.py +123 -0
- vispy/util/tests/test_emitter_group.py +262 -0
- vispy/util/tests/test_event_emitter.py +743 -0
- vispy/util/tests/test_fourier.py +35 -0
- vispy/util/tests/test_gallery_scraper.py +112 -0
- vispy/util/tests/test_import.py +127 -0
- vispy/util/tests/test_key.py +22 -0
- vispy/util/tests/test_logging.py +45 -0
- vispy/util/tests/test_run.py +14 -0
- vispy/util/tests/test_transforms.py +42 -0
- vispy/util/tests/test_vispy.py +48 -0
- vispy/util/transforms.py +201 -0
- vispy/util/wrappers.py +155 -0
- vispy/version.py +21 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +487 -0
- vispy/visuals/axis.py +678 -0
- vispy/visuals/border.py +208 -0
- vispy/visuals/box.py +79 -0
- vispy/visuals/collections/__init__.py +30 -0
- vispy/visuals/collections/agg_fast_path_collection.py +219 -0
- vispy/visuals/collections/agg_path_collection.py +197 -0
- vispy/visuals/collections/agg_point_collection.py +52 -0
- vispy/visuals/collections/agg_segment_collection.py +142 -0
- vispy/visuals/collections/array_list.py +401 -0
- vispy/visuals/collections/base_collection.py +482 -0
- vispy/visuals/collections/collection.py +253 -0
- vispy/visuals/collections/path_collection.py +23 -0
- vispy/visuals/collections/point_collection.py +19 -0
- vispy/visuals/collections/polygon_collection.py +25 -0
- vispy/visuals/collections/raw_path_collection.py +119 -0
- vispy/visuals/collections/raw_point_collection.py +113 -0
- vispy/visuals/collections/raw_polygon_collection.py +77 -0
- vispy/visuals/collections/raw_segment_collection.py +112 -0
- vispy/visuals/collections/raw_triangle_collection.py +78 -0
- vispy/visuals/collections/segment_collection.py +19 -0
- vispy/visuals/collections/triangle_collection.py +16 -0
- vispy/visuals/collections/util.py +168 -0
- vispy/visuals/colorbar.py +699 -0
- vispy/visuals/cube.py +41 -0
- vispy/visuals/ellipse.py +162 -0
- vispy/visuals/filters/__init__.py +10 -0
- vispy/visuals/filters/base_filter.py +242 -0
- vispy/visuals/filters/clipper.py +60 -0
- vispy/visuals/filters/clipping_planes.py +122 -0
- vispy/visuals/filters/color.py +181 -0
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +801 -0
- vispy/visuals/filters/picking.py +60 -0
- vispy/visuals/filters/tests/__init__.py +3 -0
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
- vispy/visuals/glsl/__init__.py +1 -0
- vispy/visuals/glsl/antialiasing.py +133 -0
- vispy/visuals/glsl/color.py +63 -0
- vispy/visuals/graphs/__init__.py +1 -0
- vispy/visuals/graphs/graph.py +240 -0
- vispy/visuals/graphs/layouts/__init__.py +55 -0
- vispy/visuals/graphs/layouts/circular.py +49 -0
- vispy/visuals/graphs/layouts/force_directed.py +211 -0
- vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
- vispy/visuals/graphs/layouts/random.py +52 -0
- vispy/visuals/graphs/tests/__init__.py +1 -0
- vispy/visuals/graphs/tests/test_layouts.py +139 -0
- vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
- vispy/visuals/graphs/util.py +120 -0
- vispy/visuals/gridlines.py +161 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +701 -0
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/infinite_line.py +199 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +213 -0
- vispy/visuals/isoline.py +241 -0
- vispy/visuals/isosurface.py +113 -0
- vispy/visuals/line/__init__.py +6 -0
- vispy/visuals/line/arrow.py +289 -0
- vispy/visuals/line/dash_atlas.py +90 -0
- vispy/visuals/line/line.py +545 -0
- vispy/visuals/line_plot.py +135 -0
- vispy/visuals/linear_region.py +199 -0
- vispy/visuals/markers.py +819 -0
- vispy/visuals/mesh.py +373 -0
- vispy/visuals/mesh_normals.py +159 -0
- vispy/visuals/plane.py +54 -0
- vispy/visuals/polygon.py +145 -0
- vispy/visuals/rectangle.py +196 -0
- vispy/visuals/regular_polygon.py +56 -0
- vispy/visuals/scrolling_lines.py +197 -0
- vispy/visuals/shaders/__init__.py +17 -0
- vispy/visuals/shaders/compiler.py +206 -0
- vispy/visuals/shaders/expression.py +99 -0
- vispy/visuals/shaders/function.py +788 -0
- vispy/visuals/shaders/multiprogram.py +145 -0
- vispy/visuals/shaders/parsing.py +140 -0
- vispy/visuals/shaders/program.py +161 -0
- vispy/visuals/shaders/shader_object.py +162 -0
- vispy/visuals/shaders/tests/__init__.py +0 -0
- vispy/visuals/shaders/tests/test_function.py +486 -0
- vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
- vispy/visuals/shaders/tests/test_parsing.py +57 -0
- vispy/visuals/shaders/variable.py +272 -0
- vispy/visuals/spectrogram.py +169 -0
- vispy/visuals/sphere.py +80 -0
- vispy/visuals/surface_plot.py +192 -0
- vispy/visuals/tests/__init__.py +0 -0
- vispy/visuals/tests/test_arrows.py +109 -0
- vispy/visuals/tests/test_axis.py +120 -0
- vispy/visuals/tests/test_collections.py +15 -0
- vispy/visuals/tests/test_colorbar.py +179 -0
- vispy/visuals/tests/test_colormap.py +97 -0
- vispy/visuals/tests/test_ellipse.py +122 -0
- vispy/visuals/tests/test_gridlines.py +30 -0
- vispy/visuals/tests/test_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +392 -0
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_infinite_line.py +53 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_isosurface.py +22 -0
- vispy/visuals/tests/test_linear_region.py +152 -0
- vispy/visuals/tests/test_markers.py +54 -0
- vispy/visuals/tests/test_mesh.py +261 -0
- vispy/visuals/tests/test_mesh_normals.py +218 -0
- vispy/visuals/tests/test_polygon.py +112 -0
- vispy/visuals/tests/test_rectangle.py +163 -0
- vispy/visuals/tests/test_regular_polygon.py +111 -0
- vispy/visuals/tests/test_scalable_textures.py +196 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -0
- vispy/visuals/tests/test_surface_plot.py +57 -0
- vispy/visuals/tests/test_text.py +95 -0
- vispy/visuals/tests/test_volume.py +542 -0
- vispy/visuals/tests/test_windbarb.py +33 -0
- vispy/visuals/text/__init__.py +7 -0
- vispy/visuals/text/_sdf_cpu.cpython-313-x86_64-linux-gnu.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +112 -0
- vispy/visuals/text/_sdf_gpu.py +316 -0
- vispy/visuals/text/text.py +675 -0
- vispy/visuals/transforms/__init__.py +34 -0
- vispy/visuals/transforms/_util.py +191 -0
- vispy/visuals/transforms/base_transform.py +233 -0
- vispy/visuals/transforms/chain.py +300 -0
- vispy/visuals/transforms/interactive.py +98 -0
- vispy/visuals/transforms/linear.py +564 -0
- vispy/visuals/transforms/nonlinear.py +398 -0
- vispy/visuals/transforms/tests/__init__.py +0 -0
- vispy/visuals/transforms/tests/test_transforms.py +243 -0
- vispy/visuals/transforms/transform_system.py +339 -0
- vispy/visuals/tube.py +173 -0
- vispy/visuals/visual.py +923 -0
- vispy/visuals/volume.py +1366 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.15.0.dist-info/METADATA +243 -0
- vispy-0.15.0.dist-info/RECORD +521 -0
- vispy-0.15.0.dist-info/WHEEL +6 -0
- vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
- vispy-0.15.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from ..base import BaseApplicationBackend, BaseCanvasBackend, BaseTimerBackend
|
|
4
|
+
from ...app import Timer
|
|
5
|
+
from ...util import keys
|
|
6
|
+
from ._offscreen_util import OffscreenContext, FrameBufferHelper
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
from jupyter_rfb import RemoteFrameBuffer
|
|
11
|
+
except Exception:
|
|
12
|
+
RemoteFrameBuffer = object
|
|
13
|
+
_msg = 'The jupyter_rfb backend relies on a the jupyter_rfb library: ``pip install jupyter_rfb``'
|
|
14
|
+
available, testable, why_not, which = False, False, _msg, None
|
|
15
|
+
else:
|
|
16
|
+
available, testable, why_not = True, False, None
|
|
17
|
+
which = "jupyter_rfb"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# -------------------------------------------------------------- capability ---
|
|
21
|
+
|
|
22
|
+
capability = dict(
|
|
23
|
+
title=False,
|
|
24
|
+
size=True,
|
|
25
|
+
position=False,
|
|
26
|
+
show=False,
|
|
27
|
+
vsync=False,
|
|
28
|
+
resizable=True,
|
|
29
|
+
decorate=False,
|
|
30
|
+
fullscreen=False,
|
|
31
|
+
context=False, # Could work, but not implemented
|
|
32
|
+
multi_window=True,
|
|
33
|
+
scroll=True,
|
|
34
|
+
parent=False, # ipywidgets has layouts, but has no concept of parents
|
|
35
|
+
always_on_top=False,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# ------------------------------------------------------- set_configuration ---
|
|
40
|
+
|
|
41
|
+
# The configuration mostly applies to the framebuffer. So if we'd want
|
|
42
|
+
# to implement some of that, we'd probably have to apply it to the FBO.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# ------------------------------------------------------------- application ---
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ApplicationBackend(BaseApplicationBackend):
|
|
49
|
+
|
|
50
|
+
def __init__(self):
|
|
51
|
+
super().__init__()
|
|
52
|
+
|
|
53
|
+
def _vispy_get_backend_name(self):
|
|
54
|
+
return 'jupyter_rfb'
|
|
55
|
+
|
|
56
|
+
def _vispy_process_events(self):
|
|
57
|
+
raise RuntimeError("Cannot process events while asyncio event-loop is running.")
|
|
58
|
+
|
|
59
|
+
def _vispy_run(self):
|
|
60
|
+
pass # We're in IPython; don't enter a mainloop or we'll block!
|
|
61
|
+
|
|
62
|
+
def _vispy_quit(self):
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def _vispy_get_native_app(self):
|
|
66
|
+
return asyncio
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ------------------------------------------------------------------ canvas ---
|
|
70
|
+
|
|
71
|
+
class CanvasBackend(BaseCanvasBackend, RemoteFrameBuffer):
|
|
72
|
+
|
|
73
|
+
_double_click_supported = True
|
|
74
|
+
|
|
75
|
+
def __init__(self, vispy_canvas, **kwargs):
|
|
76
|
+
BaseCanvasBackend.__init__(self, vispy_canvas)
|
|
77
|
+
RemoteFrameBuffer.__init__(self)
|
|
78
|
+
# Use a context per canvas, because we seem to make assumptions
|
|
79
|
+
# about OpenGL state being local to the canvas.
|
|
80
|
+
self._context = OffscreenContext() # OffscreenContext.get_global_instance()
|
|
81
|
+
self._helper = FrameBufferHelper()
|
|
82
|
+
self._loop = asyncio.get_event_loop()
|
|
83
|
+
self._logical_size = 1, 1
|
|
84
|
+
self._physical_size = 1, 1
|
|
85
|
+
self._lifecycle = 0 # 0: not initialized, 1: initialized, 2: closed
|
|
86
|
+
# Init more based on kwargs (could maybe handle, title, show, context)
|
|
87
|
+
self._vispy_set_size(*kwargs["size"])
|
|
88
|
+
self.resizable = kwargs["resizable"]
|
|
89
|
+
# Need a first update
|
|
90
|
+
self._vispy_update()
|
|
91
|
+
|
|
92
|
+
def handle_event(self, ev):
|
|
93
|
+
type = ev["event_type"]
|
|
94
|
+
if type == "resize":
|
|
95
|
+
# Note that jupyter_rfb already throttles this event
|
|
96
|
+
w, h, r = ev["width"], ev["height"], ev["pixel_ratio"]
|
|
97
|
+
self._logical_size = w, h
|
|
98
|
+
self._physical_size = int(w * r), int(h * r)
|
|
99
|
+
self._helper.set_physical_size(*self._physical_size)
|
|
100
|
+
self._loop.call_soon(self._emit_resize_event)
|
|
101
|
+
self._vispy_update() # make sure to schedule a new draw
|
|
102
|
+
elif type == "pointer_down":
|
|
103
|
+
self._vispy_mouse_press(
|
|
104
|
+
native=ev,
|
|
105
|
+
pos=(ev["x"], ev["y"]),
|
|
106
|
+
button=ev["button"],
|
|
107
|
+
modifiers=self._modifiers(ev),
|
|
108
|
+
)
|
|
109
|
+
elif type == "pointer_up":
|
|
110
|
+
self._vispy_mouse_release(
|
|
111
|
+
native=ev,
|
|
112
|
+
pos=(ev["x"], ev["y"]),
|
|
113
|
+
button=ev["button"],
|
|
114
|
+
modifiers=self._modifiers(ev),
|
|
115
|
+
)
|
|
116
|
+
elif type == "pointer_move":
|
|
117
|
+
self._vispy_mouse_move(
|
|
118
|
+
native=ev,
|
|
119
|
+
pos=(ev["x"], ev["y"]),
|
|
120
|
+
button=ev["button"],
|
|
121
|
+
modifiers=self._modifiers(ev),
|
|
122
|
+
)
|
|
123
|
+
elif type == "double_click":
|
|
124
|
+
self._vispy_mouse_double_click(
|
|
125
|
+
native=ev,
|
|
126
|
+
pos=(ev["x"], ev["y"]),
|
|
127
|
+
button=ev["button"],
|
|
128
|
+
modifiers=self._modifiers(ev),
|
|
129
|
+
)
|
|
130
|
+
elif type == "wheel":
|
|
131
|
+
self._vispy_canvas.events.mouse_wheel(
|
|
132
|
+
native=ev,
|
|
133
|
+
pos=(ev["x"], ev["y"]),
|
|
134
|
+
delta=(ev["dx"] / 100, - ev["dy"] / 100),
|
|
135
|
+
modifiers=self._modifiers(ev),
|
|
136
|
+
)
|
|
137
|
+
elif type == "key_down":
|
|
138
|
+
# The special key names are all (most?) the same
|
|
139
|
+
# But the key is actually more like tex, e.g. shift + 3 becomes "#"
|
|
140
|
+
self._vispy_canvas.events.key_press(
|
|
141
|
+
native=ev,
|
|
142
|
+
key=keys.Key(ev["key"]),
|
|
143
|
+
modifiers=self._modifiers(ev),
|
|
144
|
+
text=ev["key"],
|
|
145
|
+
)
|
|
146
|
+
elif type == "key_up":
|
|
147
|
+
self._vispy_canvas.events.key_release(
|
|
148
|
+
native=ev,
|
|
149
|
+
key=keys.Key(ev["key"]),
|
|
150
|
+
modifiers=self._modifiers(ev),
|
|
151
|
+
text=ev["key"],
|
|
152
|
+
)
|
|
153
|
+
elif type == "close":
|
|
154
|
+
self._lifecycle = 2
|
|
155
|
+
self._context.close()
|
|
156
|
+
_stop_timers(self._vispy_canvas)
|
|
157
|
+
else:
|
|
158
|
+
pass # event ignored / unknown
|
|
159
|
+
|
|
160
|
+
def _modifiers(self, ev):
|
|
161
|
+
return tuple(getattr(keys, m.upper()) for m in ev["modifiers"])
|
|
162
|
+
|
|
163
|
+
def _emit_resize_event(self):
|
|
164
|
+
self._vispy_canvas.events.resize(
|
|
165
|
+
size=self._logical_size,
|
|
166
|
+
physical_size=self._physical_size,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
def get_frame(self):
|
|
170
|
+
# This gets automatically called by the RFB widget
|
|
171
|
+
|
|
172
|
+
# Only draw if the draw region is not null
|
|
173
|
+
if self._physical_size[0] <= 1 or self._physical_size[1] <= 1:
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
# Handle initialization
|
|
177
|
+
if not self._lifecycle:
|
|
178
|
+
self._lifecycle = 1
|
|
179
|
+
self._vispy_canvas.set_current()
|
|
180
|
+
self._vispy_canvas.events.initialize()
|
|
181
|
+
self._emit_resize_event()
|
|
182
|
+
|
|
183
|
+
# Draw and obtain result
|
|
184
|
+
self._vispy_canvas.set_current()
|
|
185
|
+
with self._helper:
|
|
186
|
+
self._vispy_canvas.events.draw(region=None)
|
|
187
|
+
array = self._helper.get_frame()
|
|
188
|
+
|
|
189
|
+
# Flush commands here to clean up - otherwise we get errors related to
|
|
190
|
+
# framebuffers not existin.
|
|
191
|
+
self._vispy_canvas.context.flush_commands()
|
|
192
|
+
|
|
193
|
+
return array
|
|
194
|
+
|
|
195
|
+
def _vispy_warmup(self):
|
|
196
|
+
self._vispy_canvas.set_current()
|
|
197
|
+
|
|
198
|
+
def _vispy_set_current(self):
|
|
199
|
+
self._context.make_current()
|
|
200
|
+
|
|
201
|
+
def _vispy_swap_buffers(self):
|
|
202
|
+
pass
|
|
203
|
+
|
|
204
|
+
def _vispy_set_title(self, title):
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
def _vispy_set_size(self, w, h):
|
|
208
|
+
self.css_width = f"{w}px"
|
|
209
|
+
self.css_height = f"{h}px"
|
|
210
|
+
|
|
211
|
+
def _vispy_set_position(self, x, y):
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
def _vispy_set_visible(self, visible):
|
|
215
|
+
if not visible:
|
|
216
|
+
raise NotImplementedError("Cannot hide the RFB widget")
|
|
217
|
+
|
|
218
|
+
def _vispy_set_fullscreen(self, fullscreen):
|
|
219
|
+
raise NotImplementedError()
|
|
220
|
+
|
|
221
|
+
def _vispy_update(self):
|
|
222
|
+
self.request_draw()
|
|
223
|
+
|
|
224
|
+
def _vispy_close(self):
|
|
225
|
+
# ipywidget.Widget.close() -> closes the comm and removes all views
|
|
226
|
+
self.close()
|
|
227
|
+
|
|
228
|
+
def _vispy_get_size(self):
|
|
229
|
+
return self._logical_size
|
|
230
|
+
|
|
231
|
+
def _vispy_get_physical_size(self):
|
|
232
|
+
return self._physical_size
|
|
233
|
+
|
|
234
|
+
def _vispy_get_position(self):
|
|
235
|
+
return 0, 0
|
|
236
|
+
|
|
237
|
+
def _vispy_get_fullscreen(self):
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# ------------------------------------------------------------------- timer ---
|
|
242
|
+
|
|
243
|
+
class TimerBackend(BaseTimerBackend):
|
|
244
|
+
|
|
245
|
+
def __init__(self, vispy_timer):
|
|
246
|
+
super().__init__(vispy_timer)
|
|
247
|
+
self._loop = asyncio.get_event_loop()
|
|
248
|
+
self._task = None
|
|
249
|
+
|
|
250
|
+
async def _timer_coro(self, interval):
|
|
251
|
+
while True:
|
|
252
|
+
await asyncio.sleep(interval)
|
|
253
|
+
self._vispy_timeout()
|
|
254
|
+
|
|
255
|
+
def _vispy_start(self, interval):
|
|
256
|
+
if self._task is not None:
|
|
257
|
+
self._task.cancel()
|
|
258
|
+
self._task = asyncio.create_task(self._timer_coro(interval))
|
|
259
|
+
|
|
260
|
+
def _vispy_stop(self):
|
|
261
|
+
self._task.cancel()
|
|
262
|
+
self._task = None
|
|
263
|
+
|
|
264
|
+
def _vispy_timeout(self):
|
|
265
|
+
self._loop.call_soon(self._vispy_timer._timeout)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _stop_timers(canvas):
|
|
269
|
+
"""Stop all timers associated with a canvas."""
|
|
270
|
+
# This is nice and all, but the Canvas object is frozen, so this is never actually used
|
|
271
|
+
for attr in dir(canvas):
|
|
272
|
+
try:
|
|
273
|
+
attr_obj = getattr(canvas, attr)
|
|
274
|
+
except NotImplementedError:
|
|
275
|
+
continue # prevent error due to props that we don't implement
|
|
276
|
+
else:
|
|
277
|
+
if isinstance(attr_obj, Timer):
|
|
278
|
+
attr_obj.stop()
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utils for offscreen rendering.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .. import Application, Canvas
|
|
6
|
+
from ... import gloo
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class OffscreenContext:
|
|
10
|
+
""" A helper class to provide an OpenGL context. This context is global
|
|
11
|
+
to the application.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
_global_instance = None
|
|
15
|
+
_canvas = None
|
|
16
|
+
|
|
17
|
+
@classmethod
|
|
18
|
+
def get_global_instance(cls):
|
|
19
|
+
""" Get a global context. Note that any assumptions about OpenGL state
|
|
20
|
+
being local will not hold.
|
|
21
|
+
"""
|
|
22
|
+
if cls._global_instance is None:
|
|
23
|
+
cls._global_instance = cls()
|
|
24
|
+
return cls._global_instance
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
if self._canvas is not None:
|
|
28
|
+
return # already initialized
|
|
29
|
+
|
|
30
|
+
self._is_closed = False
|
|
31
|
+
|
|
32
|
+
# Glfw is probably the most lightweight approach, so let's try that.
|
|
33
|
+
# But there are two incompatible packages providing glfw :/
|
|
34
|
+
self.glfw = None
|
|
35
|
+
try:
|
|
36
|
+
import glfw
|
|
37
|
+
except ImportError:
|
|
38
|
+
pass
|
|
39
|
+
else:
|
|
40
|
+
need_from_glfw = ["create_window", "make_context_current"]
|
|
41
|
+
if all(hasattr(glfw, attr) for attr in need_from_glfw):
|
|
42
|
+
self.glfw = glfw
|
|
43
|
+
|
|
44
|
+
if self.glfw:
|
|
45
|
+
self.glfw.init()
|
|
46
|
+
self.glfw.window_hint(self.glfw.VISIBLE, 0)
|
|
47
|
+
self._canvas = self.glfw.create_window(1, 1, "dummy window", None, None)
|
|
48
|
+
else:
|
|
49
|
+
try:
|
|
50
|
+
_app = Application('default')
|
|
51
|
+
except Exception:
|
|
52
|
+
raise RuntimeError(
|
|
53
|
+
"Cannot find a backend to create an OpenGL context. "
|
|
54
|
+
"Install e.g. PyQt5, PySide2, or `pip install glfw`."
|
|
55
|
+
)
|
|
56
|
+
self._canvas = Canvas(app=_app)
|
|
57
|
+
self._canvas.show(False)
|
|
58
|
+
|
|
59
|
+
def make_current(self):
|
|
60
|
+
""" Make this the currently active context.
|
|
61
|
+
"""
|
|
62
|
+
# If an application only used off-screen canvases this would technically
|
|
63
|
+
# have to be called just once. But note that an application/session
|
|
64
|
+
# could run both real canvases and off-screen ones.
|
|
65
|
+
if self.glfw:
|
|
66
|
+
self.glfw.make_context_current(self._canvas)
|
|
67
|
+
else:
|
|
68
|
+
self._canvas.set_current()
|
|
69
|
+
|
|
70
|
+
def close(self):
|
|
71
|
+
""" Close the context. """
|
|
72
|
+
# Cannot close the global instance
|
|
73
|
+
if self is OffscreenContext._global_instance:
|
|
74
|
+
return
|
|
75
|
+
elif not self._is_closed:
|
|
76
|
+
self._is_closed = True
|
|
77
|
+
if self.glfw:
|
|
78
|
+
self.glfw.destroy_window(self._canvas)
|
|
79
|
+
else:
|
|
80
|
+
self._canvas.close()
|
|
81
|
+
|
|
82
|
+
def __del__(self):
|
|
83
|
+
self.close()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class FrameBufferHelper:
|
|
87
|
+
""" Provides a canvas to render to, using an FBO.
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
def __init__(self):
|
|
91
|
+
self._fbo = None
|
|
92
|
+
self._physical_size = 1, 1
|
|
93
|
+
self._fbo_size = -1, -1
|
|
94
|
+
|
|
95
|
+
def _ensure_fbo(self):
|
|
96
|
+
if self._fbo_size != self._physical_size:
|
|
97
|
+
self._fbo_size = self._physical_size
|
|
98
|
+
w, h = self._fbo_size
|
|
99
|
+
if self._fbo is None:
|
|
100
|
+
color_buffer = gloo.Texture2D((h, w, 4))
|
|
101
|
+
depth_buffer = gloo.RenderBuffer((h, w))
|
|
102
|
+
self._fbo = gloo.FrameBuffer(color_buffer, depth_buffer)
|
|
103
|
+
else:
|
|
104
|
+
self._fbo.resize((h, w))
|
|
105
|
+
|
|
106
|
+
def set_physical_size(self, w, h):
|
|
107
|
+
""" Set the physical size of the canvas.
|
|
108
|
+
"""
|
|
109
|
+
self._physical_size = w, h
|
|
110
|
+
|
|
111
|
+
def get_frame(self):
|
|
112
|
+
""" Call this within the with-context to obtain the frame buffer contents.
|
|
113
|
+
"""
|
|
114
|
+
return self._fbo.read()
|
|
115
|
+
|
|
116
|
+
def __enter__(self):
|
|
117
|
+
self._ensure_fbo()
|
|
118
|
+
return self._fbo.__enter__()
|
|
119
|
+
|
|
120
|
+
def __exit__(self, *args):
|
|
121
|
+
return self._fbo.__exit__(*args)
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# vispy: testskip
|
|
3
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
4
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
5
|
+
"""OSMesa backend for offscreen rendering on Linux/Unix."""
|
|
6
|
+
from __future__ import division
|
|
7
|
+
from ...util.ptime import time
|
|
8
|
+
from ..base import (BaseApplicationBackend, BaseCanvasBackend,
|
|
9
|
+
BaseTimerBackend)
|
|
10
|
+
from ...gloo import gl
|
|
11
|
+
from time import sleep
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from ...ext import osmesa
|
|
15
|
+
except Exception as exp:
|
|
16
|
+
available, testable, why_not, which = False, False, str(exp), None
|
|
17
|
+
else:
|
|
18
|
+
available, testable, why_not, which = True, True, None, 'OSMesa'
|
|
19
|
+
|
|
20
|
+
# -------------------------------------------------------------- capability ---
|
|
21
|
+
capability = dict(
|
|
22
|
+
# if True they mean:
|
|
23
|
+
title=True, # can set title on the fly
|
|
24
|
+
size=True, # can set size on the fly
|
|
25
|
+
position=False, # can set position on the fly
|
|
26
|
+
show=True, # can show/hide window XXX ?
|
|
27
|
+
vsync=False, # can set window to sync to blank
|
|
28
|
+
resizable=False, # can toggle resizability (e.g., no user resizing)
|
|
29
|
+
decorate=True, # can toggle decorations
|
|
30
|
+
fullscreen=False, # fullscreen window support
|
|
31
|
+
context=True, # can share contexts between windows
|
|
32
|
+
multi_window=True, # can use multiple windows at once
|
|
33
|
+
scroll=False, # scroll-wheel events are supported
|
|
34
|
+
parent=False, # can pass native widget backend parent
|
|
35
|
+
always_on_top=False, # can be made always-on-top
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
_VP_OSMESA_ALL_WINDOWS = []
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _get_osmesa_windows():
|
|
43
|
+
return [win for win in _VP_OSMESA_ALL_WINDOWS
|
|
44
|
+
if isinstance(win, CanvasBackend)]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# ------------------------------------------------------------- application ---
|
|
48
|
+
class ApplicationBackend(BaseApplicationBackend):
|
|
49
|
+
|
|
50
|
+
def __init__(self):
|
|
51
|
+
BaseApplicationBackend.__init__(self)
|
|
52
|
+
self._timers = list()
|
|
53
|
+
|
|
54
|
+
def _add_timer(self, timer):
|
|
55
|
+
if timer not in self._timers:
|
|
56
|
+
self._timers.append(timer)
|
|
57
|
+
|
|
58
|
+
def _vispy_get_backend_name(self):
|
|
59
|
+
return 'osmesa'
|
|
60
|
+
|
|
61
|
+
def _vispy_process_events(self):
|
|
62
|
+
for timer in self._timers:
|
|
63
|
+
timer._tick()
|
|
64
|
+
wins = _get_osmesa_windows()
|
|
65
|
+
for win in wins:
|
|
66
|
+
if win._needs_draw:
|
|
67
|
+
win._needs_draw = False
|
|
68
|
+
win._on_draw()
|
|
69
|
+
|
|
70
|
+
def _vispy_run(self):
|
|
71
|
+
wins = _get_osmesa_windows()
|
|
72
|
+
while not all(w.closed for w in wins):
|
|
73
|
+
self._vispy_process_events()
|
|
74
|
+
self._vispy_quit()
|
|
75
|
+
|
|
76
|
+
def _vispy_quit(self):
|
|
77
|
+
wins = _get_osmesa_windows()
|
|
78
|
+
for win in wins:
|
|
79
|
+
win._vispy_close()
|
|
80
|
+
for timer in self._timers:
|
|
81
|
+
timer._vispy_stop()
|
|
82
|
+
self._timers = []
|
|
83
|
+
|
|
84
|
+
def _vispy_get_native_app(self):
|
|
85
|
+
return osmesa
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class OSMesaContext(object):
|
|
89
|
+
"""
|
|
90
|
+
A wrapper around an OSMesa context that destroy the context when
|
|
91
|
+
garbage collected
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
def __init__(self):
|
|
95
|
+
self.context = osmesa.OSMesaCreateContext()
|
|
96
|
+
|
|
97
|
+
def make_current(self, pixels, width, height):
|
|
98
|
+
return osmesa.OSMesaMakeCurrent(self.context, pixels, width, height)
|
|
99
|
+
|
|
100
|
+
def __del__(self):
|
|
101
|
+
osmesa.OSMesaDestroyContext(self.context)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# ------------------------------------------------------------------ canvas ---
|
|
105
|
+
class CanvasBackend(BaseCanvasBackend):
|
|
106
|
+
"""OSMesa backend for Canvas"""
|
|
107
|
+
|
|
108
|
+
def __init__(self, vispy_canvas, **kwargs):
|
|
109
|
+
BaseCanvasBackend.__init__(self, vispy_canvas)
|
|
110
|
+
# We use _process_backend_kwargs() to "serialize" the kwargs
|
|
111
|
+
# and to check whether they match this backend's capability
|
|
112
|
+
p = self._process_backend_kwargs(kwargs)
|
|
113
|
+
|
|
114
|
+
# Deal with config
|
|
115
|
+
# TODO: We do not support setting config
|
|
116
|
+
# ... use context.config
|
|
117
|
+
# Deal with context
|
|
118
|
+
p.context.shared.add_ref('osmesa', self)
|
|
119
|
+
if p.context.shared.ref is self:
|
|
120
|
+
self._native_context = OSMesaContext()
|
|
121
|
+
else:
|
|
122
|
+
self._native_context = p.context.shared.ref._native_context
|
|
123
|
+
|
|
124
|
+
self._closed = False
|
|
125
|
+
self._pixels = None
|
|
126
|
+
self._vispy_set_size(*p.size)
|
|
127
|
+
_VP_OSMESA_ALL_WINDOWS.append(self)
|
|
128
|
+
|
|
129
|
+
self._vispy_canvas.set_current()
|
|
130
|
+
self._vispy_canvas.events.initialize()
|
|
131
|
+
|
|
132
|
+
def _vispy_set_current(self):
|
|
133
|
+
if self._native_context is None:
|
|
134
|
+
raise RuntimeError('Native context is None')
|
|
135
|
+
if self._pixels is None:
|
|
136
|
+
raise RuntimeError('Pixel buffer has already been deleted')
|
|
137
|
+
|
|
138
|
+
ok = self._native_context.make_current(self._pixels, self._size[0],
|
|
139
|
+
self._size[1])
|
|
140
|
+
if not ok:
|
|
141
|
+
raise RuntimeError('Failed attaching OSMesa rendering buffer')
|
|
142
|
+
|
|
143
|
+
def _vispy_swap_buffers(self):
|
|
144
|
+
if self._pixels is None:
|
|
145
|
+
raise RuntimeError('No pixel buffer')
|
|
146
|
+
gl.glFinish()
|
|
147
|
+
|
|
148
|
+
def _vispy_set_title(self, title):
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
def _vispy_set_size(self, w, h):
|
|
152
|
+
self._pixels = osmesa.allocate_pixels_buffer(w, h)
|
|
153
|
+
self._size = (w, h)
|
|
154
|
+
self._vispy_canvas.events.resize(size=(w, h))
|
|
155
|
+
self._vispy_set_current()
|
|
156
|
+
self._vispy_update()
|
|
157
|
+
|
|
158
|
+
def _vispy_set_position(self, x, y):
|
|
159
|
+
pass
|
|
160
|
+
|
|
161
|
+
def _vispy_set_visible(self, visible):
|
|
162
|
+
if visible:
|
|
163
|
+
self._vispy_set_current()
|
|
164
|
+
self._vispy_update()
|
|
165
|
+
|
|
166
|
+
def _vispy_set_fullscreen(self, fullscreen):
|
|
167
|
+
pass
|
|
168
|
+
|
|
169
|
+
def _vispy_update(self):
|
|
170
|
+
# This is checked by osmesa ApplicationBackend in process_events
|
|
171
|
+
self._needs_draw = True
|
|
172
|
+
|
|
173
|
+
def _vispy_close(self):
|
|
174
|
+
if self.closed:
|
|
175
|
+
return
|
|
176
|
+
# We do not set self._native_context = None here because this causes
|
|
177
|
+
# trouble in case a canvas is closed multiple times (as in
|
|
178
|
+
# app.test_run()). The problem occurs in gloo's glir._gl_initialize
|
|
179
|
+
# when it tries to call glGetString(GL_VERSION).
|
|
180
|
+
# But OSMesa requires a context to be attached when calling
|
|
181
|
+
# glGetString otherwise it returns an empty string, which gloo doesn't
|
|
182
|
+
# like
|
|
183
|
+
self._closed = True
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
def _vispy_warmup(self):
|
|
187
|
+
etime = time() + 0.1
|
|
188
|
+
while time() < etime:
|
|
189
|
+
sleep(0.01)
|
|
190
|
+
self._vispy_canvas.set_current()
|
|
191
|
+
self._vispy_canvas.app.process_events()
|
|
192
|
+
|
|
193
|
+
def _vispy_get_size(self):
|
|
194
|
+
if self._pixels is None:
|
|
195
|
+
return
|
|
196
|
+
return self._size
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def closed(self):
|
|
200
|
+
return self._closed
|
|
201
|
+
|
|
202
|
+
def _vispy_get_position(self):
|
|
203
|
+
return 0, 0
|
|
204
|
+
|
|
205
|
+
def _vispy_get_fullscreen(self):
|
|
206
|
+
return False
|
|
207
|
+
|
|
208
|
+
def _on_draw(self):
|
|
209
|
+
# This is called by the osmesa ApplicationBackend
|
|
210
|
+
if self._vispy_canvas is None or self._pixels is None:
|
|
211
|
+
raise RuntimeError('draw with no canvas or pixels attached')
|
|
212
|
+
return
|
|
213
|
+
self._vispy_set_current()
|
|
214
|
+
self._vispy_canvas.events.draw(region=None) # (0, 0, w, h)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# ------------------------------------------------------------------- timer ---
|
|
218
|
+
class TimerBackend(BaseTimerBackend):
|
|
219
|
+
|
|
220
|
+
def __init__(self, vispy_timer):
|
|
221
|
+
BaseTimerBackend.__init__(self, vispy_timer)
|
|
222
|
+
vispy_timer._app._backend._add_timer(self)
|
|
223
|
+
self._vispy_stop()
|
|
224
|
+
|
|
225
|
+
def _vispy_start(self, interval):
|
|
226
|
+
self._interval = interval
|
|
227
|
+
self._next_time = time() + self._interval
|
|
228
|
+
|
|
229
|
+
def _vispy_stop(self):
|
|
230
|
+
self._next_time = float('inf')
|
|
231
|
+
|
|
232
|
+
def _tick(self):
|
|
233
|
+
if time() > self._next_time:
|
|
234
|
+
self._vispy_timer._timeout()
|
|
235
|
+
self._next_time = time() + self._interval
|