def get_package(self, name) -> '<STR_LIT>':

name, cls_name = parse_package_string(name)<EOL>try:<EOL><INDENT>return self.package_map[name]<EOL><DEDENT>except KeyError:<EOL><INDENT>raise EffectError("<STR_LIT>".format(name))<EOL><DEDENT>

Get a package by python path. Can also contain path to an effect.

Args:
    name (str): Path to effect package or effect

Returns:
    The requested EffectPackage

Raises:
    EffectError when no package is found


def find_effect_class(self, path) -> Type[Effect]:

package_name, class_name = parse_package_string(path)<EOL>if package_name:<EOL><INDENT>package = self.get_package(package_name)<EOL>return package.find_effect_class(class_name, raise_for_error=True)<EOL><DEDENT>for package in self.packages:<EOL><INDENT>effect_cls = package.find_effect_class(class_name)<EOL>if effect_cls:<EOL><INDENT>return effect_cls<EOL><DEDENT><DEDENT>raise EffectError("<STR_LIT>".format(class_name))<EOL>

Find an effect class by class name or full python path to class

Args:
    path (str): effect class name or full python path to effect class

Returns:
    Effect class

Raises:
    EffectError if no class is found


def runnable_effects(self) -> List[Type[Effect]]:

return [cls for cls in self.effect_classes if cls.runnable]<EOL>

Returns the runnable effect in the package


try:<EOL><INDENT>self.package = importlib.import_module(self.name)<EOL><DEDENT>except ModuleNotFoundError:<EOL><INDENT>raise ModuleNotFoundError("<STR_LIT>".format(self.name))<EOL><DEDENT>


self.effect_classes = []<EOL>for _, cls in inspect.getmembers(self.effect_module):<EOL><INDENT>if inspect.isclass(cls):<EOL><INDENT>if cls == Effect:<EOL><INDENT>continue<EOL><DEDENT>if issubclass(cls, Effect):<EOL><INDENT>self.effect_classes.append(cls)<EOL>self.effect_class_map[cls.__name__] = cls<EOL>cls._name = "<STR_LIT>".format(self.effect_module_name, cls.__name__)<EOL><DEDENT><DEDENT><DEDENT>

Iterate the module attributes picking out effects


<EOL>try:<EOL><INDENT>name = '<STR_LIT>'.format(self.name, '<STR_LIT>')<EOL>self.dependencies_module = importlib.import_module(name)<EOL><DEDENT>except ModuleNotFoundError as err:<EOL><INDENT>raise EffectError(<EOL>(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>).format(self.name, err))<EOL><DEDENT>try:<EOL><INDENT>self.resources = getattr(self.dependencies_module, '<STR_LIT>')<EOL><DEDENT>except AttributeError:<EOL><INDENT>raise EffectError("<STR_LIT>".format(name))<EOL><DEDENT>if not isinstance(self.resources, list):<EOL><INDENT>raise EffectError(<EOL>"<STR_LIT>".format(<EOL>name, type(self.resources)))<EOL><DEDENT>try:<EOL><INDENT>self.effect_packages = getattr(self.dependencies_module, '<STR_LIT>')<EOL><DEDENT>except AttributeError:<EOL><INDENT>raise EffectError("<STR_LIT>".format(name))<EOL><DEDENT>if not isinstance(self.effect_packages, list):<EOL><INDENT>raise EffectError(<EOL>"<STR_LIT>".format(<EOL>name, type(self.effects)))<EOL><DEDENT>


def _translate_string(self, data, length):

for index, char in enumerate(data):<EOL><INDENT>if index == length:<EOL><INDENT>break<EOL><DEDENT>yield self._meta.characters - <NUM_LIT:1> - self._ct[char]<EOL><DEDENT>

Translate string into character texture positions


self._ct = [-<NUM_LIT:1>] * <NUM_LIT><EOL>index = <NUM_LIT:0><EOL>for crange in self._meta.character_ranges:<EOL><INDENT>for cpos in range(crange['<STR_LIT>'], crange['<STR_LIT>'] + <NUM_LIT:1>):<EOL><INDENT>self._ct[cpos] = index<EOL>index += <NUM_LIT:1><EOL><DEDENT><DEDENT>

Generate character translation map (latin1 pos to texture pos)


def __init__(self, area, text_lines=None, texture_height=<NUM_LIT:64>):

super().__init__(area, text_lines=text_lines)<EOL>self._texture_height = texture_height<EOL>self._texture_width = <NUM_LIT:0><EOL>self._quad = self._create_vao()<EOL>self._quad_program = self.get_program('<STR_LIT>')<EOL>self._fbo = None<EOL>self._texture_width = int(<EOL>round(self._meta.char_aspect_wh * self._texture_height * self.area[<NUM_LIT:0>] / self.area[<NUM_LIT:1>], <NUM_LIT:0>)<EOL>)<EOL>self.aspect_ratio = self._texture_width / self._texture_height<EOL>self._fbo = self.ctx.framebuffer(self.ctx.texture((self._texture_width, self._texture_height), <NUM_LIT:4>))<EOL>self._fbo_scope = self.ctx.scope(self._fbo)<EOL>

:param area: (x, y) Text area size (number of characters)
:param size: Text size
:param text: Initial text


def __init__(self, area, text_lines=None, aspect_ratio=<NUM_LIT:1.0>):

super().__init__()<EOL>self.area = area<EOL>self._text_lines = text_lines<EOL>self._projection_bytes = None<EOL>self._aspect_ratio = <NUM_LIT:1.0><EOL>self.aspect_ratio = aspect_ratio<EOL>self._vao = None<EOL>self._config = self.get_data('<STR_LIT>')<EOL>self._texture = self.get_texture('<STR_LIT>')<EOL>self._program = self.get_program('<STR_LIT>')<EOL>self._string_buffer = None<EOL>self._init(FontMeta(self._config))<EOL>self._string_buffer = self.ctx.buffer(reserve=self.area[<NUM_LIT:0>] * <NUM_LIT:4> * self.area[<NUM_LIT:1>])<EOL>self._string_buffer.clear(chunk=b'<STR_LIT>')<EOL>pos = self.ctx.buffer(data=bytes([<NUM_LIT:0>] * <NUM_LIT:4> * <NUM_LIT:3>))<EOL>self._vao = VAO("<STR_LIT>", mode=moderngl.POINTS)<EOL>self._vao.buffer(pos, '<STR_LIT>', '<STR_LIT>')<EOL>self._vao.buffer(self._string_buffer, '<STR_LIT>', '<STR_LIT>', per_instance=True)<EOL>self.text_lines = self._text_lines<EOL>

:param area: (x, y) Text area size (number of characters)
:param size: Text size
:param text: Initial text lines


try:<EOL><INDENT>module_path, class_name = dotted_path.rsplit('<STR_LIT:.>', <NUM_LIT:1>)<EOL><DEDENT>except ValueError as err:<EOL><INDENT>raise ImportError("<STR_LIT>" % dotted_path) from err<EOL><DEDENT>module = import_module(module_path)<EOL>try:<EOL><INDENT>return getattr(module, class_name)<EOL><DEDENT>except AttributeError as err:<EOL><INDENT>raise ImportError('<STR_LIT>' % (<EOL>module_path,<EOL>class_name)) from err<EOL><DEDENT>

Import a dotted module path and return the attribute/class designated by the
last name in the path. Raise ImportError if the import failed.

:param dotted_path: The path to attempt importing
:return: The object


def load_shader(self, shader_type: str, path: str):

if path:<EOL><INDENT>resolved_path = self.find_program(path)<EOL>if not resolved_path:<EOL><INDENT>raise ValueError("<STR_LIT>".format(shader_type, path))<EOL><DEDENT>print("<STR_LIT>", path)<EOL>with open(resolved_path, '<STR_LIT:r>') as fd:<EOL><INDENT>return fd.read()<EOL><DEDENT><DEDENT>


def __init__(self, meta: SceneDescription):

super().__init__(meta)<EOL>self.scenes = []<EOL>self.nodes = []<EOL>self.meshes = []<EOL>self.materials = []<EOL>self.images = []<EOL>self.samplers = []<EOL>self.textures = []<EOL>self.path = None<EOL>self.scene = None<EOL>

Parse the json file and validate its contents.
No actual data loading will happen.

Supported formats:
- gltf json format with external resources
- gltf embedded buffers
- glb Binary format


self.path = self.find_scene(self.meta.path)<EOL>if not self.path:<EOL><INDENT>raise ValueError("<STR_LIT>".format(self.meta.path))<EOL><DEDENT>self.scene = Scene(self.path)<EOL>if self.path.suffix == '<STR_LIT>':<EOL><INDENT>self.load_gltf()<EOL><DEDENT>if self.path.suffix == '<STR_LIT>':<EOL><INDENT>self.load_glb()<EOL><DEDENT>self.meta.check_version()<EOL>self.meta.check_extensions(self.supported_extensions)<EOL>self.load_images()<EOL>self.load_samplers()<EOL>self.load_textures()<EOL>self.load_materials()<EOL>self.load_meshes()<EOL>self.load_nodes()<EOL>self.scene.calc_scene_bbox()<EOL>self.scene.prepare()<EOL>return self.scene<EOL>

Deferred loading of the scene

:param scene: The scene object
:param file: Resolved path if changed by finder


with open(self.path) as fd:<EOL><INDENT>self.meta = GLTFMeta(self.path, json.load(fd))<EOL><DEDENT>


with open(self.path, '<STR_LIT:rb>') as fd:<EOL><INDENT>magic = fd.read(<NUM_LIT:4>)<EOL>if magic != GLTF_MAGIC_HEADER:<EOL><INDENT>raise ValueError("<STR_LIT>".format(self.path, magic, GLTF_MAGIC_HEADER))<EOL><DEDENT>version = struct.unpack('<STR_LIT>', fd.read(<NUM_LIT:4>))[<NUM_LIT:0>]<EOL>if version != <NUM_LIT:2>:<EOL><INDENT>raise ValueError("<STR_LIT>".format(self.path, version))<EOL><DEDENT>_ = struct.unpack('<STR_LIT>', fd.read(<NUM_LIT:4>))[<NUM_LIT:0>]  <EOL>chunk_0_length = struct.unpack('<STR_LIT>', fd.read(<NUM_LIT:4>))[<NUM_LIT:0>]<EOL>chunk_0_type = fd.read(<NUM_LIT:4>)<EOL>if chunk_0_type != b'<STR_LIT>':<EOL><INDENT>raise ValueError("<STR_LIT>".format(chunk_0_type, self.path))<EOL><DEDENT>json_meta = fd.read(chunk_0_length).decode()<EOL>chunk_1_length = struct.unpack('<STR_LIT>', fd.read(<NUM_LIT:4>))[<NUM_LIT:0>]<EOL>chunk_1_type = fd.read(<NUM_LIT:4>)<EOL>if chunk_1_type != b'<STR_LIT>':<EOL><INDENT>raise ValueError("<STR_LIT>".format(chunk_1_type, self.path))<EOL><DEDENT>self.meta = GLTFMeta(self.path, json.loads(json_meta), binary_buffer=fd.read(chunk_1_length))<EOL><DEDENT>


def __init__(self, path, data, binary_buffer=None):

self.data = data<EOL>self.path = path<EOL>self.asset = GLTFAsset(data['<STR_LIT>'])<EOL>self.materials = [GLTFMaterial(m) for m in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.images = [GLTFImage(i) for i in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.samplers = [GLTFSampler(s) for s in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.textures = [GLTFTexture(t) for t in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.scenes = [GLTFScene(s) for s in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.nodes = [GLTFNode(n) for n in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.meshes = [GLTFMesh(m) for m in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.cameras = [GLTFCamera(c) for c in data['<STR_LIT>']] if data.get('<STR_LIT>') else []<EOL>self.buffer_views = [GLTFBufferView(i, v) for i, v in enumerate(data['<STR_LIT>'])]if data.get('<STR_LIT>') else []<EOL>self.buffers = [GLTFBuffer(i, b, self.path.parent) for i, b in enumerate(data['<STR_LIT>'])]if data.get('<STR_LIT>') else []<EOL>self.accessors = [GLTFAccessor(i, a) for i, a in enumerate(data['<STR_LIT>'])]if data.get('<STR_LIT>') else []<EOL>if binary_buffer:<EOL><INDENT>self.buffers[<NUM_LIT:0>].data = binary_buffer<EOL><DEDENT>self._link_data()<EOL>self.buffers_exist()<EOL>self.images_exist()<EOL>

:param file: GLTF file name loaded
:param data: Metadata (json loaded)
:param binary_buffer: Binary buffer when loading glb files


<EOL>for acc in self.accessors:<EOL><INDENT>acc.bufferView = self.buffer_views[acc.bufferViewId]<EOL><DEDENT>for buffer_view in self.buffer_views:<EOL><INDENT>buffer_view.buffer = self.buffers[buffer_view.bufferId]<EOL><DEDENT>for mesh in self.meshes:<EOL><INDENT>for primitive in mesh.primitives:<EOL><INDENT>if getattr(primitive, "<STR_LIT>", None) is not None:<EOL><INDENT>primitive.indices = self.accessors[primitive.indices]<EOL><DEDENT>for name, value in primitive.attributes.items():<EOL><INDENT>primitive.attributes[name] = self.accessors[value]<EOL><DEDENT><DEDENT><DEDENT>for image in self.images:<EOL><INDENT>if image.bufferViewId is not None:<EOL><INDENT>image.bufferView = self.buffer_views[image.bufferViewId]<EOL><DEDENT><DEDENT>


if self.data.get('<STR_LIT>'):<EOL><INDENT>for ext in self.data.get('<STR_LIT>'):<EOL><INDENT>if ext not in supported:<EOL><INDENT>raise ValueError("<STR_LIT>".format(ext))<EOL><DEDENT><DEDENT><DEDENT>if self.data.get('<STR_LIT>'):<EOL><INDENT>for ext in self.data.get('<STR_LIT>'):<EOL><INDENT>if ext not in supported:<EOL><INDENT>raise ValueError("<STR_LIT>".format(ext))<EOL><DEDENT><DEDENT><DEDENT>

"extensionsRequired": ["KHR_draco_mesh_compression"],
"extensionsUsed": ["KHR_draco_mesh_compression"]


for buff in self.buffers:<EOL><INDENT>if not buff.is_separate_file:<EOL><INDENT>continue<EOL><DEDENT>path = self.path.parent / buff.uri<EOL>if not os.path.exists(path):<EOL><INDENT>raise FileNotFoundError("<STR_LIT>".format(path, self.path))<EOL><DEDENT><DEDENT>

Checks if the bin files referenced exist


pass<EOL>

checks if the images references in textures exist


if getattr(primitive, "<STR_LIT>") is None:<EOL><INDENT>return None, None<EOL><DEDENT>_, component_type, buffer = primitive.indices.read()<EOL>return component_type, buffer<EOL>

Loads the index buffer / polygon list for a primitive


buffer_info = []<EOL>for name, accessor in primitive.attributes.items():<EOL><INDENT>info = VBOInfo(*accessor.info())<EOL>info.attributes.append((name, info.components))<EOL>if buffer_info and buffer_info[-<NUM_LIT:1>].buffer_view == info.buffer_view:<EOL><INDENT>if buffer_info[-<NUM_LIT:1>].interleaves(info):<EOL><INDENT>buffer_info[-<NUM_LIT:1>].merge(info)<EOL>continue<EOL><DEDENT><DEDENT>buffer_info.append(info)<EOL><DEDENT>return buffer_info<EOL>

Pre-parse buffer mappings for each VBO to detect interleaved data for a primitive


accessor = primitive.attributes.get('<STR_LIT>')<EOL>return accessor.min, accessor.max<EOL>


return info.byte_offset == self.component_type.size * self.components<EOL>

Does the buffer interleave with this one?


dtype = NP_COMPONENT_DTYPE[self.component_type.value]<EOL>data = numpy.frombuffer(<EOL>self.buffer.read(byte_length=self.byte_length, byte_offset=self.byte_offset),<EOL>count=self.count * self.components,<EOL>dtype=dtype,<EOL>)<EOL>return dtype, data<EOL>


<EOL>dtype = NP_COMPONENT_DTYPE[self.componentType.value]<EOL>return ACCESSOR_TYPE[self.type], self.componentType, self.bufferView.read(<EOL>byte_offset=self.byteOffset,<EOL>dtype=dtype,<EOL>count=self.count * ACCESSOR_TYPE[self.type],<EOL>)<EOL>

Reads buffer data
:return: component count, component type, data


buffer, byte_length, byte_offset = self.bufferView.info(byte_offset=self.byteOffset)<EOL>return buffer, self.bufferView,byte_length, byte_offset,self.componentType, ACCESSOR_TYPE[self.type], self.count<EOL>

Get underlying buffer info for this accessor
:return: buffer, byte_length, byte_offset, component_type, count


return self.buffer, self.byteLength, byte_offset + self.byteOffset<EOL>

Get the underlying buffer info
:param byte_offset: byte offset from accessor
:return: buffer, byte_length, byte_offset


if not self.uri:<EOL><INDENT>return False<EOL><DEDENT>return self.uri.startswith("<STR_LIT>")<EOL>


return self.uri is not None and not self.has_data_uri<EOL>

Buffer represents an independent bin file?


return self.camera is not None or self.mesh is not None<EOL>

Is this just a reference node to a resource?


raise NotImplementedError()<EOL>


path = Path(meta.path)<EOL>for ext in cls.file_extensions:<EOL><INDENT>if path.suffixes[:len(ext)] == ext:<EOL><INDENT>return True<EOL><DEDENT><DEDENT>return False<EOL>

Check if the loader has a supported file extension


buffer_format = []<EOL>attributes = []<EOL>mesh_attributes = []<EOL>if "<STR_LIT>" in vertex_format:<EOL><INDENT>buffer_format.append("<STR_LIT>")<EOL>attributes.append("<STR_LIT>")<EOL>mesh_attributes.append(("<STR_LIT>", "<STR_LIT>", <NUM_LIT:2>))<EOL><DEDENT>if "<STR_LIT>" in vertex_format:<EOL><INDENT>buffer_format.append("<STR_LIT>")<EOL>attributes.append("<STR_LIT>")<EOL>mesh_attributes.append(("<STR_LIT>", "<STR_LIT>", <NUM_LIT:3>))<EOL><DEDENT>if "<STR_LIT>" in vertex_format:<EOL><INDENT>buffer_format.append("<STR_LIT>")<EOL>attributes.append("<STR_LIT>")<EOL>mesh_attributes.append(("<STR_LIT>", "<STR_LIT>", <NUM_LIT:3>))<EOL><DEDENT>buffer_format.append("<STR_LIT>")<EOL>attributes.append("<STR_LIT>")<EOL>mesh_attributes.append(("<STR_LIT>", "<STR_LIT>", <NUM_LIT:3>))<EOL>return "<STR_LIT:U+0020>".join(buffer_format), attributes, mesh_attributes<EOL>


path = self.find_scene(self.meta.path)<EOL>if not path:<EOL><INDENT>raise ValueError("<STR_LIT>".format(self.meta.path))<EOL><DEDENT>if path.suffix == '<STR_LIT>':<EOL><INDENT>path = path.parent / path.stem<EOL><DEDENT>data = pywavefront.Wavefront(str(path), create_materials=True, cache=True)<EOL>scene = Scene(self.meta.resolved_path)<EOL>texture_cache = {}<EOL>for _, mat in data.materials.items():<EOL><INDENT>mesh = Mesh(mat.name)<EOL>if mat.vertices:<EOL><INDENT>buffer_format, attributes, mesh_attributes = translate_buffer_format(mat.vertex_format)<EOL>vbo = numpy.array(mat.vertices, dtype='<STR_LIT>')<EOL>vao = VAO(mat.name, mode=moderngl.TRIANGLES)<EOL>vao.buffer(vbo, buffer_format, attributes)<EOL>mesh.vao = vao<EOL>for attrs in mesh_attributes:<EOL><INDENT>mesh.add_attribute(*attrs)<EOL><DEDENT><DEDENT>elif hasattr(mat, '<STR_LIT>'):<EOL><INDENT>mesh = Mesh(mat.name)<EOL>mesh.vao = mat.vao<EOL>for attrs in mat.mesh_attributes:<EOL><INDENT>mesh.add_attribute(*attrs)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>continue<EOL><DEDENT>scene.meshes.append(mesh)<EOL>mesh.material = Material(mat.name)<EOL>scene.materials.append(mesh.material)<EOL>mesh.material.color = mat.diffuse<EOL>if mat.texture:<EOL><INDENT>texture = texture_cache.get(mat.texture.path)<EOL>if not texture:<EOL><INDENT>print("<STR_LIT>", mat.texture.path)<EOL>texture = textures.load(TextureDescription(<EOL>label=mat.texture.path,<EOL>path=mat.texture.path,<EOL>mipmap=True,<EOL>))<EOL>texture_cache[mat.texture.path] = texture<EOL><DEDENT>mesh.material.mat_texture = MaterialTexture(<EOL>texture=texture,<EOL>sampler=None,<EOL>)<EOL><DEDENT>node = Node(mesh=mesh)<EOL>scene.root_nodes.append(node)<EOL><DEDENT>scene.prepare()<EOL>return scene<EOL>


self.meta = meta<EOL>

:param meta: ResourceDescription instance


raise NotImplementedError()<EOL>

Load a resource

:returns: The newly loaded resource


found_path = None<EOL>for finder in finders:<EOL><INDENT>result = finder.find(path)<EOL>if result:<EOL><INDENT>found_path = result<EOL><DEDENT><DEDENT>return found_path<EOL>

Find the last occurance of the file in finders


return context.ctx()<EOL>


self._open_image()<EOL>components, data = image_data(self.image)<EOL>texture = self.ctx.texture(<EOL>self.image.size,<EOL>components,<EOL>data,<EOL>)<EOL>texture.extra = {'<STR_LIT>': self.meta}<EOL>if self.meta.mipmap:<EOL><INDENT>texture.build_mipmaps()<EOL><DEDENT>self._close_image()<EOL>return texture<EOL>


<EOL>data = image.tobytes()<EOL>components = len(data) // (image.size[<NUM_LIT:0>] * image.size[<NUM_LIT:1>])<EOL>return components, data<EOL>


self._open_image()<EOL>width, height, depth = self.image.size[<NUM_LIT:0>], self.image.size[<NUM_LIT:1>] // self.layers, self.layers<EOL>components, data = image_data(self.image)<EOL>texture = self.ctx.texture_array(<EOL>(width, height, depth),<EOL>components,<EOL>data,<EOL>)<EOL>texture.extra = {'<STR_LIT>': self.meta}<EOL>if self.meta.mipmap:<EOL><INDENT>texture.build_mipmaps()<EOL><DEDENT>self._close_image()<EOL>return texture<EOL>


self.meta.resolved_path = self.find_data(self.meta.path)<EOL>if not self.meta.resolved_path:<EOL><INDENT>raise ImproperlyConfigured("<STR_LIT>".format(self.meta.path))<EOL><DEDENT>print("<STR_LIT>", self.meta.path)<EOL>with open(self.meta.resolved_path, '<STR_LIT:r>') as fd:<EOL><INDENT>return fd.read()<EOL><DEDENT>


self.meta.resolved_path = self.find_data(self.meta.path)<EOL>if not self.meta.resolved_path:<EOL><INDENT>raise ImproperlyConfigured("<STR_LIT>".format(self.meta.path))<EOL><DEDENT>print("<STR_LIT>", self.meta.path)<EOL>with open(self.meta.resolved_path, '<STR_LIT:r>') as fd:<EOL><INDENT>return json.loads(fd.read())<EOL><DEDENT>


self.meta.resolved_path = self.find_data(self.meta.path)<EOL>if not self.meta.resolved_path:<EOL><INDENT>raise ImproperlyConfigured("<STR_LIT>".format(self.meta.path))<EOL><DEDENT>print("<STR_LIT>", self.meta.path)<EOL>with open(self.meta.resolved_path, '<STR_LIT:rb>') as fd:<EOL><INDENT>return fd.read()<EOL><DEDENT>


settings.setup()<EOL>settings.update(**kwargs)<EOL>


view.init(*args, **kwargs)<EOL>


view.run(*args, **kwargs)<EOL>


def draw(self, time, frametime, target):

raise NotImplementedError()<EOL>

Called by the system every frame.
This method should be overridden.

:param time: The current time in seconds
:param frametime: The time one frame should take in seconds
:param target: The target FBO


pass<EOL>

Forwarded key events from the system.

:param key: The key that was pressed or released.
:param action: ACTION_PRESS, ACTION_RELEASE
:param mods: Bit field describing which modifier keys were held down.


for effect in self.effects:<EOL><INDENT>value = effect.rocket_timeline_track.time_value(time)<EOL>if value > <NUM_LIT:0.5>:<EOL><INDENT>effect.draw(time, frametime, target)<EOL><DEDENT><DEDENT>

Fetch track value for every runnable effect.
If the value is > 0.5 we draw it.


pass<EOL>


pass<EOL>

This method is for adding arguments to a command.
When extending this class we define the arguments
by adding it to the parser passed in.

:param parser: The parser to add arguments to (standard argparse)


raise NotImplementedError()<EOL>

The actual run logic for the command.

:param args: arguments from the argparser
:param options: keyword arguments from the argparser


parser = self.create_parser(argv[<NUM_LIT:0>], argv[<NUM_LIT:1>])<EOL>options = parser.parse_args(argv[<NUM_LIT:2>:])<EOL>cmd_options = vars(options)<EOL>args = cmd_options.pop('<STR_LIT:args>', ())<EOL>self.handle(*args, **cmd_options)<EOL>

Called by the system when executing the command from the command line.
This should not be overridden.

:param argv: Arguments from command line


def print_help(self, prog_name, subcommand):

parser = self.create_parser(prog_name, subcommand)<EOL>parser.print_help()<EOL>

Prints the help text generated by the argument parser defined for this command.
This method should not be overridden.

:param prog_name: name of the program that started the command.
:param subcommand: The subcommand name


def create_parser(self, prog_name, subcommand):

parser = argparse.ArgumentParser(prog_name, subcommand)<EOL>self.add_arguments(parser)<EOL>return parser<EOL>

Create argument parser and deal with ``add_arguments``.
This method should not be overriden.

:param prog_name: Name of the command (argv[0])
:return: ArgumentParser


if not name:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>if not name.isidentifier():<EOL><INDENT>raise ValueError("<STR_LIT>".format(name))<EOL><DEDENT>

Can the name be used as a python module or package?
Raises ``ValueError`` if the name is invalid.

:param name: the name to check


try:<EOL><INDENT>import_module(name)<EOL><DEDENT>except ImportError:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>raise ImportError("<STR_LIT>".format(name))<EOL><DEDENT>

Attempt to import the name.
Raises ``ImportError`` if the name cannot be imported.

:param name: the name to import


templates = list_templates()<EOL>if value not in templates:<EOL><INDENT>raise ArgumentTypeError("<STR_LIT>".format(<EOL>value, "<STR_LIT:U+002CU+0020>".join(templates)))<EOL><DEDENT>return value<EOL>

Scan for available templates in effect_templates


module_dir = os.path.dirname(globals()['<STR_LIT>'])<EOL>return os.path.dirname(os.path.dirname(module_dir))<EOL>

Get the absolute path to the root of the demosys package


return os.path.join(root_path(), '<STR_LIT>')<EOL>

Get the absolute path to the template directory


with open(os.path.join(self.template_dir, '<STR_LIT>'), '<STR_LIT:r>') as fd:<EOL><INDENT>data = fd.read().format(project_name=self.project_name)<EOL><DEDENT>with open('<STR_LIT>', '<STR_LIT:w>') as fd:<EOL><INDENT>fd.write(data)<EOL><DEDENT>os.chmod('<STR_LIT>', <NUM_LIT>)<EOL>

Write manage.py in the current directory


directory = os.path.dirname(os.path.abspath(__file__))<EOL>directory = os.path.dirname(os.path.dirname(directory))<EOL>directory = os.path.join(directory, '<STR_LIT>')<EOL>return directory<EOL>

Returns the absolute path to template directory


def find_commands(command_dir: str) -> List[str]:

if not command_dir:<EOL><INDENT>return []<EOL><DEDENT>return [name for _, name, is_pkg in pkgutil.iter_modules([command_dir])<EOL>if not is_pkg and not name.startswith('<STR_LIT:_>')]<EOL>

Get all command names in the a folder

:return: List of commands names


if not argv:<EOL><INDENT>argv = sys.argv<EOL><DEDENT>system_commands = find_commands(system_command_dir())<EOL>project_commands = find_commands(project_command_dir())<EOL>project_package = project_package_name()<EOL>command = argv[<NUM_LIT:1>] if len(argv) > <NUM_LIT:1> else None<EOL>if command in system_commands:<EOL><INDENT>cmd = load_command_class('<STR_LIT>', command)<EOL>cmd.run_from_argv(argv)<EOL><DEDENT>elif command in project_commands:<EOL><INDENT>cmd = load_command_class(project_package, command)<EOL>cmd.run_from_argv(argv)<EOL><DEDENT>else:<EOL><INDENT>print("<STR_LIT>")<EOL>for name in system_commands:<EOL><INDENT>print("<STR_LIT>".format(name))<EOL><DEDENT>for name in project_commands:<EOL><INDENT>print("<STR_LIT>".format(name))<EOL><DEDENT><DEDENT>

Currently the only entrypoint (manage.py, demosys-admin)


effects.polulate(self.effect_packages)<EOL>

Registers effect packages defined in ``effect_packages``.


def create_external_resources(self) -> List[ResourceDescription]:

return effects.get_effect_resources()<EOL>

Fetches all resource descriptions defined in effect packages.

Returns:
    List of resource descriptions to load


def create_resources(self) -> List[ResourceDescription]:

return self.resources<EOL>

Create resources for the project.
Simply returns the ``resources`` list and can be implemented to
modify what a resource list is programmatically.

Returns:
    List of resource descriptions to load


raise NotImplementedError()<EOL>

Create instances of effects.
Must be implemented or ``NotImplementedError`` is raised.


def create_effect(self, label: str, name: str, *args, **kwargs) -> Effect:

effect_cls = effects.find_effect_class(name)<EOL>effect = effect_cls(*args, **kwargs)<EOL>effect._label = label<EOL>if label in self._effects:<EOL><INDENT>raise ValueError("<STR_LIT>".format(label))<EOL><DEDENT>self._effects[label] = effect<EOL>return effect<EOL>

Create an effect instance adding it to the internal effects dictionary using the label as key.

Args:
    label (str): The unique label for the effect instance
    name (str): Name or full python path to the effect class we want to instantiate
    args: Positional arguments to the effect initializer
    kwargs: Keyword arguments to the effect initializer

Returns:
    The newly created Effect instance


for _, effect in self._effects.items():<EOL><INDENT>effect.post_load()<EOL><DEDENT>

Called after resources are loaded before effects starts rendering.
It simply iterates each effect instance calling their ``post_load`` methods.


self.create_effect_classes()<EOL>self._add_resource_descriptions_to_pools(self.create_external_resources())<EOL>self._add_resource_descriptions_to_pools(self.create_resources())<EOL>for meta, resource in resources.textures.load_pool():<EOL><INDENT>self._textures[meta.label] = resource<EOL><DEDENT>for meta, resource in resources.programs.load_pool():<EOL><INDENT>self._programs[meta.label] = resource<EOL><DEDENT>for meta, resource in resources.scenes.load_pool():<EOL><INDENT>self._scenes[meta.label] = resource<EOL><DEDENT>for meta, resource in resources.data.load_pool():<EOL><INDENT>self._data[meta.label] = resource<EOL><DEDENT>self.create_effect_instances()<EOL>self.post_load()<EOL>


if not meta_list:<EOL><INDENT>return<EOL><DEDENT>for meta in meta_list:<EOL><INDENT>getattr(resources, meta.resource_type).add(meta)<EOL><DEDENT>

Takes a list of resource descriptions adding them
to the resource pool they belong to scheduling them for loading.


print("<STR_LIT>")<EOL>for name, program in self._programs.items():<EOL><INDENT>if getattr(program, '<STR_LIT>', None):<EOL><INDENT>print("<STR_LIT>".format(program.meta.label))<EOL>program.program = resources.programs.load(program.meta)<EOL><DEDENT><DEDENT>

Reload all shader programs with the reloadable flag set


def get_effect(self, label: str) -> Effect:

return self._get_resource(label, self._effects, "<STR_LIT>")<EOL>

Get an effect instance by label

Args:
    label (str): The label for the effect instance

Returns:
    Effect class instance


def get_effect_class(self, class_name, package_name=None) -> Type[Effect]:

if package_name:<EOL><INDENT>return effects.find_effect_class("<STR_LIT>".format(package_name, class_name))<EOL><DEDENT>return effects.find_effect_class(class_name)<EOL>

Get an effect class from the effect registry.

Args:
    class_name (str): The exact class name of the effect

Keyword Args:
    package_name (str): The python path to the effect package the effect name is located.
                        This is optional and can be used to avoid issue with class name collisions.

Returns:
    Effect class


def get_scene(self, label: str) -> Scene:

return self._get_resource(label, self._scenes, "<STR_LIT>")<EOL>

Gets a scene by label

Args:
    label (str): The label for the scene to fetch

Returns:
    Scene instance


def get_texture(self, label: str) -> Union[moderngl.Texture, moderngl.TextureArray,<EOL>moderngl.Texture3D, moderngl.TextureCube]:

return self._get_resource(label, self._textures, "<STR_LIT>")<EOL>

Get a texture by label

Args:
    label (str): The label for the texture to fetch

Returns:
    Texture instance


return self._get_resource(label, self._data, "<STR_LIT:data>")<EOL>

Get a data resource by label

Args:
    label (str): The labvel for the data resource to fetch

Returns:
    The requeted data object


def _get_resource(self, label: str, source: dict, resource_type: str):

try:<EOL><INDENT>return source[label]<EOL><DEDENT>except KeyError:<EOL><INDENT>raise ValueError("<STR_LIT>".format(<EOL>resource_type, label, list(source.keys())))<EOL><DEDENT>

Generic resoure fetcher handling errors.

Args:
    label (str): The label to fetch
    source (dict): The dictionary to look up the label
    resource_type str: The display name of the resource type (used in errors)


def get_runnable_effects(self) -> List[Effect]:

return [effect for name, effect in self._effects.items() if effect.runnable]<EOL>

Returns all runnable effects in the project.

:return: List of all runnable effects


@property<EOL><INDENT>def ctx(self) -> moderngl.Context:<DEDENT>

return context.ctx()<EOL>


return quad_2d(<NUM_LIT>, <NUM_LIT>, <NUM_LIT:0.0>, <NUM_LIT:0.0>)<EOL>

Creates a screen aligned quad using two triangles with normals and texture coordiantes.

Returns:
    A :py:class:`demosys.opengl.vao.VAO` instance.


def quad_2d(width, height, xpos=<NUM_LIT:0.0>, ypos=<NUM_LIT:0.0>) -> VAO:

pos = numpy.array([<EOL>xpos - width / <NUM_LIT>, ypos + height / <NUM_LIT>, <NUM_LIT:0.0>,<EOL>xpos - width / <NUM_LIT>, ypos - height / <NUM_LIT>, <NUM_LIT:0.0>,<EOL>xpos + width / <NUM_LIT>, ypos - height / <NUM_LIT>, <NUM_LIT:0.0>,<EOL>xpos - width / <NUM_LIT>, ypos + height / <NUM_LIT>, <NUM_LIT:0.0>,<EOL>xpos + width / <NUM_LIT>, ypos - height / <NUM_LIT>, <NUM_LIT:0.0>,<EOL>xpos + width / <NUM_LIT>, ypos + height / <NUM_LIT>, <NUM_LIT:0.0>,<EOL>], dtype=numpy.float32)<EOL>normals = numpy.array([<EOL><NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL><NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL><NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL><NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL><NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL><NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL>], dtype=numpy.float32)<EOL>uvs = numpy.array([<EOL><NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL><NUM_LIT:0.0>, <NUM_LIT:0.0>,<EOL><NUM_LIT:1.0>, <NUM_LIT:0.0>,<EOL><NUM_LIT:0.0>, <NUM_LIT:1.0>,<EOL><NUM_LIT:1.0>, <NUM_LIT:0.0>,<EOL><NUM_LIT:1.0>, <NUM_LIT:1.0>,<EOL>], dtype=numpy.float32)<EOL>vao = VAO("<STR_LIT>", mode=moderngl.TRIANGLES)<EOL>vao.buffer(pos, '<STR_LIT>', ["<STR_LIT>"])<EOL>vao.buffer(normals, '<STR_LIT>', ["<STR_LIT>"])<EOL>vao.buffer(uvs, '<STR_LIT>', ["<STR_LIT>"])<EOL>return vao<EOL>

Creates a 2D quad VAO using 2 triangles with normals and texture coordinates.

Args:
    width (float): Width of the quad
    height (float): Height of the quad

Keyword Args:
    xpos (float): Center position x
    ypos (float): Center position y

Returns:
    A :py:class:`demosys.opengl.vao.VAO` instance.


def plane_xz(size=(<NUM_LIT:10>, <NUM_LIT:10>), resolution=(<NUM_LIT:10>, <NUM_LIT:10>)) -> VAO:

sx, sz = size<EOL>rx, rz = resolution<EOL>dx, dz = sx / rx, sz / rz  <EOL>ox, oz = -sx / <NUM_LIT:2>, -sz / <NUM_LIT:2>  <EOL>def gen_pos():<EOL><INDENT>for z in range(rz):<EOL><INDENT>for x in range(rx):<EOL><INDENT>yield ox + x * dx<EOL>yield <NUM_LIT:0><EOL>yield oz + z * dz<EOL><DEDENT><DEDENT><DEDENT>def gen_uv():<EOL><INDENT>for z in range(rz):<EOL><INDENT>for x in range(rx):<EOL><INDENT>yield x / (rx - <NUM_LIT:1>)<EOL>yield <NUM_LIT:1> - z / (rz - <NUM_LIT:1>)<EOL><DEDENT><DEDENT><DEDENT>def gen_normal():<EOL><INDENT>for _ in range(rx * rz):<EOL><INDENT>yield <NUM_LIT:0.0><EOL>yield <NUM_LIT:1.0><EOL>yield <NUM_LIT:0.0><EOL><DEDENT><DEDENT>def gen_index():<EOL><INDENT>for z in range(rz - <NUM_LIT:1>):<EOL><INDENT>for x in range(rx - <NUM_LIT:1>):<EOL><INDENT>yield z * rz + x + <NUM_LIT:1><EOL>yield z * rz + x<EOL>yield z * rz + x + rx<EOL>yield z * rz + x + <NUM_LIT:1><EOL>yield z * rz + x + rx<EOL>yield z * rz + x + rx + <NUM_LIT:1><EOL><DEDENT><DEDENT><DEDENT>pos_data = numpy.fromiter(gen_pos(), dtype=numpy.float32)<EOL>uv_data = numpy.fromiter(gen_uv(), dtype=numpy.float32)<EOL>normal_data = numpy.fromiter(gen_normal(), dtype=numpy.float32)<EOL>index_data = numpy.fromiter(gen_index(), dtype=numpy.uint32)<EOL>vao = VAO("<STR_LIT>", mode=moderngl.TRIANGLES)<EOL>vao.buffer(pos_data, '<STR_LIT>', ['<STR_LIT>'])<EOL>vao.buffer(uv_data, '<STR_LIT>', ['<STR_LIT>'])<EOL>vao.buffer(normal_data, '<STR_LIT>', ['<STR_LIT>'])<EOL>vao.index_buffer(index_data, index_element_size=<NUM_LIT:4>)<EOL>return vao<EOL>

Generates a plane on the xz axis of a specific size and resolution.
Normals and texture coordinates are also included.

Args:
    size: (x, y) tuple
    resolution: (x, y) tuple

Returns:
    A :py:class:`demosys.opengl.vao.VAO` instance


def bbox(width=<NUM_LIT:1.0>, height=<NUM_LIT:1.0>, depth=<NUM_LIT:1.0>):

width, height, depth = width / <NUM_LIT>, height / <NUM_LIT>, depth / <NUM_LIT><EOL>pos = numpy.array([<EOL>width, -height, depth,<EOL>width, height, depth,<EOL>-width, -height, depth,<EOL>width, height, depth,<EOL>-width, height, depth,<EOL>-width, -height, depth,<EOL>width, -height, -depth,<EOL>width, height, -depth,<EOL>width, -height, depth,<EOL>width, height, -depth,<EOL>width, height, depth,<EOL>width, -height, depth,<EOL>width, -height, -depth,<EOL>width, -height, depth,<EOL>-width, -height, depth,<EOL>width, -height, -depth,<EOL>-width, -height, depth,<EOL>-width, -height, -depth,<EOL>-width, -height, depth,<EOL>-width, height, depth,<EOL>-width, height, -depth,<EOL>-width, -height, depth,<EOL>-width, height, -depth,<EOL>-width, -height, -depth,<EOL>width, height, -depth,<EOL>width, -height, -depth,<EOL>-width, -height, -depth,<EOL>width, height, -depth,<EOL>-width, -height, -depth,<EOL>-width, height, -depth,<EOL>width, height, -depth,<EOL>-width, height, -depth,<EOL>width, height, depth,<EOL>-width, height, -depth,<EOL>-width, height, depth,<EOL>width, height, depth,<EOL>], dtype=numpy.float32)<EOL>vao = VAO("<STR_LIT>", mode=moderngl.LINE_STRIP)<EOL>vao.buffer(pos, '<STR_LIT>', ["<STR_LIT>"])<EOL>return vao<EOL>

Generates a bounding box with (0.0, 0.0, 0.0) as the center.
This is simply a box with ``LINE_STRIP`` as draw mode.

Keyword Args:
    width (float): Width of the box
    height (float): Height of the box
    depth (float): Depth of the box

Returns:
    A :py:class:`demosys.opengl.vao.VAO` instance


def points_random_3d(count, range_x=(-<NUM_LIT>, <NUM_LIT>), range_y=(-<NUM_LIT>, <NUM_LIT>), range_z=(-<NUM_LIT>, <NUM_LIT>), seed=None) -> VAO:

random.seed(seed)<EOL>def gen():<EOL><INDENT>for _ in range(count):<EOL><INDENT>yield random.uniform(*range_x)<EOL>yield random.uniform(*range_y)<EOL>yield random.uniform(*range_z)<EOL><DEDENT><DEDENT>data = numpy.fromiter(gen(), count=count * <NUM_LIT:3>, dtype=numpy.float32)<EOL>vao = VAO("<STR_LIT>", mode=moderngl.POINTS)<EOL>vao.buffer(data, '<STR_LIT>', ['<STR_LIT>'])<EOL>return vao<EOL>

Generates random positions inside a confied box.

Args:
    count (int): Number of points to generate

Keyword Args:
    range_x (tuple): min-max range for x axis: Example (-10.0. 10.0)
    range_y (tuple): min-max range for y axis: Example (-10.0. 10.0)
    range_z (tuple): min-max range for z axis: Example (-10.0. 10.0)
    seed (int): The random seed

Returns:
    A :py:class:`demosys.opengl.vao.VAO` instance


def cube(width, height, depth, center=(<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>), normals=True, uvs=True) -> VAO:

width, height, depth = width / <NUM_LIT>, height / <NUM_LIT>, depth / <NUM_LIT><EOL>pos = numpy.array([<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] - height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] - depth,<EOL>center[<NUM_LIT:0>] - width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>center[<NUM_LIT:0>] + width, center[<NUM_LIT:1>] + height, center[<NUM_LIT:2>] + depth,<EOL>], dtype=numpy.float32)<EOL>if normals:<EOL><INDENT>normal_data = numpy.array([<EOL>-<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>,<EOL>-<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>,<EOL>-<NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, -<NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, -<NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, -<NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, -<NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, -<NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, -<NUM_LIT:1>, <NUM_LIT:0>,<EOL>-<NUM_LIT:1>, -<NUM_LIT:0>, <NUM_LIT:0>,<EOL>-<NUM_LIT:1>, -<NUM_LIT:0>, <NUM_LIT:0>,<EOL>-<NUM_LIT:1>, -<NUM_LIT:0>, <NUM_LIT:0>,<EOL>-<NUM_LIT:1>, -<NUM_LIT:0>, <NUM_LIT:0>,<EOL>-<NUM_LIT:1>, -<NUM_LIT:0>, <NUM_LIT:0>,<EOL>-<NUM_LIT:1>, -<NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, -<NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, -<NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, -<NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, -<NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, -<NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>, -<NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>, <NUM_LIT:0>,<EOL>], dtype=numpy.float32)<EOL><DEDENT>if uvs:<EOL><INDENT>uvs_data = numpy.array([<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:1>, <NUM_LIT:0>,<EOL><NUM_LIT:0>, <NUM_LIT:1>,<EOL><NUM_LIT:0>, <NUM_LIT:0>,<EOL><NUM_LIT:1>, <NUM_LIT:0><EOL>], dtype=numpy.float32)<EOL><DEDENT>vao = VAO("<STR_LIT>")<EOL>vao.buffer(pos, '<STR_LIT>', ['<STR_LIT>'])<EOL>if normals:<EOL><INDENT>vao.buffer(normal_data, '<STR_LIT>', ['<STR_LIT>'])<EOL><DEDENT>if uvs:<EOL><INDENT>vao.buffer(uvs_data, '<STR_LIT>', ['<STR_LIT>'])<EOL><DEDENT>return vao<EOL>

Creates a cube VAO with normals and texture coordinates

Args:
    width (float): Width of the cube
    height (float): Height of the cube
    depth (float): Depth of the cube

Keyword Args:
    center: center of the cube as a 3-component tuple
    normals: (bool) Include normals
    uvs: (bool) include uv coordinates

Returns:
    A :py:class:`demosys.opengl.vao.VAO` instance


def sphere(radius=<NUM_LIT:0.5>, sectors=<NUM_LIT:32>, rings=<NUM_LIT:16>) -> VAO:

R = <NUM_LIT:1.0> / (rings - <NUM_LIT:1>)<EOL>S = <NUM_LIT:1.0> / (sectors - <NUM_LIT:1>)<EOL>vertices = [<NUM_LIT:0>] * (rings * sectors * <NUM_LIT:3>)<EOL>normals = [<NUM_LIT:0>] * (rings * sectors * <NUM_LIT:3>)<EOL>uvs = [<NUM_LIT:0>] * (rings * sectors * <NUM_LIT:2>)<EOL>v, n, t = <NUM_LIT:0>, <NUM_LIT:0>, <NUM_LIT:0><EOL>for r in range(rings):<EOL><INDENT>for s in range(sectors):<EOL><INDENT>y = math.sin(-math.pi / <NUM_LIT:2> + math.pi * r * R)<EOL>x = math.cos(<NUM_LIT:2> * math.pi * s * S) * math.sin(math.pi * r * R)<EOL>z = math.sin(<NUM_LIT:2> * math.pi * s * S) * math.sin(math.pi * r * R)<EOL>uvs[t] = s * S<EOL>uvs[t + <NUM_LIT:1>] = r * R<EOL>vertices[v] = x * radius<EOL>vertices[v + <NUM_LIT:1>] = y * radius<EOL>vertices[v + <NUM_LIT:2>] = z * radius<EOL>normals[n] = x<EOL>normals[n + <NUM_LIT:1>] = y<EOL>normals[n + <NUM_LIT:2>] = z<EOL>t += <NUM_LIT:2><EOL>v += <NUM_LIT:3><EOL>n += <NUM_LIT:3><EOL><DEDENT><DEDENT>indices = [<NUM_LIT:0>] * rings * sectors * <NUM_LIT:6><EOL>i = <NUM_LIT:0><EOL>for r in range(rings - <NUM_LIT:1>):<EOL><INDENT>for s in range(sectors - <NUM_LIT:1>):<EOL><INDENT>indices[i] = r * sectors + s<EOL>indices[i + <NUM_LIT:1>] = (r + <NUM_LIT:1>) * sectors + (s + <NUM_LIT:1>)<EOL>indices[i + <NUM_LIT:2>] = r * sectors + (s + <NUM_LIT:1>)<EOL>indices[i + <NUM_LIT:3>] = r * sectors + s<EOL>indices[i + <NUM_LIT:4>] = (r + <NUM_LIT:1>) * sectors + s<EOL>indices[i + <NUM_LIT:5>] = (r + <NUM_LIT:1>) * sectors + (s + <NUM_LIT:1>)<EOL>i += <NUM_LIT:6><EOL><DEDENT><DEDENT>vbo_vertices = numpy.array(vertices, dtype=numpy.float32)<EOL>vbo_normals = numpy.array(normals, dtype=numpy.float32)<EOL>vbo_uvs = numpy.array(uvs, dtype=numpy.float32)<EOL>vbo_elements = numpy.array(indices, dtype=numpy.uint32)<EOL>vao = VAO("<STR_LIT>", mode=mlg.TRIANGLES)<EOL>vao.buffer(vbo_vertices, '<STR_LIT>', ['<STR_LIT>'])<EOL>vao.buffer(vbo_normals, '<STR_LIT>', ['<STR_LIT>'])<EOL>vao.buffer(vbo_uvs, '<STR_LIT>', ['<STR_LIT>'])<EOL>vao.index_buffer(vbo_elements, index_element_size=<NUM_LIT:4>)<EOL>return vao<EOL>

Creates a sphere.

Keyword Args:
    radius (float): Radius or the sphere
    rings (int): number or horizontal rings
    sectors (int): number of vertical segments

Returns:
    A :py:class:`demosys.opengl.vao.VAO` instance


super().__init__()<EOL>if not glfw.init():<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>self.check_glfw_version()<EOL>glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, self.gl_version.major)<EOL>glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, self.gl_version.minor)<EOL>glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)<EOL>glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)<EOL>glfw.window_hint(glfw.RESIZABLE, self.resizable)<EOL>glfw.window_hint(glfw.DOUBLEBUFFER, True)<EOL>glfw.window_hint(glfw.DEPTH_BITS, <NUM_LIT>)<EOL>glfw.window_hint(glfw.SAMPLES, self.samples)<EOL>monitor = None<EOL>if self.fullscreen:<EOL><INDENT>monitor = glfw.get_primary_monitor()<EOL>mode = glfw.get_video_mode(monitor)<EOL>self.width, self.height = mode.size.width, mode.size.height<EOL>print("<STR_LIT>", mode)<EOL><DEDENT>print("<STR_LIT>", self.width, self.height)<EOL>self.window = glfw.create_window(self.width, self.height, self.title, monitor, None)<EOL>if not self.window:<EOL><INDENT>glfw.terminate()<EOL>raise ValueError("<STR_LIT>")<EOL><DEDENT>if not self.cursor:<EOL><INDENT>glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED)<EOL><DEDENT>self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window)<EOL>print("<STR_LIT>", self.buffer_width, self.buffer_height)<EOL>print("<STR_LIT>", glfw.get_window_size(self.window))<EOL>glfw.make_context_current(self.window)<EOL>if self.vsync:<EOL><INDENT>glfw.swap_interval(<NUM_LIT:1>)<EOL><DEDENT>glfw.set_key_callback(self.window, self.key_event_callback)<EOL>glfw.set_cursor_pos_callback(self.window, self.mouse_event_callback)<EOL>glfw.set_window_size_callback(self.window, self.window_resize_callback)<EOL>self.ctx = moderngl.create_context(require=self.gl_version.code)<EOL>context.WINDOW = self<EOL>self.fbo = self.ctx.screen<EOL>self.set_default_viewport()<EOL>

Initializes glfw, sets up key and mouse events and
creates a ``moderngl.Context`` using the context glfw createad.

Using the glfw window requires glfw binaries and pyGLFW.


self.fbo.use()<EOL>

Bind the window framebuffer making it the current render target


return glfw.window_should_close(self.window)<EOL>


glfw.set_window_should_close(self.window, True)<EOL>


self.frames += <NUM_LIT:1><EOL>glfw.swap_buffers(self.window)<EOL>self.poll_events()<EOL>

Swaps buffers, incement the framecounter and pull events.


self.width = width<EOL>self.height = height<EOL>self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window)<EOL>self.set_default_viewport()<EOL>

Sets the new size and buffer size internally


glfw.terminate()<EOL>


print("<STR_LIT>".format(glfw.get_version(), glfw.__version__))<EOL>if glfw.get_version() < self.min_glfw_version:<EOL><INDENT>raise ValueError("<STR_LIT>".format(self.min_glfw_version))<EOL><DEDENT>

Ensure glfw library  version is compatible


def key_event_callback(self, window, key, scancode, action, mods):

self.keyboard_event(key, action, mods)<EOL>

Key event callback for glfw.
Translates and forwards keyboard event to :py:func:`keyboard_event`

:param window: Window event origin
:param key: The key that was pressed or released.
:param scancode: The system-specific scancode of the key.
:param action: GLFW_PRESS, GLFW_RELEASE or GLFW_REPEAT
:param mods: Bit field describing which modifier keys were held down.


def mouse_event_callback(self, window, xpos, ypos):

<EOL>self.cursor_event(xpos, ypos, <NUM_LIT:0>, <NUM_LIT:0>)<EOL>

Mouse event callback from glfw.
Translates the events forwarding them to :py:func:`cursor_event`.

:param window: The window
:param xpos: viewport x pos
:param ypos: viewport y pos


def window_resize_callback(self, window, width, height):

self.resize(width, height)<EOL>

Window resize callback for glfw

:param window: The window
:param width: New width
:param height: New height


super().__init__()<EOL>pyglet.options['<STR_LIT>'] = False<EOL>config = pyglet.gl.Config()<EOL>config.double_buffer = True<EOL>config.major_version = self.gl_version.major<EOL>config.minor_version = self.gl_version.minor<EOL>config.forward_compatible = True<EOL>config.sample_buffers = <NUM_LIT:1> if self.samples > <NUM_LIT:1> else <NUM_LIT:0><EOL>config.samples = self.samples<EOL>self.window = PygletWrapper(<EOL>width=self.width, height=self.height,<EOL>caption=self.title,<EOL>resizable=self.resizable,<EOL>vsync=self.vsync,<EOL>fullscreen=self.fullscreen,<EOL>)<EOL>self.window.set_mouse_visible(self.cursor)<EOL>self.window.event(self.on_key_press)<EOL>self.window.event(self.on_key_release)<EOL>self.window.event(self.on_mouse_motion)<EOL>self.window.event(self.on_resize)<EOL>self.ctx = moderngl.create_context(require=self.gl_version.code)<EOL>context.WINDOW = self<EOL>self.fbo = self.ctx.screen<EOL>self.set_default_viewport()<EOL>

Opens a window using pyglet, registers input callbacks
and creates a moderngl context.


def on_key_press(self, symbol, modifiers):

self.keyboard_event(symbol, self.keys.ACTION_PRESS, modifiers)<EOL>

Pyglet specific key press callback.
Forwards and translates the events to :py:func:`keyboard_event`


def on_key_release(self, symbol, modifiers):

self.keyboard_event(symbol, self.keys.ACTION_RELEASE, modifiers)<EOL>

Pyglet specific key release callback.
Forwards and translates the events to :py:func:`keyboard_event`


def on_mouse_motion(self, x, y, dx, dy):

<EOL>self.cursor_event(x, self.buffer_height - y, dx, dy)<EOL>

Pyglet specific mouse motion callback.
Forwards and traslates the event to :py:func:`cursor_event`


self.width, self.height = width, height<EOL>self.buffer_width, self.buffer_height = width, height<EOL>self.resize(width, height)<EOL>

Pyglet specific callback for window resize events.


self.fbo.use()<EOL>


if not self.window.context:<EOL><INDENT>return<EOL><DEDENT>self.frames += <NUM_LIT:1><EOL>self.window.flip()<EOL>self.window.dispatch_events()<EOL>

Swap buffers, increment frame counter and pull events


return self.window.has_exit<EOL>

returns the ``has_exit`` state in the pyglet window


self.window.close()<EOL>

Sets the close state in the pyglet window


pass<EOL>

No cleanup is really needed. Empty method


pass<EOL>

For some reason pyglet calls its own resize handler randomly


super().__init__()<EOL>self._closed = False<EOL>gl = QtOpenGL.QGLFormat()<EOL>gl.setVersion(self.gl_version.major, self.gl_version.minor)<EOL>gl.setProfile(QtOpenGL.QGLFormat.CoreProfile)<EOL>gl.setDepthBufferSize(<NUM_LIT>)<EOL>gl.setDoubleBuffer(True)<EOL>gl.setSwapInterval(<NUM_LIT:1> if self.vsync else <NUM_LIT:0>)<EOL>if self.samples > <NUM_LIT:1>:<EOL><INDENT>gl.setSampleBuffers(True)<EOL>gl.setSamples(self.samples)<EOL><DEDENT>self.app = QtWidgets.QApplication([])<EOL>self.widget = QtOpenGL.QGLWidget(gl)<EOL>self.widget.setWindowTitle(self.title)<EOL>if self.fullscreen:<EOL><INDENT>rect = QtWidgets.QDesktopWidget().screenGeometry()<EOL>self.width = rect.width()<EOL>self.height = rect.height()<EOL>self.buffer_width = rect.width() * self.widget.devicePixelRatio()<EOL>self.buffer_height = rect.height() * self.widget.devicePixelRatio()<EOL><DEDENT>if self.resizable:<EOL><INDENT>size_policy = QtWidgets.QSizePolicy(<EOL>QtWidgets.QSizePolicy.Expanding,<EOL>QtWidgets.QSizePolicy.Expanding,<EOL>)<EOL>self.widget.setSizePolicy(size_policy)<EOL>self.widget.resize(self.width, self.height)<EOL><DEDENT>else:<EOL><INDENT>self.widget.setFixedSize(self.width, self.height)<EOL><DEDENT>self.widget.move(QtWidgets.QDesktopWidget().rect().center() - self.widget.rect().center())<EOL>self.widget.resizeGL = self.resize  <EOL>self.widget.show()<EOL>if not self.cursor:<EOL><INDENT>self.widget.setCursor(QtCore.Qt.BlankCursor)<EOL><DEDENT>if self.fullscreen:<EOL><INDENT>self.widget.showFullScreen()<EOL><DEDENT>self.widget.setMouseTracking(True)<EOL>self.widget.keyPressEvent = self.keyPressEvent<EOL>self.widget.keyReleaseEvent = self.keyReleaseEvent<EOL>self.widget.mouseMoveEvent = self.mouseMoveEvent<EOL>self.ctx = moderngl.create_context(require=self.gl_version.code)<EOL>context.WINDOW = self<EOL>self.fbo = self.ctx.screen<EOL>self.buffer_width = self.width * self.widget.devicePixelRatio()<EOL>self.buffer_height = self.height * self.widget.devicePixelRatio()<EOL>self.set_default_viewport()<EOL>

Creates a pyqt application and window overriding the
built in event loop. Sets up keyboard and mouse events
and creates a ``monderngl.Context``.


self.keyboard_event(event.key(), self.keys.ACTION_PRESS, <NUM_LIT:0>)<EOL>

Pyqt specific key press callback function.
Translates and forwards events to :py:func:`keyboard_event`.


self.keyboard_event(event.key(), self.keys.ACTION_RELEASE, <NUM_LIT:0>)<EOL>

Pyqt specific key release callback function.
Translates and forwards events to :py:func:`keyboard_event`.


self.cursor_event(event.x(), event.y(), <NUM_LIT:0>, <NUM_LIT:0>)<EOL>

Pyqt specific mouse event callback
Translates and forwards events to :py:func:`cursor_event`.


if not self.fbo:<EOL><INDENT>return<EOL><DEDENT>self.width = width // self.widget.devicePixelRatio()<EOL>self.height = height // self.widget.devicePixelRatio()<EOL>self.buffer_width = width<EOL>self.buffer_height = height<EOL>super().resize(width, height)<EOL>


self.frames += <NUM_LIT:1><EOL>self.widget.swapBuffers()<EOL>self.app.processEvents()<EOL>

Swaps buffers, increments the frame counter and pulls events


self.fbo.use()<EOL>

Make the window's framebuffer the current render target


return self._closed<EOL>

Checks if the internal close state is set


self._closed = True<EOL>


QtCore.QCoreApplication.instance().quit()<EOL>


super().__init__()<EOL>self.window_closing = False<EOL>self.tmp_size_x = c_int()<EOL>self.tmp_size_y = c_int()<EOL>print("<STR_LIT>", self.get_library_version())<EOL>if sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO) != <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MAJOR_VERSION, self.gl_version.major)<EOL>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_MINOR_VERSION, self.gl_version.minor)<EOL>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_PROFILE_MASK, sdl2.SDL_GL_CONTEXT_PROFILE_CORE)<EOL>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG, <NUM_LIT:1>)<EOL>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_DOUBLEBUFFER, <NUM_LIT:1>)<EOL>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_DEPTH_SIZE, <NUM_LIT>)<EOL>sdl2.SDL_ShowCursor(sdl2.SDL_ENABLE if self.cursor else sdl2.SDL_DISABLE)<EOL>if self.samples > <NUM_LIT:1>:<EOL><INDENT>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_MULTISAMPLEBUFFERS, <NUM_LIT:1>)<EOL>sdl2.video.SDL_GL_SetAttribute(sdl2.SDL_GL_MULTISAMPLESAMPLES, self.samples)<EOL><DEDENT>flags = sdl2.SDL_WINDOW_OPENGL<EOL>if self.fullscreen:<EOL><INDENT>flags |= sdl2.SDL_WINDOW_FULLSCREEN_DESKTOP<EOL><DEDENT>else:<EOL><INDENT>if self.resizable:<EOL><INDENT>flags |= sdl2.SDL_WINDOW_RESIZABLE<EOL><DEDENT><DEDENT>self.window = sdl2.SDL_CreateWindow(<EOL>self.title.encode(),<EOL>sdl2.SDL_WINDOWPOS_UNDEFINED,<EOL>sdl2.SDL_WINDOWPOS_UNDEFINED,<EOL>self.width,<EOL>self.height,<EOL>flags<EOL>)<EOL>if not self.window:<EOL><INDENT>raise ValueError("<STR_LIT>", sdl2.SDL_GetError())<EOL><DEDENT>self.context = sdl2.SDL_GL_CreateContext(self.window)<EOL>sdl2.video.SDL_GL_SetSwapInterval(<NUM_LIT:1> if self.vsync else <NUM_LIT:0>)<EOL>self.ctx = moderngl.create_context(require=self.gl_version.code)<EOL>context.WINDOW = self<EOL>self.fbo = self.ctx.screen<EOL>self.set_default_viewport()<EOL>

Initializes sdl2, sets up key and mouse events and
creates a ``moderngl.Context`` using the context sdl2 createad.

Using the sdl2 window requires sdl binaries and PySDL2.


self.fbo.use()<EOL>

Bind the window framebuffer making it the current render target


self.width = width<EOL>self.height = height<EOL>self.buffer_width, self.buffer_height = self.width, self.height<EOL>self.set_default_viewport()<EOL>

Sets the new size and buffer size internally


self.frames = <NUM_LIT:0><EOL>self.width = settings.WINDOW['<STR_LIT:size>'][<NUM_LIT:0>]<EOL>self.height = settings.WINDOW['<STR_LIT:size>'][<NUM_LIT:1>]<EOL>self.buffer_width = self.width<EOL>self.buffer_height = self.height<EOL>self.fbo = None<EOL>self.sys_camera = None<EOL>self.timer = None<EOL>self.timeline = None<EOL>self.gl_version = GLVersion(<EOL>*settings.OPENGL['<STR_LIT:version>'],<EOL>int("<STR_LIT>".format(*settings.OPENGL['<STR_LIT:version>']))<EOL>)<EOL>self.title = settings.WINDOW.get('<STR_LIT:title>') or "<STR_LIT>"<EOL>self.aspect_ratio = settings.WINDOW.get('<STR_LIT>', <NUM_LIT:16> / <NUM_LIT:9>)<EOL>self.samples = settings.WINDOW.get('<STR_LIT>', <NUM_LIT:0>)<EOL>self.resizable = settings.WINDOW.get('<STR_LIT>') or False<EOL>self.fullscreen = settings.WINDOW.get('<STR_LIT>')<EOL>self.vsync = settings.WINDOW.get('<STR_LIT>')<EOL>self.cursor = settings.WINDOW.get('<STR_LIT>')<EOL>self.clear_color = (<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>)<EOL>self.clear_depth = (<NUM_LIT:1.0>)<EOL>self.ctx = None<EOL>

Base window intializer reading values from ``settings``.

When creating the initializer in your own window always call
this methods using ``super().__init__()``.

The main responsebility of the initializer is to:

* initialize the window library
* identify the window framebuffer
* set up keyboard and mouse events
* create the ``moderngl.Context`` instance
* register the window in ``context.WINDOW``


@property<EOL><INDENT>def size(self) -> Tuple[int, int]:<DEDENT>

return (self.width, self.height)<EOL>

(width, height) tuple containing the window size.

Note that for certain displays we rely on :py:func:`buffer_size`
to get the actual window buffer size. This is fairly common
for retina and 4k displays where the UI scale is > 1.0


@property<EOL><INDENT>def buffer_size(self) -> Tuple[int, int]:<DEDENT>

return (self.buffer_width, self.buffer_height)<EOL>

(width, heigh) buffer size of the window.

This is the actual buffer size of the window
taking UI scale into account. A 1920 x 1080
window running in an environment with UI scale 2.0
would have a 3840 x 2160 window buffer.


def draw(self, current_time, frame_time):

self.set_default_viewport()<EOL>self.timeline.draw(current_time, frame_time, self.fbo)<EOL>

Draws a frame. Internally it calls the
configured timeline's draw method.

Args:
    current_time (float): The current time (preferrably always from the configured timer class)
    frame_time (float): The duration of the previous frame in seconds


def clear_values(self, red=<NUM_LIT:0.0>, green=<NUM_LIT:0.0>, blue=<NUM_LIT:0.0>, alpha=<NUM_LIT:0.0>, depth=<NUM_LIT:1.0>):

self.clear_color = (red, green, blue, alpha)<EOL>self.clear_depth = depth<EOL>

Sets the clear values for the window buffer.

Args:
    red (float): red compoent
    green (float): green compoent
    blue (float): blue compoent
    alpha (float): alpha compoent
    depth (float): depth value


raise NotImplementedError("<STR_LIT>".format(self.__class__))<EOL>

Set the window buffer as the current render target

Raises:
    NotImplementedError


raise NotImplementedError()<EOL>

Swap the buffers. Most windows have at least support for double buffering
cycling a back and front buffer.

Raises:
    NotImplementedError


Resize the window. Should normallty be overriden
when implementing a window as most window libraries need additional logic here.

Args:
    width (int): Width of the window
    height: (int): Height of the window


raise NotImplementedError()<EOL>

Set the window in close state. This doesn't actually close the window,
but should make :py:func:`should_close` return ``True`` so the
main loop can exit gracefully.

Raises:
    NotImplementedError


raise NotImplementedError()<EOL>

Check if window should close. This should always be checked in the main draw loop.

Raises:
    NotImplementedError


raise NotImplementedError()<EOL>

The actual teardown of the window.

Raises:
    NotImplementedError


def keyboard_event(self, key, action, modifier):

<EOL>if key == self.keys.ESCAPE:<EOL><INDENT>self.close()<EOL>return<EOL><DEDENT>if key == self.keys.SPACE and action == self.keys.ACTION_PRESS:<EOL><INDENT>self.timer.toggle_pause()<EOL><DEDENT>if key == self.keys.D:<EOL><INDENT>if action == self.keys.ACTION_PRESS:<EOL><INDENT>self.sys_camera.move_right(True)<EOL><DEDENT>elif action == self.keys.ACTION_RELEASE:<EOL><INDENT>self.sys_camera.move_right(False)<EOL><DEDENT><DEDENT>elif key == self.keys.A:<EOL><INDENT>if action == self.keys.ACTION_PRESS:<EOL><INDENT>self.sys_camera.move_left(True)<EOL><DEDENT>elif action == self.keys.ACTION_RELEASE:<EOL><INDENT>self.sys_camera.move_left(False)<EOL><DEDENT><DEDENT>elif key == self.keys.W:<EOL><INDENT>if action == self.keys.ACTION_PRESS:<EOL><INDENT>self.sys_camera.move_forward(True)<EOL><DEDENT>if action == self.keys.ACTION_RELEASE:<EOL><INDENT>self.sys_camera.move_forward(False)<EOL><DEDENT><DEDENT>elif key == self.keys.S:<EOL><INDENT>if action == self.keys.ACTION_PRESS:<EOL><INDENT>self.sys_camera.move_backward(True)<EOL><DEDENT>if action == self.keys.ACTION_RELEASE:<EOL><INDENT>self.sys_camera.move_backward(False)<EOL><DEDENT><DEDENT>elif key == self.keys.Q:<EOL><INDENT>if action == self.keys.ACTION_PRESS:<EOL><INDENT>self.sys_camera.move_down(True)<EOL><DEDENT>if action == self.keys.ACTION_RELEASE:<EOL><INDENT>self.sys_camera.move_down(False)<EOL><DEDENT><DEDENT>elif key == self.keys.E:<EOL><INDENT>if action == self.keys.ACTION_PRESS:<EOL><INDENT>self.sys_camera.move_up(True)<EOL><DEDENT>if action == self.keys.ACTION_RELEASE:<EOL><INDENT>self.sys_camera.move_up(False)<EOL><DEDENT><DEDENT>if key == self.keys.X and action == self.keys.ACTION_PRESS:<EOL><INDENT>screenshot.create()<EOL><DEDENT>if key == self.keys.R and action == self.keys.ACTION_PRESS:<EOL><INDENT>project.instance.reload_programs()<EOL><DEDENT>if key == self.keys.RIGHT and action == self.keys.ACTION_PRESS:<EOL><INDENT>self.timer.set_time(self.timer.get_time() + <NUM_LIT>)<EOL><DEDENT>if key == self.keys.LEFT and action == self.keys.ACTION_PRESS:<EOL><INDENT>self.timer.set_time(self.timer.get_time() - <NUM_LIT>)<EOL><DEDENT>self.timeline.key_event(key, action, modifier)<EOL>

Handles the standard keyboard events such as camera movements,
taking a screenshot, closing the window etc.

Can be overriden add new keyboard events. Ensure this method
is also called if you want to keep the standard features.

Arguments:
    key: The key that was pressed or released
    action: The key action. Can be `ACTION_PRESS` or `ACTION_RELEASE`
    modifier: Modifiers such as holding shift or ctrl


self.sys_camera.rot_state(x, y)<EOL>

The standard mouse movement event method.
Can be overriden to add new functionality.
By default this feeds the system camera with new values.

Args:
    x: The current mouse x position
    y: The current mouse y position
    dx: Delta x postion (x position difference from the previous event)
    dy: Delta y postion (y position difference from the previous event)


print("<STR_LIT>")<EOL>print('<STR_LIT>', moderngl.__version__)<EOL>print('<STR_LIT>', self.ctx.info['<STR_LIT>'])<EOL>print('<STR_LIT>', self.ctx.info['<STR_LIT>'])<EOL>print('<STR_LIT>', self.ctx.info['<STR_LIT>'])<EOL>print('<STR_LIT>', sys.version)<EOL>print('<STR_LIT>', sys.platform)<EOL>print('<STR_LIT>', self.ctx.version_code)<EOL>


<EOL>expected_height = int(self.buffer_width / self.aspect_ratio)<EOL>blank_space = self.buffer_height - expected_height<EOL>self.fbo.viewport = (<NUM_LIT:0>, blank_space // <NUM_LIT:2>, self.buffer_width, expected_height)<EOL>

Calculates the viewport based on the configured aspect ratio in settings.
Will add black borders if the window do not match the viewport.


def window(raise_on_error=True) -> BaseWindow:

if not WINDOW and raise_on_error:<EOL><INDENT>raise RuntimeError("<STR_LIT>")<EOL><DEDENT>return WINDOW<EOL>

The window instance we are rendering to

:param raise_on_error: Raise an error if the window is not created yet


win = window()<EOL>if not win.ctx:<EOL><INDENT>raise RuntimeError("<STR_LIT>")<EOL><DEDENT>return win.ctx<EOL>


super().__init__()<EOL>self.headless_frames = getattr(settings, '<STR_LIT>', <NUM_LIT:0>)<EOL>self.headless_duration = getattr(settings, '<STR_LIT>', <NUM_LIT:0>)<EOL>if not self.headless_frames and not self.headless_duration:<EOL><INDENT>raise ImproperlyConfigured("<STR_LIT>")<EOL><DEDENT>self._close = False<EOL>self.ctx = moderngl.create_standalone_context(require=self.gl_version.code)<EOL>context.WINDOW = self<EOL>self.fbo = self.ctx.framebuffer(<EOL>color_attachments=self.ctx.texture(self.size, <NUM_LIT:4>),<EOL>depth_attachment=self.ctx.depth_texture(self.size),<EOL>)<EOL>self.set_default_viewport()<EOL>self.fbo.use()<EOL>

Creates a standalone ``moderngl.Context``.
The headless window currently have no event input from keyboard or mouse.

Using this window require either ``settings`` values to be present:

* ``HEADLESS_FRAMES``: How many frames should be rendered before closing the window
* ``HEADLESS_DURATION``: How many seconds rendering should last before the window closes


super().draw(current_time, frame_time)<EOL>if self.headless_duration and current_time >= self.headless_duration:<EOL><INDENT>self.close()<EOL><DEDENT>

Calls the superclass ``draw()`` methods and checks ``HEADLESS_FRAMES``/``HEADLESS_DURATION``


self.fbo.use()<EOL>

Binds the framebuffer representing this window


return self._close<EOL>

Checks if the internal close state is set


self._close = True<EOL>


pass<EOL>

Resizing is not supported by the headless window.
We simply override with an empty method.


self.frames += <NUM_LIT:1><EOL>if self.headless_frames and self.frames >= self.headless_frames:<EOL><INDENT>self.close()<EOL><DEDENT>

Headless window currently don't support double buffering.
We only increment the frame counter here.


pass<EOL>

No teardown is needed. We override with an empty method


@property<EOL><INDENT>def label(self) -> str:<DEDENT>

return self._kwargs.get('<STR_LIT:label>')<EOL>

(str) The internal label this resource is associated with


return self._kwargs.get('<STR_LIT:path>')<EOL>

(str) The path to a resource when a single file is specified


return self._kwargs.get('<STR_LIT>') or self.default_loader<EOL>


@property<EOL><INDENT>def loader_cls(self) -> Type:<DEDENT>

return self._kwargs.get('<STR_LIT>')<EOL>

(Type) The loader class for this resource


@property<EOL><INDENT>def resolved_path(self) -> Path:<DEDENT>

return self.kwargs.get('<STR_LIT>')<EOL>

(pathlib.Path) The resolved path by a finder


@property<EOL><INDENT>def kwargs(self) -> Dict[str, str]:<DEDENT>

return self._kwargs<EOL>

(dict) All keywords arguments passed to the resource


def load(self, meta: ResourceDescription) -> Any:

self._check_meta(meta)<EOL>self.resolve_loader(meta)<EOL>return meta.loader_cls(meta).load()<EOL>

Loads a resource or return existing one

:param meta: The resource description


self._check_meta(meta)<EOL>self.resolve_loader(meta)<EOL>self._resources.append(meta)<EOL>

Add a resource to this pool.
The resource is loaded and returned when ``load_pool()`` is called.

:param meta: The resource description


for meta in self._resources:<EOL><INDENT>resource = self.load(meta)<EOL>yield meta, resource<EOL><DEDENT>self._resources = []<EOL>

Loads all the data files using the configured finders.


def resolve_loader(self, meta: ResourceDescription):

meta.loader_cls = self.get_loader(meta, raise_on_error=True)<EOL>

Attempts to assign a loader class to a resource description

:param meta: The resource description instance


def get_loader(self, meta: ResourceDescription, raise_on_error=False) -> BaseLoader:

for loader in self._loaders:<EOL><INDENT>if loader.name == meta.loader:<EOL><INDENT>return loader<EOL><DEDENT><DEDENT>if raise_on_error:<EOL><INDENT>raise ImproperlyConfigured(<EOL>"<STR_LIT>".format(<EOL>meta.loader, meta, [loader.name for loader in self._loaders]))<EOL><DEDENT>

Attempts to get a loader

:param meta: The resource description instance
:param raise_on_error: Raise ImproperlyConfigured if the loader cannot be resolved
:returns: The requested loader class


name = name.lower()<EOL>track = self.track_map.get(name)<EOL>if not track:<EOL><INDENT>track = Track(name)<EOL>self.tacks.append(track)<EOL>self.track_map[name] = track<EOL><DEDENT>return track<EOL>

Get or create a Track object.

:param name: Name of the track
:return: Track object


def resolve_loader(self, meta: SceneDescription):

for loader_cls in self._loaders:<EOL><INDENT>if loader_cls.supports_file(meta):<EOL><INDENT>meta.loader_cls = loader_cls<EOL>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise ImproperlyConfigured(<EOL>"<STR_LIT>".format(meta.path))<EOL><DEDENT>

Resolve scene loader based on file extension


def resolve_loader(self, meta: ProgramDescription):

if not meta.loader:<EOL><INDENT>meta.loader = '<STR_LIT>' if meta.path else '<STR_LIT>'<EOL><DEDENT>for loader_cls in self._loaders:<EOL><INDENT>if loader_cls.name == meta.loader:<EOL><INDENT>meta.loader_cls = loader_cls<EOL>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise ImproperlyConfigured(<EOL>(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>).format(meta.path)<EOL>)<EOL><DEDENT>


for name, value in kwargs.items():<EOL><INDENT>setattr(self, name, value)<EOL><DEDENT>


dirs = list(self.PROGRAM_DIRS)<EOL>dirs.append(directory)<EOL>self.PROGRAM_DIRS = dirs<EOL>


dirs = list(self.TEXTURE_DIRS)<EOL>dirs.append(directory)<EOL>self.TEXTURE_DIRS = dirs<EOL>


dirs = list(self.DATA_DIRS)<EOL>dirs.append(directory)<EOL>self.DATA_DIRS = dirs<EOL>


return os.path.join(__name__.split('<STR_LIT:.>')[-<NUM_LIT:2>], path)<EOL>

Prepend the effect package name to a path so resources
can still be loaded when copied into a new effect package.


if n < <NUM_LIT:0>:<EOL><INDENT>return <NUM_LIT:1><EOL><DEDENT>if n == <NUM_LIT:0>:<EOL><INDENT>return <NUM_LIT:0><EOL><DEDENT>return ((<NUM_LIT:2> * n - <NUM_LIT:2>) * <NUM_LIT:3>) + calculate_triangles(n - <NUM_LIT:2>)<EOL>

Calculate the number of triangles for the barycentric subdivision of a
single triangle (where the inner and outer subdivision is equal


def _get_queues(g, queues, edge, edge_type):

INT = numbers.Integral<EOL>if isinstance(queues, INT):<EOL><INDENT>queues = [queues]<EOL><DEDENT>elif queues is None:<EOL><INDENT>if edge is not None:<EOL><INDENT>if isinstance(edge, tuple):<EOL><INDENT>if isinstance(edge[<NUM_LIT:0>], INT) and isinstance(edge[<NUM_LIT:1>], INT):<EOL><INDENT>queues = [g.edge_index[edge]]<EOL><DEDENT><DEDENT>elif isinstance(edge[<NUM_LIT:0>], collections.Iterable):<EOL><INDENT>if np.array([len(e) == <NUM_LIT:2> for e in edge]).all():<EOL><INDENT>queues = [g.edge_index[e] for e in edge]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>queues = [g.edge_index[edge]]<EOL><DEDENT><DEDENT>elif edge_type is not None:<EOL><INDENT>if isinstance(edge_type, collections.Iterable):<EOL><INDENT>edge_type = set(edge_type)<EOL><DEDENT>else:<EOL><INDENT>edge_type = set([edge_type])<EOL><DEDENT>tmp = []<EOL>for e in g.edges():<EOL><INDENT>if g.ep(e, '<STR_LIT>') in edge_type:<EOL><INDENT>tmp.append(g.edge_index[e])<EOL><DEDENT><DEDENT>queues = np.array(tmp, int)<EOL><DEDENT>if queues is None:<EOL><INDENT>queues = range(g.number_of_edges())<EOL><DEDENT><DEDENT>return queues<EOL>

Used to specify edge indices from different types of arguments.


def animate(self, out=None, t=None, line_kwargs=None,<EOL>scatter_kwargs=None, **kwargs):

if not self._initialized:<EOL><INDENT>msg = ("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>raise QueueingToolError(msg)<EOL><DEDENT>if not HAS_MATPLOTLIB:<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ImportError(msg)<EOL><DEDENT>self._update_all_colors()<EOL>kwargs.setdefault('<STR_LIT>', self.colors['<STR_LIT>'])<EOL>fig = plt.figure(figsize=kwargs.get('<STR_LIT>', (<NUM_LIT:7>, <NUM_LIT:7>)))<EOL>ax = fig.gca()<EOL>mpl_kwargs = {<EOL>'<STR_LIT>': line_kwargs,<EOL>'<STR_LIT>': scatter_kwargs,<EOL>'<STR_LIT>': kwargs.get('<STR_LIT>')<EOL>}<EOL>line_args, scat_args = self.g.lines_scatter_args(**mpl_kwargs)<EOL>lines = LineCollection(**line_args)<EOL>lines = ax.add_collection(lines)<EOL>scatt = ax.scatter(**scat_args)<EOL>t = np.infty if t is None else t<EOL>now = self._t<EOL>def update(frame_number):<EOL><INDENT>if t is not None:<EOL><INDENT>if self._t > now + t:<EOL><INDENT>return False<EOL><DEDENT><DEDENT>self._simulate_next_event(slow=True)<EOL>lines.set_color(line_args['<STR_LIT>'])<EOL>scatt.set_edgecolors(scat_args['<STR_LIT>'])<EOL>scatt.set_facecolor(scat_args['<STR_LIT:c>'])<EOL><DEDENT>if hasattr(ax, '<STR_LIT>'):<EOL><INDENT>ax.set_facecolor(kwargs['<STR_LIT>'])<EOL><DEDENT>else:<EOL><INDENT>ax.set_axis_bgcolor(kwargs['<STR_LIT>'])<EOL><DEDENT>ax.get_xaxis().set_visible(False)<EOL>ax.get_yaxis().set_visible(False)<EOL>animation_args = {<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': False,<EOL>'<STR_LIT>': <NUM_LIT:10>,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': update,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': fig,<EOL>'<STR_LIT>': None,<EOL>}<EOL>for key, value in kwargs.items():<EOL><INDENT>if key in animation_args:<EOL><INDENT>animation_args[key] = value<EOL><DEDENT><DEDENT>animation = FuncAnimation(**animation_args)<EOL>if '<STR_LIT:filename>' not in kwargs:<EOL><INDENT>plt.ioff()<EOL>plt.show()<EOL><DEDENT>else:<EOL><INDENT>save_args = {<EOL>'<STR_LIT:filename>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None,<EOL>'<STR_LIT>': None<EOL>}<EOL>for key, value in kwargs.items():<EOL><INDENT>if key in save_args:<EOL><INDENT>save_args[key] = value<EOL><DEDENT><DEDENT>animation.save(**save_args)<EOL><DEDENT>

Animates the network as it's simulating.

        The animations can be saved to disk or viewed in interactive
        mode. Closing the window ends the animation if viewed in
        interactive mode. This method calls
        :meth:`~matplotlib.axes.scatter`, and
        :class:`~matplotlib.collections.LineCollection`, and any
        keyword arguments they accept can be passed to them.

        Parameters
        ----------
        out : str (optional)
            The location where the frames for the images will be saved.
            If this parameter is not given, then the animation is shown
            in interactive mode.
        t : float (optional)
            The amount of simulation time to simulate forward. If
            given, and ``out`` is given, ``t`` is used instead of
            ``n``.
        line_kwargs : dict (optional, default: None)
            Any keyword arguments accepted by
            :class:`~matplotlib.collections.LineCollection`.
        scatter_kwargs : dict (optional, default: None)
            Any keyword arguments accepted by
            :meth:`~matplotlib.axes.Axes.scatter`.
        bgcolor : list (optional, keyword only)
            A list with 4 floats representing a RGBA color. The
            default is defined in ``self.colors['bgcolor']``.
        figsize : tuple (optional, keyword only, default: ``(7, 7)``)
            The width and height of the figure in inches.
        **kwargs :
            This method calls
            :class:`~matplotlib.animation.FuncAnimation` and
            optionally :meth:`.matplotlib.animation.FuncAnimation.save`.
            Any keyword that can be passed to these functions are
            passed via ``kwargs``.

        Notes
        -----
        There are several parameters automatically set and passed to
        matplotlib's :meth:`~matplotlib.axes.Axes.scatter`,
        :class:`~matplotlib.collections.LineCollection`, and
        :class:`~matplotlib.animation.FuncAnimation` by default.
        These include:

            * :class:`~matplotlib.animation.FuncAnimation`: Uses the
              defaults for that function. Saving the animation is done
              by passing the 'filename' keyword argument to this method.
              This method also accepts any keyword arguments accepted
              by :meth:`~matplotlib.animation.FuncAnimation.save`.
            * :class:`~matplotlib.collections.LineCollection`: The default
              arguments are taken from
              :meth:`.QueueNetworkDiGraph.lines_scatter_args`.
            * :meth:`~matplotlib.axes.Axes.scatter`: The default
              arguments are taken from
              :meth:`.QueueNetworkDiGraph.lines_scatter_args`.

        Raises
        ------
        QueueingToolError
            Will raise a :exc:`.QueueingToolError` if the
            ``QueueNetwork`` has not been initialized. Call
            :meth:`.initialize` before running.

        Examples
        --------
        This function works similarly to ``QueueNetwork's``
        :meth:`.draw` method.

        >>> import queueing_tool as qt
        >>> g = qt.generate_pagerank_graph(100, seed=13)
        >>> net = qt.QueueNetwork(g, seed=13)
        >>> net.initialize()
        >>> net.animate(figsize=(4, 4)) # doctest: +SKIP

        To stop the animation just close the window. If you want to
        write the animation to disk run something like the following:

        >>> kwargs = {
        ...     'filename': 'test.mp4',
        ...     'frames': 300,
        ...     'fps': 30,
        ...     'writer': 'mencoder',
        ...     'figsize': (4, 4),
        ...     'vertex_size': 15
        ... }
        >>> net.animate(**kwargs) # doctest: +SKIP


self._t = <NUM_LIT:0><EOL>self.num_events = <NUM_LIT:0><EOL>self.num_agents = np.zeros(self.nE, int)<EOL>self._fancy_heap = PriorityQueue()<EOL>self._prev_edge = None<EOL>self._initialized = False<EOL>self.reset_colors()<EOL>for q in self.edge2queue:<EOL><INDENT>q.clear()<EOL><DEDENT>

Resets the queue to its initial state.

        The attributes ``t``, ``num_events``, ``num_agents`` are set to
        zero, :meth:`.reset_colors` is called, and the
        :meth:`.QueueServer.clear` method is called for each queue in
        the network.

        Notes
        -----
        ``QueueNetwork`` must be re-initialized before any simulations
        can run.


def clear_data(self, queues=None, edge=None, edge_type=None):

queues = _get_queues(self.g, queues, edge, edge_type)<EOL>for k in queues:<EOL><INDENT>self.edge2queue[k].data = {}<EOL><DEDENT>

Clears data from all queues.

        If none of the parameters are given then every queue's data is
        cleared.

        Parameters
        ----------
        queues : int or an iterable of int (optional)
            The edge index (or an iterable of edge indices) identifying
            the :class:`QueueServer(s)<.QueueServer>` whose data will
            be cleared.
        edge : 2-tuple of int or *array_like* (optional)
            Explicitly specify which queues' data to clear. Must be
            either:

            * A 2-tuple of the edge's source and target vertex
              indices, or
            * An iterable of 2-tuples of the edge's source and
              target vertex indices.

        edge_type : int or an iterable of int (optional)
            A integer, or a collection of integers identifying which
            edge types will have their data cleared.


net = QueueNetwork(None)<EOL>net.g = self.g.copy()<EOL>net.max_agents = copy.deepcopy(self.max_agents)<EOL>net.nV = copy.deepcopy(self.nV)<EOL>net.nE = copy.deepcopy(self.nE)<EOL>net.num_agents = copy.deepcopy(self.num_agents)<EOL>net.num_events = copy.deepcopy(self.num_events)<EOL>net._t = copy.deepcopy(self._t)<EOL>net._initialized = copy.deepcopy(self._initialized)<EOL>net._prev_edge = copy.deepcopy(self._prev_edge)<EOL>net._blocking = copy.deepcopy(self._blocking)<EOL>net.colors = copy.deepcopy(self.colors)<EOL>net.out_edges = copy.deepcopy(self.out_edges)<EOL>net.in_edges = copy.deepcopy(self.in_edges)<EOL>net.edge2queue = copy.deepcopy(self.edge2queue)<EOL>net._route_probs = copy.deepcopy(self._route_probs)<EOL>if net._initialized:<EOL><INDENT>keys = [q._key() for q in net.edge2queue if q._time < np.infty]<EOL>net._fancy_heap = PriorityQueue(keys, net.nE)<EOL><DEDENT>return net<EOL>


def draw(self, update_colors=True, line_kwargs=None,<EOL>scatter_kwargs=None, **kwargs):

if not HAS_MATPLOTLIB:<EOL><INDENT>raise ImportError("<STR_LIT>")<EOL><DEDENT>if update_colors:<EOL><INDENT>self._update_all_colors()<EOL><DEDENT>if '<STR_LIT>' not in kwargs:<EOL><INDENT>kwargs['<STR_LIT>'] = self.colors['<STR_LIT>']<EOL><DEDENT>self.g.draw_graph(line_kwargs=line_kwargs,<EOL>scatter_kwargs=scatter_kwargs, **kwargs)<EOL>

Draws the network. The coloring of the network corresponds
        to the number of agents at each queue.

        Parameters
        ----------
        update_colors : ``bool`` (optional, default: ``True``).
            Specifies whether all the colors are updated.
        line_kwargs : dict (optional, default: None)
            Any keyword arguments accepted by
            :class:`~matplotlib.collections.LineCollection`
        scatter_kwargs : dict (optional, default: None)
            Any keyword arguments accepted by
            :meth:`~matplotlib.axes.Axes.scatter`.
        bgcolor : list (optional, keyword only)
            A list with 4 floats representing a RGBA color. The
            default is defined in ``self.colors['bgcolor']``.
        figsize : tuple (optional, keyword only, default: ``(7, 7)``)
            The width and height of the canvas in inches.
        **kwargs
            Any parameters to pass to
            :meth:`.QueueNetworkDiGraph.draw_graph`.

        Notes
        -----
        This method relies heavily on
        :meth:`.QueueNetworkDiGraph.draw_graph`. Also, there is a
        parameter that sets the background color of the canvas, which
        is the ``bgcolor`` parameter.

        Examples
        --------
        To draw the current state of the network, call:

        >>> import queueing_tool as qt
        >>> g = qt.generate_pagerank_graph(100, seed=13)
        >>> net = qt.QueueNetwork(g, seed=13)
        >>> net.initialize(100)
        >>> net.simulate(1200)
        >>> net.draw() # doctest: +SKIP

        If you specify a file name and location, the drawing will be
        saved to disk. For example, to save the drawing to the current
        working directory do the following:

        >>> net.draw(fname="state.png", scatter_kwargs={'s': 40}) # doctest: +SKIP

        .. figure:: current_state1.png
            :align: center

        The shade of each edge depicts how many agents are located at
        the corresponding queue. The shade of each vertex is determined
        by the total number of inbound agents. Although loops are not
        visible by default, the vertex that corresponds to a loop shows
        how many agents are in that loop.

        There are several additional parameters that can be passed --
        all :meth:`.QueueNetworkDiGraph.draw_graph` parameters are
        valid. For example, to show the edges as dashed lines do the
        following.

        >>> net.draw(line_kwargs={'linestyle': 'dashed'}) # doctest: +SKIP


def get_agent_data(self, queues=None, edge=None, edge_type=None, return_header=False):

queues = _get_queues(self.g, queues, edge, edge_type)<EOL>data = {}<EOL>for qid in queues:<EOL><INDENT>for agent_id, dat in self.edge2queue[qid].data.items():<EOL><INDENT>datum = np.zeros((len(dat), <NUM_LIT:6>))<EOL>datum[:, :<NUM_LIT:5>] = np.array(dat)<EOL>datum[:, <NUM_LIT:5>] = qid<EOL>if agent_id in data:<EOL><INDENT>data[agent_id] = np.vstack((data[agent_id], datum))<EOL><DEDENT>else:<EOL><INDENT>data[agent_id] = datum<EOL><DEDENT><DEDENT><DEDENT>dType = [<EOL>('<STR_LIT:a>', float),<EOL>('<STR_LIT:s>', float),<EOL>('<STR_LIT:d>', float),<EOL>('<STR_LIT:q>', float),<EOL>('<STR_LIT:n>', float),<EOL>('<STR_LIT:id>', float)<EOL>]<EOL>for agent_id, dat in data.items():<EOL><INDENT>datum = np.array([tuple(d) for d in dat.tolist()], dtype=dType)<EOL>datum = np.sort(datum, order='<STR_LIT:a>')<EOL>data[agent_id] = np.array([tuple(d) for d in datum])<EOL><DEDENT>if return_header:<EOL><INDENT>return data, '<STR_LIT>'<EOL><DEDENT>return data<EOL>

Gets data from queues and organizes it by agent.

        If none of the parameters are given then data from every
        :class:`.QueueServer` is retrieved.

        Parameters
        ----------
        queues : int or *array_like* (optional)
            The edge index (or an iterable of edge indices) identifying
            the :class:`QueueServer(s)<.QueueServer>` whose data will
            be retrieved.
        edge : 2-tuple of int or *array_like* (optional)
            Explicitly specify which queues to retrieve agent data
            from. Must be either:

            * A 2-tuple of the edge's source and target vertex
              indices, or
            * An iterable of 2-tuples of the edge's source and
              target vertex indices.

        edge_type : int or an iterable of int (optional)
            A integer, or a collection of integers identifying which
            edge types to retrieve agent data from.
        return_header : bool (optonal, default: False)
            Determines whether the column headers are returned.

        Returns
        -------
        dict
            Returns a ``dict`` where the keys are the
            :class:`Agent's<.Agent>` ``agent_id`` and the values are
            :class:`ndarrays<~numpy.ndarray>` for that
            :class:`Agent's<.Agent>` data. The columns of this array
            are as follows:

            * First: The arrival time of an agent.
            * Second: The service start time of an agent.
            * Third: The departure time of an agent.
            * Fourth: The length of the queue upon the agents arrival.
            * Fifth: The total number of :class:`Agents<.Agent>` in the
              :class:`.QueueServer`.
            * Sixth: the :class:`QueueServer's<.QueueServer>` id
              (its edge index).

        headers : str (optional)
            A comma seperated string of the column headers. Returns
            ``'arrival,service,departure,num_queued,num_total,q_id'``


def get_queue_data(self, queues=None, edge=None, edge_type=None, return_header=False):

queues = _get_queues(self.g, queues, edge, edge_type)<EOL>data = np.zeros((<NUM_LIT:0>, <NUM_LIT:6>))<EOL>for q in queues:<EOL><INDENT>dat = self.edge2queue[q].fetch_data()<EOL>if len(dat) > <NUM_LIT:0>:<EOL><INDENT>data = np.vstack((data, dat))<EOL><DEDENT><DEDENT>if return_header:<EOL><INDENT>return data, '<STR_LIT>'<EOL><DEDENT>return data<EOL>

Gets data from all the queues.

        If none of the parameters are given then data from every
        :class:`.QueueServer` is retrieved.

        Parameters
        ----------
        queues : int or an *array_like* of int, (optional)
            The edge index (or an iterable of edge indices) identifying
            the :class:`QueueServer(s)<.QueueServer>` whose data will
            be retrieved.
        edge : 2-tuple of int or *array_like* (optional)
            Explicitly specify which queues to retrieve data from. Must
            be either:

            * A 2-tuple of the edge's source and target vertex
              indices, or
            * An iterable of 2-tuples of the edge's source and
              target vertex indices.

        edge_type : int or an iterable of int (optional)
            A integer, or a collection of integers identifying which
            edge types to retrieve data from.
        return_header : bool (optonal, default: False)
            Determines whether the column headers are returned.

        Returns
        -------
        out : :class:`~numpy.ndarray`
            * 1st: The arrival time of an agent.
            * 2nd: The service start time of an agent.
            * 3rd: The departure time of an agent.
            * 4th: The length of the queue upon the agents arrival.
            * 5th: The total number of :class:`Agents<.Agent>` in the
              :class:`.QueueServer`.
            * 6th: The :class:`QueueServer's<.QueueServer>` edge index.

        out : str (optional)
            A comma seperated string of the column headers. Returns
            ``'arrival,service,departure,num_queued,num_total,q_id'```

        Examples
        --------
        Data is not collected by default. Before simulating, by sure to
        turn it on (as well as initialize the network). The following
        returns data from queues with ``edge_type`` 1 or 3:

        >>> import queueing_tool as qt
        >>> g = qt.generate_pagerank_graph(100, seed=13)
        >>> net = qt.QueueNetwork(g, seed=13)
        >>> net.start_collecting_data()
        >>> net.initialize(10)
        >>> net.simulate(2000)
        >>> data = net.get_queue_data(edge_type=(1, 3))

        To get data from an edge connecting two vertices do the
        following:

        >>> data = net.get_queue_data(edge=(1, 50))

        To get data from several edges do the following:

        >>> data = net.get_queue_data(edge=[(1, 50), (10, 91), (99, 99)])

        You can specify the edge indices as well:

        >>> data = net.get_queue_data(queues=(20, 14, 0, 4))


def initialize(self, nActive=<NUM_LIT:1>, queues=None, edges=None, edge_type=None):

if queues is None and edges is None and edge_type is None:<EOL><INDENT>if nActive >= <NUM_LIT:1> and isinstance(nActive, numbers.Integral):<EOL><INDENT>qs = [q.edge[<NUM_LIT:2>] for q in self.edge2queue if q.edge[<NUM_LIT:3>] != <NUM_LIT:0>]<EOL>n = min(nActive, len(qs))<EOL>queues = np.random.choice(qs, size=n, replace=False)<EOL><DEDENT>elif not isinstance(nActive, numbers.Integral):<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise TypeError(msg)<EOL><DEDENT>else:<EOL><INDENT>msg = ("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>raise ValueError(msg)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>queues = _get_queues(self.g, queues, edges, edge_type)<EOL><DEDENT>queues = [e for e in queues if self.edge2queue[e].edge[<NUM_LIT:3>] != <NUM_LIT:0>]<EOL>if len(queues) == <NUM_LIT:0>:<EOL><INDENT>raise QueueingToolError("<STR_LIT>")<EOL><DEDENT>if len(queues) > self.max_agents:<EOL><INDENT>queues = queues[:self.max_agents]<EOL><DEDENT>for ei in queues:<EOL><INDENT>self.edge2queue[ei].set_active()<EOL>self.num_agents[ei] = self.edge2queue[ei]._num_total<EOL><DEDENT>keys = [q._key() for q in self.edge2queue if q._time < np.infty]<EOL>self._fancy_heap = PriorityQueue(keys, self.nE)<EOL>self._initialized = True<EOL>

Prepares the ``QueueNetwork`` for simulation.

        Each :class:`.QueueServer` in the network starts inactive,
        which means they do not accept arrivals from outside the
        network, and they have no agents in their system. This method
        sets queues to active, which then allows agents to arrive from
        outside the network.

        Parameters
        ----------
        nActive : int (optional, default: ``1``)
            The number of queues to set as active. The queues are
            selected randomly.
        queues : int *array_like* (optional)
            The edge index (or an iterable of edge indices) identifying
            the :class:`QueueServer(s)<.QueueServer>` to make active by.
        edges : 2-tuple of int or *array_like* (optional)
            Explicitly specify which queues to make active. Must be
            either:

            * A 2-tuple of the edge's source and target vertex
              indices, or
            * An iterable of 2-tuples of the edge's source and
              target vertex indices.

        edge_type : int or an iterable of int (optional)
            A integer, or a collection of integers identifying which
            edge types will be set active.

        Raises
        ------
        ValueError
            If ``queues``, ``egdes``, and ``edge_type`` are all ``None``
            and ``nActive`` is an integer less than 1
            :exc:`~ValueError` is raised.
        TypeError
            If ``queues``, ``egdes``, and ``edge_type`` are all ``None``
            and ``nActive`` is not an integer then a :exc:`~TypeError`
            is raised.
        QueueingToolError
            Raised if all the queues specified are
            :class:`NullQueues<.NullQueue>`.

        Notes
        -----
        :class:`NullQueues<.NullQueue>` cannot be activated, and are
        sifted out if they are specified. More specifically, every edge
        with edge type 0 is sifted out.


if self._fancy_heap.size == <NUM_LIT:0>:<EOL><INDENT>event_type = '<STR_LIT>'<EOL>edge_index = None<EOL><DEDENT>else:<EOL><INDENT>s = [q._key() for q in self.edge2queue]<EOL>s.sort()<EOL>e = s[<NUM_LIT:0>][<NUM_LIT:1>]<EOL>q = self.edge2queue[e]<EOL>event_type = '<STR_LIT>' if q.next_event_description() == <NUM_LIT:1> else '<STR_LIT>'<EOL>edge_index = q.edge[<NUM_LIT:2>]<EOL><DEDENT>return event_type, edge_index<EOL>

Returns whether the next event is an arrival or a departure
        and the queue the event is accuring at.

        Returns
        -------
        des : str
            Indicates whether the next event is an arrival, a
            departure, or nothing; returns ``'Arrival'``,
            ``'Departure'``, or ``'Nothing'``.
        edge : int or ``None``
            The edge index of the edge that this event will occur at.
            If there are no events then ``None`` is returned.


for k, e in enumerate(self.g.edges()):<EOL><INDENT>self.g.set_ep(e, '<STR_LIT>', self.edge2queue[k].colors['<STR_LIT>'])<EOL><DEDENT>for v in self.g.nodes():<EOL><INDENT>self.g.set_vp(v, '<STR_LIT>', self.colors['<STR_LIT>'])<EOL><DEDENT>

Resets all edge and vertex colors to their default values.


if isinstance(mat, dict):<EOL><INDENT>for key, value in mat.items():<EOL><INDENT>probs = list(value.values())<EOL>if key not in self.g.node:<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg)<EOL><DEDENT>elif len(self.out_edges[key]) > <NUM_LIT:0> and not np.isclose(sum(probs), <NUM_LIT:1>):<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg)<EOL><DEDENT>elif (np.array(probs) < <NUM_LIT:0>).any():<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg)<EOL><DEDENT>for k, e in enumerate(sorted(self.g.out_edges(key))):<EOL><INDENT>self._route_probs[key][k] = value.get(e[<NUM_LIT:1>], <NUM_LIT:0>)<EOL><DEDENT><DEDENT><DEDENT>elif isinstance(mat, np.ndarray):<EOL><INDENT>non_terminal = np.array([self.g.out_degree(v) > <NUM_LIT:0> for v in self.g.nodes()])<EOL>if mat.shape != (self.nV, self.nV):<EOL><INDENT>msg = ("<STR_LIT>"<EOL>"<STR_LIT>").format(self.nV, self.nV)<EOL>raise ValueError(msg)<EOL><DEDENT>elif not np.allclose(np.sum(mat[non_terminal, :], axis=<NUM_LIT:1>), <NUM_LIT:1>):<EOL><INDENT>msg = "<STR_LIT>"<EOL>raise ValueError(msg)<EOL><DEDENT>elif (mat < <NUM_LIT:0>).any():<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>for k in range(self.nV):<EOL><INDENT>for j, e in enumerate(sorted(self.g.out_edges(k))):<EOL><INDENT>self._route_probs[k][j] = mat[k, e[<NUM_LIT:1>]]<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT>

Change the routing transitions probabilities for the
        network.

        Parameters
        ----------
        mat : dict or :class:`~numpy.ndarray`
            A transition routing matrix or transition dictionary. If
            passed a dictionary, the keys are source vertex indices and
            the values are dictionaries with target vertex indicies
            as the keys and the probabilities of routing from the
            source to the target as the values.

        Raises
        ------
        ValueError
            A :exc:`.ValueError` is raised if: the keys in the dict
            don't match with a vertex index in the graph; or if the
            :class:`~numpy.ndarray` is passed with the wrong shape,
            must be (``num_vertices``, ``num_vertices``); or the values
            passed are not probabilities (for each vertex they are
            positive and sum to 1);
        TypeError
            A :exc:`.TypeError` is raised if mat is not a dict or
            :class:`~numpy.ndarray`.

        Examples
        --------
        The default transition matrix is every out edge being equally
        likely:

        >>> import queueing_tool as qt
        >>> adjacency = {
        ...     0: [2],
        ...     1: [2, 3],
        ...     2: [0, 1, 2, 4],
        ...     3: [1],
        ...     4: [2],
        ... }
        >>> g = qt.adjacency2graph(adjacency)
        >>> net = qt.QueueNetwork(g)
        >>> net.transitions(False)  # doctest: +ELLIPSIS
        ...                         # doctest: +NORMALIZE_WHITESPACE
        {0: {2: 1.0},
         1: {2: 0.5, 3: 0.5},
         2: {0: 0.25, 1: 0.25, 2: 0.25, 4: 0.25},
         3: {1: 1.0},
         4: {2: 1.0}}

        If you want to change only one vertex's transition
        probabilities, you can do so with the following:

        >>> net.set_transitions({1 : {2: 0.75, 3: 0.25}})
        >>> net.transitions(False)  # doctest: +ELLIPSIS
        ...                         # doctest: +NORMALIZE_WHITESPACE
        {0: {2: 1.0},
         1: {2: 0.75, 3: 0.25},
         2: {0: 0.25, 1: 0.25, 2: 0.25, 4: 0.25},
         3: {1: 1.0},
         4: {2: 1.0}}

        One can generate a transition matrix using
        :func:`.generate_transition_matrix`. You can change all
        transition probabilities with an :class:`~numpy.ndarray`:

        >>> mat = qt.generate_transition_matrix(g, seed=10)
        >>> net.set_transitions(mat)
        >>> net.transitions(False)  # doctest: +ELLIPSIS
        ...                         # doctest: +NORMALIZE_WHITESPACE
        {0: {2: 1.0},
         1: {2: 0.962..., 3: 0.037...},
         2: {0: 0.301..., 1: 0.353..., 2: 0.235..., 4: 0.108...},
         3: {1: 1.0},
         4: {2: 1.0}}

        See Also
        --------
        :meth:`.transitions` : Return the current routing
            probabilities.
        :func:`.generate_transition_matrix` : Generate a random routing
            matrix.