We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Memory Leak when adding GLScatterPlotItem
I have found that adding and removing the same `GLScatterPlotItem` in a `GLViewWidget` causes a memory leak. Here is a script to demonstrate the behavior:

``` python
import numpy as np
from PySide import QtCore, QtGui
import sys

import pyqtgraph.opengl as gl

num_points = 10
refresh_interval = 1  # ms


class PlotWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)

        # Basic layout setup
        self.viewWidget = gl.GLViewWidget()
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.viewWidget)
        self.setLayout(layout)

        # Create out scatter plot item. Note that this leak only happens with
        # scatter items, not with line or mesh items.
        pos = np.random.rand(num_points, 3)
        self.scatter = gl.GLScatterPlotItem(pos=pos)
        self.viewWidget.addItem(self.scatter)

        # Create and run timer to repeatedly add and remove scatter item.
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self._add_remove)
        self.timer.start(refresh_interval)

    def _add_remove(self):
        self.viewWidget.addItem(self.scatter)
        self.viewWidget.removeItem(self.scatter)

    def sizeHint(self):
        return QtCore.QSize(800, 800)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)

    widget = PlotWidget()
    widget.show()

    sys.exit(app.exec_())
```

I have tried using other plot items (like `GLLinePlotItem` and `GLAxisItem`), and I do not see the memory leak, so it seems only GLScatterPlotItem creates the leak. I have also tried using PyQt4 and the script still generates a memory leak.

Could this be a problem with binding data to the OpenGL context, but then that data does not get released when the plot item is removed? This is my current theory, because I used the `objgraph` package to find new Python objects every few seconds, and it couldn't find any. Furthermore, `GLScatterPlotItem` is the only item I tested that has a non-trivial `initializeGL` method.

I will do more investigation. If there is a workaround, I would appreciate that too :)

Thanks in advance for any help!


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pyqtgraph/opengl/items/GLScatterPlotItem.py`
Content:
```
1 from OpenGL.GL import *
2 from OpenGL.arrays import vbo
3 from .. GLGraphicsItem import GLGraphicsItem
4 from .. import shaders
5 from ... import QtGui
6 import numpy as np
7 
8 __all__ = ['GLScatterPlotItem']
9 
10 class GLScatterPlotItem(GLGraphicsItem):
11     """Draws points at a list of 3D positions."""
12     
13     def __init__(self, **kwds):
14         GLGraphicsItem.__init__(self)
15         glopts = kwds.pop('glOptions', 'additive')
16         self.setGLOptions(glopts)
17         self.pos = []
18         self.size = 10
19         self.color = [1.0,1.0,1.0,0.5]
20         self.pxMode = True
21         #self.vbo = {}      ## VBO does not appear to improve performance very much.
22         self.setData(**kwds)
23     
24     def setData(self, **kwds):
25         """
26         Update the data displayed by this item. All arguments are optional; 
27         for example it is allowed to update spot positions while leaving 
28         colors unchanged, etc.
29         
30         ====================  ==================================================
31         **Arguments:**
32         pos                   (N,3) array of floats specifying point locations.
33         color                 (N,4) array of floats (0.0-1.0) specifying
34                               spot colors OR a tuple of floats specifying
35                               a single color for all spots.
36         size                  (N,) array of floats specifying spot sizes or 
37                               a single value to apply to all spots.
38         pxMode                If True, spot sizes are expressed in pixels. 
39                               Otherwise, they are expressed in item coordinates.
40         ====================  ==================================================
41         """
42         args = ['pos', 'color', 'size', 'pxMode']
43         for k in kwds.keys():
44             if k not in args:
45                 raise Exception('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args)))
46             
47         args.remove('pxMode')
48         for arg in args:
49             if arg in kwds:
50                 setattr(self, arg, kwds[arg])
51                 #self.vbo.pop(arg, None)
52                 
53         self.pxMode = kwds.get('pxMode', self.pxMode)
54         self.update()
55 
56     def initializeGL(self):
57         
58         ## Generate texture for rendering points
59         w = 64
60         def fn(x,y):
61             r = ((x-w/2.)**2 + (y-w/2.)**2) ** 0.5
62             return 255 * (w/2. - np.clip(r, w/2.-1.0, w/2.))
63         pData = np.empty((w, w, 4))
64         pData[:] = 255
65         pData[:,:,3] = np.fromfunction(fn, pData.shape[:2])
66         #print pData.shape, pData.min(), pData.max()
67         pData = pData.astype(np.ubyte)
68         
69         self.pointTexture = glGenTextures(1)
70         glActiveTexture(GL_TEXTURE0)
71         glEnable(GL_TEXTURE_2D)
72         glBindTexture(GL_TEXTURE_2D, self.pointTexture)
73         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pData.shape[0], pData.shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, pData)
74         
75         self.shader = shaders.getShaderProgram('pointSprite')
76         
77     #def getVBO(self, name):
78         #if name not in self.vbo:
79             #self.vbo[name] = vbo.VBO(getattr(self, name).astype('f'))
80         #return self.vbo[name]
81         
82     #def setupGLState(self):
83         #"""Prepare OpenGL state for drawing. This function is called immediately before painting."""
84         ##glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)  ## requires z-sorting to render properly.
85         #glBlendFunc(GL_SRC_ALPHA, GL_ONE)
86         #glEnable( GL_BLEND )
87         #glEnable( GL_ALPHA_TEST )
88         #glDisable( GL_DEPTH_TEST )
89         
90         ##glEnable( GL_POINT_SMOOTH )
91 
92         ##glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)
93         ##glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, (0, 0, -1e-3))
94         ##glPointParameterfv(GL_POINT_SIZE_MAX, (65500,))
95         ##glPointParameterfv(GL_POINT_SIZE_MIN, (0,))
96         
97     def paint(self):
98         self.setupGLState()
99         
100         glEnable(GL_POINT_SPRITE)
101         
102         glActiveTexture(GL_TEXTURE0)
103         glEnable( GL_TEXTURE_2D )
104         glBindTexture(GL_TEXTURE_2D, self.pointTexture)
105     
106         glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE)
107         #glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)    ## use texture color exactly
108         #glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE )  ## texture modulates current color
109         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
110         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
111         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
112         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
113         glEnable(GL_PROGRAM_POINT_SIZE)
114         
115             
116         with self.shader:
117             #glUniform1i(self.shader.uniform('texture'), 0)  ## inform the shader which texture to use
118             glEnableClientState(GL_VERTEX_ARRAY)
119             try:
120                 pos = self.pos
121                 #if pos.ndim > 2:
122                     #pos = pos.reshape((reduce(lambda a,b: a*b, pos.shape[:-1]), pos.shape[-1]))
123                 glVertexPointerf(pos)
124             
125                 if isinstance(self.color, np.ndarray):
126                     glEnableClientState(GL_COLOR_ARRAY)
127                     glColorPointerf(self.color)
128                 else:
129                     if isinstance(self.color, QtGui.QColor):
130                         glColor4f(*fn.glColor(self.color))
131                     else:
132                         glColor4f(*self.color)
133                 
134                 if not self.pxMode or isinstance(self.size, np.ndarray):
135                     glEnableClientState(GL_NORMAL_ARRAY)
136                     norm = np.empty(pos.shape)
137                     if self.pxMode:
138                         norm[...,0] = self.size
139                     else:
140                         gpos = self.mapToView(pos.transpose()).transpose()
141                         pxSize = self.view().pixelSize(gpos)
142                         norm[...,0] = self.size / pxSize
143                     
144                     glNormalPointerf(norm)
145                 else:
146                     glNormal3f(self.size, 0, 0)  ## vertex shader uses norm.x to determine point size
147                     #glPointSize(self.size)
148                 glDrawArrays(GL_POINTS, 0, int(pos.size / pos.shape[-1]))
149             finally:
150                 glDisableClientState(GL_NORMAL_ARRAY)
151                 glDisableClientState(GL_VERTEX_ARRAY)
152                 glDisableClientState(GL_COLOR_ARRAY)
153                 #posVBO.unbind()
154                 
155         #for i in range(len(self.pos)):
156             #pos = self.pos[i]
157             
158             #if isinstance(self.color, np.ndarray):
159                 #color = self.color[i]
160             #else:
161                 #color = self.color
162             #if isinstance(self.color, QtGui.QColor):
163                 #color = fn.glColor(self.color)
164                 
165             #if isinstance(self.size, np.ndarray):
166                 #size = self.size[i]
167             #else:
168                 #size = self.size
169                 
170             #pxSize = self.view().pixelSize(QtGui.QVector3D(*pos))
171             
172             #glPointSize(size / pxSize)
173             #glBegin( GL_POINTS )
174             #glColor4f(*color)  # x is blue
175             ##glNormal3f(size, 0, 0)
176             #glVertex3f(*pos)
177             #glEnd()
178 
179         
180         
181         
182         
183
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pyqtgraph/opengl/items/GLScatterPlotItem.py b/pyqtgraph/opengl/items/GLScatterPlotItem.py
--- a/pyqtgraph/opengl/items/GLScatterPlotItem.py
+++ b/pyqtgraph/opengl/items/GLScatterPlotItem.py
@@ -66,7 +66,8 @@
         #print pData.shape, pData.min(), pData.max()
         pData = pData.astype(np.ubyte)
         
-        self.pointTexture = glGenTextures(1)
+        if getattr(self, "pointTexture", None) is None:
+            self.pointTexture = glGenTextures(1)
         glActiveTexture(GL_TEXTURE0)
         glEnable(GL_TEXTURE_2D)
         glBindTexture(GL_TEXTURE_2D, self.pointTexture)

{"golden_diff": "diff --git a/pyqtgraph/opengl/items/GLScatterPlotItem.py b/pyqtgraph/opengl/items/GLScatterPlotItem.py\n--- a/pyqtgraph/opengl/items/GLScatterPlotItem.py\n+++ b/pyqtgraph/opengl/items/GLScatterPlotItem.py\n@@ -66,7 +66,8 @@\n         #print pData.shape, pData.min(), pData.max()\n         pData = pData.astype(np.ubyte)\n         \n-        self.pointTexture = glGenTextures(1)\n+        if getattr(self, \"pointTexture\", None) is None:\n+            self.pointTexture = glGenTextures(1)\n         glActiveTexture(GL_TEXTURE0)\n         glEnable(GL_TEXTURE_2D)\n         glBindTexture(GL_TEXTURE_2D, self.pointTexture)\n", "issue": "Memory Leak when adding GLScatterPlotItem\nI have found that adding and removing the same `GLScatterPlotItem` in a `GLViewWidget` causes a memory leak. Here is a script to demonstrate the behavior:\n\n``` python\nimport numpy as np\nfrom PySide import QtCore, QtGui\nimport sys\n\nimport pyqtgraph.opengl as gl\n\nnum_points = 10\nrefresh_interval = 1  # ms\n\n\nclass PlotWidget(QtGui.QWidget):\n\n    def __init__(self, parent=None):\n        super().__init__(parent)\n\n        # Basic layout setup\n        self.viewWidget = gl.GLViewWidget()\n        layout = QtGui.QVBoxLayout()\n        layout.addWidget(self.viewWidget)\n        self.setLayout(layout)\n\n        # Create out scatter plot item. Note that this leak only happens with\n        # scatter items, not with line or mesh items.\n        pos = np.random.rand(num_points, 3)\n        self.scatter = gl.GLScatterPlotItem(pos=pos)\n        self.viewWidget.addItem(self.scatter)\n\n        # Create and run timer to repeatedly add and remove scatter item.\n        self.timer = QtCore.QTimer()\n        self.timer.timeout.connect(self._add_remove)\n        self.timer.start(refresh_interval)\n\n    def _add_remove(self):\n        self.viewWidget.addItem(self.scatter)\n        self.viewWidget.removeItem(self.scatter)\n\n    def sizeHint(self):\n        return QtCore.QSize(800, 800)\n\n\nif __name__ == \"__main__\":\n    app = QtGui.QApplication(sys.argv)\n\n    widget = PlotWidget()\n    widget.show()\n\n    sys.exit(app.exec_())\n```\n\nI have tried using other plot items (like `GLLinePlotItem` and `GLAxisItem`), and I do not see the memory leak, so it seems only GLScatterPlotItem creates the leak. I have also tried using PyQt4 and the script still generates a memory leak.\n\nCould this be a problem with binding data to the OpenGL context, but then that data does not get released when the plot item is removed? This is my current theory, because I used the `objgraph` package to find new Python objects every few seconds, and it couldn't find any. Furthermore, `GLScatterPlotItem` is the only item I tested that has a non-trivial `initializeGL` method.\n\nI will do more investigation. If there is a workaround, I would appreciate that too :)\n\nThanks in advance for any help!\n\n", "before_files": [{"content": "from OpenGL.GL import *\nfrom OpenGL.arrays import vbo\nfrom .. GLGraphicsItem import GLGraphicsItem\nfrom .. import shaders\nfrom ... import QtGui\nimport numpy as np\n\n__all__ = ['GLScatterPlotItem']\n\nclass GLScatterPlotItem(GLGraphicsItem):\n    \"\"\"Draws points at a list of 3D positions.\"\"\"\n    \n    def __init__(self, **kwds):\n        GLGraphicsItem.__init__(self)\n        glopts = kwds.pop('glOptions', 'additive')\n        self.setGLOptions(glopts)\n        self.pos = []\n        self.size = 10\n        self.color = [1.0,1.0,1.0,0.5]\n        self.pxMode = True\n        #self.vbo = {}      ## VBO does not appear to improve performance very much.\n        self.setData(**kwds)\n    \n    def setData(self, **kwds):\n        \"\"\"\n        Update the data displayed by this item. All arguments are optional; \n        for example it is allowed to update spot positions while leaving \n        colors unchanged, etc.\n        \n        ====================  ==================================================\n        **Arguments:**\n        pos                   (N,3) array of floats specifying point locations.\n        color                 (N,4) array of floats (0.0-1.0) specifying\n                              spot colors OR a tuple of floats specifying\n                              a single color for all spots.\n        size                  (N,) array of floats specifying spot sizes or \n                              a single value to apply to all spots.\n        pxMode                If True, spot sizes are expressed in pixels. \n                              Otherwise, they are expressed in item coordinates.\n        ====================  ==================================================\n        \"\"\"\n        args = ['pos', 'color', 'size', 'pxMode']\n        for k in kwds.keys():\n            if k not in args:\n                raise Exception('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args)))\n            \n        args.remove('pxMode')\n        for arg in args:\n            if arg in kwds:\n                setattr(self, arg, kwds[arg])\n                #self.vbo.pop(arg, None)\n                \n        self.pxMode = kwds.get('pxMode', self.pxMode)\n        self.update()\n\n    def initializeGL(self):\n        \n        ## Generate texture for rendering points\n        w = 64\n        def fn(x,y):\n            r = ((x-w/2.)**2 + (y-w/2.)**2) ** 0.5\n            return 255 * (w/2. - np.clip(r, w/2.-1.0, w/2.))\n        pData = np.empty((w, w, 4))\n        pData[:] = 255\n        pData[:,:,3] = np.fromfunction(fn, pData.shape[:2])\n        #print pData.shape, pData.min(), pData.max()\n        pData = pData.astype(np.ubyte)\n        \n        self.pointTexture = glGenTextures(1)\n        glActiveTexture(GL_TEXTURE0)\n        glEnable(GL_TEXTURE_2D)\n        glBindTexture(GL_TEXTURE_2D, self.pointTexture)\n        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pData.shape[0], pData.shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, pData)\n        \n        self.shader = shaders.getShaderProgram('pointSprite')\n        \n    #def getVBO(self, name):\n        #if name not in self.vbo:\n            #self.vbo[name] = vbo.VBO(getattr(self, name).astype('f'))\n        #return self.vbo[name]\n        \n    #def setupGLState(self):\n        #\"\"\"Prepare OpenGL state for drawing. This function is called immediately before painting.\"\"\"\n        ##glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)  ## requires z-sorting to render properly.\n        #glBlendFunc(GL_SRC_ALPHA, GL_ONE)\n        #glEnable( GL_BLEND )\n        #glEnable( GL_ALPHA_TEST )\n        #glDisable( GL_DEPTH_TEST )\n        \n        ##glEnable( GL_POINT_SMOOTH )\n\n        ##glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)\n        ##glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, (0, 0, -1e-3))\n        ##glPointParameterfv(GL_POINT_SIZE_MAX, (65500,))\n        ##glPointParameterfv(GL_POINT_SIZE_MIN, (0,))\n        \n    def paint(self):\n        self.setupGLState()\n        \n        glEnable(GL_POINT_SPRITE)\n        \n        glActiveTexture(GL_TEXTURE0)\n        glEnable( GL_TEXTURE_2D )\n        glBindTexture(GL_TEXTURE_2D, self.pointTexture)\n    \n        glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE)\n        #glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)    ## use texture color exactly\n        #glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE )  ## texture modulates current color\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)\n        glEnable(GL_PROGRAM_POINT_SIZE)\n        \n            \n        with self.shader:\n            #glUniform1i(self.shader.uniform('texture'), 0)  ## inform the shader which texture to use\n            glEnableClientState(GL_VERTEX_ARRAY)\n            try:\n                pos = self.pos\n                #if pos.ndim > 2:\n                    #pos = pos.reshape((reduce(lambda a,b: a*b, pos.shape[:-1]), pos.shape[-1]))\n                glVertexPointerf(pos)\n            \n                if isinstance(self.color, np.ndarray):\n                    glEnableClientState(GL_COLOR_ARRAY)\n                    glColorPointerf(self.color)\n                else:\n                    if isinstance(self.color, QtGui.QColor):\n                        glColor4f(*fn.glColor(self.color))\n                    else:\n                        glColor4f(*self.color)\n                \n                if not self.pxMode or isinstance(self.size, np.ndarray):\n                    glEnableClientState(GL_NORMAL_ARRAY)\n                    norm = np.empty(pos.shape)\n                    if self.pxMode:\n                        norm[...,0] = self.size\n                    else:\n                        gpos = self.mapToView(pos.transpose()).transpose()\n                        pxSize = self.view().pixelSize(gpos)\n                        norm[...,0] = self.size / pxSize\n                    \n                    glNormalPointerf(norm)\n                else:\n                    glNormal3f(self.size, 0, 0)  ## vertex shader uses norm.x to determine point size\n                    #glPointSize(self.size)\n                glDrawArrays(GL_POINTS, 0, int(pos.size / pos.shape[-1]))\n            finally:\n                glDisableClientState(GL_NORMAL_ARRAY)\n                glDisableClientState(GL_VERTEX_ARRAY)\n                glDisableClientState(GL_COLOR_ARRAY)\n                #posVBO.unbind()\n                \n        #for i in range(len(self.pos)):\n            #pos = self.pos[i]\n            \n            #if isinstance(self.color, np.ndarray):\n                #color = self.color[i]\n            #else:\n                #color = self.color\n            #if isinstance(self.color, QtGui.QColor):\n                #color = fn.glColor(self.color)\n                \n            #if isinstance(self.size, np.ndarray):\n                #size = self.size[i]\n            #else:\n                #size = self.size\n                \n            #pxSize = self.view().pixelSize(QtGui.QVector3D(*pos))\n            \n            #glPointSize(size / pxSize)\n            #glBegin( GL_POINTS )\n            #glColor4f(*color)  # x is blue\n            ##glNormal3f(size, 0, 0)\n            #glVertex3f(*pos)\n            #glEnd()\n\n        \n        \n        \n        \n", "path": "pyqtgraph/opengl/items/GLScatterPlotItem.py"}], "after_files": [{"content": "from OpenGL.GL import *\nfrom OpenGL.arrays import vbo\nfrom .. GLGraphicsItem import GLGraphicsItem\nfrom .. import shaders\nfrom ... import QtGui\nimport numpy as np\n\n__all__ = ['GLScatterPlotItem']\n\nclass GLScatterPlotItem(GLGraphicsItem):\n    \"\"\"Draws points at a list of 3D positions.\"\"\"\n    \n    def __init__(self, **kwds):\n        GLGraphicsItem.__init__(self)\n        glopts = kwds.pop('glOptions', 'additive')\n        self.setGLOptions(glopts)\n        self.pos = []\n        self.size = 10\n        self.color = [1.0,1.0,1.0,0.5]\n        self.pxMode = True\n        #self.vbo = {}      ## VBO does not appear to improve performance very much.\n        self.setData(**kwds)\n    \n    def setData(self, **kwds):\n        \"\"\"\n        Update the data displayed by this item. All arguments are optional; \n        for example it is allowed to update spot positions while leaving \n        colors unchanged, etc.\n        \n        ====================  ==================================================\n        **Arguments:**\n        pos                   (N,3) array of floats specifying point locations.\n        color                 (N,4) array of floats (0.0-1.0) specifying\n                              spot colors OR a tuple of floats specifying\n                              a single color for all spots.\n        size                  (N,) array of floats specifying spot sizes or \n                              a single value to apply to all spots.\n        pxMode                If True, spot sizes are expressed in pixels. \n                              Otherwise, they are expressed in item coordinates.\n        ====================  ==================================================\n        \"\"\"\n        args = ['pos', 'color', 'size', 'pxMode']\n        for k in kwds.keys():\n            if k not in args:\n                raise Exception('Invalid keyword argument: %s (allowed arguments are %s)' % (k, str(args)))\n            \n        args.remove('pxMode')\n        for arg in args:\n            if arg in kwds:\n                setattr(self, arg, kwds[arg])\n                #self.vbo.pop(arg, None)\n                \n        self.pxMode = kwds.get('pxMode', self.pxMode)\n        self.update()\n\n    def initializeGL(self):\n        \n        ## Generate texture for rendering points\n        w = 64\n        def fn(x,y):\n            r = ((x-w/2.)**2 + (y-w/2.)**2) ** 0.5\n            return 255 * (w/2. - np.clip(r, w/2.-1.0, w/2.))\n        pData = np.empty((w, w, 4))\n        pData[:] = 255\n        pData[:,:,3] = np.fromfunction(fn, pData.shape[:2])\n        #print pData.shape, pData.min(), pData.max()\n        pData = pData.astype(np.ubyte)\n        \n        if getattr(self, \"pointTexture\", None) is None:\n            self.pointTexture = glGenTextures(1)\n        glActiveTexture(GL_TEXTURE0)\n        glEnable(GL_TEXTURE_2D)\n        glBindTexture(GL_TEXTURE_2D, self.pointTexture)\n        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pData.shape[0], pData.shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, pData)\n        \n        self.shader = shaders.getShaderProgram('pointSprite')\n        \n    #def getVBO(self, name):\n        #if name not in self.vbo:\n            #self.vbo[name] = vbo.VBO(getattr(self, name).astype('f'))\n        #return self.vbo[name]\n        \n    #def setupGLState(self):\n        #\"\"\"Prepare OpenGL state for drawing. This function is called immediately before painting.\"\"\"\n        ##glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)  ## requires z-sorting to render properly.\n        #glBlendFunc(GL_SRC_ALPHA, GL_ONE)\n        #glEnable( GL_BLEND )\n        #glEnable( GL_ALPHA_TEST )\n        #glDisable( GL_DEPTH_TEST )\n        \n        ##glEnable( GL_POINT_SMOOTH )\n\n        ##glHint(GL_POINT_SMOOTH_HINT, GL_NICEST)\n        ##glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, (0, 0, -1e-3))\n        ##glPointParameterfv(GL_POINT_SIZE_MAX, (65500,))\n        ##glPointParameterfv(GL_POINT_SIZE_MIN, (0,))\n        \n    def paint(self):\n        self.setupGLState()\n        \n        glEnable(GL_POINT_SPRITE)\n        \n        glActiveTexture(GL_TEXTURE0)\n        glEnable( GL_TEXTURE_2D )\n        glBindTexture(GL_TEXTURE_2D, self.pointTexture)\n    \n        glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE)\n        #glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)    ## use texture color exactly\n        #glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE )  ## texture modulates current color\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)\n        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)\n        glEnable(GL_PROGRAM_POINT_SIZE)\n        \n            \n        with self.shader:\n            #glUniform1i(self.shader.uniform('texture'), 0)  ## inform the shader which texture to use\n            glEnableClientState(GL_VERTEX_ARRAY)\n            try:\n                pos = self.pos\n                #if pos.ndim > 2:\n                    #pos = pos.reshape((reduce(lambda a,b: a*b, pos.shape[:-1]), pos.shape[-1]))\n                glVertexPointerf(pos)\n            \n                if isinstance(self.color, np.ndarray):\n                    glEnableClientState(GL_COLOR_ARRAY)\n                    glColorPointerf(self.color)\n                else:\n                    if isinstance(self.color, QtGui.QColor):\n                        glColor4f(*fn.glColor(self.color))\n                    else:\n                        glColor4f(*self.color)\n                \n                if not self.pxMode or isinstance(self.size, np.ndarray):\n                    glEnableClientState(GL_NORMAL_ARRAY)\n                    norm = np.empty(pos.shape)\n                    if self.pxMode:\n                        norm[...,0] = self.size\n                    else:\n                        gpos = self.mapToView(pos.transpose()).transpose()\n                        pxSize = self.view().pixelSize(gpos)\n                        norm[...,0] = self.size / pxSize\n                    \n                    glNormalPointerf(norm)\n                else:\n                    glNormal3f(self.size, 0, 0)  ## vertex shader uses norm.x to determine point size\n                    #glPointSize(self.size)\n                glDrawArrays(GL_POINTS, 0, int(pos.size / pos.shape[-1]))\n            finally:\n                glDisableClientState(GL_NORMAL_ARRAY)\n                glDisableClientState(GL_VERTEX_ARRAY)\n                glDisableClientState(GL_COLOR_ARRAY)\n                #posVBO.unbind()\n                \n        #for i in range(len(self.pos)):\n            #pos = self.pos[i]\n            \n            #if isinstance(self.color, np.ndarray):\n                #color = self.color[i]\n            #else:\n                #color = self.color\n            #if isinstance(self.color, QtGui.QColor):\n                #color = fn.glColor(self.color)\n                \n            #if isinstance(self.size, np.ndarray):\n                #size = self.size[i]\n            #else:\n                #size = self.size\n                \n            #pxSize = self.view().pixelSize(QtGui.QVector3D(*pos))\n            \n            #glPointSize(size / pxSize)\n            #glBegin( GL_POINTS )\n            #glColor4f(*color)  # x is blue\n            ##glNormal3f(size, 0, 0)\n            #glVertex3f(*pos)\n            #glEnd()\n\n        \n        \n        \n        \n", "path": "pyqtgraph/opengl/items/GLScatterPlotItem.py"}]}