vispy 0.15.0__cp313-cp313-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.
- 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-darwin.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,788 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) Vispy Development Team. All Rights Reserved.
|
|
3
|
+
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
|
|
4
|
+
"""
|
|
5
|
+
Classses representing GLSL objects (functions, variables, etc) that may be
|
|
6
|
+
composed together to create complete shaders.
|
|
7
|
+
See the docstring of Function for details.
|
|
8
|
+
|
|
9
|
+
Details
|
|
10
|
+
-------
|
|
11
|
+
|
|
12
|
+
A complete GLSL program is composed of ShaderObjects, each of which may be used
|
|
13
|
+
inline as an expression, and some of which include a definition that must be
|
|
14
|
+
included on the final code. ShaderObjects keep track of a hierarchy of
|
|
15
|
+
dependencies so that all necessary code is included at compile time, and
|
|
16
|
+
changes made to any object may be propagated to the root of the hierarchy to
|
|
17
|
+
trigger a recompile.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from collections import OrderedDict
|
|
21
|
+
import logging
|
|
22
|
+
import re
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
|
|
26
|
+
from ...util.eq import eq
|
|
27
|
+
from ...util import logger
|
|
28
|
+
from . import parsing
|
|
29
|
+
from .shader_object import ShaderObject
|
|
30
|
+
from .variable import Variable, Varying
|
|
31
|
+
from .expression import TextExpression, FunctionCall
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Function(ShaderObject):
|
|
35
|
+
"""Representation of a GLSL function
|
|
36
|
+
|
|
37
|
+
Objects of this class can be used for re-using and composing GLSL
|
|
38
|
+
snippets. Each Function consists of a GLSL snippet in the form of
|
|
39
|
+
a function. The code may have template variables that start with
|
|
40
|
+
the dollar sign. These stubs can be replaced with expressions using
|
|
41
|
+
the index operation. Expressions can be:
|
|
42
|
+
|
|
43
|
+
* plain text that is inserted verbatim in the code
|
|
44
|
+
* a Function object or a call to a funcion
|
|
45
|
+
* a Variable (or Varying) object
|
|
46
|
+
* float, int, tuple are automatically turned into a uniform Variable
|
|
47
|
+
* a VertexBuffer is automatically turned into an attribute Variable
|
|
48
|
+
|
|
49
|
+
All functions have implicit "$pre" and "$post" placeholders that may be
|
|
50
|
+
used to insert code at the beginning and end of the function.
|
|
51
|
+
|
|
52
|
+
Examples
|
|
53
|
+
--------
|
|
54
|
+
This example shows the basic usage of the Function class::
|
|
55
|
+
|
|
56
|
+
vert_code_template = Function('''
|
|
57
|
+
void main() {
|
|
58
|
+
gl_Position = $pos;
|
|
59
|
+
gl_Position.x += $xoffset;
|
|
60
|
+
gl_Position.y += $yoffset;
|
|
61
|
+
}''')
|
|
62
|
+
|
|
63
|
+
scale_transform = Function('''
|
|
64
|
+
vec4 transform_scale(vec4 pos){
|
|
65
|
+
return pos * $scale;
|
|
66
|
+
}''')
|
|
67
|
+
|
|
68
|
+
# If you get the function from a snippet collection, always
|
|
69
|
+
# create new Function objects to ensure they are 'fresh'.
|
|
70
|
+
vert_code = Function(vert_code_template)
|
|
71
|
+
trans1 = Function(scale_transform)
|
|
72
|
+
trans2 = Function(scale_transform) # trans2 != trans1
|
|
73
|
+
|
|
74
|
+
# Three ways to assign to template variables:
|
|
75
|
+
#
|
|
76
|
+
# 1) Assign verbatim code
|
|
77
|
+
vert_code['xoffset'] = '(3.0 / 3.1415)'
|
|
78
|
+
|
|
79
|
+
# 2) Assign a value (this creates a new uniform or attribute)
|
|
80
|
+
vert_code['yoffset'] = 5.0
|
|
81
|
+
|
|
82
|
+
# 3) Assign a function call expression
|
|
83
|
+
pos_var = Variable('attribute vec4 a_position')
|
|
84
|
+
vert_code['pos'] = trans1(trans2(pos_var))
|
|
85
|
+
|
|
86
|
+
# Transforms also need their variables set
|
|
87
|
+
trans1['scale'] = 0.5
|
|
88
|
+
trans2['scale'] = (1.0, 0.5, 1.0, 1.0)
|
|
89
|
+
|
|
90
|
+
# You can actually change any code you want, but use this with care!
|
|
91
|
+
vert_code.replace('gl_Position.y', 'gl_Position.z')
|
|
92
|
+
|
|
93
|
+
# Finally, you can set special variables explicitly. This generates
|
|
94
|
+
# a new statement at the end of the vert_code function.
|
|
95
|
+
vert_code['gl_PointSize'] = '10.'
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
If we use ``vert_code.compile()`` we get::
|
|
99
|
+
|
|
100
|
+
attribute vec4 a_position;
|
|
101
|
+
uniform float u_yoffset;
|
|
102
|
+
uniform float u_scale_1;
|
|
103
|
+
uniform vec4 u_scale_2;
|
|
104
|
+
uniform float u_pointsize;
|
|
105
|
+
|
|
106
|
+
vec4 transform_scale_1(vec4 pos){
|
|
107
|
+
return pos * u_scale_1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
vec4 transform_scale_2(vec4 pos){
|
|
111
|
+
return pos * u_scale_2;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
void main() {
|
|
115
|
+
gl_Position = transform_scale_1(transform_scale_2(a_position));
|
|
116
|
+
gl_Position.x += (3.0 / 3.1415);
|
|
117
|
+
gl_Position.z += u_yoffset;
|
|
118
|
+
|
|
119
|
+
gl_PointSize = u_pointsize;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
Note how the two scale function resulted in two different functions
|
|
123
|
+
and two uniforms for the scale factors.
|
|
124
|
+
|
|
125
|
+
Notes
|
|
126
|
+
-----
|
|
127
|
+
|
|
128
|
+
Function calls:
|
|
129
|
+
|
|
130
|
+
As can be seen above, the arguments with which a function is to be
|
|
131
|
+
called must be specified by calling the Function object. The
|
|
132
|
+
arguments can be any of the expressions mentioned earlier. If the
|
|
133
|
+
signature is already specified in the template code, that function
|
|
134
|
+
itself must be given.
|
|
135
|
+
|
|
136
|
+
::
|
|
137
|
+
|
|
138
|
+
code = Function('''
|
|
139
|
+
void main() {
|
|
140
|
+
vec4 position = $pos;
|
|
141
|
+
gl_Position = $scale(position)
|
|
142
|
+
}
|
|
143
|
+
''')
|
|
144
|
+
|
|
145
|
+
# Example of a function call with all possible three expressions
|
|
146
|
+
vert_code['pos'] = func1('3.0', 'uniform float u_param', func2())
|
|
147
|
+
|
|
148
|
+
# For scale, the sigfnature is already specified
|
|
149
|
+
code['scale'] = scale_func # Must not specify args
|
|
150
|
+
|
|
151
|
+
Data for uniform and attribute variables:
|
|
152
|
+
|
|
153
|
+
To each variable a value can be associated. In fact, in most cases
|
|
154
|
+
the Function class is smart enough to be able to create a Variable
|
|
155
|
+
object if only the data is given.
|
|
156
|
+
|
|
157
|
+
::
|
|
158
|
+
|
|
159
|
+
code['offset'] = Variable('uniform float offset') # No data
|
|
160
|
+
code['offset'] = Variable('uniform float offset', 3.0) # With data
|
|
161
|
+
code['offset'] = 3.0 # -> Uniform Variable
|
|
162
|
+
position['position'] = VertexBuffer() # -> attribute Variable
|
|
163
|
+
|
|
164
|
+
# Updating variables
|
|
165
|
+
code['offset'].value = 4.0
|
|
166
|
+
position['position'].value.set_data(...)
|
|
167
|
+
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
def __init__(self, code, dependencies=None):
|
|
171
|
+
super(Function, self).__init__()
|
|
172
|
+
|
|
173
|
+
# Add depencencies is given. This is to allow people to
|
|
174
|
+
# manually define deps for a function that they use.
|
|
175
|
+
if dependencies is not None:
|
|
176
|
+
for dep in dependencies:
|
|
177
|
+
self._add_dep(dep)
|
|
178
|
+
|
|
179
|
+
self.code = code
|
|
180
|
+
|
|
181
|
+
# Expressions replace template variables (also our dependencies)
|
|
182
|
+
self._expressions = OrderedDict()
|
|
183
|
+
|
|
184
|
+
# Verbatim string replacements
|
|
185
|
+
self._replacements = OrderedDict()
|
|
186
|
+
|
|
187
|
+
# Stuff to do at the end
|
|
188
|
+
self._assignments = OrderedDict()
|
|
189
|
+
|
|
190
|
+
def __setitem__(self, key, val):
|
|
191
|
+
"""Setting of replacements through a dict-like syntax.
|
|
192
|
+
|
|
193
|
+
Each replacement can be:
|
|
194
|
+
* verbatim code: ``fun1['foo'] = '3.14159'``
|
|
195
|
+
* a FunctionCall: ``fun1['foo'] = fun2()``
|
|
196
|
+
* a Variable: ``fun1['foo'] = Variable(...)`` (can be auto-generated)
|
|
197
|
+
"""
|
|
198
|
+
# Check the key. Must be Varying, 'gl_X' or a known template variable
|
|
199
|
+
if isinstance(key, Variable):
|
|
200
|
+
if key.vtype == 'varying':
|
|
201
|
+
if self.name != 'main':
|
|
202
|
+
raise Exception("Varying assignment only alowed in 'main' "
|
|
203
|
+
"function.")
|
|
204
|
+
storage = self._assignments
|
|
205
|
+
else:
|
|
206
|
+
raise TypeError("Variable assignment only allowed for "
|
|
207
|
+
"varyings, not %s (in %s)"
|
|
208
|
+
% (key.vtype, self.name))
|
|
209
|
+
elif isinstance(key, str):
|
|
210
|
+
if any(map(key.startswith,
|
|
211
|
+
('gl_PointSize', 'gl_Position', 'gl_FragColor'))):
|
|
212
|
+
storage = self._assignments
|
|
213
|
+
elif key in self.template_vars or key in ('pre', 'post'):
|
|
214
|
+
storage = self._expressions
|
|
215
|
+
else:
|
|
216
|
+
raise KeyError('Invalid template variable %r' % key)
|
|
217
|
+
else:
|
|
218
|
+
raise TypeError('In `function[key]` key must be a string or '
|
|
219
|
+
'varying.')
|
|
220
|
+
|
|
221
|
+
# If values already match, bail out now
|
|
222
|
+
if eq(storage.get(key), val):
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
# If we are only changing the value (and not the dtype) of a uniform,
|
|
226
|
+
# we can set that value and return immediately to avoid triggering a
|
|
227
|
+
# recompile.
|
|
228
|
+
if val is not None and not isinstance(val, Variable):
|
|
229
|
+
# We are setting a value. If there is already a variable set here,
|
|
230
|
+
# try just updating its value.
|
|
231
|
+
variable = storage.get(key, None)
|
|
232
|
+
if isinstance(variable, Variable):
|
|
233
|
+
if np.any(variable.value != val):
|
|
234
|
+
variable.value = val
|
|
235
|
+
self.changed(value_changed=True)
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
# Could not set variable.value directly; instead we will need
|
|
239
|
+
# to create a new ShaderObject
|
|
240
|
+
val = ShaderObject.create(val, ref=key)
|
|
241
|
+
if variable is val:
|
|
242
|
+
# This can happen if ShaderObject.create returns the same
|
|
243
|
+
# object (such as when setting a Transform).
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
# Remove old references, if any
|
|
247
|
+
oldval = storage.pop(key, None)
|
|
248
|
+
if oldval is not None:
|
|
249
|
+
for obj in (key, oldval):
|
|
250
|
+
if isinstance(obj, ShaderObject):
|
|
251
|
+
self._remove_dep(obj)
|
|
252
|
+
|
|
253
|
+
# Add new references
|
|
254
|
+
if val is not None:
|
|
255
|
+
if isinstance(key, Varying):
|
|
256
|
+
# tell this varying to inherit properties from
|
|
257
|
+
# its source attribute / expression.
|
|
258
|
+
key.link(val)
|
|
259
|
+
|
|
260
|
+
# Store value and dependencies
|
|
261
|
+
storage[key] = val
|
|
262
|
+
for obj in (key, val):
|
|
263
|
+
if isinstance(obj, ShaderObject):
|
|
264
|
+
self._add_dep(obj)
|
|
265
|
+
|
|
266
|
+
# In case of verbatim text, we might have added new template vars
|
|
267
|
+
if isinstance(val, TextExpression):
|
|
268
|
+
for var in parsing.find_template_variables(val.expression()):
|
|
269
|
+
if var not in self.template_vars:
|
|
270
|
+
self.template_vars.add(var.lstrip('$'))
|
|
271
|
+
|
|
272
|
+
self.changed(code_changed=True, value_changed=True)
|
|
273
|
+
if logger.level <= logging.DEBUG:
|
|
274
|
+
import traceback
|
|
275
|
+
last = traceback.format_list(traceback.extract_stack()[-2:-1])
|
|
276
|
+
logger.debug("Assignment would trigger shader recompile:\n"
|
|
277
|
+
"Original: %r\nReplacement: %r\nSource: %s",
|
|
278
|
+
oldval, val, ''.join(last))
|
|
279
|
+
|
|
280
|
+
def __getitem__(self, key):
|
|
281
|
+
"""Return a reference to a program variable from this function.
|
|
282
|
+
|
|
283
|
+
This allows variables between functions to be linked together::
|
|
284
|
+
|
|
285
|
+
func1['var_name'] = func2['other_var_name']
|
|
286
|
+
|
|
287
|
+
In the example above, the two local variables would be assigned to the
|
|
288
|
+
same program variable whenever func1 and func2 are attached to the same
|
|
289
|
+
program.
|
|
290
|
+
"""
|
|
291
|
+
try:
|
|
292
|
+
return self._expressions[key]
|
|
293
|
+
except KeyError:
|
|
294
|
+
pass
|
|
295
|
+
|
|
296
|
+
try:
|
|
297
|
+
return self._assignments[key]
|
|
298
|
+
except KeyError:
|
|
299
|
+
pass
|
|
300
|
+
|
|
301
|
+
if key not in self.template_vars:
|
|
302
|
+
raise KeyError('Invalid template variable %r' % key)
|
|
303
|
+
else:
|
|
304
|
+
raise KeyError('No value known for key %r' % key)
|
|
305
|
+
|
|
306
|
+
def __call__(self, *args):
|
|
307
|
+
"""Set the signature for this function and return an FunctionCall
|
|
308
|
+
object. Each argument can be verbatim code or a FunctionCall object.
|
|
309
|
+
"""
|
|
310
|
+
return FunctionCall(self, args)
|
|
311
|
+
|
|
312
|
+
def __contains__(self, key):
|
|
313
|
+
return key in self.template_vars
|
|
314
|
+
|
|
315
|
+
# Public API methods
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def signature(self):
|
|
319
|
+
if self._signature is None:
|
|
320
|
+
try:
|
|
321
|
+
self._signature = parsing.parse_function_signature(self._code)
|
|
322
|
+
except Exception as err:
|
|
323
|
+
raise ValueError('Invalid code: ' + str(err))
|
|
324
|
+
return self._signature
|
|
325
|
+
|
|
326
|
+
@property
|
|
327
|
+
def name(self):
|
|
328
|
+
"""The function name. The name may be mangled in the final code
|
|
329
|
+
to avoid name clashes.
|
|
330
|
+
"""
|
|
331
|
+
return self.signature[0]
|
|
332
|
+
|
|
333
|
+
@property
|
|
334
|
+
def args(self):
|
|
335
|
+
"""
|
|
336
|
+
List of input arguments in the function signature::
|
|
337
|
+
[(arg_name, arg_type), ...]
|
|
338
|
+
"""
|
|
339
|
+
return self.signature[1]
|
|
340
|
+
|
|
341
|
+
@property
|
|
342
|
+
def rtype(self):
|
|
343
|
+
"""The return type of this function."""
|
|
344
|
+
return self.signature[2]
|
|
345
|
+
|
|
346
|
+
@property
|
|
347
|
+
def code(self):
|
|
348
|
+
"""The template code used to generate the definition for this function."""
|
|
349
|
+
return self._code
|
|
350
|
+
|
|
351
|
+
@code.setter
|
|
352
|
+
def code(self, code):
|
|
353
|
+
# Get and strip code
|
|
354
|
+
if isinstance(code, Function):
|
|
355
|
+
code = code._code
|
|
356
|
+
elif not isinstance(code, str):
|
|
357
|
+
raise ValueError('Function needs a string or Function; got %s.' %
|
|
358
|
+
type(code))
|
|
359
|
+
self._code = self._clean_code(code)
|
|
360
|
+
|
|
361
|
+
# (name, args, rval)
|
|
362
|
+
self._signature = None
|
|
363
|
+
|
|
364
|
+
# $placeholders parsed from the code
|
|
365
|
+
self._template_vars = None
|
|
366
|
+
|
|
367
|
+
# Create static Variable instances for any global variables declared
|
|
368
|
+
# in the code
|
|
369
|
+
self._static_vars = None
|
|
370
|
+
|
|
371
|
+
@property
|
|
372
|
+
def template_vars(self):
|
|
373
|
+
if self._template_vars is None:
|
|
374
|
+
self._template_vars = self._parse_template_vars()
|
|
375
|
+
return self._template_vars
|
|
376
|
+
|
|
377
|
+
def static_names(self):
|
|
378
|
+
if self._static_vars is None:
|
|
379
|
+
self._static_vars = parsing.find_program_variables(self._code)
|
|
380
|
+
return list(self._static_vars.keys()) + [arg[0] for arg in self.args]
|
|
381
|
+
|
|
382
|
+
def replace(self, str1, str2):
|
|
383
|
+
"""Set verbatim code replacement
|
|
384
|
+
|
|
385
|
+
It is strongly recommended to use function['$foo'] = 'bar' where
|
|
386
|
+
possible because template variables are less likely to changed
|
|
387
|
+
than the code itself in future versions of vispy.
|
|
388
|
+
|
|
389
|
+
Parameters
|
|
390
|
+
----------
|
|
391
|
+
str1 : str
|
|
392
|
+
String to replace
|
|
393
|
+
str2 : str
|
|
394
|
+
String to replace str1 with
|
|
395
|
+
"""
|
|
396
|
+
if str2 != self._replacements.get(str1, None):
|
|
397
|
+
self._replacements[str1] = str2
|
|
398
|
+
self.changed(code_changed=True)
|
|
399
|
+
# self._last_changed = time.time()
|
|
400
|
+
|
|
401
|
+
# Private methods
|
|
402
|
+
|
|
403
|
+
def _parse_template_vars(self):
|
|
404
|
+
"""Find all template variables in self._code, excluding the function name."""
|
|
405
|
+
template_vars = set()
|
|
406
|
+
for var in parsing.find_template_variables(self._code):
|
|
407
|
+
var = var.lstrip('$')
|
|
408
|
+
if var == self.name:
|
|
409
|
+
continue
|
|
410
|
+
if var in ('pre', 'post'):
|
|
411
|
+
raise ValueError('GLSL uses reserved template variable $%s' %
|
|
412
|
+
var)
|
|
413
|
+
template_vars.add(var)
|
|
414
|
+
return template_vars
|
|
415
|
+
|
|
416
|
+
def _get_replaced_code(self, names, version, shader):
|
|
417
|
+
"""Return code, with new name, expressions, and replacements applied."""
|
|
418
|
+
code = self._code
|
|
419
|
+
|
|
420
|
+
# Modify name
|
|
421
|
+
fname = names[self]
|
|
422
|
+
code = code.replace(" " + self.name + "(", " " + fname + "(")
|
|
423
|
+
|
|
424
|
+
# Apply string replacements first -- these may contain $placeholders
|
|
425
|
+
for key, val in self._replacements.items():
|
|
426
|
+
code = code.replace(key, val)
|
|
427
|
+
|
|
428
|
+
# Apply assignments to the end of the function
|
|
429
|
+
|
|
430
|
+
# Collect post lines
|
|
431
|
+
post_lines = []
|
|
432
|
+
for key, val in self._assignments.items():
|
|
433
|
+
if isinstance(key, Variable):
|
|
434
|
+
key = names[key]
|
|
435
|
+
if isinstance(val, ShaderObject):
|
|
436
|
+
val = val.expression(names)
|
|
437
|
+
line = ' %s = %s;' % (key, val)
|
|
438
|
+
post_lines.append(line)
|
|
439
|
+
|
|
440
|
+
# Add a default $post placeholder if needed
|
|
441
|
+
if 'post' in self._expressions:
|
|
442
|
+
post_lines.append(' $post')
|
|
443
|
+
|
|
444
|
+
# Apply placeholders for hooks
|
|
445
|
+
post_text = '\n'.join(post_lines)
|
|
446
|
+
if post_text:
|
|
447
|
+
post_text = '\n' + post_text + '\n'
|
|
448
|
+
code = code.rpartition('}')
|
|
449
|
+
code = code[0] + post_text + code[1] + code[2]
|
|
450
|
+
|
|
451
|
+
# Add a default $pre placeholder if needed
|
|
452
|
+
if 'pre' in self._expressions:
|
|
453
|
+
m = re.search(fname + r'\s*\([^{]*\)\s*{', code)
|
|
454
|
+
if m is None:
|
|
455
|
+
raise RuntimeError("Cound not find beginning of function '%s'"
|
|
456
|
+
% fname)
|
|
457
|
+
ind = m.span()[1]
|
|
458
|
+
code = code[:ind] + "\n $pre\n" + code[ind:]
|
|
459
|
+
|
|
460
|
+
# Apply template variables
|
|
461
|
+
for key, val in self._expressions.items():
|
|
462
|
+
val = val.expression(names)
|
|
463
|
+
search = r'\$' + key + r'($|[^a-zA-Z0-9_])'
|
|
464
|
+
code = re.sub(search, val+r'\1', code)
|
|
465
|
+
|
|
466
|
+
# Done
|
|
467
|
+
if '$' in code:
|
|
468
|
+
v = parsing.find_template_variables(code)
|
|
469
|
+
logger.warning('Unsubstituted placeholders in code: %s\n'
|
|
470
|
+
' replacements made: %s',
|
|
471
|
+
v, list(self._expressions.keys()))
|
|
472
|
+
|
|
473
|
+
return code + '\n'
|
|
474
|
+
|
|
475
|
+
def definition(self, names, version, shader):
|
|
476
|
+
return self._get_replaced_code(names, version, shader)
|
|
477
|
+
|
|
478
|
+
def expression(self, names):
|
|
479
|
+
return names[self]
|
|
480
|
+
|
|
481
|
+
def _clean_code(self, code):
|
|
482
|
+
"""Return *code* with indentation and leading/trailing blank lines removed."""
|
|
483
|
+
lines = code.split("\n")
|
|
484
|
+
min_indent = 100
|
|
485
|
+
for line in lines:
|
|
486
|
+
if line.strip() != "":
|
|
487
|
+
indent = len(line) - len(line.lstrip())
|
|
488
|
+
min_indent = min(indent, min_indent)
|
|
489
|
+
if min_indent > 0:
|
|
490
|
+
lines = [line[min_indent:] for line in lines]
|
|
491
|
+
code = "\n".join(lines)
|
|
492
|
+
return code
|
|
493
|
+
|
|
494
|
+
def __repr__(self):
|
|
495
|
+
try:
|
|
496
|
+
args = ', '.join([' '.join(arg) for arg in self.args])
|
|
497
|
+
except Exception:
|
|
498
|
+
return ('<%s (error parsing signature) at 0x%x>' %
|
|
499
|
+
(self.__class__.__name__, id(self)))
|
|
500
|
+
return '<%s "%s %s(%s)" at 0x%x>' % (self.__class__.__name__,
|
|
501
|
+
self.rtype,
|
|
502
|
+
self.name,
|
|
503
|
+
args,
|
|
504
|
+
id(self))
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
class MainFunction(Function):
|
|
508
|
+
"""Subclass of Function that allows multiple functions and variables to
|
|
509
|
+
be defined in a single code string. The code must contain a main() function
|
|
510
|
+
definition.
|
|
511
|
+
"""
|
|
512
|
+
|
|
513
|
+
def __init__(self, shader_type, *args, **kwargs):
|
|
514
|
+
self.shader_type = shader_type
|
|
515
|
+
self._chains = {}
|
|
516
|
+
Function.__init__(self, *args, **kwargs)
|
|
517
|
+
|
|
518
|
+
@property
|
|
519
|
+
def signature(self):
|
|
520
|
+
return ('main', [], 'void')
|
|
521
|
+
|
|
522
|
+
@property
|
|
523
|
+
def version_pragma(self):
|
|
524
|
+
"""Return version number and extra qualifiers from pragma if present."""
|
|
525
|
+
m = re.search(parsing.re_version_pragma, self.code)
|
|
526
|
+
if m is None:
|
|
527
|
+
return None
|
|
528
|
+
return int(m.group(1)), m.group(2)
|
|
529
|
+
|
|
530
|
+
def definition(self, obj_names, version, shader):
|
|
531
|
+
code = Function.definition(self, obj_names, version, shader)
|
|
532
|
+
# strip out version pragma before returning code; this will be
|
|
533
|
+
# added to the final compiled code later.
|
|
534
|
+
code = re.sub(parsing.re_version_pragma, '', code)
|
|
535
|
+
return code
|
|
536
|
+
|
|
537
|
+
def static_names(self):
|
|
538
|
+
if self._static_vars is not None:
|
|
539
|
+
return self._static_vars
|
|
540
|
+
|
|
541
|
+
# parse static variables
|
|
542
|
+
names = Function.static_names(self)
|
|
543
|
+
|
|
544
|
+
# parse all function names + argument names
|
|
545
|
+
funcs = parsing.find_functions(self.code)
|
|
546
|
+
for f in funcs:
|
|
547
|
+
if f[0] == 'main':
|
|
548
|
+
continue
|
|
549
|
+
names.append(f[0])
|
|
550
|
+
for arg in f[1]:
|
|
551
|
+
names.append(arg[1])
|
|
552
|
+
|
|
553
|
+
self._static_vars = names
|
|
554
|
+
return names
|
|
555
|
+
|
|
556
|
+
def add_chain(self, var):
|
|
557
|
+
"""Create a new ChainFunction and attach to $var."""
|
|
558
|
+
chain = FunctionChain(var, [])
|
|
559
|
+
self._chains[var] = chain
|
|
560
|
+
self[var] = chain
|
|
561
|
+
|
|
562
|
+
def add_callback(self, hook, func):
|
|
563
|
+
self._chains[hook].append(func)
|
|
564
|
+
|
|
565
|
+
def remove_callback(self, hook, func):
|
|
566
|
+
self._chains[hook].remove(func)
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class FunctionChain(Function):
|
|
570
|
+
"""Subclass that generates GLSL code to call Function list in order
|
|
571
|
+
|
|
572
|
+
Functions may be called independently, or composed such that the
|
|
573
|
+
output of each function provides the input to the next.
|
|
574
|
+
|
|
575
|
+
Parameters
|
|
576
|
+
----------
|
|
577
|
+
name : str
|
|
578
|
+
The name of the generated function
|
|
579
|
+
funcs : list of Functions
|
|
580
|
+
The list of Functions that will be called by the generated GLSL code.
|
|
581
|
+
|
|
582
|
+
Examples
|
|
583
|
+
--------
|
|
584
|
+
This creates a function chain::
|
|
585
|
+
|
|
586
|
+
>>> func1 = Function('void my_func_1() {}')
|
|
587
|
+
>>> func2 = Function('void my_func_2() {}')
|
|
588
|
+
>>> chain = FunctionChain('my_func_chain', [func1, func2])
|
|
589
|
+
|
|
590
|
+
If *chain* is included in a ModularProgram, it will generate the following
|
|
591
|
+
output::
|
|
592
|
+
|
|
593
|
+
void my_func_1() {}
|
|
594
|
+
void my_func_2() {}
|
|
595
|
+
|
|
596
|
+
void my_func_chain() {
|
|
597
|
+
my_func_1();
|
|
598
|
+
my_func_2();
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
The return type of the generated function is the same as the return type
|
|
602
|
+
of the last function in the chain. Likewise, the arguments for the
|
|
603
|
+
generated function are the same as the first function in the chain.
|
|
604
|
+
|
|
605
|
+
If the return type is not 'void', then the return value of each function
|
|
606
|
+
will be used to supply the first input argument of the next function in
|
|
607
|
+
the chain. For example::
|
|
608
|
+
|
|
609
|
+
vec3 my_func_1(vec3 input) {return input + vec3(1, 0, 0);}
|
|
610
|
+
void my_func_2(vec3 input) {return input + vec3(0, 1, 0);}
|
|
611
|
+
|
|
612
|
+
vec3 my_func_chain(vec3 input) {
|
|
613
|
+
return my_func_2(my_func_1(input));
|
|
614
|
+
}
|
|
615
|
+
"""
|
|
616
|
+
|
|
617
|
+
def __init__(self, name=None, funcs=()):
|
|
618
|
+
# bypass Function.__init__ completely.
|
|
619
|
+
ShaderObject.__init__(self)
|
|
620
|
+
if not (name is None or isinstance(name, str)):
|
|
621
|
+
raise TypeError("Name argument must be string or None.")
|
|
622
|
+
self._funcs = []
|
|
623
|
+
self._code = None
|
|
624
|
+
self._name = name or "chain"
|
|
625
|
+
self._args = []
|
|
626
|
+
self._rtype = 'void'
|
|
627
|
+
self.functions = funcs
|
|
628
|
+
|
|
629
|
+
@property
|
|
630
|
+
def functions(self):
|
|
631
|
+
return self._funcs[:]
|
|
632
|
+
|
|
633
|
+
@functions.setter
|
|
634
|
+
def functions(self, funcs):
|
|
635
|
+
while self._funcs:
|
|
636
|
+
self.remove(self._funcs[0], update=False)
|
|
637
|
+
for f in funcs:
|
|
638
|
+
self.append(f, update=False)
|
|
639
|
+
self._update()
|
|
640
|
+
|
|
641
|
+
@property
|
|
642
|
+
def signature(self):
|
|
643
|
+
return self._name, self._args, self._rtype
|
|
644
|
+
|
|
645
|
+
def _update(self):
|
|
646
|
+
funcs = self._funcs
|
|
647
|
+
if len(funcs) > 0:
|
|
648
|
+
self._rtype = funcs[-1].rtype
|
|
649
|
+
self._args = funcs[0].args[:]
|
|
650
|
+
else:
|
|
651
|
+
self._rtype = 'void'
|
|
652
|
+
self._args = []
|
|
653
|
+
|
|
654
|
+
self.changed(code_changed=True)
|
|
655
|
+
|
|
656
|
+
@property
|
|
657
|
+
def code(self):
|
|
658
|
+
# Code is generated at compile time; hopefully it is not requested
|
|
659
|
+
# before then..
|
|
660
|
+
return None
|
|
661
|
+
|
|
662
|
+
@code.setter
|
|
663
|
+
def code(self, c):
|
|
664
|
+
raise TypeError("Cannot set code property on FunctionChain.")
|
|
665
|
+
|
|
666
|
+
@property
|
|
667
|
+
def template_vars(self):
|
|
668
|
+
return {}
|
|
669
|
+
|
|
670
|
+
def append(self, function, update=True):
|
|
671
|
+
"""Append a new function to the end of this chain."""
|
|
672
|
+
self._funcs.append(function)
|
|
673
|
+
self._add_dep(function)
|
|
674
|
+
if update:
|
|
675
|
+
self._update()
|
|
676
|
+
|
|
677
|
+
def __setitem__(self, index, func):
|
|
678
|
+
self._remove_dep(self._funcs[index])
|
|
679
|
+
self._add_dep(func)
|
|
680
|
+
self._funcs[index] = func
|
|
681
|
+
|
|
682
|
+
self._update()
|
|
683
|
+
|
|
684
|
+
def __getitem__(self, k):
|
|
685
|
+
return self.functions[k]
|
|
686
|
+
|
|
687
|
+
def insert(self, index, function, update=True):
|
|
688
|
+
"""Insert a new function into the chain at *index*."""
|
|
689
|
+
self._funcs.insert(index, function)
|
|
690
|
+
self._add_dep(function)
|
|
691
|
+
if update:
|
|
692
|
+
self._update()
|
|
693
|
+
|
|
694
|
+
def remove(self, function, update=True):
|
|
695
|
+
"""Remove a function from the chain."""
|
|
696
|
+
self._funcs.remove(function)
|
|
697
|
+
self._remove_dep(function)
|
|
698
|
+
if update:
|
|
699
|
+
self._update()
|
|
700
|
+
|
|
701
|
+
def definition(self, obj_names, version, shader):
|
|
702
|
+
name = obj_names[self]
|
|
703
|
+
|
|
704
|
+
args = ", ".join(["%s %s" % arg for arg in self.args])
|
|
705
|
+
code = "%s %s(%s) {\n" % (self.rtype, name, args)
|
|
706
|
+
|
|
707
|
+
result_index = 0
|
|
708
|
+
if len(self.args) == 0:
|
|
709
|
+
last_rtype = 'void'
|
|
710
|
+
last_result = ''
|
|
711
|
+
else:
|
|
712
|
+
last_rtype, last_result = self.args[0][:2]
|
|
713
|
+
|
|
714
|
+
for fn in self._funcs:
|
|
715
|
+
# Use previous return value as an argument to the next function
|
|
716
|
+
if last_rtype == 'void':
|
|
717
|
+
args = ''
|
|
718
|
+
else:
|
|
719
|
+
args = last_result
|
|
720
|
+
if len(fn.args) != 1 or last_rtype != fn.args[0][0]:
|
|
721
|
+
raise Exception("Cannot chain output '%s' of function to "
|
|
722
|
+
"input of '%s'" %
|
|
723
|
+
(last_rtype, fn.signature))
|
|
724
|
+
last_rtype = fn.rtype
|
|
725
|
+
|
|
726
|
+
# Store the return value of this function
|
|
727
|
+
if fn.rtype == 'void':
|
|
728
|
+
set_str = ''
|
|
729
|
+
else:
|
|
730
|
+
result_index += 1
|
|
731
|
+
result = 'result_%d' % result_index
|
|
732
|
+
set_str = '%s %s = ' % (fn.rtype, result)
|
|
733
|
+
last_result = result
|
|
734
|
+
|
|
735
|
+
code += " %s%s(%s);\n" % (set_str, obj_names[fn], args)
|
|
736
|
+
|
|
737
|
+
# return the last function's output
|
|
738
|
+
if self.rtype != 'void':
|
|
739
|
+
code += " return result_%d;\n" % result_index
|
|
740
|
+
|
|
741
|
+
code += "}\n"
|
|
742
|
+
return code
|
|
743
|
+
|
|
744
|
+
def static_names(self):
|
|
745
|
+
return []
|
|
746
|
+
|
|
747
|
+
def __repr__(self):
|
|
748
|
+
fn = ",\n ".join(map(repr, self.functions))
|
|
749
|
+
return "<FunctionChain [%s] at 0x%x>" % (fn, id(self))
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
class StatementList(ShaderObject):
|
|
753
|
+
"""Represents a list of statements."""
|
|
754
|
+
|
|
755
|
+
def __init__(self):
|
|
756
|
+
self.items = {}
|
|
757
|
+
self.order = []
|
|
758
|
+
ShaderObject.__init__(self)
|
|
759
|
+
|
|
760
|
+
def add(self, item, position=5):
|
|
761
|
+
"""Add an item to the list unless it is already present.
|
|
762
|
+
|
|
763
|
+
If the item is an expression, then a semicolon will be appended to it
|
|
764
|
+
in the final compiled code.
|
|
765
|
+
"""
|
|
766
|
+
if item in self.items:
|
|
767
|
+
return
|
|
768
|
+
self.items[item] = position
|
|
769
|
+
self._add_dep(item)
|
|
770
|
+
self.order = None
|
|
771
|
+
self.changed(code_changed=True)
|
|
772
|
+
|
|
773
|
+
def remove(self, item):
|
|
774
|
+
"""Remove an item from the list."""
|
|
775
|
+
self.items.pop(item)
|
|
776
|
+
self._remove_dep(item)
|
|
777
|
+
self.order = None
|
|
778
|
+
self.changed(code_changed=True)
|
|
779
|
+
|
|
780
|
+
def expression(self, obj_names):
|
|
781
|
+
if self.order is None:
|
|
782
|
+
self.order = list(self.items.items())
|
|
783
|
+
self.order.sort(key=lambda x: x[1])
|
|
784
|
+
|
|
785
|
+
code = ""
|
|
786
|
+
for item, pos in self.order:
|
|
787
|
+
code += item.expression(obj_names) + ';\n'
|
|
788
|
+
return code
|