Skip to content

Commit

Permalink
docs: Add type hinting and docstring cleanup to model
Browse files Browse the repository at this point in the history
  • Loading branch information
benmoran56 committed May 7, 2024
1 parent 03c2da1 commit 6e2bf55
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 53 deletions.
107 changes: 57 additions & 50 deletions pyglet/model/__init__.py
Expand Up @@ -30,7 +30,6 @@ def on_draw():
simply pass in a reference to the :py:class:`~pyglet.graphics.Batch`
instance when loading the Model::
import pyglet
window = pyglet.window.Window()
Expand All @@ -45,52 +44,60 @@ def on_draw():
pyglet.app.run()
.. versionadded:: 1.4
"""
from __future__ import annotations

from typing import TYPE_CHECKING

import pyglet

from pyglet import gl
from pyglet import graphics
from pyglet.gl import current_context
from pyglet.math import Mat4, Vec3
from pyglet.graphics import shader
from pyglet.math import Mat4

from .codecs import registry as _codec_registry
from .codecs import add_default_codecs as _add_default_codecs

if TYPE_CHECKING:
from typing import BinaryIO, Iterable
from pyglet.image import Texture
from pyglet.graphics import Batch, Group
from pyglet.graphics.shader import ShaderProgram
from pyglet.graphics.vertexdomain import VertexList
from pyglet.model.codecs import ModelDecoder

def load(filename, file=None, decoder=None, batch=None, group=None):

def load(filename: str, file: BinaryIO | None = None, decoder: ModelDecoder | None = None,
batch: Batch | None = None, group: Group | None = None) -> Model:
"""Load a 3D model from a file.
:Parameters:
`filename` : str
Used to guess the model format, and to load the file if `file` is
Args:
filename:
Used to guess the model format, and to load the file if ``file`` is
unspecified.
`file` : file-like object or None
Source of model data in any supported format.
`decoder` : ModelDecoder or None
file:
An open file containing the source of model data in any supported format.
decoder:
If unspecified, all decoders that are registered for the filename
extension are tried. An exception is raised if no codecs are
registered for the file extension, or if decoding fails.
`batch` : Batch or None
batch:
An optional Batch instance to add this model to.
`group` : Group or None
group:
An optional top level Group.
:rtype: :py:mod:`~pyglet.model.Model`
"""
if decoder:
return decoder.decode(filename, file, batch=batch, group=group)
else:
return _codec_registry.decode(filename, file, batch=batch, group=group)


def get_default_shader():
def get_default_shader() -> ShaderProgram:
return pyglet.gl.current_context.create_program((MaterialGroup.default_vert_src, 'vertex'),
(MaterialGroup.default_frag_src, 'fragment'))

def get_default_textured_shader():

def get_default_textured_shader() -> ShaderProgram:
return pyglet.gl.current_context.create_program((TexturedMaterialGroup.default_vert_src, 'vertex'),
(TexturedMaterialGroup.default_frag_src, 'fragment'))

Expand All @@ -101,41 +108,39 @@ class Model:
See the module documentation for usage.
"""

def __init__(self, vertex_lists, groups, batch):
"""Create a model.
:Parameters:
`vertex_lists` : list
A list of `~pyglet.graphics.VertexList` or
`~pyglet.graphics.IndexedVertexList`.
`groups` : list
A list of `~pyglet.model.TexturedMaterialGroup`, or
`~pyglet.model.MaterialGroup`. Each group corresponds to
a vertex list in `vertex_lists` of the same index.
`batch` : `~pyglet.graphics.Batch`
Optional batch to add the model to. If no batch is provided,
def __init__(self, vertex_lists: list[VertexList], groups: list[Group], batch: Batch | None = None) -> None:
"""Create a model instance.
Args:
vertex_lists:
A list of :py:class:`~pyglet.graphics.VertexList` or
:py:class:`~pyglet.graphics.IndexedVertexList`.
groups:
A list of :py:class:`~pyglet.model.TexturedMaterialGroup`, or
:py:class:`~pyglet.model.MaterialGroup`. Each group corresponds
to a vertex list in ``vertex_lists`` at the same index.
batch:
The batch to add the model to. If no batch is provided,
the model will maintain its own internal batch.
"""
self.vertex_lists = vertex_lists
self.groups = groups
self._batch = batch
self._batch = batch or graphics.Batch()
self._modelview_matrix = Mat4()

@property
def batch(self):
def batch(self) -> Batch:
"""The graphics Batch that the Model belongs to.
The Model can be migrated from one batch to another, or removed from
a batch (for individual drawing). If not part of any batch, the Model
will keep its own internal batch. Note that batch migration can be
an expensive operation.
:type: :py:class:`pyglet.graphics.Batch`
"""
return self._batch

@batch.setter
def batch(self, batch):
def batch(self, batch: Batch | None):
if self._batch == batch:
return

Expand All @@ -148,16 +153,16 @@ def batch(self, batch):
self._batch = batch

@property
def matrix(self):
def matrix(self) -> Mat4:
return self._modelview_matrix

@matrix.setter
def matrix(self, matrix):
def matrix(self, matrix: Mat4):
self._modelview_matrix = matrix
for group in self.groups:
group.matrix = matrix

def draw(self):
def draw(self) -> None:
"""Draw the model.
This is not recommended. See the module documentation
Expand All @@ -170,7 +175,8 @@ def draw(self):
class Material:
__slots__ = ("name", "diffuse", "ambient", "specular", "emission", "shininess", "texture_name")

def __init__(self, name, diffuse, ambient, specular, emission, shininess, texture_name=None):
def __init__(self, name: str, diffuse: Iterable, ambient: Iterable, specular: Iterable,
emission: Iterable, shininess: float, texture_name: str | None = None) -> None:
self.name = name
self.diffuse = diffuse
self.ambient = ambient
Expand All @@ -179,7 +185,7 @@ def __init__(self, name, diffuse, ambient, specular, emission, shininess, textur
self.shininess = shininess
self.texture_name = texture_name

def __eq__(self, other):
def __eq__(self, other) -> bool:
return (self.name == other.name and
self.diffuse == other.diffuse and
self.ambient == other.ambient and
Expand All @@ -190,11 +196,11 @@ def __eq__(self, other):


class BaseMaterialGroup(graphics.Group):
default_vert_src = None
default_frag_src = None
matrix = Mat4()
default_vert_src: str
default_frag_src: str
matrix: Mat4 = Mat4()

def __init__(self, material, program, order=0, parent=None):
def __init__(self, material: Material, program: ShaderProgram, order: int = 0, parent: Group | None = None) -> None:
super().__init__(order, parent)
self.material = material
self.program = program
Expand Down Expand Up @@ -248,20 +254,21 @@ class TexturedMaterialGroup(BaseMaterialGroup):
}
"""

def __init__(self, material, program, texture, order=0, parent=None):
def __init__(self, material: Material, program: ShaderProgram,
texture: Texture, order: int = 0, parent: Group | None = None):
super().__init__(material, program, order, parent)
self.texture = texture

def set_state(self):
def set_state(self) -> None:
gl.glActiveTexture(gl.GL_TEXTURE0)
gl.glBindTexture(self.texture.target, self.texture.id)
self.program.use()
self.program['model'] = self.matrix

def __hash__(self):
def __hash__(self) -> int:
return hash((self.texture.target, self.texture.id, self.program, self.order, self.parent))

def __eq__(self, other):
def __eq__(self, other) -> bool:
return (self.__class__ is other.__class__ and
self.material == other.material and
self.texture.target == other.texture.target and
Expand Down Expand Up @@ -313,7 +320,7 @@ class MaterialGroup(BaseMaterialGroup):
}
"""

def set_state(self):
def set_state(self) -> None:
self.program.use()
self.program['model'] = self.matrix

Expand Down
15 changes: 12 additions & 3 deletions pyglet/model/codecs/__init__.py
@@ -1,5 +1,14 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from pyglet.util import CodecRegistry, Decoder, Encoder, DecodeException, EncodeException

if TYPE_CHECKING:
from typing import BinaryIO
from pyglet.model import Model
from pyglet.graphics import Batch, Group


registry = CodecRegistry()
add_decoders = registry.add_decoders
Expand All @@ -17,7 +26,7 @@ class ModelEncodeException(EncodeException):


class ModelDecoder(Decoder):
def decode(self, filename, file, batch, group):
def decode(self, filename: str, file: BinaryIO | None, batch: Batch | None, group: Group | None) -> Model:
"""Decode the given file object and return an instance of `Model`.
Throws ModelDecodeException if there is an error. filename
can be a file type hint.
Expand All @@ -27,7 +36,7 @@ def decode(self, filename, file, batch, group):

class ModelEncoder(Encoder):

def encode(self, model, filename, file):
def encode(self, model: Model, filename: str, file: BinaryIO | None) -> None:
"""Encode the given model to the given file. filename
provides a hint to the file format desired. options are
encoder-specific, and unknown options should be ignored or
Expand All @@ -36,7 +45,7 @@ def encode(self, model, filename, file):
raise NotImplementedError()


def add_default_codecs():
def add_default_codecs() -> None:
# Add all bundled codecs. These should be listed in order of
# preference. This is called automatically by pyglet.model.

Expand Down

0 comments on commit 6e2bf55

Please sign in to comment.