vispy 0.9.5__cp38-cp38-win_amd64.whl → 0.14.0__cp38-cp38-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (103) hide show
  1. vispy/app/backends/_glfw.py +2 -2
  2. vispy/app/backends/_pyglet.py +8 -2
  3. vispy/app/backends/_qt.py +88 -63
  4. vispy/app/backends/_wx.py +6 -1
  5. vispy/app/canvas.py +4 -2
  6. vispy/app/tests/test_canvas.py +52 -1
  7. vispy/app/tests/test_context.py +5 -3
  8. vispy/color/color_array.py +8 -1
  9. vispy/color/colormap.py +5 -25
  10. vispy/geometry/meshdata.py +76 -38
  11. vispy/geometry/rect.py +6 -0
  12. vispy/geometry/tests/test_meshdata.py +72 -0
  13. vispy/gloo/buffer.py +12 -0
  14. vispy/gloo/gl/_constants.py +9 -5
  15. vispy/gloo/gl/_es2.py +8 -4
  16. vispy/gloo/gl/_gl2.py +2 -3
  17. vispy/gloo/gl/_proxy.py +1 -1
  18. vispy/gloo/gl/_pyopengl2.py +12 -7
  19. vispy/gloo/gl/tests/test_names.py +3 -0
  20. vispy/gloo/glir.py +26 -13
  21. vispy/gloo/program.py +39 -22
  22. vispy/gloo/tests/test_program.py +9 -2
  23. vispy/gloo/tests/test_texture.py +19 -2
  24. vispy/gloo/texture.py +46 -16
  25. vispy/gloo/wrappers.py +4 -2
  26. vispy/glsl/build_spatial_filters.py +241 -293
  27. vispy/glsl/misc/spatial-filters.frag +1299 -254
  28. vispy/io/_data/spatial-filters.npy +0 -0
  29. vispy/io/datasets.py +2 -2
  30. vispy/io/image.py +1 -1
  31. vispy/io/stl.py +3 -3
  32. vispy/scene/cameras/base_camera.py +6 -2
  33. vispy/scene/cameras/panzoom.py +10 -14
  34. vispy/scene/cameras/perspective.py +6 -0
  35. vispy/scene/cameras/tests/test_cameras.py +27 -0
  36. vispy/scene/cameras/tests/test_perspective.py +37 -0
  37. vispy/scene/cameras/turntable.py +39 -23
  38. vispy/scene/canvas.py +9 -5
  39. vispy/scene/events.py +9 -0
  40. vispy/scene/node.py +19 -2
  41. vispy/scene/tests/test_canvas.py +30 -1
  42. vispy/scene/tests/test_visuals.py +113 -0
  43. vispy/scene/visuals.py +6 -1
  44. vispy/scene/widgets/viewbox.py +3 -2
  45. vispy/testing/_runners.py +6 -12
  46. vispy/testing/_testing.py +3 -4
  47. vispy/util/check_environment.py +4 -4
  48. vispy/util/gallery_scraper.py +50 -32
  49. vispy/util/tests/test_gallery_scraper.py +2 -0
  50. vispy/util/transforms.py +1 -1
  51. vispy/util/wrappers.py +1 -1
  52. vispy/version.py +2 -3
  53. vispy/visuals/__init__.py +2 -0
  54. vispy/visuals/_scalable_textures.py +20 -17
  55. vispy/visuals/collections/array_list.py +3 -3
  56. vispy/visuals/collections/base_collection.py +1 -1
  57. vispy/visuals/ellipse.py +1 -1
  58. vispy/visuals/filters/__init__.py +3 -2
  59. vispy/visuals/filters/base_filter.py +120 -0
  60. vispy/visuals/filters/clipping_planes.py +24 -12
  61. vispy/visuals/filters/markers.py +28 -0
  62. vispy/visuals/filters/mesh.py +61 -6
  63. vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
  64. vispy/visuals/graphs/graph.py +1 -1
  65. vispy/visuals/image.py +114 -26
  66. vispy/visuals/image_complex.py +130 -0
  67. vispy/visuals/instanced_mesh.py +152 -0
  68. vispy/visuals/isocurve.py +1 -1
  69. vispy/visuals/line/dash_atlas.py +46 -41
  70. vispy/visuals/line/line.py +2 -5
  71. vispy/visuals/markers.py +310 -384
  72. vispy/visuals/mesh.py +2 -2
  73. vispy/visuals/shaders/function.py +3 -0
  74. vispy/visuals/shaders/tests/test_function.py +6 -0
  75. vispy/visuals/tests/test_axis.py +2 -2
  76. vispy/visuals/tests/test_image.py +92 -2
  77. vispy/visuals/tests/test_image_complex.py +36 -0
  78. vispy/visuals/tests/test_instanced_mesh.py +50 -0
  79. vispy/visuals/tests/test_markers.py +6 -0
  80. vispy/visuals/tests/test_mesh.py +17 -0
  81. vispy/visuals/tests/test_text.py +11 -0
  82. vispy/visuals/tests/test_volume.py +218 -12
  83. vispy/visuals/text/_sdf_cpu.cp38-win_amd64.pyd +0 -0
  84. vispy/visuals/text/_sdf_cpu.pyx +21 -23
  85. vispy/visuals/text/text.py +9 -3
  86. vispy/visuals/tube.py +2 -2
  87. vispy/visuals/visual.py +144 -3
  88. vispy/visuals/volume.py +300 -131
  89. {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/LICENSE.txt +1 -1
  90. {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/METADATA +218 -198
  91. {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/RECORD +93 -96
  92. {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/WHEEL +1 -1
  93. vispy/glsl/antialias/__init__.py +0 -0
  94. vispy/glsl/arrowheads/__init__.py +0 -0
  95. vispy/glsl/arrows/__init__.py +0 -0
  96. vispy/glsl/collections/__init__.py +0 -0
  97. vispy/glsl/colormaps/__init__.py +0 -0
  98. vispy/glsl/lines/__init__.py +0 -0
  99. vispy/glsl/markers/__init__.py +0 -0
  100. vispy/glsl/math/__init__.py +0 -0
  101. vispy/glsl/misc/__init__.py +0 -0
  102. vispy/glsl/transforms/__init__.py +0 -0
  103. {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/top_level.txt +0 -0
vispy/gloo/program.py CHANGED
@@ -38,6 +38,18 @@ from .util import check_enum
38
38
  from .context import get_current_canvas
39
39
  from .preprocessor import preprocess
40
40
 
41
+ # ------------------------------------------------------------ Constants ---
42
+ REGEX_VAR = {}
43
+ for kind in ('uniform', 'attribute', 'varying', 'const', 'in', 'out'):
44
+ REGEX_VAR[kind] = re.compile(fr"\s*{kind}\s+" # kind of variable
45
+ r"((highp|mediump|lowp)\s+)?" # Precision (optional)
46
+ r"(?P<type>\w+)\s+" # type
47
+ r"(?P<name>\w+)\s*" # name
48
+ r"(\[(?P<size>\d+)\])?" # size (optional)
49
+ r"(\s*\=\s*[0-9.]+)?" # default value (optional)
50
+ r"\s*;", # end
51
+ flags=re.MULTILINE)
52
+
41
53
 
42
54
  # ------------------------------------------------------------ Shader class ---
43
55
  class Shader(GLObject):
@@ -235,21 +247,12 @@ class Program(GLObject):
235
247
  code = '\n\n'.join([sh.code for sh in self._shaders])
236
248
  code = re.sub(r'(.*)(//.*)', r'\1', code, re.M)
237
249
 
238
- # Regexp to look for variable names
239
- var_regexp = (r"\s*VARIABLE\s+" # kind of variable
240
- r"((highp|mediump|lowp)\s+)?" # Precision (optional)
241
- r"(?P<type>\w+)\s+" # type
242
- r"(?P<name>\w+)\s*" # name
243
- r"(\[(?P<size>\d+)\])?" # size (optional)
244
- r"(\s*\=\s*[0-9.]+)?" # default value (optional)
245
- r"\s*;" # end
246
- )
247
-
248
250
  # Parse uniforms, attributes and varyings
249
251
  self._code_variables = {}
250
252
  for kind in ('uniform', 'attribute', 'varying', 'const', 'in', 'out'):
251
- regex = re.compile(var_regexp.replace('VARIABLE', kind),
252
- flags=re.MULTILINE)
253
+
254
+ # pick regex for the correct kind of var
255
+ reg = REGEX_VAR[kind]
253
256
 
254
257
  # treat *in* like attribute, *out* like varying
255
258
  if kind == 'in':
@@ -257,7 +260,7 @@ class Program(GLObject):
257
260
  elif kind == 'out':
258
261
  kind = 'varying'
259
262
 
260
- for m in re.finditer(regex, code):
263
+ for m in re.finditer(reg, code):
261
264
  gtype = m.group('type')
262
265
  size = int(m.group('size')) if m.group('size') else -1
263
266
  this_kind = kind
@@ -417,11 +420,12 @@ class Program(GLObject):
417
420
  raise ValueError('data.shape[-1] must be %s '
418
421
  'not %s for %s'
419
422
  % (numel, data._last_dim, name))
423
+ divisor = getattr(data, 'divisor', None)
420
424
  self._user_variables[name] = data
421
425
  value = (data.id, data.stride, data.offset)
422
426
  self.glir.associate(data.glir)
423
427
  self._glir.command('ATTRIBUTE', self._id,
424
- name, type_, value)
428
+ name, type_, value, divisor)
425
429
  else:
426
430
  # Single-value attribute; convert to array and check size
427
431
  dtype, numel = self._gtypes[type_]
@@ -431,11 +435,12 @@ class Program(GLObject):
431
435
  if data.size != numel:
432
436
  raise ValueError('Attribute %r needs %i elements, '
433
437
  'not %i.' % (name, numel, data.size))
438
+ divisor = getattr(data, 'divisor', None)
434
439
  # Store and send GLIR command
435
440
  self._user_variables[name] = data
436
441
  value = tuple([0] + [i for i in data])
437
442
  self._glir.command('ATTRIBUTE', self._id,
438
- name, type_, value)
443
+ name, type_, value, divisor)
439
444
  else:
440
445
  raise KeyError('Cannot set data for a %s.' % kind)
441
446
  else:
@@ -490,13 +495,25 @@ class Program(GLObject):
490
495
  # Check attribute sizes
491
496
  attributes = [vbo for vbo in self._user_variables.values()
492
497
  if isinstance(vbo, DataBuffer)]
493
- sizes = [a.size for a in attributes]
494
- if len(attributes) < 1:
498
+
499
+ attrs = [a for a in attributes if getattr(a, 'divisor', None) is None]
500
+ if len(attrs) < 1:
495
501
  raise RuntimeError('Must have at least one attribute')
502
+ sizes = [a.size for a in attrs]
496
503
  if not all(s == sizes[0] for s in sizes[1:]):
497
- msg = '\n'.join(['%s: %s' % (str(a), a.size) for a in attributes])
498
- raise RuntimeError('All attributes must have the same size, got:\n'
499
- '%s' % msg)
504
+ msg = '\n'.join([f'{str(a)}: {a.size}' for a in attrs])
505
+ raise RuntimeError(f'All attributes must have the same size, got:\n{msg}')
506
+
507
+ attrs_with_div = [a for a in attributes if a not in attrs]
508
+ if attrs_with_div:
509
+ sizes = [a.size for a in attrs_with_div]
510
+ divs = [a.divisor for a in attrs_with_div]
511
+ instances = sizes[0] * divs[0]
512
+ if not all(s * d == instances for s, d in zip(sizes, divs)):
513
+ msg = '\n'.join([f'{str(a)}: {a.size} * {a.divisor} = {a.size * a.divisor}' for a in attrs_with_div])
514
+ raise RuntimeError(f'All attributes with divisors must have the same size as the number of instances, got:\n{msg}')
515
+ else:
516
+ instances = 1
500
517
 
501
518
  # Get the glir queue that we need now
502
519
  canvas = get_current_canvas()
@@ -513,11 +530,11 @@ class Program(GLObject):
513
530
  np.dtype(np.uint16): 'UNSIGNED_SHORT',
514
531
  np.dtype(np.uint32): 'UNSIGNED_INT'}
515
532
  selection = indices.id, gltypes[indices.dtype], indices.size
516
- canvas.context.glir.command('DRAW', self._id, mode, selection)
533
+ canvas.context.glir.command('DRAW', self._id, mode, selection, instances)
517
534
  elif indices is None:
518
535
  selection = 0, attributes[0].size
519
536
  logger.debug("Program drawing %r with %r" % (mode, selection))
520
- canvas.context.glir.command('DRAW', self._id, mode, selection)
537
+ canvas.context.glir.command('DRAW', self._id, mode, selection, instances)
521
538
  else:
522
539
  raise TypeError("Invalid index: %r (must be IndexBuffer)" %
523
540
  indices)
@@ -254,6 +254,13 @@ class ProgramTest(unittest.TestCase):
254
254
  # And anything else also fails
255
255
  self.assertRaises(KeyError, program.__getitem__, 'fooo')
256
256
 
257
+ def test_type_aliases(self):
258
+ program = Program("in bool A; out float B;", "foo")
259
+
260
+ # in aliased to attribute, out to varying
261
+ assert ('attribute', 'bool', 'A') in program.variables
262
+ assert ('varying', 'float', 'B') in program.variables
263
+
257
264
  def test_draw(self):
258
265
  # Init
259
266
  program = Program("attribute float A;", "uniform float foo")
@@ -267,14 +274,14 @@ class ProgramTest(unittest.TestCase):
267
274
  program.draw('triangles')
268
275
  glir_cmd = glir.clear()[-1]
269
276
  assert glir_cmd[0] == 'DRAW'
270
- assert len(glir_cmd[-1]) == 2
277
+ assert len(glir_cmd[-2]) == 2
271
278
 
272
279
  # Draw elements
273
280
  indices = gloo.IndexBuffer(np.zeros(10, dtype=np.uint8))
274
281
  program.draw('triangles', indices)
275
282
  glir_cmd = glir.clear()[-1]
276
283
  assert glir_cmd[0] == 'DRAW'
277
- assert len(glir_cmd[-1]) == 3
284
+ assert len(glir_cmd[-2]) == 3
278
285
 
279
286
  # Invalid mode
280
287
  self.assertRaises(ValueError, program.draw, 'nogeometricshape')
@@ -5,6 +5,7 @@
5
5
  # -----------------------------------------------------------------------------
6
6
  import unittest
7
7
  import numpy as np
8
+ import pytest
8
9
 
9
10
  from vispy.gloo import Texture1D, Texture2D, Texture3D, TextureAtlas
10
11
  from vispy.testing import requires_pyopengl, run_tests_if_main, assert_raises
@@ -642,7 +643,8 @@ def _test_texture_opengl_formats(Texture, baseshape):
642
643
  (1, 'red'),
643
644
  (2, 'rg'),
644
645
  (3, 'rgb'),
645
- (4, 'rgba')
646
+ (4, 'rgba'),
647
+ (1, 'depth_component'),
646
648
  ]
647
649
  )
648
650
 
@@ -674,7 +676,8 @@ def _test_texture_internalformats(Texture, baseshape):
674
676
  (1, 'red', ['red', 'r8', 'r16', 'r16f', 'r32f']),
675
677
  (2, 'rg', ['rg', 'rg8', 'rg16', 'rg16f', 'rg32f']),
676
678
  (3, 'rgb', ['rgb', 'rgb8', 'rgb16', 'rgb16f', 'rgb32f']),
677
- (4, 'rgba', ['rgba', 'rgba8', 'rgba16', 'rgba16f', 'rgba32f'])
679
+ (4, 'rgba', ['rgba', 'rgba8', 'rgba16', 'rgba16f', 'rgba32f']),
680
+ (1, 'depth_component', ['depth_component']),
678
681
  ]
679
682
 
680
683
  for channels in range(1, 5):
@@ -712,4 +715,18 @@ def test_texture_3D_internalformats():
712
715
  _test_texture_internalformats(Texture3D, (10, 10, 10))
713
716
 
714
717
 
718
+ @requires_pyopengl()
719
+ @pytest.mark.parametrize('input_dtype', [np.uint8, np.uint16, np.float32, np.float64])
720
+ @pytest.mark.parametrize('output_dtype', [np.uint8, np.uint16, np.float32, np.float64])
721
+ @pytest.mark.parametrize('ndim', [2, 3])
722
+ def test_texture_set_data_different_dtype(input_dtype, output_dtype, ndim):
723
+ shape = (20,) * ndim
724
+ data = np.random.rand(*shape).astype(input_dtype)
725
+ Texture = Texture2D if ndim == 2 else Texture3D
726
+
727
+ tex = Texture(data)
728
+ tex[:10] = np.array(1, dtype=output_dtype)
729
+ tex.set_data(data.astype(output_dtype))
730
+
731
+
715
732
  run_tests_if_main()
vispy/gloo/texture.py CHANGED
@@ -13,21 +13,49 @@ from .globject import GLObject
13
13
  from .util import check_enum
14
14
 
15
15
 
16
- F64_PRECISION_WARNING = ("GPUs can't support floating point data with more "
17
- "than 32-bits, precision will be lost due to "
18
- "downcasting to 32-bit float.")
16
+ def get_dtype_limits(dtype):
17
+ if np.issubdtype(dtype, np.floating):
18
+ info = np.finfo(dtype)
19
+ else:
20
+ info = np.iinfo(dtype)
21
+ return info.min, info.max
19
22
 
20
23
 
21
- def should_cast_to_f32(data_dtype):
22
- """Check if data type is floating point with more than 32-bits."""
23
- data_dtype = np.dtype(data_dtype)
24
- is_floating = np.issubdtype(data_dtype, np.floating)
25
- gt_float32 = data_dtype.itemsize > 4
26
- if is_floating and gt_float32:
27
- # OpenGL can't support floating point numbers greater than 32-bits
28
- warnings.warn(F64_PRECISION_WARNING)
29
- return True
30
- return False
24
+ def convert_dtype_and_clip(data, dtype, copy=False):
25
+ """
26
+ cast dtype to a new one, but first clip data to the new dtype's limits if needed
27
+ """
28
+ old_min, old_max = get_dtype_limits(data.dtype)
29
+ new_min, new_max = get_dtype_limits(dtype)
30
+ if new_max >= old_max and new_min <= old_min:
31
+ # no need to clip
32
+ return np.array(data, dtype=dtype, copy=copy)
33
+ else:
34
+ # to reduce copying, we clip into a pre-generated array of the right dtype
35
+ new_data = np.empty_like(data, dtype=dtype)
36
+ # allow "unsafe" casting here as we're explicitly clipping to the
37
+ # range of the new dtype - this was a default before numpy 1.25
38
+ np.clip(data, new_min, new_max, out=new_data, casting="unsafe")
39
+ return new_data
40
+
41
+
42
+ def downcast_to_32bit_if_needed(data, copy=False, dtype=None):
43
+ """Downcast to 32bit dtype if necessary."""
44
+ if dtype is None:
45
+ dtype = data.dtype
46
+ dtype = np.dtype(dtype)
47
+ if dtype.itemsize > 4:
48
+ warnings.warn(
49
+ f"GPUs can't support dtypes bigger than 32-bit, but got '{dtype}'. "
50
+ "Precision will be lost due to downcasting to 32-bit.",
51
+ stacklevel=2,
52
+ )
53
+
54
+ size = min(dtype.itemsize, 4)
55
+ kind = dtype.kind
56
+
57
+ new_dtype = np.dtype(f'{kind}{size}')
58
+ return convert_dtype_and_clip(data, new_dtype, copy=copy)
31
59
 
32
60
 
33
61
  class BaseTexture(GLObject):
@@ -78,7 +106,8 @@ class BaseTexture(GLObject):
78
106
  'luminance_alpha': 2,
79
107
  'rg': 2,
80
108
  'rgb': 3,
81
- 'rgba': 4
109
+ 'rgba': 4,
110
+ 'depth_component': 1,
82
111
  }
83
112
 
84
113
  # NOTE: non-normalized formats ending with 'i' and 'ui' are currently
@@ -96,7 +125,8 @@ class BaseTexture(GLObject):
96
125
  ('luminance_alpha', 2),
97
126
  ('rg', 2),
98
127
  ('rgb', 3),
99
- ('rgba', 4)
128
+ ('rgba', 4),
129
+ ('depth_component', 1),
100
130
  ])
101
131
 
102
132
  def __init__(self, data=None, format=None, resizable=True,
@@ -330,7 +360,7 @@ class BaseTexture(GLObject):
330
360
  def _set_data(self, data, offset=None, copy=False):
331
361
  """Internal method for set_data."""
332
362
  # Copy if needed, check/normalize shape
333
- data = np.array(data, copy=copy)
363
+ data = downcast_to_32bit_if_needed(data, copy=copy)
334
364
  data = self._normalize_shape(data)
335
365
 
336
366
  # Maybe resize to purge DATA commands?
vispy/gloo/wrappers.py CHANGED
@@ -43,12 +43,14 @@ GL_PRESETS = {
43
43
  depth_test=True,
44
44
  cull_face=False,
45
45
  blend=True,
46
- blend_func=('src_alpha', 'one_minus_src_alpha', 'zero', 'one')),
46
+ blend_func=('src_alpha', 'one_minus_src_alpha', 'zero', 'one'),
47
+ blend_equation='func_add'),
47
48
  'additive': dict(
48
49
  depth_test=False,
49
50
  cull_face=False,
50
51
  blend=True,
51
- blend_func=('src_alpha', 'one')),
52
+ blend_func=('src_alpha', 'one'),
53
+ blend_equation='func_add'),
52
54
  }
53
55
 
54
56