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
@@ -49,22 +49,22 @@ using 2 1D-convolution with same 1d-kernel (= the lookup table values).
49
49
  Available filters:
50
50
 
51
51
  - Nearest (radius 0.5)
52
- - Bilinear (radius 1.0)
53
- - Hanning (radius 1.0)
54
- - Hamming (radius 1.0)
55
- - Hermite (radius 1.0)
56
- - Kaiser (radius 1.0)
52
+ - Linear (radius 1)
53
+ - Hanning (radius 1)
54
+ - Hamming (radius 1)
55
+ - Hermite (radius 1)
56
+ - Kaiser (radius 1)
57
57
  - Quadric (radius 1.5)
58
- - Bicubic (radius 2.0)
59
- - CatRom (radius 2.0)
60
- - Mitchell (radius 2.0)
61
- - Spline16 (radius 2.0)
62
- - Spline36 (radius 4.0)
63
- - Gaussian (radius 2.0)
58
+ - Cubic (radius 2)
59
+ - CatRom (radius 2)
60
+ - Mitchell (radius 2)
61
+ - Spline16 (radius 2)
62
+ - Spline36 (radius 4)
63
+ - Gaussian (radius 2)
64
64
  - Bessel (radius 3.2383)
65
- - Sinc (radius 4.0)
66
- - Lanczos (radius 4.0)
67
- - Blackman (radius 4.0)
65
+ - Sinc (radius 4)
66
+ - Lanczos (radius 4)
67
+ - Blackman (radius 4)
68
68
 
69
69
 
70
70
  Note::
@@ -76,13 +76,13 @@ Note::
76
76
 
77
77
  import math
78
78
  import numpy as np
79
+ from inspect import cleandoc
80
+ from itertools import product
79
81
 
80
82
 
81
- class SpatialFilter(object):
82
- ''' '''
83
-
84
- def __init__(self, radius=1.0):
85
- self.radius = radius
83
+ class SpatialFilter:
84
+ def __init__(self, radius=1):
85
+ self.radius = math.ceil(radius)
86
86
 
87
87
  def weight(self, x):
88
88
  """
@@ -94,119 +94,38 @@ class SpatialFilter(object):
94
94
  """
95
95
  raise NotImplementedError
96
96
 
97
- def kernel(self, size=4*512):
98
- radius = self.radius
99
- r = int(max(1.0, math.ceil(radius)))
100
- samples = int(size / r)
97
+ def kernel(self, size=4 * 512):
98
+ samples = int(size / self.radius)
101
99
  n = size # r*samples
102
100
  kernel = np.zeros(n)
103
- X = np.linspace(0, r, n)
101
+ X = np.linspace(0, self.radius, n)
104
102
  for i in range(n):
105
103
  kernel[i] = self.weight(X[i])
106
104
  N = np.zeros(samples)
107
- for i in range(r):
108
- N += kernel[::+1][i*samples:(i+1)*samples]
109
- N += kernel[::-1][i*samples:(i+1)*samples]
110
- for i in range(r):
111
- kernel[i*samples:(i+1)*samples:+1] /= N
105
+ for i in range(self.radius):
106
+ N += kernel[::+1][i * samples:(i + 1) * samples]
107
+ N += kernel[::-1][i * samples:(i + 1) * samples]
108
+ for i in range(self.radius):
109
+ kernel[i * samples:(i + 1) * samples] /= N
112
110
  return kernel
113
111
 
114
- def filter_code(self):
115
-
116
- n = int(math.ceil(self.radius))
117
- filter_1 = 'filter1D_radius%d' % n
118
- filter_2 = 'filter2D_radius%d' % n
119
-
120
- code = ''
121
- code += 'vec4\n'
122
- code += '%s( sampler2D kernel, float index, float x, ' % filter_1
123
- for i in range(2*n):
124
- if i == 2*n-1:
125
- code += 'vec4 c%d )\n' % i
126
- else:
127
- code += 'vec4 c%d, ' % i
128
- code += '{\n'
129
- code += ' float w, w_sum = 0.0;\n'
130
- code += ' vec4 r = vec4(0.0,0.0,0.0,0.0);\n'
131
- for i in range(n):
132
- code += ' w = unpack_interpolate(kernel, vec2(%f+(x/%.1f), index));\n' % (1.0 - (i + 1) / float(n), n) # noqa
133
- code += ' w = w*kernel_scale + kernel_bias;\n' # noqa
134
- # code += ' w_sum += w;'
135
- code += ' r += c%d * w;\n' % i
136
- code += ' w = unpack_interpolate(kernel, vec2(%f-(x/%.1f), index));\n' % ((i+1)/float(n), n) # noqa
137
- code += ' w = w*kernel_scale + kernel_bias;\n'
138
- # code += ' w_sum += w;'
139
- code += ' r += c%d * w;\n' % (i + n)
140
- # code += ' return r/w_sum;\n'
141
- code += ' return r;\n'
142
- code += '}\n'
143
- code += "\n"
144
- code += 'vec4\n'
145
- code += '%s' % filter_2
146
- code += '(sampler2D texture, sampler2D kernel, float index, vec2 uv, vec2 pixel)\n' # noqa
147
- code += '{\n'
148
- code += ' vec2 texel = uv/pixel - vec2(0.5, 0.5) ;\n'
149
- code += ' vec2 f = fract(texel);\n'
150
- code += ' texel = (texel-fract(texel) + vec2(0.001, 0.001)) * pixel;\n' # noqa
151
- for i in range(2*n):
152
- code += ' vec4 t%d = %s(kernel, index, f.x,\n' % (i, filter_1)
153
- for j in range(2*n):
154
- x, y = (-n+1+j, -n+1+i)
155
- code += ' texture2D( texture, texel + vec2(%d, %d) * pixel),\n' % (x, y) # noqa
156
-
157
- # Remove last trailing',' and close function call
158
- code = code[:-2] + ');\n'
159
-
160
- code += ' return %s(kernel, index, f.y, ' % filter_1
161
- for i in range(2*n):
162
- code += 't%d, ' % i
163
-
164
- # Remove last trailing',' and close function call
165
- code = code[:-2] + ');\n'
166
- code += '}\n'
167
-
168
- return code
169
-
170
112
  def call_code(self, index):
171
- code = ""
172
- n = int(math.ceil(self.radius))
173
- filter_1 = 'filter1D_radius%d' % n # noqa
174
- filter_2 = 'filter2D_radius%d' % n
175
-
176
- code += 'vec4 %s(sampler2D texture, vec2 shape, vec2 uv)\n' % self.__class__.__name__ # noqa
177
- code += '{'
178
- code += ' return %s(texture, u_kernel, %f, uv, 1.0/shape); ' % (filter_2, index) # noqa
179
- code += '}\n'
180
- return code
113
+ code = cleandoc(f'''
114
+ vec4 {self.__class__.__name__}2D(sampler2D texture, vec2 shape, vec2 uv) {{
115
+ return filter2D_radius{self.radius}(texture, u_kernel, {index}, uv, 1 / shape);
116
+ }}
181
117
 
118
+ vec4 {self.__class__.__name__}3D(sampler3D texture, vec3 shape, vec3 uv) {{
119
+ return filter3D_radius{self.radius}(texture, u_kernel, {index}, uv, 1 / shape);
120
+ }}
121
+ ''')
182
122
 
183
- class Nearest(SpatialFilter):
184
- """
185
- Nearest (=None) filter (radius = 0.5).
186
-
187
- Weight function::
188
-
189
- w(x) = 1
190
- """
191
-
192
- def __init__(self):
193
- SpatialFilter.__init__(self, radius=.5)
194
-
195
- def weight(self, x):
196
- return 1.0
197
-
198
- def _get_code(self):
199
- self.build_LUT()
200
- code = 'vec4\n'
201
- code += 'interpolate(sampler2D texture, sampler1D kernel, vec2 uv, vec2 pixel)\n' # noqa
202
- code += '{\n return texture2D(texture, uv);\n}\n'
203
123
  return code
204
- code = property(_get_code, doc='''filter functions code''')
205
124
 
206
125
 
207
- class Bilinear(SpatialFilter):
126
+ class Linear(SpatialFilter):
208
127
  """
209
- Bilinear filter (radius = 1.0).
128
+ Linear filter (radius = 1).
210
129
 
211
130
  Weight function::
212
131
 
@@ -214,16 +133,13 @@ class Bilinear(SpatialFilter):
214
133
 
215
134
  """
216
135
 
217
- def __init__(self):
218
- SpatialFilter.__init__(self, radius=1.0)
219
-
220
136
  def weight(self, x):
221
- return 1.0 - x
137
+ return 1 - x
222
138
 
223
139
 
224
140
  class Hanning(SpatialFilter):
225
141
  """
226
- Hanning filter (radius = 1.0).
142
+ Hanning filter (radius = 1).
227
143
 
228
144
  Weight function::
229
145
 
@@ -231,16 +147,13 @@ class Hanning(SpatialFilter):
231
147
 
232
148
  """
233
149
 
234
- def __init__(self):
235
- SpatialFilter.__init__(self, radius=1.0)
236
-
237
150
  def weight(self, x):
238
151
  return 0.5 + 0.5 * math.cos(math.pi * x)
239
152
 
240
153
 
241
154
  class Hamming(SpatialFilter):
242
155
  """
243
- Hamming filter (radius = 1.0).
156
+ Hamming filter (radius = 1).
244
157
 
245
158
  Weight function::
246
159
 
@@ -248,15 +161,12 @@ class Hamming(SpatialFilter):
248
161
 
249
162
  """
250
163
 
251
- def __init__(self):
252
- SpatialFilter.__init__(self, radius=1.0)
253
-
254
164
  def weight(self, x):
255
165
  return 0.54 + 0.46 * math.cos(math.pi * x)
256
166
 
257
167
 
258
168
  class Hermite(SpatialFilter):
259
- """Hermite filter (radius = 1.0).
169
+ """Hermite filter (radius = 1).
260
170
 
261
171
  Weight function::
262
172
 
@@ -264,11 +174,8 @@ class Hermite(SpatialFilter):
264
174
 
265
175
  """
266
176
 
267
- def __init__(self):
268
- SpatialFilter.__init__(self, radius=1.0)
269
-
270
177
  def weight(self, x):
271
- return (2.0 * x - 3.0) * x * x + 1.0
178
+ return (2 * x - 3) * x**2 + 1
272
179
 
273
180
 
274
181
  class Quadric(SpatialFilter):
@@ -277,28 +184,27 @@ class Quadric(SpatialFilter):
277
184
 
278
185
  Weight function::
279
186
 
280
- | 0.0 ≤ x < 0.5: 0.75 - x*x
187
+ | 0 ≤ x < 0.5: 0.75 - x*x
281
188
  w(x) = | 0.5 ≤ x < 1.5: 0.5 - (x-1.5)^2
282
189
  | 1.5 ≤ x : 0
283
190
 
284
191
  """
285
192
 
286
193
  def __init__(self):
287
- SpatialFilter.__init__(self, radius=1.5)
194
+ super().__init__(radius=1.5)
288
195
 
289
196
  def weight(self, x):
290
197
  if x < 0.75:
291
- return 0.75 - x * x
198
+ return 0.75 - x**2
292
199
  elif x < 1.5:
293
200
  t = x - 1.5
294
- return 0.5 * t * t
295
- else:
296
- return 0.0
201
+ return 0.5 * t**2
202
+ return 0
297
203
 
298
204
 
299
- class Bicubic(SpatialFilter):
205
+ class Cubic(SpatialFilter):
300
206
  """
301
- Bicubic filter (radius = 2.0).
207
+ Cubic filter (radius = 2).
302
208
 
303
209
  Weight function::
304
210
 
@@ -306,24 +212,20 @@ class Bicubic(SpatialFilter):
306
212
  """
307
213
 
308
214
  def __init__(self):
309
- SpatialFilter.__init__(self, radius=2.0)
310
-
311
- def pow3(self, x):
312
- if x <= 0:
313
- return 0
314
- else:
315
- return x * x * x
215
+ super().__init__(radius=2)
316
216
 
317
217
  def weight(self, x):
318
- return (1.0/6.0) * (self.pow3(x + 2) -
319
- 4 * self.pow3(x + 1) +
320
- 6 * self.pow3(x) -
321
- 4 * self.pow3(x - 1))
218
+ return (1 / 6) * (
219
+ (x + 2)**3
220
+ - 4 * (x + 1)**3
221
+ + 6 * x**3
222
+ - 4 * (x - 1)**3
223
+ )
322
224
 
323
225
 
324
226
  class Kaiser(SpatialFilter):
325
227
  """
326
- Kaiser filter (radius = 1.0).
228
+ Kaiser filter (radius = 1).
327
229
 
328
230
 
329
231
  Weight function::
@@ -335,29 +237,29 @@ class Kaiser(SpatialFilter):
335
237
  def __init__(self, b=6.33):
336
238
  self.a = b
337
239
  self.epsilon = 1e-12
338
- self.i0a = 1.0 / self.bessel_i0(b)
339
- SpatialFilter.__init__(self, radius=1.0)
240
+ self.i0a = 1 / self.bessel_i0(b)
241
+ super().__init__(radius=1)
340
242
 
341
243
  def bessel_i0(self, x):
342
- s = 1.0
343
- y = x * x / 4.0
244
+ s = 1
245
+ y = x**2 / 4
344
246
  t = y
345
247
  i = 2
346
248
  while t > self.epsilon:
347
249
  s += t
348
- t *= float(y) / (i * i)
250
+ t *= float(y) / i**2
349
251
  i += 1
350
252
  return s
351
253
 
352
254
  def weight(self, x):
353
255
  if x > 1:
354
256
  return 0
355
- return self.bessel_i0(self.a * math.sqrt(1.0 - x * x)) * self.i0a
257
+ return self.bessel_i0(self.a * math.sqrt(1 - x**2)) * self.i0a
356
258
 
357
259
 
358
260
  class CatRom(SpatialFilter):
359
261
  """
360
- Catmull-Rom filter (radius = 2.0).
262
+ Catmull-Rom filter (radius = 2).
361
263
 
362
264
  Weight function::
363
265
 
@@ -367,21 +269,21 @@ class CatRom(SpatialFilter):
367
269
 
368
270
  """
369
271
 
370
- def __init__(self, size=256*8):
371
- SpatialFilter.__init__(self, radius=2.0)
272
+ def __init__(self):
273
+ super().__init__(radius=2)
372
274
 
373
275
  def weight(self, x):
374
- if x < 1.0:
375
- return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0))
376
- elif x < 2.0:
377
- return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x)))
276
+ if x < 1:
277
+ return 0.5 * (2 + x**2 * (-5 + x * 3))
278
+ elif x < 2:
279
+ return 0.5 * (4 + x * (-8 + x * (5 - x)))
378
280
  else:
379
- return 0.0
281
+ return 0
380
282
 
381
283
 
382
284
  class Mitchell(SpatialFilter):
383
285
  """
384
- Mitchell-Netravali filter (radius = 2.0).
286
+ Mitchell-Netravali filter (radius = 2).
385
287
 
386
288
  Weight function::
387
289
 
@@ -391,28 +293,28 @@ class Mitchell(SpatialFilter):
391
293
 
392
294
  """
393
295
 
394
- def __init__(self, b=1.0/3.0, c=1.0/3.0):
395
- self.p0 = (6.0 - 2.0 * b) / 6.0
396
- self.p2 = (-18.0 + 12.0 * b + 6.0 * c) / 6.0
397
- self.p3 = (12.0 - 9.0 * b - 6.0 * c) / 6.0
398
- self.q0 = (8.0 * b + 24.0 * c) / 6.0
399
- self.q1 = (-12.0 * b - 48.0 * c) / 6.0
400
- self.q2 = (6.0 * b + 30.0 * c) / 6.0
401
- self.q3 = (-b - 6.0 * c) / 6.0
402
- SpatialFilter.__init__(self, radius=2.0)
296
+ def __init__(self, b=1/3, c=1/3):
297
+ self.p0 = (6 - 2 * b) / 6
298
+ self.p2 = (-18 + 12 * b + 6 * c) / 6
299
+ self.p3 = (12 - 9 * b - 6 * c) / 6
300
+ self.q0 = (8 * b + 24 * c) / 6
301
+ self.q1 = (-12 * b - 48 * c) / 6
302
+ self.q2 = (6 * b + 30 * c) / 6
303
+ self.q3 = (-b - 6 * c) / 6
304
+ super().__init__(radius=2)
403
305
 
404
306
  def weight(self, x):
405
- if x < 1.0:
406
- return self.p0 + x * x * (self.p2 + x * self.p3)
407
- elif x < 2.0:
307
+ if x < 1:
308
+ return self.p0 + x**2 * (self.p2 + x * self.p3)
309
+ elif x < 2:
408
310
  return self.q0 + x * (self.q1 + x * (self.q2 + x * self.q3))
409
311
  else:
410
- return 0.0
312
+ return 0
411
313
 
412
314
 
413
315
  class Spline16(SpatialFilter):
414
316
  """
415
- Spline16 filter (radius = 2.0).
317
+ Spline16 filter (radius = 2).
416
318
 
417
319
  Weight function::
418
320
 
@@ -423,18 +325,18 @@ class Spline16(SpatialFilter):
423
325
  """
424
326
 
425
327
  def __init__(self):
426
- SpatialFilter.__init__(self, radius=2.0)
328
+ super().__init__(radius=2)
427
329
 
428
330
  def weight(self, x):
429
- if x < 1.0:
430
- return ((x - 9.0/5.0) * x - 1.0/5.0) * x + 1.0
331
+ if x < 1:
332
+ return ((x - 9/5) * x - 1/5) * x + 1
431
333
  else:
432
- return ((-1.0/3.0 * (x-1) + 4.0/5.0) * (x-1) - 7.0/15.0) * (x-1)
334
+ return ((-1/3 * (x - 1) + 4/5) * (x - 1) - 7/15) * (x - 1)
433
335
 
434
336
 
435
337
  class Spline36(SpatialFilter):
436
338
  """
437
- Spline36 filter (radius = 3.0).
339
+ Spline36 filter (radius = 3).
438
340
 
439
341
  Weight function::
440
342
 
@@ -444,20 +346,20 @@ class Spline36(SpatialFilter):
444
346
  """
445
347
 
446
348
  def __init__(self):
447
- SpatialFilter.__init__(self, radius=3.0)
349
+ super().__init__(radius=3)
448
350
 
449
351
  def weight(self, x):
450
- if x < 1.0:
451
- return ((13.0/11.0 * x - 453.0/209.0) * x - 3.0/209.0) * x + 1.0
452
- elif x < 2.0:
453
- return ((-6.0/11.0 * (x-1) + 270.0/209.0) * (x-1) - 156.0 / 209.0) * (x-1) # noqa
352
+ if x < 1:
353
+ return ((13/11 * x - 453/209) * x - 3/209) * x + 1
354
+ elif x < 2:
355
+ return ((-6/11 * (x - 1) + 270/209) * (x - 1) - 156 / 209) * (x - 1)
454
356
  else:
455
- return ((1.0 / 11.0 * (x-2) - 45.0/209.0) * (x - 2) + 26.0/209.0) * (x-2) # noqa
357
+ return ((1/11 * (x - 2) - 45/209) * (x - 2) + 26/209) * (x - 2)
456
358
 
457
359
 
458
360
  class Gaussian(SpatialFilter):
459
361
  """
460
- Gaussian filter (radius = 2.0).
362
+ Gaussian filter (radius = 2).
461
363
 
462
364
  Weight function::
463
365
 
@@ -467,7 +369,7 @@ class Gaussian(SpatialFilter):
467
369
 
468
370
  This filter does not seem to be correct since:
469
371
 
470
- x = np.linspace(0, 1.0, 100 )
372
+ x = np.linspace(0, 1, 100 )
471
373
  f = weight
472
374
  z = f(x+1)+f(x)+f(1-x)+f(2-x)
473
375
 
@@ -476,17 +378,17 @@ class Gaussian(SpatialFilter):
476
378
  """
477
379
 
478
380
  def __init__(self):
479
- SpatialFilter.__init__(self, radius=2.0)
381
+ super().__init__(radius=2)
480
382
 
481
383
  def weight(self, x):
482
- return math.exp(-2.0 * x * x) * math.sqrt(2.0 / math.pi)
384
+ return math.exp(-2 * x**2) * math.sqrt(2 / math.pi)
483
385
 
484
386
 
485
387
  class Bessel(SpatialFilter):
486
388
  """Bessel filter (radius = 3.2383)."""
487
389
 
488
390
  def __init__(self):
489
- SpatialFilter.__init__(self, radius=3.2383)
391
+ super().__init__(radius=3.2383)
490
392
 
491
393
  def besj(self, x, n):
492
394
  """Function BESJ calculates Bessel function of first kind of order n.
@@ -521,7 +423,7 @@ class Bessel(SpatialFilter):
521
423
 
522
424
  """
523
425
  if n < 0:
524
- return 0.0
426
+ return 0
525
427
  x = float(x) # force float type
526
428
 
527
429
  d = 1e-6
@@ -551,7 +453,7 @@ class Bessel(SpatialFilter):
551
453
  m8 = -1
552
454
 
553
455
  imax = m2 - 2
554
- for i in range(1, imax+1):
456
+ for i in range(1, imax + 1):
555
457
  c6 = 2 * (m2 - i) * c2 / x - c3
556
458
  c3 = c2
557
459
  c2 = c6
@@ -572,139 +474,185 @@ class Bessel(SpatialFilter):
572
474
  m2 += 3
573
475
 
574
476
  def weight(self, x):
575
- if x == 0.0:
576
- return math.pi/4.0
477
+ if x == 0:
478
+ return math.pi / 4
577
479
  else:
578
- return self.besj(math.pi * x, 1) / (2.0 * x)
480
+ return self.besj(math.pi * x, 1) / (2 * x)
579
481
 
580
482
 
581
483
  class Sinc(SpatialFilter):
582
- """Sinc filter (radius = 4.0)."""
484
+ """Sinc filter (radius = 4)."""
583
485
 
584
- def __init__(self, size=256, radius=4.0):
585
- SpatialFilter.__init__(self, radius=max(radius, 2.0))
486
+ def __init__(self):
487
+ super().__init__(radius=4)
586
488
 
587
489
  def weight(self, x):
588
- if x == 0.0:
589
- return 1.0
490
+ if x == 0:
491
+ return 1
590
492
  x *= math.pi
591
493
  return (math.sin(x) / x)
592
494
 
593
495
 
594
496
  class Lanczos(SpatialFilter):
595
- """Lanczos filter (radius = 4.0)."""
497
+ """Lanczos filter (radius = 4)."""
596
498
 
597
- def __init__(self, size=256, radius=4.0):
598
- SpatialFilter.__init__(self, radius=max(radius, 2.0))
499
+ def __init__(self):
500
+ super().__init__(radius=4)
599
501
 
600
502
  def weight(self, x):
601
- if x == 0.0:
602
- return 1.0
503
+ if x == 0:
504
+ return 1
603
505
  elif x > self.radius:
604
- return 0.0
506
+ return 0
605
507
  x *= math.pi
606
508
  xr = x / self.radius
607
- return (math.sin(x) / x) * (math.sin(xr)/xr)
509
+ return (math.sin(x) / x) * (math.sin(xr) / xr)
608
510
 
609
511
 
610
512
  class Blackman(SpatialFilter):
611
- """Blackman filter (radius = 4.0)."""
513
+ """Blackman filter (radius = 4)."""
612
514
 
613
- def __init__(self, size=256, radius=4.0):
614
- SpatialFilter.__init__(self, radius=max(radius, 2.0))
515
+ def __init__(self):
516
+ super().__init__(radius=4)
615
517
 
616
518
  def weight(self, x):
617
- if x == 0.0:
618
- return 1.0
519
+ if x == 0:
520
+ return 1
619
521
  elif x > self.radius:
620
- return 0.0
522
+ return 0
621
523
  x *= math.pi
622
524
  xr = x / self.radius
623
- return (math.sin(x) / x) * (0.42 + 0.5*math.cos(xr) + 0.08*math.cos(2*xr)) # noqa
525
+ return (math.sin(x) / x) * (0.42 + 0.5 * math.cos(xr) + 0.08 * math.cos(2 * xr))
526
+
527
+
528
+ def generate_filter_code(radius):
529
+ n = int(math.ceil(radius))
530
+
531
+ nl = '\n' # cannot use backslash in fstring
532
+ code = cleandoc(f'''
533
+ vec4 filter1D_radius{n}(sampler2D kernel, float index, float x{''.join(f', vec4 c{i}' for i in range(n * 2))}) {{
534
+ float w, w_sum = 0;
535
+ vec4 r = vec4(0);
536
+ {''.join(f"""
537
+ w = unpack_interpolate(kernel, vec2({1 - (i + 1) / n} + (x / {n}), index));
538
+ w = w * kernel_scale + kernel_bias;
539
+ r += c{i} * w;
540
+ w = unpack_interpolate(kernel, vec2({(i + 1) / n} - (x / {n}), index));
541
+ w = w * kernel_scale + kernel_bias;
542
+ r += c{i + n} * w;"""
543
+ for i in range(n))}
544
+ return r;
545
+ }}
546
+
547
+ vec4 filter2D_radius{n}(sampler2D texture, sampler2D kernel, float index, vec2 uv, vec2 pixel) {{
548
+ vec2 texel = uv / pixel - vec2(0.5);
549
+ vec2 f = fract(texel);
550
+ texel = (texel - fract(texel) + vec2(0.001)) * pixel;
551
+ {''.join(f"""
552
+ vec4 t{i} = filter1D_radius{n}(kernel, index, f.x{f''.join(
553
+ f',{nl} texture2D(texture, texel + vec2({-n + 1 + j}, {-n + 1 + i}) * pixel)'
554
+ for j in range(n * 2))});"""
555
+ for i in range(n * 2))}
556
+ return filter1D_radius{n}(kernel, index, f.y{''.join(f', t{i}' for i in range(2*n))});
557
+ }}
558
+
559
+ vec4 filter3D_radius{n}(sampler3D texture, sampler2D kernel, float index, vec3 uv, vec3 pixel) {{
560
+ vec3 texel = uv / pixel - vec3(0.5);
561
+ vec3 f = fract(texel);
562
+ texel = (texel - fract(texel) + vec3(0.001)) * pixel;
563
+ {''.join(f"""
564
+ vec4 t{i}{j} = filter1D_radius{n}(kernel, index, f.x{f''.join(
565
+ f',{nl} texture3D(texture, texel + vec3({-n + 1 + k}, {-n + 1 + j}, {-n + 1 + i}) * pixel)'
566
+ for k in range(n * 2))});"""
567
+ for i, j in product(range(n * 2), range(n * 2)))}
568
+ {f''.join(f"""
569
+ vec4 t{i} = filter1D_radius{n}(kernel, index, f.y{"".join(
570
+ f", t{i}{j}" for j in range(n * 2))});"""
571
+ for i in range(n * 2))}
572
+ return filter1D_radius{n}(kernel, index, f.z{''.join(f', t{i}' for i in range(2*n))});
573
+ }}
574
+ ''')
575
+
576
+ return code
624
577
 
625
578
 
626
579
  def main():
627
580
  # Generate kernels texture (16 x 1024)
628
- filters = [Bilinear(), Hanning(), Hamming(), Hermite(), Kaiser(), Quadric(),
629
- Bicubic(), CatRom(), Mitchell(), Spline16(), Spline36(), Gaussian(),
581
+ filters = [Linear(), Hanning(), Hamming(), Hermite(), Kaiser(), Quadric(),
582
+ Cubic(), CatRom(), Mitchell(), Spline16(), Spline36(), Gaussian(),
630
583
  Bessel(), Sinc(), Lanczos(), Blackman()]
631
584
 
632
585
  n = 1024
633
- K = np.zeros((16, n))
586
+ K = np.zeros((len(filters), n))
634
587
  for i, f in enumerate(filters):
635
588
  K[i] = f.kernel(n)
636
589
 
637
590
  bias = K.min()
638
- scale = K.max()-K.min()
639
- K = (K-bias)/scale
591
+ scale = K.max() - K.min()
592
+ K = (K - bias) / scale
640
593
  np.save("spatial-filters.npy", K.astype(np.float32))
641
594
 
642
- print("// ------------------------------------")
643
- print("// Automatically generated, do not edit")
644
- print("// ------------------------------------")
645
- print("")
646
- print("const float kernel_bias = %f;" % bias)
647
- print("const float kernel_scale = %f;" % scale)
648
- print("const float kernel_size = %f;" % n)
649
- print("const vec4 bits = vec4(1.0, 1.0/256.0, 1.0/(256.0*256.0), 1.0/(256.0*256.0*256.0));") # noqa
650
- print("uniform sampler2D u_kernel;")
651
- print("")
652
-
653
- code = 'float\n'
654
- code += 'unpack_unit(vec4 rgba)\n'
655
- code += '{\n'
656
- code += '\t// return rgba.r; // uncomment this for r32f debugging\n'
657
- code += '\treturn dot(rgba, bits);\n'
658
- code += '}\n'
659
- print(code.expandtabs(4))
660
-
661
- code = 'float\n'
662
- code += 'unpack_ieee(vec4 rgba)\n'
663
- code += '{\n'
664
- code += '\t// return rgba.r; // uncomment this for r32f debugging\n'
665
- code += '\trgba.rgba = rgba.abgr * 255.;\n'
666
- code += '\tfloat sign = 1.0 - step(128.0,rgba[0])*2.0;\n'
667
- code += '\tfloat exponent = 2.0 * mod(rgba[0],128.0) + ' \
668
- 'step(128.0,rgba[1]) - 127.0;\n'
669
- code += '\tfloat mantissa = mod(rgba[1],128.0)*65536.0 + rgba[2]*256.0 + ' \
670
- 'rgba[3] + float(0x800000);\n'
671
- code += '\treturn sign * exp2(exponent) * (mantissa * exp2(-23.));\n'
672
- code += '}\n'
673
- print(code.expandtabs(4))
674
-
675
- code = 'float\n'
676
- code += 'unpack_interpolate(sampler2D kernel, vec2 uv)\n'
677
- code += '{\n'
678
- code += '\t// return texture2D(kernel, uv).r; ' \
679
- '//uncomment this for r32f debug without interpolation\n'
680
- code += '\tfloat kpixel = 1. / kernel_size;\n'
681
- code += '\tfloat u = uv.x / kpixel;\n'
682
- code += '\tfloat v = uv.y;\n'
683
- code += '\tfloat uf = fract(u);\n'
684
- code += '\tu = (u - uf) * kpixel;\n'
685
- code += '\n'
686
- code += '\tfloat d0 = unpack_unit(texture2D(kernel, vec2(u, v)));\n'
687
- code += '\tfloat d1 = unpack_unit(texture2D(kernel, vec2(u + 1. * kpixel, v)));\n' # noqa
688
- code += '\treturn mix(d0, d1, uf);\n'
689
- code += '}\n'
690
- print(code.expandtabs(4))
691
-
692
- F = SpatialFilter(1.0)
693
- print(F.filter_code())
694
- F = SpatialFilter(2.0)
695
- print(F.filter_code())
696
- F = SpatialFilter(3.0)
697
- print(F.filter_code())
698
- F = SpatialFilter(4.0)
699
- print(F.filter_code())
700
-
701
- # Generate filter functions
702
- # Special case for nearest
703
- print("""vec4 Nearest(sampler2D texture, vec2 shape, vec2 uv)""")
704
- print("""{ return texture2D(texture,uv); }\n""")
595
+ code = cleandoc(f'''
596
+ // ------------------------------------
597
+ // Automatically generated, do not edit
598
+ // ------------------------------------
599
+ const float kernel_bias = {bias};
600
+ const float kernel_scale = {scale};
601
+ const float kernel_size = {n};
602
+ const vec4 bits = vec4(1, {1 / 256}, {1 / (256 * 256)}, {1 / (256 * 256 * 256)});
603
+ uniform sampler2D u_kernel;
604
+ ''')
605
+
606
+ # add basic unpack functions
607
+ code += '\n\n' + cleandoc('''
608
+ float unpack_unit(vec4 rgba) {
609
+ // return rgba.r; // uncomment this for r32f debugging
610
+ return dot(rgba, bits);
611
+ }
612
+
613
+ float unpack_ieee(vec4 rgba) {
614
+ // return rgba.r; // uncomment this for r32f debugging
615
+ rgba.rgba = rgba.abgr * 255;
616
+ float sign = 1 - step(128 , rgba[0]) * 2;
617
+ float exponent = 2 * mod(rgba[0] , 128) + step(128 , rgba[1]) - 127;
618
+ float mantissa = mod(rgba[1] , 128) * 65536 + rgba[2] * 256 + rgba[3] + float(0x800000);
619
+ return sign * exp2(exponent) * (mantissa * exp2(-23.));
620
+ }
621
+
622
+
623
+ float unpack_interpolate(sampler2D kernel, vec2 uv) {
624
+ // return texture2D(kernel, uv).r; //uncomment this for r32f debug without interpolation
625
+ float kpixel = 1. / kernel_size;
626
+ float u = uv.x / kpixel;
627
+ float v = uv.y;
628
+ float uf = fract(u);
629
+ u = (u - uf) * kpixel;
630
+ float d0 = unpack_unit(texture2D(kernel, vec2(u, v)));
631
+ float d1 = unpack_unit(texture2D(kernel, vec2(u + 1. * kpixel, v)));
632
+ return mix(d0, d1, uf);
633
+ }
634
+ ''')
635
+
636
+ # add 1d, 2d and 3d filter code
637
+ for radius in range(4):
638
+ code += '\n\n' + generate_filter_code(radius + 1)
639
+
640
+ # add call functions for 2D and 3D filters
641
+ # special case for nearest
642
+ code += '\n\n' + cleandoc('''
643
+ vec4 Nearest2D(sampler2D texture, vec2 shape, vec2 uv) {
644
+ return texture2D(texture, uv);
645
+ }
646
+
647
+ vec4 Nearest3D(sampler3D texture, vec3 shape, vec3 uv) {
648
+ return texture3D(texture, uv);
649
+ }
650
+ ''')
705
651
 
706
652
  for i, f in enumerate(filters):
707
- print(f.call_code((i+0.5)/16.0))
653
+ code += '\n\n' + f.call_code((i + 0.5) / 16)
654
+
655
+ print(code)
708
656
 
709
657
 
710
658
  if __name__ == "__main__":