class_docstr: Shader program object
  
  A Program is an object to which shaders can be attached and linked to
  create the final program.
  
  Uniforms and attributes can be set using indexing: e.g.
  ``program['a_pos'] = pos_data`` and ``program['u_color'] = (1, 0, 0)``.
  
  Parameters
  ----------
  vert : str
      The vertex shader to be used by this program
  frag : str
      The fragment shader to be used by this program
  count : int (optional)
      The program will prepare a structured vertex buffer of count
      vertices. All attributes set using ``prog['attr'] = X`` will
      be combined into a structured vbo with interleaved elements, which
      is more efficient than having one vbo per attribute.
  
  Notes
  -----
  If several shaders are specified, only one can contain the main
  function. OpenGL ES 2.0 does not support a list of shaders.
class_docstr_tok: ["Shader","program","object","A","Program","is","an","object","to","which","shaders","can","be","attached","and","linked","to","create","the","final","program",".","Uniforms","and","attributes","can","be","set","using","indexing",":","e.g",".","``","program","[","'a_pos","'","]","=","pos_data","``","and","``","program","[","'u_color","'","]","=","(","1",",","0",",","0",")","``",".","Parameters","--","--","--","--","--","vert",":","str","The","vertex","shader","to","be","used","by","this","program","frag",":","str","The","fragment","shader","to","be","used","by","this","program","count",":","int","(","optional",")","The","program","will","prepare","a","structured","vertex","buffer","of","count","vertices",".","All","attributes","set","using","``","prog","[","'attr","'","]","=","X","``","will","be","combined","into","a","structured","vbo","with","interleaved","elements",",","which","is","more","efficient","than","having","one","vbo","per","attribute",".","Notes","--","--","-","If","several","shaders","are","specified",",","only","one","can","contain","the","main","function",".","OpenGL","ES","2.0","does","not","support","a","list","of","shaders","."]
code: def __init__(self, vert=None, frag=None, count=0):
      GLObject.__init__(self)
  
      # Init source code for vertex and fragment shader
      self._shaders = None, None
  
      # Init description of variables obtained from source code
      self._code_variables = {}  # name -> (kind, type_, name)
      # Init user-defined data for attributes and uniforms
      self._user_variables = {}  # name -> data / buffer / texture
      # Init pending user-defined data
      self._pending_variables = {}  # name -> data
  
      # NOTE: we *could* allow vert and frag to be a tuple/list of shaders,
      # but that would complicate the GLIR implementation, and it seems
      # unncessary
  
      # Check and set shaders
      if isinstance(vert, str) and isinstance(frag, str):
          self.set_shaders(vert, frag)
      elif not (vert is None and frag is None):
          raise ValueError(
              "Vert and frag must either both be str or None"
          )
  
      # Build associated structured vertex buffer if count is given.
      # This makes it easy to create a structured vertex buffer
      # without having to create a numpy array with structured dtype.
      # All assignments must be done before the GLIR commands are
      # sent away for parsing (in draw) though.
      self._count = count
      self._buffer = None  # Set to None in draw()
      if self._count > 0:
          dtype = []
          for kind, type_, name, size in self._code_variables.values():
              if kind == "attribute":
                  dt, numel = self._gtypes[type_]
                  dtype.append(
                      (name, dt, numel) if numel != 1 else (name, dt)
                  )
          self._buffer = np.zeros(self._count, dtype=dtype)
          self.bind(VertexBuffer(self._buffer))
  
imports: import re
  import numpy
  from .globject import GLObject
  from .buffer import VertexBuffer, IndexBuffer, DataBuffer
  from .texture import BaseTexture, Texture2D, Texture3D, Texture1D, TextureCube
  from ..util import logger
  from .util import check_enum
  from .context import get_current_canvas
  from .preprocessor import preprocess
label_desc: Use image node_id 1 to create a new Program object from inherited base classes: GLObject with example: obj = Program(vert, frag, count)