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.
- vispy/app/backends/_glfw.py +2 -2
- vispy/app/backends/_pyglet.py +8 -2
- vispy/app/backends/_qt.py +88 -63
- vispy/app/backends/_wx.py +6 -1
- vispy/app/canvas.py +4 -2
- vispy/app/tests/test_canvas.py +52 -1
- vispy/app/tests/test_context.py +5 -3
- vispy/color/color_array.py +8 -1
- vispy/color/colormap.py +5 -25
- vispy/geometry/meshdata.py +76 -38
- vispy/geometry/rect.py +6 -0
- vispy/geometry/tests/test_meshdata.py +72 -0
- vispy/gloo/buffer.py +12 -0
- vispy/gloo/gl/_constants.py +9 -5
- vispy/gloo/gl/_es2.py +8 -4
- vispy/gloo/gl/_gl2.py +2 -3
- vispy/gloo/gl/_proxy.py +1 -1
- vispy/gloo/gl/_pyopengl2.py +12 -7
- vispy/gloo/gl/tests/test_names.py +3 -0
- vispy/gloo/glir.py +26 -13
- vispy/gloo/program.py +39 -22
- vispy/gloo/tests/test_program.py +9 -2
- vispy/gloo/tests/test_texture.py +19 -2
- vispy/gloo/texture.py +46 -16
- vispy/gloo/wrappers.py +4 -2
- vispy/glsl/build_spatial_filters.py +241 -293
- vispy/glsl/misc/spatial-filters.frag +1299 -254
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +2 -2
- vispy/io/image.py +1 -1
- vispy/io/stl.py +3 -3
- vispy/scene/cameras/base_camera.py +6 -2
- vispy/scene/cameras/panzoom.py +10 -14
- vispy/scene/cameras/perspective.py +6 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_perspective.py +37 -0
- vispy/scene/cameras/turntable.py +39 -23
- vispy/scene/canvas.py +9 -5
- vispy/scene/events.py +9 -0
- vispy/scene/node.py +19 -2
- vispy/scene/tests/test_canvas.py +30 -1
- vispy/scene/tests/test_visuals.py +113 -0
- vispy/scene/visuals.py +6 -1
- vispy/scene/widgets/viewbox.py +3 -2
- vispy/testing/_runners.py +6 -12
- vispy/testing/_testing.py +3 -4
- vispy/util/check_environment.py +4 -4
- vispy/util/gallery_scraper.py +50 -32
- vispy/util/tests/test_gallery_scraper.py +2 -0
- vispy/util/transforms.py +1 -1
- vispy/util/wrappers.py +1 -1
- vispy/version.py +2 -3
- vispy/visuals/__init__.py +2 -0
- vispy/visuals/_scalable_textures.py +20 -17
- vispy/visuals/collections/array_list.py +3 -3
- vispy/visuals/collections/base_collection.py +1 -1
- vispy/visuals/ellipse.py +1 -1
- vispy/visuals/filters/__init__.py +3 -2
- vispy/visuals/filters/base_filter.py +120 -0
- vispy/visuals/filters/clipping_planes.py +24 -12
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +61 -6
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/graphs/graph.py +1 -1
- vispy/visuals/image.py +114 -26
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +1 -1
- vispy/visuals/line/dash_atlas.py +46 -41
- vispy/visuals/line/line.py +2 -5
- vispy/visuals/markers.py +310 -384
- vispy/visuals/mesh.py +2 -2
- vispy/visuals/shaders/function.py +3 -0
- vispy/visuals/shaders/tests/test_function.py +6 -0
- vispy/visuals/tests/test_axis.py +2 -2
- vispy/visuals/tests/test_image.py +92 -2
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_markers.py +6 -0
- vispy/visuals/tests/test_mesh.py +17 -0
- vispy/visuals/tests/test_text.py +11 -0
- vispy/visuals/tests/test_volume.py +218 -12
- vispy/visuals/text/_sdf_cpu.cp38-win_amd64.pyd +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +21 -23
- vispy/visuals/text/text.py +9 -3
- vispy/visuals/tube.py +2 -2
- vispy/visuals/visual.py +144 -3
- vispy/visuals/volume.py +300 -131
- {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/LICENSE.txt +1 -1
- {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/METADATA +218 -198
- {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/RECORD +93 -96
- {vispy-0.9.5.dist-info → vispy-0.14.0.dist-info}/WHEEL +1 -1
- vispy/glsl/antialias/__init__.py +0 -0
- vispy/glsl/arrowheads/__init__.py +0 -0
- vispy/glsl/arrows/__init__.py +0 -0
- vispy/glsl/collections/__init__.py +0 -0
- vispy/glsl/colormaps/__init__.py +0 -0
- vispy/glsl/lines/__init__.py +0 -0
- vispy/glsl/markers/__init__.py +0 -0
- vispy/glsl/math/__init__.py +0 -0
- vispy/glsl/misc/__init__.py +0 -0
- vispy/glsl/transforms/__init__.py +0 -0
- {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
|
-
|
|
252
|
-
|
|
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(
|
|
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
|
-
|
|
494
|
-
if
|
|
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(['
|
|
498
|
-
raise RuntimeError('All attributes must have the same size, got:\n'
|
|
499
|
-
|
|
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)
|
vispy/gloo/tests/test_program.py
CHANGED
|
@@ -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[-
|
|
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[-
|
|
284
|
+
assert len(glir_cmd[-2]) == 3
|
|
278
285
|
|
|
279
286
|
# Invalid mode
|
|
280
287
|
self.assertRaises(ValueError, program.draw, 'nogeometricshape')
|
vispy/gloo/tests/test_texture.py
CHANGED
|
@@ -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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return
|
|
30
|
-
|
|
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 =
|
|
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
|
|