From 8a6d8a37d57a7940f473ef9af97cfd89b5a70e71 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 10 May 2023 17:10:46 -0400 Subject: [PATCH 1/5] Re-apply all the `arcade.gl` changes in a new PR This reverts commit bfee79a186a1188f788a26155a3bf0218ea7f0b7. --- arcade/gl/buffer.py | 2 +- arcade/gl/compute_shader.py | 2 +- arcade/gl/context.py | 33 ++++++++++++++++++++------------- arcade/gl/geometry.py | 6 +++--- arcade/gl/glsl.py | 4 ++-- arcade/gl/program.py | 6 +++--- arcade/gl/texture.py | 6 +++--- arcade/gl/types.py | 23 ++++++++++++++--------- arcade/gl/uniform.py | 2 -- arcade/gl/vertex_array.py | 26 +++++++++++++------------- 10 files changed, 60 insertions(+), 50 deletions(-) diff --git a/arcade/gl/buffer.py b/arcade/gl/buffer.py index 8918bd97d..2980d686e 100644 --- a/arcade/gl/buffer.py +++ b/arcade/gl/buffer.py @@ -66,7 +66,7 @@ def __init__( elif reserve > 0: self._size = reserve # populate the buffer with zero byte values - data = (gl.GLubyte * self._size)(0) + data = (gl.GLubyte * self._size)() gl.glBufferData(gl.GL_ARRAY_BUFFER, self._size, data, self._usage) else: raise ValueError("Buffer takes byte data or number of reserved bytes") diff --git a/arcade/gl/compute_shader.py b/arcade/gl/compute_shader.py index 6d1650a03..f52f74ca4 100644 --- a/arcade/gl/compute_shader.py +++ b/arcade/gl/compute_shader.py @@ -17,7 +17,7 @@ class ComputeShader: def __init__(self, ctx: "Context", glsl_source: str) -> None: self._ctx = ctx self._source = glsl_source - self._uniforms: Dict[str, Uniform] = dict() + self._uniforms: Dict[str, Union[UniformBlock, Uniform]] = dict() from arcade.gl import ShaderException diff --git a/arcade/gl/context.py b/arcade/gl/context.py index 25b197af2..ade4a7a56 100644 --- a/arcade/gl/context.py +++ b/arcade/gl/context.py @@ -1,12 +1,14 @@ import logging +import typing import weakref from collections import deque from contextlib import contextmanager from ctypes import c_char_p, c_float, c_int, cast -from typing import (Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, +from typing import (TYPE_CHECKING, Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union) import pyglet +import pyglet.gl.lib from pyglet import gl from pyglet.window import Window @@ -17,7 +19,7 @@ from .program import Program from .query import Query from .texture import Texture2D -from .types import BufferDescription +from .types import BufferDescription, GLenumLike, PyGLenum from .vertex_array import Geometry from ..types import BufferProtocol @@ -872,9 +874,9 @@ def texture( components: int = 4, dtype: str = "f1", data: Optional[BufferProtocol] = None, - wrap_x: Optional[gl.GLenum] = None, - wrap_y: Optional[gl.GLenum] = None, - filter: Optional[Tuple[gl.GLenum, gl.GLenum]] = None, + wrap_x: Optional[PyGLenum] = None, + wrap_y: Optional[PyGLenum] = None, + filter: Optional[Tuple[GLenumLike, GLenumLike]] = None, samples: int = 0, immutable: bool = False, ) -> Texture2D: @@ -1313,36 +1315,41 @@ def __init__(self, ctx): warn("Error happened while querying of limits. Moving on ..") - def get_int_tuple(self, enum: gl.GLenum, length: int): + def get_int_tuple(self, enum: GLenumLike, length: int): """Get an enum as an int tuple""" try: values = (c_int * length)() gl.glGetIntegerv(enum, values) return tuple(values) - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return tuple([0] * length) - def get(self, enum: gl.GLenum, default=0) -> int: + def get(self, enum: GLenumLike, default=0) -> int: """Get an integer limit""" try: value = c_int() gl.glGetIntegerv(enum, value) return value.value - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return default - def get_float(self, enum: gl.GLenum, default=0.0) -> float: + def get_float(self, enum: GLenumLike, default=0.0) -> float: """Get a float limit""" try: value = c_float() gl.glGetFloatv(enum, value) return value.value - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return default - def get_str(self, enum: gl.GLenum) -> str: + def get_str(self, enum: GLenumLike) -> str: """Get a string limit""" try: return cast(gl.glGetString(enum), c_char_p).value.decode() # type: ignore - except gl.lib.GLException: + except pyglet.gl.lib.GLException: return "Unknown" + +if TYPE_CHECKING: + # Arcade's Context is passed into code paths that require a pyglet Context + # So we must prove they are compatible. + __typecheck__: pyglet.gl.base.Context = typing.cast(Context, '__typecheck__') diff --git a/arcade/gl/geometry.py b/arcade/gl/geometry.py index 8b45e3b17..4356c5193 100644 --- a/arcade/gl/geometry.py +++ b/arcade/gl/geometry.py @@ -231,9 +231,9 @@ def sphere( R = 1.0 / (rings - 1) S = 1.0 / (sectors - 1) - vertices = [0] * (rings * sectors * 3) - normals = [0] * (rings * sectors * 3) - uvs = [0] * (rings * sectors * 2) + vertices = [0.0] * (rings * sectors * 3) + normals = [0.0] * (rings * sectors * 3) + uvs = [0.0] * (rings * sectors * 2) v, n, t = 0, 0, 0 for r in range(rings): diff --git a/arcade/gl/glsl.py b/arcade/gl/glsl.py index 05569e9ca..81f2546e9 100644 --- a/arcade/gl/glsl.py +++ b/arcade/gl/glsl.py @@ -4,7 +4,7 @@ from pyglet import gl from .exceptions import ShaderException -from .types import SHADER_TYPE_NAMES +from .types import SHADER_TYPE_NAMES, PyGLenum class ShaderSource: @@ -31,7 +31,7 @@ def __init__( ctx: gl.Context, source: str, common: Optional[Iterable[str]], - source_type: gl.GLenum, + source_type: PyGLenum, ): """Create a shader source wrapper.""" self._source = source.strip() diff --git a/arcade/gl/program.py b/arcade/gl/program.py index ecf6ada87..ba3c8cc2b 100644 --- a/arcade/gl/program.py +++ b/arcade/gl/program.py @@ -15,7 +15,7 @@ from pyglet import gl from .uniform import Uniform, UniformBlock -from .types import AttribFormat, GLTypes, SHADER_TYPE_NAMES +from .types import AttribFormat, GLTypes, SHADER_TYPE_NAMES, PyGLenum from .exceptions import ShaderException if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -93,7 +93,7 @@ def __init__( f"Valid modes are: {self._valid_capture_modes}." ) - shaders = [(vertex_shader, gl.GL_VERTEX_SHADER)] + shaders: list[tuple[str, int]] = [(vertex_shader, gl.GL_VERTEX_SHADER)] if fragment_shader: shaders.append((fragment_shader, gl.GL_FRAGMENT_SHADER)) if geometry_shader: @@ -486,7 +486,7 @@ def _query_uniform_block(self, location: int) -> Tuple[int, int, str]: return index, b_size.value, u_name.value.decode() @staticmethod - def compile_shader(source: str, shader_type: gl.GLenum) -> gl.GLuint: + def compile_shader(source: str, shader_type: PyGLenum) -> gl.GLuint: """Compile the shader code of the given type. `shader_type` could be GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, ... diff --git a/arcade/gl/texture.py b/arcade/gl/texture.py index 44474d8e4..685e8ca81 100644 --- a/arcade/gl/texture.py +++ b/arcade/gl/texture.py @@ -6,7 +6,7 @@ from .buffer import Buffer from .utils import data_to_ctypes -from .types import pixel_formats, BufferOrBufferProtocol +from .types import PyGLuint, pixel_formats, BufferOrBufferProtocol from ..types import BufferProtocol if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -115,8 +115,8 @@ def __init__( dtype: str = "f1", data: Optional[BufferProtocol] = None, filter: Optional[Tuple[gl.GLuint, gl.GLuint]] = None, - wrap_x: Optional[gl.GLuint] = None, - wrap_y: Optional[gl.GLuint] = None, + wrap_x: Optional[PyGLuint] = None, + wrap_y: Optional[PyGLuint] = None, target=gl.GL_TEXTURE_2D, depth=False, samples: int = 0, diff --git a/arcade/gl/types.py b/arcade/gl/types.py index 76bf0ce69..96ee8efdc 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -1,5 +1,5 @@ import re -from typing import Optional, Iterable, List, Union +from typing import Optional, Iterable, List, Sequence, Union from pyglet import gl @@ -9,6 +9,10 @@ BufferOrBufferProtocol = Union[BufferProtocol, Buffer] +GLenumLike = Union[gl.GLenum, int] +PyGLenum = int +GLuintLike = Union[gl.GLuint, int] +PyGLuint = int _float_base_format = (0, gl.GL_RED, gl.GL_RG, gl.GL_RGB, gl.GL_RGBA) _int_base_format = ( @@ -102,7 +106,7 @@ } -def gl_name(gl_type: gl.GLenum) -> str: +def gl_name(gl_type: PyGLenum) -> Union[str, PyGLenum]: """Return the name of a gl type""" return GL_NAMES.get(gl_type, gl_type) @@ -112,7 +116,7 @@ class AttribFormat: Represents an attribute in a BufferDescription or a Program. :param str name: Name of the attribute - :param gl.GLEnum gl_type: The OpenGL type such as GL_FLOAT, GL_HALF_FLOAT etc. + :param GLenumLike gl_type: The OpenGL type such as GL_FLOAT, GL_HALF_FLOAT etc. :param int bytes_per_component: Number of bytes a single component takes :param int offset: (Optional offset for BufferDescription) :param int location: (Optional location for program attribute) @@ -128,9 +132,10 @@ class AttribFormat: ) def __init__( - self, name: str, gl_type: gl.GLenum, components: int, bytes_per_component: int, offset=0, location=0 + self, name: Optional[str], gl_type: Optional[PyGLenum], components: int, bytes_per_component: int, offset=0, + location=0 ): - self.name: str = name + self.name = name self.gl_type = gl_type self.components = components self.bytes_per_component = bytes_per_component @@ -188,7 +193,7 @@ class BufferDescription: # Describe all variants of a format string to simplify parsing (single component) # format: gl_type, byte_size - _formats = { + _formats: dict[str, tuple[Optional[PyGLenum], int]] = { # (gl enum, byte size) # Floats "f": (gl.GL_FLOAT, 4), @@ -227,7 +232,7 @@ def __init__( self, buffer: Buffer, formats: str, - attributes: Iterable[str], + attributes: Sequence[str], normalized: Optional[Iterable[str]] = None, instanced: bool = False, ): @@ -266,7 +271,7 @@ def __init__( f"attributes ({len(self.attributes)})" ) - def zip_attrs(formats, attributes): + def zip_attrs(formats: list[str], attributes: Sequence[str]): """Join together formats and attribute names taking padding into account""" attr_index = 0 for f in formats: @@ -344,7 +349,7 @@ class TypeInfo: """ __slots__ = "name", "enum", "gl_type", "gl_size", "components" - def __init__(self, name: str, enum: gl.GLenum, gl_type: gl.GLenum, gl_size: int, components: int): + def __init__(self, name: str, enum: GLenumLike, gl_type: PyGLenum, gl_size: int, components: int): self.name = name self.enum = enum self.gl_type = gl_type diff --git a/arcade/gl/uniform.py b/arcade/gl/uniform.py index 5a3c3a9fe..778d5b0f1 100644 --- a/arcade/gl/uniform.py +++ b/arcade/gl/uniform.py @@ -114,8 +114,6 @@ def __init__(self, ctx, program_id, location, name, data_type, array_length): self._components = 0 #: The getter function configured for this uniform #: The setter function configured for this uniform - self.getter = None - self.setter = None self._setup_getters_and_setters() @property diff --git a/arcade/gl/vertex_array.py b/arcade/gl/vertex_array.py index d4b45bac2..e630ffb7c 100644 --- a/arcade/gl/vertex_array.py +++ b/arcade/gl/vertex_array.py @@ -5,7 +5,7 @@ from pyglet import gl from .buffer import Buffer -from .types import BufferDescription, gl_name +from .types import BufferDescription, GLenumLike, GLuintLike, gl_name from .program import Program if TYPE_CHECKING: # handle import cycle caused by type hinting @@ -239,7 +239,7 @@ def _build( gl.glVertexAttribDivisor(prog_attr.location, 1) def render( - self, mode: gl.GLenum, first: int = 0, vertices: int = 0, instances: int = 1 + self, mode: GLenumLike, first: int = 0, vertices: int = 0, instances: int = 1 ): """Render the VertexArray to the currently active framebuffer. @@ -259,7 +259,7 @@ def render( else: gl.glDrawArraysInstanced(mode, first, vertices, instances) - def render_indirect(self, buffer: Buffer, mode: gl.GLuint, count, first, stride): + def render_indirect(self, buffer: Buffer, mode: GLuintLike, count, first, stride): """ Render the VertexArray to the framebuffer using indirect rendering. @@ -300,8 +300,8 @@ def render_indirect(self, buffer: Buffer, mode: gl.GLuint, count, first, stride) def transform_interleaved( self, buffer: Buffer, - mode: gl.GLenum, - output_mode: gl.GLenum, + mode: GLenumLike, + output_mode: GLenumLike, first: int = 0, vertices: int = 0, instances: int = 1, @@ -310,8 +310,8 @@ def transform_interleaved( """Run a transform feedback. :param Buffer buffer: The buffer to write the output - :param gl.GLenum mode: The input primitive mode - :param gl.GLenum output_mode: The output primitive mode + :param GLenumLike mode: The input primitive mode + :param GLenumLike output_mode: The output primitive mode :param int first: Offset start vertex :param int vertices: Number of vertices to render :param int instances: Number of instances to render @@ -355,8 +355,8 @@ def transform_interleaved( def transform_separate( self, buffers: List[Buffer], - mode: gl.GLenum, - output_mode: gl.GLenum, + mode: GLenumLike, + output_mode: GLenumLike, first: int = 0, vertices: int = 0, instances: int = 1, @@ -366,8 +366,8 @@ def transform_separate( Run a transform feedback writing to separate buffers. :param List[Buffer] buffers: The buffers to write the output - :param gl.GLenum mode: The input primitive mode - :param gl.GLenum output_mode: The output primitive mode + :param GLenumLike mode: The input primitive mode + :param GLenumLike output_mode: The output primitive mode :param int first: Offset start vertex :param int vertices: Number of vertices to render :param int instances: Number of instances to render @@ -537,7 +537,7 @@ def render( self, program: Program, *, - mode: Optional[gl.GLenum] = None, + mode: Optional[GLenumLike] = None, first: int = 0, vertices: Optional[int] = None, instances: int = 1, @@ -549,7 +549,7 @@ def render( or have resized the buffers after the geometry instance was created. :param Program program: The Program to render with - :param gl.GLenum mode: Override what primitive mode should be used + :param GLenumLike mode: Override what primitive mode should be used :param int first: Offset start vertex :param int vertices: Override the number of vertices to render :param int instances: Number of instances to render From 1e2dac4046f8126fd236ff5346a6d19d07cb47a5 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 17 May 2023 21:46:45 -0400 Subject: [PATCH 2/5] Address review feedback --- arcade/gl/context.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arcade/gl/context.py b/arcade/gl/context.py index ade4a7a56..01be837c7 100644 --- a/arcade/gl/context.py +++ b/arcade/gl/context.py @@ -1,10 +1,9 @@ import logging -import typing import weakref from collections import deque from contextlib import contextmanager from ctypes import c_char_p, c_float, c_int, cast -from typing import (TYPE_CHECKING, Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, +from typing import (Any, Deque, Dict, Iterable, List, Optional, Sequence, Set, Tuple, Union) import pyglet @@ -1348,8 +1347,3 @@ def get_str(self, enum: GLenumLike) -> str: return cast(gl.glGetString(enum), c_char_p).value.decode() # type: ignore except pyglet.gl.lib.GLException: return "Unknown" - -if TYPE_CHECKING: - # Arcade's Context is passed into code paths that require a pyglet Context - # So we must prove they are compatible. - __typecheck__: pyglet.gl.base.Context = typing.cast(Context, '__typecheck__') From 773d9dc3a2bcb1efd1d17b8abe4a751a21da731f Mon Sep 17 00:00:00 2001 From: cspotcode Date: Wed, 17 May 2023 21:47:02 -0400 Subject: [PATCH 3/5] Fix typecheck error --- arcade/gl/vertex_array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arcade/gl/vertex_array.py b/arcade/gl/vertex_array.py index e630ffb7c..2c8ffb030 100644 --- a/arcade/gl/vertex_array.py +++ b/arcade/gl/vertex_array.py @@ -146,7 +146,7 @@ def _build( # Build the vao according to the shader's attribute specifications for _, prog_attr in enumerate(program.attributes): # Do we actually have an attribute with this name in buffer descriptions? - if prog_attr.name.startswith("gl_"): + if prog_attr.name is not None and prog_attr.name.startswith("gl_"): continue try: buff_descr, attr_descr = descr_attribs[prog_attr.name] From 2df086043b947f5d6677a728a7298b0c58013546 Mon Sep 17 00:00:00 2001 From: cspotcode Date: Thu, 18 May 2023 12:11:16 -0400 Subject: [PATCH 4/5] address review feedback --- arcade/gl/program.py | 2 +- arcade/gl/types.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arcade/gl/program.py b/arcade/gl/program.py index ba3c8cc2b..ac0de00b4 100644 --- a/arcade/gl/program.py +++ b/arcade/gl/program.py @@ -93,7 +93,7 @@ def __init__( f"Valid modes are: {self._valid_capture_modes}." ) - shaders: list[tuple[str, int]] = [(vertex_shader, gl.GL_VERTEX_SHADER)] + shaders: List[Tuple[str, int]] = [(vertex_shader, gl.GL_VERTEX_SHADER)] if fragment_shader: shaders.append((fragment_shader, gl.GL_FRAGMENT_SHADER)) if geometry_shader: diff --git a/arcade/gl/types.py b/arcade/gl/types.py index 96ee8efdc..a71ad41c7 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -1,5 +1,5 @@ import re -from typing import Optional, Iterable, List, Sequence, Union +from typing import Dict, Optional, Iterable, List, Sequence, Tuple, Union from pyglet import gl @@ -193,7 +193,7 @@ class BufferDescription: # Describe all variants of a format string to simplify parsing (single component) # format: gl_type, byte_size - _formats: dict[str, tuple[Optional[PyGLenum], int]] = { + _formats: Dict[str, Tuple[Optional[PyGLenum], int]] = { # (gl enum, byte size) # Floats "f": (gl.GL_FLOAT, 4), @@ -271,7 +271,7 @@ def __init__( f"attributes ({len(self.attributes)})" ) - def zip_attrs(formats: list[str], attributes: Sequence[str]): + def zip_attrs(formats: List[str], attributes: Sequence[str]): """Join together formats and attribute names taking padding into account""" attr_index = 0 for f in formats: From 886993624688a3af26b943683e7fab66cfde150f Mon Sep 17 00:00:00 2001 From: cspotcode Date: Thu, 18 May 2023 12:26:19 -0400 Subject: [PATCH 5/5] Fix last type issue --- arcade/gl/types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arcade/gl/types.py b/arcade/gl/types.py index a71ad41c7..67e7e7190 100644 --- a/arcade/gl/types.py +++ b/arcade/gl/types.py @@ -106,8 +106,10 @@ } -def gl_name(gl_type: PyGLenum) -> Union[str, PyGLenum]: +def gl_name(gl_type: Optional[PyGLenum]) -> Union[str, PyGLenum, None]: """Return the name of a gl type""" + if gl_type is None: + return None return GL_NAMES.get(gl_type, gl_type)